## Automatically generated incremental diff
## From:   linux-2.5.6-pre3
## To:     linux-2.5.6
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.5.6-pre3/Documentation/DocBook/kernel-locking.tmpl linux-2.5.6/Documentation/DocBook/kernel-locking.tmpl
--- linux-2.5.6-pre3/Documentation/DocBook/kernel-locking.tmpl	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/Documentation/DocBook/kernel-locking.tmpl	Thu Mar  7 18:24:40 2002
@@ -788,8 +788,18 @@
     </para>
 
     <para>
-      Note that the atomic operations are defined to act as both
-      read and write barriers on all platforms.
+      Note that the atomic operations do in general not act as memory
+      barriers. Instead you can insert a memory barrier before or
+      after <function>atomic_inc()</function> or
+      <function>atomic_dec()</function> by inserting
+      <function>smp_mb__before_atomic_inc()</function>,
+      <function>smp_mb__after_atomic_inc()</function>,
+      <function>smp_mb__before_atomic_dec()</function> or
+      <function>smp_mb__after_atomic_dec()</function>
+      respectively. The advantage of using those macros instead of
+      <function>smp_mb()</function> is, that they are cheaper on some
+      platforms.    
+      <!-- Sebastian Wilhelmi <seppi@seppi.de> 2002-03-04 -->
     </para>
    </sect1>
 
diff -urN linux-2.5.6-pre3/Documentation/filesystems/cramfs.txt linux-2.5.6/Documentation/filesystems/cramfs.txt
--- linux-2.5.6-pre3/Documentation/filesystems/cramfs.txt	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/Documentation/filesystems/cramfs.txt	Thu Mar  7 18:24:40 2002
@@ -10,7 +10,7 @@
 
 You can't write to a cramfs filesystem (making it compressible and
 compact also makes it _very_ hard to update on-the-fly), so you have to
-create the disk image with the "mkcramfs" utility in scripts/cramfs.
+create the disk image with the "mkcramfs" utility.
 
 
 Usage Notes
@@ -19,9 +19,7 @@
 File sizes are limited to less than 16MB.
 
 Maximum filesystem size is a little over 256MB.  (The last file on the
-filesystem is allowed to extend past 256MB.)  (Comments in mkcramfs.c
-suggest that ROM sizes may be limited to 64MB, though that's not a
-limitation in cramfs code.)
+filesystem is allowed to extend past 256MB.)
 
 Only the low 8 bits of gid are stored.  The current version of
 mkcramfs simply truncates to 8 bits, which is a potential security
@@ -48,18 +46,28 @@
 
 
 For /usr/share/magic
-------------------
+--------------------
 
-0	long	0x28cd3d45	Linux cramfs
->4	long	x		size %d
->8	long	x		flags 0x%x
->12	long	x		future 0x%x
+0	ulelong	0x28cd3d45	Linux cramfs offset 0
+>4	ulelong	x		size %d
+>8	ulelong	x		flags 0x%x
+>12	ulelong	x		future 0x%x
 >16	string	>\0		signature "%.16s"
->32	long	x		fsid.crc 0x%x
->36	long	x		fsid.edition %d
->40	long	x		fsid.blocks %d
->44	long	x		fsid.files %d
+>32	ulelong	x		fsid.crc 0x%x
+>36	ulelong	x		fsid.edition %d
+>40	ulelong	x		fsid.blocks %d
+>44	ulelong	x		fsid.files %d
 >48	string	>\0		name "%.16s"
+512	ulelong	0x28cd3d45	Linux cramfs offset 512
+>516	ulelong	x		size %d
+>520	ulelong	x		flags 0x%x
+>524	ulelong	x		future 0x%x
+>528	string	>\0		signature "%.16s"
+>544	ulelong	x		fsid.crc 0x%x
+>548	ulelong	x		fsid.edition %d
+>552	ulelong	x		fsid.blocks %d
+>556	ulelong	x		fsid.files %d
+>560	string	>\0		name "%.16s"
 
 
 Hacker Notes
diff -urN linux-2.5.6-pre3/Documentation/networking/driver.txt linux-2.5.6/Documentation/networking/driver.txt
--- linux-2.5.6-pre3/Documentation/networking/driver.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/networking/driver.txt	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,84 @@
+Documents about softnet driver issues in general can be found
+at:
+
+	http://www.firstfloor.org/~andi/softnet/
+
+Transmit path guidelines:
+
+1) The hard_start_xmit method must never return '1' under any
+   normal circumstances.  It is considered a hard error unless
+   there is no way your device can tell ahead of time when it's
+   transmit function will become busy.
+
+   Instead it must maintain the queue properly.  For example,
+   for a driver implementing scatter-gather this means:
+
+	static int drv_hard_start_xmit(struct sk_buff *skb,
+		   		       struct net_device *dev)
+	{
+		struct drv *dp = dev->priv;
+
+		lock_tx(dp);
+		...
+		/* This is a hard error log it. */
+		if (TX_BUFFS_AVAIL(dp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+			netif_stop_queue(dev);
+			unlock_tx(dp);
+			printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+			       dev->name);
+			return 1;
+		}
+
+		... queue packet to card ...
+		... update tx consumer index ...
+
+		if (TX_BUFFS_AVAIL(dp) <= (MAX_SKB_FRAGS + 1))
+			netif_stop_queue(dev);
+
+		...
+		unlock_tx(dp);
+		...
+	}
+
+   And then at the end of your TX reclaimation event handling:
+
+	if (netif_queue_stopped(dp->dev) &&
+            TX_BUFFS_AVAIL(dp) > (MAX_SKB_FRAGS + 1))
+		netif_wake_queue(dp->dev);
+
+   For a non-scatter-gather supporting card, the three tests simply become:
+
+		/* This is a hard error log it. */
+		if (TX_BUFFS_AVAIL(dp) <= 0)
+
+   and:
+
+		if (TX_BUFFS_AVAIL(dp) == 0)
+
+   and:
+
+	if (netif_queue_stopped(dp->dev) &&
+            TX_BUFFS_AVAIL(dp) > 0)
+		netif_wake_queue(dp->dev);
+
+2) Do not forget to update netdev->trans_start to jiffies after
+   each new tx packet is given to the hardware.
+
+3) Do not forget that once you return 0 from your hard_start_xmit
+   method, it is your driver's responsibility to free up the SKB
+   and in some finite amount of time.
+
+   For example, this means that it is not allowed for your TX
+   mitigation scheme to let TX packets "hang out" in the TX
+   ring unreclaimed forever if no new TX packets are sent.
+   This error can deadlock sockets waiting for send buffer room
+   to be freed up.
+
+   If you return 1 from the hard_start_xmit method, you must not keep
+   any reference to that SKB and you must not attempt to free it up.
+
+Probing guidelines:
+
+1) Any hardware layer address you obtain for your device should
+   be verified.  For example, for ethernet check it with
+   linux/etherdevice.h:is_valid_ether_addr()
diff -urN linux-2.5.6-pre3/Documentation/networking/generic-hdlc.txt linux-2.5.6/Documentation/networking/generic-hdlc.txt
--- linux-2.5.6-pre3/Documentation/networking/generic-hdlc.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/networking/generic-hdlc.txt	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,115 @@
+Generic HDLC layer for Linux kernel 2.4/2.5
+Krzysztof Halasa <khc@pm.waw.pl>
+May, 2001
+
+
+Generic HDLC layer currently supports:
+- Frame Relay (ANSI, CCITT and no LMI), with ARP support (no InARP),
+- raw HDLC (IPv4 only),
+- Cisco HDLC,
+- PPP (uses syncppp.c),
+- X.25 (uses X.25 routines).
+
+There are hardware drivers for the following cards:
+- C101 by Moxa Technologies Co., Ltd.
+- RISCom/N2 by SDL Communications Inc.
+- and others, some not in the official kernel.
+
+Make sure the hdlc.o and the hardware driver are loaded. It should
+create a number of "hdlc" (hdlc0 etc) network devices, one for each
+WAN port. You'll need the "sethdlc" utility, get it from:
+	http://hq.pm.waw.pl/hdlc/
+
+Compile sethdlc.c utility:
+	gcc -O2 -Wall -o sethdlc sethdlc.c
+Make sure you're using a correct version of sethdlc for your kernel.
+
+Use sethdlc to set physical interface, clock rate, HDLC mode used,
+and add any required PVCs if using Frame Relay.
+Usually you want something like:
+
+	sethdlc hdlc0 clock int rate 128000
+	sethdlc hdlc0 cisco interval 10 timeout 25
+or
+	sethdlc hdlc0 rs232 clock ext
+	sethdlc fr lmi ansi
+	sethdlc create 99
+
+In Frame Relay mode, ifconfig master hdlc device up (without assigning
+any IP address to it) before using pvc devices.
+
+
+Setting interface:
+
+* v35 | rs232 | x21 | t1 | e1 - sets physical interface for a given port
+                                if the card has software-selectable interfaces
+  loopback - activate hardware loopback (for testing only)
+* clock ext - external clock (uses DTE RX and TX clock)
+* clock int - internal clock (provides clock signal on DCE clock output)
+* clock txint - TX internal, RX external (provides TX clock on DCE output)
+* clock txfromrx - TX clock derived from RX clock (TX clock on DCE output)
+* rate - sets clock rate in bps (not required for external clock or
+                                 for txfromrx)
+
+Setting protocol:
+
+* hdlc - sets raw HDLC (IP-only) mode
+  nrz / nrzi / fm-mark / fm-space / manchester - sets transmission code
+  no-parity / crc16 / crc16-pr0 (CRC16 with preset zeros) / crc32-itu
+  crc16-itu (CRC16 with ITU-T polynomial) / crc16-itu-pr0 - sets parity
+
+* cisco - sets Cisco HDLC mode (IP, IPv6 and IPX supported)
+  interval - time in seconds between keepalive packets
+  timeout - time in seconds after last received keepalive packet before
+            we assume the link is down
+
+* ppp - sets synchronous PPP mode
+
+* x25 - sets X.25 mode
+
+* fr - Frame Relay mode
+  lmi ansi / ccitt / none - LMI (link management) type
+  dce - Frame Relay DCE (network) side LMI instead of default DTE (user).
+  It has nothing to do with clocks!
+  t391 - link integrity verification polling timer (in seconds) - user
+  t392 - polling verification timer (in seconds) - network
+  n391 - full status polling counter - user
+  n392 - error threshold - both user and network
+  n393 - monitored events count - both user and network
+
+* create | delete n - FR only - adds / deletes PVC interface with DLCI #n.
+
+
+
+
+Board-specific issues
+---------------------
+
+n2.o and c101.o need parameters to work (note double quotes):
+
+	insmod n2 hw='"io,irq,ram,ports[:io,irq,...]"'
+example:
+	insmod n2 hw='"0x300,10,0xD0000,01"'
+
+or
+	insmod c101 hw='"irq,ram[:irq,...]"
+example:
+	insmod c101 hw='"9,0xdc000"'
+
+If built into the kernel, these drivers need kernel (command line) parameters:
+	n2=io,irq,ram,ports:...
+or
+	c101=irq,ram:...
+
+
+
+If you have a problem with N2 or C101 card, you can issue the "private"
+command to see port's packet descriptor rings:
+
+	sethdlc hdlc0 private
+
+The hardware driver have to be build with CONFIG_HDLC_DEBUG_RINGS.
+Attaching this info to bug reports would be helpful. Anyway, let me know
+if you have problems using this.
+
+For patches and other info look at http://hq.pm.waw.pl/hdlc/
diff -urN linux-2.5.6-pre3/Documentation/pci.txt linux-2.5.6/Documentation/pci.txt
--- linux-2.5.6-pre3/Documentation/pci.txt	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/Documentation/pci.txt	Thu Mar  7 18:24:41 2002
@@ -156,6 +156,11 @@
 which enables the bus master bit in PCI_COMMAND register and also fixes
 the latency timer value if it's set to something bogus by the BIOS.
 
+   If you want to use the PCI Memory-Write-Invalidate transaction,
+call pci_set_mwi().  This enables bit PCI_COMMAND bit for Mem-Wr-Inval
+and also ensures that the cache line size register is set correctly.
+Make sure to check the return value of pci_set_mwi(), not all architectures
+may support Memory-Write-Invalidate.
 
 4. How to access PCI config space
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -202,6 +207,8 @@
 pci_resource_len()		Returns the byte length of a PCI region
 pci_set_drvdata()		Set private driver data pointer for a pci_dev
 pci_get_drvdata()		Return private driver data pointer for a pci_dev
+pci_set_mwi()			Enable Memory-Write-Invalidate transactions.
+pci_clear_mwi()			Disable Memory-Write-Invalidate transactions.
 
 
 7. Miscellaneous hints
diff -urN linux-2.5.6-pre3/Documentation/sound/AD1816 linux-2.5.6/Documentation/sound/AD1816
--- linux-2.5.6-pre3/Documentation/sound/AD1816	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/Documentation/sound/AD1816	Wed Dec 31 16:00:00 1969
@@ -1,84 +0,0 @@
-Documentation for the AD1816(A) sound driver
-============================================
-
-Installation:
--------------
-
-To get your AD1816(A) based sound card work, you'll have to enable support for
-experimental code ("Prompt for development and/or incomplete code/drivers")
-and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable
-"Sound card support", "OSS modules support" and "Support for AD1816(A) based
-cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install
-and reboot the new kernel as usual.
-
-Features:
----------
-
-List of features supported by this driver:
-- full-duplex support
-- supported audio formats: unsigned 8bit, signed 16bit little endian, 
-                           signed 16bit big endian, µ-law, A-law
-- supported channels: mono and stereo
-- supported recording sources: Master, CD, Line, Line1, Line2, Mic
-- supports phat 3d stereo circuit (Line 3)
-
-
-Supported cards:
-----------------
-
-The following cards are known to work with this driver:
-- Terratec Base 1 
-- Terratec Base 64 
-- HP Kayak 
-- Acer FX-3D
-- SY-1816 
-- Highscreen Sound-Boostar 32 Wave 3D
-- Highscreen Sound-Boostar 16 
-- AVM Apex Pro card 
-- (Aztech SC-16 3D) 
-- (Newcom SC-16 3D) 
-- (Terratec EWS64S) 
-
-Cards listed in brackets are not supported reliable. If you have such a card 
-you should add the extra parameter:
-  options=1
-when loading the ad1816 module via modprobe. 
-
-
-Troubleshooting:
-----------------
-
-First of all you should check, if the driver has been loaded
-properly.
-
-If loading of the driver succeeds, but playback/capture fails, check
-if you used the correct values for irq, dma and dma2 when loading the module.
-If one of them is wrong you usually get the following error message:
-
-Nov  6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error?
-
-If playback/capture is too fast or to slow, you should have a look at
-the clock chip of your sound card. The AD1816 was designed for a 33MHz
-oscillator, however most sound card manufacturer use slightly
-different oscillators as they are cheaper than 33MHz oscillators. If
-you have such a card you have to adjust the ad1816_clockfreq parameter
-above. For example: For a card using a 32.875MHz oscillator use
-ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000.
-
-
-Updates, bugfixes and bugreports:
---------------------------------
-
-As the driver is still experimental and under development, you should
-watch out for updates.  Updates of the driver are available on the
-Internet from one of my home pages:
-  http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
-or:
-  http://www.tu-darmstadt.de/~tek01/projects/linux.html
-
-Bugreports, bugfixes and related questions should be sent via E-Mail to:
-  tek@rbg.informatik.tu-darmstadt.de
-
-Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
-Christoph Hellwig <hch@infradead.org>
-	Last modified: 2000/09/20
diff -urN linux-2.5.6-pre3/Documentation/sound/ALS linux-2.5.6/Documentation/sound/ALS
--- linux-2.5.6-pre3/Documentation/sound/ALS	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/Documentation/sound/ALS	Wed Dec 31 16:00:00 1969
@@ -1,66 +0,0 @@
-ALS-007/ALS-100/ALS-200 based sound cards
-=========================================
-
-Support for sound cards based around the Avance Logic
-ALS-007/ALS-100/ALS-200 chip is included.  These chips are a single
-chip PnP sound solution which is mostly hardware compatible with the
-Sound Blaster 16 card, with most differences occurring in the use of
-the mixer registers.  For this reason the ALS code is integrated
-as part of the Sound Blaster 16 driver (adding only 800 bytes to the
-SB16 driver).
-
-To use an ALS sound card under Linux, enable the following options as
-modules in the sound configuration section of the kernel config:
-  - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
-  - FM synthesizer (YM3812/OPL-3) support 
-  - standalone MPU401 support may be required for some cards; for the
-    ALS-007, when using isapnptools, it is required
-Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be
-compiled in.  If kernel level PnP support is not included, isapnptools will
-be required to configure the card before the sound modules are loaded.
-
-When using kernel level ISAPnP, the kernel should correctly identify and
-configure all resources required by the card when the "sb" module is
-inserted.  Note that the ALS-007 does not have a 16 bit DMA channel and that
-the MPU401 interface on this card uses a different interrupt to the audio
-section.  This should all be correctly configured by the kernel; if problems
-with the MPU401 interface surface, try using the standalone MPU401 module,
-passing "0" as the "sb" module's "mpu_io" module parameter to prevent the
-soundblaster driver attempting to register the MPU401 itself.  The onboard
-synth device can be accessed using the "opl3" module.
-
-If isapnptools is used to wake up the sound card (as in 2.2.x), the settings
-of the card's resources should be passed to the kernel modules ("sb", "opl3"
-and "mpu401") using the module parameters.  When configuring an ALS-007, be
-sure to specify different IRQs for the audio and MPU401 sections - this card
-requires they be different.  For "sb", "io", "irq" and "dma" should be set
-to the same values used to configure the audio section of the card with
-isapnp.  "dma16" should be explicitly set to "-1" for an ALS-007 since this
-card does not have a 16 bit dma channel; if not specified the kernel will
-default to using channel 5 anyway which will cause audio not to work. 
-"mpu_io" should be set to 0.  The "io" parameter of the "opl3" module should
-also agree with the setting used by isapnp.  To get the MPU401 interface
-working on an ALS-007 card, the "mpu401" module will be required since this
-card uses separate IRQs for the audio and MPU401 sections and there is no
-parameter available to pass a different IRQ to the "sb" driver (whose
-inbuilt MPU401 driver would otherwise be fine).  Insert the mpu401 module
-passing appropriate values using the "io" and "irq" parameters.
-
-The resulting sound driver will provide the following capabilities:
-  - 8 and 16 bit audio playback
-  - 8 and 16 bit audio recording
-  - Software selection of record source (line in, CD, FM, mic, master)
-  - Record and playback of midi data via the external MPU-401
-  - Playback of midi data using inbuilt FM synthesizer
-  - Control of the ALS-007 mixer via any OSS-compatible mixer programs. 
-    Controls available are Master (L&R), Line in (L&R), CD (L&R), 
-    DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
-
-Jonathan Woithe
-jwoithe@physics.adelaide.edu.au
-30 March 1998
-
-Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
-Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
-Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au
- - updated information for kernel 2.4.x.
diff -urN linux-2.5.6-pre3/Documentation/sound/AWE32 linux-2.5.6/Documentation/sound/AWE32
--- linux-2.5.6-pre3/Documentation/sound/AWE32	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/Documentation/sound/AWE32	Wed Dec 31 16:00:00 1969
@@ -1,76 +0,0 @@
-	Installing and using Creative AWE midi sound under Linux.
-
-This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and 
-SB32.
-
-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
-   is important, because the driver works only with real Creative cards.
-
-2) The first thing you need to do is re-compile your kernel with support for
-   your sound card. Run your favourite tool to configure the kernel and when
-   you get to the "Sound" menu you should enable support for the following:
-
-   Sound card support,
-   OSS sound modules,
-   100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
-   AWE32 synth
-
-   If your card is "Plug and Play" you will also need to enable these two
-   options, found under the "Plug and Play configuration" menu:
-
-   Plug and Play support
-   ISA Plug and Play support
-
-   Now compile and install the kernel in normal fashion. If you don't know
-   how to do this you can find instructions for this in the README file
-   located in the root directory of the kernel source.
-
-3) Before you can start playing midi files you will have to load a sound
-   bank file. The utility needed for doing this is called "sfxload", and it
-   is one of the utilities found in a package called "awesfx". If this
-   package is not available in your distribution you can download the AWE
-   snapshot from Creative Labs Open Source website:
-
-   http://www.opensource.creative.com/snapshot.html
-
-   Once you have unpacked the AWE snapshot you will see a "awesfx"
-   directory. Follow the instructions in awesfx/docs/INSTALL to install the
-   utilities in this package. After doing this, sfxload should be installed
-   as:
-
-   /usr/local/bin/sfxload
-
-   To enable AWE general midi synthesis you should also get the sound bank
-   file for general midi from:
-
-   http://members.xoom.com/yar/synthgm.sbk.gz
-
-   Copy it to a directory of your choice, and unpack it there.
-
-4) Edit /etc/modules.conf, and insert the following lines at the end of the
-   file:
-
-  alias sound-slot-0 sb
-  alias sound-service-0-1 awe_wave
-  post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
-
-  You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
-  path of of the sound bank file. That will enable the Sound Blaster and AWE
-  wave synthesis. To play midi files you should get one of these programs if
-  you don't already have them:
-
-  Playmidi:			http://playmidi.openprojects.net
-
-  AWEMidi Player (drvmidi)  	Included in the previously mentioned AWE
-  				snapshot.
-
-  You will probably have to pass the "-e" switch to playmidi to have it use
-  your midi device. drvmidi should work without switches.
-
-  If something goes wrong please e-mail me. All comments and suggestions are
-  welcome.
-
-		    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
-			    http://www.yar.opennet.ru
-
-Last Updated: Feb 3 2001
diff -urN linux-2.5.6-pre3/Documentation/sound/AudioExcelDSP16 linux-2.5.6/Documentation/sound/AudioExcelDSP16
--- linux-2.5.6-pre3/Documentation/sound/AudioExcelDSP16	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/Documentation/sound/AudioExcelDSP16	Wed Dec 31 16:00:00 1969
@@ -1,101 +0,0 @@
-Driver
-------
-
-Informations about Audio Excel DSP 16 driver can be found in the source
-file lowlevel/aedsp16.c
-Please, read the head of the source before using it. It contain useful
-informations.
-
-Configuration
--------------
-
-The Audio Excel configuration, is now done with the standard Linux setup.
-You have to configure the sound card (Sound Blaster or Microsoft Sound System)
-and, if you want it, the Roland MPU-401 (do not use the Sound Blaster MPU-401,
-SB-MPU401) in the main driver menu. Activate the lowlevel drivers then select
-the Audio Excel hardware that you want to initialize. Check the IRQ/DMA/MIRQ
-of the Audio Excel initialization: it must be the same as the SBPRO (or MSS)
-setup. If the parameters are different, correct it.
-I you own a Gallant's audio card based on SC-6600, activate the SC-6600 support.
-If you want to change the configuration of the sound board, be sure to
-check off all the configuration items before re-configure it.
-
-Module parameters
------------------
-To use this driver as a module, you must configure some module parameters, to
-set up I/O addresses, IRQ lines and DMA channels. Some parameters are
-mandatory while some others are optional. Here a list of parameters you can
-use with this module:
-
-Name		Description
-====		===========
-MANDATORY
-io		I/O base address (0x220 or 0x240)
-irq		irq line (5, 7, 9, 10 or 11)
-dma		dma channel (0, 1 or 3)
-
-OPTIONAL
-mss_base	I/O base address for activate MSS mode (default SBPRO)
-		(0x530 or 0xE80)
-mpu_base	I/O base address for activate MPU-401 mode
-		(0x300, 0x310, 0x320 or 0x330)
-mpu_irq		MPU-401 irq line (5, 7, 9, 10 or 0)
-
-The /etc/modules.conf will have lines like this:
-
-options opl3 io=0x388
-options ad1848 io=0x530 irq=11 dma=3
-options aedsp16 io=0x220 irq=11 dma=3 mss_base=0x530
-
-Where the aedsp16 options are the options for this driver while opl3 and
-ad1848 are the corresponding options for the MSS and OPL3 modules.
-
-Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly
-the sound card. Installation dependencies must be written in the modules.conf
-file:
-
-pre-install ad1848 modprobe aedsp16
-pre-install opl3 modprobe aedsp16
-
-Then you must load the sound modules stack in this order:
-sound -> aedsp16 -> [ ad1848, opl3 ]
-
-With the above configuration, loading ad1848 or opl3 modules, will
-automatically load all the sound stack.
-
-Sound cards supported
----------------------
-This driver supports the SC-6000 and SC-6600 based Gallant's sound card.
-It don't support the Audio Excel DSP 16 III (try the SC-6600 code).
-I'm working on the III version of the card: if someone have useful
-informations about it, please let me know.
-For all the non-supported audio cards, you have to boot MS-DOS (or WIN95)
-activating the audio card with the MS-DOS device driver, then you have to
-<ctrl>-<alt>-<del> and boot Linux.
-Follow these steps:
-
-1) Compile Linux kernel with standard sound driver, using the emulation
-   you want, with the parameters of your audio card,
-   e.g. Microsoft Sound System irq10 dma3
-2) Install your new kernel as the default boot kernel.
-3) Boot MS-DOS and configure the audio card with the boot time device
-   driver, for MSS irq10 dma3 in our example.
-4) <ctrl>-<alt>-<del> and boot Linux. This will maintain the DOS configuration
-   and will boot the new kernel with sound driver. The sound driver will find
-   the audio card and will recognize and attach it.
-
-Reports on User successes
--------------------------
-
-> Date: Mon, 29 Jul 1996 08:35:40 +0100
-> From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk>
-> To: riccardo@cdc8g5.cdc.polimi.it (Riccardo Facchetti)
-> Subject: Re: Audio Excel DSP 16 initialization code
->
-> Just to let you know got my Audio Excel (emulating a MSS) working
-> with my original SB16, thanks for the driver!
-
-
-Last revised: 20 August 1998
-Riccardo Facchetti
-fizban@tin.it
diff -urN linux-2.5.6-pre3/Documentation/sound/CMI8330 linux-2.5.6/Documentation/sound/CMI8330
--- linux-2.5.6-pre3/Documentation/sound/CMI8330	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/Documentation/sound/CMI8330	Wed Dec 31 16:00:00 1969
@@ -1,153 +0,0 @@
-Documentation for CMI 8330 (SoundPRO) 
--------------------------------------
-Alessandro Zummo <azummo@ita.flashnet.it>
-
-( Be sure to read Documentation/sound/SoundPro too )
-
-
-This adapter is now directly supported by the sb driver.
-
- The only thing you have to do is to compile the kernel sound
-support as a module and to enable kernel ISAPnP support,
-as shown below.
-
-
-CONFIG_SOUND=m
-CONFIG_SOUND_SB=m
-
-CONFIG_PNP=y
-CONFIG_ISAPNP=y
-
-
-and optionally:
-
-
-CONFIG_SOUND_MPU401=m
-
- for MPU401 support.
-
-
-(I suggest you to use "make menuconfig" or "make xconfig" 
- for a more comfortable configuration editing)
-
-
-
-Then you can do
-
- modprobe sb
-
-and everything will be (hopefully) configured.
-
-You should get something similar in syslog:
-
-sb: CMI8330 detected.
-sb: CMI8330 sb base located at 0x220
-sb: CMI8330 mpu base located at 0x330
-sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>
-sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5
-
-
-
-
-The old documentation file follows for reference
-purposes.
-
-
-How to enable CMI 8330 (SOUNDPRO) soundchip on Linux
-------------------------------------------
-Stefan Laudat <Stefan.Laudat@asit.ro>
-
-[Note: The CMI 8338 is unrelated and is supported by cmpci.o]
-
-	
-	In order to use CMI8330 under Linux  you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience.  I use isapnp 1.17, but
-you may get a better one I guess at http://www.roestock.demon.co.uk/isapnptools/.
-
-	Of course you will have to compile kernel sound support as module, as shown below:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_OSS=m
-CONFIG_SOUND_SB=m
-CONFIG_SOUND_ADLIB=m
-CONFIG_SOUND_MPU401=m
-# Mikro$chaft sound system (kinda useful here ;))	
-CONFIG_SOUND_MSS=m
-
-	The /etc/isapnp.conf file will be:
-
-<snip below>
-
-
-(READPORT 0x0203)
-(ISOLATE PRESERVE)
-(IDENTIFY *)
-(VERBOSITY 2)
-(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
-(VERIFYLD N)
-
-
-# WSS 
-
-(CONFIGURE CMI0001/16777472 (LD 0
-(IO 0 (SIZE 8) (BASE 0x0530))
-(IO 1 (SIZE 8) (BASE 0x0388))
-(INT 0 (IRQ 7 (MODE +E)))
-(DMA 0 (CHANNEL 0))
-(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}")
-(ACT Y)
-))
-
-# MPU
-
-(CONFIGURE CMI0001/16777472 (LD 1
-(IO 0 (SIZE 2) (BASE 0x0330))
-(INT 0 (IRQ 11 (MODE +E)))
-(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}")
-(ACT Y)
-))
-
-# Joystick
-
-(CONFIGURE CMI0001/16777472 (LD 2
-(IO 0 (SIZE 8) (BASE 0x0200))
-(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}")
-(ACT Y)
-))
-
-# SoundBlaster 
- 
-(CONFIGURE CMI0001/16777472 (LD 3
-(IO 0 (SIZE 16) (BASE 0x0220))
-(INT 0 (IRQ 5 (MODE +E)))
-(DMA 0 (CHANNEL 1))
-(DMA 1 (CHANNEL 5))
-(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}")
-(ACT Y)
-))
-
-
-(WAITFORKEY)
-
-<end of snip>
-
-	The module sequence is trivial:
-
-/sbin/insmod soundcore
-/sbin/insmod sound
-/sbin/insmod uart401
-# insert this first
-/sbin/insmod ad1848 io=0x530 irq=7 dma=0 soundpro=1
-# The sb module is an alternative to the ad1848 (Microsoft Sound System)
-# Anyhow, this is full duplex and has MIDI
-/sbin/insmod sb io=0x220 dma=1 dma16=5 irq=5 mpu_io=0x330
-
-
-
-Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/modules.conf:
-
-alias sound ad1848
-alias synth0 opl3
-options ad1848 io=0x530 irq=7 dma=0 soundpro=1
-options opl3 io=0x388
-
-	
diff -urN linux-2.5.6-pre3/Documentation/sound/CMI8338 linux-2.5.6/Documentation/sound/CMI8338
--- linux-2.5.6-pre3/Documentation/sound/CMI8338	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/Documentation/sound/CMI8338	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-Audio driver for CM8338/CM8738 chips by Chen-Li Tien
-
-
-HARDWARE SUPPORTED
-================================================================================
-C-Media CMI8338
-C-Media CMI8738
-On-board C-Media chips
-
-
-STEPS TO BUILD DRIVER
-================================================================================
-
-  1. Backup the Config.in and Makefile in the sound driver directory
-     (/usr/src/linux/driver/sound).
-     The Configure.help provide help when you config driver in step
-     4, please backup the original one (/usr/src/linux/Document) and
-     copy this file.
-     The cmpci is document for the driver in detail, please copy it
-     to /usr/src/linux/Document/sound so you can refer it. Backup if
-     there is already one.
-
-  2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
-     directory.
-
-  3. Change directory to /usr/src/linux
-
-  4. Config cm8338 driver by 'make menuconfig', 'make config' or
-     'make xconfig' command.
-
-  5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
-     driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
-     For driver option, please refer 'DRIVER PARAMETER'
-
-  6. Compile the kernel if necessary.
-
-  7. Compile the modules by 'make modules'.
-
-  8. Install the modules by 'make modules_install'
-
-
-INSTALL DRIVER
-================================================================================
-
-  1. Before first time to run the driver, create module dependency by
-     'depmod -a'
-
-  2. To install the driver manually, enter 'modprobe cmpci'.
-
-  3. Driver installation for various distributions:
-
-    a. Slackware 4.0
-       Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
-       file.so you can start the driver automatically each time booting.
-
-    b. Caldera OpenLinux 2.2
-       Use LISA to load the cmpci module.
-
-    c. RedHat 6.0 and S.u.S.E. 6.1
-       Add following command in /etc/conf.modules:
-
-       alias sound cmpci
-
-	also visit http://www.cmedia.com.tw for installation instruction.
-
-DRIVER PARAMETER
-================================================================================
-
-  Some functions for the cm8738 can be configured in Kernel Configuration
-  or modules parameters. Set these parameters to 1 to enable.
-
-  mpuio:	I/O ports base for MPU-401, 0 if disabled.
-  fmio:		I/O ports base for OPL-3, 0 if disabled.
-  spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
-		CD-ROM or DVD-ROM.
-  spdif_loop:   Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
-                directly.
-  speakers:     Number of speakers used.
-  use_line_as_rear:Enable this if you want to use line-in as
-                rear-out.
-  use_line_as_bass:Enable this if you want to use line-in as
-                bass-out.
-  joystick:	Enable joystick. You will need to install Linux joystick
-		driver.
-
diff -urN linux-2.5.6-pre3/Documentation/sound/CS4232 linux-2.5.6/Documentation/sound/CS4232
--- linux-2.5.6-pre3/Documentation/sound/CS4232	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/Documentation/sound/CS4232	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-To configure the Crystal CS423x sound chip and activate its DSP functions,
-modules may be loaded in this order:
-  
-	modprobe sound
-	insmod ad1848
-	insmod uart401
-	insmod cs4232 io=* irq=* dma=* dma2=*
-  
-This is the meaning of the parameters:
-  
-	io--I/O address of the Windows Sound System (normally 0x534)
-	irq--IRQ of this device
-	dma and dma2--DMA channels (DMA2 may be 0)
-  
-On some cards, the board attempts to do non-PnP setup, and fails.  If you
-have problems, use Linux' PnP facilities. 
-  
-To get MIDI facilities add
-  
-	insmod opl3 io=*
-  
-where "io" is the I/O address of the OPL3 synthesizer. This will be shown
-in /proc/sys/pnp and is normally 0x388.
diff -urN linux-2.5.6-pre3/Documentation/sound/ChangeLog.awe linux-2.5.6/Documentation/sound/ChangeLog.awe
--- linux-2.5.6-pre3/Documentation/sound/ChangeLog.awe	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/ChangeLog.awe	Wed Dec 31 16:00:00 1969
@@ -1,230 +0,0 @@
-ver.0.4.3p4
-	- Bug fix for invalid memory detection when initialized twice
-	- Add sample sharing function - works together with awesfx-0.4.3p3
-	- Add AWE_PROBE_DATA for probing sample id
-
-ver.0.4.3p3
-	- Replace memset to MEMSET (for FreeBSD)
-	- Add PAN_EXCHANGE switch
-
-ver.0.4.3p2
-	- MIDI emulation device is added
-	- Controls volume and filter targets
-	- Include chorus/reverb/equalizer values in MISC_MODE
-
-ver.0.4.3p1
-	- Change the volume calculation method
-	- Support for Tom Lees' PnP driver (v0.3)
-
-ver.0.4.2d
-	- Support for OSS/Free 3.8 on 2.0 kernels.
-	- Support for Linux PnP driver
-	- Support for module (for recent 2.1 kernels and RH5.0)
-	- Support for FreeBSD-3.0 system
-
-ver.0.4.2c
-	- Add a mode to enable drum channel toggle via bank number
-	  change.
-
-ver.0.4.2b
-	- Clear voice position after note on
-	- Change nrvoices according to the current playing mode
-
-ver.0.4.2a
-	- Fix a bug in pitch calculation with scale parameter
-	- Change default chorus & reverb modes
-
-ver.0.4.2
-	- Use indirect voice allocation mode; used as default mode
-	- Add preset mapping
-	- Free buffers when resetting samples
-	- Set default preset/bank/drumset as variable
-	- Fix a bug in exclusive note-off
-	- Add channel reset control macro
-	- Change modwheel sensitivity as variable
-	- Add lock option in open_patch
-	- Add channel priority mode macro, and disable it as default
-	- Add unset effect macro
-	- Add user defined chorus/reverb modes
-	- Do not initialize effect parameters when allocating voices
-	- Accept realtime filter-Q parameter change
-	- Check value range of set/add effects
-	- Change drum flags automatically when receiving bank #128
-
-ver.0.4.1	development versions
-
-ver.0.4.0c
-	- Fix kernel oops when setting AWE_FX_ATTEN
-
-ver.0.4.0b
-	- Do not kill_note in start_note when velocity is zero
-
-ver.0.4.0a
-	- Fix a bug in channel pressure effects
-
-ver.0.4.0
-	- Support dynamic buffer allocation
-	- Add functions to open/close/unload a patch
-	- Change from pointer to integer index in voice/sample lists
-	- Support for Linux/Alpha-AXP
-	- Fix for FreeBSD
-	- Add sostenuto control
-	- Add midi channel priority
-	- Fix a bug in all notes off control
-	- Use AWE_DEFAULT_MEMSIZE always if defined
-	- Fix a bug in awe_reset causes seg fault when no DRAM onboard
-	- Use awe_mem_start variable instead of constant
-
-ver.0.3.3c
-	- Fix IOCTL_TO_USER for OSS-3.8 (on Linux-2.1.25)
-	- Fix i/o macros for mixer controls
-
-ver.0.3.3b
-	- Fix version number in awe_version.h
-	- Fix a small bug in noteoff/release all
-
-ver.0.3.3a
-	- Fix all notes/sounds off
-	- Add layer effect control
-	- Add misc mode controls; realtime pan, version number, etc.
-	- Move gus bank control in misc mode control
-	- Modify awe_operations for OSS3.8b5
-	- Fix installation script
-
-ver.0.3.3
-	- Add bass/treble control in Emu8000 chip
-	- Add mixer device
-	- Fix sustain on to value 127
-
-ver.0.3.2
-	- Refuse linux-2.0.0 at installation
-	- Move awe_voice.h to /usr/include/linux
-
-ver.0.3.1b (not released)
-	- Rewrite chorus/reverb mode change functions
-	- Rewrite awe_detect & awe_check_dram routines
-
-ver.0.3.1a
-	- Fix a bug to reset voice counter in awe_reset
-	- Fix voice balance on GUS mode
-	- Make symlink on /usr/include/asm in install script
-
-ver.0.3.1
-	- Remove zero size arrays from awe_voice.h
-	- Fix init_fm routine
-	- Remove all samples except primary samples in REMOVE_LAST_SAMPLES
-
-ver.0.3.0a
-	- Add AWE_NOTEOFF_ALL control
-	- Remove AWE_INIT_ATTEN control
-
-ver.0.3.0
-	- Fix decay time table
-	- Add exclusive sounds mode
-	- Add capability to get current status
-
-ver.0.2.99e
-	- Add #ifdef for all sounds/notes off controls.
-	- Fix bugs on searching the default drumset/preset.
-	- Fix usslite patch to modify the default Config.in.
-
-ver.0.2.99d
-	- Fix bugs of attack/hold parameters
-	- Fix attack & decay time table
-
-ver.0.2.99c
-	- Change volume control messages (main & expression volume)
-	  to accesspt normal MIDI parameters in channel mode.
-	- Use channel mode in SEQ2 controls.
-
-ver.0.2.99b
-	- #ifdef patch manager functions (for OSS-3.7)
-
-ver.0.2.99a
-	- Fix sustain bug
-
-ver.0.2.99 (0.3 beta)
-	- Support multiple instruments
-
-ver.0.2.0c
-	- Add copyright notice
-	- FreeBSD 2.2-ALPHA integration
-
-ver.0.2.0b
-	- Remove buffered reading appended in v0.2.0a
-	- Remove SMAxW register check on writing
-	- Support Linux 2.1.x kernel
-	- Rewrite installation script
-
-ver.0.2.0a
-	- Define SEQUENCER_C for tuning.h for FreeBSD system
-	- Improvement of sample loading speed
-	- Fix installation script
-	- Add PnP driver functions for ISA PnP driver support
-
-ver.0.2.0
-	- Includes FreeBSD port
-	- Can load GUS compatible patches
-	- Change values of hardware control parameters for compatibility
-	  with GUS driver
-	- Accept 8bit or unsigned wave data
-	- Accept no blank loop data
-	- Add sample mode flags in sample_info
-
-ver.0.1.6
-	- Add voice effects control
-	- Fix awe_voice.h for word alignment
-
-ver.0.1.5c
-	- Fix FM(OPL) playback problem
-
-ver.0.1.5b
-	- Fix pitch calculation for fixed midi key
-
-ver.0.1.5a
-	- Fix bugs in removing samples from linked list.
-
-ver.0.1.5
-	- Add checksum verification for sample uploading
-	  (not compatible from older sample_info structure)
-	- Fix sample offset pointers to (actual value - 1)
-	- Add sequencer command to initialize awe32
-
-ver.0.1.4c
-	- Fix card detection and memory check function to avoid system crash
-	  at booting
-
-ver.0.1.4b
-	- Add release sustain mode
-	- Initialize FM each time after loading samples
-
-ver.0.1.4a
-	- Fix AWE card detection code
-	- Correct FM initialize position 
-	- Add non-releasing mode on voice info
-
-ver.0.1.4
-	- Add AWE card and DRAM detection codes
-	- Add FM initialization code
-	- Modify volume control
-	- Remove linear volume mode
-	- Change memory management; not using malloc dynamically
-	- Add remove-samples command
-	- Use internal id implicitly at loading samples
-
-ver.0.1.3
-	- Fix a bug on patch uploading to RAM
-
-ver.0.1.2
-	- Divide to separated packages
-	- Fix disagreed macro conditions
-	- Fix unresolved function bugs
-	- Integrate VoxWare and USS-Lite driver source (awe_voice.c)
-	  and remove awe_card.c
-
-ver.0.1.1
-	- Fix wrong sample numbers in sbktext
-	- Fix txt2sfx bug
-	- Fix pan parameter calculation
-	- Append USS-Lite/Linux2.0 driver
-
diff -urN linux-2.5.6-pre3/Documentation/sound/ChangeLog.multisound linux-2.5.6/Documentation/sound/ChangeLog.multisound
--- linux-2.5.6-pre3/Documentation/sound/ChangeLog.multisound	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/Documentation/sound/ChangeLog.multisound	Wed Dec 31 16:00:00 1969
@@ -1,213 +0,0 @@
-1998-12-04  Andrew T. Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.8.2.2
-
-	* Add msndreset program to shell archive.
-
-1998-11-11  Andrew T. Veliath  <andrewv@usa.net>
-
-	* msnd_pinnacle.c (mixer_ioctl): Add a mixer ioctl for
-	SOUND_MIXER_PRIVATE1 which does a full reset on the card.
-	(mixer_set): Move line in recording source to input monitor, aux
-	input level added, some mixer fixes.
-
-1998-09-10  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.8.2
-
-	* Add SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls.
-
-1998-09-09  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.8.1
-	
-	* msnd_pinnacle.c: Fix resetting of default audio parameters. Turn
-	flush code from dsp_halt into dsp_write_flush, and use that for
-	SNDCTL_DSP_SYNC.
-
-1998-09-07  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.8.0
-
-	* Provide separate signal parameters for play and record.
-	
-	* Cleanups to locking and interrupt handling, change default
-	fifosize to 128kB.
-
-	* Update version to 0.7.15
-
-	* Interprocess full-duplex support (ie `cat /dev/dsp > /dev/dsp').
-
-	* More mutex sections for read and write fifos (read + write locks
-	added).
-
-1998-09-05  Andrew Veliath  <andrewtv@usa.net>
-
-	* msnd_pinnacle.c: (chk_send_dsp_cmd) Do full DSP reset upon DSP
-	timeout (when not in interrupt; maintains mixer settings).  Fixes
-	to flushing and IRQ ref counting. Rewrote queuing for smoother
-	playback and fixed initial playback cutoff problem.
-
-1998-09-03  Andrew Veliath  <andrewtv@usa.net>
-
-	* Replaced packed structure accesses with standard C equivalents.
-
-1998-09-01  Andrew Veliath  <andrewtv@usa.net>
-
-	* msnd_pinnacle.c: Add non-PnP configuration to driver code, which
-	  will facilitate compiled-in operation.
-
-1998-08-29  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.7.6
-	
-	* msnd_pinnacle.c (dsp_ioctl): Add DSP_GETFMTS, change SAMPLESIZE
-	  to DSP_SETFMT.
-
-	* Update version to 0.7.5
-	
-	* Create pinnaclecfg.c and turn MultiSound doc into a shell
-	  archive with pinnaclecfg.c included.  pinnaclecfg.c can
-	  now fully configure the card in non-PnP mode, including the
-	  joystick and IDE controller.  Also add an isapnp conf
-	  example.
-
-	* Reduce DSP reset timeout from 20000 to 100
-
-1998-08-06  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.7.2
-	
-	* After A/D calibration, do an explicit set to the line input,
-	  rather than using set_recsrc
-
-1998-07-20  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.7.1
-
-	* Add more OSS ioctls
-	
-1998-07-19  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update doc file
-	
-	* Bring back DIGITAL1 with digital parameter to msnd_pinnacle.c
-	  and CONFIG_MSNDPIN_DIGITAL.  I'm not sure this actually works,
-	  since I find audio playback goes into a very speeded mode of
-	  operation, however it might be due to a lack of a digital
-	  source, which I don't have to test.
-
-1998-07-18  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.7.0
-
-	* Can now compile with Alan Cox' 2.0.34-modular-sound patch (so
-	  now it requires >= 2.1.106 or 2.0.34-ms) (note for 2.0.34-ms it
-	  is in the Experimental section)
-
-	* More modularization, consolidation, also some MIDI hooks
-	  installed for future MIDI modules
-
-	* Write flush
-
-	* Change default speed, channels, bit size to OSS/Free defaults
-
-1998-06-02  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.5b
-
-	* Fix version detection
-	
-	* Remove underflow and overflow resets (delay was too long)
-
-	* Replace spinlocked bitops with atomic bit ops
-
-1998-05-27  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.5a
-	
-	* Better recovery from underflow or overflow conditions
-	
-	* Fix a deadlock condition with one thread reading and the other
-	  writing
-
-1998-05-26  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.5
-	
-	* Separate reset queue functions for play and record
-
-	* Add delays in dsp_halt
-
-1998-05-24  Andrew Veliath  <andrewtv@usa.net>
-
-	* Add a check for Linux >= 2.1.95
-	
-	* Remove DIGITAL1 input until I figure out how to make it work
-	
-	* Add HAVE_DSPCODEH which when not defined will load firmware from
-	  files using mod_firmware_load, then release memory after they
-	  are uploaded (requires reorganized OSS).
-
-1998-05-22  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.4c
-
-	* Hopefully fix the mixer volume problem
-
-1998-05-19  Andrew Veliath  <andrewtv@usa.net>
-
-	* Add __initfuncs and __initdatas to reduce resident code size
-
-	* Move bunch of code around, remove some protos
-
-	* Integrate preliminary changes for Alan Cox's OSS reorganization
-	  for non-OSS drivers to coexist with OSS devices on the same
-	  major.  To compile standalone, must now define STANDALONE.
-
-1998-05-16  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.4b
-	
-	* Integrated older card support into a unified driver, tested on a
-	  MultiSound Classic c/o Kendrick Vargas.
-
-1998-05-15  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.4
-	
-	* Fix read/write return values
-
-1998-05-13  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.3
-
-	* Stop play gracefully
-
-	* Add busy flag
-	
-	* Add major and calibrate_signal module parameters
-	
-	* Add ADC calibration
-
-	* Add some OSS compatibility ioctls
-
-	* Add mixer record selection
-	
-	* Add O_NONBLOCK support, separate read/write wait queues
-
-	* Add sample bit size ioctl, expanded sample rate ioctl
-
-	* Playback suspension now resumes
-
-	* Use signal_pending after interruptible_sleep_on
-	
-	* Add recording, change ints to bit flags
-
-1998-05-11  Andrew Veliath  <andrewtv@usa.net>
-
-	* Update version to 0.2
-
-	* Add preliminary playback support
-
-	* Use new Turtle Beach DSP code
\ No newline at end of file
diff -urN linux-2.5.6-pre3/Documentation/sound/ESS linux-2.5.6/Documentation/sound/ESS
--- linux-2.5.6-pre3/Documentation/sound/ESS	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/Documentation/sound/ESS	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-Documentation for the ESS AudioDrive chips
-
-In 2.4 kernels the SoundBlaster driver not only tries to detect an ESS chip, it
-tries to detect the type of ESS chip too. The correct detection of the chip 
-doesn't always succeed however, so unless you use the kernel isapnp facilities
-(and you chip is pnp capable) the default behaviour is 2.0 behaviour which
-means: only detect ES688 and ES1688.
-
-All ESS chips now have a recording level setting. This is a need-to-have for
-people who want to use their ESS for recording sound.
-
-Every chip that's detected as a later-than-es1688 chip has a 6 bits logarithmic
-master volume control.
-
-Every chip that's detected as a ES1887 now has Full Duplex support. Made a 
-little testprogram that shows that is works, haven't seen a real program that
-needs this however.
-
-For ESS chips an additional parameter "esstype" can be specified. This controls
-the (auto) detection of the ESS chips. It can have 3 kinds of values:
-
--1   Act like 2.0 kernels: only detect ES688 or ES1688.
-0	 Try to auto-detect the chip (may fail for ES1688)
-688  The chip will be treated as  ES688
-1688  ,,  ,,   ,,  ,,    ,,   ,, ES1688
-1868  ,,  ,,   ,,  ,,    ,,   ,, ES1868
-1869  ,,  ,,   ,,  ,,    ,,   ,, ES1869
-1788  ,,  ,,   ,,  ,,    ,,   ,, ES1788
-1887  ,,  ,,   ,,  ,,    ,,   ,, ES1887
-1888  ,,  ,,   ,,  ,,    ,,   ,, ES1888
-
-Because Full Duplex is supported for ES1887 you can specify a second DMA
-channel by specifying module parameter dma16. It can be one of: 0, 1, 3 or 5.
-
diff -urN linux-2.5.6-pre3/Documentation/sound/ESS1868 linux-2.5.6/Documentation/sound/ESS1868
--- linux-2.5.6-pre3/Documentation/sound/ESS1868	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/Documentation/sound/ESS1868	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-Documentation for the ESS1868F AudioDrive PnP sound card
-
-The ESS1868 sound card is a PnP ESS1688-compatible 16-bit sound card.
-
-It should be automatically detected by the Linux Kernel isapnp support when you
-load the sb.o module. Otherwise you should take care of:
-
-  *  The ESS1868 does not allow use of a 16-bit DMA, thus DMA 0, 1, 2, and 3
-     may only be used.
-
-  *  isapnptools version 1.14 does work with ESS1868.  Earlier versions might
-     not.
-
-  *  Sound support MUST be compiled as MODULES, not statically linked
-     into the kernel.
-
-
-NOTE: this is only needed when not using the kernel isapnp support!
-
-For configuring the sound card's I/O addresses, IRQ and DMA, here is a
-sample copy of the isapnp.conf directives regarding the ESS1868:
-
-(CONFIGURE ESS1868/-1 (LD 1
-(IO 0 (BASE 0x0220))
-(IO 1 (BASE 0x0388))
-(IO 2 (BASE 0x0330))
-(DMA 0 (CHANNEL 1))
-(INT 0 (IRQ 5 (MODE +E)))
-(ACT Y)
-))
-
-(for a full working isapnp.conf file, remember the
-(ISOLATE)
-(IDENTIFY *)
-at the beginning and the
-(WAITFORKEY)
-at the end.)
-
-In this setup, the main card I/O is 0x0220, FM synthesizer is 0x0388, and
-the MPU-401 MIDI port is located at 0x0330.  IRQ is IRQ 5, DMA is channel 1.
-
-After configuring the sound card via isapnp, to use the card you must load
-the sound modules with the proper I/O information.  Here is my setup:
-
-# ESS1868F AudioDrive initialization
-
-/sbin/modprobe sound
-/sbin/insmod uart401
-/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1
-/sbin/insmod mpu401 io=0x330
-/sbin/insmod opl3 io=0x388
-/sbin/insmod v_midi
-
-opl3 is the FM synthesizer
-/sbin/insmod opl3 io=0x388
diff -urN linux-2.5.6-pre3/Documentation/sound/INSTALL.awe linux-2.5.6/Documentation/sound/INSTALL.awe
--- linux-2.5.6-pre3/Documentation/sound/INSTALL.awe	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/Documentation/sound/INSTALL.awe	Wed Dec 31 16:00:00 1969
@@ -1,134 +0,0 @@
-================================================================
-	INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
-	Takashi Iwai	<iwai@ww.uni-erlangen.de>
-================================================================
-
-----------------------------------------------------------------
-* Attention to SB-PnP Card Users
-
-If you're using PnP cards, the initialization of PnP is required
-before loading this driver.  You have now three options:
-  1. Use isapnptools.
-  2. Use in-kernel isapnp support.
-  3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
-In this document, only the case 1 case is treated.
-
-----------------------------------------------------------------
-* Installation on Red Hat 5.0 Sound Driver
-
-Please use install-rh.sh under RedHat5.0 directory.
-DO NOT USE install.sh below.
-See INSTALL.RH for more details.
-
-----------------------------------------------------------------
-* Installation/Update by Shell Script
-
-  1. Become root
-
-	% su
-
-  2. If you have never configured the kernel tree yet, run make config
-    once (to make dependencies and symlinks).
-
-	# cd /usr/src/linux
-	# make xconfig
-    
-  3. Run install.sh script
-
-	# sh ./install.sh
-
-  4. Configure your kernel
-
-	(for Linux 2.[01].x user)
-	# cd /usr/src/linux
-	# make xconfig (or make menuconfig)
-
-	(for Linux 1.2.x user)
-	# cd /usr/src/linux
-	# make config
-
-    Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items 
-    in Sound menu.  ("lowlevel drivers" will appear only in 2.x
-    kernel.)
-
-  5. Make your kernel (and modules), and install them as usual.
-
-	5a. make kernel image
-		# make zImage
-
-	5b. make modules and install them
-		# make modules && make modules_install
-
-	5c. If you're using lilo, copy the kernel image and run lilo.
-	    Otherwise, copy the kernel image to suitable directory or
-	    media for your system.
-
-  6. Reboot the kernel if necessary.
-	- If you updated only the modules, you don't have to reboot
-	  the system.  Just remove the old sound modules here.
-		in 
-		# rmmod sound.o		(linux-2.0 or OSS/Free)
-		# rmmod awe_wave.o	(linux-2.1)
-
-  7. If your AWE card is a PnP and not initialized yet, you'll have to
-    do it by isapnp tools.  Otherwise, skip to 8.
-
-	This section described only a brief explanation.  For more
-	details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
-
-	7a. If you have no isapnp.conf file, generate it by pnpdump.
-	    Otherwise, skip to 7d.
-		# pnpdump > /etc/isapnp.conf
-
-	7b. Edit isapnp.conf file.  Comment out the appropriate
-	    lines containing desirable I/O ports, DMA and IRQs.
-	    Don't forget to enable (ACT Y) line.
-
-	7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
-	    ex)
-		(CONFIGURE CTL0048/58128 (LD 2
-		#     ANSI string -->WaveTable<--
-		  (IO 0 (BASE 0x0620))
-		  (IO 1 (BASE 0x0A20))
-		  (IO 2 (BASE 0x0E20))
-		  (ACT Y)
-		))
-
-	7d. Load the config file.
-	    CAUTION: This will reset all PnP cards!
-
-		# isapnp /etc/isapnp.conf
-
-  8. Load the sound module (if you configured it as a module):
-
-	for 2.0 kernel or OSS/Free monolithic module:
-
-		# modprobe sound.o
-
-	for 2.1 kernel:
-
-		# modprobe sound
-		# insmod uart401
-		# insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
-		(These values depend on your settings.)
-		# insmod awe_wave
-		(Be sure to load awe_wave after sb!)
-
-		See /usr/src/linux/Documentation/sound/AWE32 for
-		more details.
-
-  9. (only for obsolete systems) If you don't have /dev/sequencer
-     device file, make it according to Readme.linux file on
-     /usr/src/linux/drivers/sound. (Run a shell script included in
-     that file). <-- This file no longer exists in the recent kernels!
-
-  10. OK, load your own soundfont file, and enjoy MIDI!
-
-	% sfxload synthgm.sbk
-	% drvmidi foo.mid
-
-  11. For more advanced use (eg. dynamic loading, virtual bank and
-      etc.), please read the awedrv FAQ or the instructions in awesfx
-      and awemidi packages.
-
-Good luck!
diff -urN linux-2.5.6-pre3/Documentation/sound/Introduction linux-2.5.6/Documentation/sound/Introduction
--- linux-2.5.6-pre3/Documentation/sound/Introduction	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/Introduction	Wed Dec 31 16:00:00 1969
@@ -1,461 +0,0 @@
-Introduction	Notes on Modular Sound Drivers and Soundcore
-Wade Hampton 
-2/14/2001
-
-Purpose:  
-========
-This document provides some general notes on the modular 
-sound drivers and their configuration, along with the 
-support modules sound.o and soundcore.o.
-
-Note, some of this probably should be added to the Sound-HOWTO!
-
-Note, soundlow.o was present with 2.2 kernels but is not 
-required for 2.4.x kernels.  References have been removed
-to this.
-
-
-Copying:
-========
-none
-
-
-History:
-========
-0.1.0  11/20/1998  First version, draft
-1.0.0  11/1998     Alan Cox changes, incorporation in 2.2.0
-                   as /usr/src/linux/Documentation/sound/Introduction
-1.1.0  6/30/1999   Second version, added notes on making the drivers,
-                   added info on multiple sound cards of similar types,]
-                   added more diagnostics info, added info about esd.
-                   added info on OSS and ALSA.
-1.1.1  19991031	   Added notes on sound-slot- and sound-service.
-			(Alan Cox)
-1.1.2  20000920    Modified for Kernel 2.4 (Christoph Hellwig)
-1.1.3  20010214    Minor notes and corrections (Wade Hampton)
-                   Added examples of sound-slot-0, etc.
-
-
-Modular Sound Drivers:
-======================
-
-Thanks to the GREAT work by Alan Cox (alan@lxorguk.ukuu.org.uk),
-
-[And Oleg Drokin, Thomas Sailer, Andrew Veliath and more than a few 
- others - not to mention Hannu's original code being designed well
- enough to cope with that kind of chopping up](Alan)
-
-the standard Linux kernels support a modular sound driver.  From
-Alan's comments in linux/drivers/sound/README.FIRST:
-
-  The modular sound driver patches were funded by Red Hat Software 
-  (www.redhat.com). The sound driver here is thus a modified version of 
-  Hannu's code. Please bear that in mind when considering the appropriate
-  forums for bug reporting.
-
-The modular sound drivers may be loaded via insmod or modprobe.  
-To support all the various sound modules, there are two general 
-support modules that must be loaded first:
- 
-   soundcore.o:   Top level handler for the sound system, provides
-                  a set of functions for registration of devices
-                  by type.
-
-   sound.o:       Common sound functions required by all modules.
-
-For the specific sound modules (e.g., sb.o for the Soundblaster), 
-read the documentation on that module to determine what options
-are available, for example IRQ, address, DMA.
-
-Warning, the options for different cards sometime use different names 
-for the same or a similar feature (dma1= versus dma16=).  As a last 
-resort, inspect the code (search for MODULE_PARM).
-
-Notes:
-
-1.  There is a new OpenSource sound driver called ALSA which is
-    currently under development:  http://www.alsa-project.org/
-    The ALSA drivers support some newer hardware that may not 
-    be supported by this sound driver and also provide some 
-    additional features.
-
-2.  The commercial OSS driver may be obtained from the site:
-    http://www/opensound.com.  This may be used for cards that
-    are unsupported by the kernel driver, or may be used
-    by other operating systems.  
-
-3.  The enlightenment sound daemon may be used for playing
-    multiple sounds at the same time via a single card, eliminating
-    some of the requirements for multiple sound card systems.  For
-    more information, see:  http://www.tux.org/~ricdude/EsounD.html  
-    The "esd" program may be used with the real-player and mpeg 
-    players like mpg123 and x11amp.  The newer real-player 
-    and some games even include built-in support for ESD!
-
-
-Building the Modules:
-=====================
-
-This document does not provide full details on building the 
-kernel, etc.  The notes below apply only to making the kernel
-sound modules.   If this conflicts with the kernel's README,
-the README takes precedence. 
-
-1.  To make the kernel sound modules, cd to your /usr/src/linux
-    directory (typically) and type make config, make menuconfig, 
-    or make xconfig (to start the command line, dialog, or x-based
-    configuration tool).  
-
-2.  Select the Sound option and a dialog will be displayed.  
-
-3.  Select M (module) for "Sound card support".
-
-4.  Select your sound driver(s) as a module.  For ProAudio, Sound
-    Blaster, etc., select M (module) for OSS sound modules.
-    [thanks to Marvin Stodolsky <stodolsk@erols.com>]A
-
-5.  Make the kernel (e.g., make dep ; make bzImage), and install
-    the kernel.
-
-6.  Make the modules and install them (make modules; make modules_install).
-
-Note, for 2.4.x kernels, make sure you have the newer modutils 
-loaded or modules will not be loaded properly.  2.4.x changed the 
-layout of /lib/modules/2.4.x and requires an updated modutils.
-
-
-Plug and Play (PnP:
-===================
-
-If the sound card is an ISA PnP card, isapnp may be used
-to configure the card.  See the file isapnp.txt in the 
-directory one level up (e.g., /usr/src/linux/Documentation).
-
-Also the 2.4.x kernels provide PnP capabilities, see the 
-file NEWS in this directory.
-
-PCI sound cards are highly recommended, as they are far 
-easier to configure and from what I have read, they use
-less resources and are more CPU efficient.
-
-
-INSMOD:
-=======
-
-If loading via insmod, the common modules must be loaded in the 
-order below BEFORE loading the other sound modules.  The card-specific
-modules may then be loaded (most require parameters).  For example,
-I use the following via a shell script to load my SoundBlaster:
-
-SB_BASE=0x240
-SB_IRQ=9
-SB_DMA=3
-SB_DMA2=5
-SB_MPU=0x300
-#
-echo Starting sound
-/sbin/insmod soundcore
-/sbin/insmod sound  
-#
-echo Starting sound blaster....
-/sbin/insmod uart401
-/sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP
-
-When using sound as a module, I typically put these commands
-in a file such as /root/soundon.sh.
-
-
-MODPROBE:
-=========
-
-If loading via modprobe, these common files are automatically loaded 
-when requested by modprobe.  For example, my /etc/modules.conf contains:
-
-alias sound sb 
-options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300
-
-All you need to do to load the module is:
-
-	/sbin/modprobe sb
-
-
-Sound Status:
-=============
-
-The status of sound may be read/checked by:
-        cat (anyfile).au >/dev/audio
-
-[WWH:  This may not work properly for SoundBlaster PCI 128 cards
-such as the es1370/1 (see the es1370/1 files in this directory) 
-as they do not automatically support uLaw on /dev/audio.]
-
-The status of the modules and which modules depend on 
-which other modules may be checked by:
-	/sbin/lsmod
-
-/sbin/lsmod should show something like the following:
-	sb                     26280   0 
-	uart401                 5640   0  [sb]
-	sound                  57112   0  [sb uart401]
-	soundcore               1968   8  [sb sound]
-
-
-Removing Sound: 
-=============== 
-
-Sound may be removed by using /sbin/rmmod in the reverse order
-in which you load the modules.  Note, if a program has a sound device
-open (e.g., xmixer), that module (and the modules on which it 
-depends) may not be unloaded.
-
-For example, I use the following to remove my Soundblaster (rmmod
-in the reverse order in which I loaded the modules):
-
-/sbin/rmmod sb
-/sbin/rmmod uart401
-/sbin/rmmod sound
-/sbin/rmmod soundcore
-
-When using sound as a module, I typically put these commands
-in a script such as /root/soundoff.sh.
-
-
-Removing Sound for use with OSS: 
-================================ 
-
-If you get really stuck or have a card that the kernel modules
-will not support, you can get a commercial sound driver from
-http://www.opensound.com.  Before loading the commercial sound
-driver, you should do the following:
-
-1.  remove sound modules (detailed above)
-2.  remove the sound modules from /etc/modules.conf
-3.  move the sound modules from /lib/modules/<kernel>/misc
-    (for example, I make a /lib/modules/<kernel>/misc/tmp
-    directory and copy the sound module files to that 
-    directory).
-
-
-Multiple Sound Cards:
-=====================
-
-The sound drivers will support multiple sound cards and there
-are some great applications like multitrack that support them.  
-Typically, you need two sound cards of different types.  Note, this
-uses more precious interrupts and DMA channels and sometimes 
-can be a configuration nightmare.  I have heard reports of 3-4
-sound cards (typically I only use 2).  You can sometimes use
-multiple PCI sound cards of the same type.
-
-On my machine I have two sound cards (cs4232 and Soundblaster Vibra
-16).  By loading sound as modules, I can control which is the first
-sound device (/dev/dsp, /dev/audio, /dev/mixer) and which is 
-the second.  Normally, the cs4232 (Dell sound on the motherboard) 
-would be the first sound device, but I prefer the Soundblaster.  
-All you have to do is to load the one you want as /dev/dsp 
-first (in my case "sb") and then load the other one
-(in my case "cs4232").
-
-If you have two cards of the same type that are jumpered 
-cards or different PnP revisions, you may load the same 
-module twice.  For example, I have a SoundBlaster vibra 16
-and an older SoundBlaster 16 (jumpers).  To load the module
-twice, you need to do the following:
-
-1.  Copy the sound modules to a new name.  For example
-    sb.o could be copied (or symlinked) to sb1.o for the
-    second SoundBlaster.
-
-2.  Make a second entry in /etc/modules.conf, for example,
-    sound1 or sb1.  This second entry should refer to the
-    new module names for example sb1, and should include
-    the I/O, etc. for the second sound card.
-
-3.  Update your soundon.sh script, etc.
-
-Warning:  I have never been able to get two PnP sound cards of the
-same type to load at the same time.  I have tried this several times
-with the Soundblaster Vibra 16 cards.  OSS has indicated that this
-is a PnP problem....  If anyone has any luck doing this, please 
-send me an E-MAIL.  PCI sound cards should not have this problem.a
-Since this was originally release, I have received a couple of 
-mails from people who have accomplished this!
-
-NOTE: In Linux 2.4 the Sound Blaster driver (and only this one yet)
-supports multiple cards with one module by default.
-Read the file 'Soundblaster' in this directory for details.
-
-
-Sound Problems:
-===============
-
-First RTFM (including the troubleshooting section 
-in the Sound-HOWTO). 
-
-1)  If you are having problems loading the modules (for
-    example, if you get device conflict errors) try the
-    following:
-
-  A)  If you have Win95 or NT on the same computer,  
-      write down what addresses, IRQ, and DMA channels
-      those were using for the same hardware.  You probably 
-      can use these addresses, IRQs, and DMA channels.
-      You should really do this BEFORE attempting to get
-      sound working!
-  
-  B)  Check (cat) /proc/interrupts, /proc/ioports,
-      and /proc/dma.  Are you trying to use an address,
-      IRQ or DMA port that another device is using?
-  
-  C)  Check (cat) /proc/isapnp
-  
-  D)  Inspect your /var/log/messages file.  Often that will 
-      indicate what IRQ or IO port could not be obtained.
-  
-  E)  Try another port or IRQ.  Note this may involve 
-      using the PnP tools to move the sound card to 
-      another location.  Sometimes this is the only way 
-      and it is more or less trial and error.
-
-2)  If you get motor-boating (the same sound or part of a 
-    sound clip repeated), you probably have either an IRQ
-    or DMA conflict.  Move the card to another IRQ or DMA
-    port.  This has happened to me when playing long files 
-    when I had an IRQ conflict.
-
-3.  If you get dropouts or pauses when playing high sample
-    rate files such as using mpg123 or x11amp/xmms, you may 
-    have too slow of a CPU and may have to use the options to 
-    play the files at 1/2 speed.  For example, you may use
-    the -2 or -4 option on mpg123.  You may also get this
-    when trying to play mpeg files stored on a CD-ROM
-    (my Toshiba T8000 PII/366 sometimes has this problem).
-
-4.  If you get "cannot access device" errors, your /dev/dsp
-    files, etc. may be set to owner root, mode 600.  You 
-    may have to use the command:
-      chmod 666 /dev/dsp /dev/mixer /dev/audio
-
-5.  If you get "device busy" errors, another program has the
-    sound device open.  For example, if using the Enlightenment
-    sound daemon "esd", the "esd" program has the sound device.
-    If using "esd", please RTFM the docs on ESD.  For example,
-    esddsp <program> may be used to play files via a non-esd
-    aware program.
-
-6)  Ask for help on the sound list or send E-MAIL to the
-    sound driver author/maintainer.
-
-7)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
-
-8)  If the system reports insufficient DMA memory then you may want to
-    load sound with the "dmabufs=1" option. Or in /etc/conf.modules add
-	
-	preinstall sound dmabufs=1
-
-    This makes the sound system allocate its buffers and hang onto them.
-
-    You may also set persistent DMA when building a 2.4.x kernel.
-
-
-Configuring Sound:
-==================
-
-There are several ways of configuring your sound:
-
-1)  On the kernel command line (when using the sound driver(s)
-    compiled in the kernel). Check the driver source and
-    documentation for details.
-
-2)  On the command line when using insmod or in a bash script
-    using command line calls to load sound.
-
-3)  In /etc/modules.conf when using modprobe.
-
-4)  Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based).
-
-5)  Via the OSS soundconf program (with the commercial version
-    of the OSS driver.
-
-6)  By just loading the module and let isapnp do everything relevant
-    for you. This works only with a few drivers yet and - of course -
-    only with isapnp hardware.
-
-And I am sure, several other ways.  
-
-Anyone want to write a linuxconf module for configuring sound?
-
-
-Module Loading:
-===============
-
-When a sound card is first referenced and sound is modular, the sound system
-will ask for the sound devices to be loaded. Initially it requests that
-the driver for the sound system is loaded. It then will ask for 
-sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and
-so on). Thus you can do
-
-alias sound-slot-0 sb
-
-To load a soundblaster at this point. If the slot loading does not provide
-the desired device - for example a soundblaster does not directly provide
-a midi synth in all cases then it will request "sound-service-0-n" where n
-is
-
-  0	Mixer
-
-  2  	MIDI
-
-  3, 4	DSP audio
-
-
-For example, I use the following to load my Soundblaster PCI 128
-(ES 1371) card first, followed by my SoundBlaster Vibra 16 card,
-then by my TV card:
-
-# Load the Soundblaster PCI 128 as /dev/dsp, /dev/dsp1, /dev/mixer
-alias sound-slot-0 es1371
-
-# Load the Soundblaster Vibra 16 as /dev/dsp2, /dev/mixer1
-alias sound-slot-1 sb
-options sb io=0x240 irq=5 dma=1 dma16=5 mpu_io=0x330
-
-# Load the BTTV (TV card) as /dev/mixer2
-alias sound-slot-2 bttv
-alias sound-service-2-0 tvmixer
-
-pre-install bttv  modprobe tuner ; modprobe tvmixer
-pre-install tvmixer modprobe msp3400; modprobe tvaudio 
-options tuner debug=0 type=8 
-options bttv  card=0 radio=0 pll=0
-
-
-For More Information (RTFM):
-============================
-1)  Information on kernel modules:  linux/Documentation/modules.txt
-    and manual pages for insmod and modprobe.
-
-2)  Information on PnP, RTFM manual pages for isapnp.
-
-3)  Sound-HOWTO and Sound-Playing-HOWTO.
-
-4)  OSS's WWW site at http://www.opensound.com.
-
-5)  All the files in linux/Documentation/sound.
-
-6)  The comments and code in linux/drivers/sound.
-
-7)  The sndconfig and rhsound documentation from Red Hat.
-
-8)  The Linux-sound mailing list:  sound-list@redhat.com.
-
-9)  Enlightenment documentation (for info on esd)
-    http://www.tux.org/~ricdude/EsounD.html.
-
-10) ALSA home page:  http://www.alsa-project.org/
-
-
-Contact Information:
-====================
-Wade Hampton:  (whampton@staffnet.com)
-
diff -urN linux-2.5.6-pre3/Documentation/sound/MAD16 linux-2.5.6/Documentation/sound/MAD16
--- linux-2.5.6-pre3/Documentation/sound/MAD16	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/Documentation/sound/MAD16	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-(This recipe has been edited to update the configuration symbols.)
-
-From: Shaw Carruthers <shaw@shawc.demon.co.uk>
-
-I have been using mad16 sound for some time now with no problems, current
-kernel 2.1.89
-
-lsmod shows:
-
-mad16                   5176   0 
-sb                     22044   0  [mad16]
-uart401                 5576   0  [mad16 sb]
-ad1848                 14176   1  [mad16]
-sound                  61928   0  [mad16 sb uart401 ad1848]
-
-.config has:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_ADLIB=m
-CONFIG_SOUND_MAD16=m
-CONFIG_SOUND_YM3812=m
-
-modules.conf has:
-
-alias char-major-14 mad16
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-
-To get the built in mixer to work this needs to be:
-
-options adlib_card io=0x388     # FM synthesizer
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
-
-------------------------------------------------------------------------
-The mad16 module in addition supports the following options:
-
-option:			meaning:			default:
-joystick=0,1 		disabled, enabled 		disabled
-cdtype=0x00,0x02,0x04,	disabled, Sony CDU31A,		disabled
-       0x06,0x08,0x0a   Mitsumi, Panasonic,
-			Secondary IDE, Primary IDE 
-cdport=0x340,0x320,					0x340
-       0x330,0x360
-cdirq=0,3,5,7,9,10,11 	disabled, IRQ3, ... 		disabled
-cddma=0,5,6,7 		disabled, DMA5, ... 		DMA5 for Mitsumi or IDE
-cddma=0,1,2,3 		disabled, DMA1, ... 		DMA3 for Sony or Panasonic
-opl4=0,1 		OPL3, OPL4 			OPL3	
-
-for more details see linux/drivers/sound/mad16.c
-
-Rui Sousa
diff -urN linux-2.5.6-pre3/Documentation/sound/Maestro linux-2.5.6/Documentation/sound/Maestro
--- linux-2.5.6-pre3/Documentation/sound/Maestro	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/Documentation/sound/Maestro	Wed Dec 31 16:00:00 1969
@@ -1,123 +0,0 @@
-	An OSS/Lite Driver for the ESS Maestro family of sound cards
-
-			Zach Brown, December 1999
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
-	http://www.zabbo.net/maestro/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-ESS Maestro Chip Family
------------------------
-
-There are 3 main variants of the ESS Maestro PCI sound chip.  The first
-is the Maestro 1.  It was originally produced by Platform Tech as the
-'AGOGO'.  It can be recognized by Platform Tech's PCI ID 0x1285 with
-0x0100 as the device ID.  It was put on some sound boards and a few laptops.  
-ESS bought the design and cleaned it up as the Maestro 2.  This starts
-their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
-The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
-
-The various families of Maestro are mostly identical as far as this 
-driver is concerned.  It doesn't touch the DSP parts that differ (though
-it could for FM synthesis).
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.   This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves almost as expected.  Playback is
-supported in all the various lovely formats.  8/16bit stereo/mono from
-8khz to 48khz, and mmap()ing for playback behaves.  Capture/recording
-is limited due to oddities with the Maestro hardware.  One can only
-record in 16bit stereo.  For recording the maestro uses non interleaved
-stereo buffers so that mmap()ing the incoming data does not result in
-a ring buffer of LRLR data.  mmap()ing of the read buffers is therefore
-disallowed until this can be cleaned up.
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro.  It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro.  Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
-
-The driver doesn't support MIDI or FM playback at the moment.  Typically
-the Maestro is wired to an MPU MIDI chip, but some hardware implementations
-don't.  We need to assemble a white list of hardware implementations that
-have MIDI wired properly before we can claim to support it safely.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers.  Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
-in the config system.  
-
-It may be modular or statically linked.  If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere.  'alias sound maestro'
-should also be added to your module configs (typically /etc/conf.modules)
-if you're using modular OSS/Lite sound and want to default to using a
-maestro chip.
-
-As this is a PCI device, the module does not need to be informed of
-any IO or IRQ resources it should use, it devines these from the
-system.  Sometimes, on sucky PCs, the BIOS fails to allocated resources
-for the maestro.  This will result in a message like:
-	maestro: PCI subsystem reports IRQ 0, this might not be correct.
-from the kernel.  Should this happen the sound chip most likely will
-not operate correctly.  To solve this one has to dig through their BIOS
-(typically entered by hitting a hot key at boot time) and figure out
-what magic needs to happen so that the BIOS will reward the maestro with
-an IRQ.  This operation is incredibly system specific, so you're on your
-own.  Sometimes the magic lies in 'PNP Capable Operating System' settings.
-
-There are very few options to the driver.  One is 'debug' which will 
-tell the driver to print minimal debugging information as it runs.  This
-can be collected with 'dmesg' or through the klogd daemon.
-
-The other, more interesting option, is 'dsps_order'.  Typically at
-install time the driver will only register one available /dev/dsp device
-for its use.  The 'dsps_order' module parameter allows for more devices
-to be allocated, as a power of two.  Up to 4 devices can be registered
-( dsps_order=2 ).  These devices act as fully distinct units and use
-separate channels in the maestro.
-
-Power Management
-----------------
-
-As of version 0.14, this driver has a minimal understanding of PCI
-Power Management.  If it finds a valid power management capability
-on the PCI device it will attempt to use the power management
-functions of the maestro.  It will only do this on Maestro 2Es and
-only on machines that are known to function well.  You can
-force the use of power management by setting the 'use_pm' module
-option to 1, or can disable it entirely by setting it to 0.
-
-When using power management, the driver does a few things
-differently.  It will keep the chip in a lower power mode
-when the module is inserted but /dev/dsp is not open.  This
-allows the mixer to function but turns off the clocks
-on other parts of the chip.  When /dev/dsp is opened the chip
-is brought into full power mode, and brought back down
-when it is closed.  It also powers down the chip entirely
-when the module is removed or the machine is shutdown.  This
-can have nonobvious consequences.  CD audio may not work
-after a power managing driver is removed.  Also, software that
-doesn't understand power management may not be able to talk
-to the powered down chip until the machine goes through a hard
-reboot to bring it back.
-
-.. more details ..
-------------------
-
-drivers/sound/maestro.c contains comments that hopefully explain
-the maestro implementation.
diff -urN linux-2.5.6-pre3/Documentation/sound/Maestro3 linux-2.5.6/Documentation/sound/Maestro3
--- linux-2.5.6-pre3/Documentation/sound/Maestro3	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/Documentation/sound/Maestro3	Wed Dec 31 16:00:00 1969
@@ -1,84 +0,0 @@
-	An OSS/Lite Driver for the ESS Maestro3 family of sound chips
-
-			Zach Brown, January 2001
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
-	http://www.zabbo.net/maestro3/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-Historically I've sucked pretty hard at actually doing that, however.
-
-ESS Maestro3 Chip Family
------------------------
-
-The 'Maestro3' is much like the Maestro2 chip.  The noted improvement
-is the removal of the silicon in the '2' that did PCM mixing.  All that
-work is now done through a custom DSP called the ASSP, the Asynchronus
-Specific Signal Processor.
-
-The 'Allegro' is a baby version of the Maestro3.  I'm not entirely clear
-on the extent of the differences, but the driver supports them both :)
-
-The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
-both under ESS's vendor ID of 0x125D.  The Maestro3 can also show up as
-0x199a when hardware strapping is used.
-
-The chip can also act as a multi function device.  The modem IDs follow
-the audio multimedia device IDs.  (so the modem part of an Allegro shows
-up as 0x1989)
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.   This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves as expected.  Playback is
-supported in all the various lovely formats.  8/16bit stereo/mono from
-8khz to 48khz, with both read()/write(), and mmap().
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro3.  It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro3.  Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
-The Allegro has an onchip AC'97.
-
-The driver doesn't support MIDI or FM playback at the moment.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers.  Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
-in the config system.  
-
-It may be modular or statically linked.  If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere.  'alias sound-slot-0
-maestro3' should also be added to your module configs (typically
-/etc/modules.conf) if you're using modular OSS/Lite sound and want to
-default to using a maestro3 chip.
-
-There are very few options to the driver.  One is 'debug' which will 
-tell the driver to print minimal debugging information as it runs.  This
-can be collected with 'dmesg' or through the klogd daemon.
-
-The other is 'external_amp', which tells the driver to attempt to enable
-an external amplifier.  This defaults to '1', you can tell the driver
-not to bother enabling such an amplifier by setting it to '0'.
-
-Power Management
-----------------
-
-This driver has a minimal understanding of PCI Power Management.  It will
-try and power down the chip when the system is suspended, and power
-it up with it is resumed.  It will also try and power down the chip
-when the machine is shut down.
diff -urN linux-2.5.6-pre3/Documentation/sound/MultiSound linux-2.5.6/Documentation/sound/MultiSound
--- linux-2.5.6-pre3/Documentation/sound/MultiSound	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/MultiSound	Wed Dec 31 16:00:00 1969
@@ -1,1137 +0,0 @@
-#! /bin/sh
-#
-#  Turtle Beach MultiSound Driver Notes
-#  -- Andrew Veliath <andrewtv@usa.net>
-#
-#  Last update:                      September 10, 1998
-#  Corresponding msnd driver:        0.8.3
-#
-# ** This file is a README (top part) and shell archive (bottom part).
-#    The corresponding archived utility sources can be unpacked by
-#    running `sh MultiSound' (the utilities are only needed for the
-#    Pinnacle and Fiji cards). **
-#
-#
-#  -=-=- Getting Firmware -=-=-
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#  
-#  See the section `Obtaining and Creating Firmware Files' in this
-#  document for instructions on obtaining the necessary firmware
-#  files.
-#  
-#  
-#  Supported Features
-#  ~~~~~~~~~~~~~~~~~~
-#  
-#  Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is
-#  not currently available) and mixer functionality (/dev/mixer) are
-#  supported (memory mapped digital audio is not yet supported).
-#  Digital transfers and monitoring can be done as well if you have
-#  the digital daughterboard (see the section on using the S/PDIF port
-#  for more information).
-#
-#  Support for the Turtle Beach MultiSound Hurricane architecture is
-#  composed of the following modules (these can also operate compiled
-#  into the kernel):
-#  
-#  msnd               - MultiSound base (requires soundcore)
-#
-#  msnd_classic       - Base audio/mixer support for Classic, Monetery and
-#                       Tahiti cards
-#
-#  msnd_pinnacle      - Base audio/mixer support for Pinnacle and Fiji cards
-#  
-#  
-#  Important Notes - Read Before Using
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#  
-#  The firmware files are not included (may change in future).  You
-#  must obtain these images from Turtle Beach (they are included in
-#  the MultiSound Development Kits), and place them in /etc/sound for
-#  example, and give the full paths in the Linux configuration.  If
-#  you are compiling in support for the MultiSound driver rather than
-#  using it as a module, these firmware files must be accessible
-#  during kernel compilation.
-#
-#  Please note these files must be binary files, not assembler.  See
-#  the section later in this document for instructions to obtain these
-#  files.
-#  
-#  
-#  Configuring Card Resources
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~
-#
-#  ** This section is very important, as your card may not work at all
-#     or your machine may crash if you do not do this correctly. **
-#
-#  * Classic/Monterey/Tahiti
-#  
-#  These cards are configured through the driver msnd_classic.  You must
-#  know the io port, then the driver will select the irq and memory resources
-#  on the card.  It is up to you to know if these are free locations or now,
-#  a conflict can lock the machine up.
-#
-#  * Pinnacle/Fiji
-#
-#  The Pinnacle and Fiji cards have an extra config port, either
-#  0x250, 0x260 or 0x270.  This port can be disabled to have the card
-#  configured strictly through PnP, however you lose the ability to
-#  access the IDE controller and joystick devices on this card when
-#  using PnP.  The included pinnaclecfg program in this shell archive
-#  can be used to configure the card in non-PnP mode, and in PnP mode
-#  you can use isapnptools.  These are described briefly here.
-#
-#  pinnaclecfg is not required; you can use the msnd_pinnacle module
-#  to fully configure the card as well.  However, pinnaclecfg can be
-#  used to change the resource values of a particular device after the
-#  msnd_pinnacle module has been loaded.  If you are compiling the
-#  driver into the kernel, you must set these values during compile
-#  time, however other peripheral resource values can be changed with
-#  the pinnaclecfg program after the kernel is loaded.
-#
-#
-#  *** PnP mode
-#  
-#  Use pnpdump to obtain a sample configuration if you can; I was able
-#  to obtain one with the command `pnpdump 1 0x203' -- this may vary
-#  for you (running pnpdump by itself did not work for me).  Then,
-#  edit this file and use isapnp to uncomment and set the card values.
-#  Use these values when inserting the msnd_pinnacle module.  Using
-#  this method, you can set the resources for the DSP and the Kurzweil
-#  synth (Pinnacle).  Since Linux does not directly support PnP
-#  devices, you may have difficulty when using the card in PnP mode
-#  when it the driver is compiled into the kernel.  Using non-PnP mode
-#  is preferable in this case.
-#
-#  Here is an example mypinnacle.conf for isapnp that sets the card to
-#  io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil
-#  synth to 0x330 and irq 9 (may need editing for your system):
-#
-#  (READPORT 0x0203)
-#  (CSN 2)
-#  (IDENTIFY *)
-#  
-#  # DSP
-#  (CONFIGURE BVJ0440/-1 (LD 0
-#          (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000))
-#          (ACT Y)))
-#  
-#  # Kurzweil Synth (Pinnacle Only)
-#  (CONFIGURE BVJ0440/-1 (LD 1
-#          (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E)))
-#          (ACT Y)))
-#  
-#  (WAITFORKEY)
-#
-#
-#  *** Non-PnP mode
-#  
-#  The second way is by running the card in non-PnP mode.  This
-#  actually has some advantages in that you can access some other
-#  devices on the card, such as the joystick and IDE controller.  To
-#  configure the card, unpack this shell archive and build the
-#  pinnaclecfg program.  Using this program, you can assign the
-#  resource values to the card's devices, or disable the devices.  As
-#  an alternative to using pinnaclecfg, you can specify many of the
-#  configuration values when loading the msnd_pinnacle module (or
-#  during kernel configuration when compiling the driver into the
-#  kernel).
-#
-#  If you specify cfg=0x250 for the msnd_pinnacle module, it
-#  automatically configure the card to the given io, irq and memory
-#  values using that config port (the config port is jumper selectable
-#  on the card to 0x250, 0x260 or 0x270).
-#
-#  See the `msnd_pinnacle Additional Options' section below for more
-#  information on these parameters (also, if you compile the driver
-#  directly into the kernel, these extra parameters can be useful
-#  here).
-#
-#
-# ** It is very easy to cause problems in your machine if you choose a
-#    resource value which is incorrect. **
-#  
-#
-#  Examples
-#  ~~~~~~~~
-#  
-#  * MultiSound Classic/Monterey/Tahiti:
-#  
-#  modprobe soundcore
-#  insmod msnd
-#  insmod msnd_classic io=0x290 irq=7 mem=0xd0000
-#  
-#  * MultiSound Pinnacle in PnP mode:
-#  
-#  modprobe soundcore
-#  insmod msnd
-#  isapnp mypinnacle.conf
-#  insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values
-#  
-#  * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port,
-#    one of 0x250, 0x260 or 0x270):
-#  
-#  insmod soundcore
-#  insmod msnd
-#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000
-#  
-# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP
-#   mode, add the following (assumes you did `isapnp mypinnacle.conf'):
-#  
-#  insmod sound
-#  insmod mpu401 io=0x330 irq=9                    <-- match mypinnacle.conf values
-#  
-# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP
-#   mode, add the following.  Note how we first configure the peripheral's
-#   resources, _then_ install a Linux driver for it:
-#  
-#  insmod sound
-#  pinnaclecfg 0x250 mpu 0x330 9
-#  insmod mpu401 io=0x330 irq=9
-#
-#  -- OR you can use the following sequence without pinnaclecfg in non-PnP mode:
-#
-#  insmod soundcore
-#  insmod msnd
-#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9
-#  insmod sound
-#  insmod mpu401 io=0x330 irq=9
-#
-# * To setup the joystick port on the Pinnacle in non-PnP mode (though
-#   you have to find the actual Linux joystick driver elsewhere), you
-#   can use pinnaclecfg:
-#
-#   pinnaclecfg 0x250 joystick 0x200
-#
-#  -- OR you can configure this using msnd_pinnacle with the following:
-#
-#  insmod soundcore
-#  insmod msnd
-#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200
-#
-#  
-#  msnd_classic, msnd_pinnacle Required Options
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#  
-#  If the following options are not given, the module will not load.
-#  Examine the kernel message log for informative error messages.
-#  WARNING--probing isn't supported so try to make sure you have the
-#  correct shared memory area, otherwise you may experience problems.
-#  
-#  io                   I/O base of DSP, e.g. io=0x210
-#  irq                  IRQ number, e.g. irq=5
-#  mem                  Shared memory area, e.g. mem=0xd8000
-#  
-#  
-#  msnd_classic, msnd_pinnacle Additional Options
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#  
-#  fifosize             The digital audio FIFOs, in kilobytes.  If not
-#                       specified, the default will be used.  Increasing
-#                       this value will reduce the chance of a FIFO
-#                       underflow at the expense of increasing overall
-#                       latency.  For example, fifosize=512 will
-#                       allocate 512kB read and write FIFOs (1MB total).
-#                       While this may reduce dropouts, a heavy machine
-#                       load will undoubtedly starve the FIFO of data
-#                       and you will eventually get dropouts.  One
-#                       option is to alter the scheduling priority of
-#                       the playback process, using `nice' or some form
-#                       of POSIX soft real-time scheduling.
-#
-#  calibrate_signal     Setting this to one calibrates the ADCs to the
-#                       signal, zero calibrates to the card (defaults
-#                       to zero).
-#  
-#  
-#  msnd_pinnacle Additional Options
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#
-#  digital              Specify digital=1 to enable the S/PDIF input
-#                       if you have the digital daughterboard
-#                       adapter. This will enable access to the
-#                       DIGITAL1 input for the soundcard in the mixer.
-#                       Some mixer programs might have trouble setting
-#                       the DIGITAL1 source as an input.  If you have
-#                       trouble, you can try the setdigital.c program
-#                       at the bottom of this document.
-#
-#  cfg                  Non-PnP configuration port for the Pinnacle
-#                       and Fiji (typically 0x250, 0x260 or 0x270,
-#                       depending on the jumper configuration).  If
-#                       this option is omitted, then it is assumed
-#                       that the card is in PnP mode, and that the
-#                       specified DSP resource values are already
-#                       configured with PnP (i.e. it won't attempt to
-#                       do any sort of configuration).
-#
-#  When the Pinnacle is in non-PnP mode, you can use the following
-#  options to configure particular devices.  If a full specification
-#  for a device is not given, then the device is not configured.  Note
-#  that you still must use a Linux driver for any of these devices
-#  once their resources are setup (such as the Linux joystick driver,
-#  or the MPU401 driver from OSS for the Kurzweil synth).
-#
-#  mpu_io               I/O port of MPU (on-board Kurzweil synth)
-#  mpu_irq              IRQ of MPU (on-board Kurzweil synth)
-#  ide_io0		First I/O port of IDE controller
-#  ide_io1		Second I/O port of IDE controller
-#  ide_irq		IRQ IDE controller
-#  joystick_io          I/O port of joystick
-#  
-#  
-#  Obtaining and Creating Firmware Files
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#  
-#       For the Classic/Tahiti/Monterey
-#       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
-#  
-#  Download to /tmp and unzip the following file from Turtle Beach:
-#  
-#       ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip
-#  
-#  When unzipped, unzip the file named MsndFiles.zip.  Then copy the
-#  following firmware files to /etc/sound (note the file renaming):
-#  
-#    cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
-#    cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
-#  
-#  When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
-#  /etc/sound/msndperm.bin for the two firmware files (Linux kernel
-#  versions older than 2.2 do not ask for firmware paths, and are
-#  hardcoded to /etc/sound).
-#
-#  If you are compiling the driver into the kernel, these files must
-#  be accessible during compilation, but will not be needed later.
-#  The files must remain, however, if the driver is used as a module.
-#  
-#  
-#       For the Pinnacle/Fiji
-#       ~~~~~~~~~~~~~~~~~~~~~
-#  
-#  Download to /tmp and unzip the following file from Turtle Beach (be
-#  sure to use the entire URL; some have had trouble navigating to the
-#  URL):
-#  
-#       ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip
-#
-#  Unpack this shell archive, and run make in the created directory
-#  (you need a C compiler and flex to build the utilities).  This
-#  should give you the executables conv, pinnaclecfg and setdigital.
-#  conv is only used temporarily here to create the firmware files,
-#  while pinnaclecfg is used to configure the Pinnacle or Fiji card in
-#  non-PnP mode, and setdigital can be used to set the S/PDIF input on
-#  the mixer (pinnaclecfg and setdigital should be copied to a
-#  convenient place, possibly run during system initialization).
-#
-#  To generating the firmware files with the `conv' program, we create
-#  the binary firmware files by doing the following conversion
-#  (assuming the archive unpacked into a directory named PINNDDK):
-#  
-#    ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
-#    ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
-#  
-#  The conv (and conv.l) program is not needed after conversion and can
-#  be safely deleted.  Then, when configuring the Linux kernel, specify
-#  /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
-#  firmware files (Linux kernel versions older than 2.2 do not ask for
-#  firmware paths, and are hardcoded to /etc/sound).
-#  
-#  If you are compiling the driver into the kernel, these files must
-#  be accessible during compilation, but will not be needed later.
-#  The files must remain, however, if the driver is used as a module.
-#
-#  
-#  Using Digital I/O with the S/PDIF Port
-#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-#
-#  If you have a Pinnacle or Fiji with the digital daughterboard and
-#  want to set it as the input source, you can use this program if you
-#  have trouble trying to do it with a mixer program (be sure to
-#  insert the module with the digital=1 option, or say Y to the option
-#  during compiled-in kernel operation).  Upon selection of the S/PDIF
-#  port, you should be able monitor and record from it.
-#
-#  There is something to note about using the S/PDIF port.  Digital
-#  timing is taken from the digital signal, so if a signal is not
-#  connected to the port and it is selected as recording input, you
-#  will find PCM playback to be distorted in playback rate.  Also,
-#  attempting to record at a sampling rate other than the DAT rate may
-#  be problematic (i.e. trying to record at 8000Hz when the DAT signal
-#  is 44100Hz).  If you have a problem with this, set the recording
-#  input to analog if you need to record at a rate other than that of
-#  the DAT rate.
-#
-#
-#  -- Shell archive attached below, just run `sh MultiSound' to extract.
-#     Contains Pinnacle/Fiji utilities to convert firmware, configure
-#     in non-PnP mode, and select the DIGITAL1 input for the mixer.
-#
-#
-#!/bin/sh
-# This is a shell archive (produced by GNU sharutils 4.2).
-# To extract the files from this archive, save it to some FILE, remove
-# everything before the `!/bin/sh' line above, then type `sh FILE'.
-#
-# Made on 1998-12-04 10:07 EST by <andrewtv@ztransform.velsoft.com>.
-# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'.
-#
-# Existing files will *not* be overwritten unless `-c' is specified.
-#
-# This shar contains:
-# length mode       name
-# ------ ---------- ------------------------------------------
-#   2046 -rw-rw-r-- MultiSound.d/setdigital.c
-#  10235 -rw-rw-r-- MultiSound.d/pinnaclecfg.c
-#    106 -rw-rw-r-- MultiSound.d/Makefile
-#    141 -rw-rw-r-- MultiSound.d/conv.l
-#   1472 -rw-rw-r-- MultiSound.d/msndreset.c
-#
-save_IFS="${IFS}"
-IFS="${IFS}:"
-gettext_dir=FAILED
-locale_dir=FAILED
-first_param="$1"
-for dir in $PATH
-do
-  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
-     && ($dir/gettext --version >/dev/null 2>&1)
-  then
-    set `$dir/gettext --version 2>&1`
-    if test "$3" = GNU
-    then
-      gettext_dir=$dir
-    fi
-  fi
-  if test "$locale_dir" = FAILED && test -f $dir/shar \
-     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
-  then
-    locale_dir=`$dir/shar --print-text-domain-dir`
-  fi
-done
-IFS="$save_IFS"
-if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
-then
-  echo=echo
-else
-  TEXTDOMAINDIR=$locale_dir
-  export TEXTDOMAINDIR
-  TEXTDOMAIN=sharutils
-  export TEXTDOMAIN
-  echo="$gettext_dir/gettext -s"
-fi
-touch -am 1231235999 $$.touch >/dev/null 2>&1
-if test ! -f 1231235999 && test -f $$.touch; then
-  shar_touch=touch
-else
-  shar_touch=:
-  echo
-  $echo 'WARNING: not restoring timestamps.  Consider getting and'
-  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
-  echo
-fi
-rm -f 1231235999 $$.touch
-#
-if mkdir _sh01426; then
-  $echo 'x -' 'creating lock directory'
-else
-  $echo 'failed to create lock directory'
-  exit 1
-fi
-# ============= MultiSound.d/setdigital.c ==============
-if test ! -d 'MultiSound.d'; then
-  $echo 'x -' 'creating directory' 'MultiSound.d'
-  mkdir 'MultiSound.d'
-fi
-if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)'
-else
-  $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' &&
-/*********************************************************************
-X *
-X * setdigital.c - sets the DIGITAL1 input for a mixer
-X *
-X * Copyright (C) 1998 Andrew Veliath
-X *
-X * This program is free software; you can redistribute it and/or modify
-X * it under the terms of the GNU General Public License as published by
-X * the Free Software Foundation; either version 2 of the License, or
-X * (at your option) any later version.
-X *
-X * This program is distributed in the hope that it will be useful,
-X * but WITHOUT ANY WARRANTY; without even the implied warranty of
-X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-X * GNU General Public License for more details.
-X *
-X * You should have received a copy of the GNU General Public License
-X * along with this program; if not, write to the Free Software
-X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-X *
-X ********************************************************************/
-X
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/soundcard.h>
-X
-int main(int argc, char *argv[])
-{
-X	int fd;
-X	unsigned long recmask, recsrc;
-X
-X	if (argc != 2) {
-X		fprintf(stderr, "usage: setdigital <mixer device>\n");
-X		exit(1);
-X	}
-X
-X	if ((fd = open(argv[1], O_RDWR)) < 0) {
-X		perror(argv[1]);
-X		exit(1);
-X	}
-X
-X	if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) {
-X		fprintf(stderr, "error: ioctl read recording mask failed\n");
-X		perror("ioctl");
-X		close(fd);
-X		exit(1);
-X	}
-X
-X	if (!(recmask & SOUND_MASK_DIGITAL1)) {
-X		fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n");
-X		close(fd);
-X		exit(1);
-X	}
-X
-X	if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) {
-X		fprintf(stderr, "error: ioctl read recording source failed\n");
-X		perror("ioctl");
-X		close(fd);
-X		exit(1);
-X	}
-X
-X	recsrc |= SOUND_MASK_DIGITAL1;
-X	
-X	if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) {
-X		fprintf(stderr, "error: ioctl write recording source failed\n");
-X		perror("ioctl");
-X		close(fd);
-X		exit(1);
-X	}
-X
-X	close(fd);
-X	
-X	return 0;
-}
-SHAR_EOF
-  $shar_touch -am 1204092598 'MultiSound.d/setdigital.c' &&
-  chmod 0664 'MultiSound.d/setdigital.c' ||
-  $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed'
-e87217fc3e71288102ba41fd81f71ec4  MultiSound.d/setdigital.c
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`"
-    test 2046 -eq "$shar_count" ||
-    $echo 'MultiSound.d/setdigital.c:' 'original size' '2046,' 'current size' "$shar_count!"
-  fi
-fi
-# ============= MultiSound.d/pinnaclecfg.c ==============
-if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)'
-else
-  $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' &&
-/*********************************************************************
-X *
-X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program
-X *
-X * This is for NON-PnP mode only.  For PnP mode, use isapnptools.
-X *
-X * This is Linux-specific, and must be run with root permissions.
-X *
-X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux
-X *
-X * Copyright (C) 1998 Andrew Veliath
-X *
-X * This program is free software; you can redistribute it and/or modify
-X * it under the terms of the GNU General Public License as published by
-X * the Free Software Foundation; either version 2 of the License, or
-X * (at your option) any later version.
-X *
-X * This program is distributed in the hope that it will be useful,
-X * but WITHOUT ANY WARRANTY; without even the implied warranty of
-X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-X * GNU General Public License for more details.
-X *
-X * You should have received a copy of the GNU General Public License
-X * along with this program; if not, write to the Free Software
-X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-X *
-X ********************************************************************/
-X
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <asm/io.h>
-#include <asm/types.h>
-X
-#define IREG_LOGDEVICE		0x07
-#define IREG_ACTIVATE		0x30
-#define LD_ACTIVATE		0x01
-#define LD_DISACTIVATE		0x00
-#define IREG_EECONTROL		0x3F
-#define IREG_MEMBASEHI		0x40
-#define IREG_MEMBASELO		0x41
-#define IREG_MEMCONTROL		0x42
-#define IREG_MEMRANGEHI		0x43
-#define IREG_MEMRANGELO		0x44
-#define MEMTYPE_8BIT		0x00
-#define MEMTYPE_16BIT		0x02
-#define MEMTYPE_RANGE		0x00
-#define MEMTYPE_HIADDR		0x01
-#define IREG_IO0_BASEHI		0x60
-#define IREG_IO0_BASELO		0x61
-#define IREG_IO1_BASEHI		0x62
-#define IREG_IO1_BASELO		0x63
-#define IREG_IRQ_NUMBER		0x70
-#define IREG_IRQ_TYPE		0x71
-#define IRQTYPE_HIGH		0x02
-#define IRQTYPE_LOW		0x00
-#define IRQTYPE_LEVEL		0x01
-#define IRQTYPE_EDGE		0x00
-X
-#define HIBYTE(w)		((BYTE)(((WORD)(w) >> 8) & 0xFF))
-#define LOBYTE(w)		((BYTE)(w))
-#define MAKEWORD(low,hi)	((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
-X
-typedef __u8			BYTE;
-typedef __u16			USHORT;
-typedef __u16			WORD;
-X
-static int config_port = -1;
-X
-static int msnd_write_cfg(int cfg, int reg, int value)
-{
-X	outb(reg, cfg);
-X	outb(value, cfg + 1);
-X	if (value != inb(cfg + 1)) {
-X		fprintf(stderr, "error: msnd_write_cfg: I/O error\n");
-X		return -EIO;
-X	}
-X	return 0;
-}
-X
-static int msnd_read_cfg(int cfg, int reg)
-{
-X	outb(reg, cfg);
-X	return inb(cfg + 1);
-}
-X
-static int msnd_write_cfg_io0(int cfg, int num, WORD io)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_read_cfg_io0(int cfg, int num, WORD *io)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	
-X	*io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO),
-X		       msnd_read_cfg(cfg, IREG_IO0_BASEHI));
-X
-X	return 0;
-}
-X
-static int msnd_write_cfg_io1(int cfg, int num, WORD io)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_read_cfg_io1(int cfg, int num, WORD *io)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	
-X	*io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO),
-X		       msnd_read_cfg(cfg, IREG_IO1_BASEHI));
-X
-X	return 0;
-}
-X
-static int msnd_write_cfg_irq(int cfg, int num, WORD irq)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_read_cfg_irq(int cfg, int num, WORD *irq)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	
-X	*irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER);
-X
-X	return 0;
-}
-X
-static int msnd_write_cfg_mem(int cfg, int num, int mem)
-{
-X	WORD wmem;
-X
-X	mem >>= 8;
-X	mem &= 0xfff;
-X	wmem = (WORD)mem;
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
-X		return -EIO;
-X	if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT)))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_read_cfg_mem(int cfg, int num, int *mem)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	
-X	*mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO),
-X			msnd_read_cfg(cfg, IREG_MEMBASEHI));
-X	*mem <<= 8;
-X
-X	return 0;
-}
-X
-static int msnd_activate_logical(int cfg, int num)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_write_cfg_io0(cfg, num, io0))
-X		return -EIO;
-X	if (msnd_write_cfg_io1(cfg, num, io1))
-X		return -EIO;
-X	if (msnd_write_cfg_irq(cfg, num, irq))
-X		return -EIO;
-X	if (msnd_write_cfg_mem(cfg, num, mem))
-X		return -EIO;
-X	if (msnd_activate_logical(cfg, num))
-X		return -EIO;
-X	return 0;
-}
-X
-static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem)
-{
-X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
-X		return -EIO;
-X	if (msnd_read_cfg_io0(cfg, num, io0))
-X		return -EIO;
-X	if (msnd_read_cfg_io1(cfg, num, io1))
-X		return -EIO;
-X	if (msnd_read_cfg_irq(cfg, num, irq))
-X		return -EIO;
-X	if (msnd_read_cfg_mem(cfg, num, mem))
-X		return -EIO;
-X	return 0;
-}
-X
-static void usage(void)
-{
-X	fprintf(stderr,
-X		"\n"
-X		"pinnaclecfg 1.0\n"
-X		"\n"
-X		"usage: pinnaclecfg <config port> [device config]\n"
-X		"\n"
-X		"This is for use with the card in NON-PnP mode only.\n"
-X		"\n"
-X		"Available devices (not all available for Fiji):\n"
-X		"\n"
-X		"        Device                       Description\n"
-X		"        -------------------------------------------------------------------\n"
-X		"        reset                        Reset all devices (i.e. disable)\n"
-X		"        show                         Display current device configurations\n"
-X		"\n"
-X		"        dsp <io> <irq> <mem>         Audio device\n"
-X		"        mpu <io> <irq>               Internal Kurzweil synth\n"
-X		"        ide <io0> <io1> <irq>        On-board IDE controller\n"
-X		"        joystick <io>                Joystick port\n"
-X		"\n");
-X	exit(1);
-}
-X
-static int cfg_reset(void)
-{
-X	int i;
-X
-X	for (i = 0; i < 4; ++i)
-X		msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0);
-X	
-X	return 0;
-}
-X
-static int cfg_show(void)
-{
-X	int i;
-X	int count = 0;
-X
-X	for (i = 0; i < 4; ++i) {
-X		WORD io0, io1, irq;
-X		int mem;
-X		msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem);
-X		switch (i) {
-X		case 0:
-X			if (io0 || irq || mem) {
-X				printf("dsp 0x%x %d 0x%x\n", io0, irq, mem);
-X				++count;
-X			}
-X			break;
-X		case 1:
-X			if (io0 || irq) {
-X				printf("mpu 0x%x %d\n", io0, irq);
-X				++count;
-X			}
-X			break;
-X		case 2:
-X			if (io0 || io1 || irq) {
-X				printf("ide 0x%x 0x%x %d\n", io0, io1, irq);
-X				++count;
-X			}
-X			break;
-X		case 3:
-X			if (io0) {
-X				printf("joystick 0x%x\n", io0);
-X				++count;
-X			}
-X			break;
-X		}
-X	}
-X
-X	if (count == 0)
-X		fprintf(stderr, "no devices configured\n");
-X	
-X	return 0;
-}
-X
-static int cfg_dsp(int argc, char *argv[])
-{
-X	int io, irq, mem;
-X
-X	if (argc < 3 ||
-X	    sscanf(argv[0], "0x%x", &io) != 1 ||
-X	    sscanf(argv[1], "%d", &irq) != 1 ||
-X	    sscanf(argv[2], "0x%x", &mem) != 1)
-X		usage();
-X
-X	if (!(io == 0x290 ||
-X	      io == 0x260 ||
-X	      io == 0x250 ||
-X	      io == 0x240 ||
-X	      io == 0x230 ||
-X	      io == 0x220 ||
-X	      io == 0x210 ||
-X	      io == 0x3e0)) {
-X		fprintf(stderr, "error: io must be one of "
-X			"210, 220, 230, 240, 250, 260, 290, or 3E0\n");
-X		usage();
-X	}
-X	
-X	if (!(irq == 5 ||
-X	      irq == 7 ||
-X	      irq == 9 ||
-X	      irq == 10 ||
-X	      irq == 11 ||
-X	      irq == 12)) {
-X		fprintf(stderr, "error: irq must be one of "
-X			"5, 7, 9, 10, 11 or 12\n");
-X		usage();
-X	}
-X
-X	if (!(mem == 0xb0000 ||
-X	      mem == 0xc8000 ||
-X	      mem == 0xd0000 ||
-X	      mem == 0xd8000 ||
-X	      mem == 0xe0000 ||
-X	      mem == 0xe8000)) {
-X		fprintf(stderr, "error: mem must be one of "
-X			"0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
-X		usage();
-X	}
-X
-X	return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem);
-}
-X
-static int cfg_mpu(int argc, char *argv[])
-{
-X	int io, irq;
-X
-X	if (argc < 2 ||
-X	    sscanf(argv[0], "0x%x", &io) != 1 ||
-X	    sscanf(argv[1], "%d", &irq) != 1)
-X		usage();
-X	
-X	return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0);
-}
-X
-static int cfg_ide(int argc, char *argv[])
-{
-X	int io0, io1, irq;
-X
-X	if (argc < 3 ||
-X	    sscanf(argv[0], "0x%x", &io0) != 1 ||
-X	    sscanf(argv[0], "0x%x", &io1) != 1 ||
-X	    sscanf(argv[1], "%d", &irq) != 1)
-X		usage();
-X	
-X	return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0);
-}
-X
-static int cfg_joystick(int argc, char *argv[])
-{
-X	int io;
-X
-X	if (argc < 1 ||
-X	    sscanf(argv[0], "0x%x", &io) != 1)
-X		usage();
-X	
-X	return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0);
-}
-X
-int main(int argc, char *argv[])
-{
-X	char *device;
-X	int rv = 0;
-X
-X	--argc; ++argv;
-X
-X	if (argc < 2)
-X		usage();
-X
-X	sscanf(argv[0], "0x%x", &config_port);
-X	if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) {
-X		fprintf(stderr, "error: <config port> must be 0x250, 0x260 or 0x270\n");
-X		exit(1);
-X	}
-X	if (ioperm(config_port, 2, 1)) {
-X		perror("ioperm");
-X		fprintf(stderr, "note: pinnaclecfg must be run as root\n");
-X		exit(1);
-X	}
-X	device = argv[1];
-X
-X	argc -= 2; argv += 2;
-X
-X	if (strcmp(device, "reset") == 0)
-X		rv = cfg_reset();
-X	else if (strcmp(device, "show") == 0)
-X		rv = cfg_show();
-X	else if (strcmp(device, "dsp") == 0)
-X		rv = cfg_dsp(argc, argv);
-X	else if (strcmp(device, "mpu") == 0)
-X		rv = cfg_mpu(argc, argv);
-X	else if (strcmp(device, "ide") == 0)
-X		rv = cfg_ide(argc, argv);
-X	else if (strcmp(device, "joystick") == 0)
-X		rv = cfg_joystick(argc, argv);
-X	else {
-X		fprintf(stderr, "error: unknown device %s\n", device);
-X		usage();
-X	}
-X
-X	if (rv)
-X		fprintf(stderr, "error: device configuration failed\n");
-X	
-X	return 0;
-}
-SHAR_EOF
-  $shar_touch -am 1204092598 'MultiSound.d/pinnaclecfg.c' &&
-  chmod 0664 'MultiSound.d/pinnaclecfg.c' ||
-  $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed'
-366bdf27f0db767a3c7921d0a6db20fe  MultiSound.d/pinnaclecfg.c
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`"
-    test 10235 -eq "$shar_count" ||
-    $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10235,' 'current size' "$shar_count!"
-  fi
-fi
-# ============= MultiSound.d/Makefile ==============
-if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)'
-else
-  $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' &&
-CC	= gcc
-CFLAGS	= -O
-PROGS	= setdigital msndreset pinnaclecfg conv
-X
-all: $(PROGS)
-X
-clean:
-X	rm -f $(PROGS)
-SHAR_EOF
-  $shar_touch -am 1204092398 'MultiSound.d/Makefile' &&
-  chmod 0664 'MultiSound.d/Makefile' ||
-  $echo 'restore of' 'MultiSound.d/Makefile' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'MultiSound.d/Makefile:' 'MD5 check failed'
-76ca8bb44e3882edcf79c97df6c81845  MultiSound.d/Makefile
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`"
-    test 106 -eq "$shar_count" ||
-    $echo 'MultiSound.d/Makefile:' 'original size' '106,' 'current size' "$shar_count!"
-  fi
-fi
-# ============= MultiSound.d/conv.l ==============
-if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)'
-else
-  $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' &&
-%%
-[ \n\t,\r]
-\;.*
-DB
-[0-9A-Fa-f]+H	{ int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
-%%
-int yywrap() { return 1; }
-main() { yylex(); }
-SHAR_EOF
-  $shar_touch -am 0828231798 'MultiSound.d/conv.l' &&
-  chmod 0664 'MultiSound.d/conv.l' ||
-  $echo 'restore of' 'MultiSound.d/conv.l' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'MultiSound.d/conv.l:' 'MD5 check failed'
-d2411fc32cd71a00dcdc1f009e858dd2  MultiSound.d/conv.l
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`"
-    test 141 -eq "$shar_count" ||
-    $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!"
-  fi
-fi
-# ============= MultiSound.d/msndreset.c ==============
-if test -f 'MultiSound.d/msndreset.c' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'MultiSound.d/msndreset.c' '(file already exists)'
-else
-  $echo 'x -' extracting 'MultiSound.d/msndreset.c' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/msndreset.c' &&
-/*********************************************************************
-X *
-X * msndreset.c - resets the MultiSound card
-X *
-X * Copyright (C) 1998 Andrew Veliath
-X *
-X * This program is free software; you can redistribute it and/or modify
-X * it under the terms of the GNU General Public License as published by
-X * the Free Software Foundation; either version 2 of the License, or
-X * (at your option) any later version.
-X *
-X * This program is distributed in the hope that it will be useful,
-X * but WITHOUT ANY WARRANTY; without even the implied warranty of
-X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-X * GNU General Public License for more details.
-X *
-X * You should have received a copy of the GNU General Public License
-X * along with this program; if not, write to the Free Software
-X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-X *
-X ********************************************************************/
-X
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/soundcard.h>
-X
-int main(int argc, char *argv[])
-{
-X	int fd;
-X
-X	if (argc != 2) {
-X		fprintf(stderr, "usage: msndreset <mixer device>\n");
-X		exit(1);
-X	}
-X
-X	if ((fd = open(argv[1], O_RDWR)) < 0) {
-X		perror(argv[1]);
-X		exit(1);
-X	}
-X
-X	if (ioctl(fd, SOUND_MIXER_PRIVATE1, 0) < 0) {
-X		fprintf(stderr, "error: msnd ioctl reset failed\n");
-X		perror("ioctl");
-X		close(fd);
-X		exit(1);
-X	}
-X
-X	close(fd);
-X	
-X	return 0;
-}
-SHAR_EOF
-  $shar_touch -am 1204100698 'MultiSound.d/msndreset.c' &&
-  chmod 0664 'MultiSound.d/msndreset.c' ||
-  $echo 'restore of' 'MultiSound.d/msndreset.c' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'MultiSound.d/msndreset.c:' 'MD5 check failed'
-c52f876521084e8eb25e12e01dcccb8a  MultiSound.d/msndreset.c
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/msndreset.c'`"
-    test 1472 -eq "$shar_count" ||
-    $echo 'MultiSound.d/msndreset.c:' 'original size' '1472,' 'current size' "$shar_count!"
-  fi
-fi
-rm -fr _sh01426
-exit 0
diff -urN linux-2.5.6-pre3/Documentation/sound/NEWS linux-2.5.6/Documentation/sound/NEWS
--- linux-2.5.6-pre3/Documentation/sound/NEWS	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/Documentation/sound/NEWS	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-Linux 2.4 Sound Changes
-2000-September-25
-Christoph Hellwig, <hch@infradead.org>
-
-
-
-=== isapnp support
-
-The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
-Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
-detecting and configuring isapnp devices.
-If you have a not yet supported isapnp soundcard, mail me the content
-of '/proc/isapnp' on your system and some information about your card
-and its driver(s) so I can try to get isapnp working for it.
-
-
-
-=== soundcard resources on kernel commandline
-
-Before Linux 2.4 you had to specify the resources for sounddrivers
-statically linked into the kernel at compile time
-(in make config/menuconfig/xconfig). In Linux 2.4 the ressources are
-now specified at the boot-time kernel commandline (e.g. the lilo
-'append=' line or everything that's after the kernel name in grub).
-Read the Configure.help entry for your card for the parameters.
-
-
-=== softoss is gone
-
-In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
-Use a user space software synthesizer like timidity instead.
-
-
-
-=== /dev/sndstat and /proc/sound are gone
-
-In older Linux versions those files exported some information about the
-OSS/Free configuration to userspace. In Linux 2.3 they were removed because
-they did not support the growing number of pci soundcards and there were
-some general problems with this interface.
-
-
diff -urN linux-2.5.6-pre3/Documentation/sound/NM256 linux-2.5.6/Documentation/sound/NM256
--- linux-2.5.6-pre3/Documentation/sound/NM256	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/Documentation/sound/NM256	Wed Dec 31 16:00:00 1969
@@ -1,280 +0,0 @@
-=======================================================
-Documentation for the NeoMagic 256AV/256ZX sound driver
-=======================================================
-
-You're looking at version 1.1 of the driver.  (Woohoo!) It has been
-successfully tested against the following laptop models:
-
-	Sony Z505S/Z505SX/Z505DX/Z505RX
-	Sony F150, F160, F180, F250, F270, F280, PCG-F26
-	Dell Latitude CPi, CPt (various submodels)
-
-There are a few caveats, which is why you should read the entirety of
-this document first.
-
-This driver was developed without any support or assistance from
-NeoMagic.  There is no warranty, expressed, implied, or otherwise.  It
-is free software in the public domain; feel free to use it, sell it,
-give it to your best friends, even claim that you wrote it (but why?!)
-but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
-when it blows up your computer.
-
-Version 1.1 contains a change to try and detect non-AC97 versions of
-the hardware, and not install itself appropriately.  It should also
-reinitialize the hardware on an APM resume event, assuming that APM
-was configured into your kernel.
-
-============
-Installation
-============
-
-Enable the sound drivers, the OSS sound drivers, and then the NM256
-driver.  The NM256 driver *must* be configured as a module (it won't
-give you any other choice).
-
-Next, do the usual "make modules" and "make modules_install".
-Finally, insmod the soundcore, sound and nm256 modules.
-
-When the nm256 driver module is loaded, you should see a couple of
-confirmation messages in the kernel logfile indicating that it found
-the device (the device does *not* use any I/O ports or DMA channels).
-Now try playing a wav file, futz with the CD-ROM if you have one, etc.
-
-The NM256 is entirely a PCI-based device, and all the necessary
-information is automatically obtained from the card.  It can only be
-configured as a module in a vain attempt to prevent people from
-hurting themselves.  It works correctly if it shares an IRQ with
-another device (it normally shares IRQ 9 with the builtin eepro100
-ethernet on the Sony Z505 laptops). 
-
-It does not run the card in any sort of compatibility mode. It will
-not work on laptops that have the SB16-compatible, AD1848-compatible
-or CS4232-compatible codec/mixer; you will want to use the appropriate
-compatible OSS driver with these chipsets.  I cannot provide any
-assistance with machines using the SB16, AD1848 or CS4232 compatible
-versions.  (The driver now attempts to detect the mixer version, and
-will refuse to load if it believes the hardware is not
-AC97-compatible.)
-
-The sound support is very basic, but it does include simultaneous
-playback and record capability.  The mixer support is also quite
-simple, although this is in keeping with the rather limited
-functionality of the chipset.
-
-There is no hardware synthesizer available, as the Losedows OPL-3 and
-MIDI support is done via hardware emulation.
-
-Only three recording devices are available on the Sony: the
-microphone, the CD-ROM input, and the volume device (which corresponds
-to the stereo output).  (Other devices may be available on other
-models of laptops.)  The Z505 series does not have a builtin CD-ROM,
-so of course the CD-ROM input doesn't work.  It does work on laptops
-with a builtin CD-ROM drive.
-
-The mixer device does not appear to have any tone controls, at least
-on the Z505 series.  The mixer module checks for tone controls in the
-AC97 mixer, and will enable them if they are available.
-
-==============
-Known problems
-==============
-
-  * There are known problems with PCMCIA cards and the eepro100 ethernet 
-    driver on the Z505S/Z505SX/Z505DX.  Keep reading.
-
-  * There are also potential problems with using a virtual X display, and
-    also problems loading the module after the X server has been started. 
-    Keep reading.
-
-  * The volume control isn't anywhere near linear.  Sorry.  This will be
-    fixed eventually, when I get sufficiently annoyed with it.  (I doubt
-    it will ever be fixed now, since I've never gotten sufficiently
-    annoyed with it and nobody else seems to care.)
-
-  * There are reports that the CD-ROM volume is very low.  Since I do not
-    have a CD-ROM equipped laptop, I cannot test this (it's kinda hard to
-    do remotely).
-
-  * Only 8 fixed-rate speeds are supported.  This is mainly a chipset
-    limitation.  It may be possible to support other speeds in the future.
-
-  * There is no support for the telephone mixer/codec.  There is support
-    for a phonein/phoneout device in the mixer driver;  whether or not 
-    it does anything is anyone's guess.  (Reports on this would be
-    appreciated.  You'll have to figure out how to get the phone to
-    go off-hook before it'll work, tho.)
-
-  * This driver was not written with any cooperation or support from
-    NeoMagic.  If you have any questions about this, see their website
-    for their official stance on supporting open source drivers.
-
-============
-Video memory
-============
-
-The NeoMagic sound engine uses a portion of the display memory to hold
-the sound buffer.  (Crazy, eh?)  The NeoMagic video BIOS sets up a
-special pointer at the top of video RAM to indicate where the top of
-the audio buffer should be placed.
-
-At the present time XFree86 is apparently not aware of this.  It will
-thus write over either the pointer or the sound buffer with abandon.
-(Accelerated-X seems to do a better job here.)
-
-This implies a few things:
-
-  * Sometimes the NM256 driver has to guess at where the buffer 
-    should be placed, especially if the module is loaded after the
-    X server is started.  It's usually correct, but it will consistently
-    fail on the Sony F250.
-
-  * Virtual screens greater than 1024x768x16 under XFree86 are
-    problematic on laptops with only 2.5MB of screen RAM. This
-    includes all of the 256AV-equipped laptops.  (Virtual displays
-    may or may not work on the 256ZX, which has at least 4MB of
-    video RAM.)
-
-If you start having problems with random noise being output either
-constantly (this is the usual symptom on the F250), or when windows
-are moved around (this is the usual symptom when using a virtual
-screen), the best fix is to
-
-  * Don't use a virtual frame buffer.
-  * Make sure you load the NM256 module before the X server is
-    started.
-
-On the F250, it is possible to force the driver to load properly even
-after the XFree86 server is started by doing:
-
-	insmod nm256 buffertop=0x25a800
-
-This forces the audio buffers to the correct offset in screen RAM.
-
-One user has reported a similar problem on the Sony F270, although
-others apparently aren't seeing any problems.  His suggested command
-is
-
-	insmod nm256 buffertop=0x272800
-
-=================
-Official WWW site
-=================
-
-The official site for the NM256 driver is:
-
-	http://www.uglx.org/sony.html
-
-You should always be able to get the latest version of the driver there,
-and the driver will be supported for the foreseeable future.
-
-==============
-Z505RX and IDE
-==============
-
-There appears to be a problem with the IDE chipset on the Z505RX; one
-of the symptoms is that sound playback periodically hangs (when the
-disk is accessed).  The user reporting the problem also reported that
-enabling all of the IDE chipset workarounds in the kernel solved the
-problem, tho obviously only one of them should be needed--if someone
-can give me more details I would appreciate it.
-
-==============================
-Z505S/Z505SX on-board Ethernet
-==============================
-
-If you're using the on-board Ethernet Pro/100 ethernet support on the Z505
-series, I strongly encourage you to download the latest eepro100 driver from
-Donald Becker's site:
-
-	ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/test/eepro100.c
-
-There was a reported problem on the Z505SX that if the ethernet
-interface is disabled and reenabled while the sound driver is loaded,
-the machine would lock up.  I have included a workaround that is
-working satisfactorily.  However, you may occasionally see a message
-about "Releasing interrupts, over 1000 bad interrupts" which indicates
-that the workaround is doing its job.
-
-==================================
-PCMCIA and the Z505S/Z505SX/Z505DX
-==================================
-
-There is also a known problem with the Sony Z505S and Z505SX hanging
-if a PCMCIA card is inserted while the ethernet driver is loaded, or
-in some cases if the laptop is suspended.  This is caused by tons of
-spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
-
-There is currently no fix for the problem that works in every case.
-The only known workarounds are to disable the ethernet interface
-before inserting or removing a PCMCIA card, or with some cards
-disabling the PCMCIA card before ejecting it will also help the
-problem with the laptop hanging when the card is ejected.
-
-One user has reported that setting the tcic's cs_irq to some value
-other than 9 (like 11) fixed the problem.  This doesn't work on my
-Z505S, however--changing the value causes the cardmgr to stop seeing
-card insertions and removals, cards don't seem to work correctly, and
-I still get hangs if a card is inserted when the kernel is booted.
-
-Using the latest ethernet driver and pcmcia package allows me to
-insert an Adaptec 1480A SlimScsi card without the laptop hanging,
-although I still have to shut down the card before ejecting or
-powering down the laptop.  However, similar experiments with a DE-660
-ethernet card still result in hangs when the card is inserted.  I am
-beginning to think that the interrupts are CardBus-related, since the
-Adaptec card is a CardBus card, and the DE-660 is not; however, I
-don't have any other CardBus cards to test with.
-
-======
-Thanks
-======
-
-First, I want to thank everyone (except NeoMagic of course) for their
-generous support and encouragement.  I'd like to list everyone's name
-here that replied during the development phase, but the list is
-amazingly long.
-
-I will be rather unfair and single out a few people, however:
-
-	Justin Maurer, for being the first random net.person to try it,
-	and for letting me login to his Z505SX to get it working there
-
-	Edi Weitz for trying out several different versions, and giving
-	me a lot of useful feedback
-
-	Greg Rumple for letting me login remotely to get the driver 
-	functional on the 256ZX, for his assistance on tracking
-	down all sorts of random stuff, and for trying out Accel-X
-
-	Zach Brown, for the initial AC97 mixer interface design
-
-	Jeff Garzik, for various helpful suggestions on the AC97
-	interface
-
-	"Mr. Bumpy" for feedback on the Z505RX
-
-	Bill Nottingham, for generous assistance in getting the mixer ID
-	code working
-
-=================
-Previous versions
-=================
-
-Versions prior to 0.3 (aka `noname') had problems with weird artifacts
-in the output and failed to set the recording rate properly.  These
-problems have long since been fixed.
-
-Versions prior to 0.5 had problems with clicks in the output when
-anything other than 16-bit stereo sound was being played, and also had
-periodic clicks when recording.
-
-Version 0.7 first incorporated support for the NM256ZX chipset, which
-is found on some Dell Latitude laptops (the CPt, and apparently
-some CPi models as well).  It also included the generic AC97
-mixer module.
-
-Version 0.75 renamed all the functions and files with slightly more
-generic names.
-
-Note that previous versions of this document claimed that recording was
-8-bit only; it actually has been working for 16-bits all along.
diff -urN linux-2.5.6-pre3/Documentation/sound/OPL3 linux-2.5.6/Documentation/sound/OPL3
--- linux-2.5.6-pre3/Documentation/sound/OPL3	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/Documentation/sound/OPL3	Wed Dec 31 16:00:00 1969
@@ -1,6 +0,0 @@
-A pure OPL3 card is nice and easy to configure. Simply do
-
-insmod opl3 io=0x388
-
-Change the I/O address in the very unlikely case this card is differently
-configured
diff -urN linux-2.5.6-pre3/Documentation/sound/OPL3-SA linux-2.5.6/Documentation/sound/OPL3-SA
--- linux-2.5.6-pre3/Documentation/sound/OPL3-SA	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/OPL3-SA	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-OPL3-SA1 sound driver (opl3sa.o)
-
----
-Note: This howto only describes how to setup the OPL3-SA1 chip; this info
-does not apply to the SA2, SA3, or SA4. 
----
-
-The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
-it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
-and OPL3 FM Synth capabilities.
-
-You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
-CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
-
-You'll need to know all of the relevant info (irq, dma, and io port) for the
-chip's WSS mode, since that is the mode the kernel sound driver uses, and of
-course you'll also need to know about where the MPU401 and OPL3 ports and
-IRQs are if you want to use those.
-
-Here's the skinny on how to load it as a module:
-
-	modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
-
-Module options in detail:
-
-	io:	This is the WSS's port base.
-	irq:	This is the WSS's IRQ.
-	dma:	This is the WSS's DMA line. In my BIOS setup screen this was
-		listed as "WSS Play DMA"
-	dma2:	This is the WSS's secondary DMA line. My BIOS calls it the
-		"WSS capture DMA"
-	
-	mpu_io:	This is the MPU401's port base.
-	mpu_irq: This is the MPU401's IRQ.
-
-If you'd like to use the OPL3 FM Synthesizer, make sure you enable
-CONFIG_YM3812 (in 'make config'). That'll build the opl3.o module.
-
-Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
-
-You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
-Here's how:
-
-Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
-
-If you said yes, the software synth is available once you boot your new
-kernel.
-
-If you chose to build it as a module, just insmod the resulting softoss2.o
-
-Questions? Comments?
-<stiker@northlink.com>
diff -urN linux-2.5.6-pre3/Documentation/sound/OPL3-SA2 linux-2.5.6/Documentation/sound/OPL3-SA2
--- linux-2.5.6-pre3/Documentation/sound/OPL3-SA2	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/Documentation/sound/OPL3-SA2	Wed Dec 31 16:00:00 1969
@@ -1,210 +0,0 @@
-Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
----------------------------------------------------------------
-
-Scott Murray, scott@spiteful.org
-January 7, 2001
-
-NOTE: All trade-marked terms mentioned below are properties of their
-      respective owners.
-
-
-Supported Devices
------------------
-
-This driver is for PnP soundcards based on the following Yamaha audio
-controller chipsets:
-
-YMF711 aka OPL3-SA2
-YMF715 and YMF719 aka OPL3-SA3
-
-Up until recently (December 2000), I'd thought the 719 to be a
-different chipset, the OPL3-SAx.  After an email exhange with
-Yamaha, however, it turns out that the 719 is just a re-badged
-715, and the chipsets are identical.  The chipset detection code
-has been updated to reflect this.
-
-Anyways, all of these chipsets implement the following devices:
-
-OPL3 FM synthesizer
-Soundblaster Pro
-Microsoft/Windows Sound System
-MPU401 MIDI interface
-
-Note that this driver uses the MSS device, and to my knowledge these
-chipsets enforce an either/or situation with the Soundblaster Pro
-device and the MSS device.  Since the MSS device has better
-capabilities, I have implemented the driver to use it.
-
-
-Mixer Channels
---------------
-
-Older versions of this driver (pre-December 2000) had two mixers,
-an OPL3-SA2 or SA3 mixer and a MSS mixer.  The OPL3-SA[23] mixer
-device contained a superset of mixer channels consisting of its own
-channels and all of the MSS mixer channels.  To simplify the driver
-considerably, and to partition functionality better, the OPL3-SA[23]
-mixer device now contains has its own specific mixer channels.  They
-are:
-
-Volume     - Hardware master volume control
-Bass       - SA3 only, now supports left and right channels
-Treble     - SA3 only, now supports left and right channels
-Microphone - Hardware microphone input volume control
-Digital1   - Yamaha 3D enhancement "Wide" mixer
-
-All other mixer channels (e.g. "PCM", "CD", etc.) now have to be
-controlled via the "MS Sound System (CS4231)" mixer.  To facilitate
-this, the mixer device creation order has been switched so that
-the MSS mixer is created first.  This allows accessing the majority
-of the useful mixer channels even via single mixer-aware tools
-such as "aumix".
-
-
-Plug 'n Play
-------------
-
-In previous kernels (2.2.x), some configuration was required to
-get the driver to talk to the card.  Being the new millennium and
-all, the 2.4.x kernels now support auto-configuration if ISA PnP
-support is configured in.  Theoretically, the driver even supports
-having more than one card in this case.
-
-With the addition of PnP support to the driver, two new parameters
-have been added to control it:
-
-isapnp   - set to 0 to disable ISA PnP card detection
-
-multiple - set to 0 to disable multiple PnP card detection
-
-
-Optional Parameters
--------------------
-
-Recent (December 2000) additions to the driver (based on a patch
-provided by Peter Englmaier) are two new parameters:
-
-ymode -    Set Yamaha 3D enhancement mode:
-           0 = Desktop/Normal  5-12 cm speakers
-           1 = Notebook PC (1) 3 cm speakers
-           2 = Notebook PC (2) 1.5 cm speakers
-           3 = Hi-Fi           16-38 cm speakers
-
-loopback - Set A/D input source. Useful for echo cancellation:
-           0 = Mic Right channel (default)
-           1 = Mono output loopback
-
-The ymode parameter has been tested and does work.  The loopback
-parameter, however, is untested.  Any feedback on its usefulness
-would be appreciated.
-
-
-Manual Configuration
---------------------
-
-If for some reason you decide not to compile ISA PnP support into
-your kernel, or disabled the driver's usage of it by setting the
-isapnp parameter as discussed above, then you will need to do some
-manual configuration.  There are two ways of doing this.  The most
-common is to use the isapnptools package to initialize the card, and
-use the kernel module form of the sound subsystem and sound drivers.
-Alternatively, some BIOS's allow manual configuration of installed
-PnP devices in a BIOS menu, which should allow using the non-modular
-sound drivers, i.e. built into the kernel.
-
-I personally use isapnp and modules, and do not have access to a PnP
-BIOS machine to test.  If you have such a beast, configuring the
-driver to be built into the kernel should just work (thanks to work
-done by David Luyer <luyer@ucs.uwa.edu.au>).  You will still need
-to specify settings, which can be done by adding:
-
-opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>
-
-to the kernel command line.  For example:
-
-opl3sa2=0x370,5,0,1,0x530,0x330
-
-If you are instead using the isapnp tools (as most people have been
-before Linux 2.4.x), follow the directions in their documentation to
-produce a configuration file.  Here is the relevant excerpt I used to
-use for my SA3 card from my isapnp.conf:
-
-(CONFIGURE YMH0800/-1 (LD 0
-
-# NOTE: IO 0 is for the unused SoundBlaster part of the chipset.
-(IO 0 (BASE 0x0220))
-(IO 1 (BASE 0x0530))
-(IO 2 (BASE 0x0388))
-(IO 3 (BASE 0x0330))
-(IO 4 (BASE 0x0370))
-(INT 0 (IRQ 5 (MODE +E)))
-(DMA 0 (CHANNEL 0))
-(DMA 1 (CHANNEL 1))
-
-Here, note that:
-
-Port  Acceptable Range  Purpose
-----  ----------------  -------
-IO 0  0x0220 - 0x0280   SB base address, unused.
-IO 1  0x0530 - 0x0F48   MSS base address
-IO 2  0x0388 - 0x03F8   OPL3 base address
-IO 3  0x0300 - 0x0334   MPU base address
-IO 4  0x0100 - 0x0FFE   card's own base address for its control I/O ports
-
-The IRQ and DMA values can be any that are considered acceptable for a
-MSS.  Assuming you've got isapnp all happy, then you should be able to
-do something like the following (which matches up with the isapnp
-configuration above):
-
-modprobe mpu401
-modprobe ad1848
-modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1
-modprobe opl3 io=0x388
-
-See the section "Automatic Module Loading" below for how to set up
-/etc/modules.conf to automate this.
-
-An important thing to remember that the opl3sa2 module's io argument is
-for it's own control port, which handles the card's master mixer for
-volume (on all cards), and bass and treble (on SA3 cards).
-
-
-Troubleshooting
----------------
-
-If all goes well and you see no error messages, you should be able to
-start using the sound capabilities of your system.  If you get an
-error message while trying to insert the opl3sa2 module, then make
-sure that the values of the various arguments match what you specified
-in your isapnp configuration file, and that there is no conflict with
-another device for an I/O port or interrupt.  Checking the contents of
-/proc/ioports and /proc/interrupts can be useful to see if you're
-butting heads with another device.
-
-If you still cannot get the module to load, look at the contents of
-your system log file, usually /var/log/messages.  If you see the
-message "opl3sa2: Unknown Yamaha audio controller version", then you
-have a different chipset version than I've encountered so far.  Look
-for all messages in the log file that start with "opl3sa2: " and see
-if they provide any clues.  If you do not see the chipset version
-message, and none of the other messages present in the system log are
-helpful, email me some details and I'll try my best to help.
-
-
-Automatic Module Loading
-------------------------
-
-Lastly, if you're using modules and want to set up automatic module
-loading with kmod, the kernel module loader, here is the section I
-currently use in my modules.conf file:
-
-# Sound
-alias sound-slot-0 opl3sa2
-options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
-options opl3 io=0x388
-
-That's all it currently takes to get an OPL3-SA3 card working on my
-system.  Once again, if you have any other problems, email me at the
-address listed above.
-
-Scott
diff -urN linux-2.5.6-pre3/Documentation/sound/Opti linux-2.5.6/Documentation/sound/Opti
--- linux-2.5.6-pre3/Documentation/sound/Opti	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/Documentation/sound/Opti	Wed Dec 31 16:00:00 1969
@@ -1,222 +0,0 @@
-Support for the OPTi 82C931 chip
---------------------------------
-Note: parts of this README file apply also to other
-cards that use the mad16 driver.
-
-Some items in this README file are based on features
-added to the sound driver after Linux-2.1.91 was out.
-By the time of writing this I do not know which official
-kernel release will include these features.
-Please do not report inconsistencies on older Linux
-kernels.
-
-The OPTi 82C931 is supported in its non-PnP mode.
-Usually you do not need to set jumpers, etc. The sound driver
-will check the card status and if it is required it will
-force the card into a mode in which it can be programmed.
-
-If you have another OS installed on your computer it is recommended
-that Linux and the other OS use the same resources.
-
-Also, it is recommended that resources specified in /etc/modules.conf
-and resources specified in /etc/isapnp.conf agree.
-
-Compiling the sound driver
---------------------------
-I highly recommend that you build a modularized sound driver.
-This document does not cover a sound-driver which is built in
-the kernel.
-
-Sound card support should be enabled as a module (chose m).
-Answer 'm' for  these items:
-  Generic OPL2/OPL3 FM synthesizer support		(CONFIG_SOUND_ADLIB)
-  Microsoft Sound System support			(CONFIG_SOUND_MSS)
-  Support for OPTi MAD16 and/or Mozart based cards	(CONFIG_SOUND_MAD16)
-  FM synthesizer (YM3812/OPL-3) support			(CONFIG_SOUND_YM3812)
-
-The configuration menu may ask for addresses, IRQ lines or DMA
-channels. If the card is used as a module the module loading
-options will override these values.
-
-For the OPTi 931 you can answer 'n' to:
-  Support MIDI in older MAD16 based cards (requires SB)	(CONFIG_SOUND_MAD16_OLDCARD)
-If you do need MIDI support in a Mozart or C928 based card you
-need to answer 'm' to the above question. In that case you will
-also need to answer 'm' to:
-  '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB)
-
-Go on and compile your kernel and modules. Install the modules. Run depmod -a.
-
-Using isapnptools
------------------
-In most systems with a PnP BIOS you do not need to use isapnp. The
-initialization provided by the BIOS is sufficient for the driver
-to pick up the card and continue initialization.
-
-If that fails, or if you have other PnP cards, you need to use isapnp
-to initialize the card.
-This was tested with isapnptools-1.11 but I recommend that you use
-isapnptools-1.13 (or newer). Run pnpdump to dump the information
-about your PnP cards. Then edit the resulting file and select
-the options of your choice. This file is normally installed as
-/etc/isapnp.conf.
-
-The driver has one limitation with respect to I/O port resources:
-IO3 base must be 0x0E0C.  Although isapnp allows other ports, this
-address is hard-coded into the driver.
-
-Using kmod and autoloading the sound driver
--------------------------------------------
-Comment: as of linux-2.1.90 kmod is replacing kerneld.
-The config file '/etc/modules.conf' is used as before.
-
-This is the sound part of my /etc/modules.conf file.
-Following that I will explain each line.
-
-alias mixer0 mad16
-alias audio0 mad16
-alias midi0  mad16
-alias synth0 opl3
-options sb mad16=1
-options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
-options opl3 io=0x388
-post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
-
-If you have an MPU daughtercard or onboard MPU you will want to add to the
-"options mad16" line - eg 
-
-options mad16 irq=5 dma=0 dma16=3 io=0x530 mpu_io=0x330 mpu_irq=9
-
-To set the I/O and IRQ of the MPU.
-
-
-Explain:
-
-alias mixer0 mad16
-alias audio0 mad16
-alias midi0  mad16
-alias synth0 opl3
-
-When any sound device is opened the kernel requests auto-loading
-of char-major-14. There is a built-in alias that translates this
-request to loading the main sound module.
-
-The sound module in its turn will request loading of a sub-driver
-for mixer, audio, midi or synthesizer device. The first 3 are
-supported by the mad16 driver. The synth device is supported
-by the opl3 driver.
-
-There is currently no way to autoload the sound device driver
-if more than one card is installed.
-
-options sb mad16=1
-
-This is left for historical reasons. If you enable the
-config option 'Support MIDI in older MAD16 based cards (requires SB)'
-or if you use an older mad16 driver it will force loading of the
-SoundBlaster driver. This option tells the SB driver not to look
-for a SB card but to wait for the mad16 driver.
-
-options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
-options opl3 io=0x388
-
-post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
-
-This sets resources and options for the mad16 and opl3 drivers.
-I use two DMA channels (only one is required) to enable full duplex.
-joystick=1 enables the joystick port. cdtype=0 disables the cd port.
-You can also set mpu_io and mpu_irq in the mad16 options for the
-uart401 driver.
-
-This tells modprobe to run /sbin/ad1848_mixer_reroute after
-mad16 is successfully loaded and initialized. The source
-for ad1848_mixer_reroute is appended to the end of this readme
-file. It is impossible for the sound driver to know the actual
-connections to the mixer. The 3 inputs intended for cd, synth
-and line-in are mapped to the generic inputs line1, line2 and
-line3. This program reroutes these mixer channels to their
-right names (note the right mapping depends on the actual sound
-card that you use).
-The numeric parameters mean:
- 14=line1 8=cd    - reroute line1 to the CD input.
- 15=line2 3=synth - reroute line2 to the synthesizer input.
- 16=line3 6=line  - reroute line3 to the line input.
-For reference on other input names look at the file
-/usr/include/linux/soundcard.h.
-
-Using a joystick
------------------
-You must enable a joystick in the mad16 options. (also
-in /etc/isapnp.conf if you use it).
-Tested with regular analog joysticks.
-
-A CDROM drive connected to the sound card
------------------------------------------
-The 82C931 chip has support only for secondary ATAPI cdrom.
-(cdtype=8). Loading the mad16 driver resets the C931 chip
-and if a cdrom was already mounted it may cause a complete
-system hang. Do not use the sound card if you have an alternative.
-If you do use the sound card it is important that you load
-the mad16 driver (use "modprobe mad16" to prevent auto-unloading)
-before the cdrom is accessed the first time.
-
-Using the sound driver built-in to the kernel may help here, but...
-Most new systems have a PnP BIOS and also two IDE controllers.
-The IDE controller on the sound card may be needed only on older
-systems (which have only one IDE controller) but these systems
-also do not have a PnP BIOS - requiring isapnptools and a modularized
-driver.
-
-Known problems
---------------
-1. See the section on "A CDROM drive connected to the sound card".
-
-2. On my system the codec cannot capture companded sound samples.
-   (eg., recording from /dev/audio). When any companded capture is
-   requested I get stereo-16 bit samples instead. Playback of
-   companded samples works well. Apparently this problem is not common
-   to all C931 based cards. I do not know how to identify cards that
-   have this problem.
-
-Source for ad1848_mixer_reroute.c
----------------------------------
-#include <stdio.h>
-#include <fcntl.h>
-#include <linux/soundcard.h>
-
-static char *mixer_names[SOUND_MIXER_NRDEVICES] =
-	SOUND_DEVICE_LABELS;
-
-int
-main(int argc, char **argv) {
-	int val, from, to;
-	int i, fd;
-
-	fd = open("/dev/mixer", O_RDWR);
-	if(fd < 0) {
-		perror("/dev/mixer");
-		return 1;
-	}
-
-	for(i = 2; i < argc; i += 2) {
-		from = atoi(argv[i-1]);
-		to = atoi(argv[i]);
-
-		if(to == SOUND_MIXER_NONE)
-			fprintf(stderr, "%s: turning off mixer %s\n",
-				argv[0], mixer_names[to]);
-		else
-			fprintf(stderr, "%s: rerouting mixer %s to %s\n",
-				argv[0], mixer_names[from], mixer_names[to]);
-
-		val = from << 8 | to;
-
-		if(ioctl(fd, SOUND_MIXER_PRIVATE2, &val)) {
-			perror("AD1848 mixer reroute");
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
diff -urN linux-2.5.6-pre3/Documentation/sound/PAS16 linux-2.5.6/Documentation/sound/PAS16
--- linux-2.5.6-pre3/Documentation/sound/PAS16	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/Documentation/sound/PAS16	Wed Dec 31 16:00:00 1969
@@ -1,163 +0,0 @@
-Pro Audio Spectrum 16 for 2.3.99 and later
-=========================================
-by Thomas Molina (tmolina@home.com)
-last modified 3 Mar 2001
-Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken
-from Configure.help, Riccardo Facchetti for stuff from README.OSS,
-and others whose names I could not find.
-
-This documentation is relevant for the PAS16 driver (pas2_card.c and
-friends) under kernel version 2.3.99 and later.  If you are
-unfamiliar with configuring sound under Linux, please read the
-Sound-HOWTO, linux/Documentation/sound/Introduction and other 
-relevant docs first.
-
-The following information is relevant information from README.OSS
-and legacy docs for the Pro Audio Spectrum 16 (PAS16):
-==================================================================
-
-The pas2_card.c driver supports the following cards --
-Pro Audio Spectrum 16 (PAS16) and compatibles:
-        Pro Audio Spectrum 16
-        Pro Audio Studio 16
-        Logitech Sound Man 16
-        NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
-              and will not be supported by the driver.
-
-The sound driver configuration dialog
--------------------------------------
-
-Sound configuration starts by making some yes/no questions. Be careful
-when answering to these questions since answering y to a question may
-prevent some later ones from being asked. For example don't answer y to
-the question about (PAS16) if you don't really have a PAS16.  Sound
-configuration may also be made modular by answering m to configuration
-options presented. 
-
-Note also that all questions may not be asked. The configuration program
-may disable some questions depending on the earlier choices. It may also
-select some options automatically as well.
-
-  "ProAudioSpectrum 16 support",
-        - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
-          Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
-          you read the above list correctly). Don't answer 'y' if you
-          have some other card made by Media Vision or Logitech since they
-          are not PAS16 compatible.
-          NOTE! Since 3.5-beta10 you need to enable SB support (next question)
-          if you want to use the SB emulation of PAS16. It's also possible to
-          the emulation if you want to use a true SB card together with PAS16
-          (there is another question about this that is asked later).
-
-  "Generic OPL2/OPL3 FM synthesizer support",
-        - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-	  The PAS16 has an OPL3-compatible FM chip.
-
-With PAS16 you can use two audio device files at the same time. /dev/dsp (and
-/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
-/dev/audio1) is connected to the SB emulation (8 bit mono only).
-
-
-The new stuff for 2.3.99 and later
-============================================================================
-The following configuration options from linux/Documentation/Configure.help
-are relevant to configuring the PAS16:
-
-Sound card support
-CONFIG_SOUND
-  If you have a sound card in your computer, i.e. if it can say more
-  than an occasional beep, say Y. Be sure to have all the information
-  about your sound card and its configuration down (I/O port,
-  interrupt and DMA channel), because you will be asked for it.
-
-  You want to read the Sound-HOWTO, available from
-  http://www.linuxdoc.org/docs.html#howto . General information
-  about the modular sound system is contained in the files
-  Documentation/sound/Introduction. The file
-  Documentation/sound/README.OSS contains some slightly outdated but
-  still useful information as well.
-
-OSS sound modules
-CONFIG_SOUND_OSS
-  OSS is the Open Sound System suite of sound card drivers. They make
-  sound programming easier since they provide a common API. Say Y or M
-  here (the module will be called sound.o) if you haven't found a
-  driver for your sound card above, then pick your driver from the
-  list below.
-
-Persistent DMA buffers
-CONFIG_SOUND_DMAP
-  Linux can often have problems allocating DMA buffers for ISA sound
-  cards on machines with more than 16MB of RAM. This is because ISA
-  DMA buffers must exist below the 16MB boundary and it is quite
-  possible that a large enough free block in this region cannot be
-  found after the machine has been running for a while. If you say Y
-  here the DMA buffers (64Kb) will be allocated at boot time and kept
-  until the shutdown. This option is only useful if you said Y to
-  "OSS sound modules", above. If you said M to "OSS sound modules"
-  then you can get the persistent DMA buffer functionality by passing
-  the command-line argument "dmabuf=1" to the sound.o module.
-
-  Say y here for PAS16.
-
-ProAudioSpectrum 16 support
-CONFIG_SOUND_PAS
-  Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
-  16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
-  some other card made by Media Vision or Logitech since they are not
-  PAS16 compatible.  It is not necessary to enable the  separate
-  Sound Blaster support; it is included in the PAS driver.
-
-  If you compile the driver into the kernel, you have to add
-  "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
-  to the kernel command line.
-
-FM Synthesizer (YM3812/OPL-3) support
-CONFIG_SOUND_YM3812
-  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-  Answering Y is usually a safe and recommended choice, however some
-  cards may have software (TSR) FM emulation. Enabling FM support with
-  these cards may cause trouble (I don't currently know of any such
-  cards, however).
-  Please read the file Documentation/sound/OPL3 if your card has an
-  OPL3 chip.
-  If you compile the driver into the kernel, you have to add
-  "opl3=<io>" to the kernel command line.
-
-  If you compile your drivers into the kernel, you MUST configure 
-  OPL3 support as a module for PAS16 support to work properly.
-  You can then get OPL3 functionality by issuing the command:
-  insmod opl3
-  In addition, you must either add the following line to 
-  /etc/modules.conf:
-  options opl3 io=0x388
-  or else add the following line to /etc/lilo.conf:
-  opl3=0x388
-
-
-EXAMPLES
-===================================================================
-To use the PAS16 in my computer I have enabled the following sound
-configuration options:
-
-CONFIG_SOUND=y
-CONFIG_SOUND_OSS=y
-CONFIG_SOUND_TRACEINIT=y
-CONFIG_SOUND_DMAP=y
-CONFIG_SOUND_PAS=y
-CONFIG_SOUND_SB=n
-CONFIG_SOUND_YM3812=m
-
-I have also included the following append line in /etc/lilo.conf:
-append="pas2=0x388,10,3,-1,0x220,5,1,-1 sb=0x220,5,1,-1 opl3=0x388"
-
-The io address of 0x388 is default configuration on the PAS16.  The
-irq of 10 and dma of 3 may not match your installation.  The above 
-configuration enables PAS16, 8-bit Soundblaster and OPL3
-functionality.  If Soundblaster functionality is not desired, the
-following line would be appropriate:
-append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
-
-If sound is built totally modular, the above options may be 
-specified in /etc/modules.conf for pas2.o, sb.o and opl3.o 
-respectively. 
diff -urN linux-2.5.6-pre3/Documentation/sound/PSS linux-2.5.6/Documentation/sound/PSS
--- linux-2.5.6-pre3/Documentation/sound/PSS	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/Documentation/sound/PSS	Wed Dec 31 16:00:00 1969
@@ -1,41 +0,0 @@
-The PSS cards and other ECHO based cards provide an onboard DSP with 
-downloadable programs and also has an AD1848 "Microsoft Sound System" 
-device. The PSS driver enables MSS and MPU401 modes of the card. SB 
-is not enabled since it doesn't work concurrently with MSS. 
-
-If you build this driver as a module then the driver takes the following
-parameters
-
-pss_io. 	The I/O base the PSS card is configured at (normally 0x220
-		or 0x240)
-
-mss_io		The base address of the Microsoft Sound System interface.
-		This is normally 0x530, but may be 0x604 or other addresses.
-
-mss_irq		The interrupt assigned to the Microsoft Sound System
-		emulation. IRQ's 3,5,7,9,10,11 and 12 are available. If you
-		get IRQ errors be sure to check the interrupt is set to 
-		"ISA/Legacy" in the BIOS on modern machines.
-
-mss_dma		The DMA channel used by the Microsoft Sound System.
-		This can be 0, 1, or 3. DMA 0 is not available on older 
-		machines and will cause a crash on them.
-
-mpu_io		The MPU emulation base address. This sets the base of the
-		synthesizer. It is typically 0x330 but can be altered.
-
-mpu_irq		The interrupt to use for the synthesizer. It must differ
-		from the IRQ used by the Microsoft Sound System port.
-
-
-The mpu_io/mpu_irq fields are optional. If they are not specified the 
-synthesizer parts are not configured.
-
-When the module is loaded it looks for a file called 
-/etc/sound/pss_synth. This is the firmware file from the DOS install disks.
-This fil holds a general MIDI emulation. The file expected is called
-genmidi.ld on newer DOS driver install disks and synth.ld on older ones.
-
-You can also load alternative DSP algorithms into the card if you wish. One
-alternative driver can be found at http://www.mpg123.de/
-
diff -urN linux-2.5.6-pre3/Documentation/sound/PSS-updates linux-2.5.6/Documentation/sound/PSS-updates
--- linux-2.5.6-pre3/Documentation/sound/PSS-updates	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/Documentation/sound/PSS-updates	Wed Dec 31 16:00:00 1969
@@ -1,88 +0,0 @@
-	This file contains notes for users of PSS sound cards who wish to use the 
-newly added features of the newest version of this driver.
-
-	The major enhancements present in this new revision of this driver is the 
-addition of two new module parameters that allow you to take full advantage of 
-all the features present on your PSS sound card.  These features include the 
-ability to enable both the builtin CDROM and joystick ports.
-
-pss_enable_joystick
-
-	This parameter is basically a flag.  A 0 will leave the joystick port 
-disabled, while a non-zero value would enable the joystick port.  The default 
-setting is pss_enable_joystick=0 as this keeps this driver fully compatable 
-with systems that were using previous versions of this driver.  If you wish to 
-enable the joystick port you will have to add pss_enable_joystick=1 as an 
-argument to the driver.  To actually use the joystick port you will then have 
-to load the joystick driver itself.  Just remember to load the joystick driver 
-AFTER the pss sound driver.
-
-pss_cdrom_port
-
-	This parameter takes a port address as its parameter.  Any available port 
-address can be specified to enable the CDROM port, except for 0x0 and -1 as 
-these values would leave the port disabled.  Like the joystick port, the cdrom 
-port will require that an appropiate CDROM driver be loaded before you can make 
-use of the newly enabled CDROM port.  Like the joystick port option above, 
-remember to load the CDROM driver AFTER the pss sound driver.  While it may 
-differ on some PSS sound cards, all the PSS sound cards that I have seen have a 
-builtin Wearnes CDROM port.  If this is the case with your PSS sound card you 
-should load aztcd with the appropiate port option that matches the port you 
-assigned to the CDROM port when you loaded your pss sound driver.  (ex. 
-modprobe pss pss_cdrom_port=0x340 && modprobe aztcd aztcd=0x340)  The default 
-setting of this parameter leaves the CDROM port disabled to maintain full 
-compatability with systems using previous versions of this driver.
-
-	Other options have also been added for the added convenience and utility 
-of the user.  These options are only available if this driver is loaded as a 
-module.
-
-pss_no_sound
-
-	This module parameter is a flag that can be used to tell the driver to 
-just configure non-sound components.  0 configures all components, a non-0 
-value will only attept to configure the CDROM and joystick ports.  This 
-parameter can be used by a user who only wished to use the builtin joystick 
-and/or CDROM port(s) of his PSS sound card.  If this driver is loaded with this 
-parameter and with the paramter below set to true then a user can safely unload 
-this driver with the following command "rmmod pss && rmmod ad1848 && rmmod 
-mpu401 && rmmod sound && rmmod soundcore" and retain the full functionality of 
-his CDROM and/or joystick port(s) while gaining back the memory previously used 
-by the sound drivers.  This default setting of this parameter is 0 to retain 
-full behavioral compatability with previous versions of this driver.
-
-pss_keep_settings
-
-	This parameter can be used to specify whether you want the driver to reset 
-all emulations whenever its unloaded.  This can be useful for those who are 
-sharing resources (io ports, IRQ's, DMA's) between different ISA cards.  This 
-flag can also be useful in that future versions of this driver may reset all 
-emulations by default on the driver's unloading (as it probably should), so 
-specifying it now will ensure that all future versions of this driver will 
-continue to work as expected.  The default value of this parameter is 1 to 
-retain full behavioral compatability with previous versions of this driver.
-
-pss_firmware
-
-	This parameter can be used to specify the file containing the firmware 
-code so that a user could tell the driver where that file is located instead 
-of having to put it in a predefined location with a predefined name.  The 
-default setting of this parameter is "/etc/sound/pss_synth" as this was the 
-path and filename the hardcoded value in the previous versions of this driver.
-
-Examples:
-
-# Normal PSS sound card system, loading of drivers.
-# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules).
-
-/sbin/modprobe pss pss_io=0x220 mpu_io=0x338 mpu_irq=9 mss_io=0x530 mss_irq=10 mss_dma=1 pss_cdrom_port=0x340 pss_enable_joystick=1
-/sbin/modprobe aztcd aztcd=0x340
-/sbin/modprobe joystick
-
-# System using the PSS sound card just for its CDROM and joystick ports.
-# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules).
-
-/sbin/modprobe pss pss_io=0x220 pss_cdrom_port=0x340 pss_enable_joystick=1 pss_no_sound=1
-/sbin/rmmod pss && /sbin/rmmod ad1848 && /sbin/rmmod mpu401 && /sbin/rmmod sound && /sbin/rmmod soundcore  # This line not needed, but saves memory.
-/sbin/modprobe aztcd aztcd=0x340
-/sbin/modprobe joystick
diff -urN linux-2.5.6-pre3/Documentation/sound/README.OSS linux-2.5.6/Documentation/sound/README.OSS
--- linux-2.5.6-pre3/Documentation/sound/README.OSS	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/Documentation/sound/README.OSS	Wed Dec 31 16:00:00 1969
@@ -1,1456 +0,0 @@
-Introduction
-------------
-
-This file is a collection of all the old Readme files distributed with
-OSS/Lite by Hannu Savolainen. Since the new Linux sound driver is founded
-on it I think these information may still be interesting for users that
-have to configure their sound system.
-
-Be warned: Alan Cox is the current maintainer of the Linux sound driver so if
-you have problems with it, please contact him or the current device-specific
-driver maintainer (e.g. for aedsp16 specific problems contact me). If you have
-patches, contributions or suggestions send them to Alan: I'm sure they are
-welcome.
-
-In this document you will find a lot of references about OSS/Lite or ossfree:
-they are gone forever. Keeping this in mind and with a grain of salt this
-document can be still interesting and very helpful.
-
-[ File edited 17.01.1999 - Riccardo Facchetti ]
-[ Edited miroSOUND section 19.04.2001 - Robert Siemer ]
-
-OSS/Free version 3.8 release notes
-----------------------------------
-
-Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux FTP 
-sites). It gives instructions about using sound with Linux. It's bit out of
-date but still very useful. Information about bug fixes and such things
-is available from the web page (see above).
-
-Please check http://www.opensound.com/pguide for more info about programming
-with OSS API.
-
-   ====================================================
--  THIS VERSION ____REQUIRES____ Linux 2.1.57 OR LATER.
-   ====================================================
-
-Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z"
-contain useful utilities to be used with this driver.
-See http://www.opensound.com/ossfree/getting.html for
-download instructions.
-
-If you are looking for the installation instructions, please
-look forward into this document.
-
-Supported sound cards
----------------------
-
-See below.
-
-Contributors
-------------
-
-This driver contains code by several contributors. In addition several other
-persons have given useful suggestions. The following is a list of major
-contributors. (I could have forgotten some names.)
-
-	Craig Metz	1/2 of the PAS16 Mixer and PCM support
-	Rob Hooft	Volume computation algorithm for the FM synth.
-	Mika Liljeberg	uLaw encoding and decoding routines
-	Jeff Tranter	Linux SOUND HOWTO document
-	Greg Lee	Volume computation algorithm for the GUS and
-			lots of valuable suggestions.
-	Andy Warner	ISC port
-	Jim Lowe,
-	Amancio Hasty Jr	FreeBSD/NetBSD port
-	Anders Baekgaard 	Bug hunting and valuable suggestions.
-	Joerg Schubert	SB16 DSP support (initial version).
-	Andrew Robinson Improvements to the GUS driver
-	Megens SA	MIDI recording for SB and SB Pro (initial version).
-	Mikael Nordqvist  Linear volume support for GUS and
-			  nonblocking /dev/sequencer.
-	Ian Hartas		SVR4.2 port
-	Markus Aroharju	and
-	Risto Kankkunen		Major contributions to the mixer support
-				of GUS v3.7.
-	Hunyue Yau	Mixer support for SG NX Pro.
-	Marc Hoffman	PSS support (initial version).
-	Rainer Vranken	Initialization for Jazz16 (initial version).
-	Peter Trattler	Initial version of loadable module support for Linux.
-	JRA Gibson	16 bit mode for Jazz16 (initial version)
-	Davor Jadrijevic MAD16 support (initial version)
-	Gregor Hoffleit	Mozart support (initial version)
-	Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
-	James Hightower Spotting a tiny but important bug in CS423x support.
-	Denis Sablic	OPTi 82C924 specific enhancements (non PnP mode)
-	Tim MacKenzie	Full duplex support for OPTi 82C930.
-	
-	Please look at lowlevel/README for more contributors.
-
-There are probably many other names missing. If you have sent me some
-patches and your name is not in the above list, please inform me.
-
-Sending your contributions or patches
--------------------------------------
-
-First of all it's highly recommended to contact me before sending anything
-or before even starting to do any work. Tell me what you suggest to be
-changed or what you have planned to do. Also ensure you are using the
-very latest (development) version of OSS/Free since the change may already be
-implemented there. In general it's a major waste of time to try to improve a
-several months old version. Information about the latest version can be found
-from http://www.opensound.com/ossfree. In general there is no point in
-sending me patches relative to production kernels.
-
-Sponsors etc.
--------------
-
-The following companies have greatly helped development of this driver 
-in form of a free copy of their product:
-
-Novell, Inc.		UnixWare personal edition + SDK
-The Santa Cruz Operation, Inc. 	A SCO OpenServer + SDK
-Ensoniq Corp,		a SoundScape card and extensive amount of assistance
-MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK
-Acer, Inc.		a pair of AcerMagic S23 cards.
-
-In addition the following companies have provided me sufficient amount
-of technical information at least some of their products (free or $$$):
-
-Advanced Gravis Computer Technology Ltd.
-Media Vision Inc.
-Analog Devices Inc.
-Logitech Inc.
-Aztech Labs Inc.
-Crystal Semiconductor Corporation,
-Integrated Circuit Systems Inc.
-OAK Technology
-OPTi
-Turtle Beach
-miro
-Ad Lib Inc. ($$)
-Music Quest Inc. ($$)
-Creative Labs ($$$)
-
-If you have some problems
-=========================
-
-Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
-Also look at the home page (http://www.opensound.com/ossfree). It may
-contain info about some recent bug fixes.
-
-It's likely that you have some problems when trying to use the sound driver
-first time. Sound cards don't have standard configuration so there are no
-good default configuration to use. Please try to use same I/O, DMA and IRQ
-values for the sound card than with DOS.
-
-If you get an error message when trying to use the driver, please look
-at /var/adm/messages for more verbose error message.
-
-
-The following errors are likely with /dev/dsp and /dev/audio.
-
-	- "No such device or address".
-	This error indicates that there are no suitable hardware for the
-	device file or the sound driver has been compiled without support for
-	this particular device. For example /dev/audio and /dev/dsp will not
-	work if "digitized voice support" was not enabled during "make config".
-	
-	- "Device or resource busy". Probably the IRQ (or DMA) channel 
-	required by the sound card is in use by some other device/driver.
-
-	- "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
-	Look at the kernel messages in /var/adm/notice for more info.
-
-	- "Invalid argument". The application is calling ioctl()
-	with impossible parameters. Check that the application is
-	for sound driver version 2.X or later.
-
-Linux installation
-==================
-
-IMPORTANT!	Read this if you are installing a separately
-		distributed version of this driver.
-
-		Check that your kernel version works with this
-		release of the driver (see Readme). Also verify
-		that your current kernel version doesn't have more
-		recent sound driver version than this one. IT'S HIGHLY
-		RECOMMENDED THAT YOU USE THE SOUND DRIVER VERSION THAT
-		IS DISTRIBUTED WITH KERNEL SOURCES.
-
-- When installing separately distributed sound driver you should first
-  read the above notice. Then try to find proper directory where and how
-  to install the driver sources. You should not try to install a separately
-  distributed driver version if you are not able to find the proper way
-  yourself (in this case use the version that is distributed with kernel
-  sources). Remove old version of linux/drivers/sound directory before
-  installing new files.
-
-- To build the device files you need to run the enclosed shell script 
-  (see below). You need to do this only when installing sound driver
-  first time or when upgrading to much recent version than the earlier
-  one.
-
-- Configure and compile Linux as normally (remember to include the
-  sound support during "make config"). Please refer to kernel documentation
-  for instructions about configuring and compiling kernel. File Readme.cards
-  contains card specific instructions for configuring this driver for
-  use with various sound cards.
-
-Boot time configuration (using lilo and insmod) 
------------------------------------------------
-
-This information has been removed. Too many users didn't believe
-that it's really not necessary to use this method. Please look at
-Readme of sound driver version 3.0.1 if you still want to use this method.
-
-Problems
---------
-
-Common error messages:
-
-- /dev/???????: No such file or directory.
-Run the script at the end of this file.
-
-- /dev/???????: No such device.
-You are not running kernel which contains the sound driver. When using
-modularized sound driver this error means that the sound driver is not
-loaded.
-
-- /dev/????: No such device or address.
-Sound driver didn't detect suitable card when initializing. Please look at
-Readme.cards for info about configuring the driver with your card. Also
-check for possible boot (insmod) time error messages in /var/adm/messages.
-
-- Other messages or problems
-Please check http://www.opensound.com/ossfree for more info.
-
-Configuring version 3.8 (for Linux) with some common sound cards
-================================================================
-
-This document describes configuring sound cards with the freeware version of
-Open Sound Systems (OSS/Free). Information about the commercial version
-(OSS/Linux) and its configuration is available from 
-http://www.opensound.com/linux.html. Information presented here is
-not valid for OSS/Linux. 
-
-If you are unsure about how to configure OSS/Free
-you can download the free evaluation version of OSS/Linux from the above
-address. There is a chance that it can autodetect your sound card. In this case
-you can use the information included in soundon.log when configuring OSS/Free.
-
-
-IMPORTANT!	This document covers only cards that were "known" when
-		this driver version was released. Please look at
-		http://www.opensound.com/ossfree for info about
-		cards introduced recently.
-
-		When configuring the sound driver, you should carefully
-		check each sound configuration option (particularly
-		"Support for /dev/dsp and /dev/audio"). The default values
-		offered by these programs are not necessarily valid.
-
-
-THE BIGGEST MISTAKES YOU CAN MAKE
-=================================
-
-1. Assuming that the card is Sound Blaster compatible when it's not.
---------------------------------------------------------------------
-
-The number one mistake is to assume that your card is compatible with
-Sound Blaster. Only the cards made by Creative Technology or which have
-one or more chips labeled by Creative are SB compatible. In addition there
-are few sound chipsets which are SB compatible in Linux such as ESS1688 or
-Jazz16. Note that SB compatibility in DOS/Windows does _NOT_ mean anything
-in Linux. 
-
-IF YOU REALLY ARE 150% SURE YOU HAVE A SOUND BLASTER YOU CAN SKIP THE REST OF
-THIS CHAPTER.
-
-For most other "supposed to be SB compatible" cards you have to use other
-than SB drivers (see below).  It is possible to get most sound cards to work
-in SB mode but in general it's a complete waste of time. There are several
-problems which you will encounter by using SB mode with cards that are not
-truly SB compatible:
-
-- The SB emulation is at most SB Pro (DSP version 3.x) which means that 
-you get only 8 bit audio (there is always an another ("native") mode which
-gives the 16 bit capability). The 8 bit only operation is the reason why
-many users claim that sound quality in Linux is much worse than in DOS.
-In addition some applications require 16 bit mode and they produce just
-noise with a 8 bit only device.
-- The card may work only in some cases but refuse to work most of the
-time. The SB compatible mode always requires special initialization which is 
-done by the DOS/Windows drivers. This kind of cards work in Linux after
-you have warm booted it after DOS but they don't work after cold boot
-(power on or reset).
-- You get the famous "DMA timed out" messages. Usually all SB clones have
-software selectable IRQ and DMA settings. If the (power on default) values
-currently used by the card don't match configuration of the driver you will
-get the above error message whenever you try to record or play. There are
-few other reasons to the DMA timeout message but using the SB mode seems
-to be the most common cause.
-
-2. Trying to use a PnP (Plug & Play) card just like an ordinary sound card
---------------------------------------------------------------------------
-
-Plug & Play is a protocol defined by Intel and Microsoft. It lets operating
-systems to easily identify and reconfigure I/O ports, IRQs and DMAs of ISA
-cards. The problem with PnP cards is that the standard Linux doesn't currently
-(versions 2.1.x and earlier) don't support PnP. This means that you will have
-to use some special tricks (see later) to get a PnP card alive. Many PnP cards
-work after they have been initialized but this is not always the case.
-
-There are sometimes both PnP and non-PnP versions of the same sound card.
-The non-PnP version is the original model which usually has been discontinued
-more than an year ago. The PnP version has the same name but with "PnP"
-appended to it (sometimes not). This causes major confusion since the non-PnP
-model works with Linux but the PnP one doesn't.
-
-You should carefully check if "Plug & Play" or "PnP" is mentioned in the name
-of the card or in the documentation or package that came with the card. 
-Everything described in the rest of this document is not necessarily valid for
-PnP models of sound cards even you have managed to wake up the card properly.
-Many PnP cards are simply too different from their non-PnP ancestors which are
-covered by this document.
-
-
-Cards that are not (fully) supported by this driver
-===================================================
-
-See http://www.opensound.com/ossfree for information about sound cards 
-to be supported in future. 
-
-
-How to use sound without recompiling kernel and/or sound driver
-===============================================================
-
-There is a commercial sound driver which comes in precompiled form and doesn't
-require recompiling of the kernel. See http://www.4Front-tech.com/oss.html for
-more info.
-
-
-Configuring PnP cards
-=====================
-
-New versions of most sound cards use the so-called ISA PnP protocol for
-soft configuring their I/O, IRQ, DMA and shared memory resources.
-Currently at least cards made by Creative Technology (SB32 and SB32AWE
-PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and
-Aztech (some Sound Galaxy models) use PnP technology. The CS4232/4236 audio
-chip by Crystal Semiconductor (Intel Atlantis, HP Pavilion and many other
-motherboards) is also based on PnP technology but there is a "native" driver
-available for it (see information about CS4232 later in this document).
-
-PnP sound cards (as well as most other PnP ISA cards) are not supported
-by this version of the driver . Proper
-support for them should be released during 97 once the kernel level
-PnP support is available.
-
-There is a method to get most of the PnP cards to work. The basic method
-is the following:
-
-1) Boot DOS so the card's DOS drivers have a chance to initialize it.
-2) _Cold_ boot to Linux by using "loadlin.exe".  Hitting ctrl-alt-del
-works with older machines but causes a hard reset of all cards on recent
-(Pentium) machines.
-3) If you have the sound driver in Linux configured properly, the card should
-work now. "Proper" means that I/O, IRQ and DMA settings are the same as in
-DOS. The hard part is to find which settings were used. See the documentation of
-your card for more info.
-
-Windows 95 could work as well as DOS but running loadlin may be difficult.
-Probably you should "shut down" your machine to MS-DOS mode before running it.
-
-Some machines have a BIOS utility for setting PnP resources. This is a good
-way to configure some cards. In this case you don't need to boot DOS/Win95
-before starting Linux.
-
-Another way to initialize PnP cards without DOS/Win95 is a Linux based
-PnP isolation tool. When writing this there is a pre alpha test version
-of such a tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The
-file is called isapnptools-*. Please note that this tool is just a temporary
-solution which may be incompatible with future kernel versions having proper
-support for PnP cards. There are bugs in setting DMA channels in earlier
-versions of isapnptools so at least version 1.6 is required with sound cards.
-
-Yet another way to use PnP cards is to use (commercial) OSS/Linux drivers.  See
-http://www.opensound.com/linux.html for more info. This is probably the way you
-should do it if you don't want to spend time recompiling the kernel and 
-required tools.
-
-
-Read this before trying to configure the driver
-===============================================
-
-There are currently many cards that work with this driver. Some of the cards
-have native support while others work since they emulate some other
-card (usually SB, MSS/WSS and/or MPU401). The following cards have native
-support in the driver. Detailed instructions for configuring these cards
-will be given later in this document.
-
-Pro Audio Spectrum 16 (PAS16) and compatibles:
-	Pro Audio Spectrum 16
-	Pro Audio Studio 16
-	Logitech Sound Man 16
-	NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
-	      and will not be supported by the driver.
-
-Media Vision Jazz16 based cards
-	Pro Sonic 16
-	Logitech SoundMan Wave
-	(Other Jazz based cards should work but I don't have any reports
-	about them).
-
-Sound Blasters
-	SB 1.0 to 2.0
-	SB Pro
-	SB 16
-	SB32/64/AWE
-		Configure SB32/64/AWE just like SB16. See lowlevel/README.awe
-		for information about using the wave table synth.
-	        NOTE! AWE63/Gold and 16/32/AWE "PnP" cards need to be activated
-		      using isapnptools before they work with OSS/Free.
-	SB16 compatible cards by other manufacturers than Creative.
-		You have been fooled since there are _no_ SB16 compatible
-		cards on the market (as of May 1997). It's likely that your card
-		is compatible just with SB Pro but there is also a non-SB-
-		compatible 16 bit mode. Usually it's MSS/WSS but it could also
-		be a proprietary one like MV Jazz16 or ESS ES688. OPTi
-		MAD16 chips are very common in so called "SB 16 bit cards"
-		(try with the MAD16 driver).
-
-	======================================================================
-	"Supposed to be SB compatible" cards.
-		Forget the SB compatibility and check for other alternatives
-		first. The only cards that work with the SB driver in
-		Linux have been made by Creative Technology (there is at least
-		one chip on the card with "CREATIVE" printed on it). The
-		only other SB compatible chips are ESS and Jazz16 chips
-		(maybe ALSxxx chips too but they probably don't work).
-		Most other "16 bit SB compatible" cards such as "OPTi/MAD16" or
-		"Crystal" are _NOT_ SB compatible in Linux.
-
-		Practically all sound cards have some kind of SB emulation mode
-		in addition to their native (16 bit) mode. In most cases this
-		(8 bit only) SB compatible mode doesn't work with Linux. If
-		you get it working it may cause problems with games and
-		applications which require 16 bit audio. Some 16 bit only
-		applications don't check if the card actually supports 16 bits.
-		They just dump 16 bit data to a 8 bit card which produces just
-		noise.
-
-		In most cases the 16 bit native mode is supported by Linux.
-		Use the SB mode with "clones" only if you don't find anything
-		better from the rest of this doc.
-	======================================================================
-
-Gravis Ultrasound (GUS)
-	GUS
-	GUS + the 16 bit option
-	GUS MAX
-	GUS ACE (No MIDI port and audio recording)
-	GUS PnP (with RAM)
-
-MPU-401	and compatibles
-	The driver works both with the full (intelligent mode) MPU-401
-	cards (such as MPU IPC-T and MQX-32M) and with the UART only
-	dumb MIDI ports. MPU-401 is currently the most common MIDI
-	interface. Most sound cards are compatible with it. However,
-	don't enable MPU401 mode blindly. Many cards with native support
-	in the driver have their own MPU401 driver. Enabling the standard one
-	will cause a conflict with these cards. So check if your card is
-	in the list of supported cards before enabling MPU401.
-
-Windows Sound System (MSS/WSS)
-	Even when Microsoft has discontinued their own Sound System card 
-	they managed to make it a standard. MSS compatible cards are based on 
-	a codec chip which is easily available from at least two manufacturers
-	(AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
-	Currently most sound cards are based on one of the MSS compatible codec
-	chips. The CS4231 is used in the high quality cards such as GUS MAX,
-	MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). 
-
-	Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
-	sign. Even if the card is not MSS compatible, it could be easy to write
-	support for it. Note also that most MSS compatible cards
-	require special boot time initialization which may not be present
-	in the driver. Also, some MSS compatible cards have native support.
-	Enabling the MSS support with these cards is likely to
-	cause a conflict. So check if your card is listed in this file before
-	enabling the MSS support.
-
-Yamaha FM synthesizers (OPL2, OPL3 (not OPL3-SA) and OPL4)
-	Most sound cards have a FM synthesizer chip. The OPL2 is a 2
-	operator chip used in the original AdLib card. Currently it's used
-	only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator 
-	FM chip which provides better sound quality and/or more available 
-	voices than the OPL2. The OPL4 is a new chip that has an OPL3 and
-	a wave table synthesizer packed onto the same chip. The driver supports
-	just the OPL3 mode directly. Most cards with an OPL4 (like
-	SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401
-	emulation. Writing a native OPL4 support is difficult
-	since Yamaha doesn't give information about their sample ROM chip.
-
-	Enable the generic OPL2/OPL3 FM synthesizer support if your
-	card has a FM chip made by Yamaha. Don't enable it if your card
-	has a software (TRS) based FM emulator.
-
-	----------------------------------------------------------------
-	NOTE! OPL3-SA is different chip than the ordinary OPL3. In addition
-	to the FM synth this chip has also digital audio (WSS) and
-	MIDI (MPU401) capabilities. Support for OPL3-SA is described below.
-	----------------------------------------------------------------
-
-Yamaha OPL3-SA1
-
-	Yamaha OPL3-SA1 (YMF701) is an audio controller chip used on some
-	(Intel) motherboards and on cheap sound cards. It should not be
-	confused with the original OPL3 chip (YMF278) which is entirely
-        different chip. OPL3-SA1 has support for MSS, MPU401 and SB Pro
-	(not used in OSS/Free) in addition to the OPL3 FM synth.
-
-	There are also chips called OPL3-SA2, OPL3-SA3, ..., OPL3SA-N. They
-	are PnP chips and will not work with the OPL3-SA1 driver. You should 
-	use the standard MSS, MPU401 and OPL3 options with these chips and to
-	activate the card using isapnptools.
-
-4Front Technologies SoftOSS
-
-	SoftOSS is a software based wave table emulation which works with
-	any 16 bit stereo sound card. Due to its nature a fast CPU is
-	required (P133 is minimum). Although SoftOSS does _not_ use MMX
-	instructions it has proven out that recent processors (which appear
-	to have MMX) perform significantly better with SoftOSS than earlier
-	ones. For example a P166MMX beats a PPro200. SoftOSS should not be used
-	on 486 or 386 machines.
-
-	The amount of CPU load caused by SoftOSS can be controlled by
-	selecting the CONFIG_SOFTOSS_RATE and CONFIG_SOFTOSS_VOICES
-	parameters properly (they will be prompted by make config). It's
-	recommended to set CONFIG_SOFTOSS_VOICES to 32. If you have a
-	P166MMX or faster (PPro200 is not faster) you can set
-	CONFIG_SOFTOSS_RATE to 44100 (kHz). However with slower systems it
-	recommended to use sampling rates around 22050 or even 16000 kHz.
-	Selecting too high values for these parameters may hang your
-	system when playing MIDI files with hight degree of polyphony
-	(number of concurrently playing notes). It's also possible to
-	decrease CONFIG_SOFTOSS_VOICES. This makes it possible to use
-	higher sampling rates. However using fewer voices decreases
-	playback quality more than decreasing the sampling rate.
-
-	SoftOSS keeps the samples loaded on the system's RAM so much RAM is
-	required. SoftOSS should never be used on machines with less than 16 MB
-	of RAM since this is potentially dangerous (you may accidentally run out
-	of memory which probably crashes the machine). 
-
-	SoftOSS implements the wave table API originally designed for GUS. For
-	this reason all applications designed for GUS should work (at least
-	after minor modifications). For example gmod/xgmod and playmidi -g are
-	known to work.
-
-	To work SoftOSS will require GUS compatible
-	patch files to be installed on the system (in /dos/ultrasnd/midi). You
-	can use the public domain MIDIA patchset available from several ftp
-	sites.
-
-        *********************************************************************
-	IMPORTANT NOTICE! The original patch set distributed with the Gravis 
-	Ultrasound card is not in public domain (even though it's available from
-	some FTP sites). You should contact Voice Crystal (www.voicecrystal.com)
-	if you like to use these patches with SoftOSS included in OSS/Free.
-        *********************************************************************
-
-PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC)
-	Analog Devices and Echo Speech have together defined a sound card
-	architecture based on the above chips. The DSP chip is used
-	for emulation of SB Pro, FM and General MIDI/MT32.
-
-	There are several cards based on this architecture. The most known
-	ones are Orchid SW32 and Cardinal DSP16. 
-
-	The driver supports downloading DSP algorithms to these cards.
-
-	NOTE! You will have to use the "old" config script when configuring
-	PSS cards.
-
-MediaTrix AudioTrix Pro
-	The ATP card is built around a CS4231 codec and an OPL4 synthesizer
-	chips. The OPL4 mode is supported by a microcontroller running a
-	General MIDI emulator. There is also a SB 1.5 compatible playback mode.
-
-Ensoniq SoundScape and compatibles
-	Ensoniq has designed a sound card architecture based on the
-	OTTO synthesizer chip used in their professional MIDI synthesizers.
-	Several companies (including Ensoniq, Reveal and Spea) are selling
-	cards based on this architecture.
-
-	NOTE! The SoundScape PnP is not supported by OSS/Free. Ensoniq VIVO and
-	VIVO90 cards are not compatible with Soundscapes so the Soundscape
-        driver will not work with them. You may want to use OSS/Linux with these
-        cards.
-
-OPTi MAD16 and Mozart based cards
-	The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929),
-	OPTi 82C924/82C925 (in _non_ PnP mode) and OPTi 82C930 interface
-	chips are used in many different sound cards, including some
-	cards by Reveal miro and Turtle Beach (Tropez). The purpose of these
-	chips is to connect other audio components to the PC bus. The
-	interface chip performs address decoding for the other chips.
-	NOTE! Tropez Plus is not MAD16 but CS4232 based.
-	NOTE! MAD16 PnP cards (82C924, 82C925, 82C931) are not MAD16 compatible
-	in the PnP mode. You will have to use them in MSS mode after having
-	initialized them using isapnptools or DOS. 82C931 probably requires
-	initialization using DOS/Windows (running isapnptools is not enough).
-	It's possible to use 82C931 with OSS/Free by jumpering it to non-PnP
-	mode (provided that the card has a jumper for this). In non-PnP mode
-	82C931 is compatible with 82C930 and should work with the MAD16 driver
-	(without need to use isapnptools or DOS to initialize it). All OPTi
-	chips are supported by OSS/Linux (both in PnP and non-PnP modes).
-
-Audio Excel DSP16 
-	Support for this card was written by Riccardo Faccetti
-	(riccardo@cdc8g5.cdc.polimi.it). The AEDSP16 driver included in
-	the lowlevel/ directory. To use it you should enable the
-	"Additional low level drivers" option.
-
-Crystal CS4232 and CS4236 based cards such as AcerMagic S23, TB Tropez _Plus_ and 
-	many PC motherboards (Compaq, HP, Intel, ...)
-	CS4232 is a PnP multimedia chip which contains a CS3231A codec,
-	SB and MPU401 emulations. There is support for OPL3 too.
-	Unfortunately the MPU401 mode doesn't work (I don't know how to
-	initialize it). CS4236 is an enhanced (compatible) version of CS4232.
-	NOTE! Don't ever try to use isapnptools with CS4232 since this will just
-	freeze your machine (due to chip bugs). If you have problems in getting
-	CS4232 working you could try initializing it with DOS (CS4232C.EXE) and
-	then booting Linux using loadlin. CS4232C.EXE loads a secret firmware
-	patch which is not documented by Crystal.
-
-Turtle Beach Maui and Tropez "classic"
-	This driver version supports sample, patch and program loading commands
-	described in the Maui/Tropez User's manual. 
-	There is now full initialization support too. The audio side of
-	the Tropez is based on the MAD16 chip (see above).
-	NOTE! Tropez Plus is different card than Tropez "classic" and will not
-	work fully in Linux. You can get audio features working by configuring
-	the card as a CS4232 based card (above).
-
-
-Jumpers and software configuration
-==================================
-
-Some of the earliest sound cards were jumper configurable. You have to
-configure the driver use I/O, IRQ and DMA settings
-that match the jumpers. Just few 8 bit cards are fully jumper 
-configurable (SB 1.x/2.x, SB Pro and clones).
-Some cards made by Aztech have an EEPROM which contains the 
-config info. These cards behave much like hardware jumpered cards.
-
-Most cards have jumper for the base I/O address but other parameters
-are software configurable. Sometimes there are few other jumpers too.
-
-Latest cards are fully software configurable or they are PnP ISA
-compatible. There are no jumpers on the board.
-
-The driver handles software configurable cards automatically. Just configure
-the driver to use I/O, IRQ and DMA settings which are known to work.
-You could usually use the same values than with DOS and/or Windows.
-Using different settings is possible but not recommended since it may cause
-some trouble (for example when warm booting from an OS to another or
-when installing new hardware to the machine).
-
-Sound driver sets the soft configurable parameters of the card automatically
-during boot. Usually you don't need to run any extra initialization
-programs when booting Linux but there are some exceptions. See the
-card-specific instructions below for more info.
-
-The drawback of software configuration is that the driver needs to know
-how the card must be initialized. It cannot initialize unknown cards
-even if they are otherwise compatible with some other cards (like SB,
-MPU401 or Windows Sound System).
-
-
-What if your card was not listed above?
-=======================================
-
-The first thing to do is to look at the major IC chips on the card.
-Many of the latest sound cards are based on some standard chips. If you
-are lucky, all of them could be supported by the driver. The most common ones
-are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures
-listed above. Also look at the end of this file for list of unsupported
-cards and the ones which could be supported later.
-
-The last resort is to send _exact_ name and model information of the card
-to me together with a list of the major IC chips (manufactured, model) to 
-me. I could then try to check if your card looks like something familiar.
-
-There are many more cards in the world than listed above. The first thing to
-do with these cards is to check if they emulate some other card or interface
-such as SB, MSS and/or MPU401. In this case there is a chance to get the
-card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del
-and boot Linux without hard resetting the machine). In this method the
-DOS based driver initializes the hardware to use known I/O, IRQ and DMA
-settings. If sound driver is configured to use the same settings, everything
-should work OK.
-
-
-Configuring sound driver (with Linux)
-=====================================
-
-The sound driver is currently distributed as part of the Linux kernel. The 
-files are in /usr/src/linux/drivers/sound/. 
-
-****************************************************************************
-*	ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH	   *
-*	THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST  *
-*	VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE	   *
-*	BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE   *
-*	KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER 	   *
-*	INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME	   *
-*	INCOMPATIBILITY PROBLEMS.					   *
-*									   *
-*	IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, *
-*	BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE  *
-*	INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER	   *
-*	DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR	   *
-*	COMPILED.							   *
-****************************************************************************
-
-To configure the driver, run "make config" in the kernel source directory
-(/usr/src/linux). Answer "y" or "m" to the question about Sound card support
-(after the questions about mouse, CD-ROM, ftape, etc. support).  Questions
-about options for sound will then be asked.
-
-After configuring the kernel and sound driver, run "make dep" and compile
-the kernel following instructions in the kernel README.
-
-The sound driver configuration dialog
--------------------------------------
-
-Sound configuration starts by making some yes/no questions. Be careful
-when answering to these questions since answering y to a question may
-prevent some later ones from being asked. For example don't answer y to
-the first question (PAS16) if you don't really have a PAS16. Don't enable
-more cards than you really need since they just consume memory. Also
-some drivers (like MPU401) may conflict with your SCSI controller and
-prevent kernel from booting. If you card was in the list of supported
-cards (above), please look at the card specific config instructions
-(later in this file) before starting to configure. Some cards must be
-configured in way which is not obvious.
-
-So here is the beginning of the config dialog. Answer 'y' or 'n' to these
-questions. The default answer is shown so that (y/n) means 'y' by default and
-(n/y) means 'n'. To use the default value, just hit ENTER. But be careful
-since using the default _doesn't_ guarantee anything.
-
-Note also that all questions may not be asked. The configuration program
-may disable some questions depending on the earlier choices. It may also
-select some options automatically as well.
-
-  "ProAudioSpectrum 16 support",
-	- Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
-	  Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
-	  you read the above list correctly). Don't answer 'y' if you
-	  have some other card made by Media Vision or Logitech since they
-	  are not PAS16 compatible.
-	  NOTE! Since 3.5-beta10 you need to enable SB support (next question)
-	  if you want to use the SB emulation of PAS16. It's also possible to
-   	  the emulation if you want to use a true SB card together with PAS16
-	  (there is another question about this that is asked later).
-  "Sound Blaster support",
-	- Answer 'y' if you have an original SB card made by Creative Labs
-	  or a full 100% hardware compatible clone (like Thunderboard or
-	  SM Games). If your card was in the list of supported cards (above),
-	  please look at the card specific instructions later in this file
-	  before answering this question. For an unknown card you may answer 
-	  'y' if the card claims to be SB compatible.
-	 Enable this option also with PAS16 (changed since v3.5-beta9).
-
-	 Don't enable SB if you have a MAD16 or Mozart compatible card.
-
-  "Generic OPL2/OPL3 FM synthesizer support",
-	- Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
-	  Answering 'y' is usually a safe and recommended choice. However some
-	  cards may have software (TSR) FM emulation. Enabling FM support
-	  with these cards may cause trouble. However I don't currently know
-	  such cards.
-  "Gravis Ultrasound support",
-	- Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't
-	  have GUS since the GUS driver consumes much memory.
-	  Currently I don't have experiences with the GUS ACE so I don't
-	  know what to answer with it.
-  "MPU-401 support (NOT for SB16)",
-	- Be careful with this question. The MPU401 interface is supported
-	  by almost any sound card today. However some natively supported cards
-	  have their own driver for MPU401. Enabling the MPU401 option with
-	  these cards will cause a conflict. Also enabling MPU401 on a system
-	  that doesn't really have a MPU401 could cause some trouble. If your
-	  card was in the list of supported cards (above), please look at
-	  the card specific instructions later in this file.
-
-	  In MOST cases this MPU401 driver should only be used with "true"
-	  MIDI-only MPU401 professional cards. In most other cases there
-	  is another way to get the MPU401 compatible interface of a
-	  sound card to work.
-	  Support for the MPU401 compatible MIDI port of SB16, ESS1688
-	  and MV Jazz16 cards is included in the SB driver. Use it instead
-	  of this separate MPU401 driver with these cards. As well 
-	  Soundscape, PSS and Maui drivers include their own MPU401
-	  options.
-
-	  It's safe to answer 'y' if you have a true MPU401 MIDI interface
-	  card. 
-  "6850 UART Midi support",
-	- It's safe to answer 'n' to this question in all cases. The 6850
-	  UART interface is so rarely used.
-  "PSS (ECHO-ADI2111) support",
-	- Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some
-	  other card based on the PSS chipset (AD1848 codec + ADSP-2115
-	  DSP chip + Echo ESC614 ASIC CHIP).
-  "16 bit sampling option of GUS (_NOT_ GUS MAX)",
-	- Answer 'y' if you have installed the 16 bit sampling daughtercard
-	  to your GUS. Answer 'n' if you have GUS MAX. Enabling this option
-	  disables GUS MAX support.
-  "GUS MAX support",
-	- Answer 'y' only if you have a GUS MAX.
-  "Microsoft Sound System support",
-	- Again think carefully before answering 'y' to this question. It's
-	  safe to answer 'y' in case you have the original Windows Sound 
-	  System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).
-	  Also you may answer 'y' in case your card was not listed earlier
-	  in this file. For cards having native support in the driver, consult
-	  the card specific instructions later in this file. Some drivers
-	  have their own MSS support and enabling this option will cause a
-	  conflict. 
-	  Note! The MSS driver permits configuring two DMA channels. This is a
-	  "nonstandard" feature and works only with very few cards (if any).
-	  In most cases the second DMA channel should be disabled or set to
-	  the same channel than the first one. Trying to configure two separate
-	  channels with cards that don't support this feature will prevent
-	  audio (at least recording) from working.
-  "Ensoniq Soundscape support",
-	- Answer 'y' if you have a sound card based on the Ensoniq SoundScape
-	  chipset. Such cards are being manufactured at least by Ensoniq,
-	  Spea and Reveal (note that Reveal makes other cards also).  The oldest
-	  cards made by Spea don't work properly with Linux. 
-	  Soundscape PnP as well as Ensoniq VIVO work only with the commercial
-	  OSS/Linux version.
-  "MediaTrix AudioTrix Pro support",
-	- Answer 'y' if you have the AudioTrix Pro.
-  "Support for MAD16 and/or Mozart based cards",
-	- Answer y if your card has a Mozart (OAK OTI-601) or MAD16
-	  (OPTi 82C928, 82C929, 82C924/82C925 or 82C930) audio interface chip. 
-	  These chips are
-	  currently quite common so it's possible that many no-name cards
-	  have one of them. In addition the MAD16 chip is used in some
-	  cards made by known manufacturers such as Turtle Beach (Tropez),
-	  Reveal (some models) and Diamond (some recent models).
-	  Note OPTi 82C924 and 82C925 are MAD16 compatible only in non PnP
-	  mode (jumper selectable on many cards).
-  "Support for TB Maui"
-	- This enables TB Maui specific initialization. Works with TB Maui
-	and TB Tropez (may not work with Tropez Plus).
-
-
-Then the configuration program asks some y/n questions about the higher
-level services. It's recommended to answer 'y' to each of these questions.
-Answer 'n' only if you know you will not need the option.
-
-  "MIDI interface support",
-	- Answering 'n' disables /dev/midi## devices and access to any
-	  MIDI ports using /dev/sequencer and /dev/music. This option
-	  also affects any MPU401 and/or General MIDI compatible devices.
-  "FM synthesizer (YM3812/OPL-3) support",
-	- Answer 'y' here.
-  "/dev/sequencer support",
-	- Answering 'n' disables /dev/sequencer and /dev/music.
-
-Entering the I/O, IRQ and DMA config parameters
------------------------------------------------
-
-After the above questions the configuration program prompts for the
-card specific configuration information. Usually just a set of
-I/O address, IRQ and DMA numbers are asked. With some cards the program
-asks for some files to be used during initialization of the card. For example
-many cards have a DSP chip or microprocessor which must be initialized by
-downloading a program (microcode) file to the card.
-
-Instructions for answering these questions are given in the next section.
-
-
-Card specific information
-=========================
-
-This section gives additional instructions about configuring some cards.
-Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using
-the same settings with DOS/Windows and Linux is recommended. Using
-different values could cause some problems when switching between
-different operating systems.
-
-Sound Blasters (the original ones by Creative)
----------------------------------------------
-
-NOTE! Check if you have a PnP Sound Blaster (cards sold after summer 1995
-      are almost certainly PnP ones). With PnP cards you should use isapnptools
-      to activate them (see above).
-
-It's possible to configure these cards to use different I/O, IRQ and
-DMA settings. Since the possible/default settings have changed between various
-models, you have to consult manual of your card for the proper ones. It's
-a good idea to use the same values than with DOS/Windows. With SB and SB Pro
-it's the only choice. SB16 has software selectable IRQ and DMA channels but
-using different values with DOS and Linux is likely to cause troubles. The
-DOS driver is not able to reset the card properly after warm boot from Linux
-if Linux has used different IRQ or DMA values.
-
-The original (steam) Sound Blaster (versions 1.x and 2.x) use always
-DMA1. There is no way to change it.
-
-The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for
-8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory
-it's possible to use just one (8 bit) DMA channel by answering the 8 bit
-one when the configuration program asks for the 16 bit one. This may work
-in some systems but is likely to cause terrible noise on some other systems.
-
-It's possible to use two SB16/32/64 at the same time. To do this you should
-first configure OSS/Free for one card. Then edit local.h manually and define
-SB2_BASE, SB2_IRQ, SB2_DMA and SB2_DMA2 for the second one. You can't get
-the OPL3, MIDI and EMU8000 devices of the second card to work. If you are
-going to use two PnP Sound Blasters, ensure that they are of different model
-and have different PnP IDs. There is no way to get two cards with the same
-card ID and serial number to work. The easiest way to check this is trying 
-if isapnptools can see both cards or just one.
-
-NOTE!	Don't enable the SM Games option (asked by the configuration program)
-	if you are not 101% sure that your card is a Logitech Soundman Games
-	(not a SM Wave or SM16).
-
-SB Clones
----------
-
-First of all: There are no SB16 clones. There are SB Pro clones with a
-16 bit mode which is not SB16 compatible. The most likely alternative is that
-the 16 bit mode means MSS/WSS.
-
-There are just a few fully 100% hardware SB or SB Pro compatible cards.
-I know just Thunderboard and SM Games. Other cards require some kind of
-hardware initialization before they become SB compatible. Check if your card
-was listed in the beginning of this file. In this case you should follow
-instructions for your card later in this file.
-
-For other not fully SB clones you may try initialization using DOS in
-the following way:
-
-	- Boot DOS so that the card specific driver gets run.
-	- Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't
-	  switch off power or press the reset button.
-	- If you use the same I/O, IRQ and DMA settings in Linux, the
-	  card should work.
-
-If your card is both SB and MSS compatible, I recommend using the MSS mode.
-Most cards of this kind are not able to work in the SB and the MSS mode 
-simultaneously. Using the MSS mode provides 16 bit recording and playback.
-
-ProAudioSpectrum 16 and compatibles
------------------------------------
-
-PAS16 has a SB emulation chip which can be used together with the native
-(16 bit) mode of the card. To enable this emulation you should configure 
-the driver to have SB support too (this has been changed since version
-3.5-beta9 of this driver).
-
-With current driver versions it's also possible to use PAS16 together with 
-another SB compatible card. In this case you should configure SB support
-for the other card and to disable the SB emulation of PAS16 (there is a
-separate questions about this).
-
-With PAS16 you can use two audio device files at the same time. /dev/dsp (and
-/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
-/dev/audio1) is connected to the SB emulation (8 bit mono only).
-
-Gravis Ultrasound
------------------
-
-There are many different revisions of the Ultrasound card (GUS). The
-earliest ones (pre 3.7) don't have a hardware mixer. With these cards
-the driver uses a software emulation for synth and pcm playbacks. It's
-also possible to switch some of the inputs (line in, mic) off by setting
-mixer volume of the channel level below 10%. For recording you have
-to select the channel as a recording source and to use volume above 10%.
-
-GUS 3.7 has a hardware mixer.
-
-GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which 
-also contains a mixer.
-
-Configuring GUS is simple. Just enable the GUS support and GUS MAX or
-the 16 bit daughtercard if you have them. Note that enabling the daughter
-card disables GUS MAX driver.
-
-NOTE for owners of the 16 bit daughtercard: By default the daughtercard
-uses /dev/dsp (and /dev/audio). Command "ln -sf /dev/dsp1 /dev/dsp"
-selects the daughter card as the default device.
-
-With just the standard GUS enabled the configuration program prompts
-for the I/O, IRQ and DMA numbers for the card. Use the same values than
-with DOS.
-
-With the daughter card option enabled you will be prompted for the I/O,
-IRQ and DMA numbers for the daughter card. You have to use different I/O
-and DMA values than for the standard GUS. The daughter card permits
-simultaneous recording and playback. Use /dev/dsp (the daughtercard) for
-recording and /dev/dsp1 (GUS GF1) for playback.
-
-GUS MAX uses the same I/O address and IRQ settings than the original GUS
-(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used.
-Using two DMA channels permits simultaneous playback using two devices
-(dev/dsp0 and /dev/dsp1). The second DMA channel is required for
-full duplex audio.
-To enable the second DMA channels, give a valid DMA channel when the config
-program asks for the GUS MAX DMA (entering -1 disables the second DMA).
-Using 16 bit DMA channels (5,6 or 7) is recommended.
-
-If you have problems in recording with GUS MAX, you could try to use
-just one 8 bit DMA channel. Recording will not work with one DMA
-channel if it's a 16 bit one.
-
-Microphone input of GUS MAX is connected to mixer in little bit nonstandard
-way. There is actually two microphone volume controls. Normal "mic" controls
-only recording level. Mixer control "speaker" is used to control volume of
-microphone signal connected directly to line/speaker out. So just decrease
-volume of "speaker" if you have problems with microphone feedback.
-
-GUS ACE works too but any attempt to record or to use the MIDI port
-will fail.
-
-GUS PnP (with RAM) is partially supported but it needs to be initialized using
-DOS or isapnptools before starting the driver.
-
-MPU401 and Windows Sound System
--------------------------------
-
-Again. Don't enable these options in case your card is listed
-somewhere else in this file.
-
-Configuring these cards is obvious (or it should be). With MSS
-you should probably enable the OPL3 synth also since
-most MSS compatible cards have it. However check that this is true
-before enabling OPL3.
-
-Sound driver supports more than one MPU401 compatible cards at the same time
-but the config program asks config info for just the first of them.
-Adding the second or third MPU interfaces must be done manually by
-editing sound/local.h (after running the config program). Add defines for
-MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file.
-
-CAUTION!
-
-The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which
-is also the default of the MPU401 driver. Don't configure the sound driver to
-use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot
-if you make this mistake.
-
-PSS
----
-
-Even the PSS cards are compatible with SB, MSS and MPU401, you must not
-enable these options when configuring the driver. The configuration
-program handles these options itself. (You may use the SB, MPU and MSS options
-together with PSS if you have another card on the system).
-
-The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled 
-since it doesn't work concurrently with MSS. The driver loads also a
-DSP algorithm which is used to for the general MIDI emulation. The
-algorithm file (.ld) is read by the config program and written to a
-file included when the pss.c is compiled. For this reason the config
-program asks if you want to download the file. Use the genmidi.ld file
-distributed with the DOS/Windows drivers of the card (don't use the mt32.ld).
-With some cards the file is called 'synth.ld'. You must have access to
-the file when configuring the driver. The easiest way is to mount the DOS
-partition containing the file with Linux. 
-
-It's possible to load your own DSP algorithms and run them with the card.
-Look at the directory pss_test of snd-util-3.0.tar.gz for more info.
-
-AudioTrix Pro
--------------
-
-You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition
-to the native AudioTrix driver. Don't enable MSS or MPU drivers.
-
-Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
-DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
-attempt to use the same IRQ or DMA channels twice.
-
-The SB mode of ATP is implemented so the ATP driver just enables SB
-in the proper address. The SB driver handles the rest. You have to configure
-both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
-settings.
-
-Also the ATP has a microcontroller for the General MIDI emulation (OPL4).
-For this reason the driver asks for the name of a file containing the
-microcode (TRXPRO.HEX). This file is usually located in the directory
-where the DOS drivers were installed. You must have access to this file
-when configuring the driver. 
-
-If you have the effects daughtercard, it must be initialized by running
-the setfx program of snd-util-3.0.tar.gz package. This step is not required
-when using the (future) binary distribution version of the driver.
-
-Ensoniq SoundScape
-------------------
-
-NOTE!	The new PnP SoundScape is not supported yet. Soundscape compatible
-	cards made by Reveal don't work with Linux. They use older revision
-	of the Soundscape chipset which is not fully compatible with
-	newer cards made by Ensoniq.
-
-The SoundScape driver handles initialization of MSS and MPU supports
-itself so you don't need to enable other drivers than SoundScape
-(enable also the /dev/dsp, /dev/sequencer and MIDI supports).
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!!!!!                                                                   !!!!
-!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio 	!!!!
-!!!!!       device files (/dev/dsp0 and /dev/dsp1). The first one WAS   !!!!
-!!!!!	    used only for card initialization and the second for audio  !!!!
-!!!!!	    purposes. It WAS required to change /dev/dsp (a symlink) to !!!!
-!!!!!	    point to /dev/dsp1.						!!!!
-!!!!!                                                                   !!!!
-!!!!!	    This is not required with OSS versions 3.5-beta6 and later	!!!!
-!!!!!	    since there is now just one audio device file. Please 	!!!!
-!!!!!	    change /dev/dsp to point back to /dev/dsp0 if you are	!!!!
-!!!!!	    upgrading from an earlier driver version using		!!!!
-!!!!!	    (cd /dev;rm dsp;ln -s dsp0 dsp).				!!!!
-!!!!!                                                                   !!!!
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-The configuration program asks one DMA channel and two interrupts. One IRQ
-and one DMA is used by the MSS codec. The second IRQ is required for the
-MPU401 mode (you have to use different IRQs for both purposes).
-There were earlier two DMA channels for SoundScape but the current driver
-version requires just one.
-
-The SoundScape card has a Motorola microcontroller which must initialized
-_after_ boot (the driver doesn't initialize it during boot).
-The initialization is done by running the 'ssinit' program which is
-distributed in the snd-util-3.0.tar.gz package. You have to edit two
-defines in the ssinit.c and then compile the program. You may run ssinit 
-manually (after each boot) or add it to /etc/rc.d/rc.local.
-
-The ssinit program needs the microcode file that comes with the DOS/Windows
-driver of the card. You will need to use version 1.30.00 or later
-of the microcode file (sndscape.co0 or sndscape.co1 depending on
-your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR
-MACHINE. The only way to get the new microcode file is to download
-and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub.
-
-Then you have to select the proper microcode file to use: soundscape.co0
-is the right one for most cards and sndscape.co1 is for few (older) cards
-made by Reveal and/or Spea. The driver has capability to detect the card
-version during boot. Look at the boot log messages in /var/adm/messages
-and locate the sound driver initialization message for the SoundScape
-card. If the driver displays string <Ensoniq Soundscape (old)>, you have
-an old card and you will need to use sndscape.co1. For other cards use
-soundscape.co0. New Soundscape revisions such as Elite and PnP use
-code files with higher numbers (.co2, .co3, etc.).
-
-NOTE!	Ensoniq Soundscape VIVO is not compatible with other Soundscape cards.
-	Currently it's possible to use it in Linux only with OSS/Linux
-	drivers.
-
-Check /var/adm/messages after running ssinit. The driver prints
-the board version after downloading the microcode file. That version
-number must match the number in the name of the microcode file (extension).
-
-Running ssinit with a wrong version of the sndscape.co? file is not
-dangerous as long as you don't try to use a file called sndscape.cod.
-If you have initialized the card using a wrong microcode file (sounds
-are terrible), just modify ssinit.c to use another microcode file and try
-again. It's possible to use an earlier version of sndscape.co[01] but it
-may sound weird.
-
-MAD16 (Pro) and Mozart
-----------------------
-
-You need to enable just the MAD16 /Mozart support when configuring
-the driver. _Don't_ enable SB, MPU401 or MSS. However you will need the
-/dev/audio, /dev/sequencer and MIDI supports.
-
-Mozart and OPTi 82C928 (the original MAD16) chips don't support
-MPU401 mode so enter just 0 when the configuration program asks the
-MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401
-mode.
-
-TB Tropez is based on the 82C929 chip. It has two MIDI ports.
-The one connected to the MAD16 chip is the second one (there is a second
-MIDI connector/pins somewhere??). If you have not connected the second MIDI
-port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of
-Tropez is jumper configurable and not connected to the MAD16 chip (the
-Maui driver can be used with it).
-
-Some MAD16 based cards may cause feedback, whistle or terrible noise if the
-line3 mixer channel is turned too high. This happens at least with Shuttle
-Sound System. Current driver versions set volume of line3 low enough so
-this should not be a problem.
-
-If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
-chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4
-to the file linux/drivers/sound/local.h (after running make config).
-
-MAD16 cards having a CS4231 codec support full duplex mode. This mode
-can be enabled by configuring the card to use two DMA channels. Possible
-DMA channel pairs are: 0&1, 1&0 and 3&0.
-
-NOTE! Cards having an OPTi 82C924/82C925 chip work with OSS/Free only in
-non-PnP mode (usually jumper selectable). The PnP mode is supported only
-by OSS/Linux.
-
-MV Jazz (ProSonic)
-------------------
-
-The Jazz16 driver is just a hack made to the SB Pro driver. However it works
-fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports
-when configuring the driver. The configuration program asks later if you
-want support for MV Jazz16 based cards (after asking SB base address). Answer
-'y' here and the driver asks the second (16 bit) DMA channel.
-
-The Jazz16 driver uses the MPU401 driver in a way which will cause
-problems if you have another MPU401 compatible card. In this case you must
-give address of the Jazz16 based MPU401 interface when the config
-program prompts for the MPU401 information. Then look at the MPU401
-specific section for instructions about configuring more than one MPU401 cards.
-
-Logitech Soundman Wave
-----------------------
-
-Read the above MV Jazz specific instructions first.
-
-The Logitech SoundMan Wave (don't confuse this with the SM16 or SM Games) is
-a MV Jazz based card which has an additional OPL4 based wave table
-synthesizer. The OPL4 chip is handled by an on board microcontroller
-which must be initialized during boot. The config program asks if
-you have a SM Wave immediately after asking the second DMA channel of jazz16.
-If you answer 'y', the config program will ask name of the file containing
-code to be loaded to the microcontroller. The file is usually called
-MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file
-may also be called as TSUNAMI.BIN or something else (older cards?).
-
-The OPL4 synth will be inaccessible without loading the microcontroller code.
-
-Also remember to enable SB MPU401 support if you want to use the OPL4 mode.
-(Don't enable the 'normal' MPU401 device as with some earlier driver
-versions (pre 3.5-alpha8)).
-
-NOTE!	Don't answer 'y' when the driver asks about SM Games support
-	(the next question after the MIDI0001.BIN name). However
-	answering 'y' doesn't cause damage your computer so don't panic. 
-
-Sound Galaxies
---------------
-
-There are many different Sound Galaxy cards made by Aztech. The 8 bit
-ones are fully SB or SB Pro compatible and there should be no problems
-with them. 
-
-The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
-an EEPROM chip for storing the configuration data. There is a microcontroller
-which initializes the card to match the EEPROM settings when the machine
-is powered on. These cards actually behave just like they have jumpers
-for all of the settings. Configure driver for MSS, MPU, SB/SB Pro  and OPL3 
-supports with these cards. 
-
-There are some new Sound Galaxies in the market. I have no experience with
-them so read the card's manual carefully.
-
-ESS ES1688 and ES688 'AudioDrive' based cards
----------------------------------------------
-
-Support for these two ESS chips is embedded in the SB driver.
-Configure these cards just like SB. Enable the 'SB MPU401 MIDI port'
-if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
-so you don't need to enable it (the driver uses normal SB MIDI automatically
-with ES688).
-
-NOTE! ESS cards are not compatible with MSS/WSS so don't worry if MSS support
-of OSS doesn't work with it.
-
-There are some ES1688/688 based sound cards and (particularly) motherboards
-which use software configurable I/O port relocation feature of the chip.
-This ESS proprietary feature is supported only by OSS/Linux.
-
-There are ES1688 based cards which use different interrupt pin assignment than
-recommended by ESS (5, 7, 9/2 and 10). In this case all IRQs don't work.
-At least a card called (Pearl?) Hypersound 16 supports IRQ 15 but it doesn't
-work.
-
-ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688
-probably works with OSS/Free after initialization using isapnptools.
-
-Reveal cards
-------------
-
-There are several different cards made/marketed by Reveal. Some of them
-are compatible with SoundScape and some use the MAD16 chip. You may have
-to look at the card and try to identify its origin.
-
-Diamond
--------
-
-The oldest (Sierra Aria based) sound cards made by Diamond are not supported
-(they may work if the card is initialized using DOS). The recent (LX?)
-models are based on the MAD16 chip which is supported by the driver.
-
-Audio Excel DSP16
------------------
-
-Support for this card is currently not functional. A new driver for it
-should be available later this year.
-
-PCMCIA cards
-------------
-
-Sorry, can't help. Some cards may work and some don't.
-
-TI TM4000M notebooks
---------------------
-
-These computers have a built in sound support based on the Jazz chipset.
-Look at the instructions for MV Jazz (above). It's also important to note
-that there is something wrong with the mouse port and sound at least on
-some TM models. Don't enable the "C&T 82C710 mouse port support" when
-configuring Linux. Having it enabled is likely to cause mysterious problems
-and kernel failures when sound is used.
-
-miroSOUND
----------
-
-The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used
-successfully. These cards are based on the MAD16, OPL4, and CS4231A chips
-and everything said in the section about MAD16 cards applies here,
-too. The only major difference between the PCMxx and other MAD16 cards
-is that instead of the mixer in the CS4231 codec a separate mixer
-controlled by an on-board 80C32 microcontroller is used. Control of
-the mixer takes place via the ACI (miro's audio control interface)
-protocol that is implemented in a separate lowlevel driver. Make sure
-you compile this ACI driver together with the normal MAD16 support
-when you use a miroSOUND PCMxx card. The ACI mixer is controlled by
-/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load
-time). Only in special cases you want to change something regularly on
-the CS4231 mixer.
-
-The miroSOUND PCM12 and PCM20 radio is capable of full duplex
-operation (simultaneous PCM replay and recording), which allows you to
-implement nice real-time signal processing audio effect software and
-network telephones. The ACI mixer has to be switched into the "solo"
-mode for duplex operation in order to avoid feedback caused by the
-mixer (input hears output signal). You can de-/activate this mode
-through toggleing the record button for the wave controller with an
-OSS-mixer.
-
-The PCM20 contains a radio tuner, which is also controlled by
-ACI. This radio tuner is supported by the ACI driver together with the
-miropcm20.o module. Also the 7-band equalizer is integrated
-(limited by the OSS-design). Developement has started and maybe
-finished for the RDS decoder on this card, too. You will be able to
-read RadioText, the Programme Service name, Programme TYpe and
-others. Even the v4l radio module benefits from it with a refined
-strength value. See aci.[ch] and miropcm20*.[ch] for more details.
-
-The following configuration parameters have worked fine for the PCM12
-in Markus Kuhn's system, many other configurations might work, too:
-CONFIG_MAD16_BASE=0x530, CONFIG_MAD16_IRQ=11, CONFIG_MAD16_DMA=3, 
-CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10,
-DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000.
-
-Bas van der Linden is using his PCM1-pro with a configuration that
-differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9
-
-Compaq Deskpro XL
------------------
-
-The builtin sound hardware of Compaq Deskpro XL is now supported. 
-You need to configure the driver with MSS and OPL3 supports enabled.
-In addition you need to manually edit linux/drivers/sound/local.h and
-to add a line containing "#define DESKPROXL" if you used 
-make menuconfig/xconfig.
-
-Others?
--------
-
-Since there are so many different sound cards, it's likely that I have 
-forgotten to mention many of them. Please inform me if you know yet another
-card which works with Linux, please inform me (or is anybody else
-willing to maintain a database of supported cards (just like in XF86)?).
-
-Cards not supported yet
-=======================
-
-Please check the version of sound driver you are using before 
-complaining that your card is not supported. It's possible you are 
-using a driver version which was released months before your card was
-introduced.
-
-First of all, there is an easy way to make most sound cards work with Linux.
-Just use the DOS based driver to initialize the card to a known state, then use
-loadlin.exe to boot Linux. If Linux is configured to use the same I/O, IRQ and
-DMA numbers as DOS, the card could work.
-(ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with
-new motherboards). This method works also with all/most PnP sound cards.
-
-Don't get fooled with SB compatibility. Most cards are compatible with
-SB but that may require a TSR which is not possible with Linux. If
-the card is compatible with MSS, it's a better choice. Some cards
-don't work in the SB and MSS modes at the same time.
-
-Then there are cards which are no longer manufactured and/or which
-are relatively rarely used (such as the 8 bit ProAudioSpectrum
-models). It's extremely unlikely that such cards ever get supported.
-Adding support for a new card requires much work and increases time
-required in maintaining the driver (some changes need to be done
-to all low level drivers and be tested too, maybe with multiple
-operating systems). For this reason I have made a decision to not support
-obsolete cards. It's possible that someone else makes a separately 
-distributed driver (diffs) for the card. 
-
-Writing a driver for a new card is not possible if there are no 
-programming information available about the card. If you don't
-find your new card from this file, look from the home page 
-(http://www.opensound.com/ossfree). Then please contact
-manufacturer of the card and ask if they have (or are willing to)
-released technical details of the card. Do this before contacting me. I
-can only answer 'no' if there are no programming information available.
-
-I have made decision to not accept code based on reverse engineering
-to the driver. There are three main reasons: First I don't want to break
-relationships to sound card manufacturers. The second reason is that
-maintaining and supporting a driver without any specs will be a pain.
-The third reason is that companies have freedom to refuse selling their
-products to other than Windows users.
-
-Some companies don't give low level technical information about their
-products to public or at least their require signing a NDA. It's not
-possible to implement a freeware driver for them. However it's possible
-that support for such cards become available in the commercial version
-of this driver (see http://www.4Front-tech.com/oss.html for more info).
-
-There are some common audio chipsets that are not supported yet. For example
-Sierra Aria and IBM Mwave. It's possible that these architectures
-get some support in future but I can't make any promises. Just look
-at the home page (http://www.opensound.com/ossfree/new_cards.html)
-for latest info.
-
-Information about unsupported sound cards and chipsets is welcome as well
-as free copies of sound cards, SDKs and operating systems.
-
-If you have any corrections and/or comments, please contact me.
-
-Hannu Savolainen
-hannu@opensound.com
-
-Personal home page:	   http://www.compusonic.fi/~hannu
-home page of OSS/Free: http://www.opensound.com/ossfree
-
-home page of commercial OSS
-(Open Sound System) drivers: http://www.opensound.com/oss.html
diff -urN linux-2.5.6-pre3/Documentation/sound/README.awe linux-2.5.6/Documentation/sound/README.awe
--- linux-2.5.6-pre3/Documentation/sound/README.awe	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/README.awe	Wed Dec 31 16:00:00 1969
@@ -1,218 +0,0 @@
-================================================================
-	AWE32 Sound Driver for Linux / FreeBSD
-		version 0.4.3; Nov. 1, 1998
-
-	Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-* GENERAL NOTES
-
-This is a sound driver extension for SoundBlaster AWE32 and other
-compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
-the wave synth operations.  The driver is provided for Linux 1.2.x
-and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
-Alpha systems.
-
-This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
-and provided "as is".  The original source (awedrv-0.4.3.tar.gz) and
-binary packages are available on the following URL:
-	http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
-Note that since the author is apart from this web site, the update is
-not frequent now.
-
-
-* NOTE TO LINUX USERS
-
-To enable this driver on linux-2.[01].x kernels, you need turn on 
-"AWE32 synth" options in sound menu when configure your linux kernel
-and modules.  The precise installation procedure is described in the
-AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
-
-If you're using PnP cards, the card must be initialized before loading
-the sound driver.  There're several options to do this:
-    - Initialize the card via ISA PnP tools, and load the sound module.
-    - Initialize the card on DOS, and load linux by loadlin.exe
-    - Use PnP kernel driver (for Linux-2.x.x)
-The detailed instruction for the solution using isapnp tools is found
-in many documents like above.  A brief instruction is also included in
-the installation document of this package.
-For PnP driver project, please refer to the following URL:
-	http://www-jcr.lmh.ox.ac.uk/~pnp/
-
-
-* USING THE DRIVER
-
-The awedrv has several different playing modes to realize easy channel 
-allocation for MIDI songs.  To hear the exact sound quality, you need
-to obtain the extended sequencer program, drvmidi or playmidi-2.5.
-
-For playing MIDI files, you *MUST* load the soundfont file on the
-driver previously by sfxload utility.  Otherwise you'll here no sounds 
-at all!  All the utilities and driver source packages are found in the
-above URL.  The sfxload program is included in the package
-awesfx-0.4.3.tgz.  Binary packages are available there, too.  See the
-instruction in each package for installation.
-
-Loading a soundfont file is very simple.  Just execute the command
-
-	% sfxload synthgm.sbk
-
-Then, sfxload transfers the file "synthgm.sbk" to the driver.
-Both SF1 and SF2 formats are accepted.
-
-Now you can hear midi musics by a midi player.
-
-	% drvmidi foo.mid
-
-If you run MIDI player after MOD player, you need to load soundfont
-files again, since MOD player programs clear the previous loaded
-samples by their own data.
-
-If you have only 512kb on the sound card, I recommend to use dynamic
-sample loading via -L option of drvmidi.  2MB GM/GS soundfont file is
-available in most midi files.
-
-	% sfxload synthgm
-	% drvmidi -L 2mbgmgs foo.mid
-
-This makes a big difference (believe me)!  For more details, please
-refer to the FAQ list which is available on the URL above.
-
-The current chorus, reverb and equalizer status can be changed by
-aweset utility program (included in awesfx package).  Note that
-some awedrv-native programs (like drvmidi and xmp) will change the
-current settings by themselves.  The aweset program is effective
-only for other programs like playmidi.
-
-Enjoy.
-
-
-* COMPILE FLAGS
-
-Compile conditions are defined in awe_config.h.
-
-[Compatibility Conditions]
-The following flags are defined automatically when using installation
-shell script.
-
-- AWE_MODULE_SUPPORT
-    indicates your Linux kernel supports module for each sound card
-    (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
-    as distributed in the RH5.0 package).
-    This flag is automatically set when you're using 2.1.x kernels.
-    You can pass the base address and memory size via the following
-    module options,
-	io = base I/O port address (eg. 0x620)
-	memsize = DRAM size in kilobytes (eg. 512)
-    As default, AWE driver probes these values automatically.
-
-
-[Hardware Conditions]
-You DON'T have to define the following two values.
-Define them only when the driver couldn't detect the card properly.
-
-- AWE_DEFAULT_BASE_ADDR		(default: not defined)
-    specifies the base port address of your AWE32 card.
-    0 means to autodetect the address.
-
-- AWE_DEFAULT_MEM_SIZE		(default: not defined)
-    specifies the memory size of your AWE32 card in kilobytes.
-    -1 means to autodetect its size.
-    
-
-[Sample Table Size]
-From ver.0.4.0, sample tables are allocated dynamically (except
-Linux-1.2.x system), so you need NOT to touch these parameters.
-Linux-1.2.x users may need to increase these values to appropriate size 
-if the sound card is equipped with more DRAM.
-
-- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
-
-
-[Other Conditions]
-
-- AWE_ALWAYS_INIT_FM		(default: not defined)
-    indicates the AWE driver always initialize FM passthrough even
-    without DRAM on board.  Emu8000 chip has a restriction for playing
-    samples on DRAM that at least two channels must be occupied as
-    passthrough channels. 
-
-- AWE_DEBUG_ON			(default: defined)
-    turns on debugging messages if defined.
-
-- AWE_HAS_GUS_COMPATIBILITY	(default: defined)
-    Enables GUS compatibility mode if defined, reading GUS patches and 
-    GUS control commands.  Define this option to use GMOD or other
-    GUS module players.
-
-- CONFIG_AWE32_MIDIEMU		(default: defined)
-    Adds a MIDI emulation device by Emu8000 wavetable.  The emulation
-    device can be accessed as an external MIDI, and sends the MIDI
-    control codes directly.  XG and GS sysex/NRPN are accepted.
-    No MIDI input is supported.
-
-- CONFIG_AWE32_MIXER		(default: not defined)
-    Adds a mixer device for AWE32 bass/treble equalizer control.
-    You can access this device using /dev/mixer?? (usually mixer01).
-
-- AWE_USE_NEW_VOLUME_CALC	(default: defined)
-    Use the new method to calculate the volume change as compatible
-    with DOS/Win drivers.  This option can be toggled via aweset
-    program, or drvmidi player.
-
-- AWE_CHECK_VTARGET		(default: defined)
-    Check the current volume target value when searching for an
-    empty channel to allocate a new voice.  This is experimentally
-    implemented in this version.  (probably, this option doesn't
-    affect the sound quality severely...)
-
-- AWE_ALLOW_SAMPLE_SHARING	(default: defined)
-   Allow sample sharing for differently loaded patches.
-   This function is available only together with awesfx-0.4.3p3.
-   Note that this is still an experimental option.
-
-- DEF_FM_CHORUS_DEPTH		(default: 0x10)
-    The default strength to be sent to the chorus effect engine.
-    From 0 to 0xff.  Larger numbers may often cause weird sounds.
-
-- DEF_FM_REVERB_DEPTH		(default: 0x10)
-    The default strength to be sent to the reverb effect engine.
-    From 0 to 0xff.  Larger numbers may often cause weird sounds.
-
-
-* ACKNOWLEDGMENTS
-
-Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
-on programming of AWE32.  Much code is brought from his AWE32-native 
-MOD player, ALMP.
-The port of awedrv to FreeBSD is done by Randall Hopper
-(rhh@ct.picker.com).
-The new volume calculation routine was derived from Mark Weaver's
-ADIP compatible routines.
-I also thank linux-awe-ml members for their efforts
-to reboot their system many times :-)
-
-
-* TODO'S
-
-- Complete DOS/Win compatibility
-- DSP-like output
-
-
-* COPYRIGHT
-
-Copyright (C) 1996-1998 Takashi Iwai
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
diff -urN linux-2.5.6-pre3/Documentation/sound/README.modules linux-2.5.6/Documentation/sound/README.modules
--- linux-2.5.6-pre3/Documentation/sound/README.modules	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/Documentation/sound/README.modules	Wed Dec 31 16:00:00 1969
@@ -1,105 +0,0 @@
-Building a modular sound driver
-================================
-
-  The following information is current as of linux-2.1.85. Check the other
-readme files, especially README.OSS, for information not specific to
-making sound modular.
-
-  First, configure your kernel. This is an idea of what you should be
-setting in the sound section:
-
-<M> Sound card support 
-
-<M> 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support 
-
-  I have SoundBlaster. Select your card from the list.
-
-<M> Generic OPL2/OPL3 FM synthesizer support 
-<M> FM synthesizer (YM3812/OPL-3) support 
-
-  If you don't set these, you will probably find you can play .wav files
-but not .midi. As the help for them says, set them unless you know your
-card does not use one of these chips for FM support.
-
-  Once you are configured, make zlilo, modules, modules_install; reboot.
-Note that it is no longer necessary or possible to configure sound in the
-drivers/sound dir. Now one simply configures and makes one's kernel and
-modules in the usual way.
-
- Then, add to your /etc/modules.conf something like:
-
-alias char-major-14 sb
-post-install sb /sbin/modprobe "-k" "adlib_card"
-options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
-options adlib_card io=0x388     # FM synthesizer
-
- Alternatively, if you have compiled in kernel level ISAPnP support:
-
-alias char-major-14 sb
-post-install sb /sbin/modprobe "-k" "adlib_card"
-options adlib_card io=0x388
-
-  The effect of this is that the sound driver and all necessary bits and
-pieces autoload on demand, assuming you use kerneld (a sound choice) and
-autoclean when not in use. Also, options for the device drivers are
-set. They will not work without them. Change as appropriate for your card.
-If you are not yet using the very cool kerneld, you will have to "modprobe
--k sb" yourself to get things going. Eventually things may be fixed so
-that this kludgery is not necessary; for the time being, it seems to work
-well.
-
-  Replace 'sb' with the driver for your card, and give it the right
-options. To find the filename of the driver, look in
-/lib/modules/<kernel-version>/misc. Mine looks like:
-
-adlib_card.o # This is the generic OPLx driver
-opl3.o # The OPL3 driver
-sb.o # <<The SoundBlaster driver. Yours may differ.>>
-sound.o # The sound driver
-uart401.o # Used by sb, maybe other cards
-
- Whichever card you have, try feeding it the options that would be the
-default if you were making the driver wired, not as modules. You can look
-at the init_module() code for the card to see what args are expected.
-
- Note that at present there is no way to configure the io, irq and other
-parameters for the modular drivers as one does for the wired drivers.. One
-needs to pass the modules the necessary parameters as arguments, either
-with /etc/modules.conf or with command-line args to modprobe, e.g.
-
-modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
-modprobe -k adlib_card io=0x388
-
- recommend using /etc/modules.conf.
-
-Persistent DMA Buffers:
-
-The sound modules normally allocate DMA buffers during open() and
-deallocate them during close(). Linux can often have problems allocating
-DMA buffers for ISA cards on machines with more than 16MB RAM. This is
-because ISA DMA buffers must exist below the 16MB boundary and it is quite
-possible that we can't find a large enough free block in this region after
-the machine has been running for any amount of time. The way to avoid this
-problem is to allocate the DMA buffers during module load and deallocate
-them when the module is unloaded. For this to be effective we need to load
-the sound modules right after the kernel boots, either manually or by an
-init script, and keep them around until we shut down. This is a little
-wasteful of RAM, but it guarantees that sound always works.
-
-To make the sound driver use persistent DMA buffers we need to pass the
-sound.o module a "dmabuf=1" command-line argument. This is normally done
-in /etc/modules.conf like so:
-
-options sound		dmabuf=1
-
-If you have 16MB or less RAM or a PCI sound card, this is wasteful and
-unnecessary. It is possible that machine with 16MB or less RAM will find
-this option useful, but if your machine is so memory-starved that it
-cannot find a 64K block free, you will be wasting even more RAM by keeping
-the sound modules loaded and the DMA buffers allocated when they are not
-needed. The proper solution is to upgrade your RAM. But you do also have
-this improper solution as well. Use it wisely.
-
-  I'm afraid I know nothing about anything but my setup, being more of a
-text-mode guy anyway. If you have options for other cards or other helpful
-hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb.
diff -urN linux-2.5.6-pre3/Documentation/sound/README.ymfsb linux-2.5.6/Documentation/sound/README.ymfsb
--- linux-2.5.6-pre3/Documentation/sound/README.ymfsb	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/Documentation/sound/README.ymfsb	Wed Dec 31 16:00:00 1969
@@ -1,107 +0,0 @@
-Legacy audio driver for YMF7xx PCI cards.
-
-
-FIRST OF ALL
-============
-
-  This code references YAMAHA's sample codes and data sheets.
-  I respect and thank for all people they made open the informations
-  about YMF7xx cards.
-
-  And this codes heavily based on Jeff Garzik <jgarzik@pobox.com>'s
-  old VIA 82Cxxx driver (via82cxxx.c). I also respect him.
-
-
-DISCLIMER
-=========
-
- This driver is currently at early ALPHA stage. It may cause serious
- damage to your computer when used.
- PLEASE USE IT AT YOUR OWN RISK.
-
-
-ABOUT THIS DRIVER
-=================
-
-  This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754
- cards. When enabled, your card acts as "SoundBlaster Pro" compatible card.
- It can only play 22.05kHz / 8bit / Stereo samples, control external MIDI
- port.
- If you want to use your card as recent "16-bit" card, you should use
- Alsa or OSS/Linux driver. Of course you can write native PCI driver for
- your cards :)
-
-
-USAGE
-=====
-
- # modprobe ymfsb (options)
-
-
-OPTIONS FOR MODULE
-==================
-
-  io           : SB base address     (0x220, 0x240, 0x260, 0x280)
-  synth_io     : OPL3 base address   (0x388, 0x398, 0x3a0, 0x3a8)
-  dma          : DMA number          (0,1,3)
-  master_volume: AC'97 PCM out Vol   (0-100)
-  spdif_out    : SPDIF-out flag      (0:disable 1:enable)
-
- These options will change in future...
-
-
-FREQUENCY
-=========
-
-  When playing sounds via this driver, you will hear its pitch is slightly
- lower than original sounds. Since this driver recognizes your card acts
- with 21.739kHz sample rates rather than 22.050kHz (I think it must be
- hardware restriction). So many players become tone deafness.
- To prevent this, you should express some options to your sound player
- that specify correct sample frequency. For example, to play your MP3 file
- correctly with mpg123, specify the frequency like following:
-
-  %  mpg123 -r 21739 foo.mp3
-
-
-SPDIF OUT
-=========
-
-  With installing modules with option 'spdif_out=1', you can enjoy your
- sounds from SPDIF-out of your card (if it had).
- Its Fs is fixed to 48kHz (It never means the sample frequency become 
- up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your
- digital-in capable components has to be able to handle 48kHz Fs.
-
-
-COPYING
-=======
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-TODO
-====
- * support for multiple cards
-   (set the different SB_IO,MPU_IO,OPL_IO for each cards)
-
- * support for OPL (dmfm) : There will be no requirements... :-<
-
-
-AUTHOR
-======
-
- Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
diff -urN linux-2.5.6-pre3/Documentation/sound/SoundPro linux-2.5.6/Documentation/sound/SoundPro
--- linux-2.5.6-pre3/Documentation/sound/SoundPro	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/SoundPro	Wed Dec 31 16:00:00 1969
@@ -1,105 +0,0 @@
-Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o)
-------------------------------------------------------------------------------
-
-( Be sure to read Documentation/sound/CMI8330 too )
-
-Ion Badulescu, ionut@cs.columbia.edu
-February 24, 1999
-
-(derived from the OPL3-SA2 documentation by Scott Murray)
-
-The SoundPro CMI8330 (ISA) is a chip usually found on some Taiwanese
-motherboards.  The official name in the documentation is CMI8330, SoundPro
-is the nickname and the big inscription on the chip itself.
-
-The chip emulates a WSS as well as a SB16, but it has certain differences
-in the mixer section which require separate support. It also emulates an
-MPU401 and an OPL3 synthesizer, so you probably want to enable support
-for these, too.
-
-The chip identifies itself as an AD1848, but its mixer is significantly
-more advanced than the original AD1848 one. If your system works with
-either WSS or SB16 and you are having problems with some mixer controls
-(no CD audio, no line-in, etc), you might want to give this driver a try.
-Detection should work, but it hasn't been widely tested, so it might still
-mis-identify the chip. You can still force soundpro=1 in the modprobe
-parameters for ad1848. Please let me know if it happens to you, so I can
-adjust the detection routine.
-
-The chip is capable of doing full-duplex, but since the driver sees it as an
-AD1848, it cannot take advantage of this.  Moreover, the full-duplex mode is
-not achievable through the WSS interface, b/c it needs a dma16 line which is
-assigned only to the SB16 subdevice (with isapnp). Windows documentation
-says the user must use WSS Playback and SB16 Recording for full-duplex, so
-it might be possible to do the same thing under Linux. You can try loading
-up both ad1848 and sb then use one for playback and the other for
-recording. I don't know if this works, b/c I haven't tested it. Anyway, if
-you try it, be very careful: the SB16 mixer *mostly* works, but certain
-settings can have unexpected effects. Use the WSS mixer for best results.
-
-There is also a PCI SoundPro chip. I have not seen this chip, so I have
-no idea if the driver will work with it. I suspect it won't.
-
-As with PnP cards, some configuration is required.  There are two ways
-of doing this.  The most common is to use the isapnptools package to
-initialize the card, and use the kernel module form of the sound
-subsystem and sound drivers.  Alternatively, some BIOS's allow manual
-configuration of installed PnP devices in a BIOS menu, which should
-allow using the non-modular sound drivers, i.e. built into the kernel.
-Since in this latter case you cannot use module parameters, you will
-have to enable support for the SoundPro at compile time.
-
-The IRQ and DMA values can be any that are considered acceptable for a
-WSS.  Assuming you've got isapnp all happy, then you should be able to
-do something like the following (which *must* match the isapnp/BIOS
-configuration):
-
-modprobe ad1848 io=0x530 irq=11 dma=0 soundpro=1
--and maybe-
-modprobe sb io=0x220 irq=5 dma=1 dma16=5
-
--then-
-modprobe mpu401 io=0x330 irq=9
-modprobe opl3 io=0x388
-
-If all goes well and you see no error messages, you should be able to
-start using the sound capabilities of your system.  If you get an
-error message while trying to insert the module(s), then make
-sure that the values of the various arguments match what you specified
-in your isapnp configuration file, and that there is no conflict with
-another device for an I/O port or interrupt.  Checking the contents of
-/proc/ioports and /proc/interrupts can be useful to see if you're
-butting heads with another device.
-
-If you do not see the chipset version message, and none of the other
-messages present in the system log are helpful, try adding 'debug=1'
-to the ad1848 parameters, email me the syslog results and I'll do
-my best to help. 
-
-Lastly, if you're using modules and want to set up automatic module
-loading with kmod, the kernel module loader, here is the section I
-currently use in my conf.modules file:
-
-# Sound
-post-install sound modprobe -k ad1848; modprobe -k mpu401; modprobe -k opl3
-options ad1848 io=0x530 irq=11 dma=0
-options sb io=0x220 irq=5 dma=1 dma16=5
-options mpu401 io=0x330 irq=9
-options opl3 io=0x388
-
-The above ensures that ad1848 will be loaded whenever the sound system
-is being used.
-
-Good luck.
-
-Ion
-
-NOT REALLY TESTED:
-- recording
-- recording device selection
-- full-duplex
-
-TODO:
-- implement mixer support for surround, loud, digital CD switches.
-- come up with a scheme which allows recording volumes for each subdevice.
-This is a major OSS API change.
diff -urN linux-2.5.6-pre3/Documentation/sound/Soundblaster linux-2.5.6/Documentation/sound/Soundblaster
--- linux-2.5.6-pre3/Documentation/sound/Soundblaster	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/Documentation/sound/Soundblaster	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-modprobe sound
-insmod uart401
-insmod sb ...
-
-This loads the driver for the Sound Blaster and assorted clones. Cards that
-are covered by other drivers should not be using this driver.
-
-The Sound Blaster module takes the following arguments
-
-io		I/O address of the Sound Blaster chip (0x220,0x240,0x260,0x280)
-irq		IRQ of the Sound Blaster chip (5,7,9,10)
-dma		8-bit DMA channel for the Sound Blaster (0,1,3)
-dma16		16-bit DMA channel for SB16 and equivalent cards (5,6,7)
-mpu_io		I/O for MPU chip if present (0x300,0x330)
-
-sm_games=1	Set if you have a Logitech soundman games
-acer=1		Set this to detect cards in some ACER notebooks
-mwave_bug=1	Set if you are trying to use this driver with mwave (see on)
-type		Use this to specify a specific card type
-
-The following arguments are taken if ISAPnP support is compiled in
-
-isapnp=0	Set this to disable ISAPnP detection (use io=0xXXX etc. above)
-multiple=0	Set to disable detection of multiple Soundblaster cards.
-		Consider it a bug if this option is needed, and send in a
-		report.
-pnplegacy=1	Set this to be able to use a PnP card(s) along with a single
-		non-PnP (legacy) card.  Above options for io, irq, etc. are
-		needed, and will apply only to the legacy card.
-reverse=1	Reverses the order of the search in the PnP table.
-uart401=1	Set to enable detection of mpu devices on some clones.
-isapnpjump=n	Jumps to slot n in the driver's PnP table. Use the source,
-		Luke.
-
-You may well want to load the opl3 driver for synth music on most SB and
-clone SB devices
-
-insmod opl3 io=0x388
-
-Using Mwave
-
-To make this driver work with Mwave you must set mwave_bug. You also need
-to warm boot from DOS/Windows with the required firmware loaded under this
-OS. IBM are being difficult about documenting how to load this firmware.
-
-Avance Logic ALS007
-
-This card is supported; see the separate file ALS007 for full details.
-
-Avance Logic ALS100
-
-This card is supported; setup should be as for a standard Sound Blaster 16.
-The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)".
diff -urN linux-2.5.6-pre3/Documentation/sound/Tropez+ linux-2.5.6/Documentation/sound/Tropez+
--- linux-2.5.6-pre3/Documentation/sound/Tropez+	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/Documentation/sound/Tropez+	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-From: Paul Barton-Davis <pbd@op.net>
-
-Here is the configuration I use with a Tropez+ and my modular
-driver:
-
-  alias char-major-14 wavefront
-  alias synth0 wavefront
-  alias mixer0 cs4232
-  alias audio0 cs4232
-  pre-install wavefront modprobe "-k" "cs4232"
-  post-install wavefront modprobe "-k" "opl3"
-  options wavefront io=0x200 irq=9
-  options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
-  options opl3 io=0x388
-
-Things to note: 
-
-       the wavefront options "io" and "irq" ***MUST*** match the "synthio"
-       and "synthirq" cs4232 options.
-
-       you can do without the opl3 module if you don't
-       want to use the OPL/[34] synth on the soundcard
-
-       the opl3 io parameter is conventionally not adjustable.
-
-Please see drivers/sound/README.wavefront for more details.
diff -urN linux-2.5.6-pre3/Documentation/sound/VIA-chipset linux-2.5.6/Documentation/sound/VIA-chipset
--- linux-2.5.6-pre3/Documentation/sound/VIA-chipset	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/Documentation/sound/VIA-chipset	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-Running sound cards on VIA chipsets
-
-o	There are problems with VIA chipsets and sound cards that appear to
-	lock the hardware solidly. Test programs under DOS have verified the
-	problem exists on at least some (but apparently not all) VIA boards
-
-o	VIA have so far failed to bother to answer support mail on the subject
-	so if you are a VIA engineer feeling aggrieved as you read this 
-	document go chase your own people. If there is a workaround please
-	let us know so we can implement it.
-
-
-Certain patterns of ISA DMA access used for most PC sound cards cause the
-VIA chipsets to lock up. From the collected reports this appears to cover a
-wide range of boards. Some also lock up with sound cards under Win* as well.
-
-Linux implements a workaround providing your chipset is PCI and you compiled
-with PCI Quirks enabled. If so you will see a message
-	"Activating ISA DMA bug workarounds"
-
-during booting. If you have a VIA PCI chipset that hangs when you use the
-sound and is not generating this message even with PCI quirks enabled
-please report the information to the linux-kernel list (see REPORTING-BUGS).
-
-If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA
-chipset board you need to do the following to build a special kernel for
-your board
-
-	edit linux/include/asm-i386/dma.h
-
-change
-
-#define isa_dma_bridge_buggy 	(0)
-
-to
-
-#define isa_dma_bridge_buggy 	(1)
-
-and rebuild a kernel without PCI quirk support.
-
-
-Other than this particular glitch the VIA [M]VP* chipsets appear to work
-perfectly with Linux.
diff -urN linux-2.5.6-pre3/Documentation/sound/VIBRA16 linux-2.5.6/Documentation/sound/VIBRA16
--- linux-2.5.6-pre3/Documentation/sound/VIBRA16	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/Documentation/sound/VIBRA16	Wed Dec 31 16:00:00 1969
@@ -1,80 +0,0 @@
-Sound Blaster 16X Vibra addendum
---------------------------------
-by Marius Ilioaea <mariusi@protv.ro>
-   Stefan Laudat  <stefan@asit.ro>
-
-Sat Mar 6 23:55:27 EET 1999
-
-			Hello again,
-	
-	Playing with a SB Vibra 16x soundcard we found it very difficult
-to setup because the kernel reported a lot of DMA errors and wouldn't
-simply play any sound.
-	A good starting point is that the vibra16x chip full-duplex facility
-is neither still exploited by the sb driver found in the linux kernel 
-(tried it with a 2.2.2-ac7), nor in the commercial OSS package (it reports
-it as half-duplex soundcard). Oh, I almost forgot, the RedHat sndconfig
-failed detecting it ;)
-	So, the big problem still remains, because the sb module wants a
-8-bit and a 16-bit dma, which we could not allocate for vibra... it supports
-only two 8-bit dma channels, the second one will be passed to the module
-as a 16 bit channel, the kernel will yield about that but everything will
-be okay, trust us. 
-	The only inconvenient you may find is that you will have
-some sound playing jitters if you have HDD dma support enabled - but this
-will happen with almost all soundcards...
-
-	A fully working isapnp.conf is just here:
-
-<snip here>
-
-(READPORT 0x0203)
-(ISOLATE PRESERVE)
-(IDENTIFY *)
-(VERBOSITY 2)
-(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
-# SB 16 and OPL3 devices
-(CONFIGURE CTL00f0/-1 (LD 0
-(INT 0 (IRQ 5 (MODE +E)))
-(DMA 0 (CHANNEL 1))
-(DMA 1 (CHANNEL 3))
-(IO 0 (SIZE 16) (BASE 0x0220))
-(IO 2 (SIZE 4) (BASE 0x0388))
-(NAME "CTL00f0/-1[0]{Audio               }")
-(ACT Y)
-))
-
-# Joystick device - only if you need it :-/
-
-(CONFIGURE CTL00f0/-1 (LD 1
-(IO 0 (SIZE 1) (BASE 0x0200))
-(NAME "CTL00f0/-1[1]{Game                }")
-(ACT Y)
-))
-(WAITFORKEY)
-
-<end of snipping>
-
-	So, after a good kernel modules compilation and a 'depmod -a kernel_ver'
-you may want to:
-
-modprobe sb io=0x220 irq=5 dma=1 dma16=3
-
-	Or, take the hard way:
-
-insmod souncore
-insmod sound
-insmod uart401
-insmod sb io=0x220 irq=5 dma=1 dma16=3
-# do you need MIDI?
-insmod opl3=0x388
-
-	Just in case, the kernel sound support should be:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_OSS=m
-CONFIG_SOUND_SB=m
-	
-	Enjoy your new noisy Linux box! ;)
-	
-
diff -urN linux-2.5.6-pre3/Documentation/sound/WaveArtist linux-2.5.6/Documentation/sound/WaveArtist
--- linux-2.5.6-pre3/Documentation/sound/WaveArtist	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/Documentation/sound/WaveArtist	Wed Dec 31 16:00:00 1969
@@ -1,170 +0,0 @@
-
- (the following is from the armlinux CVS)
-
- WaveArtist mixer and volume levels can be accessed via these commands:
-
-  nn30	read registers nn, where nn = 00 - 09 for mixer settings
-		                              0a - 13 for channel volumes
-  mm31	write the volume setting in pairs, where mm = (nn - 10) / 2
-  rr32	write the mixer settings in pairs, where rr = nn/2
-  xx33	reset all settings to default
-  0y34	select mono source, y=0 = left, y=1 = right
-
-                                           bits
- nn  15  14 13 12 11   10    9     8     7    6     5     4     3     2     1     0
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 00 | 0 | 0  0  1  1 | left line mixer gain       | left aux1 mixer gain        |lmute|
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 01 | 0 | 0  1  0  1 | left aux2 mixer gain       | right 2 left mic gain       |mmute|
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 02 | 0 | 0  1  1  1 | left mic mixer gain        | left mic  | left mixer gain |dith |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 03 | 0 | 1  0  0  1 | left mixer input select                |lrfg | left ADC gain   |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 04 | 0 | 1  0  1  1 | right line mixer gain      | right aux1 mixer gain       |rmute|
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 05 | 0 | 1  1  0  1 | right aux2 mixer gain      | left 2 right mic gain       |test |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 06 | 0 | 1  1  1  1 | right mic mixer gain       | right mic |right mixer gain |rbyps|
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 07 | 1 | 0  0  0  1 | right mixer select                     |rrfg | right ADC gain  |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 08 | 1 | 0  0  1  1 | mono mixer gain            |right ADC mux sel|left ADC mux sel |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 09 | 1 | 0  1  0  1 |loopb|left linout|loop|ADCch|TxFch|OffCD|test |loopb|loopb|osamp|
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0a | 0 | left PCM channel volume                                                     |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0b | 0 | right PCM channel volume                                                    |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0c | 0 | left FM channel volume                                                      |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0d | 0 | right FM channel volume                                                     |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0e | 0 | left wavetable channel volume                                               |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 0f | 0 | right wavetable channel volume                                              |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 10 | 0 | left PCM expansion channel volume                                           |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 11 | 0 | right PCM expansion channel volume                                          |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 12 | 0 | left FM expansion channel volume                                            |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
- 13 | 0 | right FM expansion channel volume                                           |
-----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
-
- lmute: left mute
- mmute: mono mute
- dith: dithds
- lrfg:
- rmute: right mute
- rbyps: right bypass
- rrfg:
- ADCch:
- TxFch:
- OffCD:
- osamp:
-
- And the following diagram is derived from the description in the CVS archive:
-
- MIC L (mouthpiece)
-   +------+
- -->PreAmp>-\
-   +--^---+ |
-      |     |
-    r2b4-5  |                                +--------+
-       /----*-------------------------------->5       |
-       |                                     |        |
-       | /----------------------------------->4       |
-       | |                                   |        |
-       | | /--------------------------------->3 1of5  |  +---+
-       | | |                                 |  mux   >-->AMP>--> ADC L
-       | | | /------------------------------->2       |  +-^-+
-       | | | |                               |        |    |
- Line  | | | | +----+  +------+  +---+  /---->1       |  r3b3-0
- ------------*->mute>--> Gain >-->   |  |    |        |
-  L    | | |   +----+  +------+  |   |  |  *->0       |
-       | | |                     |   |  |    +---^----+
- Aux2  | | |   +----+  +------+  |   |  |        |
- ----------*--->mute>--> Gain >--> M |  |     r8b0-2
-  L    | |     +----+  +------+  |   |  |
-       | |                       |   |  \------\
- Aux1  | |     +----+  +------+  |   |         |
- --------*----->mute>--> Gain >--> I |         |
-  L    |       +----+  +------+  |   |         |
-       |                         |   |         |
-       |       +----+  +------+  |   |  +---+  |
-       *------->mute>--> Gain >--> X >-->AMP>--*
-       |       +----+  +------+  |   |  +-^-+  |
-       |                         |   |    |    |
-       |       +----+  +------+  |   |  r2b1-3 |  
-       | /----->mute>--> Gain >--> E |         |
-       | |     +----+  +------+  |   |         |
-       | |                       |   |         |
-       | |     +----+  +------+  |   |         |
-       | | /--->mute>--> Gain >--> R |         |
-       | | |   +----+  +------+  |   |         |
-       | | |                     |   |         |   r9b8-9
-       | | |   +----+  +------+  |   |         |     |
-       | | | /->mute>--> Gain >-->   |         | +---v---+
-       | | | | +----+  +------+  +---+       /-*->0      |
- DAC   | | | |                               |   |       |
- ------------*----------------------------------->?      |  +----+
-  L    | | |                                 |   |  Mux  >-->mute>--> L output
-       | | |                                 | /->?      |  +--^-+
-       | | |                                 | | |       |     |
-       | | |                           /--------->?      |   r0b0
-       | | |                           |     | | +-------+
-       | | |                           |     | |
- Mono  | | |                           |     | | +-------+
- ----------*                           |     \--->       |  +----+
-       | | |                           |       | |  Mix  >-->mute>--> Mono output
-       | | |                           |       *->       |  +--^-+
-       | | |                           |       | +-------+     |
-       | | |                           |       |             r1b0
- DAC   | | |                           |       | +-------+
- ------------*-------------------------*--------->1      |  +----+
-  R    | | | |                                 | |  Mux  >-->mute>--> R output
-       | | | | +----+  +------+  +---+         *->0      |  +--^-+
-       | | | \->mute>--> Gain >-->   |         | +---^---+     |
-       | | |   +----+  +------+  |   |         |     |       r5b0
-       | | |                     |   |         |   r6b0
-       | | |   +----+  +------+  |   |         |
-       | | \--->mute>--> Gain >--> M |         |
-       | |     +----+  +------+  |   |         |
-       | |                       |   |         |
-       | |     +----+  +------+  |   |         |
-       | *----->mute>--> Gain >--> I |         |
-       | |     +----+  +------+  |   |         |
-       | |                       |   |         |
-       | |     +----+  +------+  |   |  +---+  |
-       \------->mute>--> Gain >--> X >-->AMP>--*
-         |     +----+  +------+  |   |  +-^-+  |
-      /--/                       |   |    |    |
- Aux1 |        +----+  +------+  |   |  r6b1-3 |
- -------*------>mute>--> Gain >--> E |         |
-  R   | |      +----+  +------+  |   |         |
-      | |                        |   |         |
- Aux2 | |      +----+  +------+  |   |  /------/
- ---------*---->mute>--> Gain >--> R |  |
-  R   | | |    +----+  +------+  |   |  |
-      | | |                      |   |  |    +--------+
- Line | | |    +----+  +------+  |   |  |  *->0       |
- -----------*-->mute>--> Gain >-->   |  |    |        |
-  R   | | | |  +----+  +------+  +---+  \---->1       |
-      | | | |                                |        |
-      | | | \-------------------------------->2       |  +---+
-      | | |                                  |  Mux   >-->AMP>--> ADC R
-      | | \---------------------------------->3       |  +-^-+
-      | |                                    |        |    |
-      | \------------------------------------>4       |  r7b3-0
-      |                                      |        |
-      \-----*-------------------------------->5       |
-            |                                +---^----+
-    r6b4-5  |                                    |
-      |     |                                  r8b3-5
-   +--v---+ |
- -->PreAmp>-/
-   +------+
- MIC R (electret mic)
diff -urN linux-2.5.6-pre3/Documentation/sound/Wavefront linux-2.5.6/Documentation/sound/Wavefront
--- linux-2.5.6-pre3/Documentation/sound/Wavefront	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/Documentation/sound/Wavefront	Wed Dec 31 16:00:00 1969
@@ -1,341 +0,0 @@
-	     An OSS/Free Driver for WaveFront soundcards
-	       (Turtle Beach Maui, Tropez, Tropez Plus)
-
-		     Paul Barton-Davis, July 1998
-
-			  VERSION 0.2.5
-
-Driver Status
--------------
-
-Requires: Kernel 2.1.106 or later (the driver is included with kernels
-2.1.109 and above)
-	  
-As of 7/22/1998, this driver is currently in *BETA* state. This means
-that it compiles and runs, and that I use it on my system (Linux
-2.1.106) with some reasonably demanding applications and uses.  I
-believe the code is approaching an initial "finished" state that
-provides bug-free support for the Tropez Plus.
-
-Please note that to date, the driver has ONLY been tested on a Tropez
-Plus. I would very much like to hear (and help out) people with Tropez
-and Maui cards, since I think the driver can support those cards as
-well. 
-
-Finally, the driver has not been tested (or even compiled) as a static
-(non-modular) part of the kernel. Alan Cox's good work in modularizing
-OSS/Free for Linux makes this rather unnecessary.
-
-Some Questions
---------------
-
-**********************************************************************
-0) What does this driver do that the maui driver did not ?
-**********************************************************************
-
-* can fully initialize a WaveFront card from cold boot - no DOS 
-          utilities needed
-* working patch/sample/program loading and unloading (the maui
-      driver didn't document how to make this work, and assumed
-      user-level preparation of the patch data for writing
-      to the board. ick.)
-* full user-level access to all WaveFront commands
-* for the Tropez Plus, (primitive) control of the YSS225 FX processor
-* Virtual MIDI mode supported - 2 MIDI devices accessible via the
-          WaveFront's MPU401/UART emulation. One
-	  accesses the WaveFront synth, the other accesses the
-	  external MIDI connector. Full MIDI read/write semantics
-	  for both devices.
-* OSS-compliant /dev/sequencer interface for the WaveFront synth,
-	  including native and GUS-format patch downloading.
-* semi-intelligent patch management (prototypical at this point)
-
-**********************************************************************
-1) What to do about MIDI interfaces ?
-**********************************************************************
-
-The Tropez Plus (and perhaps other WF cards) can in theory support up
-to 2 physical MIDI interfaces. One of these is connected to the
-ICS2115 chip (the WaveFront synth itself) and is controlled by
-MPU/UART-401 emulation code running as part of the WaveFront OS.  The
-other is controlled by the CS4232 chip present on the board. However,
-physical access to the CS4232 connector is difficult, and it is
-unlikely (though not impossible) that you will want to use it.
-
-An older version of this driver introduced an additional kernel config
-variable which controlled whether or not the CS4232 MIDI interface was
-configured. Because of Alan Cox's work on modularizing the sound
-drivers, and now backporting them to 2.0.34 kernels, there seems to be
-little reason to support "static" configuration variables, and so this
-has been abandoned in favor of *only* module parameters. Specifying
-"mpuio" and "mpuirq" for the cs4232 parameter will result in the
-CS4232 MIDI interface being configured; leaving them unspecified will
-leave it unconfigured (and thus unusable).
-
-BTW, I have heard from one Tropez+ user that the CS4232 interface is
-more reliable than the ICS2115 one. I have had no problems with the
-latter, and I don't have the right cable to test the former one
-out. Reports welcome.
-
-**********************************************************************
-2) Why does line XXX of the code look like this .... ?
-**********************************************************************
-
-Either because its not finished yet, or because you're a better coder
-than I am, or because you don't understand some aspect of how the card
-or the code works. 
-
-I absolutely welcome comments, criticisms and suggestions about the
-design and implementation of the driver. 
-
-**********************************************************************
-3) What files are included ?
-**********************************************************************
-
-   drivers/sound/README.wavefront       -- this file
-
-   drivers/sound/wavefront.patch	-- patches for the 2.1.106 sound drivers
-					   needed to make the rest of this work
-				           DO NOT USE IF YOU'VE APPLIED THEM 
-					   BEFORE, OR HAVE 2.1.109 OR ABOVE
-
-   drivers/sound/wavfront.c             -- the driver
-   drivers/sound/ys225.h                -- data declarations for FX config
-   drivers/sound/ys225.c                -- data definitions for FX config
-   drivers/sound/wf_midi.c              -- the "uart401" driver 
-   				              to support virtual MIDI mode.
-   include/wavefront.h                  -- the header file
-   Documentation/sound/Tropez+          -- short docs on configuration
-
-**********************************************************************
-4) How do I compile/install/use it ?
-**********************************************************************
-
-PART ONE: install the source code into your sound driver directory
-
-  cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
-  tar -zxvf <where-you-put/wavefront.tar.gz>
-
-PART TWO: apply the patches
-
-     DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
-     AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
-
-  cd drivers/sound
-  patch < wavefront.patch
-
-PART THREE: configure your kernel
-
-  cd <top of your kernel tree>
-  make xconfig (or whichever config option you use)
-
-         - choose YES for Sound Support	      
-         - choose MODULE (M) for OSS Sound Modules
-         - choose MODULE(M) to YM3812/OPL3 support
-	 - choose MODULE(M) for WaveFront support
-	 - choose MODULE(M) for CS4232 support
-
-	 - choose "N" for everything else (unless you have other
-	      soundcards you want support for)
-
-
-   make dep
-   make boot
-   .
-   .
-   .
-   <whatever you normally do for a kernel install>
-   make modules
-   .
-   .
-   .
-   make modules_install
-
-Here's my autoconf.h SOUND section:
-
-/*
- * Sound
- */
-#define CONFIG_SOUND 1
-#undef  CONFIG_SOUND_OSS
-#define CONFIG_SOUND_OSS_MODULE 1
-#undef  CONFIG_SOUND_PAS
-#undef  CONFIG_SOUND_SB
-#undef  CONFIG_SOUND_ADLIB
-#undef  CONFIG_SOUND_GUS
-#undef  CONFIG_SOUND_MPU401
-#undef  CONFIG_SOUND_PSS
-#undef  CONFIG_SOUND_MSS
-#undef  CONFIG_SOUND_SSCAPE
-#undef  CONFIG_SOUND_TRIX
-#undef  CONFIG_SOUND_MAD16
-#undef  CONFIG_SOUND_WAVEFRONT
-#define CONFIG_SOUND_WAVEFRONT_MODULE 1
-#undef  CONFIG_SOUND_CS4232
-#define CONFIG_SOUND_CS4232_MODULE 1
-#undef  CONFIG_SOUND_MAUI
-#undef  CONFIG_SOUND_SGALAXY
-#undef  CONFIG_SOUND_OPL3SA1
-#undef  CONFIG_SOUND_SOFTOSS
-#undef  CONFIG_SOUND_YM3812
-#define CONFIG_SOUND_YM3812_MODULE 1
-#undef  CONFIG_SOUND_VMIDI
-#undef  CONFIG_SOUND_UART6850
-/*
- * Additional low level sound drivers
- */
-#undef  CONFIG_LOWLEVEL_SOUND
-
-************************************************************
-6) How do I configure my card ?
-************************************************************
-
-You need to edit /etc/modules.conf. Here's mine (edited to show the
-relevant details):
-
-  # Sound system
-  alias char-major-14 wavefront
-  alias synth0 wavefront
-  alias mixer0 cs4232
-  alias audio0 cs4232
-  pre-install wavefront modprobe "-k" "cs4232"
-  post-install wavefront modprobe "-k" "opl3"
-  options wavefront io=0x200 irq=9
-  options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
-  options opl3 io=0x388
-
-Things to note: 
-
-       the wavefront options "io" and "irq" ***MUST*** match the "synthio"
-       and "synthirq" cs4232 options.
-
-       you can do without the opl3 module if you don't
-       want to use the OPL/[34] FM synth on the soundcard
-
-       the opl3 io parameter is conventionally not adjustable.
-       In theory, any not-in-use IO port address would work, but
-       just use 0x388 and stick with the crowd.
-
-**********************************************************************
-7) What about firmware ?
-**********************************************************************
-
-Turtle Beach have not given me permission to distribute their firmware
-for the ICS2115. However, if you have a WaveFront card, then you
-almost certainly have the firmware, and if not, its freely available
-on their website, at:
-
-   http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus 
-
-The file is called WFOS2001.MOT (for the Tropez+).
-
-This driver, however, doesn't use the pure firmware as distributed,
-but instead relies on a somewhat processed form of it. You can
-generate this very easily. Following an idea from Andrew Veliath's
-Pinnacle driver, the following flex program will generate the
-processed version:
-
----- cut here -------------------------
-%option main
-%%
-^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
-<<EOF>> { fputc ('\0', stdout); return; }
-\n {} 
-.  {}
----- cut here -------------------------
-
-To use it, put the above in file (say, ws.l) compile it like this:
-
-      shell> flex -ows.c ws.l
-      shell> cc -o ws ws.c
-      
-and then use it like this:
-
-    ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
-
-If you put it somewhere else, you'll always have to use the wf_ospath
-module parameter (see below) or alter the source code.
-
-**********************************************************************
-7) How do I get it working ?
-**********************************************************************
-
-Optionally, you can reboot with the "new" kernel (even though the only
-changes have really been made to a module).
-
-Then, as root do:
-
-     modprobe wavefront
-
-You should get something like this in /var/log/messages:
-
-    WaveFront: firmware 1.20 already loaded.
-
-or 
-
-    WaveFront: no response to firmware probe, assume raw.
-
-then:
-
-    WaveFront: waiting for memory configuration ...
-    WaveFront: hardware version 1.64
-    WaveFront: available DRAM 8191k
-    WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
-    WaveFront: 128 programs slots in use
-    WaveFront: 256 patch slots filled, 142 in use
-
-The whole process takes about 16 seconds, the longest waits being
-after reporting the hardware version (during the firmware download),
-and after reporting program status (during patch status inquiry).  Its
-shorter (about 10 secs) if the firmware is already loaded (i.e. only
-warm reboots since the last firmware load).
-
-The "available DRAM" line will vary depending on how much added RAM
-your card has. Mine has 8MB.
-
-To check basically functionality, use play(1) or splay(1) to send a
-.WAV or other audio file through the audio portion. Then use playmidi
-to play a General MIDI file. Try the "-D 0" to hear the
-difference between sending MIDI to the WaveFront and using the OPL/3,
-which is the default (I think ...). If you have an external synth(s)
-hooked to the soundcard, you can use "-e" to route to the
-external synth(s) (in theory, -D 1 should work as well, but I think
-there is a bug in playmidi which prevents this from doing what it
-should). 
-
-**********************************************************************
-8) What are the module parameters ?
-**********************************************************************
-
-Its best to read wavefront.c for this, but here is a summary:
-
-integers: 
-	  wf_raw  - if set, ignore apparent presence of firmware
-		    loaded onto the ICS2115, reset the whole
-		    board, and initialize it from scratch. (default = 0)
-
-          fx_raw  - if set, always initialize the YSS225 processor
-		    on the Tropez plus. (default = 1)
-
-          < The next 4 are basically for kernel hackers to allow
-	    tweaking the driver for testing purposes. >		    
-
-          wait_usecs        -  loop timer used when waiting for
-			       status conditions on the board. 
-			       The default is 150.
-
-          debug_default    - debugging flags. See sound/wavefront.h
-			     for WF_DEBUG_* values. Default is zero.
-			     Setting this allows you to debug the
-			     driver during module installation.
-strings:
-	  ospath - path to get to the pre-processed OS firmware.
-		    (default: /etc/sound/wavefront.os)
-
-**********************************************************************
-9) Who should I contact if I have problems?
-**********************************************************************
-
-Just me: Paul Barton-Davis <pbd@op.net>
-
-
diff -urN linux-2.5.6-pre3/Documentation/sound/alsa/CMIPCI.txt linux-2.5.6/Documentation/sound/alsa/CMIPCI.txt
--- linux-2.5.6-pre3/Documentation/sound/alsa/CMIPCI.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/alsa/CMIPCI.txt	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,228 @@
+              Brief Notes on C-Media 8738/8338 Driver
+              =======================================
+
+                   Takashi Iwai <tiwai@suse.de>
+
+
+Front/Rear Multi-channel Playback
+---------------------------------
+
+CM8x38 chip can use ADC as the second DAC so that two different stereo
+channels can be used for front/rear playbacks.  Since there are two
+DACs, both streams are handled independently unlike the 4/6ch multi-
+channel playbacks in the section below.
+
+As default, ALSA driver assigns the first PCM device (i.e. hw:0,0 for
+card#0) for front and 4/6ch playbacks, while the second PCM device
+(hw:0,1) is assigned to the second DAC for rear playback.
+
+There are slight difference between two DACs.
+
+- The first DAC supports U8 and S16LE formats, while the second DAC
+  supports only S16LE.
+- The second DAC supports only two channel stereo.
+
+Please note that the CM8x38 DAC doesn't support continuous playback
+rate but only fixed rates: 5512, 8000, 11025, 16000, 22050, 32000,
+44100 and 48000 Hz.
+
+The rear output can be heard only when "Four Channel Mode" switch is
+disabled.  Otherwise no signal will be routed to the rear speakers.
+As default it's turned on.
+
+*** WARNING ***
+When "Four Channel Mode" switch is off, the output from rear speakers
+will be FULL VOLUME regardless of Master and PCM volumes.
+This might damage your audio equipment.  Please disconnect speakers
+before your turn off this switch.
+*** WARNING ***
+
+[ Well.. I once got the output with correct volume (i.e. same with the
+  front one) and was so excited.  It was even with "Four Channel" bit
+  on and "double DAC" mode.  Actually I could hear separate 4 channels
+  from front and rear speakers!  But.. after reboot, all was gone.
+  It's a very pity that I didn't save the register dump at that
+  time..  Maybe there is an unknown register to achieve this... ]
+
+If your card has an extra output jack for the rear output, the rear
+playback should be routed there as default.  If not, there is a
+control switch in the driver "Line-In As Rear", which you can change
+via alsamixer or somewhat else.  When this switch is on, line-in jack
+is used as rear output.
+
+There are two more controls regarding to the rear output.
+The "Exchange DAC" switch is used to exchange front and rear playback
+routes, i.e. the 2nd DAC is output from front output.
+
+
+4/6 Multi-Channel Playback
+--------------------------
+
+The recent CM8738 chips support for the 4/6 multi-channel playback
+function.  This is useful especially for AC3 decoding.
+
+When the multi-channel is supported, the driver name has a suffix
+"-MC" such like "CMI8738-MC6".  You can check this name from
+/proc/asound/cards.
+
+When the 4/6-ch output is enabled, the front DAC accepts up to 6 (or
+4) channels.  This is different from the dual DACs described in the
+previous section.  While the dual DAC supports two different rates or
+formats, the 4/6-ch playback supports only the same condition for all
+channels.
+
+For using 4/6 channel playback, you need to specify the PCM channels
+as you like and set the format S16LE.  For example, for playback with
+4 channels,
+
+	snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
+	    // or mmap if you like
+	snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16_LE);
+	snd_pcm_hw_params_set_channels(pcm, hw, 4);
+
+and use the interleaved 4 channel data.
+
+There is a control switch, "Line-In As Bass".  As you can imagine from
+its name, the line-in jack is used for the bass (5th and 6th channels)
+output.
+
+
+Digital I/O
+-----------
+
+The CM8x38 provides the excellent SPDIF capability with very chip
+price (yes, that's the reason I bought the card :)
+
+The SPDIF playback and capture are done via the third PCM device
+(hw:0,2).  Usually this is assigned to the PCM device "spdif".
+The available rates are 44100 and 48000 Hz.
+For playback with aplay, you can run like below:
+
+	% aplay -Dhw:0,2 foo.wav
+
+or
+
+	% aplay -Dspdif foo.wav
+
+So far, only S16LE format is supported.  Still no 24bit.  Sorry, not
+enough info for this.
+
+The playback and capture over SPDIF use normal DAC and ADC,
+respectively, so you cannot playback both analog and digital streams
+simultaneously.
+
+To enable SPDIF output, you need to turn on "IEC958 Output Switch"
+control via mixer or alsactl.  Then you'll see the red light on from
+the card so you know that's working obviously :)
+The SPDIF input is always enabled, so you can hear SPDIF input data
+from line-out with "IEC958 In Monitor" switch at any time (see
+below).
+
+You can play via SPDIF even with the first device (hw:0,0),
+but SPDIF is enabled only when the proper format (S16LE), sample rate
+(441100 or 48000) and channels (2) are used.  Otherwise it's turned
+off.  (Also don't forget to turn on "IEC958 Output Switch", too.)
+
+
+Additionally there are relevant control switches:
+
+"IEC958 Mix Analog" - Mix analog PCM playback and FM-OPL/3 streams and
+	output through SPDIF.  This switch appears only on old chip
+	models (CM8738 033 and 037).
+	Note: without this control you can output PCM to SPDIF.
+	This is "mixing" of streams, so e.g. it's not for AC3 output
+	(see the next section).
+
+"IEC958 In Select"  - Select SPDIF input, the internal CD-in (false)
+	and the external input (true).  This switch appears only on
+	the chip models 039 or later.
+
+"IEC958 Loop"       - SPDIF input data is loop back into SPDIF
+	output (aka bypass)
+
+"IEC958 Copyright"  - Set the copyright bit.
+
+"IEC958 5V"         - Select 0.5V (coax) or 5V (optical) interface.
+	On some cards this doesn't work and you need to change the
+	configuration with hardware dip-switch.
+
+"IEC958 In Monitor" - SPDIF input is routed to DAC.
+
+"IEC958 In Phase Inverse" - Set SPDIF input format as inverse.
+	[FIXME: this doesn't work on all chips..]
+
+"IEC958 In Valid"   - Set input validity flag detection.
+
+Note: When "PCM Playback Switch" is on, you'll hear the digital output
+stream through analog line-out.
+
+
+The AC3 (RAW DIGITAL) OUTPUT
+----------------------------
+
+The driver supports raw digital (typically AC3) i/o over SPDIF.  This
+can be toggled via IEC958 playback control, but usually you need to
+access it via alsa-lib.  See alsa-lib documents for more details.
+
+On the raw digital mode, the "PCM Playback Switch" is automatically
+turned off so that non-audio data is heard from the analog line-out.
+Similarly the following switches are off: "IEC958 Mix Analog" and
+"IEC958 Loop".  The switches are resumed after closing the SPDIF PCM
+device automatically to the previous state.
+
+
+ANALOG MIXER INTERFACE
+----------------------
+
+The mixer interface on CM8x38 is similar to SB16.
+There are Master, PCM, Synth, CD, Line, Mic and PC Speaker playback
+volumes.  Synth, CD, Line and Mic have playback and capture switches,
+too, as well as SB16.
+
+In addition to the standard SB mixer, CM8x38 provides more functions.
+- PCM playback switch
+- PCM capture switch (to capture the data sent to DAC)
+- Mic Boost switch
+- Mic capture volume
+- Aux playback volume/switch and capture switch
+- 3D control switch
+
+
+MIDI CONTROLLER
+---------------
+
+The MPU401-UART interface is enabled as default only for the first
+(CMIPCI) card.  You need to set module option "snd_midi_port" properly
+for the 2nd (CMIPCI) card.
+
+There is _no_ hardware wavetable function on this chip (except for
+OPL3 synth below).
+What's said as MIDI synth on Windows is a software synthesizer
+emulation.  On Linux use TiMidity or other softsynth program for
+playing MIDI music.
+
+
+FM OPL/3 Synth
+--------------
+
+The FM OPL/3 is also enabled as default only for the first card.
+Set "snd_fm_port" module option for more cards.
+
+The output quality of FM OPL/3 is, however, very weird.
+I don't know why..
+
+
+Joystick and Modem
+------------------
+
+The joystick and modem should be available by enabling the control
+switch "Joystick" and "Modem" respectively.  But I myself have never
+tested them yet.
+
+
+Debugging Information
+---------------------
+
+The registers are shown in /proc/asound/cardX/cmipci.  If you have any
+problem (especially unexpected behavior of mixer), please attach the
+output of this proc file together with the bug report.
diff -urN linux-2.5.6-pre3/Documentation/sound/alsa/SB-Live-mixer.txt linux-2.5.6/Documentation/sound/alsa/SB-Live-mixer.txt
--- linux-2.5.6-pre3/Documentation/sound/alsa/SB-Live-mixer.txt	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/alsa/SB-Live-mixer.txt	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,356 @@
+
+		Sound Blaster Live mixer / default DSP code
+		===========================================
+
+
+The EMU10K1 chips have a DSP part which can be programmed to support
+various ways of sample processing, which is described here.
+(This acticle does not deal with the overall functionality of the 
+EMU10K1 chips. See the manuals section for further details.)
+
+The ALSA driver programs this portion of chip by default code
+(can be altered later) which offers the following functionality:
+
+
+1) IEC958 (S/PDIF) raw PCM
+--------------------------
+
+This PCM device (it's the 4th PCM device (index 3!) and first subdevice
+(index 0) for a given card) allows to forward 48kHz, stereo, 16-bit
+little endian streams without any modifications to the digital output
+(coaxial or optical). The universal interface allows the creation of up
+to 8 raw PCM devices operating at 48kHz, 16-bit little endian. It would
+be easy to add support for multichannel devices to the current code,
+but the conversion routines exist only for stereo (2-channel streams)
+at the time. 
+
+Look to tram_poke routines in lowlevel/emu10k1/emufx.c for more details.
+
+
+2) Digital mixer controls
+-------------------------
+
+These controls are built using the DSP instructions. They offer extended
+functionality. Only the default build-in code in the ALSA driver is described
+here. Note that the controls work as attenuators: the maximum value is the 
+neutral position leaving the signal unchanged. Note that if the  same destination 
+is mentioned in multiple controls, the signal is accumulated and can be wrapped 
+(set to maximal or minimal value without checking of overflow).
+
+
+Explanation of used abbreviations:
+
+DAC    - digital to analog converter
+ADC    - analog to digital converter
+I2S    - one-way three wire serial bus for digital sound by Philips Semiconductors
+         (this standard is used for connecting standalone DAC and ADC converters)
+LFE    - low frequency effects (subwoofer signal)
+AC97   - a chip containing an analog mixer, DAC and ADC converters
+IEC958 - S/PDIF
+FX-bus - the EMU10K1 chip has an effect bus containing 16 accumulators.
+         Each of the synthesizer voices can feed its output to these accumulators
+         and the DSP microcontroller can operate with the resulting sum.
+
+
+name='Wave Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Wave Surround Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result samples are forwarded to the rear I2S DACs. These DACs operates
+separately (they are not inside the AC97 codec).
+
+name='Wave Center Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM samples.
+The result is mixed to mono signal (single channel) and forwarded to
+the ??rear?? right DAC PCM slot of the AC97 codec.
+
+name='Wave LFE Playback Volume',index=0
+
+This control is used to attenuate samples for left and right PCM FX-bus
+accumulators. ALSA uses accumulators 0 and 1 for left and right PCM.
+The result is mixed to mono signal (single channel) and forwarded to
+the ??rear?? left DAC PCM slot of the AC97 codec.
+
+name='Wave Capture Volume',index=0
+name='Wave Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right PCM FX-bus
+accumulator. ALSA uses accumulators 0 and 1 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Music Playback Volume',index=0
+
+This control is used to attenuate samples for left and right MIDI FX-bus
+accumulators. ALSA uses accumulators 4 and 5 for left and right MIDI samples.
+The result samples are forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Music Capture Volume',index=0
+name='Music Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right MIDI FX-bus
+accumulator. ALSA uses accumulators 4 and 5 for left and right PCM.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Surround Digital Playback Volume',index=0
+
+This control is used to attenuate samples for left and right rear PCM FX-bus
+accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
+The result samples are forwarded to the rear I2S DACs. These DACs operate
+separately (they are not inside the AC97 codec).
+
+name='Surround Digital Capture Volume',index=0
+name='Surround Digital Capture Switch',index=0
+
+These controls are used to attenuate samples for left and right rear PCM FX-bus
+accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples.
+The result is forwarded to the ADC capture FIFO (thus to the standard capture
+PCM device).
+
+name='Center Playback Volume',index=0
+
+This control is used to attenuate sample for center PCM FX-bus accumulator.
+ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
+to the ??rear?? right DAC PCM slot of the AC97 codec.
+
+name='LFE Playback Volume',index=0
+
+This control is used to attenuate sample for center PCM FX-bus accumulator.
+ALSA uses accumulator 6 for center PCM sample. The result sample is forwarded
+to the ??rear?? left DAC PCM slot of the AC97 codec.
+
+name='AC97 Playback Volume',index=0
+
+This control is used to attenuate samples for left and right front ADC PCM slots
+of the AC97 codec. The result samples are forwarded to the front DAC PCM
+slots of the AC97 codec.
+********************************************************************************
+*** Note: This control should be zero for the standard operations, otherwise ***
+*** a digital loopback is activated.                                         ***
+********************************************************************************
+
+name='AC97 Capture Volume',index=0
+
+This control is used to attenuate samples for left and right front ADC PCM slots
+of the AC97 codec. The result is forwarded to the ADC capture FIFO (thus to
+the standard capture PCM device).
+********************************************************************************
+*** Note: This control should be 100 (maximal value), otherwise no analog    ***
+*** inputs of the AC97 codec can be captured (recorded).                     ***
+********************************************************************************
+
+name='IEC958 TTL Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='IEC958 TTL Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 TTL
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
+
+name='Zoom Video Playback Volume',index=0
+
+This control is used to attenuate samples from left and right zoom video
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the front DAC PCM slots of the AC97 codec.
+
+name='Zoom Video Capture Volume',index=0
+
+This control is used to attenuate samples from left and right zoom video
+digital inputs (usually used by a CDROM drive). The result samples are
+forwarded to the ADC capture FIFO (thus to the standard capture PCM device).
+
+name='IEC958 Optical Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital input. The result samples are forwarded to the front DAC PCM slots
+of the AC97 codec.
+
+name='IEC958 Optical Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 optical
+digital inputs. The result samples are forwarded to the ADC capture FIFO
+(thus to the standard capture PCM device).
+
+name='IEC958 Coaxial Playback Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 coaxial
+digital inputs. The result samples are forwarded to the front DAC PCM slots
+of the AC97 codec.
+
+name='IEC958 Coaxial Capture Volume',index=0
+
+This control is used to attenuate samples from left and right IEC958 coaxial
+digital inputs. The result samples are forwarded to the ADC capture FIFO
+(thus to the standard capture PCM device).
+
+name='Line LiveDrive Playback Volume',index=0
+name='Line LiveDrive Playback Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the LiveDrive). The result samples are forwarded to the front
+DAC PCM slots of the AC97 codec.
+
+name='Line LiveDrive Capture Volume',index=1
+name='Line LiveDrive Capture Volume',index=1
+
+This control is used to attenuate samples from left and right I2S ADC
+inputs (on the LiveDrive). The result samples are forwarded to the ADC
+capture FIFO (thus to the standard capture PCM device).
+
+name='Tone Control - Switch',index=0
+
+This control turns the tone control on or off. The samples for front, rear
+and center / LFE outputs are affected.
+
+name='Tone Control - Bass',index=0
+
+This control sets the bass intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='Tone Control - Treble',index=0
+
+This control sets the treble intensity. There is no neutral value!!
+When the tone control code is activated, the samples are always modified.
+The closest value to pure signal is 20.
+
+name='IEC958 Optical Raw Playback Switch',index=0
+
+If this switch is on, then the samples for the IEC958 (S/PDIF) digital
+output are taken only from the raw FX8010 PCM, otherwise standard front
+PCM samples are taken.
+
+name='Headphone Playback Volume',index=1
+
+This control attenuates the samples for the headphone output.
+
+name='Headphone Center Playback Switch',index=1
+
+If this switch is on, then the sample for the center PCM is put to the
+left headphone output (useful for SB Live cards without separate center/LFE
+output).
+
+name='Headphone LFE Playback Switch',index=1
+
+If this switch is on, then the sample for the center PCM is put to the
+right headphone output (useful for SB Live cards without separate center/LFE
+output).
+
+
+3) PCM stream related controls
+------------------------------
+
+name='EMU10K1 PCM Volume',index 0-31
+
+Channel volume attenuation in range 0-0xffff. The maximum value (no
+attenuation) is default. The channel mapping for three values is
+as follows:
+
+	0 - mono, default 0xffff (no attenuation)
+	1 - left, default 0xffff (no attenuation)
+	2 - right, default 0xffff (no attenuation)
+
+name='EMU10K1 PCM Send Routing',index 0-31
+
+This control specifies the destination - FX-bus accumulators. There are
+twelve values with this mapping:
+
+	 0 -  mono, A destination (FX-bus 0-15), default 0
+	 1 -  mono, B destination (FX-bus 0-15), default 1
+	 2 -  mono, C destination (FX-bus 0-15), default 2
+	 3 -  mono, D destination (FX-bus 0-15), default 3
+	 4 -  left, A destination (FX-bus 0-15), default 0
+	 5 -  left, B destination (FX-bus 0-15), default 1
+	 6 -  left, C destination (FX-bus 0-15), default 2
+	 7 -  left, D destination (FX-bus 0-15), default 3
+	 8 - right, A destination (FX-bus 0-15), default 0
+	 9 - right, B destination (FX-bus 0-15), default 1
+	10 - right, C destination (FX-bus 0-15), default 2
+	11 - right, D destination (FX-bus 0-15), default 3
+
+Don't forget that it's illegal to assign a channel to the same FX-bus accumulator 
+more than once (it means 0=0 && 1=0 is an invalid combination).
+ 
+name='EMU10K1 PCM Send Volume',index 0-31
+
+It specifies the attenuation (amount) for given destination in range 0-255.
+The channel mapping is following:
+
+	 0 -  mono, A destination attn, default 255 (no attenuation)
+	 1 -  mono, B destination attn, default 255 (no attenuation)
+	 2 -  mono, C destination attn, default 0 (mute)
+	 3 -  mono, D destination attn, default 0 (mute)
+	 4 -  left, A destination attn, default 255 (no attenuation)
+	 5 -  left, B destination attn, default 0 (mute)
+	 6 -  left, C destination attn, default 0 (mute)
+	 7 -  left, D destination attn, default 0 (mute)
+	 8 - right, A destination attn, default 0 (mute)
+	 9 - right, B destination attn, default 255 (no attenuation)
+	10 - right, C destination attn, default 0 (mute)
+	11 - right, D destination attn, default 0 (mute)
+
+
+
+4) MANUALS/PATENTS:
+-------------------
+
+ftp://opensource.creative.com/pub/doc
+-------------------------------------
+
+        Files:
+        LM4545.pdf      AC97 Codec
+
+        m2049.pdf       The EMU10K1 Digital Audio Processor
+
+        hog63.ps        FX8010 - A DSP Chip Architecture for Audio Effects
+
+
+WIPO Patents
+------------
+        Patent numbers:
+        WO 9901813 (A1) Audio Effects Processor with multiple asynchronous (Jan. 14, 1999)
+                        streams
+
+        WO 9901814 (A1) Processor with Instruction Set for Audio Effects (Jan. 14, 1999)
+
+        WO 9901953 (A1) Audio Effects Processor having Decoupled Instruction
+                        Execution and Audio Data Sequencing (Jan. 14, 1999)
+
+
+US Patents (http://www.uspto.gov/)
+----------------------------------
+
+        US 5925841      Digital Sampling Instrument employing cache memory (Jul. 20, 1999)
+
+        US 5928342      Audio Effects Processor integrated on a single chip (Jul. 27, 1999)
+                        with a multiport memory onto which multiple asynchronous
+                        digital sound samples can be concurrently loaded
+
+        US 5930158      Processor with Instruction Set for Audio Effects (Jul. 27, 1999)
+
+        US 6032235      Memory initialization circuit (Tram) (Feb. 29, 2000)
+
+        US 6138207      Interpolation looping of audio samples in cache connected to    (Oct. 24, 2000)
+                        system bus with prioritization and modification of bus transfers
+                        in accordance with loop ends and minimum block sizes
+
+        US 6151670      Method for conserving memory storage using a (Nov. 21, 2000)
+                        pool of  short term memory registers
+
+        US 6195715      Interrupt control for multiple programs communicating with      (Feb. 27, 2001)
+                        a common interrupt by associating programs to GP registers,
+                        defining interrupt register, polling GP registers, and invoking
+                        callback routine associated with defined interrupt register
diff -urN linux-2.5.6-pre3/Documentation/sound/alsa/seq_oss.html linux-2.5.6/Documentation/sound/alsa/seq_oss.html
--- linux-2.5.6-pre3/Documentation/sound/alsa/seq_oss.html	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/alsa/seq_oss.html	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,409 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+   <TITLE>OSS Sequencer Emulation on ALSA</TITLE>
+</HEAD>
+<BODY>
+
+<CENTER>
+<H1>
+
+<HR WIDTH="100%"></H1></CENTER>
+
+<CENTER>
+<H1>
+OSS Sequencer Emulation on ALSA</H1></CENTER>
+
+<HR WIDTH="100%">
+<P>Copyright (c) 1998,1999 by Takashi Iwai
+<TT><A HREF="mailto:iwai@ww.uni-erlangen.de">&lt;iwai@ww.uni-erlangen.de></A></TT>
+<P>ver.0.1.8; Nov. 16, 1999
+<H2>
+
+<HR WIDTH="100%"></H2>
+
+<H2>
+1. Description</H2>
+This directory contains the OSS sequencer emulation driver on ALSA. Note
+that this program is still in the development state.
+<P>What this does - it provides the emulation of the OSS sequencer, access
+via
+<TT>/dev/sequencer</TT> and <TT>/dev/music</TT> devices.
+The most of applications using OSS can run if the appropriate ALSA
+sequencer is prepared.
+<P>The following features are emulated by this driver:
+<UL>
+<LI>
+Normal sequencer and MIDI events:</LI>
+
+<BR>They are converted to the ALSA sequencer events, and sent to the corresponding
+port.
+<LI>
+Timer events:</LI>
+
+<BR>The timer is not selectable by ioctl. The control rate is fixed to
+100 regardless of HZ. That is, even on Alpha system, a tick is always
+1/100 second. The base rate and tempo can be changed in <TT>/dev/music</TT>.
+
+<LI>
+Patch loading:</LI>
+
+<BR>It purely depends on the synth drivers whether it's supported since
+the patch loading is realized by callback to the synth driver.
+<LI>
+I/O controls:</LI>
+
+<BR>Most of controls are accepted. Some controls
+are dependent on the synth driver, as well as even on original OSS.</UL>
+Furthermore, you can find the following advanced features:
+<UL>
+<LI>
+Better queue mechanism:</LI>
+
+<BR>The events are queued before processing them.
+<LI>
+Multiple applications:</LI>
+
+<BR>You can run two or more applications simultaneously (even for OSS sequencer)!
+However, each MIDI device is exclusive - that is, if a MIDI device is opened
+once by some application, other applications can't use it. No such a restriction
+in synth devices.
+<LI>
+Real-time event processing:</LI>
+
+<BR>The events can be processed in real time without using out of bound
+ioctl. To switch to real-time mode, send ABSTIME 0 event. The followed
+events will be processed in real-time without queued. To switch off the
+real-time mode, send RELTIME 0 event.
+<LI>
+<TT>/proc</TT> interface:</LI>
+
+<BR>The status of applications and devices can be shown via <TT>/proc/asound/seq/oss</TT>
+at any time. In the later version, configuration will be changed via <TT>/proc</TT>
+interface, too.</UL>
+
+<H2>
+2. Installation</H2>
+Run configure script with both sequencer support (<TT>--with-sequencer=yes</TT>)
+and OSS emulation (<TT>--with-oss=yes</TT>) options. A module <TT>snd-seq-oss.o</TT>
+will be created. If the synth module of your sound card supports for OSS
+emulation (so far, only Emu8000 driver), this module will be loaded automatically.
+Otherwise, you need to load this module manually.
+<P>At beginning, this module probes all the MIDI ports which have been
+already connected to the sequencer. Once after that, the creation and deletion
+of ports are watched by announcement mechanism of ALSA sequencer.
+<P>The available synth and MIDI devices can be found in proc interface.
+Run "<TT>cat /proc/asound/seq/oss</TT>", and check the devices. For example,
+if you use an AWE64 card, you'll see like the following:
+<PRE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OSS sequencer emulation version 0.1.8
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA client number 63
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ALSA receiver port 0
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of applications: 0
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of synth devices: 1
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; synth 0: [EMU8000]
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; type 0x1 : subtype 0x20 : voices 32
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capabilties : ioctl enabled / load_patch enabled
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of MIDI devices: 3
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 0: [Emu8000 Port-0] ALSA port 65:0
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 1: [Emu8000 Port-1] ALSA port 65:1
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability write / opened none
+
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; midi 2: [0: MPU-401 (UART)] ALSA port 64:0
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; capability read/write / opened none</PRE>
+Note that the device number may be different from the information of
+<TT>/proc/asound/oss-devices</TT>
+or ones of the original OSS driver. Use the device number listed in <TT>/proc/asound/seq/oss</TT>
+to play via OSS sequencer emulation.
+<H2>
+3. Using Synthesizer Devices</H2>
+Run your favorite program. I've tested playmidi-2.4, awemidi-0.4.3, gmod-3.1
+and xmp-1.1.5. You can load samples via <TT>/dev/sequencer</TT> like sfxload,
+too.
+<P>If the lowlevel driver supports multiple access to synth devices (like
+Emu8000 driver), two or more applications are allowed to run at the same
+time.
+<H2>
+4. Using MIDI Devices</H2>
+So far, only MIDI output was tested. MIDI input was not checked at all,
+but hopefully it will work. Use the device number listed in <TT>/proc/asound/seq/oss</TT>.
+Be aware that these numbers are mostly different from the list in
+<TT>/proc/asound/oss-devices</TT>.
+<H2>
+5. Module Options</H2>
+The following module options are available:
+<UL>
+<LI>
+<TT>maxqlen</TT></LI>
+
+<BR>specifies the maximum read/write queue length. This queue is private
+for OSS sequencer, so that it is independent from the queue length of ALSA
+sequencer. Default value is 1024.
+<LI>
+<TT>seq_oss_debug</TT></LI>
+
+<BR>specifies the debug level and accepts zero (= no debug message) or
+positive integer. Default value is 0.</UL>
+
+<H2>
+6. Queue Mechanism</H2>
+OSS sequencer emulation uses an ALSA priority queue. The
+events from <TT>/dev/sequencer</TT> are processed and put onto the queue
+specified by module option.
+<P>All the events from <TT>/dev/sequencer</TT> are parsed at beginning.
+The timing events are also parsed at this moment, so that the events may
+be processed in real-time. Sending an event ABSTIME 0 switches the operation
+mode to real-time mode, and sending an event RELTIME 0 switches it off.
+In the real-time mode, all events are dispatched immediately.
+<P>The queued events are dispatched to the corresponding ALSA sequencer
+ports after scheduled time by ALSA sequencer dispatcher.
+<P>If the write-queue is full, the application sleeps until a certain amount
+(as default one half) becomes empty in blocking mode. The synchronization
+to write timing was implemented, too.
+<P>The input from MIDI devices or echo-back events are stored on read FIFO
+queue. If application reads <TT>/dev/sequencer</TT> in blocking mode, the
+process will be awaked.
+
+<H2>
+7. Interface to Synthesizer Device</H2>
+
+<H3>
+7.1. Registration</H3>
+To register an OSS synthesizer device, use <TT>snd_seq_oss_synth_register</TT>
+function.
+<PRE>int snd_seq_oss_synth_register(char *name, int type, int subtype, int nvoices,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_oss_callback_t *oper, void *private_data)</PRE>
+The arguments <TT>name</TT>, <TT>type</TT>, <TT>subtype</TT> and
+<TT>nvoices</TT>
+are used for making the appropriate synth_info structure for ioctl. The
+return value is an index number of this device. This index must be remembered
+for unregister. If registration is failed, -errno will be returned.
+<P>To release this device, call <TT>snd_seq_oss_synth_unregister function</TT>:
+<PRE>int snd_seq_oss_synth_unregister(int index),</PRE>
+where the <TT>index</TT> is the index number returned by register function.
+<H3>
+7.2. Callbacks</H3>
+OSS synthesizer devices have capability for sample downloading and ioctls
+like sample reset. In OSS emulation, these special features are realized
+by using callbacks. The registration argument oper is used to specify these
+callbacks. The following callback functions must be defined:
+<PRE>snd_seq_oss_callback_t:
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*open)(snd_seq_oss_arg_t *p, void *closure);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*close)(snd_seq_oss_arg_t *p);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*ioctl)(snd_seq_oss_arg_t *p, unsigned int cmd, unsigned long arg);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*load_patch)(snd_seq_oss_arg_t *p, int format, const char *buf, int offs, int count);
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int (*reset)(snd_seq_oss_arg_t *p);
+Except for <TT>open</TT> and <TT>close</TT> callbacks, they are allowed
+to be NULL.
+<P>Each callback function takes the argument type snd_seq_oss_arg_t as the
+first argument.
+<PRE>struct snd_seq_oss_arg_t {
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int app_index;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int file_mode;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int seq_mode;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; snd_seq_addr_t addr;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *private_data;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int event_passing;
+};</PRE>
+The first three fields, <TT>app_index</TT>, <TT>file_mode</TT> and
+<TT>seq_mode</TT>
+are initialized by OSS sequencer. The <TT>app_index</TT> is the application
+index which is unique to each application opening OSS sequencer. The
+<TT>file_mode</TT>
+is bit-flags indicating the file operation mode. See
+<TT>seq_oss.h</TT>
+for its meaning. The <TT>seq_mode</TT> is sequencer operation mode. In
+the current version, only <TT>SND_OSSSEQ_MODE_SYNTH</TT> is used.
+<P>The next two fields, <TT>addr</TT> and <TT>private_data</TT>, must be
+filled by the synth driver at open callback. The <TT>addr</TT> contains
+the address of ALSA sequencer port which is assigned to this device. If
+the driver allocates memory for <TT>private_data</TT>, it must be released
+in close callback by itself.
+<P>The last field, <TT>event_passing</TT>, indicates how to translate note-on
+/ off events. In <TT>PROCESS_EVENTS</TT> mode, the note 255 is regarded
+as velocity change, and key pressure event is passed to the port. In <TT>PASS_EVENTS</TT>
+mode, all note on/off events are passed to the port without modified. <TT>PROCESS_KEYPRESS</TT>
+mode checks the note above 128 and regards it as key pressure event (mainly
+for Emu8000 driver).
+<H4>
+7.2.1. Open Callback</H4>
+The <TT>open</TT> is called at each time this device is opened by an application
+using OSS sequencer. This must not be NULL. Typically, the open callback
+does the following procedure:
+<OL>
+<LI>
+Allocate private data record.</LI>
+
+<LI>
+Create an ALSA sequencer port.</LI>
+
+<LI>
+Set the new port address on arg->addr.</LI>
+
+<LI>
+Set the private data record pointer on arg->private_data.</LI>
+</OL>
+Note that the type bit-flags in port_info of this synth port must NOT contain
+<TT>TYPE_MIDI_GENERIC</TT>
+bit. Instead, <TT>TYPE_SPECIFIC</TT> should be used. Also, <TT>CAP_SUBSCRIPTION</TT>
+bit should NOT be included, too. This is necessary to tell it from other
+normal MIDI devices. If the open procedure succeeded, return zero. Otherwise,
+return -errno.
+<H4>
+7.2.2 Ioctl Callback</H4>
+The <TT>ioctl</TT> callback is called when the sequencer receives device-specific
+ioctls. The following two ioctls should be processed by this callback:
+<UL>
+<LI>
+<TT>IOCTL_SEQ_RESET_SAMPLES</TT></LI>
+
+<BR>reset all samples on memory -- return 0
+<LI>
+<TT>IOCTL_SYNTH_MEMAVL</TT></LI>
+
+<BR>return the available memory size
+<LI>
+<TT>FM_4OP_ENABLE</TT></LI>
+
+<BR>can be ignored usually</UL>
+The other ioctls are processed inside the sequencer without passing to
+the lowlevel driver.
+<H4>
+7.2.3 Load_Patch Callback</H4>
+The <TT>load_patch</TT> callback is used for sample-downloading. This callback
+must read the data on user-space and transfer to each device. Return 0
+if succeeded, and -errno if failed. The format argument is the patch key
+in patch_info record. The buf is user-space pointer where patch_info record
+is stored. The offs can be ignored. The count is total data size of this
+sample data.
+<H4>
+7.2.4 Close Callback</H4>
+The <TT>close</TT> callback is called when this device is closed by the
+applicaion. If any private data was allocated in open callback, it must
+be released in the close callback. The deletion of ALSA port should be
+done here, too. This callback must not be NULL.
+<H4>
+7.2.5 Reset Callback</H4>
+The <TT>reset</TT> callback is called when sequencer device is reset or
+closed by applications. The callback should turn off the sounds on the
+relevant port immediately, and initialize the status of the port. If this
+callback is undefined, OSS seq sends a <TT>HEARTBEAT</TT> event to the
+port.
+<H3>
+7.3 Events</H3>
+Most of the events are processed by sequencer and translated to the adequate
+ALSA sequencer events, so that each synth device can receive by input_event
+callback of ALSA sequencer port. The following ALSA events should be implemented
+by the driver:
+<BR>&nbsp;
+<TABLE BORDER WIDTH="75%" NOSAVE >
+<TR NOSAVE>
+<TD NOSAVE><B>ALSA event</B></TD>
+
+<TD><B>Original OSS events</B></TD>
+</TR>
+
+<TR>
+<TD>NOTEON</TD>
+
+<TD>SEQ_NOTEON
+<BR>MIDI_NOTEON</TD>
+</TR>
+
+<TR>
+<TD>NOTE</TD>
+
+<TD>SEQ_NOTEOFF
+<BR>MIDI_NOTEOFF</TD>
+</TR>
+
+<TR NOSAVE>
+<TD NOSAVE>KEYPRESS</TD>
+
+<TD>MIDI_KEY_PRESSURE</TD>
+</TR>
+
+<TR NOSAVE>
+<TD>CHANPRESS</TD>
+
+<TD NOSAVE>SEQ_AFTERTOUCH
+<BR>MIDI_CHN_PRESSURE</TD>
+</TR>
+
+<TR NOSAVE>
+<TD NOSAVE>PGMCHANGE</TD>
+
+<TD NOSAVE>SEQ_PGMCHANGE
+<BR>MIDI_PGM_CHANGE</TD>
+</TR>
+
+<TR>
+<TD>PITCHBEND</TD>
+
+<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER)
+<BR>MIDI_PITCH_BEND</TD>
+</TR>
+
+<TR>
+<TD>CONTROLLER</TD>
+
+<TD>MIDI_CTL_CHANGE
+<BR>SEQ_BALANCE (with CTL_PAN)</TD>
+</TR>
+
+<TR>
+<TD>CONTROL14</TD>
+
+<TD>SEQ_CONTROLLER</TD>
+</TR>
+
+<TR>
+<TD>REGPARAM</TD>
+
+<TD>SEQ_CONTROLLER(CTRL_PITCH_BENDER_RANGE)</TD>
+</TR>
+
+<TR>
+<TD>SYSEX</TD>
+
+<TD>SEQ_SYSEX</TD>
+</TR>
+</TABLE>
+
+<P>The most of these behavior can be realized by MIDI emulation driver
+included in the Emu8000 lowlevel driver. In the future release, this module
+will be independent.
+<P>Some OSS events (<TT>SEQ_PRIVATE</TT> and <TT>SEQ_VOLUME</TT> events) are passed as event
+type SND_SEQ_OSS_PRIVATE.  The OSS sequencer passes these event 8 byte
+packets without any modification. The lowlevel driver should process these
+events appropriately.
+<H2>
+8. Interface to MIDI Device</H2>
+Since the OSS emulation probes the creation and deletion of ALSA MIDI sequencer
+ports automatically by receiving announcement from ALSA sequencer, the
+MIDI devices don't need to be registered explicitly like synth devices.
+However, the MIDI port_info registered to ALSA sequencer must include a group
+name <TT>SND_SEQ_GROUP_DEVICE</TT> and a capability-bit <TT>CAP_READ</TT> or
+<TT>CAP_WRITE</TT>. Also, subscription capabilities, <TT>CAP_SUBS_READ</TT> or <TT>CAP_SUBS_WRITE</TT>,
+must be defined, too. If these conditions are not satisfied, the port is not
+registered as OSS sequencer MIDI device.
+<P>The events via MIDI devices are parsed in OSS sequencer and converted
+to the corresponding ALSA sequencer events. The input from MIDI sequencer
+is also converted to MIDI byte events by OSS sequencer. This works just
+a reverse way of seq_midi module.
+<H2>
+9. Known Problems / TODO's</H2>
+
+<UL>
+<LI>
+Patch loading via ALSA instrument layer is not implemented yet.</LI>
+</UL>
+
+</BODY>
+</HTML>
diff -urN linux-2.5.6-pre3/Documentation/sound/btaudio linux-2.5.6/Documentation/sound/btaudio
--- linux-2.5.6-pre3/Documentation/sound/btaudio	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/Documentation/sound/btaudio	Wed Dec 31 16:00:00 1969
@@ -1,92 +0,0 @@
-
-Intro
-=====
-
-people start bugging me about this with questions, looks like I
-should write up some documentation for this beast.  That way I
-don't have to answer that much mails I hope.  Yes, I'm lazy...
-
-
-You might have noticed that the bt878 grabber cards have actually
-_two_ PCI functions:
-
-$ lspci
-[ ... ]
-00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
-00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02)
-[ ... ]
-
-The first does video, it is backward compatible to the bt848.  The second
-does audio.  btaudio is a driver for the second function.  It's a sound
-driver which can be used for recording sound (and _only_ recording, no
-playback).  As most TV cards come with a short cable which can be plugged
-into your sound card's line-in you probably don't need this driver if all
-you want to do is just watching TV...
-
-
-Driver Status
-=============
-
-Still somewhat experimental.  The driver should work stable, i.e. it
-should'nt crash your box.  It might not work as expected, have bugs,
-not being fully OSS API compilant, ...
-
-Latest versions are available from http://bytesex.org/bttv/, the
-driver is in the bttv tarball.  Kernel patches might be available too,
-have a look at http://bytesex.org/bttv/listing.html.
-
-The chip knows two different modes.  btaudio registers two dsp
-devices, one for each mode.  They can not be used at the same time.
-
-
-Digital audio mode
-==================
-
-The chip gives you 16 bit stereo sound.  The sample rate depends on
-the external source which feeds the bt878 with digital sound via I2S
-interface.  There is a insmod option (rate) to tell the driver which
-sample rate the hardware uses (32000 is the default).
-
-One possible source for digital sound is the msp34xx audio processor
-chip which provides digital sound via I2S with 32 kHz sample rate.  My
-Hauppauge board works this way.
-
-The Osprey-200 reportly gives you digital sound with 44100 Hz sample
-rate.  It is also possible that you get no sound at all.
-
-
-analog mode (A/D)
-=================
-
-You can tell the driver to use this mode with the insmod option "analog=1".
-The chip has three analog inputs.  Consequently you'll get a mixer device
-to control these.
-
-The analog mode supports mono only.  Both 8 + 16 bit.  Both are _signed_
-int, which is uncommon for the 8 bit case.  Sample rate range is 119 kHz
-to 448 kHz.  Yes, the number of digits is correct.  The driver supports
-downsampling by powers of two, so you can ask for more usual sample rates
-like 44 kHz too.
-
-With my Hauppauge I get noisy sound on the second input (mapped to line2
-by the mixer device).  Others get a useable signal on line1.
-
-
-some examples
-=============
-
-* read audio data from btaudio (dsp2), send to es1730 (dsp,dsp1):
-  $ sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp
-
-* read audio data from btaudio, send to esound daemon (which might be
-  running on another host):
-  $ sox -c 2 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -r 32000
-  $ sox -c 1 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -m -r 32000
-
-
-Have fun,
-
-  Gerd
-
--- 
-Gerd Knorr <kraxel@bytesex.org>
diff -urN linux-2.5.6-pre3/Documentation/sound/cs46xx linux-2.5.6/Documentation/sound/cs46xx
--- linux-2.5.6-pre3/Documentation/sound/cs46xx	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/Documentation/sound/cs46xx	Wed Dec 31 16:00:00 1969
@@ -1,138 +0,0 @@
-
-Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio 
-controller chips (2001/05/11)
-
-The cs46xx audio driver supports the DSP line of Cirrus controllers. 
-Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280
-products.  This driver uses the generic ac97_codec driver for AC97 codec
-support.  
-
-
-Features:
-
-Full Duplex Playback/Capture supported from 8k-48k.
-16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
-
-APM/PM - 2.2.x PM is enabled and functional. APM can also
-be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
-definition.
-
-DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg 
-(defaultorder=11).  DMA capture buffer size is fixed at a single 4k page as
-two 2k fragments.
-
-MMAP seems to work well with QuakeIII, and test XMMS plugin.
-
-Myth2 works, but the polling logic is not fully correct, but is functional.
-
-The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested 
-with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o).  This 
-audio driver must be loaded prior to the joystick driver to enable the
-DSP task image supporting the joystick device.
-
-
-Limitations:
-
-SPDIF is currently not supported.
-
-Primary codec support only.  No secondary codec support is implemented.
-
-
-
-NOTES:
-
-Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
-and has been tested.
-Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR
-to disable the external amplifier.
-
-VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
-the external amplifier for the "back" speakers, since we do not
-support the secondary codec then this external amp is not
-turned on.  The primary codec external amplifier is supported but
-note that the AC97 EAPD bit is inverted logic (amp_voyetra()).
-
-DMA buffer size - there are issues with many of the Linux applications
-concerning the optimal buffer size.  Several applications request a 
-certain fragment size and number and then do not verify that the driver
-has the ability to support the requested configuration.  
-SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and
-number of fragments.  Some applications exit if an error is returned
-on this particular ioctl. Therefore, in alignment with the other OSS audio 
-drivers, no error is returned when a SETFRAGs IOCTL is received, but the 
-values passed from the app are not used in any buffer calculation 
-(ossfragshift/ossmaxfrags are not used).
-Use the "defaultorder=N" module parameter to change the buffer size if
-you have an application that requires a specific number of fragments
-or a specific buffer size (see below).
-
-Debug Interface
----------------
-There is an ioctl debug interface to allow runtime modification of the 
-debug print levels.  This debug interface code can be disabled from the 
-compilation process with commenting the following define:
-#define CSDEBUG_INTERFACE 1
-There is also a debug print methodolgy to select printf statements from
-different areas of the driver.  A debug print level is also used to allow
-additional printfs to be active.  Comment out the following line in the
-driver to disable compilation of the CS_DBGOUT print statements:
-#define CSDEBUG 1
- 
-Please see the defintions for cs_debuglevel and cs_debugmask for additional
-information on the debug levels and sections.
-
-There is also a csdbg executable to allow runtime manipulation of these 
-parameters.  for a copy email: twoller@crystal.cirrus.com
-
-
-
-MODULE_PARMS definitions
-------------------------
-MODULE_PARM(defaultorder, "i");
-defaultorder=N
-where N is a value from 1 to 12
-The buffer order determines the size of the dma buffer for the driver.
-under Linux, a smaller buffer allows more responsiveness from many of the 
-applications (e.g. games).  A larger buffer allows some of the apps (esound) 
-to not underrun the dma buffer as easily.  As default, use 32k (order=3)
-rather than 64k as some of the games work more responsively.
-(2^N) * PAGE_SIZE = allocated buffer size
-
-MODULE_PARM(cs_debuglevel, "i");
-MODULE_PARM(cs_debugmask, "i");
-cs_debuglevel=N
-cs_debugmask=0xMMMMMMMM
-where N is a value from 0 (no debug printfs), to 9 (maximum)
-0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
-
-MODULE_PARM(hercules_egpio_disable, "i");
-hercules_egpio_disable=N
-where N is a 0 (enable egpio), or a 1 (disable egpio support)
-
-MODULE_PARM(initdelay, "i");
-initdelay=N
-This value is used to determine the millescond delay during the initialization
-code prior to powering up the PLL.  On laptops this value can be used to
-assist with errors on resume, mostly with IBM laptops.  Basically, if the 
-system is booted under battery power then the mdelay()/udelay() functions fail to 
-properly delay the required time.  Also, if the system is booted under AC power
-and then the power removed, the mdelay()/udelay() functions will not delay properly.
- 
-MODULE_PARM(powerdown, "i");
-powerdown=N
-where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
-
-
-MODULE_PARM(external_amp, "i");
-external_amp=1
-if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
-override the detection logic and force the external amp bit in the AC97 0x26 register
-to be reset (0).  EAPD should be 0 for powerup, and 1 for powerdown.  The VTB Santa Cruz
-card has inverted logic, so there is a special function for these cards.
-
-MODULE_PARM(thinkpad, "i");
-thinkpad=1
-if N is set to 1, then force enabling the clkrun functionality.
-Currently, when the part is being used, then clkrun is disabled for the entire system,
-but re-enabled when the driver is released or there is no outstanding open count.
-
diff -urN linux-2.5.6-pre3/Documentation/sound/es1370 linux-2.5.6/Documentation/sound/es1370
--- linux-2.5.6-pre3/Documentation/sound/es1370	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/Documentation/sound/es1370	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-This soundcard does not have any hardware MIDI synthesizer;
-MIDI synthesis has to be done in software. To allow this
-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
-The second one goes to the mixer "synth" setting and supports
-only a limited set of sampling rates (44100, 22050, 11025, 5512).
-By setting lineout to 1 on the driver command line
-(eg. insmod es1370 lineout=1) it is even possible on some
-cards to convert the LINEIN jack into a second LINEOUT jack, thus
-making it possible to output four independent audio channels!
-
-There is a freely available software package that allows
-MIDI file playback on this soundcard called Timidity.
-See http://www.cgs.fi/~tt/timidity/.
-
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/es1371 linux-2.5.6/Documentation/sound/es1371
--- linux-2.5.6-pre3/Documentation/sound/es1371	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/Documentation/sound/es1371	Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-This soundcard does not have any hardware MIDI synthesizer;
-MIDI synthesis has to be done in software. To allow this
-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
-
-There is a freely available software package that allows
-MIDI file playback on this soundcard called Timidity.
-See http://www.cgs.fi/~tt/timidity/.
-
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/mwave linux-2.5.6/Documentation/sound/mwave
--- linux-2.5.6-pre3/Documentation/sound/mwave	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/Documentation/sound/mwave	Wed Dec 31 16:00:00 1969
@@ -1,185 +0,0 @@
-	How to try to survive an IBM Mwave under Linux SB drivers
-
-
-+	IBM have now released documentation of sorts and Torsten is busy
-	trying to make the Mwave work. This is not however a trivial task.
-
-----------------------------------------------------------------------------
-
-OK, first thing - the IRQ problem IS a problem, whether the test is bypassed or
-not.  It is NOT a Linux problem, but an MWAVE problem that is fixed with the
-latest MWAVE patches. So, in other words, don't bypass the test for MWAVES!
-
-I have Windows 95 on /dev/hda1, swap on /dev/hda2, and Red Hat 5 on /dev/hda3.
-
-The steps, then:
-
-    Boot to Linux. 
-    Mount Windows 95 file system (assume mount point = /dos95).
-    mkdir /dos95/linux
-    mkdir /dos95/linux/boot
-    mkdir /dos95/linux/boot/parms
-
-    Copy the kernel, any initrd image, and loadlin to /dos95/linux/boot/.
-
-    Reboot to Windows 95.
-
-    Edit C:/msdos.sys and add or change the following:
-
-        Logo=0
-        BootGUI=0
-
-    Note that msdos.sys is a text file but it needs to be made 'unhidden',
-    readable and writable before it can be edited.  This can be done with
-    DOS' "attrib" command.
-
-    Edit config.sys to have multiple config menus. I have one for windows 95 and
-    five for Linux, like this:
-------------
-[menu]
-menuitem=W95, Windows 95
-menuitem=LINTP, Linux - ThinkPad
-menuitem=LINTP3, Linux - ThinkPad Console
-menuitem=LINDOC, Linux - Docked
-menuitem=LINDOC3, Linux - Docked Console
-menuitem=LIN1, Linux - Single User Mode
-REM menudefault=W95,10
-
-[W95]
-
-[LINTP]
-
-[LINDOC]
-
-[LINTP3]
-
-[LINDOC3]
-
-[LIN1]
-
-[COMMON]
-FILES=30
-REM Please read README.TXT in C:\MWW subdirectory before changing the DOS= statement.
-DOS=HIGH,UMB
-DEVICE=C:\MWW\MANAGER\MWD50430.EXE
-SHELL=c:\command.com /e:2048
--------------------
-
-The important things are the SHELL and DEVICE statements.
-
-    Then change autoexec.bat. Basically everything in there originally should be
-    done ONLY when Windows 95 is booted. Then you add new things specifically
-    for Linux.  Mine is as follows
-
----------------
-@ECHO OFF
-if "%CONFIG%" == "W95" goto W95
-
-REM
-REM Linux stuff
-REM
-SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
-SET BLASTER=A220 I5 D1
-SET MWROOT=C:\MWW
-SET LIBPATH=C:\MWW\DLL
-SET PATH=C:\WINDOWS;C:\MWW\DLL;
-CALL MWAVE START NOSHOW
-c:\linux\boot\loadlin.exe @c:\linux\boot\parms\%CONFIG%.par
-
-:W95
-REM
-REM Windows 95 stuff
-REM
-c:\toolkit\guard
-SET MSINPUT=C:\MSINPUT
-SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
-REM The following is used by DOS games to recognize Sound Blaster hardware.
-REM If hardware settings are changed, please change this line as well.
-REM See the Mwave README file for instructions.
-SET BLASTER=A220 I5 D1
-SET MWROOT=C:\MWW
-SET LIBPATH=C:\MWW\DLL
-SET PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;E:\ORAWIN95\BIN;f:\msdev\bin;e:\v30\bin.dbg;v:\devt\v30\bin;c:\JavaSDK\Bin;C:\MWW\DLL;
-SET INCLUDE=f:\MSDEV\INCLUDE;F:\MSDEV\MFC\INCLUDE
-SET LIB=F:\MSDEV\LIB;F:\MSDEV\MFC\LIB
-win
-
-------------------------
-
-Now build a file in c:\linux\boot\parms for each Linux config that you have.
-
-For example, my LINDOC3 config is for a docked Thinkpad at runlevel 3 with no
-initrd image, and has a parameter file named LINDOC3.PAR in c:\linux\boot\parms:
-
------------------------
-#   LOADLIN @param_file image=other_image root=/dev/other
-#
-#	Linux Console in docking station
-#
-c:\linux\boot\zImage.krn        # First value must be filename of Linux kernel.
-root=/dev/hda3                  # device which gets mounted as root FS
-ro                              # Other kernel arguments go here.
-apm=off
-doc=yes
-3
------------------------
-
-The doc=yes parameter is an environment variable used by my init scripts, not
-a kernel argument.
-
-However, the apm=off parameter IS a kernel argument!  APM, at least in my setup,
-causes the kernel to crash when loaded via loadlin (but NOT when loaded via
-LILO). The APM stuff COULD be forced out of the kernel via the kernel compile
-options. Instead, I got an unofficial patch to the APM drivers that allows them
-to be dynamically deactivated via kernel arguments. Whatever you chose to
-document, APM, it seems, MUST be off for setups like mine.
-
-Now make sure C:\MWW\MWCONFIG.REF looks like this:
-
-----------------------
-[NativeDOS]
-Default=SB1.5
-SBInputSource=CD
-SYNTH=FM
-QSound=OFF
-Reverb=OFF
-Chorus=OFF
-ReverbDepth=5
-ChorusDepth=5
-SBInputVolume=5
-SBMainVolume=10
-SBWaveVolume=10
-SBSynthVolume=10
-WaveTableVolume=10
-AudioPowerDriver=ON
-
-[FastCFG]
-Show=No
-HideOption=Off
------------------------------
-
-OR the Default= line COULD be
-
-Default=SBPRO
-
-Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure
-the sound modules and voilà - ThinkPad sound with Linux.
-
-Now the gotchas - you can either have CD sound OR Mixers but not both. That's a
-problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why
-this is!
-
-For some reason MPEG3 files, when played through mpg123, sound like they
-are playing at 1/8th speed - not very useful!  If you have ANY insight
-on why this second thing might be happening, I would be grateful.
-
-===========================================================
-    _/      _/_/_/_/
-   _/_/  _/_/     _/
-  _/ _/_/ _/_/_/_/      Martin John Bartlett
- _/  _/  _/     _/      (martin@nitram.demon.co.uk)
-_/      _/_/_/_/
-       _/
-_/    _/
- _/_/
-===========================================================
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/AD1816 linux-2.5.6/Documentation/sound/oss/AD1816
--- linux-2.5.6-pre3/Documentation/sound/oss/AD1816	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/AD1816	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,84 @@
+Documentation for the AD1816(A) sound driver
+============================================
+
+Installation:
+-------------
+
+To get your AD1816(A) based sound card work, you'll have to enable support for
+experimental code ("Prompt for development and/or incomplete code/drivers")
+and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable
+"Sound card support", "OSS modules support" and "Support for AD1816(A) based
+cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install
+and reboot the new kernel as usual.
+
+Features:
+---------
+
+List of features supported by this driver:
+- full-duplex support
+- supported audio formats: unsigned 8bit, signed 16bit little endian, 
+                           signed 16bit big endian, µ-law, A-law
+- supported channels: mono and stereo
+- supported recording sources: Master, CD, Line, Line1, Line2, Mic
+- supports phat 3d stereo circuit (Line 3)
+
+
+Supported cards:
+----------------
+
+The following cards are known to work with this driver:
+- Terratec Base 1 
+- Terratec Base 64 
+- HP Kayak 
+- Acer FX-3D
+- SY-1816 
+- Highscreen Sound-Boostar 32 Wave 3D
+- Highscreen Sound-Boostar 16 
+- AVM Apex Pro card 
+- (Aztech SC-16 3D) 
+- (Newcom SC-16 3D) 
+- (Terratec EWS64S) 
+
+Cards listed in brackets are not supported reliable. If you have such a card 
+you should add the extra parameter:
+  options=1
+when loading the ad1816 module via modprobe. 
+
+
+Troubleshooting:
+----------------
+
+First of all you should check, if the driver has been loaded
+properly.
+
+If loading of the driver succeeds, but playback/capture fails, check
+if you used the correct values for irq, dma and dma2 when loading the module.
+If one of them is wrong you usually get the following error message:
+
+Nov  6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error?
+
+If playback/capture is too fast or to slow, you should have a look at
+the clock chip of your sound card. The AD1816 was designed for a 33MHz
+oscillator, however most sound card manufacturer use slightly
+different oscillators as they are cheaper than 33MHz oscillators. If
+you have such a card you have to adjust the ad1816_clockfreq parameter
+above. For example: For a card using a 32.875MHz oscillator use
+ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000.
+
+
+Updates, bugfixes and bugreports:
+--------------------------------
+
+As the driver is still experimental and under development, you should
+watch out for updates.  Updates of the driver are available on the
+Internet from one of my home pages:
+  http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
+or:
+  http://www.tu-darmstadt.de/~tek01/projects/linux.html
+
+Bugreports, bugfixes and related questions should be sent via E-Mail to:
+  tek@rbg.informatik.tu-darmstadt.de
+
+Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
+Christoph Hellwig <hch@infradead.org>
+	Last modified: 2000/09/20
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ALS linux-2.5.6/Documentation/sound/oss/ALS
--- linux-2.5.6-pre3/Documentation/sound/oss/ALS	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ALS	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,66 @@
+ALS-007/ALS-100/ALS-200 based sound cards
+=========================================
+
+Support for sound cards based around the Avance Logic
+ALS-007/ALS-100/ALS-200 chip is included.  These chips are a single
+chip PnP sound solution which is mostly hardware compatible with the
+Sound Blaster 16 card, with most differences occurring in the use of
+the mixer registers.  For this reason the ALS code is integrated
+as part of the Sound Blaster 16 driver (adding only 800 bytes to the
+SB16 driver).
+
+To use an ALS sound card under Linux, enable the following options as
+modules in the sound configuration section of the kernel config:
+  - 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
+  - FM synthesizer (YM3812/OPL-3) support 
+  - standalone MPU401 support may be required for some cards; for the
+    ALS-007, when using isapnptools, it is required
+Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be
+compiled in.  If kernel level PnP support is not included, isapnptools will
+be required to configure the card before the sound modules are loaded.
+
+When using kernel level ISAPnP, the kernel should correctly identify and
+configure all resources required by the card when the "sb" module is
+inserted.  Note that the ALS-007 does not have a 16 bit DMA channel and that
+the MPU401 interface on this card uses a different interrupt to the audio
+section.  This should all be correctly configured by the kernel; if problems
+with the MPU401 interface surface, try using the standalone MPU401 module,
+passing "0" as the "sb" module's "mpu_io" module parameter to prevent the
+soundblaster driver attempting to register the MPU401 itself.  The onboard
+synth device can be accessed using the "opl3" module.
+
+If isapnptools is used to wake up the sound card (as in 2.2.x), the settings
+of the card's resources should be passed to the kernel modules ("sb", "opl3"
+and "mpu401") using the module parameters.  When configuring an ALS-007, be
+sure to specify different IRQs for the audio and MPU401 sections - this card
+requires they be different.  For "sb", "io", "irq" and "dma" should be set
+to the same values used to configure the audio section of the card with
+isapnp.  "dma16" should be explicitly set to "-1" for an ALS-007 since this
+card does not have a 16 bit dma channel; if not specified the kernel will
+default to using channel 5 anyway which will cause audio not to work. 
+"mpu_io" should be set to 0.  The "io" parameter of the "opl3" module should
+also agree with the setting used by isapnp.  To get the MPU401 interface
+working on an ALS-007 card, the "mpu401" module will be required since this
+card uses separate IRQs for the audio and MPU401 sections and there is no
+parameter available to pass a different IRQ to the "sb" driver (whose
+inbuilt MPU401 driver would otherwise be fine).  Insert the mpu401 module
+passing appropriate values using the "io" and "irq" parameters.
+
+The resulting sound driver will provide the following capabilities:
+  - 8 and 16 bit audio playback
+  - 8 and 16 bit audio recording
+  - Software selection of record source (line in, CD, FM, mic, master)
+  - Record and playback of midi data via the external MPU-401
+  - Playback of midi data using inbuilt FM synthesizer
+  - Control of the ALS-007 mixer via any OSS-compatible mixer programs. 
+    Controls available are Master (L&R), Line in (L&R), CD (L&R), 
+    DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
+
+Jonathan Woithe
+jwoithe@physics.adelaide.edu.au
+30 March 1998
+
+Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
+Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
+Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au
+ - updated information for kernel 2.4.x.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/AWE32 linux-2.5.6/Documentation/sound/oss/AWE32
--- linux-2.5.6-pre3/Documentation/sound/oss/AWE32	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/AWE32	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,76 @@
+	Installing and using Creative AWE midi sound under Linux.
+
+This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and 
+SB32.
+
+1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
+   is important, because the driver works only with real Creative cards.
+
+2) The first thing you need to do is re-compile your kernel with support for
+   your sound card. Run your favourite tool to configure the kernel and when
+   you get to the "Sound" menu you should enable support for the following:
+
+   Sound card support,
+   OSS sound modules,
+   100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
+   AWE32 synth
+
+   If your card is "Plug and Play" you will also need to enable these two
+   options, found under the "Plug and Play configuration" menu:
+
+   Plug and Play support
+   ISA Plug and Play support
+
+   Now compile and install the kernel in normal fashion. If you don't know
+   how to do this you can find instructions for this in the README file
+   located in the root directory of the kernel source.
+
+3) Before you can start playing midi files you will have to load a sound
+   bank file. The utility needed for doing this is called "sfxload", and it
+   is one of the utilities found in a package called "awesfx". If this
+   package is not available in your distribution you can download the AWE
+   snapshot from Creative Labs Open Source website:
+
+   http://www.opensource.creative.com/snapshot.html
+
+   Once you have unpacked the AWE snapshot you will see a "awesfx"
+   directory. Follow the instructions in awesfx/docs/INSTALL to install the
+   utilities in this package. After doing this, sfxload should be installed
+   as:
+
+   /usr/local/bin/sfxload
+
+   To enable AWE general midi synthesis you should also get the sound bank
+   file for general midi from:
+
+   http://members.xoom.com/yar/synthgm.sbk.gz
+
+   Copy it to a directory of your choice, and unpack it there.
+
+4) Edit /etc/modules.conf, and insert the following lines at the end of the
+   file:
+
+  alias sound-slot-0 sb
+  alias sound-service-0-1 awe_wave
+  post-install awe_wave /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
+
+  You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
+  path of of the sound bank file. That will enable the Sound Blaster and AWE
+  wave synthesis. To play midi files you should get one of these programs if
+  you don't already have them:
+
+  Playmidi:			http://playmidi.openprojects.net
+
+  AWEMidi Player (drvmidi)  	Included in the previously mentioned AWE
+  				snapshot.
+
+  You will probably have to pass the "-e" switch to playmidi to have it use
+  your midi device. drvmidi should work without switches.
+
+  If something goes wrong please e-mail me. All comments and suggestions are
+  welcome.
+
+		    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
+			    http://www.yar.opennet.ru
+
+Last Updated: Feb 3 2001
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/AudioExcelDSP16 linux-2.5.6/Documentation/sound/oss/AudioExcelDSP16
--- linux-2.5.6-pre3/Documentation/sound/oss/AudioExcelDSP16	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/AudioExcelDSP16	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,101 @@
+Driver
+------
+
+Informations about Audio Excel DSP 16 driver can be found in the source
+file lowlevel/aedsp16.c
+Please, read the head of the source before using it. It contain useful
+informations.
+
+Configuration
+-------------
+
+The Audio Excel configuration, is now done with the standard Linux setup.
+You have to configure the sound card (Sound Blaster or Microsoft Sound System)
+and, if you want it, the Roland MPU-401 (do not use the Sound Blaster MPU-401,
+SB-MPU401) in the main driver menu. Activate the lowlevel drivers then select
+the Audio Excel hardware that you want to initialize. Check the IRQ/DMA/MIRQ
+of the Audio Excel initialization: it must be the same as the SBPRO (or MSS)
+setup. If the parameters are different, correct it.
+I you own a Gallant's audio card based on SC-6600, activate the SC-6600 support.
+If you want to change the configuration of the sound board, be sure to
+check off all the configuration items before re-configure it.
+
+Module parameters
+-----------------
+To use this driver as a module, you must configure some module parameters, to
+set up I/O addresses, IRQ lines and DMA channels. Some parameters are
+mandatory while some others are optional. Here a list of parameters you can
+use with this module:
+
+Name		Description
+====		===========
+MANDATORY
+io		I/O base address (0x220 or 0x240)
+irq		irq line (5, 7, 9, 10 or 11)
+dma		dma channel (0, 1 or 3)
+
+OPTIONAL
+mss_base	I/O base address for activate MSS mode (default SBPRO)
+		(0x530 or 0xE80)
+mpu_base	I/O base address for activate MPU-401 mode
+		(0x300, 0x310, 0x320 or 0x330)
+mpu_irq		MPU-401 irq line (5, 7, 9, 10 or 0)
+
+The /etc/modules.conf will have lines like this:
+
+options opl3 io=0x388
+options ad1848 io=0x530 irq=11 dma=3
+options aedsp16 io=0x220 irq=11 dma=3 mss_base=0x530
+
+Where the aedsp16 options are the options for this driver while opl3 and
+ad1848 are the corresponding options for the MSS and OPL3 modules.
+
+Loading MSS and OPL3 needs to pre load the aedsp16 module to set up correctly
+the sound card. Installation dependencies must be written in the modules.conf
+file:
+
+pre-install ad1848 modprobe aedsp16
+pre-install opl3 modprobe aedsp16
+
+Then you must load the sound modules stack in this order:
+sound -> aedsp16 -> [ ad1848, opl3 ]
+
+With the above configuration, loading ad1848 or opl3 modules, will
+automatically load all the sound stack.
+
+Sound cards supported
+---------------------
+This driver supports the SC-6000 and SC-6600 based Gallant's sound card.
+It don't support the Audio Excel DSP 16 III (try the SC-6600 code).
+I'm working on the III version of the card: if someone have useful
+informations about it, please let me know.
+For all the non-supported audio cards, you have to boot MS-DOS (or WIN95)
+activating the audio card with the MS-DOS device driver, then you have to
+<ctrl>-<alt>-<del> and boot Linux.
+Follow these steps:
+
+1) Compile Linux kernel with standard sound driver, using the emulation
+   you want, with the parameters of your audio card,
+   e.g. Microsoft Sound System irq10 dma3
+2) Install your new kernel as the default boot kernel.
+3) Boot MS-DOS and configure the audio card with the boot time device
+   driver, for MSS irq10 dma3 in our example.
+4) <ctrl>-<alt>-<del> and boot Linux. This will maintain the DOS configuration
+   and will boot the new kernel with sound driver. The sound driver will find
+   the audio card and will recognize and attach it.
+
+Reports on User successes
+-------------------------
+
+> Date: Mon, 29 Jul 1996 08:35:40 +0100
+> From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk>
+> To: riccardo@cdc8g5.cdc.polimi.it (Riccardo Facchetti)
+> Subject: Re: Audio Excel DSP 16 initialization code
+>
+> Just to let you know got my Audio Excel (emulating a MSS) working
+> with my original SB16, thanks for the driver!
+
+
+Last revised: 20 August 1998
+Riccardo Facchetti
+fizban@tin.it
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/CMI8330 linux-2.5.6/Documentation/sound/oss/CMI8330
--- linux-2.5.6-pre3/Documentation/sound/oss/CMI8330	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/CMI8330	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,153 @@
+Documentation for CMI 8330 (SoundPRO) 
+-------------------------------------
+Alessandro Zummo <azummo@ita.flashnet.it>
+
+( Be sure to read Documentation/sound/SoundPro too )
+
+
+This adapter is now directly supported by the sb driver.
+
+ The only thing you have to do is to compile the kernel sound
+support as a module and to enable kernel ISAPnP support,
+as shown below.
+
+
+CONFIG_SOUND=m
+CONFIG_SOUND_SB=m
+
+CONFIG_PNP=y
+CONFIG_ISAPNP=y
+
+
+and optionally:
+
+
+CONFIG_SOUND_MPU401=m
+
+ for MPU401 support.
+
+
+(I suggest you to use "make menuconfig" or "make xconfig" 
+ for a more comfortable configuration editing)
+
+
+
+Then you can do
+
+ modprobe sb
+
+and everything will be (hopefully) configured.
+
+You should get something similar in syslog:
+
+sb: CMI8330 detected.
+sb: CMI8330 sb base located at 0x220
+sb: CMI8330 mpu base located at 0x330
+sb: CMI8330 mail reports to Alessandro Zummo <azummo@ita.flashnet.it>
+sb: ISAPnP reports CMI 8330 SoundPRO at i/o 0x220, irq 7, dma 1,5
+
+
+
+
+The old documentation file follows for reference
+purposes.
+
+
+How to enable CMI 8330 (SOUNDPRO) soundchip on Linux
+------------------------------------------
+Stefan Laudat <Stefan.Laudat@asit.ro>
+
+[Note: The CMI 8338 is unrelated and is supported by cmpci.o]
+
+	
+	In order to use CMI8330 under Linux  you just have to use a proper isapnp.conf, a good isapnp and a little bit of patience.  I use isapnp 1.17, but
+you may get a better one I guess at http://www.roestock.demon.co.uk/isapnptools/.
+
+	Of course you will have to compile kernel sound support as module, as shown below:
+
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS=m
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_MPU401=m
+# Mikro$chaft sound system (kinda useful here ;))	
+CONFIG_SOUND_MSS=m
+
+	The /etc/isapnp.conf file will be:
+
+<snip below>
+
+
+(READPORT 0x0203)
+(ISOLATE PRESERVE)
+(IDENTIFY *)
+(VERBOSITY 2)
+(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+(VERIFYLD N)
+
+
+# WSS 
+
+(CONFIGURE CMI0001/16777472 (LD 0
+(IO 0 (SIZE 8) (BASE 0x0530))
+(IO 1 (SIZE 8) (BASE 0x0388))
+(INT 0 (IRQ 7 (MODE +E)))
+(DMA 0 (CHANNEL 0))
+(NAME "CMI0001/16777472[0]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# MPU
+
+(CONFIGURE CMI0001/16777472 (LD 1
+(IO 0 (SIZE 2) (BASE 0x0330))
+(INT 0 (IRQ 11 (MODE +E)))
+(NAME "CMI0001/16777472[1]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# Joystick
+
+(CONFIGURE CMI0001/16777472 (LD 2
+(IO 0 (SIZE 8) (BASE 0x0200))
+(NAME "CMI0001/16777472[2]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+# SoundBlaster 
+ 
+(CONFIGURE CMI0001/16777472 (LD 3
+(IO 0 (SIZE 16) (BASE 0x0220))
+(INT 0 (IRQ 5 (MODE +E)))
+(DMA 0 (CHANNEL 1))
+(DMA 1 (CHANNEL 5))
+(NAME "CMI0001/16777472[3]{CMI8330/C3D Audio Adapter}")
+(ACT Y)
+))
+
+
+(WAITFORKEY)
+
+<end of snip>
+
+	The module sequence is trivial:
+
+/sbin/insmod soundcore
+/sbin/insmod sound
+/sbin/insmod uart401
+# insert this first
+/sbin/insmod ad1848 io=0x530 irq=7 dma=0 soundpro=1
+# The sb module is an alternative to the ad1848 (Microsoft Sound System)
+# Anyhow, this is full duplex and has MIDI
+/sbin/insmod sb io=0x220 dma=1 dma16=5 irq=5 mpu_io=0x330
+
+
+
+Alma Chao <elysian@ethereal.torsion.org> suggests the following /etc/modules.conf:
+
+alias sound ad1848
+alias synth0 opl3
+options ad1848 io=0x530 irq=7 dma=0 soundpro=1
+options opl3 io=0x388
+
+	
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/CMI8338 linux-2.5.6/Documentation/sound/oss/CMI8338
--- linux-2.5.6-pre3/Documentation/sound/oss/CMI8338	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/CMI8338	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,85 @@
+Audio driver for CM8338/CM8738 chips by Chen-Li Tien
+
+
+HARDWARE SUPPORTED
+================================================================================
+C-Media CMI8338
+C-Media CMI8738
+On-board C-Media chips
+
+
+STEPS TO BUILD DRIVER
+================================================================================
+
+  1. Backup the Config.in and Makefile in the sound driver directory
+     (/usr/src/linux/driver/sound).
+     The Configure.help provide help when you config driver in step
+     4, please backup the original one (/usr/src/linux/Document) and
+     copy this file.
+     The cmpci is document for the driver in detail, please copy it
+     to /usr/src/linux/Document/sound so you can refer it. Backup if
+     there is already one.
+
+  2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
+     directory.
+
+  3. Change directory to /usr/src/linux
+
+  4. Config cm8338 driver by 'make menuconfig', 'make config' or
+     'make xconfig' command.
+
+  5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
+     driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
+     For driver option, please refer 'DRIVER PARAMETER'
+
+  6. Compile the kernel if necessary.
+
+  7. Compile the modules by 'make modules'.
+
+  8. Install the modules by 'make modules_install'
+
+
+INSTALL DRIVER
+================================================================================
+
+  1. Before first time to run the driver, create module dependency by
+     'depmod -a'
+
+  2. To install the driver manually, enter 'modprobe cmpci'.
+
+  3. Driver installation for various distributions:
+
+    a. Slackware 4.0
+       Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
+       file.so you can start the driver automatically each time booting.
+
+    b. Caldera OpenLinux 2.2
+       Use LISA to load the cmpci module.
+
+    c. RedHat 6.0 and S.u.S.E. 6.1
+       Add following command in /etc/conf.modules:
+
+       alias sound cmpci
+
+	also visit http://www.cmedia.com.tw for installation instruction.
+
+DRIVER PARAMETER
+================================================================================
+
+  Some functions for the cm8738 can be configured in Kernel Configuration
+  or modules parameters. Set these parameters to 1 to enable.
+
+  mpuio:	I/O ports base for MPU-401, 0 if disabled.
+  fmio:		I/O ports base for OPL-3, 0 if disabled.
+  spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
+		CD-ROM or DVD-ROM.
+  spdif_loop:   Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
+                directly.
+  speakers:     Number of speakers used.
+  use_line_as_rear:Enable this if you want to use line-in as
+                rear-out.
+  use_line_as_bass:Enable this if you want to use line-in as
+                bass-out.
+  joystick:	Enable joystick. You will need to install Linux joystick
+		driver.
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/CS4232 linux-2.5.6/Documentation/sound/oss/CS4232
--- linux-2.5.6-pre3/Documentation/sound/oss/CS4232	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/CS4232	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,23 @@
+To configure the Crystal CS423x sound chip and activate its DSP functions,
+modules may be loaded in this order:
+  
+	modprobe sound
+	insmod ad1848
+	insmod uart401
+	insmod cs4232 io=* irq=* dma=* dma2=*
+  
+This is the meaning of the parameters:
+  
+	io--I/O address of the Windows Sound System (normally 0x534)
+	irq--IRQ of this device
+	dma and dma2--DMA channels (DMA2 may be 0)
+  
+On some cards, the board attempts to do non-PnP setup, and fails.  If you
+have problems, use Linux' PnP facilities. 
+  
+To get MIDI facilities add
+  
+	insmod opl3 io=*
+  
+where "io" is the I/O address of the OPL3 synthesizer. This will be shown
+in /proc/sys/pnp and is normally 0x388.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ChangeLog.awe linux-2.5.6/Documentation/sound/oss/ChangeLog.awe
--- linux-2.5.6-pre3/Documentation/sound/oss/ChangeLog.awe	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ChangeLog.awe	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,230 @@
+ver.0.4.3p4
+	- Bug fix for invalid memory detection when initialized twice
+	- Add sample sharing function - works together with awesfx-0.4.3p3
+	- Add AWE_PROBE_DATA for probing sample id
+
+ver.0.4.3p3
+	- Replace memset to MEMSET (for FreeBSD)
+	- Add PAN_EXCHANGE switch
+
+ver.0.4.3p2
+	- MIDI emulation device is added
+	- Controls volume and filter targets
+	- Include chorus/reverb/equalizer values in MISC_MODE
+
+ver.0.4.3p1
+	- Change the volume calculation method
+	- Support for Tom Lees' PnP driver (v0.3)
+
+ver.0.4.2d
+	- Support for OSS/Free 3.8 on 2.0 kernels.
+	- Support for Linux PnP driver
+	- Support for module (for recent 2.1 kernels and RH5.0)
+	- Support for FreeBSD-3.0 system
+
+ver.0.4.2c
+	- Add a mode to enable drum channel toggle via bank number
+	  change.
+
+ver.0.4.2b
+	- Clear voice position after note on
+	- Change nrvoices according to the current playing mode
+
+ver.0.4.2a
+	- Fix a bug in pitch calculation with scale parameter
+	- Change default chorus & reverb modes
+
+ver.0.4.2
+	- Use indirect voice allocation mode; used as default mode
+	- Add preset mapping
+	- Free buffers when resetting samples
+	- Set default preset/bank/drumset as variable
+	- Fix a bug in exclusive note-off
+	- Add channel reset control macro
+	- Change modwheel sensitivity as variable
+	- Add lock option in open_patch
+	- Add channel priority mode macro, and disable it as default
+	- Add unset effect macro
+	- Add user defined chorus/reverb modes
+	- Do not initialize effect parameters when allocating voices
+	- Accept realtime filter-Q parameter change
+	- Check value range of set/add effects
+	- Change drum flags automatically when receiving bank #128
+
+ver.0.4.1	development versions
+
+ver.0.4.0c
+	- Fix kernel oops when setting AWE_FX_ATTEN
+
+ver.0.4.0b
+	- Do not kill_note in start_note when velocity is zero
+
+ver.0.4.0a
+	- Fix a bug in channel pressure effects
+
+ver.0.4.0
+	- Support dynamic buffer allocation
+	- Add functions to open/close/unload a patch
+	- Change from pointer to integer index in voice/sample lists
+	- Support for Linux/Alpha-AXP
+	- Fix for FreeBSD
+	- Add sostenuto control
+	- Add midi channel priority
+	- Fix a bug in all notes off control
+	- Use AWE_DEFAULT_MEMSIZE always if defined
+	- Fix a bug in awe_reset causes seg fault when no DRAM onboard
+	- Use awe_mem_start variable instead of constant
+
+ver.0.3.3c
+	- Fix IOCTL_TO_USER for OSS-3.8 (on Linux-2.1.25)
+	- Fix i/o macros for mixer controls
+
+ver.0.3.3b
+	- Fix version number in awe_version.h
+	- Fix a small bug in noteoff/release all
+
+ver.0.3.3a
+	- Fix all notes/sounds off
+	- Add layer effect control
+	- Add misc mode controls; realtime pan, version number, etc.
+	- Move gus bank control in misc mode control
+	- Modify awe_operations for OSS3.8b5
+	- Fix installation script
+
+ver.0.3.3
+	- Add bass/treble control in Emu8000 chip
+	- Add mixer device
+	- Fix sustain on to value 127
+
+ver.0.3.2
+	- Refuse linux-2.0.0 at installation
+	- Move awe_voice.h to /usr/include/linux
+
+ver.0.3.1b (not released)
+	- Rewrite chorus/reverb mode change functions
+	- Rewrite awe_detect & awe_check_dram routines
+
+ver.0.3.1a
+	- Fix a bug to reset voice counter in awe_reset
+	- Fix voice balance on GUS mode
+	- Make symlink on /usr/include/asm in install script
+
+ver.0.3.1
+	- Remove zero size arrays from awe_voice.h
+	- Fix init_fm routine
+	- Remove all samples except primary samples in REMOVE_LAST_SAMPLES
+
+ver.0.3.0a
+	- Add AWE_NOTEOFF_ALL control
+	- Remove AWE_INIT_ATTEN control
+
+ver.0.3.0
+	- Fix decay time table
+	- Add exclusive sounds mode
+	- Add capability to get current status
+
+ver.0.2.99e
+	- Add #ifdef for all sounds/notes off controls.
+	- Fix bugs on searching the default drumset/preset.
+	- Fix usslite patch to modify the default Config.in.
+
+ver.0.2.99d
+	- Fix bugs of attack/hold parameters
+	- Fix attack & decay time table
+
+ver.0.2.99c
+	- Change volume control messages (main & expression volume)
+	  to accesspt normal MIDI parameters in channel mode.
+	- Use channel mode in SEQ2 controls.
+
+ver.0.2.99b
+	- #ifdef patch manager functions (for OSS-3.7)
+
+ver.0.2.99a
+	- Fix sustain bug
+
+ver.0.2.99 (0.3 beta)
+	- Support multiple instruments
+
+ver.0.2.0c
+	- Add copyright notice
+	- FreeBSD 2.2-ALPHA integration
+
+ver.0.2.0b
+	- Remove buffered reading appended in v0.2.0a
+	- Remove SMAxW register check on writing
+	- Support Linux 2.1.x kernel
+	- Rewrite installation script
+
+ver.0.2.0a
+	- Define SEQUENCER_C for tuning.h for FreeBSD system
+	- Improvement of sample loading speed
+	- Fix installation script
+	- Add PnP driver functions for ISA PnP driver support
+
+ver.0.2.0
+	- Includes FreeBSD port
+	- Can load GUS compatible patches
+	- Change values of hardware control parameters for compatibility
+	  with GUS driver
+	- Accept 8bit or unsigned wave data
+	- Accept no blank loop data
+	- Add sample mode flags in sample_info
+
+ver.0.1.6
+	- Add voice effects control
+	- Fix awe_voice.h for word alignment
+
+ver.0.1.5c
+	- Fix FM(OPL) playback problem
+
+ver.0.1.5b
+	- Fix pitch calculation for fixed midi key
+
+ver.0.1.5a
+	- Fix bugs in removing samples from linked list.
+
+ver.0.1.5
+	- Add checksum verification for sample uploading
+	  (not compatible from older sample_info structure)
+	- Fix sample offset pointers to (actual value - 1)
+	- Add sequencer command to initialize awe32
+
+ver.0.1.4c
+	- Fix card detection and memory check function to avoid system crash
+	  at booting
+
+ver.0.1.4b
+	- Add release sustain mode
+	- Initialize FM each time after loading samples
+
+ver.0.1.4a
+	- Fix AWE card detection code
+	- Correct FM initialize position 
+	- Add non-releasing mode on voice info
+
+ver.0.1.4
+	- Add AWE card and DRAM detection codes
+	- Add FM initialization code
+	- Modify volume control
+	- Remove linear volume mode
+	- Change memory management; not using malloc dynamically
+	- Add remove-samples command
+	- Use internal id implicitly at loading samples
+
+ver.0.1.3
+	- Fix a bug on patch uploading to RAM
+
+ver.0.1.2
+	- Divide to separated packages
+	- Fix disagreed macro conditions
+	- Fix unresolved function bugs
+	- Integrate VoxWare and USS-Lite driver source (awe_voice.c)
+	  and remove awe_card.c
+
+ver.0.1.1
+	- Fix wrong sample numbers in sbktext
+	- Fix txt2sfx bug
+	- Fix pan parameter calculation
+	- Append USS-Lite/Linux2.0 driver
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ChangeLog.multisound linux-2.5.6/Documentation/sound/oss/ChangeLog.multisound
--- linux-2.5.6-pre3/Documentation/sound/oss/ChangeLog.multisound	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ChangeLog.multisound	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,213 @@
+1998-12-04  Andrew T. Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.8.2.2
+
+	* Add msndreset program to shell archive.
+
+1998-11-11  Andrew T. Veliath  <andrewv@usa.net>
+
+	* msnd_pinnacle.c (mixer_ioctl): Add a mixer ioctl for
+	SOUND_MIXER_PRIVATE1 which does a full reset on the card.
+	(mixer_set): Move line in recording source to input monitor, aux
+	input level added, some mixer fixes.
+
+1998-09-10  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.8.2
+
+	* Add SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls.
+
+1998-09-09  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.8.1
+	
+	* msnd_pinnacle.c: Fix resetting of default audio parameters. Turn
+	flush code from dsp_halt into dsp_write_flush, and use that for
+	SNDCTL_DSP_SYNC.
+
+1998-09-07  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.8.0
+
+	* Provide separate signal parameters for play and record.
+	
+	* Cleanups to locking and interrupt handling, change default
+	fifosize to 128kB.
+
+	* Update version to 0.7.15
+
+	* Interprocess full-duplex support (ie `cat /dev/dsp > /dev/dsp').
+
+	* More mutex sections for read and write fifos (read + write locks
+	added).
+
+1998-09-05  Andrew Veliath  <andrewtv@usa.net>
+
+	* msnd_pinnacle.c: (chk_send_dsp_cmd) Do full DSP reset upon DSP
+	timeout (when not in interrupt; maintains mixer settings).  Fixes
+	to flushing and IRQ ref counting. Rewrote queuing for smoother
+	playback and fixed initial playback cutoff problem.
+
+1998-09-03  Andrew Veliath  <andrewtv@usa.net>
+
+	* Replaced packed structure accesses with standard C equivalents.
+
+1998-09-01  Andrew Veliath  <andrewtv@usa.net>
+
+	* msnd_pinnacle.c: Add non-PnP configuration to driver code, which
+	  will facilitate compiled-in operation.
+
+1998-08-29  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.7.6
+	
+	* msnd_pinnacle.c (dsp_ioctl): Add DSP_GETFMTS, change SAMPLESIZE
+	  to DSP_SETFMT.
+
+	* Update version to 0.7.5
+	
+	* Create pinnaclecfg.c and turn MultiSound doc into a shell
+	  archive with pinnaclecfg.c included.  pinnaclecfg.c can
+	  now fully configure the card in non-PnP mode, including the
+	  joystick and IDE controller.  Also add an isapnp conf
+	  example.
+
+	* Reduce DSP reset timeout from 20000 to 100
+
+1998-08-06  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.7.2
+	
+	* After A/D calibration, do an explicit set to the line input,
+	  rather than using set_recsrc
+
+1998-07-20  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.7.1
+
+	* Add more OSS ioctls
+	
+1998-07-19  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update doc file
+	
+	* Bring back DIGITAL1 with digital parameter to msnd_pinnacle.c
+	  and CONFIG_MSNDPIN_DIGITAL.  I'm not sure this actually works,
+	  since I find audio playback goes into a very speeded mode of
+	  operation, however it might be due to a lack of a digital
+	  source, which I don't have to test.
+
+1998-07-18  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.7.0
+
+	* Can now compile with Alan Cox' 2.0.34-modular-sound patch (so
+	  now it requires >= 2.1.106 or 2.0.34-ms) (note for 2.0.34-ms it
+	  is in the Experimental section)
+
+	* More modularization, consolidation, also some MIDI hooks
+	  installed for future MIDI modules
+
+	* Write flush
+
+	* Change default speed, channels, bit size to OSS/Free defaults
+
+1998-06-02  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.5b
+
+	* Fix version detection
+	
+	* Remove underflow and overflow resets (delay was too long)
+
+	* Replace spinlocked bitops with atomic bit ops
+
+1998-05-27  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.5a
+	
+	* Better recovery from underflow or overflow conditions
+	
+	* Fix a deadlock condition with one thread reading and the other
+	  writing
+
+1998-05-26  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.5
+	
+	* Separate reset queue functions for play and record
+
+	* Add delays in dsp_halt
+
+1998-05-24  Andrew Veliath  <andrewtv@usa.net>
+
+	* Add a check for Linux >= 2.1.95
+	
+	* Remove DIGITAL1 input until I figure out how to make it work
+	
+	* Add HAVE_DSPCODEH which when not defined will load firmware from
+	  files using mod_firmware_load, then release memory after they
+	  are uploaded (requires reorganized OSS).
+
+1998-05-22  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.4c
+
+	* Hopefully fix the mixer volume problem
+
+1998-05-19  Andrew Veliath  <andrewtv@usa.net>
+
+	* Add __initfuncs and __initdatas to reduce resident code size
+
+	* Move bunch of code around, remove some protos
+
+	* Integrate preliminary changes for Alan Cox's OSS reorganization
+	  for non-OSS drivers to coexist with OSS devices on the same
+	  major.  To compile standalone, must now define STANDALONE.
+
+1998-05-16  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.4b
+	
+	* Integrated older card support into a unified driver, tested on a
+	  MultiSound Classic c/o Kendrick Vargas.
+
+1998-05-15  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.4
+	
+	* Fix read/write return values
+
+1998-05-13  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.3
+
+	* Stop play gracefully
+
+	* Add busy flag
+	
+	* Add major and calibrate_signal module parameters
+	
+	* Add ADC calibration
+
+	* Add some OSS compatibility ioctls
+
+	* Add mixer record selection
+	
+	* Add O_NONBLOCK support, separate read/write wait queues
+
+	* Add sample bit size ioctl, expanded sample rate ioctl
+
+	* Playback suspension now resumes
+
+	* Use signal_pending after interruptible_sleep_on
+	
+	* Add recording, change ints to bit flags
+
+1998-05-11  Andrew Veliath  <andrewtv@usa.net>
+
+	* Update version to 0.2
+
+	* Add preliminary playback support
+
+	* Use new Turtle Beach DSP code
\ No newline at end of file
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ESS linux-2.5.6/Documentation/sound/oss/ESS
--- linux-2.5.6-pre3/Documentation/sound/oss/ESS	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ESS	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,34 @@
+Documentation for the ESS AudioDrive chips
+
+In 2.4 kernels the SoundBlaster driver not only tries to detect an ESS chip, it
+tries to detect the type of ESS chip too. The correct detection of the chip 
+doesn't always succeed however, so unless you use the kernel isapnp facilities
+(and you chip is pnp capable) the default behaviour is 2.0 behaviour which
+means: only detect ES688 and ES1688.
+
+All ESS chips now have a recording level setting. This is a need-to-have for
+people who want to use their ESS for recording sound.
+
+Every chip that's detected as a later-than-es1688 chip has a 6 bits logarithmic
+master volume control.
+
+Every chip that's detected as a ES1887 now has Full Duplex support. Made a 
+little testprogram that shows that is works, haven't seen a real program that
+needs this however.
+
+For ESS chips an additional parameter "esstype" can be specified. This controls
+the (auto) detection of the ESS chips. It can have 3 kinds of values:
+
+-1   Act like 2.0 kernels: only detect ES688 or ES1688.
+0	 Try to auto-detect the chip (may fail for ES1688)
+688  The chip will be treated as  ES688
+1688  ,,  ,,   ,,  ,,    ,,   ,, ES1688
+1868  ,,  ,,   ,,  ,,    ,,   ,, ES1868
+1869  ,,  ,,   ,,  ,,    ,,   ,, ES1869
+1788  ,,  ,,   ,,  ,,    ,,   ,, ES1788
+1887  ,,  ,,   ,,  ,,    ,,   ,, ES1887
+1888  ,,  ,,   ,,  ,,    ,,   ,, ES1888
+
+Because Full Duplex is supported for ES1887 you can specify a second DMA
+channel by specifying module parameter dma16. It can be one of: 0, 1, 3 or 5.
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ESS1868 linux-2.5.6/Documentation/sound/oss/ESS1868
--- linux-2.5.6-pre3/Documentation/sound/oss/ESS1868	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ESS1868	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,55 @@
+Documentation for the ESS1868F AudioDrive PnP sound card
+
+The ESS1868 sound card is a PnP ESS1688-compatible 16-bit sound card.
+
+It should be automatically detected by the Linux Kernel isapnp support when you
+load the sb.o module. Otherwise you should take care of:
+
+  *  The ESS1868 does not allow use of a 16-bit DMA, thus DMA 0, 1, 2, and 3
+     may only be used.
+
+  *  isapnptools version 1.14 does work with ESS1868.  Earlier versions might
+     not.
+
+  *  Sound support MUST be compiled as MODULES, not statically linked
+     into the kernel.
+
+
+NOTE: this is only needed when not using the kernel isapnp support!
+
+For configuring the sound card's I/O addresses, IRQ and DMA, here is a
+sample copy of the isapnp.conf directives regarding the ESS1868:
+
+(CONFIGURE ESS1868/-1 (LD 1
+(IO 0 (BASE 0x0220))
+(IO 1 (BASE 0x0388))
+(IO 2 (BASE 0x0330))
+(DMA 0 (CHANNEL 1))
+(INT 0 (IRQ 5 (MODE +E)))
+(ACT Y)
+))
+
+(for a full working isapnp.conf file, remember the
+(ISOLATE)
+(IDENTIFY *)
+at the beginning and the
+(WAITFORKEY)
+at the end.)
+
+In this setup, the main card I/O is 0x0220, FM synthesizer is 0x0388, and
+the MPU-401 MIDI port is located at 0x0330.  IRQ is IRQ 5, DMA is channel 1.
+
+After configuring the sound card via isapnp, to use the card you must load
+the sound modules with the proper I/O information.  Here is my setup:
+
+# ESS1868F AudioDrive initialization
+
+/sbin/modprobe sound
+/sbin/insmod uart401
+/sbin/insmod sb io=0x220 irq=5 dma=1 dma16=-1
+/sbin/insmod mpu401 io=0x330
+/sbin/insmod opl3 io=0x388
+/sbin/insmod v_midi
+
+opl3 is the FM synthesizer
+/sbin/insmod opl3 io=0x388
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/INSTALL.awe linux-2.5.6/Documentation/sound/oss/INSTALL.awe
--- linux-2.5.6-pre3/Documentation/sound/oss/INSTALL.awe	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/INSTALL.awe	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,134 @@
+================================================================
+	INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
+	Takashi Iwai	<iwai@ww.uni-erlangen.de>
+================================================================
+
+----------------------------------------------------------------
+* Attention to SB-PnP Card Users
+
+If you're using PnP cards, the initialization of PnP is required
+before loading this driver.  You have now three options:
+  1. Use isapnptools.
+  2. Use in-kernel isapnp support.
+  3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
+In this document, only the case 1 case is treated.
+
+----------------------------------------------------------------
+* Installation on Red Hat 5.0 Sound Driver
+
+Please use install-rh.sh under RedHat5.0 directory.
+DO NOT USE install.sh below.
+See INSTALL.RH for more details.
+
+----------------------------------------------------------------
+* Installation/Update by Shell Script
+
+  1. Become root
+
+	% su
+
+  2. If you have never configured the kernel tree yet, run make config
+    once (to make dependencies and symlinks).
+
+	# cd /usr/src/linux
+	# make xconfig
+    
+  3. Run install.sh script
+
+	# sh ./install.sh
+
+  4. Configure your kernel
+
+	(for Linux 2.[01].x user)
+	# cd /usr/src/linux
+	# make xconfig (or make menuconfig)
+
+	(for Linux 1.2.x user)
+	# cd /usr/src/linux
+	# make config
+
+    Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items 
+    in Sound menu.  ("lowlevel drivers" will appear only in 2.x
+    kernel.)
+
+  5. Make your kernel (and modules), and install them as usual.
+
+	5a. make kernel image
+		# make zImage
+
+	5b. make modules and install them
+		# make modules && make modules_install
+
+	5c. If you're using lilo, copy the kernel image and run lilo.
+	    Otherwise, copy the kernel image to suitable directory or
+	    media for your system.
+
+  6. Reboot the kernel if necessary.
+	- If you updated only the modules, you don't have to reboot
+	  the system.  Just remove the old sound modules here.
+		in 
+		# rmmod sound.o		(linux-2.0 or OSS/Free)
+		# rmmod awe_wave.o	(linux-2.1)
+
+  7. If your AWE card is a PnP and not initialized yet, you'll have to
+    do it by isapnp tools.  Otherwise, skip to 8.
+
+	This section described only a brief explanation.  For more
+	details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
+
+	7a. If you have no isapnp.conf file, generate it by pnpdump.
+	    Otherwise, skip to 7d.
+		# pnpdump > /etc/isapnp.conf
+
+	7b. Edit isapnp.conf file.  Comment out the appropriate
+	    lines containing desirable I/O ports, DMA and IRQs.
+	    Don't forget to enable (ACT Y) line.
+
+	7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
+	    ex)
+		(CONFIGURE CTL0048/58128 (LD 2
+		#     ANSI string -->WaveTable<--
+		  (IO 0 (BASE 0x0620))
+		  (IO 1 (BASE 0x0A20))
+		  (IO 2 (BASE 0x0E20))
+		  (ACT Y)
+		))
+
+	7d. Load the config file.
+	    CAUTION: This will reset all PnP cards!
+
+		# isapnp /etc/isapnp.conf
+
+  8. Load the sound module (if you configured it as a module):
+
+	for 2.0 kernel or OSS/Free monolithic module:
+
+		# modprobe sound.o
+
+	for 2.1 kernel:
+
+		# modprobe sound
+		# insmod uart401
+		# insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
+		(These values depend on your settings.)
+		# insmod awe_wave
+		(Be sure to load awe_wave after sb!)
+
+		See /usr/src/linux/Documentation/sound/AWE32 for
+		more details.
+
+  9. (only for obsolete systems) If you don't have /dev/sequencer
+     device file, make it according to Readme.linux file on
+     /usr/src/linux/drivers/sound. (Run a shell script included in
+     that file). <-- This file no longer exists in the recent kernels!
+
+  10. OK, load your own soundfont file, and enjoy MIDI!
+
+	% sfxload synthgm.sbk
+	% drvmidi foo.mid
+
+  11. For more advanced use (eg. dynamic loading, virtual bank and
+      etc.), please read the awedrv FAQ or the instructions in awesfx
+      and awemidi packages.
+
+Good luck!
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Introduction linux-2.5.6/Documentation/sound/oss/Introduction
--- linux-2.5.6-pre3/Documentation/sound/oss/Introduction	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Introduction	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,461 @@
+Introduction	Notes on Modular Sound Drivers and Soundcore
+Wade Hampton 
+2/14/2001
+
+Purpose:  
+========
+This document provides some general notes on the modular 
+sound drivers and their configuration, along with the 
+support modules sound.o and soundcore.o.
+
+Note, some of this probably should be added to the Sound-HOWTO!
+
+Note, soundlow.o was present with 2.2 kernels but is not 
+required for 2.4.x kernels.  References have been removed
+to this.
+
+
+Copying:
+========
+none
+
+
+History:
+========
+0.1.0  11/20/1998  First version, draft
+1.0.0  11/1998     Alan Cox changes, incorporation in 2.2.0
+                   as /usr/src/linux/Documentation/sound/Introduction
+1.1.0  6/30/1999   Second version, added notes on making the drivers,
+                   added info on multiple sound cards of similar types,]
+                   added more diagnostics info, added info about esd.
+                   added info on OSS and ALSA.
+1.1.1  19991031	   Added notes on sound-slot- and sound-service.
+			(Alan Cox)
+1.1.2  20000920    Modified for Kernel 2.4 (Christoph Hellwig)
+1.1.3  20010214    Minor notes and corrections (Wade Hampton)
+                   Added examples of sound-slot-0, etc.
+
+
+Modular Sound Drivers:
+======================
+
+Thanks to the GREAT work by Alan Cox (alan@lxorguk.ukuu.org.uk),
+
+[And Oleg Drokin, Thomas Sailer, Andrew Veliath and more than a few 
+ others - not to mention Hannu's original code being designed well
+ enough to cope with that kind of chopping up](Alan)
+
+the standard Linux kernels support a modular sound driver.  From
+Alan's comments in linux/drivers/sound/README.FIRST:
+
+  The modular sound driver patches were funded by Red Hat Software 
+  (www.redhat.com). The sound driver here is thus a modified version of 
+  Hannu's code. Please bear that in mind when considering the appropriate
+  forums for bug reporting.
+
+The modular sound drivers may be loaded via insmod or modprobe.  
+To support all the various sound modules, there are two general 
+support modules that must be loaded first:
+ 
+   soundcore.o:   Top level handler for the sound system, provides
+                  a set of functions for registration of devices
+                  by type.
+
+   sound.o:       Common sound functions required by all modules.
+
+For the specific sound modules (e.g., sb.o for the Soundblaster), 
+read the documentation on that module to determine what options
+are available, for example IRQ, address, DMA.
+
+Warning, the options for different cards sometime use different names 
+for the same or a similar feature (dma1= versus dma16=).  As a last 
+resort, inspect the code (search for MODULE_PARM).
+
+Notes:
+
+1.  There is a new OpenSource sound driver called ALSA which is
+    currently under development:  http://www.alsa-project.org/
+    The ALSA drivers support some newer hardware that may not 
+    be supported by this sound driver and also provide some 
+    additional features.
+
+2.  The commercial OSS driver may be obtained from the site:
+    http://www/opensound.com.  This may be used for cards that
+    are unsupported by the kernel driver, or may be used
+    by other operating systems.  
+
+3.  The enlightenment sound daemon may be used for playing
+    multiple sounds at the same time via a single card, eliminating
+    some of the requirements for multiple sound card systems.  For
+    more information, see:  http://www.tux.org/~ricdude/EsounD.html  
+    The "esd" program may be used with the real-player and mpeg 
+    players like mpg123 and x11amp.  The newer real-player 
+    and some games even include built-in support for ESD!
+
+
+Building the Modules:
+=====================
+
+This document does not provide full details on building the 
+kernel, etc.  The notes below apply only to making the kernel
+sound modules.   If this conflicts with the kernel's README,
+the README takes precedence. 
+
+1.  To make the kernel sound modules, cd to your /usr/src/linux
+    directory (typically) and type make config, make menuconfig, 
+    or make xconfig (to start the command line, dialog, or x-based
+    configuration tool).  
+
+2.  Select the Sound option and a dialog will be displayed.  
+
+3.  Select M (module) for "Sound card support".
+
+4.  Select your sound driver(s) as a module.  For ProAudio, Sound
+    Blaster, etc., select M (module) for OSS sound modules.
+    [thanks to Marvin Stodolsky <stodolsk@erols.com>]A
+
+5.  Make the kernel (e.g., make dep ; make bzImage), and install
+    the kernel.
+
+6.  Make the modules and install them (make modules; make modules_install).
+
+Note, for 2.4.x kernels, make sure you have the newer modutils 
+loaded or modules will not be loaded properly.  2.4.x changed the 
+layout of /lib/modules/2.4.x and requires an updated modutils.
+
+
+Plug and Play (PnP:
+===================
+
+If the sound card is an ISA PnP card, isapnp may be used
+to configure the card.  See the file isapnp.txt in the 
+directory one level up (e.g., /usr/src/linux/Documentation).
+
+Also the 2.4.x kernels provide PnP capabilities, see the 
+file NEWS in this directory.
+
+PCI sound cards are highly recommended, as they are far 
+easier to configure and from what I have read, they use
+less resources and are more CPU efficient.
+
+
+INSMOD:
+=======
+
+If loading via insmod, the common modules must be loaded in the 
+order below BEFORE loading the other sound modules.  The card-specific
+modules may then be loaded (most require parameters).  For example,
+I use the following via a shell script to load my SoundBlaster:
+
+SB_BASE=0x240
+SB_IRQ=9
+SB_DMA=3
+SB_DMA2=5
+SB_MPU=0x300
+#
+echo Starting sound
+/sbin/insmod soundcore
+/sbin/insmod sound  
+#
+echo Starting sound blaster....
+/sbin/insmod uart401
+/sbin/insmod sb io=$SB_BASE irq=$SB_IRQ dma=$SB_DMA dma16=$SB_DMA2 mpu_io=$SB_MP
+
+When using sound as a module, I typically put these commands
+in a file such as /root/soundon.sh.
+
+
+MODPROBE:
+=========
+
+If loading via modprobe, these common files are automatically loaded 
+when requested by modprobe.  For example, my /etc/modules.conf contains:
+
+alias sound sb 
+options sb io=0x240 irq=9 dma=3 dma16=5 mpu_io=0x300
+
+All you need to do to load the module is:
+
+	/sbin/modprobe sb
+
+
+Sound Status:
+=============
+
+The status of sound may be read/checked by:
+        cat (anyfile).au >/dev/audio
+
+[WWH:  This may not work properly for SoundBlaster PCI 128 cards
+such as the es1370/1 (see the es1370/1 files in this directory) 
+as they do not automatically support uLaw on /dev/audio.]
+
+The status of the modules and which modules depend on 
+which other modules may be checked by:
+	/sbin/lsmod
+
+/sbin/lsmod should show something like the following:
+	sb                     26280   0 
+	uart401                 5640   0  [sb]
+	sound                  57112   0  [sb uart401]
+	soundcore               1968   8  [sb sound]
+
+
+Removing Sound: 
+=============== 
+
+Sound may be removed by using /sbin/rmmod in the reverse order
+in which you load the modules.  Note, if a program has a sound device
+open (e.g., xmixer), that module (and the modules on which it 
+depends) may not be unloaded.
+
+For example, I use the following to remove my Soundblaster (rmmod
+in the reverse order in which I loaded the modules):
+
+/sbin/rmmod sb
+/sbin/rmmod uart401
+/sbin/rmmod sound
+/sbin/rmmod soundcore
+
+When using sound as a module, I typically put these commands
+in a script such as /root/soundoff.sh.
+
+
+Removing Sound for use with OSS: 
+================================ 
+
+If you get really stuck or have a card that the kernel modules
+will not support, you can get a commercial sound driver from
+http://www.opensound.com.  Before loading the commercial sound
+driver, you should do the following:
+
+1.  remove sound modules (detailed above)
+2.  remove the sound modules from /etc/modules.conf
+3.  move the sound modules from /lib/modules/<kernel>/misc
+    (for example, I make a /lib/modules/<kernel>/misc/tmp
+    directory and copy the sound module files to that 
+    directory).
+
+
+Multiple Sound Cards:
+=====================
+
+The sound drivers will support multiple sound cards and there
+are some great applications like multitrack that support them.  
+Typically, you need two sound cards of different types.  Note, this
+uses more precious interrupts and DMA channels and sometimes 
+can be a configuration nightmare.  I have heard reports of 3-4
+sound cards (typically I only use 2).  You can sometimes use
+multiple PCI sound cards of the same type.
+
+On my machine I have two sound cards (cs4232 and Soundblaster Vibra
+16).  By loading sound as modules, I can control which is the first
+sound device (/dev/dsp, /dev/audio, /dev/mixer) and which is 
+the second.  Normally, the cs4232 (Dell sound on the motherboard) 
+would be the first sound device, but I prefer the Soundblaster.  
+All you have to do is to load the one you want as /dev/dsp 
+first (in my case "sb") and then load the other one
+(in my case "cs4232").
+
+If you have two cards of the same type that are jumpered 
+cards or different PnP revisions, you may load the same 
+module twice.  For example, I have a SoundBlaster vibra 16
+and an older SoundBlaster 16 (jumpers).  To load the module
+twice, you need to do the following:
+
+1.  Copy the sound modules to a new name.  For example
+    sb.o could be copied (or symlinked) to sb1.o for the
+    second SoundBlaster.
+
+2.  Make a second entry in /etc/modules.conf, for example,
+    sound1 or sb1.  This second entry should refer to the
+    new module names for example sb1, and should include
+    the I/O, etc. for the second sound card.
+
+3.  Update your soundon.sh script, etc.
+
+Warning:  I have never been able to get two PnP sound cards of the
+same type to load at the same time.  I have tried this several times
+with the Soundblaster Vibra 16 cards.  OSS has indicated that this
+is a PnP problem....  If anyone has any luck doing this, please 
+send me an E-MAIL.  PCI sound cards should not have this problem.a
+Since this was originally release, I have received a couple of 
+mails from people who have accomplished this!
+
+NOTE: In Linux 2.4 the Sound Blaster driver (and only this one yet)
+supports multiple cards with one module by default.
+Read the file 'Soundblaster' in this directory for details.
+
+
+Sound Problems:
+===============
+
+First RTFM (including the troubleshooting section 
+in the Sound-HOWTO). 
+
+1)  If you are having problems loading the modules (for
+    example, if you get device conflict errors) try the
+    following:
+
+  A)  If you have Win95 or NT on the same computer,  
+      write down what addresses, IRQ, and DMA channels
+      those were using for the same hardware.  You probably 
+      can use these addresses, IRQs, and DMA channels.
+      You should really do this BEFORE attempting to get
+      sound working!
+  
+  B)  Check (cat) /proc/interrupts, /proc/ioports,
+      and /proc/dma.  Are you trying to use an address,
+      IRQ or DMA port that another device is using?
+  
+  C)  Check (cat) /proc/isapnp
+  
+  D)  Inspect your /var/log/messages file.  Often that will 
+      indicate what IRQ or IO port could not be obtained.
+  
+  E)  Try another port or IRQ.  Note this may involve 
+      using the PnP tools to move the sound card to 
+      another location.  Sometimes this is the only way 
+      and it is more or less trial and error.
+
+2)  If you get motor-boating (the same sound or part of a 
+    sound clip repeated), you probably have either an IRQ
+    or DMA conflict.  Move the card to another IRQ or DMA
+    port.  This has happened to me when playing long files 
+    when I had an IRQ conflict.
+
+3.  If you get dropouts or pauses when playing high sample
+    rate files such as using mpg123 or x11amp/xmms, you may 
+    have too slow of a CPU and may have to use the options to 
+    play the files at 1/2 speed.  For example, you may use
+    the -2 or -4 option on mpg123.  You may also get this
+    when trying to play mpeg files stored on a CD-ROM
+    (my Toshiba T8000 PII/366 sometimes has this problem).
+
+4.  If you get "cannot access device" errors, your /dev/dsp
+    files, etc. may be set to owner root, mode 600.  You 
+    may have to use the command:
+      chmod 666 /dev/dsp /dev/mixer /dev/audio
+
+5.  If you get "device busy" errors, another program has the
+    sound device open.  For example, if using the Enlightenment
+    sound daemon "esd", the "esd" program has the sound device.
+    If using "esd", please RTFM the docs on ESD.  For example,
+    esddsp <program> may be used to play files via a non-esd
+    aware program.
+
+6)  Ask for help on the sound list or send E-MAIL to the
+    sound driver author/maintainer.
+
+7)  Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
+
+8)  If the system reports insufficient DMA memory then you may want to
+    load sound with the "dmabufs=1" option. Or in /etc/conf.modules add
+	
+	preinstall sound dmabufs=1
+
+    This makes the sound system allocate its buffers and hang onto them.
+
+    You may also set persistent DMA when building a 2.4.x kernel.
+
+
+Configuring Sound:
+==================
+
+There are several ways of configuring your sound:
+
+1)  On the kernel command line (when using the sound driver(s)
+    compiled in the kernel). Check the driver source and
+    documentation for details.
+
+2)  On the command line when using insmod or in a bash script
+    using command line calls to load sound.
+
+3)  In /etc/modules.conf when using modprobe.
+
+4)  Via Red Hat's GPL'd /usr/sbin/sndconfig program (text based).
+
+5)  Via the OSS soundconf program (with the commercial version
+    of the OSS driver.
+
+6)  By just loading the module and let isapnp do everything relevant
+    for you. This works only with a few drivers yet and - of course -
+    only with isapnp hardware.
+
+And I am sure, several other ways.  
+
+Anyone want to write a linuxconf module for configuring sound?
+
+
+Module Loading:
+===============
+
+When a sound card is first referenced and sound is modular, the sound system
+will ask for the sound devices to be loaded. Initially it requests that
+the driver for the sound system is loaded. It then will ask for 
+sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and
+so on). Thus you can do
+
+alias sound-slot-0 sb
+
+To load a soundblaster at this point. If the slot loading does not provide
+the desired device - for example a soundblaster does not directly provide
+a midi synth in all cases then it will request "sound-service-0-n" where n
+is
+
+  0	Mixer
+
+  2  	MIDI
+
+  3, 4	DSP audio
+
+
+For example, I use the following to load my Soundblaster PCI 128
+(ES 1371) card first, followed by my SoundBlaster Vibra 16 card,
+then by my TV card:
+
+# Load the Soundblaster PCI 128 as /dev/dsp, /dev/dsp1, /dev/mixer
+alias sound-slot-0 es1371
+
+# Load the Soundblaster Vibra 16 as /dev/dsp2, /dev/mixer1
+alias sound-slot-1 sb
+options sb io=0x240 irq=5 dma=1 dma16=5 mpu_io=0x330
+
+# Load the BTTV (TV card) as /dev/mixer2
+alias sound-slot-2 bttv
+alias sound-service-2-0 tvmixer
+
+pre-install bttv  modprobe tuner ; modprobe tvmixer
+pre-install tvmixer modprobe msp3400; modprobe tvaudio 
+options tuner debug=0 type=8 
+options bttv  card=0 radio=0 pll=0
+
+
+For More Information (RTFM):
+============================
+1)  Information on kernel modules:  linux/Documentation/modules.txt
+    and manual pages for insmod and modprobe.
+
+2)  Information on PnP, RTFM manual pages for isapnp.
+
+3)  Sound-HOWTO and Sound-Playing-HOWTO.
+
+4)  OSS's WWW site at http://www.opensound.com.
+
+5)  All the files in linux/Documentation/sound.
+
+6)  The comments and code in linux/drivers/sound.
+
+7)  The sndconfig and rhsound documentation from Red Hat.
+
+8)  The Linux-sound mailing list:  sound-list@redhat.com.
+
+9)  Enlightenment documentation (for info on esd)
+    http://www.tux.org/~ricdude/EsounD.html.
+
+10) ALSA home page:  http://www.alsa-project.org/
+
+
+Contact Information:
+====================
+Wade Hampton:  (whampton@staffnet.com)
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/MAD16 linux-2.5.6/Documentation/sound/oss/MAD16
--- linux-2.5.6-pre3/Documentation/sound/oss/MAD16	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/MAD16	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,55 @@
+(This recipe has been edited to update the configuration symbols.)
+
+From: Shaw Carruthers <shaw@shawc.demon.co.uk>
+
+I have been using mad16 sound for some time now with no problems, current
+kernel 2.1.89
+
+lsmod shows:
+
+mad16                   5176   0 
+sb                     22044   0  [mad16]
+uart401                 5576   0  [mad16 sb]
+ad1848                 14176   1  [mad16]
+sound                  61928   0  [mad16 sb uart401 ad1848]
+
+.config has:
+
+CONFIG_SOUND=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_MAD16=m
+CONFIG_SOUND_YM3812=m
+
+modules.conf has:
+
+alias char-major-14 mad16
+options sb mad16=1
+options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+
+
+To get the built in mixer to work this needs to be:
+
+options adlib_card io=0x388     # FM synthesizer
+options sb mad16=1
+options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+
+The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
+
+------------------------------------------------------------------------
+The mad16 module in addition supports the following options:
+
+option:			meaning:			default:
+joystick=0,1 		disabled, enabled 		disabled
+cdtype=0x00,0x02,0x04,	disabled, Sony CDU31A,		disabled
+       0x06,0x08,0x0a   Mitsumi, Panasonic,
+			Secondary IDE, Primary IDE 
+cdport=0x340,0x320,					0x340
+       0x330,0x360
+cdirq=0,3,5,7,9,10,11 	disabled, IRQ3, ... 		disabled
+cddma=0,5,6,7 		disabled, DMA5, ... 		DMA5 for Mitsumi or IDE
+cddma=0,1,2,3 		disabled, DMA1, ... 		DMA3 for Sony or Panasonic
+opl4=0,1 		OPL3, OPL4 			OPL3	
+
+for more details see linux/drivers/sound/mad16.c
+
+Rui Sousa
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Maestro linux-2.5.6/Documentation/sound/oss/Maestro
--- linux-2.5.6-pre3/Documentation/sound/oss/Maestro	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Maestro	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,123 @@
+	An OSS/Lite Driver for the ESS Maestro family of sound cards
+
+			Zach Brown, December 1999
+
+Driver Status and Availability
+------------------------------
+
+The most recent version of this driver will hopefully always be available at
+	http://www.zabbo.net/maestro/
+
+I will try and maintain the most recent stable version of the driver
+in both the stable and development kernel lines.
+
+ESS Maestro Chip Family
+-----------------------
+
+There are 3 main variants of the ESS Maestro PCI sound chip.  The first
+is the Maestro 1.  It was originally produced by Platform Tech as the
+'AGOGO'.  It can be recognized by Platform Tech's PCI ID 0x1285 with
+0x0100 as the device ID.  It was put on some sound boards and a few laptops.  
+ESS bought the design and cleaned it up as the Maestro 2.  This starts
+their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
+The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
+
+The various families of Maestro are mostly identical as far as this 
+driver is concerned.  It doesn't touch the DSP parts that differ (though
+it could for FM synthesis).
+
+Driver OSS Behavior
+--------------------
+
+This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+mostly adhere to the OSS spec.   This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
+
+The /dev/dsp device exported behaves almost as expected.  Playback is
+supported in all the various lovely formats.  8/16bit stereo/mono from
+8khz to 48khz, and mmap()ing for playback behaves.  Capture/recording
+is limited due to oddities with the Maestro hardware.  One can only
+record in 16bit stereo.  For recording the maestro uses non interleaved
+stereo buffers so that mmap()ing the incoming data does not result in
+a ring buffer of LRLR data.  mmap()ing of the read buffers is therefore
+disallowed until this can be cleaned up.
+
+/dev/mixer is an interface to the AC'97 codec on the Maestro.  It is
+worth noting that there are a variety of AC'97s that can be wired to
+the Maestro.  Which is used is entirely up to the hardware implementor.
+This should only be visible to the user by the presence, or lack, of
+'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
+
+The driver doesn't support MIDI or FM playback at the moment.  Typically
+the Maestro is wired to an MPU MIDI chip, but some hardware implementations
+don't.  We need to assemble a white list of hardware implementations that
+have MIDI wired properly before we can claim to support it safely.
+
+Compiling and Installing
+------------------------
+
+With the drivers inclusion into the kernel, compiling and installing
+is the same as most OSS/Lite modular sound drivers.  Compilation
+of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
+in the config system.  
+
+It may be modular or statically linked.  If it is modular it should be
+installed with the rest of the modules for the kernel on the system.
+Typically this will be in /lib/modules/ somewhere.  'alias sound maestro'
+should also be added to your module configs (typically /etc/conf.modules)
+if you're using modular OSS/Lite sound and want to default to using a
+maestro chip.
+
+As this is a PCI device, the module does not need to be informed of
+any IO or IRQ resources it should use, it devines these from the
+system.  Sometimes, on sucky PCs, the BIOS fails to allocated resources
+for the maestro.  This will result in a message like:
+	maestro: PCI subsystem reports IRQ 0, this might not be correct.
+from the kernel.  Should this happen the sound chip most likely will
+not operate correctly.  To solve this one has to dig through their BIOS
+(typically entered by hitting a hot key at boot time) and figure out
+what magic needs to happen so that the BIOS will reward the maestro with
+an IRQ.  This operation is incredibly system specific, so you're on your
+own.  Sometimes the magic lies in 'PNP Capable Operating System' settings.
+
+There are very few options to the driver.  One is 'debug' which will 
+tell the driver to print minimal debugging information as it runs.  This
+can be collected with 'dmesg' or through the klogd daemon.
+
+The other, more interesting option, is 'dsps_order'.  Typically at
+install time the driver will only register one available /dev/dsp device
+for its use.  The 'dsps_order' module parameter allows for more devices
+to be allocated, as a power of two.  Up to 4 devices can be registered
+( dsps_order=2 ).  These devices act as fully distinct units and use
+separate channels in the maestro.
+
+Power Management
+----------------
+
+As of version 0.14, this driver has a minimal understanding of PCI
+Power Management.  If it finds a valid power management capability
+on the PCI device it will attempt to use the power management
+functions of the maestro.  It will only do this on Maestro 2Es and
+only on machines that are known to function well.  You can
+force the use of power management by setting the 'use_pm' module
+option to 1, or can disable it entirely by setting it to 0.
+
+When using power management, the driver does a few things
+differently.  It will keep the chip in a lower power mode
+when the module is inserted but /dev/dsp is not open.  This
+allows the mixer to function but turns off the clocks
+on other parts of the chip.  When /dev/dsp is opened the chip
+is brought into full power mode, and brought back down
+when it is closed.  It also powers down the chip entirely
+when the module is removed or the machine is shutdown.  This
+can have nonobvious consequences.  CD audio may not work
+after a power managing driver is removed.  Also, software that
+doesn't understand power management may not be able to talk
+to the powered down chip until the machine goes through a hard
+reboot to bring it back.
+
+.. more details ..
+------------------
+
+drivers/sound/maestro.c contains comments that hopefully explain
+the maestro implementation.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Maestro3 linux-2.5.6/Documentation/sound/oss/Maestro3
--- linux-2.5.6-pre3/Documentation/sound/oss/Maestro3	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Maestro3	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,84 @@
+	An OSS/Lite Driver for the ESS Maestro3 family of sound chips
+
+			Zach Brown, January 2001
+
+Driver Status and Availability
+------------------------------
+
+The most recent version of this driver will hopefully always be available at
+	http://www.zabbo.net/maestro3/
+
+I will try and maintain the most recent stable version of the driver
+in both the stable and development kernel lines.
+
+Historically I've sucked pretty hard at actually doing that, however.
+
+ESS Maestro3 Chip Family
+-----------------------
+
+The 'Maestro3' is much like the Maestro2 chip.  The noted improvement
+is the removal of the silicon in the '2' that did PCM mixing.  All that
+work is now done through a custom DSP called the ASSP, the Asynchronus
+Specific Signal Processor.
+
+The 'Allegro' is a baby version of the Maestro3.  I'm not entirely clear
+on the extent of the differences, but the driver supports them both :)
+
+The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
+both under ESS's vendor ID of 0x125D.  The Maestro3 can also show up as
+0x199a when hardware strapping is used.
+
+The chip can also act as a multi function device.  The modem IDs follow
+the audio multimedia device IDs.  (so the modem part of an Allegro shows
+up as 0x1989)
+
+Driver OSS Behavior
+--------------------
+
+This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+mostly adhere to the OSS spec.   This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
+
+The /dev/dsp device exported behaves as expected.  Playback is
+supported in all the various lovely formats.  8/16bit stereo/mono from
+8khz to 48khz, with both read()/write(), and mmap().
+
+/dev/mixer is an interface to the AC'97 codec on the Maestro3.  It is
+worth noting that there are a variety of AC'97s that can be wired to
+the Maestro3.  Which is used is entirely up to the hardware implementor.
+This should only be visible to the user by the presence, or lack, of
+'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
+The Allegro has an onchip AC'97.
+
+The driver doesn't support MIDI or FM playback at the moment.
+
+Compiling and Installing
+------------------------
+
+With the drivers inclusion into the kernel, compiling and installing
+is the same as most OSS/Lite modular sound drivers.  Compilation
+of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
+in the config system.  
+
+It may be modular or statically linked.  If it is modular it should be
+installed with the rest of the modules for the kernel on the system.
+Typically this will be in /lib/modules/ somewhere.  'alias sound-slot-0
+maestro3' should also be added to your module configs (typically
+/etc/modules.conf) if you're using modular OSS/Lite sound and want to
+default to using a maestro3 chip.
+
+There are very few options to the driver.  One is 'debug' which will 
+tell the driver to print minimal debugging information as it runs.  This
+can be collected with 'dmesg' or through the klogd daemon.
+
+The other is 'external_amp', which tells the driver to attempt to enable
+an external amplifier.  This defaults to '1', you can tell the driver
+not to bother enabling such an amplifier by setting it to '0'.
+
+Power Management
+----------------
+
+This driver has a minimal understanding of PCI Power Management.  It will
+try and power down the chip when the system is suspended, and power
+it up with it is resumed.  It will also try and power down the chip
+when the machine is shut down.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/MultiSound linux-2.5.6/Documentation/sound/oss/MultiSound
--- linux-2.5.6-pre3/Documentation/sound/oss/MultiSound	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/MultiSound	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,1137 @@
+#! /bin/sh
+#
+#  Turtle Beach MultiSound Driver Notes
+#  -- Andrew Veliath <andrewtv@usa.net>
+#
+#  Last update:                      September 10, 1998
+#  Corresponding msnd driver:        0.8.3
+#
+# ** This file is a README (top part) and shell archive (bottom part).
+#    The corresponding archived utility sources can be unpacked by
+#    running `sh MultiSound' (the utilities are only needed for the
+#    Pinnacle and Fiji cards). **
+#
+#
+#  -=-=- Getting Firmware -=-=-
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#  
+#  See the section `Obtaining and Creating Firmware Files' in this
+#  document for instructions on obtaining the necessary firmware
+#  files.
+#  
+#  
+#  Supported Features
+#  ~~~~~~~~~~~~~~~~~~
+#  
+#  Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is
+#  not currently available) and mixer functionality (/dev/mixer) are
+#  supported (memory mapped digital audio is not yet supported).
+#  Digital transfers and monitoring can be done as well if you have
+#  the digital daughterboard (see the section on using the S/PDIF port
+#  for more information).
+#
+#  Support for the Turtle Beach MultiSound Hurricane architecture is
+#  composed of the following modules (these can also operate compiled
+#  into the kernel):
+#  
+#  msnd               - MultiSound base (requires soundcore)
+#
+#  msnd_classic       - Base audio/mixer support for Classic, Monetery and
+#                       Tahiti cards
+#
+#  msnd_pinnacle      - Base audio/mixer support for Pinnacle and Fiji cards
+#  
+#  
+#  Important Notes - Read Before Using
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#  
+#  The firmware files are not included (may change in future).  You
+#  must obtain these images from Turtle Beach (they are included in
+#  the MultiSound Development Kits), and place them in /etc/sound for
+#  example, and give the full paths in the Linux configuration.  If
+#  you are compiling in support for the MultiSound driver rather than
+#  using it as a module, these firmware files must be accessible
+#  during kernel compilation.
+#
+#  Please note these files must be binary files, not assembler.  See
+#  the section later in this document for instructions to obtain these
+#  files.
+#  
+#  
+#  Configuring Card Resources
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#  ** This section is very important, as your card may not work at all
+#     or your machine may crash if you do not do this correctly. **
+#
+#  * Classic/Monterey/Tahiti
+#  
+#  These cards are configured through the driver msnd_classic.  You must
+#  know the io port, then the driver will select the irq and memory resources
+#  on the card.  It is up to you to know if these are free locations or now,
+#  a conflict can lock the machine up.
+#
+#  * Pinnacle/Fiji
+#
+#  The Pinnacle and Fiji cards have an extra config port, either
+#  0x250, 0x260 or 0x270.  This port can be disabled to have the card
+#  configured strictly through PnP, however you lose the ability to
+#  access the IDE controller and joystick devices on this card when
+#  using PnP.  The included pinnaclecfg program in this shell archive
+#  can be used to configure the card in non-PnP mode, and in PnP mode
+#  you can use isapnptools.  These are described briefly here.
+#
+#  pinnaclecfg is not required; you can use the msnd_pinnacle module
+#  to fully configure the card as well.  However, pinnaclecfg can be
+#  used to change the resource values of a particular device after the
+#  msnd_pinnacle module has been loaded.  If you are compiling the
+#  driver into the kernel, you must set these values during compile
+#  time, however other peripheral resource values can be changed with
+#  the pinnaclecfg program after the kernel is loaded.
+#
+#
+#  *** PnP mode
+#  
+#  Use pnpdump to obtain a sample configuration if you can; I was able
+#  to obtain one with the command `pnpdump 1 0x203' -- this may vary
+#  for you (running pnpdump by itself did not work for me).  Then,
+#  edit this file and use isapnp to uncomment and set the card values.
+#  Use these values when inserting the msnd_pinnacle module.  Using
+#  this method, you can set the resources for the DSP and the Kurzweil
+#  synth (Pinnacle).  Since Linux does not directly support PnP
+#  devices, you may have difficulty when using the card in PnP mode
+#  when it the driver is compiled into the kernel.  Using non-PnP mode
+#  is preferable in this case.
+#
+#  Here is an example mypinnacle.conf for isapnp that sets the card to
+#  io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil
+#  synth to 0x330 and irq 9 (may need editing for your system):
+#
+#  (READPORT 0x0203)
+#  (CSN 2)
+#  (IDENTIFY *)
+#  
+#  # DSP
+#  (CONFIGURE BVJ0440/-1 (LD 0
+#          (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000))
+#          (ACT Y)))
+#  
+#  # Kurzweil Synth (Pinnacle Only)
+#  (CONFIGURE BVJ0440/-1 (LD 1
+#          (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E)))
+#          (ACT Y)))
+#  
+#  (WAITFORKEY)
+#
+#
+#  *** Non-PnP mode
+#  
+#  The second way is by running the card in non-PnP mode.  This
+#  actually has some advantages in that you can access some other
+#  devices on the card, such as the joystick and IDE controller.  To
+#  configure the card, unpack this shell archive and build the
+#  pinnaclecfg program.  Using this program, you can assign the
+#  resource values to the card's devices, or disable the devices.  As
+#  an alternative to using pinnaclecfg, you can specify many of the
+#  configuration values when loading the msnd_pinnacle module (or
+#  during kernel configuration when compiling the driver into the
+#  kernel).
+#
+#  If you specify cfg=0x250 for the msnd_pinnacle module, it
+#  automatically configure the card to the given io, irq and memory
+#  values using that config port (the config port is jumper selectable
+#  on the card to 0x250, 0x260 or 0x270).
+#
+#  See the `msnd_pinnacle Additional Options' section below for more
+#  information on these parameters (also, if you compile the driver
+#  directly into the kernel, these extra parameters can be useful
+#  here).
+#
+#
+# ** It is very easy to cause problems in your machine if you choose a
+#    resource value which is incorrect. **
+#  
+#
+#  Examples
+#  ~~~~~~~~
+#  
+#  * MultiSound Classic/Monterey/Tahiti:
+#  
+#  modprobe soundcore
+#  insmod msnd
+#  insmod msnd_classic io=0x290 irq=7 mem=0xd0000
+#  
+#  * MultiSound Pinnacle in PnP mode:
+#  
+#  modprobe soundcore
+#  insmod msnd
+#  isapnp mypinnacle.conf
+#  insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values
+#  
+#  * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port,
+#    one of 0x250, 0x260 or 0x270):
+#  
+#  insmod soundcore
+#  insmod msnd
+#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000
+#  
+# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP
+#   mode, add the following (assumes you did `isapnp mypinnacle.conf'):
+#  
+#  insmod sound
+#  insmod mpu401 io=0x330 irq=9                    <-- match mypinnacle.conf values
+#  
+# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP
+#   mode, add the following.  Note how we first configure the peripheral's
+#   resources, _then_ install a Linux driver for it:
+#  
+#  insmod sound
+#  pinnaclecfg 0x250 mpu 0x330 9
+#  insmod mpu401 io=0x330 irq=9
+#
+#  -- OR you can use the following sequence without pinnaclecfg in non-PnP mode:
+#
+#  insmod soundcore
+#  insmod msnd
+#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9
+#  insmod sound
+#  insmod mpu401 io=0x330 irq=9
+#
+# * To setup the joystick port on the Pinnacle in non-PnP mode (though
+#   you have to find the actual Linux joystick driver elsewhere), you
+#   can use pinnaclecfg:
+#
+#   pinnaclecfg 0x250 joystick 0x200
+#
+#  -- OR you can configure this using msnd_pinnacle with the following:
+#
+#  insmod soundcore
+#  insmod msnd
+#  insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200
+#
+#  
+#  msnd_classic, msnd_pinnacle Required Options
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#  
+#  If the following options are not given, the module will not load.
+#  Examine the kernel message log for informative error messages.
+#  WARNING--probing isn't supported so try to make sure you have the
+#  correct shared memory area, otherwise you may experience problems.
+#  
+#  io                   I/O base of DSP, e.g. io=0x210
+#  irq                  IRQ number, e.g. irq=5
+#  mem                  Shared memory area, e.g. mem=0xd8000
+#  
+#  
+#  msnd_classic, msnd_pinnacle Additional Options
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#  
+#  fifosize             The digital audio FIFOs, in kilobytes.  If not
+#                       specified, the default will be used.  Increasing
+#                       this value will reduce the chance of a FIFO
+#                       underflow at the expense of increasing overall
+#                       latency.  For example, fifosize=512 will
+#                       allocate 512kB read and write FIFOs (1MB total).
+#                       While this may reduce dropouts, a heavy machine
+#                       load will undoubtedly starve the FIFO of data
+#                       and you will eventually get dropouts.  One
+#                       option is to alter the scheduling priority of
+#                       the playback process, using `nice' or some form
+#                       of POSIX soft real-time scheduling.
+#
+#  calibrate_signal     Setting this to one calibrates the ADCs to the
+#                       signal, zero calibrates to the card (defaults
+#                       to zero).
+#  
+#  
+#  msnd_pinnacle Additional Options
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#  digital              Specify digital=1 to enable the S/PDIF input
+#                       if you have the digital daughterboard
+#                       adapter. This will enable access to the
+#                       DIGITAL1 input for the soundcard in the mixer.
+#                       Some mixer programs might have trouble setting
+#                       the DIGITAL1 source as an input.  If you have
+#                       trouble, you can try the setdigital.c program
+#                       at the bottom of this document.
+#
+#  cfg                  Non-PnP configuration port for the Pinnacle
+#                       and Fiji (typically 0x250, 0x260 or 0x270,
+#                       depending on the jumper configuration).  If
+#                       this option is omitted, then it is assumed
+#                       that the card is in PnP mode, and that the
+#                       specified DSP resource values are already
+#                       configured with PnP (i.e. it won't attempt to
+#                       do any sort of configuration).
+#
+#  When the Pinnacle is in non-PnP mode, you can use the following
+#  options to configure particular devices.  If a full specification
+#  for a device is not given, then the device is not configured.  Note
+#  that you still must use a Linux driver for any of these devices
+#  once their resources are setup (such as the Linux joystick driver,
+#  or the MPU401 driver from OSS for the Kurzweil synth).
+#
+#  mpu_io               I/O port of MPU (on-board Kurzweil synth)
+#  mpu_irq              IRQ of MPU (on-board Kurzweil synth)
+#  ide_io0		First I/O port of IDE controller
+#  ide_io1		Second I/O port of IDE controller
+#  ide_irq		IRQ IDE controller
+#  joystick_io          I/O port of joystick
+#  
+#  
+#  Obtaining and Creating Firmware Files
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#  
+#       For the Classic/Tahiti/Monterey
+#       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+#  
+#  Download to /tmp and unzip the following file from Turtle Beach:
+#  
+#       ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip
+#  
+#  When unzipped, unzip the file named MsndFiles.zip.  Then copy the
+#  following firmware files to /etc/sound (note the file renaming):
+#  
+#    cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin
+#    cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin
+#  
+#  When configuring the Linux kernel, specify /etc/sound/msndinit.bin and
+#  /etc/sound/msndperm.bin for the two firmware files (Linux kernel
+#  versions older than 2.2 do not ask for firmware paths, and are
+#  hardcoded to /etc/sound).
+#
+#  If you are compiling the driver into the kernel, these files must
+#  be accessible during compilation, but will not be needed later.
+#  The files must remain, however, if the driver is used as a module.
+#  
+#  
+#       For the Pinnacle/Fiji
+#       ~~~~~~~~~~~~~~~~~~~~~
+#  
+#  Download to /tmp and unzip the following file from Turtle Beach (be
+#  sure to use the entire URL; some have had trouble navigating to the
+#  URL):
+#  
+#       ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip
+#
+#  Unpack this shell archive, and run make in the created directory
+#  (you need a C compiler and flex to build the utilities).  This
+#  should give you the executables conv, pinnaclecfg and setdigital.
+#  conv is only used temporarily here to create the firmware files,
+#  while pinnaclecfg is used to configure the Pinnacle or Fiji card in
+#  non-PnP mode, and setdigital can be used to set the S/PDIF input on
+#  the mixer (pinnaclecfg and setdigital should be copied to a
+#  convenient place, possibly run during system initialization).
+#
+#  To generating the firmware files with the `conv' program, we create
+#  the binary firmware files by doing the following conversion
+#  (assuming the archive unpacked into a directory named PINNDDK):
+#  
+#    ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin
+#    ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin
+#  
+#  The conv (and conv.l) program is not needed after conversion and can
+#  be safely deleted.  Then, when configuring the Linux kernel, specify
+#  /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two
+#  firmware files (Linux kernel versions older than 2.2 do not ask for
+#  firmware paths, and are hardcoded to /etc/sound).
+#  
+#  If you are compiling the driver into the kernel, these files must
+#  be accessible during compilation, but will not be needed later.
+#  The files must remain, however, if the driver is used as a module.
+#
+#  
+#  Using Digital I/O with the S/PDIF Port
+#  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+#  If you have a Pinnacle or Fiji with the digital daughterboard and
+#  want to set it as the input source, you can use this program if you
+#  have trouble trying to do it with a mixer program (be sure to
+#  insert the module with the digital=1 option, or say Y to the option
+#  during compiled-in kernel operation).  Upon selection of the S/PDIF
+#  port, you should be able monitor and record from it.
+#
+#  There is something to note about using the S/PDIF port.  Digital
+#  timing is taken from the digital signal, so if a signal is not
+#  connected to the port and it is selected as recording input, you
+#  will find PCM playback to be distorted in playback rate.  Also,
+#  attempting to record at a sampling rate other than the DAT rate may
+#  be problematic (i.e. trying to record at 8000Hz when the DAT signal
+#  is 44100Hz).  If you have a problem with this, set the recording
+#  input to analog if you need to record at a rate other than that of
+#  the DAT rate.
+#
+#
+#  -- Shell archive attached below, just run `sh MultiSound' to extract.
+#     Contains Pinnacle/Fiji utilities to convert firmware, configure
+#     in non-PnP mode, and select the DIGITAL1 input for the mixer.
+#
+#
+#!/bin/sh
+# This is a shell archive (produced by GNU sharutils 4.2).
+# To extract the files from this archive, save it to some FILE, remove
+# everything before the `!/bin/sh' line above, then type `sh FILE'.
+#
+# Made on 1998-12-04 10:07 EST by <andrewtv@ztransform.velsoft.com>.
+# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'.
+#
+# Existing files will *not* be overwritten unless `-c' is specified.
+#
+# This shar contains:
+# length mode       name
+# ------ ---------- ------------------------------------------
+#   2046 -rw-rw-r-- MultiSound.d/setdigital.c
+#  10235 -rw-rw-r-- MultiSound.d/pinnaclecfg.c
+#    106 -rw-rw-r-- MultiSound.d/Makefile
+#    141 -rw-rw-r-- MultiSound.d/conv.l
+#   1472 -rw-rw-r-- MultiSound.d/msndreset.c
+#
+save_IFS="${IFS}"
+IFS="${IFS}:"
+gettext_dir=FAILED
+locale_dir=FAILED
+first_param="$1"
+for dir in $PATH
+do
+  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
+     && ($dir/gettext --version >/dev/null 2>&1)
+  then
+    set `$dir/gettext --version 2>&1`
+    if test "$3" = GNU
+    then
+      gettext_dir=$dir
+    fi
+  fi
+  if test "$locale_dir" = FAILED && test -f $dir/shar \
+     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
+  then
+    locale_dir=`$dir/shar --print-text-domain-dir`
+  fi
+done
+IFS="$save_IFS"
+if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
+then
+  echo=echo
+else
+  TEXTDOMAINDIR=$locale_dir
+  export TEXTDOMAINDIR
+  TEXTDOMAIN=sharutils
+  export TEXTDOMAIN
+  echo="$gettext_dir/gettext -s"
+fi
+touch -am 1231235999 $$.touch >/dev/null 2>&1
+if test ! -f 1231235999 && test -f $$.touch; then
+  shar_touch=touch
+else
+  shar_touch=:
+  echo
+  $echo 'WARNING: not restoring timestamps.  Consider getting and'
+  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
+  echo
+fi
+rm -f 1231235999 $$.touch
+#
+if mkdir _sh01426; then
+  $echo 'x -' 'creating lock directory'
+else
+  $echo 'failed to create lock directory'
+  exit 1
+fi
+# ============= MultiSound.d/setdigital.c ==============
+if test ! -d 'MultiSound.d'; then
+  $echo 'x -' 'creating directory' 'MultiSound.d'
+  mkdir 'MultiSound.d'
+fi
+if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)'
+else
+  $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' &&
+/*********************************************************************
+X *
+X * setdigital.c - sets the DIGITAL1 input for a mixer
+X *
+X * Copyright (C) 1998 Andrew Veliath
+X *
+X * This program is free software; you can redistribute it and/or modify
+X * it under the terms of the GNU General Public License as published by
+X * the Free Software Foundation; either version 2 of the License, or
+X * (at your option) any later version.
+X *
+X * This program is distributed in the hope that it will be useful,
+X * but WITHOUT ANY WARRANTY; without even the implied warranty of
+X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+X * GNU General Public License for more details.
+X *
+X * You should have received a copy of the GNU General Public License
+X * along with this program; if not, write to the Free Software
+X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+X *
+X ********************************************************************/
+X
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+X
+int main(int argc, char *argv[])
+{
+X	int fd;
+X	unsigned long recmask, recsrc;
+X
+X	if (argc != 2) {
+X		fprintf(stderr, "usage: setdigital <mixer device>\n");
+X		exit(1);
+X	}
+X
+X	if ((fd = open(argv[1], O_RDWR)) < 0) {
+X		perror(argv[1]);
+X		exit(1);
+X	}
+X
+X	if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) {
+X		fprintf(stderr, "error: ioctl read recording mask failed\n");
+X		perror("ioctl");
+X		close(fd);
+X		exit(1);
+X	}
+X
+X	if (!(recmask & SOUND_MASK_DIGITAL1)) {
+X		fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n");
+X		close(fd);
+X		exit(1);
+X	}
+X
+X	if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) {
+X		fprintf(stderr, "error: ioctl read recording source failed\n");
+X		perror("ioctl");
+X		close(fd);
+X		exit(1);
+X	}
+X
+X	recsrc |= SOUND_MASK_DIGITAL1;
+X	
+X	if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) {
+X		fprintf(stderr, "error: ioctl write recording source failed\n");
+X		perror("ioctl");
+X		close(fd);
+X		exit(1);
+X	}
+X
+X	close(fd);
+X	
+X	return 0;
+}
+SHAR_EOF
+  $shar_touch -am 1204092598 'MultiSound.d/setdigital.c' &&
+  chmod 0664 'MultiSound.d/setdigital.c' ||
+  $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed'
+  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+    || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed'
+e87217fc3e71288102ba41fd81f71ec4  MultiSound.d/setdigital.c
+SHAR_EOF
+  else
+    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`"
+    test 2046 -eq "$shar_count" ||
+    $echo 'MultiSound.d/setdigital.c:' 'original size' '2046,' 'current size' "$shar_count!"
+  fi
+fi
+# ============= MultiSound.d/pinnaclecfg.c ==============
+if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)'
+else
+  $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' &&
+/*********************************************************************
+X *
+X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program
+X *
+X * This is for NON-PnP mode only.  For PnP mode, use isapnptools.
+X *
+X * This is Linux-specific, and must be run with root permissions.
+X *
+X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux
+X *
+X * Copyright (C) 1998 Andrew Veliath
+X *
+X * This program is free software; you can redistribute it and/or modify
+X * it under the terms of the GNU General Public License as published by
+X * the Free Software Foundation; either version 2 of the License, or
+X * (at your option) any later version.
+X *
+X * This program is distributed in the hope that it will be useful,
+X * but WITHOUT ANY WARRANTY; without even the implied warranty of
+X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+X * GNU General Public License for more details.
+X *
+X * You should have received a copy of the GNU General Public License
+X * along with this program; if not, write to the Free Software
+X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+X *
+X ********************************************************************/
+X
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <asm/io.h>
+#include <asm/types.h>
+X
+#define IREG_LOGDEVICE		0x07
+#define IREG_ACTIVATE		0x30
+#define LD_ACTIVATE		0x01
+#define LD_DISACTIVATE		0x00
+#define IREG_EECONTROL		0x3F
+#define IREG_MEMBASEHI		0x40
+#define IREG_MEMBASELO		0x41
+#define IREG_MEMCONTROL		0x42
+#define IREG_MEMRANGEHI		0x43
+#define IREG_MEMRANGELO		0x44
+#define MEMTYPE_8BIT		0x00
+#define MEMTYPE_16BIT		0x02
+#define MEMTYPE_RANGE		0x00
+#define MEMTYPE_HIADDR		0x01
+#define IREG_IO0_BASEHI		0x60
+#define IREG_IO0_BASELO		0x61
+#define IREG_IO1_BASEHI		0x62
+#define IREG_IO1_BASELO		0x63
+#define IREG_IRQ_NUMBER		0x70
+#define IREG_IRQ_TYPE		0x71
+#define IRQTYPE_HIGH		0x02
+#define IRQTYPE_LOW		0x00
+#define IRQTYPE_LEVEL		0x01
+#define IRQTYPE_EDGE		0x00
+X
+#define HIBYTE(w)		((BYTE)(((WORD)(w) >> 8) & 0xFF))
+#define LOBYTE(w)		((BYTE)(w))
+#define MAKEWORD(low,hi)	((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8)))
+X
+typedef __u8			BYTE;
+typedef __u16			USHORT;
+typedef __u16			WORD;
+X
+static int config_port = -1;
+X
+static int msnd_write_cfg(int cfg, int reg, int value)
+{
+X	outb(reg, cfg);
+X	outb(value, cfg + 1);
+X	if (value != inb(cfg + 1)) {
+X		fprintf(stderr, "error: msnd_write_cfg: I/O error\n");
+X		return -EIO;
+X	}
+X	return 0;
+}
+X
+static int msnd_read_cfg(int cfg, int reg)
+{
+X	outb(reg, cfg);
+X	return inb(cfg + 1);
+}
+X
+static int msnd_write_cfg_io0(int cfg, int num, WORD io)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_read_cfg_io0(int cfg, int num, WORD *io)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	
+X	*io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO),
+X		       msnd_read_cfg(cfg, IREG_IO0_BASEHI));
+X
+X	return 0;
+}
+X
+static int msnd_write_cfg_io1(int cfg, int num, WORD io)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_read_cfg_io1(int cfg, int num, WORD *io)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	
+X	*io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO),
+X		       msnd_read_cfg(cfg, IREG_IO1_BASEHI));
+X
+X	return 0;
+}
+X
+static int msnd_write_cfg_irq(int cfg, int num, WORD irq)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_read_cfg_irq(int cfg, int num, WORD *irq)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	
+X	*irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER);
+X
+X	return 0;
+}
+X
+static int msnd_write_cfg_mem(int cfg, int num, int mem)
+{
+X	WORD wmem;
+X
+X	mem >>= 8;
+X	mem &= 0xfff;
+X	wmem = (WORD)mem;
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
+X		return -EIO;
+X	if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT)))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_read_cfg_mem(int cfg, int num, int *mem)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	
+X	*mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO),
+X			msnd_read_cfg(cfg, IREG_MEMBASEHI));
+X	*mem <<= 8;
+X
+X	return 0;
+}
+X
+static int msnd_activate_logical(int cfg, int num)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_write_cfg_io0(cfg, num, io0))
+X		return -EIO;
+X	if (msnd_write_cfg_io1(cfg, num, io1))
+X		return -EIO;
+X	if (msnd_write_cfg_irq(cfg, num, irq))
+X		return -EIO;
+X	if (msnd_write_cfg_mem(cfg, num, mem))
+X		return -EIO;
+X	if (msnd_activate_logical(cfg, num))
+X		return -EIO;
+X	return 0;
+}
+X
+static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem)
+{
+X	if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
+X		return -EIO;
+X	if (msnd_read_cfg_io0(cfg, num, io0))
+X		return -EIO;
+X	if (msnd_read_cfg_io1(cfg, num, io1))
+X		return -EIO;
+X	if (msnd_read_cfg_irq(cfg, num, irq))
+X		return -EIO;
+X	if (msnd_read_cfg_mem(cfg, num, mem))
+X		return -EIO;
+X	return 0;
+}
+X
+static void usage(void)
+{
+X	fprintf(stderr,
+X		"\n"
+X		"pinnaclecfg 1.0\n"
+X		"\n"
+X		"usage: pinnaclecfg <config port> [device config]\n"
+X		"\n"
+X		"This is for use with the card in NON-PnP mode only.\n"
+X		"\n"
+X		"Available devices (not all available for Fiji):\n"
+X		"\n"
+X		"        Device                       Description\n"
+X		"        -------------------------------------------------------------------\n"
+X		"        reset                        Reset all devices (i.e. disable)\n"
+X		"        show                         Display current device configurations\n"
+X		"\n"
+X		"        dsp <io> <irq> <mem>         Audio device\n"
+X		"        mpu <io> <irq>               Internal Kurzweil synth\n"
+X		"        ide <io0> <io1> <irq>        On-board IDE controller\n"
+X		"        joystick <io>                Joystick port\n"
+X		"\n");
+X	exit(1);
+}
+X
+static int cfg_reset(void)
+{
+X	int i;
+X
+X	for (i = 0; i < 4; ++i)
+X		msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0);
+X	
+X	return 0;
+}
+X
+static int cfg_show(void)
+{
+X	int i;
+X	int count = 0;
+X
+X	for (i = 0; i < 4; ++i) {
+X		WORD io0, io1, irq;
+X		int mem;
+X		msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem);
+X		switch (i) {
+X		case 0:
+X			if (io0 || irq || mem) {
+X				printf("dsp 0x%x %d 0x%x\n", io0, irq, mem);
+X				++count;
+X			}
+X			break;
+X		case 1:
+X			if (io0 || irq) {
+X				printf("mpu 0x%x %d\n", io0, irq);
+X				++count;
+X			}
+X			break;
+X		case 2:
+X			if (io0 || io1 || irq) {
+X				printf("ide 0x%x 0x%x %d\n", io0, io1, irq);
+X				++count;
+X			}
+X			break;
+X		case 3:
+X			if (io0) {
+X				printf("joystick 0x%x\n", io0);
+X				++count;
+X			}
+X			break;
+X		}
+X	}
+X
+X	if (count == 0)
+X		fprintf(stderr, "no devices configured\n");
+X	
+X	return 0;
+}
+X
+static int cfg_dsp(int argc, char *argv[])
+{
+X	int io, irq, mem;
+X
+X	if (argc < 3 ||
+X	    sscanf(argv[0], "0x%x", &io) != 1 ||
+X	    sscanf(argv[1], "%d", &irq) != 1 ||
+X	    sscanf(argv[2], "0x%x", &mem) != 1)
+X		usage();
+X
+X	if (!(io == 0x290 ||
+X	      io == 0x260 ||
+X	      io == 0x250 ||
+X	      io == 0x240 ||
+X	      io == 0x230 ||
+X	      io == 0x220 ||
+X	      io == 0x210 ||
+X	      io == 0x3e0)) {
+X		fprintf(stderr, "error: io must be one of "
+X			"210, 220, 230, 240, 250, 260, 290, or 3E0\n");
+X		usage();
+X	}
+X	
+X	if (!(irq == 5 ||
+X	      irq == 7 ||
+X	      irq == 9 ||
+X	      irq == 10 ||
+X	      irq == 11 ||
+X	      irq == 12)) {
+X		fprintf(stderr, "error: irq must be one of "
+X			"5, 7, 9, 10, 11 or 12\n");
+X		usage();
+X	}
+X
+X	if (!(mem == 0xb0000 ||
+X	      mem == 0xc8000 ||
+X	      mem == 0xd0000 ||
+X	      mem == 0xd8000 ||
+X	      mem == 0xe0000 ||
+X	      mem == 0xe8000)) {
+X		fprintf(stderr, "error: mem must be one of "
+X			"0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
+X		usage();
+X	}
+X
+X	return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem);
+}
+X
+static int cfg_mpu(int argc, char *argv[])
+{
+X	int io, irq;
+X
+X	if (argc < 2 ||
+X	    sscanf(argv[0], "0x%x", &io) != 1 ||
+X	    sscanf(argv[1], "%d", &irq) != 1)
+X		usage();
+X	
+X	return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0);
+}
+X
+static int cfg_ide(int argc, char *argv[])
+{
+X	int io0, io1, irq;
+X
+X	if (argc < 3 ||
+X	    sscanf(argv[0], "0x%x", &io0) != 1 ||
+X	    sscanf(argv[0], "0x%x", &io1) != 1 ||
+X	    sscanf(argv[1], "%d", &irq) != 1)
+X		usage();
+X	
+X	return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0);
+}
+X
+static int cfg_joystick(int argc, char *argv[])
+{
+X	int io;
+X
+X	if (argc < 1 ||
+X	    sscanf(argv[0], "0x%x", &io) != 1)
+X		usage();
+X	
+X	return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0);
+}
+X
+int main(int argc, char *argv[])
+{
+X	char *device;
+X	int rv = 0;
+X
+X	--argc; ++argv;
+X
+X	if (argc < 2)
+X		usage();
+X
+X	sscanf(argv[0], "0x%x", &config_port);
+X	if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) {
+X		fprintf(stderr, "error: <config port> must be 0x250, 0x260 or 0x270\n");
+X		exit(1);
+X	}
+X	if (ioperm(config_port, 2, 1)) {
+X		perror("ioperm");
+X		fprintf(stderr, "note: pinnaclecfg must be run as root\n");
+X		exit(1);
+X	}
+X	device = argv[1];
+X
+X	argc -= 2; argv += 2;
+X
+X	if (strcmp(device, "reset") == 0)
+X		rv = cfg_reset();
+X	else if (strcmp(device, "show") == 0)
+X		rv = cfg_show();
+X	else if (strcmp(device, "dsp") == 0)
+X		rv = cfg_dsp(argc, argv);
+X	else if (strcmp(device, "mpu") == 0)
+X		rv = cfg_mpu(argc, argv);
+X	else if (strcmp(device, "ide") == 0)
+X		rv = cfg_ide(argc, argv);
+X	else if (strcmp(device, "joystick") == 0)
+X		rv = cfg_joystick(argc, argv);
+X	else {
+X		fprintf(stderr, "error: unknown device %s\n", device);
+X		usage();
+X	}
+X
+X	if (rv)
+X		fprintf(stderr, "error: device configuration failed\n");
+X	
+X	return 0;
+}
+SHAR_EOF
+  $shar_touch -am 1204092598 'MultiSound.d/pinnaclecfg.c' &&
+  chmod 0664 'MultiSound.d/pinnaclecfg.c' ||
+  $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed'
+  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+    || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed'
+366bdf27f0db767a3c7921d0a6db20fe  MultiSound.d/pinnaclecfg.c
+SHAR_EOF
+  else
+    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`"
+    test 10235 -eq "$shar_count" ||
+    $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10235,' 'current size' "$shar_count!"
+  fi
+fi
+# ============= MultiSound.d/Makefile ==============
+if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)'
+else
+  $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' &&
+CC	= gcc
+CFLAGS	= -O
+PROGS	= setdigital msndreset pinnaclecfg conv
+X
+all: $(PROGS)
+X
+clean:
+X	rm -f $(PROGS)
+SHAR_EOF
+  $shar_touch -am 1204092398 'MultiSound.d/Makefile' &&
+  chmod 0664 'MultiSound.d/Makefile' ||
+  $echo 'restore of' 'MultiSound.d/Makefile' 'failed'
+  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+    || $echo 'MultiSound.d/Makefile:' 'MD5 check failed'
+76ca8bb44e3882edcf79c97df6c81845  MultiSound.d/Makefile
+SHAR_EOF
+  else
+    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`"
+    test 106 -eq "$shar_count" ||
+    $echo 'MultiSound.d/Makefile:' 'original size' '106,' 'current size' "$shar_count!"
+  fi
+fi
+# ============= MultiSound.d/conv.l ==============
+if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)'
+else
+  $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' &&
+%%
+[ \n\t,\r]
+\;.*
+DB
+[0-9A-Fa-f]+H	{ int n; sscanf(yytext, "%xH", &n); printf("%c", n); }
+%%
+int yywrap() { return 1; }
+main() { yylex(); }
+SHAR_EOF
+  $shar_touch -am 0828231798 'MultiSound.d/conv.l' &&
+  chmod 0664 'MultiSound.d/conv.l' ||
+  $echo 'restore of' 'MultiSound.d/conv.l' 'failed'
+  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+    || $echo 'MultiSound.d/conv.l:' 'MD5 check failed'
+d2411fc32cd71a00dcdc1f009e858dd2  MultiSound.d/conv.l
+SHAR_EOF
+  else
+    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`"
+    test 141 -eq "$shar_count" ||
+    $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!"
+  fi
+fi
+# ============= MultiSound.d/msndreset.c ==============
+if test -f 'MultiSound.d/msndreset.c' && test "$first_param" != -c; then
+  $echo 'x -' SKIPPING 'MultiSound.d/msndreset.c' '(file already exists)'
+else
+  $echo 'x -' extracting 'MultiSound.d/msndreset.c' '(text)'
+  sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/msndreset.c' &&
+/*********************************************************************
+X *
+X * msndreset.c - resets the MultiSound card
+X *
+X * Copyright (C) 1998 Andrew Veliath
+X *
+X * This program is free software; you can redistribute it and/or modify
+X * it under the terms of the GNU General Public License as published by
+X * the Free Software Foundation; either version 2 of the License, or
+X * (at your option) any later version.
+X *
+X * This program is distributed in the hope that it will be useful,
+X * but WITHOUT ANY WARRANTY; without even the implied warranty of
+X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+X * GNU General Public License for more details.
+X *
+X * You should have received a copy of the GNU General Public License
+X * along with this program; if not, write to the Free Software
+X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+X *
+X ********************************************************************/
+X
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+X
+int main(int argc, char *argv[])
+{
+X	int fd;
+X
+X	if (argc != 2) {
+X		fprintf(stderr, "usage: msndreset <mixer device>\n");
+X		exit(1);
+X	}
+X
+X	if ((fd = open(argv[1], O_RDWR)) < 0) {
+X		perror(argv[1]);
+X		exit(1);
+X	}
+X
+X	if (ioctl(fd, SOUND_MIXER_PRIVATE1, 0) < 0) {
+X		fprintf(stderr, "error: msnd ioctl reset failed\n");
+X		perror("ioctl");
+X		close(fd);
+X		exit(1);
+X	}
+X
+X	close(fd);
+X	
+X	return 0;
+}
+SHAR_EOF
+  $shar_touch -am 1204100698 'MultiSound.d/msndreset.c' &&
+  chmod 0664 'MultiSound.d/msndreset.c' ||
+  $echo 'restore of' 'MultiSound.d/msndreset.c' 'failed'
+  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
+  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
+    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
+    || $echo 'MultiSound.d/msndreset.c:' 'MD5 check failed'
+c52f876521084e8eb25e12e01dcccb8a  MultiSound.d/msndreset.c
+SHAR_EOF
+  else
+    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/msndreset.c'`"
+    test 1472 -eq "$shar_count" ||
+    $echo 'MultiSound.d/msndreset.c:' 'original size' '1472,' 'current size' "$shar_count!"
+  fi
+fi
+rm -fr _sh01426
+exit 0
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/NEWS linux-2.5.6/Documentation/sound/oss/NEWS
--- linux-2.5.6-pre3/Documentation/sound/oss/NEWS	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/NEWS	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,42 @@
+Linux 2.4 Sound Changes
+2000-September-25
+Christoph Hellwig, <hch@infradead.org>
+
+
+
+=== isapnp support
+
+The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
+Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
+detecting and configuring isapnp devices.
+If you have a not yet supported isapnp soundcard, mail me the content
+of '/proc/isapnp' on your system and some information about your card
+and its driver(s) so I can try to get isapnp working for it.
+
+
+
+=== soundcard resources on kernel commandline
+
+Before Linux 2.4 you had to specify the resources for sounddrivers
+statically linked into the kernel at compile time
+(in make config/menuconfig/xconfig). In Linux 2.4 the ressources are
+now specified at the boot-time kernel commandline (e.g. the lilo
+'append=' line or everything that's after the kernel name in grub).
+Read the Configure.help entry for your card for the parameters.
+
+
+=== softoss is gone
+
+In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
+Use a user space software synthesizer like timidity instead.
+
+
+
+=== /dev/sndstat and /proc/sound are gone
+
+In older Linux versions those files exported some information about the
+OSS/Free configuration to userspace. In Linux 2.3 they were removed because
+they did not support the growing number of pci soundcards and there were
+some general problems with this interface.
+
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/NM256 linux-2.5.6/Documentation/sound/oss/NM256
--- linux-2.5.6-pre3/Documentation/sound/oss/NM256	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/NM256	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,280 @@
+=======================================================
+Documentation for the NeoMagic 256AV/256ZX sound driver
+=======================================================
+
+You're looking at version 1.1 of the driver.  (Woohoo!) It has been
+successfully tested against the following laptop models:
+
+	Sony Z505S/Z505SX/Z505DX/Z505RX
+	Sony F150, F160, F180, F250, F270, F280, PCG-F26
+	Dell Latitude CPi, CPt (various submodels)
+
+There are a few caveats, which is why you should read the entirety of
+this document first.
+
+This driver was developed without any support or assistance from
+NeoMagic.  There is no warranty, expressed, implied, or otherwise.  It
+is free software in the public domain; feel free to use it, sell it,
+give it to your best friends, even claim that you wrote it (but why?!)
+but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
+when it blows up your computer.
+
+Version 1.1 contains a change to try and detect non-AC97 versions of
+the hardware, and not install itself appropriately.  It should also
+reinitialize the hardware on an APM resume event, assuming that APM
+was configured into your kernel.
+
+============
+Installation
+============
+
+Enable the sound drivers, the OSS sound drivers, and then the NM256
+driver.  The NM256 driver *must* be configured as a module (it won't
+give you any other choice).
+
+Next, do the usual "make modules" and "make modules_install".
+Finally, insmod the soundcore, sound and nm256 modules.
+
+When the nm256 driver module is loaded, you should see a couple of
+confirmation messages in the kernel logfile indicating that it found
+the device (the device does *not* use any I/O ports or DMA channels).
+Now try playing a wav file, futz with the CD-ROM if you have one, etc.
+
+The NM256 is entirely a PCI-based device, and all the necessary
+information is automatically obtained from the card.  It can only be
+configured as a module in a vain attempt to prevent people from
+hurting themselves.  It works correctly if it shares an IRQ with
+another device (it normally shares IRQ 9 with the builtin eepro100
+ethernet on the Sony Z505 laptops). 
+
+It does not run the card in any sort of compatibility mode. It will
+not work on laptops that have the SB16-compatible, AD1848-compatible
+or CS4232-compatible codec/mixer; you will want to use the appropriate
+compatible OSS driver with these chipsets.  I cannot provide any
+assistance with machines using the SB16, AD1848 or CS4232 compatible
+versions.  (The driver now attempts to detect the mixer version, and
+will refuse to load if it believes the hardware is not
+AC97-compatible.)
+
+The sound support is very basic, but it does include simultaneous
+playback and record capability.  The mixer support is also quite
+simple, although this is in keeping with the rather limited
+functionality of the chipset.
+
+There is no hardware synthesizer available, as the Losedows OPL-3 and
+MIDI support is done via hardware emulation.
+
+Only three recording devices are available on the Sony: the
+microphone, the CD-ROM input, and the volume device (which corresponds
+to the stereo output).  (Other devices may be available on other
+models of laptops.)  The Z505 series does not have a builtin CD-ROM,
+so of course the CD-ROM input doesn't work.  It does work on laptops
+with a builtin CD-ROM drive.
+
+The mixer device does not appear to have any tone controls, at least
+on the Z505 series.  The mixer module checks for tone controls in the
+AC97 mixer, and will enable them if they are available.
+
+==============
+Known problems
+==============
+
+  * There are known problems with PCMCIA cards and the eepro100 ethernet 
+    driver on the Z505S/Z505SX/Z505DX.  Keep reading.
+
+  * There are also potential problems with using a virtual X display, and
+    also problems loading the module after the X server has been started. 
+    Keep reading.
+
+  * The volume control isn't anywhere near linear.  Sorry.  This will be
+    fixed eventually, when I get sufficiently annoyed with it.  (I doubt
+    it will ever be fixed now, since I've never gotten sufficiently
+    annoyed with it and nobody else seems to care.)
+
+  * There are reports that the CD-ROM volume is very low.  Since I do not
+    have a CD-ROM equipped laptop, I cannot test this (it's kinda hard to
+    do remotely).
+
+  * Only 8 fixed-rate speeds are supported.  This is mainly a chipset
+    limitation.  It may be possible to support other speeds in the future.
+
+  * There is no support for the telephone mixer/codec.  There is support
+    for a phonein/phoneout device in the mixer driver;  whether or not 
+    it does anything is anyone's guess.  (Reports on this would be
+    appreciated.  You'll have to figure out how to get the phone to
+    go off-hook before it'll work, tho.)
+
+  * This driver was not written with any cooperation or support from
+    NeoMagic.  If you have any questions about this, see their website
+    for their official stance on supporting open source drivers.
+
+============
+Video memory
+============
+
+The NeoMagic sound engine uses a portion of the display memory to hold
+the sound buffer.  (Crazy, eh?)  The NeoMagic video BIOS sets up a
+special pointer at the top of video RAM to indicate where the top of
+the audio buffer should be placed.
+
+At the present time XFree86 is apparently not aware of this.  It will
+thus write over either the pointer or the sound buffer with abandon.
+(Accelerated-X seems to do a better job here.)
+
+This implies a few things:
+
+  * Sometimes the NM256 driver has to guess at where the buffer 
+    should be placed, especially if the module is loaded after the
+    X server is started.  It's usually correct, but it will consistently
+    fail on the Sony F250.
+
+  * Virtual screens greater than 1024x768x16 under XFree86 are
+    problematic on laptops with only 2.5MB of screen RAM. This
+    includes all of the 256AV-equipped laptops.  (Virtual displays
+    may or may not work on the 256ZX, which has at least 4MB of
+    video RAM.)
+
+If you start having problems with random noise being output either
+constantly (this is the usual symptom on the F250), or when windows
+are moved around (this is the usual symptom when using a virtual
+screen), the best fix is to
+
+  * Don't use a virtual frame buffer.
+  * Make sure you load the NM256 module before the X server is
+    started.
+
+On the F250, it is possible to force the driver to load properly even
+after the XFree86 server is started by doing:
+
+	insmod nm256 buffertop=0x25a800
+
+This forces the audio buffers to the correct offset in screen RAM.
+
+One user has reported a similar problem on the Sony F270, although
+others apparently aren't seeing any problems.  His suggested command
+is
+
+	insmod nm256 buffertop=0x272800
+
+=================
+Official WWW site
+=================
+
+The official site for the NM256 driver is:
+
+	http://www.uglx.org/sony.html
+
+You should always be able to get the latest version of the driver there,
+and the driver will be supported for the foreseeable future.
+
+==============
+Z505RX and IDE
+==============
+
+There appears to be a problem with the IDE chipset on the Z505RX; one
+of the symptoms is that sound playback periodically hangs (when the
+disk is accessed).  The user reporting the problem also reported that
+enabling all of the IDE chipset workarounds in the kernel solved the
+problem, tho obviously only one of them should be needed--if someone
+can give me more details I would appreciate it.
+
+==============================
+Z505S/Z505SX on-board Ethernet
+==============================
+
+If you're using the on-board Ethernet Pro/100 ethernet support on the Z505
+series, I strongly encourage you to download the latest eepro100 driver from
+Donald Becker's site:
+
+	ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/test/eepro100.c
+
+There was a reported problem on the Z505SX that if the ethernet
+interface is disabled and reenabled while the sound driver is loaded,
+the machine would lock up.  I have included a workaround that is
+working satisfactorily.  However, you may occasionally see a message
+about "Releasing interrupts, over 1000 bad interrupts" which indicates
+that the workaround is doing its job.
+
+==================================
+PCMCIA and the Z505S/Z505SX/Z505DX
+==================================
+
+There is also a known problem with the Sony Z505S and Z505SX hanging
+if a PCMCIA card is inserted while the ethernet driver is loaded, or
+in some cases if the laptop is suspended.  This is caused by tons of
+spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
+
+There is currently no fix for the problem that works in every case.
+The only known workarounds are to disable the ethernet interface
+before inserting or removing a PCMCIA card, or with some cards
+disabling the PCMCIA card before ejecting it will also help the
+problem with the laptop hanging when the card is ejected.
+
+One user has reported that setting the tcic's cs_irq to some value
+other than 9 (like 11) fixed the problem.  This doesn't work on my
+Z505S, however--changing the value causes the cardmgr to stop seeing
+card insertions and removals, cards don't seem to work correctly, and
+I still get hangs if a card is inserted when the kernel is booted.
+
+Using the latest ethernet driver and pcmcia package allows me to
+insert an Adaptec 1480A SlimScsi card without the laptop hanging,
+although I still have to shut down the card before ejecting or
+powering down the laptop.  However, similar experiments with a DE-660
+ethernet card still result in hangs when the card is inserted.  I am
+beginning to think that the interrupts are CardBus-related, since the
+Adaptec card is a CardBus card, and the DE-660 is not; however, I
+don't have any other CardBus cards to test with.
+
+======
+Thanks
+======
+
+First, I want to thank everyone (except NeoMagic of course) for their
+generous support and encouragement.  I'd like to list everyone's name
+here that replied during the development phase, but the list is
+amazingly long.
+
+I will be rather unfair and single out a few people, however:
+
+	Justin Maurer, for being the first random net.person to try it,
+	and for letting me login to his Z505SX to get it working there
+
+	Edi Weitz for trying out several different versions, and giving
+	me a lot of useful feedback
+
+	Greg Rumple for letting me login remotely to get the driver 
+	functional on the 256ZX, for his assistance on tracking
+	down all sorts of random stuff, and for trying out Accel-X
+
+	Zach Brown, for the initial AC97 mixer interface design
+
+	Jeff Garzik, for various helpful suggestions on the AC97
+	interface
+
+	"Mr. Bumpy" for feedback on the Z505RX
+
+	Bill Nottingham, for generous assistance in getting the mixer ID
+	code working
+
+=================
+Previous versions
+=================
+
+Versions prior to 0.3 (aka `noname') had problems with weird artifacts
+in the output and failed to set the recording rate properly.  These
+problems have long since been fixed.
+
+Versions prior to 0.5 had problems with clicks in the output when
+anything other than 16-bit stereo sound was being played, and also had
+periodic clicks when recording.
+
+Version 0.7 first incorporated support for the NM256ZX chipset, which
+is found on some Dell Latitude laptops (the CPt, and apparently
+some CPi models as well).  It also included the generic AC97
+mixer module.
+
+Version 0.75 renamed all the functions and files with slightly more
+generic names.
+
+Note that previous versions of this document claimed that recording was
+8-bit only; it actually has been working for 16-bits all along.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/OPL3 linux-2.5.6/Documentation/sound/oss/OPL3
--- linux-2.5.6-pre3/Documentation/sound/oss/OPL3	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/OPL3	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,6 @@
+A pure OPL3 card is nice and easy to configure. Simply do
+
+insmod opl3 io=0x388
+
+Change the I/O address in the very unlikely case this card is differently
+configured
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/OPL3-SA linux-2.5.6/Documentation/sound/oss/OPL3-SA
--- linux-2.5.6-pre3/Documentation/sound/oss/OPL3-SA	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/OPL3-SA	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,52 @@
+OPL3-SA1 sound driver (opl3sa.o)
+
+---
+Note: This howto only describes how to setup the OPL3-SA1 chip; this info
+does not apply to the SA2, SA3, or SA4. 
+---
+
+The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
+it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
+and OPL3 FM Synth capabilities.
+
+You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
+CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
+
+You'll need to know all of the relevant info (irq, dma, and io port) for the
+chip's WSS mode, since that is the mode the kernel sound driver uses, and of
+course you'll also need to know about where the MPU401 and OPL3 ports and
+IRQs are if you want to use those.
+
+Here's the skinny on how to load it as a module:
+
+	modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
+
+Module options in detail:
+
+	io:	This is the WSS's port base.
+	irq:	This is the WSS's IRQ.
+	dma:	This is the WSS's DMA line. In my BIOS setup screen this was
+		listed as "WSS Play DMA"
+	dma2:	This is the WSS's secondary DMA line. My BIOS calls it the
+		"WSS capture DMA"
+	
+	mpu_io:	This is the MPU401's port base.
+	mpu_irq: This is the MPU401's IRQ.
+
+If you'd like to use the OPL3 FM Synthesizer, make sure you enable
+CONFIG_YM3812 (in 'make config'). That'll build the opl3.o module.
+
+Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
+
+You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
+Here's how:
+
+Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
+
+If you said yes, the software synth is available once you boot your new
+kernel.
+
+If you chose to build it as a module, just insmod the resulting softoss2.o
+
+Questions? Comments?
+<stiker@northlink.com>
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/OPL3-SA2 linux-2.5.6/Documentation/sound/oss/OPL3-SA2
--- linux-2.5.6-pre3/Documentation/sound/oss/OPL3-SA2	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/OPL3-SA2	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,210 @@
+Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
+---------------------------------------------------------------
+
+Scott Murray, scott@spiteful.org
+January 7, 2001
+
+NOTE: All trade-marked terms mentioned below are properties of their
+      respective owners.
+
+
+Supported Devices
+-----------------
+
+This driver is for PnP soundcards based on the following Yamaha audio
+controller chipsets:
+
+YMF711 aka OPL3-SA2
+YMF715 and YMF719 aka OPL3-SA3
+
+Up until recently (December 2000), I'd thought the 719 to be a
+different chipset, the OPL3-SAx.  After an email exhange with
+Yamaha, however, it turns out that the 719 is just a re-badged
+715, and the chipsets are identical.  The chipset detection code
+has been updated to reflect this.
+
+Anyways, all of these chipsets implement the following devices:
+
+OPL3 FM synthesizer
+Soundblaster Pro
+Microsoft/Windows Sound System
+MPU401 MIDI interface
+
+Note that this driver uses the MSS device, and to my knowledge these
+chipsets enforce an either/or situation with the Soundblaster Pro
+device and the MSS device.  Since the MSS device has better
+capabilities, I have implemented the driver to use it.
+
+
+Mixer Channels
+--------------
+
+Older versions of this driver (pre-December 2000) had two mixers,
+an OPL3-SA2 or SA3 mixer and a MSS mixer.  The OPL3-SA[23] mixer
+device contained a superset of mixer channels consisting of its own
+channels and all of the MSS mixer channels.  To simplify the driver
+considerably, and to partition functionality better, the OPL3-SA[23]
+mixer device now contains has its own specific mixer channels.  They
+are:
+
+Volume     - Hardware master volume control
+Bass       - SA3 only, now supports left and right channels
+Treble     - SA3 only, now supports left and right channels
+Microphone - Hardware microphone input volume control
+Digital1   - Yamaha 3D enhancement "Wide" mixer
+
+All other mixer channels (e.g. "PCM", "CD", etc.) now have to be
+controlled via the "MS Sound System (CS4231)" mixer.  To facilitate
+this, the mixer device creation order has been switched so that
+the MSS mixer is created first.  This allows accessing the majority
+of the useful mixer channels even via single mixer-aware tools
+such as "aumix".
+
+
+Plug 'n Play
+------------
+
+In previous kernels (2.2.x), some configuration was required to
+get the driver to talk to the card.  Being the new millennium and
+all, the 2.4.x kernels now support auto-configuration if ISA PnP
+support is configured in.  Theoretically, the driver even supports
+having more than one card in this case.
+
+With the addition of PnP support to the driver, two new parameters
+have been added to control it:
+
+isapnp   - set to 0 to disable ISA PnP card detection
+
+multiple - set to 0 to disable multiple PnP card detection
+
+
+Optional Parameters
+-------------------
+
+Recent (December 2000) additions to the driver (based on a patch
+provided by Peter Englmaier) are two new parameters:
+
+ymode -    Set Yamaha 3D enhancement mode:
+           0 = Desktop/Normal  5-12 cm speakers
+           1 = Notebook PC (1) 3 cm speakers
+           2 = Notebook PC (2) 1.5 cm speakers
+           3 = Hi-Fi           16-38 cm speakers
+
+loopback - Set A/D input source. Useful for echo cancellation:
+           0 = Mic Right channel (default)
+           1 = Mono output loopback
+
+The ymode parameter has been tested and does work.  The loopback
+parameter, however, is untested.  Any feedback on its usefulness
+would be appreciated.
+
+
+Manual Configuration
+--------------------
+
+If for some reason you decide not to compile ISA PnP support into
+your kernel, or disabled the driver's usage of it by setting the
+isapnp parameter as discussed above, then you will need to do some
+manual configuration.  There are two ways of doing this.  The most
+common is to use the isapnptools package to initialize the card, and
+use the kernel module form of the sound subsystem and sound drivers.
+Alternatively, some BIOS's allow manual configuration of installed
+PnP devices in a BIOS menu, which should allow using the non-modular
+sound drivers, i.e. built into the kernel.
+
+I personally use isapnp and modules, and do not have access to a PnP
+BIOS machine to test.  If you have such a beast, configuring the
+driver to be built into the kernel should just work (thanks to work
+done by David Luyer <luyer@ucs.uwa.edu.au>).  You will still need
+to specify settings, which can be done by adding:
+
+opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>
+
+to the kernel command line.  For example:
+
+opl3sa2=0x370,5,0,1,0x530,0x330
+
+If you are instead using the isapnp tools (as most people have been
+before Linux 2.4.x), follow the directions in their documentation to
+produce a configuration file.  Here is the relevant excerpt I used to
+use for my SA3 card from my isapnp.conf:
+
+(CONFIGURE YMH0800/-1 (LD 0
+
+# NOTE: IO 0 is for the unused SoundBlaster part of the chipset.
+(IO 0 (BASE 0x0220))
+(IO 1 (BASE 0x0530))
+(IO 2 (BASE 0x0388))
+(IO 3 (BASE 0x0330))
+(IO 4 (BASE 0x0370))
+(INT 0 (IRQ 5 (MODE +E)))
+(DMA 0 (CHANNEL 0))
+(DMA 1 (CHANNEL 1))
+
+Here, note that:
+
+Port  Acceptable Range  Purpose
+----  ----------------  -------
+IO 0  0x0220 - 0x0280   SB base address, unused.
+IO 1  0x0530 - 0x0F48   MSS base address
+IO 2  0x0388 - 0x03F8   OPL3 base address
+IO 3  0x0300 - 0x0334   MPU base address
+IO 4  0x0100 - 0x0FFE   card's own base address for its control I/O ports
+
+The IRQ and DMA values can be any that are considered acceptable for a
+MSS.  Assuming you've got isapnp all happy, then you should be able to
+do something like the following (which matches up with the isapnp
+configuration above):
+
+modprobe mpu401
+modprobe ad1848
+modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1
+modprobe opl3 io=0x388
+
+See the section "Automatic Module Loading" below for how to set up
+/etc/modules.conf to automate this.
+
+An important thing to remember that the opl3sa2 module's io argument is
+for it's own control port, which handles the card's master mixer for
+volume (on all cards), and bass and treble (on SA3 cards).
+
+
+Troubleshooting
+---------------
+
+If all goes well and you see no error messages, you should be able to
+start using the sound capabilities of your system.  If you get an
+error message while trying to insert the opl3sa2 module, then make
+sure that the values of the various arguments match what you specified
+in your isapnp configuration file, and that there is no conflict with
+another device for an I/O port or interrupt.  Checking the contents of
+/proc/ioports and /proc/interrupts can be useful to see if you're
+butting heads with another device.
+
+If you still cannot get the module to load, look at the contents of
+your system log file, usually /var/log/messages.  If you see the
+message "opl3sa2: Unknown Yamaha audio controller version", then you
+have a different chipset version than I've encountered so far.  Look
+for all messages in the log file that start with "opl3sa2: " and see
+if they provide any clues.  If you do not see the chipset version
+message, and none of the other messages present in the system log are
+helpful, email me some details and I'll try my best to help.
+
+
+Automatic Module Loading
+------------------------
+
+Lastly, if you're using modules and want to set up automatic module
+loading with kmod, the kernel module loader, here is the section I
+currently use in my modules.conf file:
+
+# Sound
+alias sound-slot-0 opl3sa2
+options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
+options opl3 io=0x388
+
+That's all it currently takes to get an OPL3-SA3 card working on my
+system.  Once again, if you have any other problems, email me at the
+address listed above.
+
+Scott
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Opti linux-2.5.6/Documentation/sound/oss/Opti
--- linux-2.5.6-pre3/Documentation/sound/oss/Opti	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Opti	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,222 @@
+Support for the OPTi 82C931 chip
+--------------------------------
+Note: parts of this README file apply also to other
+cards that use the mad16 driver.
+
+Some items in this README file are based on features
+added to the sound driver after Linux-2.1.91 was out.
+By the time of writing this I do not know which official
+kernel release will include these features.
+Please do not report inconsistencies on older Linux
+kernels.
+
+The OPTi 82C931 is supported in its non-PnP mode.
+Usually you do not need to set jumpers, etc. The sound driver
+will check the card status and if it is required it will
+force the card into a mode in which it can be programmed.
+
+If you have another OS installed on your computer it is recommended
+that Linux and the other OS use the same resources.
+
+Also, it is recommended that resources specified in /etc/modules.conf
+and resources specified in /etc/isapnp.conf agree.
+
+Compiling the sound driver
+--------------------------
+I highly recommend that you build a modularized sound driver.
+This document does not cover a sound-driver which is built in
+the kernel.
+
+Sound card support should be enabled as a module (chose m).
+Answer 'm' for  these items:
+  Generic OPL2/OPL3 FM synthesizer support		(CONFIG_SOUND_ADLIB)
+  Microsoft Sound System support			(CONFIG_SOUND_MSS)
+  Support for OPTi MAD16 and/or Mozart based cards	(CONFIG_SOUND_MAD16)
+  FM synthesizer (YM3812/OPL-3) support			(CONFIG_SOUND_YM3812)
+
+The configuration menu may ask for addresses, IRQ lines or DMA
+channels. If the card is used as a module the module loading
+options will override these values.
+
+For the OPTi 931 you can answer 'n' to:
+  Support MIDI in older MAD16 based cards (requires SB)	(CONFIG_SOUND_MAD16_OLDCARD)
+If you do need MIDI support in a Mozart or C928 based card you
+need to answer 'm' to the above question. In that case you will
+also need to answer 'm' to:
+  '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB)
+
+Go on and compile your kernel and modules. Install the modules. Run depmod -a.
+
+Using isapnptools
+-----------------
+In most systems with a PnP BIOS you do not need to use isapnp. The
+initialization provided by the BIOS is sufficient for the driver
+to pick up the card and continue initialization.
+
+If that fails, or if you have other PnP cards, you need to use isapnp
+to initialize the card.
+This was tested with isapnptools-1.11 but I recommend that you use
+isapnptools-1.13 (or newer). Run pnpdump to dump the information
+about your PnP cards. Then edit the resulting file and select
+the options of your choice. This file is normally installed as
+/etc/isapnp.conf.
+
+The driver has one limitation with respect to I/O port resources:
+IO3 base must be 0x0E0C.  Although isapnp allows other ports, this
+address is hard-coded into the driver.
+
+Using kmod and autoloading the sound driver
+-------------------------------------------
+Comment: as of linux-2.1.90 kmod is replacing kerneld.
+The config file '/etc/modules.conf' is used as before.
+
+This is the sound part of my /etc/modules.conf file.
+Following that I will explain each line.
+
+alias mixer0 mad16
+alias audio0 mad16
+alias midi0  mad16
+alias synth0 opl3
+options sb mad16=1
+options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
+options opl3 io=0x388
+post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
+
+If you have an MPU daughtercard or onboard MPU you will want to add to the
+"options mad16" line - eg 
+
+options mad16 irq=5 dma=0 dma16=3 io=0x530 mpu_io=0x330 mpu_irq=9
+
+To set the I/O and IRQ of the MPU.
+
+
+Explain:
+
+alias mixer0 mad16
+alias audio0 mad16
+alias midi0  mad16
+alias synth0 opl3
+
+When any sound device is opened the kernel requests auto-loading
+of char-major-14. There is a built-in alias that translates this
+request to loading the main sound module.
+
+The sound module in its turn will request loading of a sub-driver
+for mixer, audio, midi or synthesizer device. The first 3 are
+supported by the mad16 driver. The synth device is supported
+by the opl3 driver.
+
+There is currently no way to autoload the sound device driver
+if more than one card is installed.
+
+options sb mad16=1
+
+This is left for historical reasons. If you enable the
+config option 'Support MIDI in older MAD16 based cards (requires SB)'
+or if you use an older mad16 driver it will force loading of the
+SoundBlaster driver. This option tells the SB driver not to look
+for a SB card but to wait for the mad16 driver.
+
+options mad16 irq=10 dma=0 dma16=1 io=0x530 joystick=1 cdtype=0
+options opl3 io=0x388
+
+post-install mad16 /sbin/ad1848_mixer_reroute 14 8 15 3 16 6
+
+This sets resources and options for the mad16 and opl3 drivers.
+I use two DMA channels (only one is required) to enable full duplex.
+joystick=1 enables the joystick port. cdtype=0 disables the cd port.
+You can also set mpu_io and mpu_irq in the mad16 options for the
+uart401 driver.
+
+This tells modprobe to run /sbin/ad1848_mixer_reroute after
+mad16 is successfully loaded and initialized. The source
+for ad1848_mixer_reroute is appended to the end of this readme
+file. It is impossible for the sound driver to know the actual
+connections to the mixer. The 3 inputs intended for cd, synth
+and line-in are mapped to the generic inputs line1, line2 and
+line3. This program reroutes these mixer channels to their
+right names (note the right mapping depends on the actual sound
+card that you use).
+The numeric parameters mean:
+ 14=line1 8=cd    - reroute line1 to the CD input.
+ 15=line2 3=synth - reroute line2 to the synthesizer input.
+ 16=line3 6=line  - reroute line3 to the line input.
+For reference on other input names look at the file
+/usr/include/linux/soundcard.h.
+
+Using a joystick
+-----------------
+You must enable a joystick in the mad16 options. (also
+in /etc/isapnp.conf if you use it).
+Tested with regular analog joysticks.
+
+A CDROM drive connected to the sound card
+-----------------------------------------
+The 82C931 chip has support only for secondary ATAPI cdrom.
+(cdtype=8). Loading the mad16 driver resets the C931 chip
+and if a cdrom was already mounted it may cause a complete
+system hang. Do not use the sound card if you have an alternative.
+If you do use the sound card it is important that you load
+the mad16 driver (use "modprobe mad16" to prevent auto-unloading)
+before the cdrom is accessed the first time.
+
+Using the sound driver built-in to the kernel may help here, but...
+Most new systems have a PnP BIOS and also two IDE controllers.
+The IDE controller on the sound card may be needed only on older
+systems (which have only one IDE controller) but these systems
+also do not have a PnP BIOS - requiring isapnptools and a modularized
+driver.
+
+Known problems
+--------------
+1. See the section on "A CDROM drive connected to the sound card".
+
+2. On my system the codec cannot capture companded sound samples.
+   (eg., recording from /dev/audio). When any companded capture is
+   requested I get stereo-16 bit samples instead. Playback of
+   companded samples works well. Apparently this problem is not common
+   to all C931 based cards. I do not know how to identify cards that
+   have this problem.
+
+Source for ad1848_mixer_reroute.c
+---------------------------------
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/soundcard.h>
+
+static char *mixer_names[SOUND_MIXER_NRDEVICES] =
+	SOUND_DEVICE_LABELS;
+
+int
+main(int argc, char **argv) {
+	int val, from, to;
+	int i, fd;
+
+	fd = open("/dev/mixer", O_RDWR);
+	if(fd < 0) {
+		perror("/dev/mixer");
+		return 1;
+	}
+
+	for(i = 2; i < argc; i += 2) {
+		from = atoi(argv[i-1]);
+		to = atoi(argv[i]);
+
+		if(to == SOUND_MIXER_NONE)
+			fprintf(stderr, "%s: turning off mixer %s\n",
+				argv[0], mixer_names[to]);
+		else
+			fprintf(stderr, "%s: rerouting mixer %s to %s\n",
+				argv[0], mixer_names[from], mixer_names[to]);
+
+		val = from << 8 | to;
+
+		if(ioctl(fd, SOUND_MIXER_PRIVATE2, &val)) {
+			perror("AD1848 mixer reroute");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/PAS16 linux-2.5.6/Documentation/sound/oss/PAS16
--- linux-2.5.6-pre3/Documentation/sound/oss/PAS16	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/PAS16	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,163 @@
+Pro Audio Spectrum 16 for 2.3.99 and later
+=========================================
+by Thomas Molina (tmolina@home.com)
+last modified 3 Mar 2001
+Acknowledgement to Axel Boldt (boldt@math.ucsb.edu) for stuff taken
+from Configure.help, Riccardo Facchetti for stuff from README.OSS,
+and others whose names I could not find.
+
+This documentation is relevant for the PAS16 driver (pas2_card.c and
+friends) under kernel version 2.3.99 and later.  If you are
+unfamiliar with configuring sound under Linux, please read the
+Sound-HOWTO, linux/Documentation/sound/Introduction and other 
+relevant docs first.
+
+The following information is relevant information from README.OSS
+and legacy docs for the Pro Audio Spectrum 16 (PAS16):
+==================================================================
+
+The pas2_card.c driver supports the following cards --
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+        Pro Audio Spectrum 16
+        Pro Audio Studio 16
+        Logitech Sound Man 16
+        NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+              and will not be supported by the driver.
+
+The sound driver configuration dialog
+-------------------------------------
+
+Sound configuration starts by making some yes/no questions. Be careful
+when answering to these questions since answering y to a question may
+prevent some later ones from being asked. For example don't answer y to
+the question about (PAS16) if you don't really have a PAS16.  Sound
+configuration may also be made modular by answering m to configuration
+options presented. 
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions depending on the earlier choices. It may also
+select some options automatically as well.
+
+  "ProAudioSpectrum 16 support",
+        - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+          Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
+          you read the above list correctly). Don't answer 'y' if you
+          have some other card made by Media Vision or Logitech since they
+          are not PAS16 compatible.
+          NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+          if you want to use the SB emulation of PAS16. It's also possible to
+          the emulation if you want to use a true SB card together with PAS16
+          (there is another question about this that is asked later).
+
+  "Generic OPL2/OPL3 FM synthesizer support",
+        - Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+	  The PAS16 has an OPL3-compatible FM chip.
+
+With PAS16 you can use two audio device files at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+
+The new stuff for 2.3.99 and later
+============================================================================
+The following configuration options from linux/Documentation/Configure.help
+are relevant to configuring the PAS16:
+
+Sound card support
+CONFIG_SOUND
+  If you have a sound card in your computer, i.e. if it can say more
+  than an occasional beep, say Y. Be sure to have all the information
+  about your sound card and its configuration down (I/O port,
+  interrupt and DMA channel), because you will be asked for it.
+
+  You want to read the Sound-HOWTO, available from
+  http://www.linuxdoc.org/docs.html#howto . General information
+  about the modular sound system is contained in the files
+  Documentation/sound/Introduction. The file
+  Documentation/sound/README.OSS contains some slightly outdated but
+  still useful information as well.
+
+OSS sound modules
+CONFIG_SOUND_OSS
+  OSS is the Open Sound System suite of sound card drivers. They make
+  sound programming easier since they provide a common API. Say Y or M
+  here (the module will be called sound.o) if you haven't found a
+  driver for your sound card above, then pick your driver from the
+  list below.
+
+Persistent DMA buffers
+CONFIG_SOUND_DMAP
+  Linux can often have problems allocating DMA buffers for ISA sound
+  cards on machines with more than 16MB of RAM. This is because ISA
+  DMA buffers must exist below the 16MB boundary and it is quite
+  possible that a large enough free block in this region cannot be
+  found after the machine has been running for a while. If you say Y
+  here the DMA buffers (64Kb) will be allocated at boot time and kept
+  until the shutdown. This option is only useful if you said Y to
+  "OSS sound modules", above. If you said M to "OSS sound modules"
+  then you can get the persistent DMA buffer functionality by passing
+  the command-line argument "dmabuf=1" to the sound.o module.
+
+  Say y here for PAS16.
+
+ProAudioSpectrum 16 support
+CONFIG_SOUND_PAS
+  Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
+  16 or Logitech SoundMan 16 sound card. Don't answer Y if you have
+  some other card made by Media Vision or Logitech since they are not
+  PAS16 compatible.  It is not necessary to enable the  separate
+  Sound Blaster support; it is included in the PAS driver.
+
+  If you compile the driver into the kernel, you have to add
+  "pas2=<io>,<irq>,<dma>,<dma2>,<sbio>,<sbirq>,<sbdma>,<sbdma2>
+  to the kernel command line.
+
+FM Synthesizer (YM3812/OPL-3) support
+CONFIG_SOUND_YM3812
+  Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+  Answering Y is usually a safe and recommended choice, however some
+  cards may have software (TSR) FM emulation. Enabling FM support with
+  these cards may cause trouble (I don't currently know of any such
+  cards, however).
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
+  If you compile the driver into the kernel, you have to add
+  "opl3=<io>" to the kernel command line.
+
+  If you compile your drivers into the kernel, you MUST configure 
+  OPL3 support as a module for PAS16 support to work properly.
+  You can then get OPL3 functionality by issuing the command:
+  insmod opl3
+  In addition, you must either add the following line to 
+  /etc/modules.conf:
+  options opl3 io=0x388
+  or else add the following line to /etc/lilo.conf:
+  opl3=0x388
+
+
+EXAMPLES
+===================================================================
+To use the PAS16 in my computer I have enabled the following sound
+configuration options:
+
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS=y
+CONFIG_SOUND_TRACEINIT=y
+CONFIG_SOUND_DMAP=y
+CONFIG_SOUND_PAS=y
+CONFIG_SOUND_SB=n
+CONFIG_SOUND_YM3812=m
+
+I have also included the following append line in /etc/lilo.conf:
+append="pas2=0x388,10,3,-1,0x220,5,1,-1 sb=0x220,5,1,-1 opl3=0x388"
+
+The io address of 0x388 is default configuration on the PAS16.  The
+irq of 10 and dma of 3 may not match your installation.  The above 
+configuration enables PAS16, 8-bit Soundblaster and OPL3
+functionality.  If Soundblaster functionality is not desired, the
+following line would be appropriate:
+append="pas2=0x388,10,3,-1,0,-1,-1,-1 opl3=0x388"
+
+If sound is built totally modular, the above options may be 
+specified in /etc/modules.conf for pas2.o, sb.o and opl3.o 
+respectively. 
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/PSS linux-2.5.6/Documentation/sound/oss/PSS
--- linux-2.5.6-pre3/Documentation/sound/oss/PSS	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/PSS	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,41 @@
+The PSS cards and other ECHO based cards provide an onboard DSP with 
+downloadable programs and also has an AD1848 "Microsoft Sound System" 
+device. The PSS driver enables MSS and MPU401 modes of the card. SB 
+is not enabled since it doesn't work concurrently with MSS. 
+
+If you build this driver as a module then the driver takes the following
+parameters
+
+pss_io. 	The I/O base the PSS card is configured at (normally 0x220
+		or 0x240)
+
+mss_io		The base address of the Microsoft Sound System interface.
+		This is normally 0x530, but may be 0x604 or other addresses.
+
+mss_irq		The interrupt assigned to the Microsoft Sound System
+		emulation. IRQ's 3,5,7,9,10,11 and 12 are available. If you
+		get IRQ errors be sure to check the interrupt is set to 
+		"ISA/Legacy" in the BIOS on modern machines.
+
+mss_dma		The DMA channel used by the Microsoft Sound System.
+		This can be 0, 1, or 3. DMA 0 is not available on older 
+		machines and will cause a crash on them.
+
+mpu_io		The MPU emulation base address. This sets the base of the
+		synthesizer. It is typically 0x330 but can be altered.
+
+mpu_irq		The interrupt to use for the synthesizer. It must differ
+		from the IRQ used by the Microsoft Sound System port.
+
+
+The mpu_io/mpu_irq fields are optional. If they are not specified the 
+synthesizer parts are not configured.
+
+When the module is loaded it looks for a file called 
+/etc/sound/pss_synth. This is the firmware file from the DOS install disks.
+This fil holds a general MIDI emulation. The file expected is called
+genmidi.ld on newer DOS driver install disks and synth.ld on older ones.
+
+You can also load alternative DSP algorithms into the card if you wish. One
+alternative driver can be found at http://www.mpg123.de/
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/PSS-updates linux-2.5.6/Documentation/sound/oss/PSS-updates
--- linux-2.5.6-pre3/Documentation/sound/oss/PSS-updates	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/PSS-updates	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,88 @@
+	This file contains notes for users of PSS sound cards who wish to use the 
+newly added features of the newest version of this driver.
+
+	The major enhancements present in this new revision of this driver is the 
+addition of two new module parameters that allow you to take full advantage of 
+all the features present on your PSS sound card.  These features include the 
+ability to enable both the builtin CDROM and joystick ports.
+
+pss_enable_joystick
+
+	This parameter is basically a flag.  A 0 will leave the joystick port 
+disabled, while a non-zero value would enable the joystick port.  The default 
+setting is pss_enable_joystick=0 as this keeps this driver fully compatable 
+with systems that were using previous versions of this driver.  If you wish to 
+enable the joystick port you will have to add pss_enable_joystick=1 as an 
+argument to the driver.  To actually use the joystick port you will then have 
+to load the joystick driver itself.  Just remember to load the joystick driver 
+AFTER the pss sound driver.
+
+pss_cdrom_port
+
+	This parameter takes a port address as its parameter.  Any available port 
+address can be specified to enable the CDROM port, except for 0x0 and -1 as 
+these values would leave the port disabled.  Like the joystick port, the cdrom 
+port will require that an appropiate CDROM driver be loaded before you can make 
+use of the newly enabled CDROM port.  Like the joystick port option above, 
+remember to load the CDROM driver AFTER the pss sound driver.  While it may 
+differ on some PSS sound cards, all the PSS sound cards that I have seen have a 
+builtin Wearnes CDROM port.  If this is the case with your PSS sound card you 
+should load aztcd with the appropiate port option that matches the port you 
+assigned to the CDROM port when you loaded your pss sound driver.  (ex. 
+modprobe pss pss_cdrom_port=0x340 && modprobe aztcd aztcd=0x340)  The default 
+setting of this parameter leaves the CDROM port disabled to maintain full 
+compatability with systems using previous versions of this driver.
+
+	Other options have also been added for the added convenience and utility 
+of the user.  These options are only available if this driver is loaded as a 
+module.
+
+pss_no_sound
+
+	This module parameter is a flag that can be used to tell the driver to 
+just configure non-sound components.  0 configures all components, a non-0 
+value will only attept to configure the CDROM and joystick ports.  This 
+parameter can be used by a user who only wished to use the builtin joystick 
+and/or CDROM port(s) of his PSS sound card.  If this driver is loaded with this 
+parameter and with the paramter below set to true then a user can safely unload 
+this driver with the following command "rmmod pss && rmmod ad1848 && rmmod 
+mpu401 && rmmod sound && rmmod soundcore" and retain the full functionality of 
+his CDROM and/or joystick port(s) while gaining back the memory previously used 
+by the sound drivers.  This default setting of this parameter is 0 to retain 
+full behavioral compatability with previous versions of this driver.
+
+pss_keep_settings
+
+	This parameter can be used to specify whether you want the driver to reset 
+all emulations whenever its unloaded.  This can be useful for those who are 
+sharing resources (io ports, IRQ's, DMA's) between different ISA cards.  This 
+flag can also be useful in that future versions of this driver may reset all 
+emulations by default on the driver's unloading (as it probably should), so 
+specifying it now will ensure that all future versions of this driver will 
+continue to work as expected.  The default value of this parameter is 1 to 
+retain full behavioral compatability with previous versions of this driver.
+
+pss_firmware
+
+	This parameter can be used to specify the file containing the firmware 
+code so that a user could tell the driver where that file is located instead 
+of having to put it in a predefined location with a predefined name.  The 
+default setting of this parameter is "/etc/sound/pss_synth" as this was the 
+path and filename the hardcoded value in the previous versions of this driver.
+
+Examples:
+
+# Normal PSS sound card system, loading of drivers.
+# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules).
+
+/sbin/modprobe pss pss_io=0x220 mpu_io=0x338 mpu_irq=9 mss_io=0x530 mss_irq=10 mss_dma=1 pss_cdrom_port=0x340 pss_enable_joystick=1
+/sbin/modprobe aztcd aztcd=0x340
+/sbin/modprobe joystick
+
+# System using the PSS sound card just for its CDROM and joystick ports.
+# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules).
+
+/sbin/modprobe pss pss_io=0x220 pss_cdrom_port=0x340 pss_enable_joystick=1 pss_no_sound=1
+/sbin/rmmod pss && /sbin/rmmod ad1848 && /sbin/rmmod mpu401 && /sbin/rmmod sound && /sbin/rmmod soundcore  # This line not needed, but saves memory.
+/sbin/modprobe aztcd aztcd=0x340
+/sbin/modprobe joystick
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/README.OSS linux-2.5.6/Documentation/sound/oss/README.OSS
--- linux-2.5.6-pre3/Documentation/sound/oss/README.OSS	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/README.OSS	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,1456 @@
+Introduction
+------------
+
+This file is a collection of all the old Readme files distributed with
+OSS/Lite by Hannu Savolainen. Since the new Linux sound driver is founded
+on it I think these information may still be interesting for users that
+have to configure their sound system.
+
+Be warned: Alan Cox is the current maintainer of the Linux sound driver so if
+you have problems with it, please contact him or the current device-specific
+driver maintainer (e.g. for aedsp16 specific problems contact me). If you have
+patches, contributions or suggestions send them to Alan: I'm sure they are
+welcome.
+
+In this document you will find a lot of references about OSS/Lite or ossfree:
+they are gone forever. Keeping this in mind and with a grain of salt this
+document can be still interesting and very helpful.
+
+[ File edited 17.01.1999 - Riccardo Facchetti ]
+[ Edited miroSOUND section 19.04.2001 - Robert Siemer ]
+
+OSS/Free version 3.8 release notes
+----------------------------------
+
+Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux FTP 
+sites). It gives instructions about using sound with Linux. It's bit out of
+date but still very useful. Information about bug fixes and such things
+is available from the web page (see above).
+
+Please check http://www.opensound.com/pguide for more info about programming
+with OSS API.
+
+   ====================================================
+-  THIS VERSION ____REQUIRES____ Linux 2.1.57 OR LATER.
+   ====================================================
+
+Packages "snd-util-3.8.tar.gz" and "snd-data-0.1.tar.Z"
+contain useful utilities to be used with this driver.
+See http://www.opensound.com/ossfree/getting.html for
+download instructions.
+
+If you are looking for the installation instructions, please
+look forward into this document.
+
+Supported sound cards
+---------------------
+
+See below.
+
+Contributors
+------------
+
+This driver contains code by several contributors. In addition several other
+persons have given useful suggestions. The following is a list of major
+contributors. (I could have forgotten some names.)
+
+	Craig Metz	1/2 of the PAS16 Mixer and PCM support
+	Rob Hooft	Volume computation algorithm for the FM synth.
+	Mika Liljeberg	uLaw encoding and decoding routines
+	Jeff Tranter	Linux SOUND HOWTO document
+	Greg Lee	Volume computation algorithm for the GUS and
+			lots of valuable suggestions.
+	Andy Warner	ISC port
+	Jim Lowe,
+	Amancio Hasty Jr	FreeBSD/NetBSD port
+	Anders Baekgaard 	Bug hunting and valuable suggestions.
+	Joerg Schubert	SB16 DSP support (initial version).
+	Andrew Robinson Improvements to the GUS driver
+	Megens SA	MIDI recording for SB and SB Pro (initial version).
+	Mikael Nordqvist  Linear volume support for GUS and
+			  nonblocking /dev/sequencer.
+	Ian Hartas		SVR4.2 port
+	Markus Aroharju	and
+	Risto Kankkunen		Major contributions to the mixer support
+				of GUS v3.7.
+	Hunyue Yau	Mixer support for SG NX Pro.
+	Marc Hoffman	PSS support (initial version).
+	Rainer Vranken	Initialization for Jazz16 (initial version).
+	Peter Trattler	Initial version of loadable module support for Linux.
+	JRA Gibson	16 bit mode for Jazz16 (initial version)
+	Davor Jadrijevic MAD16 support (initial version)
+	Gregor Hoffleit	Mozart support (initial version)
+	Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
+	James Hightower Spotting a tiny but important bug in CS423x support.
+	Denis Sablic	OPTi 82C924 specific enhancements (non PnP mode)
+	Tim MacKenzie	Full duplex support for OPTi 82C930.
+	
+	Please look at lowlevel/README for more contributors.
+
+There are probably many other names missing. If you have sent me some
+patches and your name is not in the above list, please inform me.
+
+Sending your contributions or patches
+-------------------------------------
+
+First of all it's highly recommended to contact me before sending anything
+or before even starting to do any work. Tell me what you suggest to be
+changed or what you have planned to do. Also ensure you are using the
+very latest (development) version of OSS/Free since the change may already be
+implemented there. In general it's a major waste of time to try to improve a
+several months old version. Information about the latest version can be found
+from http://www.opensound.com/ossfree. In general there is no point in
+sending me patches relative to production kernels.
+
+Sponsors etc.
+-------------
+
+The following companies have greatly helped development of this driver 
+in form of a free copy of their product:
+
+Novell, Inc.		UnixWare personal edition + SDK
+The Santa Cruz Operation, Inc. 	A SCO OpenServer + SDK
+Ensoniq Corp,		a SoundScape card and extensive amount of assistance
+MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK
+Acer, Inc.		a pair of AcerMagic S23 cards.
+
+In addition the following companies have provided me sufficient amount
+of technical information at least some of their products (free or $$$):
+
+Advanced Gravis Computer Technology Ltd.
+Media Vision Inc.
+Analog Devices Inc.
+Logitech Inc.
+Aztech Labs Inc.
+Crystal Semiconductor Corporation,
+Integrated Circuit Systems Inc.
+OAK Technology
+OPTi
+Turtle Beach
+miro
+Ad Lib Inc. ($$)
+Music Quest Inc. ($$)
+Creative Labs ($$$)
+
+If you have some problems
+=========================
+
+Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
+Also look at the home page (http://www.opensound.com/ossfree). It may
+contain info about some recent bug fixes.
+
+It's likely that you have some problems when trying to use the sound driver
+first time. Sound cards don't have standard configuration so there are no
+good default configuration to use. Please try to use same I/O, DMA and IRQ
+values for the sound card than with DOS.
+
+If you get an error message when trying to use the driver, please look
+at /var/adm/messages for more verbose error message.
+
+
+The following errors are likely with /dev/dsp and /dev/audio.
+
+	- "No such device or address".
+	This error indicates that there are no suitable hardware for the
+	device file or the sound driver has been compiled without support for
+	this particular device. For example /dev/audio and /dev/dsp will not
+	work if "digitized voice support" was not enabled during "make config".
+	
+	- "Device or resource busy". Probably the IRQ (or DMA) channel 
+	required by the sound card is in use by some other device/driver.
+
+	- "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
+	Look at the kernel messages in /var/adm/notice for more info.
+
+	- "Invalid argument". The application is calling ioctl()
+	with impossible parameters. Check that the application is
+	for sound driver version 2.X or later.
+
+Linux installation
+==================
+
+IMPORTANT!	Read this if you are installing a separately
+		distributed version of this driver.
+
+		Check that your kernel version works with this
+		release of the driver (see Readme). Also verify
+		that your current kernel version doesn't have more
+		recent sound driver version than this one. IT'S HIGHLY
+		RECOMMENDED THAT YOU USE THE SOUND DRIVER VERSION THAT
+		IS DISTRIBUTED WITH KERNEL SOURCES.
+
+- When installing separately distributed sound driver you should first
+  read the above notice. Then try to find proper directory where and how
+  to install the driver sources. You should not try to install a separately
+  distributed driver version if you are not able to find the proper way
+  yourself (in this case use the version that is distributed with kernel
+  sources). Remove old version of linux/drivers/sound directory before
+  installing new files.
+
+- To build the device files you need to run the enclosed shell script 
+  (see below). You need to do this only when installing sound driver
+  first time or when upgrading to much recent version than the earlier
+  one.
+
+- Configure and compile Linux as normally (remember to include the
+  sound support during "make config"). Please refer to kernel documentation
+  for instructions about configuring and compiling kernel. File Readme.cards
+  contains card specific instructions for configuring this driver for
+  use with various sound cards.
+
+Boot time configuration (using lilo and insmod) 
+-----------------------------------------------
+
+This information has been removed. Too many users didn't believe
+that it's really not necessary to use this method. Please look at
+Readme of sound driver version 3.0.1 if you still want to use this method.
+
+Problems
+--------
+
+Common error messages:
+
+- /dev/???????: No such file or directory.
+Run the script at the end of this file.
+
+- /dev/???????: No such device.
+You are not running kernel which contains the sound driver. When using
+modularized sound driver this error means that the sound driver is not
+loaded.
+
+- /dev/????: No such device or address.
+Sound driver didn't detect suitable card when initializing. Please look at
+Readme.cards for info about configuring the driver with your card. Also
+check for possible boot (insmod) time error messages in /var/adm/messages.
+
+- Other messages or problems
+Please check http://www.opensound.com/ossfree for more info.
+
+Configuring version 3.8 (for Linux) with some common sound cards
+================================================================
+
+This document describes configuring sound cards with the freeware version of
+Open Sound Systems (OSS/Free). Information about the commercial version
+(OSS/Linux) and its configuration is available from 
+http://www.opensound.com/linux.html. Information presented here is
+not valid for OSS/Linux. 
+
+If you are unsure about how to configure OSS/Free
+you can download the free evaluation version of OSS/Linux from the above
+address. There is a chance that it can autodetect your sound card. In this case
+you can use the information included in soundon.log when configuring OSS/Free.
+
+
+IMPORTANT!	This document covers only cards that were "known" when
+		this driver version was released. Please look at
+		http://www.opensound.com/ossfree for info about
+		cards introduced recently.
+
+		When configuring the sound driver, you should carefully
+		check each sound configuration option (particularly
+		"Support for /dev/dsp and /dev/audio"). The default values
+		offered by these programs are not necessarily valid.
+
+
+THE BIGGEST MISTAKES YOU CAN MAKE
+=================================
+
+1. Assuming that the card is Sound Blaster compatible when it's not.
+--------------------------------------------------------------------
+
+The number one mistake is to assume that your card is compatible with
+Sound Blaster. Only the cards made by Creative Technology or which have
+one or more chips labeled by Creative are SB compatible. In addition there
+are few sound chipsets which are SB compatible in Linux such as ESS1688 or
+Jazz16. Note that SB compatibility in DOS/Windows does _NOT_ mean anything
+in Linux. 
+
+IF YOU REALLY ARE 150% SURE YOU HAVE A SOUND BLASTER YOU CAN SKIP THE REST OF
+THIS CHAPTER.
+
+For most other "supposed to be SB compatible" cards you have to use other
+than SB drivers (see below).  It is possible to get most sound cards to work
+in SB mode but in general it's a complete waste of time. There are several
+problems which you will encounter by using SB mode with cards that are not
+truly SB compatible:
+
+- The SB emulation is at most SB Pro (DSP version 3.x) which means that 
+you get only 8 bit audio (there is always an another ("native") mode which
+gives the 16 bit capability). The 8 bit only operation is the reason why
+many users claim that sound quality in Linux is much worse than in DOS.
+In addition some applications require 16 bit mode and they produce just
+noise with a 8 bit only device.
+- The card may work only in some cases but refuse to work most of the
+time. The SB compatible mode always requires special initialization which is 
+done by the DOS/Windows drivers. This kind of cards work in Linux after
+you have warm booted it after DOS but they don't work after cold boot
+(power on or reset).
+- You get the famous "DMA timed out" messages. Usually all SB clones have
+software selectable IRQ and DMA settings. If the (power on default) values
+currently used by the card don't match configuration of the driver you will
+get the above error message whenever you try to record or play. There are
+few other reasons to the DMA timeout message but using the SB mode seems
+to be the most common cause.
+
+2. Trying to use a PnP (Plug & Play) card just like an ordinary sound card
+--------------------------------------------------------------------------
+
+Plug & Play is a protocol defined by Intel and Microsoft. It lets operating
+systems to easily identify and reconfigure I/O ports, IRQs and DMAs of ISA
+cards. The problem with PnP cards is that the standard Linux doesn't currently
+(versions 2.1.x and earlier) don't support PnP. This means that you will have
+to use some special tricks (see later) to get a PnP card alive. Many PnP cards
+work after they have been initialized but this is not always the case.
+
+There are sometimes both PnP and non-PnP versions of the same sound card.
+The non-PnP version is the original model which usually has been discontinued
+more than an year ago. The PnP version has the same name but with "PnP"
+appended to it (sometimes not). This causes major confusion since the non-PnP
+model works with Linux but the PnP one doesn't.
+
+You should carefully check if "Plug & Play" or "PnP" is mentioned in the name
+of the card or in the documentation or package that came with the card. 
+Everything described in the rest of this document is not necessarily valid for
+PnP models of sound cards even you have managed to wake up the card properly.
+Many PnP cards are simply too different from their non-PnP ancestors which are
+covered by this document.
+
+
+Cards that are not (fully) supported by this driver
+===================================================
+
+See http://www.opensound.com/ossfree for information about sound cards 
+to be supported in future. 
+
+
+How to use sound without recompiling kernel and/or sound driver
+===============================================================
+
+There is a commercial sound driver which comes in precompiled form and doesn't
+require recompiling of the kernel. See http://www.4Front-tech.com/oss.html for
+more info.
+
+
+Configuring PnP cards
+=====================
+
+New versions of most sound cards use the so-called ISA PnP protocol for
+soft configuring their I/O, IRQ, DMA and shared memory resources.
+Currently at least cards made by Creative Technology (SB32 and SB32AWE
+PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and
+Aztech (some Sound Galaxy models) use PnP technology. The CS4232/4236 audio
+chip by Crystal Semiconductor (Intel Atlantis, HP Pavilion and many other
+motherboards) is also based on PnP technology but there is a "native" driver
+available for it (see information about CS4232 later in this document).
+
+PnP sound cards (as well as most other PnP ISA cards) are not supported
+by this version of the driver . Proper
+support for them should be released during 97 once the kernel level
+PnP support is available.
+
+There is a method to get most of the PnP cards to work. The basic method
+is the following:
+
+1) Boot DOS so the card's DOS drivers have a chance to initialize it.
+2) _Cold_ boot to Linux by using "loadlin.exe".  Hitting ctrl-alt-del
+works with older machines but causes a hard reset of all cards on recent
+(Pentium) machines.
+3) If you have the sound driver in Linux configured properly, the card should
+work now. "Proper" means that I/O, IRQ and DMA settings are the same as in
+DOS. The hard part is to find which settings were used. See the documentation of
+your card for more info.
+
+Windows 95 could work as well as DOS but running loadlin may be difficult.
+Probably you should "shut down" your machine to MS-DOS mode before running it.
+
+Some machines have a BIOS utility for setting PnP resources. This is a good
+way to configure some cards. In this case you don't need to boot DOS/Win95
+before starting Linux.
+
+Another way to initialize PnP cards without DOS/Win95 is a Linux based
+PnP isolation tool. When writing this there is a pre alpha test version
+of such a tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The
+file is called isapnptools-*. Please note that this tool is just a temporary
+solution which may be incompatible with future kernel versions having proper
+support for PnP cards. There are bugs in setting DMA channels in earlier
+versions of isapnptools so at least version 1.6 is required with sound cards.
+
+Yet another way to use PnP cards is to use (commercial) OSS/Linux drivers.  See
+http://www.opensound.com/linux.html for more info. This is probably the way you
+should do it if you don't want to spend time recompiling the kernel and 
+required tools.
+
+
+Read this before trying to configure the driver
+===============================================
+
+There are currently many cards that work with this driver. Some of the cards
+have native support while others work since they emulate some other
+card (usually SB, MSS/WSS and/or MPU401). The following cards have native
+support in the driver. Detailed instructions for configuring these cards
+will be given later in this document.
+
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+	Pro Audio Spectrum 16
+	Pro Audio Studio 16
+	Logitech Sound Man 16
+	NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+	      and will not be supported by the driver.
+
+Media Vision Jazz16 based cards
+	Pro Sonic 16
+	Logitech SoundMan Wave
+	(Other Jazz based cards should work but I don't have any reports
+	about them).
+
+Sound Blasters
+	SB 1.0 to 2.0
+	SB Pro
+	SB 16
+	SB32/64/AWE
+		Configure SB32/64/AWE just like SB16. See lowlevel/README.awe
+		for information about using the wave table synth.
+	        NOTE! AWE63/Gold and 16/32/AWE "PnP" cards need to be activated
+		      using isapnptools before they work with OSS/Free.
+	SB16 compatible cards by other manufacturers than Creative.
+		You have been fooled since there are _no_ SB16 compatible
+		cards on the market (as of May 1997). It's likely that your card
+		is compatible just with SB Pro but there is also a non-SB-
+		compatible 16 bit mode. Usually it's MSS/WSS but it could also
+		be a proprietary one like MV Jazz16 or ESS ES688. OPTi
+		MAD16 chips are very common in so called "SB 16 bit cards"
+		(try with the MAD16 driver).
+
+	======================================================================
+	"Supposed to be SB compatible" cards.
+		Forget the SB compatibility and check for other alternatives
+		first. The only cards that work with the SB driver in
+		Linux have been made by Creative Technology (there is at least
+		one chip on the card with "CREATIVE" printed on it). The
+		only other SB compatible chips are ESS and Jazz16 chips
+		(maybe ALSxxx chips too but they probably don't work).
+		Most other "16 bit SB compatible" cards such as "OPTi/MAD16" or
+		"Crystal" are _NOT_ SB compatible in Linux.
+
+		Practically all sound cards have some kind of SB emulation mode
+		in addition to their native (16 bit) mode. In most cases this
+		(8 bit only) SB compatible mode doesn't work with Linux. If
+		you get it working it may cause problems with games and
+		applications which require 16 bit audio. Some 16 bit only
+		applications don't check if the card actually supports 16 bits.
+		They just dump 16 bit data to a 8 bit card which produces just
+		noise.
+
+		In most cases the 16 bit native mode is supported by Linux.
+		Use the SB mode with "clones" only if you don't find anything
+		better from the rest of this doc.
+	======================================================================
+
+Gravis Ultrasound (GUS)
+	GUS
+	GUS + the 16 bit option
+	GUS MAX
+	GUS ACE (No MIDI port and audio recording)
+	GUS PnP (with RAM)
+
+MPU-401	and compatibles
+	The driver works both with the full (intelligent mode) MPU-401
+	cards (such as MPU IPC-T and MQX-32M) and with the UART only
+	dumb MIDI ports. MPU-401 is currently the most common MIDI
+	interface. Most sound cards are compatible with it. However,
+	don't enable MPU401 mode blindly. Many cards with native support
+	in the driver have their own MPU401 driver. Enabling the standard one
+	will cause a conflict with these cards. So check if your card is
+	in the list of supported cards before enabling MPU401.
+
+Windows Sound System (MSS/WSS)
+	Even when Microsoft has discontinued their own Sound System card 
+	they managed to make it a standard. MSS compatible cards are based on 
+	a codec chip which is easily available from at least two manufacturers
+	(AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
+	Currently most sound cards are based on one of the MSS compatible codec
+	chips. The CS4231 is used in the high quality cards such as GUS MAX,
+	MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). 
+
+	Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
+	sign. Even if the card is not MSS compatible, it could be easy to write
+	support for it. Note also that most MSS compatible cards
+	require special boot time initialization which may not be present
+	in the driver. Also, some MSS compatible cards have native support.
+	Enabling the MSS support with these cards is likely to
+	cause a conflict. So check if your card is listed in this file before
+	enabling the MSS support.
+
+Yamaha FM synthesizers (OPL2, OPL3 (not OPL3-SA) and OPL4)
+	Most sound cards have a FM synthesizer chip. The OPL2 is a 2
+	operator chip used in the original AdLib card. Currently it's used
+	only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator 
+	FM chip which provides better sound quality and/or more available 
+	voices than the OPL2. The OPL4 is a new chip that has an OPL3 and
+	a wave table synthesizer packed onto the same chip. The driver supports
+	just the OPL3 mode directly. Most cards with an OPL4 (like
+	SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401
+	emulation. Writing a native OPL4 support is difficult
+	since Yamaha doesn't give information about their sample ROM chip.
+
+	Enable the generic OPL2/OPL3 FM synthesizer support if your
+	card has a FM chip made by Yamaha. Don't enable it if your card
+	has a software (TRS) based FM emulator.
+
+	----------------------------------------------------------------
+	NOTE! OPL3-SA is different chip than the ordinary OPL3. In addition
+	to the FM synth this chip has also digital audio (WSS) and
+	MIDI (MPU401) capabilities. Support for OPL3-SA is described below.
+	----------------------------------------------------------------
+
+Yamaha OPL3-SA1
+
+	Yamaha OPL3-SA1 (YMF701) is an audio controller chip used on some
+	(Intel) motherboards and on cheap sound cards. It should not be
+	confused with the original OPL3 chip (YMF278) which is entirely
+        different chip. OPL3-SA1 has support for MSS, MPU401 and SB Pro
+	(not used in OSS/Free) in addition to the OPL3 FM synth.
+
+	There are also chips called OPL3-SA2, OPL3-SA3, ..., OPL3SA-N. They
+	are PnP chips and will not work with the OPL3-SA1 driver. You should 
+	use the standard MSS, MPU401 and OPL3 options with these chips and to
+	activate the card using isapnptools.
+
+4Front Technologies SoftOSS
+
+	SoftOSS is a software based wave table emulation which works with
+	any 16 bit stereo sound card. Due to its nature a fast CPU is
+	required (P133 is minimum). Although SoftOSS does _not_ use MMX
+	instructions it has proven out that recent processors (which appear
+	to have MMX) perform significantly better with SoftOSS than earlier
+	ones. For example a P166MMX beats a PPro200. SoftOSS should not be used
+	on 486 or 386 machines.
+
+	The amount of CPU load caused by SoftOSS can be controlled by
+	selecting the CONFIG_SOFTOSS_RATE and CONFIG_SOFTOSS_VOICES
+	parameters properly (they will be prompted by make config). It's
+	recommended to set CONFIG_SOFTOSS_VOICES to 32. If you have a
+	P166MMX or faster (PPro200 is not faster) you can set
+	CONFIG_SOFTOSS_RATE to 44100 (kHz). However with slower systems it
+	recommended to use sampling rates around 22050 or even 16000 kHz.
+	Selecting too high values for these parameters may hang your
+	system when playing MIDI files with hight degree of polyphony
+	(number of concurrently playing notes). It's also possible to
+	decrease CONFIG_SOFTOSS_VOICES. This makes it possible to use
+	higher sampling rates. However using fewer voices decreases
+	playback quality more than decreasing the sampling rate.
+
+	SoftOSS keeps the samples loaded on the system's RAM so much RAM is
+	required. SoftOSS should never be used on machines with less than 16 MB
+	of RAM since this is potentially dangerous (you may accidentally run out
+	of memory which probably crashes the machine). 
+
+	SoftOSS implements the wave table API originally designed for GUS. For
+	this reason all applications designed for GUS should work (at least
+	after minor modifications). For example gmod/xgmod and playmidi -g are
+	known to work.
+
+	To work SoftOSS will require GUS compatible
+	patch files to be installed on the system (in /dos/ultrasnd/midi). You
+	can use the public domain MIDIA patchset available from several ftp
+	sites.
+
+        *********************************************************************
+	IMPORTANT NOTICE! The original patch set distributed with the Gravis 
+	Ultrasound card is not in public domain (even though it's available from
+	some FTP sites). You should contact Voice Crystal (www.voicecrystal.com)
+	if you like to use these patches with SoftOSS included in OSS/Free.
+        *********************************************************************
+
+PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC)
+	Analog Devices and Echo Speech have together defined a sound card
+	architecture based on the above chips. The DSP chip is used
+	for emulation of SB Pro, FM and General MIDI/MT32.
+
+	There are several cards based on this architecture. The most known
+	ones are Orchid SW32 and Cardinal DSP16. 
+
+	The driver supports downloading DSP algorithms to these cards.
+
+	NOTE! You will have to use the "old" config script when configuring
+	PSS cards.
+
+MediaTrix AudioTrix Pro
+	The ATP card is built around a CS4231 codec and an OPL4 synthesizer
+	chips. The OPL4 mode is supported by a microcontroller running a
+	General MIDI emulator. There is also a SB 1.5 compatible playback mode.
+
+Ensoniq SoundScape and compatibles
+	Ensoniq has designed a sound card architecture based on the
+	OTTO synthesizer chip used in their professional MIDI synthesizers.
+	Several companies (including Ensoniq, Reveal and Spea) are selling
+	cards based on this architecture.
+
+	NOTE! The SoundScape PnP is not supported by OSS/Free. Ensoniq VIVO and
+	VIVO90 cards are not compatible with Soundscapes so the Soundscape
+        driver will not work with them. You may want to use OSS/Linux with these
+        cards.
+
+OPTi MAD16 and Mozart based cards
+	The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929),
+	OPTi 82C924/82C925 (in _non_ PnP mode) and OPTi 82C930 interface
+	chips are used in many different sound cards, including some
+	cards by Reveal miro and Turtle Beach (Tropez). The purpose of these
+	chips is to connect other audio components to the PC bus. The
+	interface chip performs address decoding for the other chips.
+	NOTE! Tropez Plus is not MAD16 but CS4232 based.
+	NOTE! MAD16 PnP cards (82C924, 82C925, 82C931) are not MAD16 compatible
+	in the PnP mode. You will have to use them in MSS mode after having
+	initialized them using isapnptools or DOS. 82C931 probably requires
+	initialization using DOS/Windows (running isapnptools is not enough).
+	It's possible to use 82C931 with OSS/Free by jumpering it to non-PnP
+	mode (provided that the card has a jumper for this). In non-PnP mode
+	82C931 is compatible with 82C930 and should work with the MAD16 driver
+	(without need to use isapnptools or DOS to initialize it). All OPTi
+	chips are supported by OSS/Linux (both in PnP and non-PnP modes).
+
+Audio Excel DSP16 
+	Support for this card was written by Riccardo Faccetti
+	(riccardo@cdc8g5.cdc.polimi.it). The AEDSP16 driver included in
+	the lowlevel/ directory. To use it you should enable the
+	"Additional low level drivers" option.
+
+Crystal CS4232 and CS4236 based cards such as AcerMagic S23, TB Tropez _Plus_ and 
+	many PC motherboards (Compaq, HP, Intel, ...)
+	CS4232 is a PnP multimedia chip which contains a CS3231A codec,
+	SB and MPU401 emulations. There is support for OPL3 too.
+	Unfortunately the MPU401 mode doesn't work (I don't know how to
+	initialize it). CS4236 is an enhanced (compatible) version of CS4232.
+	NOTE! Don't ever try to use isapnptools with CS4232 since this will just
+	freeze your machine (due to chip bugs). If you have problems in getting
+	CS4232 working you could try initializing it with DOS (CS4232C.EXE) and
+	then booting Linux using loadlin. CS4232C.EXE loads a secret firmware
+	patch which is not documented by Crystal.
+
+Turtle Beach Maui and Tropez "classic"
+	This driver version supports sample, patch and program loading commands
+	described in the Maui/Tropez User's manual. 
+	There is now full initialization support too. The audio side of
+	the Tropez is based on the MAD16 chip (see above).
+	NOTE! Tropez Plus is different card than Tropez "classic" and will not
+	work fully in Linux. You can get audio features working by configuring
+	the card as a CS4232 based card (above).
+
+
+Jumpers and software configuration
+==================================
+
+Some of the earliest sound cards were jumper configurable. You have to
+configure the driver use I/O, IRQ and DMA settings
+that match the jumpers. Just few 8 bit cards are fully jumper 
+configurable (SB 1.x/2.x, SB Pro and clones).
+Some cards made by Aztech have an EEPROM which contains the 
+config info. These cards behave much like hardware jumpered cards.
+
+Most cards have jumper for the base I/O address but other parameters
+are software configurable. Sometimes there are few other jumpers too.
+
+Latest cards are fully software configurable or they are PnP ISA
+compatible. There are no jumpers on the board.
+
+The driver handles software configurable cards automatically. Just configure
+the driver to use I/O, IRQ and DMA settings which are known to work.
+You could usually use the same values than with DOS and/or Windows.
+Using different settings is possible but not recommended since it may cause
+some trouble (for example when warm booting from an OS to another or
+when installing new hardware to the machine).
+
+Sound driver sets the soft configurable parameters of the card automatically
+during boot. Usually you don't need to run any extra initialization
+programs when booting Linux but there are some exceptions. See the
+card-specific instructions below for more info.
+
+The drawback of software configuration is that the driver needs to know
+how the card must be initialized. It cannot initialize unknown cards
+even if they are otherwise compatible with some other cards (like SB,
+MPU401 or Windows Sound System).
+
+
+What if your card was not listed above?
+=======================================
+
+The first thing to do is to look at the major IC chips on the card.
+Many of the latest sound cards are based on some standard chips. If you
+are lucky, all of them could be supported by the driver. The most common ones
+are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures
+listed above. Also look at the end of this file for list of unsupported
+cards and the ones which could be supported later.
+
+The last resort is to send _exact_ name and model information of the card
+to me together with a list of the major IC chips (manufactured, model) to 
+me. I could then try to check if your card looks like something familiar.
+
+There are many more cards in the world than listed above. The first thing to
+do with these cards is to check if they emulate some other card or interface
+such as SB, MSS and/or MPU401. In this case there is a chance to get the
+card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del
+and boot Linux without hard resetting the machine). In this method the
+DOS based driver initializes the hardware to use known I/O, IRQ and DMA
+settings. If sound driver is configured to use the same settings, everything
+should work OK.
+
+
+Configuring sound driver (with Linux)
+=====================================
+
+The sound driver is currently distributed as part of the Linux kernel. The 
+files are in /usr/src/linux/drivers/sound/. 
+
+****************************************************************************
+*	ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH	   *
+*	THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST  *
+*	VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE	   *
+*	BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE   *
+*	KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER 	   *
+*	INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME	   *
+*	INCOMPATIBILITY PROBLEMS.					   *
+*									   *
+*	IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, *
+*	BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE  *
+*	INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER	   *
+*	DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR	   *
+*	COMPILED.							   *
+****************************************************************************
+
+To configure the driver, run "make config" in the kernel source directory
+(/usr/src/linux). Answer "y" or "m" to the question about Sound card support
+(after the questions about mouse, CD-ROM, ftape, etc. support).  Questions
+about options for sound will then be asked.
+
+After configuring the kernel and sound driver, run "make dep" and compile
+the kernel following instructions in the kernel README.
+
+The sound driver configuration dialog
+-------------------------------------
+
+Sound configuration starts by making some yes/no questions. Be careful
+when answering to these questions since answering y to a question may
+prevent some later ones from being asked. For example don't answer y to
+the first question (PAS16) if you don't really have a PAS16. Don't enable
+more cards than you really need since they just consume memory. Also
+some drivers (like MPU401) may conflict with your SCSI controller and
+prevent kernel from booting. If you card was in the list of supported
+cards (above), please look at the card specific config instructions
+(later in this file) before starting to configure. Some cards must be
+configured in way which is not obvious.
+
+So here is the beginning of the config dialog. Answer 'y' or 'n' to these
+questions. The default answer is shown so that (y/n) means 'y' by default and
+(n/y) means 'n'. To use the default value, just hit ENTER. But be careful
+since using the default _doesn't_ guarantee anything.
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions depending on the earlier choices. It may also
+select some options automatically as well.
+
+  "ProAudioSpectrum 16 support",
+	- Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+	  Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that
+	  you read the above list correctly). Don't answer 'y' if you
+	  have some other card made by Media Vision or Logitech since they
+	  are not PAS16 compatible.
+	  NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+	  if you want to use the SB emulation of PAS16. It's also possible to
+   	  the emulation if you want to use a true SB card together with PAS16
+	  (there is another question about this that is asked later).
+  "Sound Blaster support",
+	- Answer 'y' if you have an original SB card made by Creative Labs
+	  or a full 100% hardware compatible clone (like Thunderboard or
+	  SM Games). If your card was in the list of supported cards (above),
+	  please look at the card specific instructions later in this file
+	  before answering this question. For an unknown card you may answer 
+	  'y' if the card claims to be SB compatible.
+	 Enable this option also with PAS16 (changed since v3.5-beta9).
+
+	 Don't enable SB if you have a MAD16 or Mozart compatible card.
+
+  "Generic OPL2/OPL3 FM synthesizer support",
+	- Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+	  Answering 'y' is usually a safe and recommended choice. However some
+	  cards may have software (TSR) FM emulation. Enabling FM support
+	  with these cards may cause trouble. However I don't currently know
+	  such cards.
+  "Gravis Ultrasound support",
+	- Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't
+	  have GUS since the GUS driver consumes much memory.
+	  Currently I don't have experiences with the GUS ACE so I don't
+	  know what to answer with it.
+  "MPU-401 support (NOT for SB16)",
+	- Be careful with this question. The MPU401 interface is supported
+	  by almost any sound card today. However some natively supported cards
+	  have their own driver for MPU401. Enabling the MPU401 option with
+	  these cards will cause a conflict. Also enabling MPU401 on a system
+	  that doesn't really have a MPU401 could cause some trouble. If your
+	  card was in the list of supported cards (above), please look at
+	  the card specific instructions later in this file.
+
+	  In MOST cases this MPU401 driver should only be used with "true"
+	  MIDI-only MPU401 professional cards. In most other cases there
+	  is another way to get the MPU401 compatible interface of a
+	  sound card to work.
+	  Support for the MPU401 compatible MIDI port of SB16, ESS1688
+	  and MV Jazz16 cards is included in the SB driver. Use it instead
+	  of this separate MPU401 driver with these cards. As well 
+	  Soundscape, PSS and Maui drivers include their own MPU401
+	  options.
+
+	  It's safe to answer 'y' if you have a true MPU401 MIDI interface
+	  card. 
+  "6850 UART Midi support",
+	- It's safe to answer 'n' to this question in all cases. The 6850
+	  UART interface is so rarely used.
+  "PSS (ECHO-ADI2111) support",
+	- Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some
+	  other card based on the PSS chipset (AD1848 codec + ADSP-2115
+	  DSP chip + Echo ESC614 ASIC CHIP).
+  "16 bit sampling option of GUS (_NOT_ GUS MAX)",
+	- Answer 'y' if you have installed the 16 bit sampling daughtercard
+	  to your GUS. Answer 'n' if you have GUS MAX. Enabling this option
+	  disables GUS MAX support.
+  "GUS MAX support",
+	- Answer 'y' only if you have a GUS MAX.
+  "Microsoft Sound System support",
+	- Again think carefully before answering 'y' to this question. It's
+	  safe to answer 'y' in case you have the original Windows Sound 
+	  System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).
+	  Also you may answer 'y' in case your card was not listed earlier
+	  in this file. For cards having native support in the driver, consult
+	  the card specific instructions later in this file. Some drivers
+	  have their own MSS support and enabling this option will cause a
+	  conflict. 
+	  Note! The MSS driver permits configuring two DMA channels. This is a
+	  "nonstandard" feature and works only with very few cards (if any).
+	  In most cases the second DMA channel should be disabled or set to
+	  the same channel than the first one. Trying to configure two separate
+	  channels with cards that don't support this feature will prevent
+	  audio (at least recording) from working.
+  "Ensoniq Soundscape support",
+	- Answer 'y' if you have a sound card based on the Ensoniq SoundScape
+	  chipset. Such cards are being manufactured at least by Ensoniq,
+	  Spea and Reveal (note that Reveal makes other cards also).  The oldest
+	  cards made by Spea don't work properly with Linux. 
+	  Soundscape PnP as well as Ensoniq VIVO work only with the commercial
+	  OSS/Linux version.
+  "MediaTrix AudioTrix Pro support",
+	- Answer 'y' if you have the AudioTrix Pro.
+  "Support for MAD16 and/or Mozart based cards",
+	- Answer y if your card has a Mozart (OAK OTI-601) or MAD16
+	  (OPTi 82C928, 82C929, 82C924/82C925 or 82C930) audio interface chip. 
+	  These chips are
+	  currently quite common so it's possible that many no-name cards
+	  have one of them. In addition the MAD16 chip is used in some
+	  cards made by known manufacturers such as Turtle Beach (Tropez),
+	  Reveal (some models) and Diamond (some recent models).
+	  Note OPTi 82C924 and 82C925 are MAD16 compatible only in non PnP
+	  mode (jumper selectable on many cards).
+  "Support for TB Maui"
+	- This enables TB Maui specific initialization. Works with TB Maui
+	and TB Tropez (may not work with Tropez Plus).
+
+
+Then the configuration program asks some y/n questions about the higher
+level services. It's recommended to answer 'y' to each of these questions.
+Answer 'n' only if you know you will not need the option.
+
+  "MIDI interface support",
+	- Answering 'n' disables /dev/midi## devices and access to any
+	  MIDI ports using /dev/sequencer and /dev/music. This option
+	  also affects any MPU401 and/or General MIDI compatible devices.
+  "FM synthesizer (YM3812/OPL-3) support",
+	- Answer 'y' here.
+  "/dev/sequencer support",
+	- Answering 'n' disables /dev/sequencer and /dev/music.
+
+Entering the I/O, IRQ and DMA config parameters
+-----------------------------------------------
+
+After the above questions the configuration program prompts for the
+card specific configuration information. Usually just a set of
+I/O address, IRQ and DMA numbers are asked. With some cards the program
+asks for some files to be used during initialization of the card. For example
+many cards have a DSP chip or microprocessor which must be initialized by
+downloading a program (microcode) file to the card.
+
+Instructions for answering these questions are given in the next section.
+
+
+Card specific information
+=========================
+
+This section gives additional instructions about configuring some cards.
+Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using
+the same settings with DOS/Windows and Linux is recommended. Using
+different values could cause some problems when switching between
+different operating systems.
+
+Sound Blasters (the original ones by Creative)
+---------------------------------------------
+
+NOTE! Check if you have a PnP Sound Blaster (cards sold after summer 1995
+      are almost certainly PnP ones). With PnP cards you should use isapnptools
+      to activate them (see above).
+
+It's possible to configure these cards to use different I/O, IRQ and
+DMA settings. Since the possible/default settings have changed between various
+models, you have to consult manual of your card for the proper ones. It's
+a good idea to use the same values than with DOS/Windows. With SB and SB Pro
+it's the only choice. SB16 has software selectable IRQ and DMA channels but
+using different values with DOS and Linux is likely to cause troubles. The
+DOS driver is not able to reset the card properly after warm boot from Linux
+if Linux has used different IRQ or DMA values.
+
+The original (steam) Sound Blaster (versions 1.x and 2.x) use always
+DMA1. There is no way to change it.
+
+The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for
+8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory
+it's possible to use just one (8 bit) DMA channel by answering the 8 bit
+one when the configuration program asks for the 16 bit one. This may work
+in some systems but is likely to cause terrible noise on some other systems.
+
+It's possible to use two SB16/32/64 at the same time. To do this you should
+first configure OSS/Free for one card. Then edit local.h manually and define
+SB2_BASE, SB2_IRQ, SB2_DMA and SB2_DMA2 for the second one. You can't get
+the OPL3, MIDI and EMU8000 devices of the second card to work. If you are
+going to use two PnP Sound Blasters, ensure that they are of different model
+and have different PnP IDs. There is no way to get two cards with the same
+card ID and serial number to work. The easiest way to check this is trying 
+if isapnptools can see both cards or just one.
+
+NOTE!	Don't enable the SM Games option (asked by the configuration program)
+	if you are not 101% sure that your card is a Logitech Soundman Games
+	(not a SM Wave or SM16).
+
+SB Clones
+---------
+
+First of all: There are no SB16 clones. There are SB Pro clones with a
+16 bit mode which is not SB16 compatible. The most likely alternative is that
+the 16 bit mode means MSS/WSS.
+
+There are just a few fully 100% hardware SB or SB Pro compatible cards.
+I know just Thunderboard and SM Games. Other cards require some kind of
+hardware initialization before they become SB compatible. Check if your card
+was listed in the beginning of this file. In this case you should follow
+instructions for your card later in this file.
+
+For other not fully SB clones you may try initialization using DOS in
+the following way:
+
+	- Boot DOS so that the card specific driver gets run.
+	- Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't
+	  switch off power or press the reset button.
+	- If you use the same I/O, IRQ and DMA settings in Linux, the
+	  card should work.
+
+If your card is both SB and MSS compatible, I recommend using the MSS mode.
+Most cards of this kind are not able to work in the SB and the MSS mode 
+simultaneously. Using the MSS mode provides 16 bit recording and playback.
+
+ProAudioSpectrum 16 and compatibles
+-----------------------------------
+
+PAS16 has a SB emulation chip which can be used together with the native
+(16 bit) mode of the card. To enable this emulation you should configure 
+the driver to have SB support too (this has been changed since version
+3.5-beta9 of this driver).
+
+With current driver versions it's also possible to use PAS16 together with 
+another SB compatible card. In this case you should configure SB support
+for the other card and to disable the SB emulation of PAS16 (there is a
+separate questions about this).
+
+With PAS16 you can use two audio device files at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+Gravis Ultrasound
+-----------------
+
+There are many different revisions of the Ultrasound card (GUS). The
+earliest ones (pre 3.7) don't have a hardware mixer. With these cards
+the driver uses a software emulation for synth and pcm playbacks. It's
+also possible to switch some of the inputs (line in, mic) off by setting
+mixer volume of the channel level below 10%. For recording you have
+to select the channel as a recording source and to use volume above 10%.
+
+GUS 3.7 has a hardware mixer.
+
+GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which 
+also contains a mixer.
+
+Configuring GUS is simple. Just enable the GUS support and GUS MAX or
+the 16 bit daughtercard if you have them. Note that enabling the daughter
+card disables GUS MAX driver.
+
+NOTE for owners of the 16 bit daughtercard: By default the daughtercard
+uses /dev/dsp (and /dev/audio). Command "ln -sf /dev/dsp1 /dev/dsp"
+selects the daughter card as the default device.
+
+With just the standard GUS enabled the configuration program prompts
+for the I/O, IRQ and DMA numbers for the card. Use the same values than
+with DOS.
+
+With the daughter card option enabled you will be prompted for the I/O,
+IRQ and DMA numbers for the daughter card. You have to use different I/O
+and DMA values than for the standard GUS. The daughter card permits
+simultaneous recording and playback. Use /dev/dsp (the daughtercard) for
+recording and /dev/dsp1 (GUS GF1) for playback.
+
+GUS MAX uses the same I/O address and IRQ settings than the original GUS
+(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used.
+Using two DMA channels permits simultaneous playback using two devices
+(dev/dsp0 and /dev/dsp1). The second DMA channel is required for
+full duplex audio.
+To enable the second DMA channels, give a valid DMA channel when the config
+program asks for the GUS MAX DMA (entering -1 disables the second DMA).
+Using 16 bit DMA channels (5,6 or 7) is recommended.
+
+If you have problems in recording with GUS MAX, you could try to use
+just one 8 bit DMA channel. Recording will not work with one DMA
+channel if it's a 16 bit one.
+
+Microphone input of GUS MAX is connected to mixer in little bit nonstandard
+way. There is actually two microphone volume controls. Normal "mic" controls
+only recording level. Mixer control "speaker" is used to control volume of
+microphone signal connected directly to line/speaker out. So just decrease
+volume of "speaker" if you have problems with microphone feedback.
+
+GUS ACE works too but any attempt to record or to use the MIDI port
+will fail.
+
+GUS PnP (with RAM) is partially supported but it needs to be initialized using
+DOS or isapnptools before starting the driver.
+
+MPU401 and Windows Sound System
+-------------------------------
+
+Again. Don't enable these options in case your card is listed
+somewhere else in this file.
+
+Configuring these cards is obvious (or it should be). With MSS
+you should probably enable the OPL3 synth also since
+most MSS compatible cards have it. However check that this is true
+before enabling OPL3.
+
+Sound driver supports more than one MPU401 compatible cards at the same time
+but the config program asks config info for just the first of them.
+Adding the second or third MPU interfaces must be done manually by
+editing sound/local.h (after running the config program). Add defines for
+MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file.
+
+CAUTION!
+
+The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which
+is also the default of the MPU401 driver. Don't configure the sound driver to
+use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot
+if you make this mistake.
+
+PSS
+---
+
+Even the PSS cards are compatible with SB, MSS and MPU401, you must not
+enable these options when configuring the driver. The configuration
+program handles these options itself. (You may use the SB, MPU and MSS options
+together with PSS if you have another card on the system).
+
+The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled 
+since it doesn't work concurrently with MSS. The driver loads also a
+DSP algorithm which is used to for the general MIDI emulation. The
+algorithm file (.ld) is read by the config program and written to a
+file included when the pss.c is compiled. For this reason the config
+program asks if you want to download the file. Use the genmidi.ld file
+distributed with the DOS/Windows drivers of the card (don't use the mt32.ld).
+With some cards the file is called 'synth.ld'. You must have access to
+the file when configuring the driver. The easiest way is to mount the DOS
+partition containing the file with Linux. 
+
+It's possible to load your own DSP algorithms and run them with the card.
+Look at the directory pss_test of snd-util-3.0.tar.gz for more info.
+
+AudioTrix Pro
+-------------
+
+You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition
+to the native AudioTrix driver. Don't enable MSS or MPU drivers.
+
+Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
+DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
+attempt to use the same IRQ or DMA channels twice.
+
+The SB mode of ATP is implemented so the ATP driver just enables SB
+in the proper address. The SB driver handles the rest. You have to configure
+both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
+settings.
+
+Also the ATP has a microcontroller for the General MIDI emulation (OPL4).
+For this reason the driver asks for the name of a file containing the
+microcode (TRXPRO.HEX). This file is usually located in the directory
+where the DOS drivers were installed. You must have access to this file
+when configuring the driver. 
+
+If you have the effects daughtercard, it must be initialized by running
+the setfx program of snd-util-3.0.tar.gz package. This step is not required
+when using the (future) binary distribution version of the driver.
+
+Ensoniq SoundScape
+------------------
+
+NOTE!	The new PnP SoundScape is not supported yet. Soundscape compatible
+	cards made by Reveal don't work with Linux. They use older revision
+	of the Soundscape chipset which is not fully compatible with
+	newer cards made by Ensoniq.
+
+The SoundScape driver handles initialization of MSS and MPU supports
+itself so you don't need to enable other drivers than SoundScape
+(enable also the /dev/dsp, /dev/sequencer and MIDI supports).
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!!!!!                                                                   !!!!
+!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio 	!!!!
+!!!!!       device files (/dev/dsp0 and /dev/dsp1). The first one WAS   !!!!
+!!!!!	    used only for card initialization and the second for audio  !!!!
+!!!!!	    purposes. It WAS required to change /dev/dsp (a symlink) to !!!!
+!!!!!	    point to /dev/dsp1.						!!!!
+!!!!!                                                                   !!!!
+!!!!!	    This is not required with OSS versions 3.5-beta6 and later	!!!!
+!!!!!	    since there is now just one audio device file. Please 	!!!!
+!!!!!	    change /dev/dsp to point back to /dev/dsp0 if you are	!!!!
+!!!!!	    upgrading from an earlier driver version using		!!!!
+!!!!!	    (cd /dev;rm dsp;ln -s dsp0 dsp).				!!!!
+!!!!!                                                                   !!!!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+The configuration program asks one DMA channel and two interrupts. One IRQ
+and one DMA is used by the MSS codec. The second IRQ is required for the
+MPU401 mode (you have to use different IRQs for both purposes).
+There were earlier two DMA channels for SoundScape but the current driver
+version requires just one.
+
+The SoundScape card has a Motorola microcontroller which must initialized
+_after_ boot (the driver doesn't initialize it during boot).
+The initialization is done by running the 'ssinit' program which is
+distributed in the snd-util-3.0.tar.gz package. You have to edit two
+defines in the ssinit.c and then compile the program. You may run ssinit 
+manually (after each boot) or add it to /etc/rc.d/rc.local.
+
+The ssinit program needs the microcode file that comes with the DOS/Windows
+driver of the card. You will need to use version 1.30.00 or later
+of the microcode file (sndscape.co0 or sndscape.co1 depending on
+your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR
+MACHINE. The only way to get the new microcode file is to download
+and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub.
+
+Then you have to select the proper microcode file to use: soundscape.co0
+is the right one for most cards and sndscape.co1 is for few (older) cards
+made by Reveal and/or Spea. The driver has capability to detect the card
+version during boot. Look at the boot log messages in /var/adm/messages
+and locate the sound driver initialization message for the SoundScape
+card. If the driver displays string <Ensoniq Soundscape (old)>, you have
+an old card and you will need to use sndscape.co1. For other cards use
+soundscape.co0. New Soundscape revisions such as Elite and PnP use
+code files with higher numbers (.co2, .co3, etc.).
+
+NOTE!	Ensoniq Soundscape VIVO is not compatible with other Soundscape cards.
+	Currently it's possible to use it in Linux only with OSS/Linux
+	drivers.
+
+Check /var/adm/messages after running ssinit. The driver prints
+the board version after downloading the microcode file. That version
+number must match the number in the name of the microcode file (extension).
+
+Running ssinit with a wrong version of the sndscape.co? file is not
+dangerous as long as you don't try to use a file called sndscape.cod.
+If you have initialized the card using a wrong microcode file (sounds
+are terrible), just modify ssinit.c to use another microcode file and try
+again. It's possible to use an earlier version of sndscape.co[01] but it
+may sound weird.
+
+MAD16 (Pro) and Mozart
+----------------------
+
+You need to enable just the MAD16 /Mozart support when configuring
+the driver. _Don't_ enable SB, MPU401 or MSS. However you will need the
+/dev/audio, /dev/sequencer and MIDI supports.
+
+Mozart and OPTi 82C928 (the original MAD16) chips don't support
+MPU401 mode so enter just 0 when the configuration program asks the
+MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401
+mode.
+
+TB Tropez is based on the 82C929 chip. It has two MIDI ports.
+The one connected to the MAD16 chip is the second one (there is a second
+MIDI connector/pins somewhere??). If you have not connected the second MIDI
+port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of
+Tropez is jumper configurable and not connected to the MAD16 chip (the
+Maui driver can be used with it).
+
+Some MAD16 based cards may cause feedback, whistle or terrible noise if the
+line3 mixer channel is turned too high. This happens at least with Shuttle
+Sound System. Current driver versions set volume of line3 low enough so
+this should not be a problem.
+
+If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer
+chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4
+to the file linux/drivers/sound/local.h (after running make config).
+
+MAD16 cards having a CS4231 codec support full duplex mode. This mode
+can be enabled by configuring the card to use two DMA channels. Possible
+DMA channel pairs are: 0&1, 1&0 and 3&0.
+
+NOTE! Cards having an OPTi 82C924/82C925 chip work with OSS/Free only in
+non-PnP mode (usually jumper selectable). The PnP mode is supported only
+by OSS/Linux.
+
+MV Jazz (ProSonic)
+------------------
+
+The Jazz16 driver is just a hack made to the SB Pro driver. However it works
+fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports
+when configuring the driver. The configuration program asks later if you
+want support for MV Jazz16 based cards (after asking SB base address). Answer
+'y' here and the driver asks the second (16 bit) DMA channel.
+
+The Jazz16 driver uses the MPU401 driver in a way which will cause
+problems if you have another MPU401 compatible card. In this case you must
+give address of the Jazz16 based MPU401 interface when the config
+program prompts for the MPU401 information. Then look at the MPU401
+specific section for instructions about configuring more than one MPU401 cards.
+
+Logitech Soundman Wave
+----------------------
+
+Read the above MV Jazz specific instructions first.
+
+The Logitech SoundMan Wave (don't confuse this with the SM16 or SM Games) is
+a MV Jazz based card which has an additional OPL4 based wave table
+synthesizer. The OPL4 chip is handled by an on board microcontroller
+which must be initialized during boot. The config program asks if
+you have a SM Wave immediately after asking the second DMA channel of jazz16.
+If you answer 'y', the config program will ask name of the file containing
+code to be loaded to the microcontroller. The file is usually called
+MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file
+may also be called as TSUNAMI.BIN or something else (older cards?).
+
+The OPL4 synth will be inaccessible without loading the microcontroller code.
+
+Also remember to enable SB MPU401 support if you want to use the OPL4 mode.
+(Don't enable the 'normal' MPU401 device as with some earlier driver
+versions (pre 3.5-alpha8)).
+
+NOTE!	Don't answer 'y' when the driver asks about SM Games support
+	(the next question after the MIDI0001.BIN name). However
+	answering 'y' doesn't cause damage your computer so don't panic. 
+
+Sound Galaxies
+--------------
+
+There are many different Sound Galaxy cards made by Aztech. The 8 bit
+ones are fully SB or SB Pro compatible and there should be no problems
+with them. 
+
+The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
+an EEPROM chip for storing the configuration data. There is a microcontroller
+which initializes the card to match the EEPROM settings when the machine
+is powered on. These cards actually behave just like they have jumpers
+for all of the settings. Configure driver for MSS, MPU, SB/SB Pro  and OPL3 
+supports with these cards. 
+
+There are some new Sound Galaxies in the market. I have no experience with
+them so read the card's manual carefully.
+
+ESS ES1688 and ES688 'AudioDrive' based cards
+---------------------------------------------
+
+Support for these two ESS chips is embedded in the SB driver.
+Configure these cards just like SB. Enable the 'SB MPU401 MIDI port'
+if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
+so you don't need to enable it (the driver uses normal SB MIDI automatically
+with ES688).
+
+NOTE! ESS cards are not compatible with MSS/WSS so don't worry if MSS support
+of OSS doesn't work with it.
+
+There are some ES1688/688 based sound cards and (particularly) motherboards
+which use software configurable I/O port relocation feature of the chip.
+This ESS proprietary feature is supported only by OSS/Linux.
+
+There are ES1688 based cards which use different interrupt pin assignment than
+recommended by ESS (5, 7, 9/2 and 10). In this case all IRQs don't work.
+At least a card called (Pearl?) Hypersound 16 supports IRQ 15 but it doesn't
+work.
+
+ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688
+probably works with OSS/Free after initialization using isapnptools.
+
+Reveal cards
+------------
+
+There are several different cards made/marketed by Reveal. Some of them
+are compatible with SoundScape and some use the MAD16 chip. You may have
+to look at the card and try to identify its origin.
+
+Diamond
+-------
+
+The oldest (Sierra Aria based) sound cards made by Diamond are not supported
+(they may work if the card is initialized using DOS). The recent (LX?)
+models are based on the MAD16 chip which is supported by the driver.
+
+Audio Excel DSP16
+-----------------
+
+Support for this card is currently not functional. A new driver for it
+should be available later this year.
+
+PCMCIA cards
+------------
+
+Sorry, can't help. Some cards may work and some don't.
+
+TI TM4000M notebooks
+--------------------
+
+These computers have a built in sound support based on the Jazz chipset.
+Look at the instructions for MV Jazz (above). It's also important to note
+that there is something wrong with the mouse port and sound at least on
+some TM models. Don't enable the "C&T 82C710 mouse port support" when
+configuring Linux. Having it enabled is likely to cause mysterious problems
+and kernel failures when sound is used.
+
+miroSOUND
+---------
+
+The miroSOUND PCM1-pro, PCM12 and PCM20 radio has been used
+successfully. These cards are based on the MAD16, OPL4, and CS4231A chips
+and everything said in the section about MAD16 cards applies here,
+too. The only major difference between the PCMxx and other MAD16 cards
+is that instead of the mixer in the CS4231 codec a separate mixer
+controlled by an on-board 80C32 microcontroller is used. Control of
+the mixer takes place via the ACI (miro's audio control interface)
+protocol that is implemented in a separate lowlevel driver. Make sure
+you compile this ACI driver together with the normal MAD16 support
+when you use a miroSOUND PCMxx card. The ACI mixer is controlled by
+/dev/mixer and the CS4231 mixer by /dev/mixer1 (depends on load
+time). Only in special cases you want to change something regularly on
+the CS4231 mixer.
+
+The miroSOUND PCM12 and PCM20 radio is capable of full duplex
+operation (simultaneous PCM replay and recording), which allows you to
+implement nice real-time signal processing audio effect software and
+network telephones. The ACI mixer has to be switched into the "solo"
+mode for duplex operation in order to avoid feedback caused by the
+mixer (input hears output signal). You can de-/activate this mode
+through toggleing the record button for the wave controller with an
+OSS-mixer.
+
+The PCM20 contains a radio tuner, which is also controlled by
+ACI. This radio tuner is supported by the ACI driver together with the
+miropcm20.o module. Also the 7-band equalizer is integrated
+(limited by the OSS-design). Developement has started and maybe
+finished for the RDS decoder on this card, too. You will be able to
+read RadioText, the Programme Service name, Programme TYpe and
+others. Even the v4l radio module benefits from it with a refined
+strength value. See aci.[ch] and miropcm20*.[ch] for more details.
+
+The following configuration parameters have worked fine for the PCM12
+in Markus Kuhn's system, many other configurations might work, too:
+CONFIG_MAD16_BASE=0x530, CONFIG_MAD16_IRQ=11, CONFIG_MAD16_DMA=3, 
+CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10,
+DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000.
+
+Bas van der Linden is using his PCM1-pro with a configuration that
+differs in: CONFIG_MAD16_IRQ=7, CONFIG_MAD16_DMA=1, CONFIG_MAD16_MPU_IRQ=9
+
+Compaq Deskpro XL
+-----------------
+
+The builtin sound hardware of Compaq Deskpro XL is now supported. 
+You need to configure the driver with MSS and OPL3 supports enabled.
+In addition you need to manually edit linux/drivers/sound/local.h and
+to add a line containing "#define DESKPROXL" if you used 
+make menuconfig/xconfig.
+
+Others?
+-------
+
+Since there are so many different sound cards, it's likely that I have 
+forgotten to mention many of them. Please inform me if you know yet another
+card which works with Linux, please inform me (or is anybody else
+willing to maintain a database of supported cards (just like in XF86)?).
+
+Cards not supported yet
+=======================
+
+Please check the version of sound driver you are using before 
+complaining that your card is not supported. It's possible you are 
+using a driver version which was released months before your card was
+introduced.
+
+First of all, there is an easy way to make most sound cards work with Linux.
+Just use the DOS based driver to initialize the card to a known state, then use
+loadlin.exe to boot Linux. If Linux is configured to use the same I/O, IRQ and
+DMA numbers as DOS, the card could work.
+(ctrl-alt-del can be used in place of loadlin.exe but it doesn't work with
+new motherboards). This method works also with all/most PnP sound cards.
+
+Don't get fooled with SB compatibility. Most cards are compatible with
+SB but that may require a TSR which is not possible with Linux. If
+the card is compatible with MSS, it's a better choice. Some cards
+don't work in the SB and MSS modes at the same time.
+
+Then there are cards which are no longer manufactured and/or which
+are relatively rarely used (such as the 8 bit ProAudioSpectrum
+models). It's extremely unlikely that such cards ever get supported.
+Adding support for a new card requires much work and increases time
+required in maintaining the driver (some changes need to be done
+to all low level drivers and be tested too, maybe with multiple
+operating systems). For this reason I have made a decision to not support
+obsolete cards. It's possible that someone else makes a separately 
+distributed driver (diffs) for the card. 
+
+Writing a driver for a new card is not possible if there are no 
+programming information available about the card. If you don't
+find your new card from this file, look from the home page 
+(http://www.opensound.com/ossfree). Then please contact
+manufacturer of the card and ask if they have (or are willing to)
+released technical details of the card. Do this before contacting me. I
+can only answer 'no' if there are no programming information available.
+
+I have made decision to not accept code based on reverse engineering
+to the driver. There are three main reasons: First I don't want to break
+relationships to sound card manufacturers. The second reason is that
+maintaining and supporting a driver without any specs will be a pain.
+The third reason is that companies have freedom to refuse selling their
+products to other than Windows users.
+
+Some companies don't give low level technical information about their
+products to public or at least their require signing a NDA. It's not
+possible to implement a freeware driver for them. However it's possible
+that support for such cards become available in the commercial version
+of this driver (see http://www.4Front-tech.com/oss.html for more info).
+
+There are some common audio chipsets that are not supported yet. For example
+Sierra Aria and IBM Mwave. It's possible that these architectures
+get some support in future but I can't make any promises. Just look
+at the home page (http://www.opensound.com/ossfree/new_cards.html)
+for latest info.
+
+Information about unsupported sound cards and chipsets is welcome as well
+as free copies of sound cards, SDKs and operating systems.
+
+If you have any corrections and/or comments, please contact me.
+
+Hannu Savolainen
+hannu@opensound.com
+
+Personal home page:	   http://www.compusonic.fi/~hannu
+home page of OSS/Free: http://www.opensound.com/ossfree
+
+home page of commercial OSS
+(Open Sound System) drivers: http://www.opensound.com/oss.html
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/README.awe linux-2.5.6/Documentation/sound/oss/README.awe
--- linux-2.5.6-pre3/Documentation/sound/oss/README.awe	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/README.awe	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,218 @@
+================================================================
+	AWE32 Sound Driver for Linux / FreeBSD
+		version 0.4.3; Nov. 1, 1998
+
+	Takashi Iwai <iwai@ww.uni-erlangen.de>
+================================================================
+
+* GENERAL NOTES
+
+This is a sound driver extension for SoundBlaster AWE32 and other
+compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
+the wave synth operations.  The driver is provided for Linux 1.2.x
+and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
+Alpha systems.
+
+This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
+and provided "as is".  The original source (awedrv-0.4.3.tar.gz) and
+binary packages are available on the following URL:
+	http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
+Note that since the author is apart from this web site, the update is
+not frequent now.
+
+
+* NOTE TO LINUX USERS
+
+To enable this driver on linux-2.[01].x kernels, you need turn on 
+"AWE32 synth" options in sound menu when configure your linux kernel
+and modules.  The precise installation procedure is described in the
+AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
+
+If you're using PnP cards, the card must be initialized before loading
+the sound driver.  There're several options to do this:
+    - Initialize the card via ISA PnP tools, and load the sound module.
+    - Initialize the card on DOS, and load linux by loadlin.exe
+    - Use PnP kernel driver (for Linux-2.x.x)
+The detailed instruction for the solution using isapnp tools is found
+in many documents like above.  A brief instruction is also included in
+the installation document of this package.
+For PnP driver project, please refer to the following URL:
+	http://www-jcr.lmh.ox.ac.uk/~pnp/
+
+
+* USING THE DRIVER
+
+The awedrv has several different playing modes to realize easy channel 
+allocation for MIDI songs.  To hear the exact sound quality, you need
+to obtain the extended sequencer program, drvmidi or playmidi-2.5.
+
+For playing MIDI files, you *MUST* load the soundfont file on the
+driver previously by sfxload utility.  Otherwise you'll here no sounds 
+at all!  All the utilities and driver source packages are found in the
+above URL.  The sfxload program is included in the package
+awesfx-0.4.3.tgz.  Binary packages are available there, too.  See the
+instruction in each package for installation.
+
+Loading a soundfont file is very simple.  Just execute the command
+
+	% sfxload synthgm.sbk
+
+Then, sfxload transfers the file "synthgm.sbk" to the driver.
+Both SF1 and SF2 formats are accepted.
+
+Now you can hear midi musics by a midi player.
+
+	% drvmidi foo.mid
+
+If you run MIDI player after MOD player, you need to load soundfont
+files again, since MOD player programs clear the previous loaded
+samples by their own data.
+
+If you have only 512kb on the sound card, I recommend to use dynamic
+sample loading via -L option of drvmidi.  2MB GM/GS soundfont file is
+available in most midi files.
+
+	% sfxload synthgm
+	% drvmidi -L 2mbgmgs foo.mid
+
+This makes a big difference (believe me)!  For more details, please
+refer to the FAQ list which is available on the URL above.
+
+The current chorus, reverb and equalizer status can be changed by
+aweset utility program (included in awesfx package).  Note that
+some awedrv-native programs (like drvmidi and xmp) will change the
+current settings by themselves.  The aweset program is effective
+only for other programs like playmidi.
+
+Enjoy.
+
+
+* COMPILE FLAGS
+
+Compile conditions are defined in awe_config.h.
+
+[Compatibility Conditions]
+The following flags are defined automatically when using installation
+shell script.
+
+- AWE_MODULE_SUPPORT
+    indicates your Linux kernel supports module for each sound card
+    (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
+    as distributed in the RH5.0 package).
+    This flag is automatically set when you're using 2.1.x kernels.
+    You can pass the base address and memory size via the following
+    module options,
+	io = base I/O port address (eg. 0x620)
+	memsize = DRAM size in kilobytes (eg. 512)
+    As default, AWE driver probes these values automatically.
+
+
+[Hardware Conditions]
+You DON'T have to define the following two values.
+Define them only when the driver couldn't detect the card properly.
+
+- AWE_DEFAULT_BASE_ADDR		(default: not defined)
+    specifies the base port address of your AWE32 card.
+    0 means to autodetect the address.
+
+- AWE_DEFAULT_MEM_SIZE		(default: not defined)
+    specifies the memory size of your AWE32 card in kilobytes.
+    -1 means to autodetect its size.
+    
+
+[Sample Table Size]
+From ver.0.4.0, sample tables are allocated dynamically (except
+Linux-1.2.x system), so you need NOT to touch these parameters.
+Linux-1.2.x users may need to increase these values to appropriate size 
+if the sound card is equipped with more DRAM.
+
+- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
+
+
+[Other Conditions]
+
+- AWE_ALWAYS_INIT_FM		(default: not defined)
+    indicates the AWE driver always initialize FM passthrough even
+    without DRAM on board.  Emu8000 chip has a restriction for playing
+    samples on DRAM that at least two channels must be occupied as
+    passthrough channels. 
+
+- AWE_DEBUG_ON			(default: defined)
+    turns on debugging messages if defined.
+
+- AWE_HAS_GUS_COMPATIBILITY	(default: defined)
+    Enables GUS compatibility mode if defined, reading GUS patches and 
+    GUS control commands.  Define this option to use GMOD or other
+    GUS module players.
+
+- CONFIG_AWE32_MIDIEMU		(default: defined)
+    Adds a MIDI emulation device by Emu8000 wavetable.  The emulation
+    device can be accessed as an external MIDI, and sends the MIDI
+    control codes directly.  XG and GS sysex/NRPN are accepted.
+    No MIDI input is supported.
+
+- CONFIG_AWE32_MIXER		(default: not defined)
+    Adds a mixer device for AWE32 bass/treble equalizer control.
+    You can access this device using /dev/mixer?? (usually mixer01).
+
+- AWE_USE_NEW_VOLUME_CALC	(default: defined)
+    Use the new method to calculate the volume change as compatible
+    with DOS/Win drivers.  This option can be toggled via aweset
+    program, or drvmidi player.
+
+- AWE_CHECK_VTARGET		(default: defined)
+    Check the current volume target value when searching for an
+    empty channel to allocate a new voice.  This is experimentally
+    implemented in this version.  (probably, this option doesn't
+    affect the sound quality severely...)
+
+- AWE_ALLOW_SAMPLE_SHARING	(default: defined)
+   Allow sample sharing for differently loaded patches.
+   This function is available only together with awesfx-0.4.3p3.
+   Note that this is still an experimental option.
+
+- DEF_FM_CHORUS_DEPTH		(default: 0x10)
+    The default strength to be sent to the chorus effect engine.
+    From 0 to 0xff.  Larger numbers may often cause weird sounds.
+
+- DEF_FM_REVERB_DEPTH		(default: 0x10)
+    The default strength to be sent to the reverb effect engine.
+    From 0 to 0xff.  Larger numbers may often cause weird sounds.
+
+
+* ACKNOWLEDGMENTS
+
+Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
+on programming of AWE32.  Much code is brought from his AWE32-native 
+MOD player, ALMP.
+The port of awedrv to FreeBSD is done by Randall Hopper
+(rhh@ct.picker.com).
+The new volume calculation routine was derived from Mark Weaver's
+ADIP compatible routines.
+I also thank linux-awe-ml members for their efforts
+to reboot their system many times :-)
+
+
+* TODO'S
+
+- Complete DOS/Win compatibility
+- DSP-like output
+
+
+* COPYRIGHT
+
+Copyright (C) 1996-1998 Takashi Iwai
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/README.modules linux-2.5.6/Documentation/sound/oss/README.modules
--- linux-2.5.6-pre3/Documentation/sound/oss/README.modules	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/README.modules	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,105 @@
+Building a modular sound driver
+================================
+
+  The following information is current as of linux-2.1.85. Check the other
+readme files, especially README.OSS, for information not specific to
+making sound modular.
+
+  First, configure your kernel. This is an idea of what you should be
+setting in the sound section:
+
+<M> Sound card support 
+
+<M> 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support 
+
+  I have SoundBlaster. Select your card from the list.
+
+<M> Generic OPL2/OPL3 FM synthesizer support 
+<M> FM synthesizer (YM3812/OPL-3) support 
+
+  If you don't set these, you will probably find you can play .wav files
+but not .midi. As the help for them says, set them unless you know your
+card does not use one of these chips for FM support.
+
+  Once you are configured, make zlilo, modules, modules_install; reboot.
+Note that it is no longer necessary or possible to configure sound in the
+drivers/sound dir. Now one simply configures and makes one's kernel and
+modules in the usual way.
+
+ Then, add to your /etc/modules.conf something like:
+
+alias char-major-14 sb
+post-install sb /sbin/modprobe "-k" "adlib_card"
+options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
+options adlib_card io=0x388     # FM synthesizer
+
+ Alternatively, if you have compiled in kernel level ISAPnP support:
+
+alias char-major-14 sb
+post-install sb /sbin/modprobe "-k" "adlib_card"
+options adlib_card io=0x388
+
+  The effect of this is that the sound driver and all necessary bits and
+pieces autoload on demand, assuming you use kerneld (a sound choice) and
+autoclean when not in use. Also, options for the device drivers are
+set. They will not work without them. Change as appropriate for your card.
+If you are not yet using the very cool kerneld, you will have to "modprobe
+-k sb" yourself to get things going. Eventually things may be fixed so
+that this kludgery is not necessary; for the time being, it seems to work
+well.
+
+  Replace 'sb' with the driver for your card, and give it the right
+options. To find the filename of the driver, look in
+/lib/modules/<kernel-version>/misc. Mine looks like:
+
+adlib_card.o # This is the generic OPLx driver
+opl3.o # The OPL3 driver
+sb.o # <<The SoundBlaster driver. Yours may differ.>>
+sound.o # The sound driver
+uart401.o # Used by sb, maybe other cards
+
+ Whichever card you have, try feeding it the options that would be the
+default if you were making the driver wired, not as modules. You can look
+at the init_module() code for the card to see what args are expected.
+
+ Note that at present there is no way to configure the io, irq and other
+parameters for the modular drivers as one does for the wired drivers.. One
+needs to pass the modules the necessary parameters as arguments, either
+with /etc/modules.conf or with command-line args to modprobe, e.g.
+
+modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330
+modprobe -k adlib_card io=0x388
+
+ recommend using /etc/modules.conf.
+
+Persistent DMA Buffers:
+
+The sound modules normally allocate DMA buffers during open() and
+deallocate them during close(). Linux can often have problems allocating
+DMA buffers for ISA cards on machines with more than 16MB RAM. This is
+because ISA DMA buffers must exist below the 16MB boundary and it is quite
+possible that we can't find a large enough free block in this region after
+the machine has been running for any amount of time. The way to avoid this
+problem is to allocate the DMA buffers during module load and deallocate
+them when the module is unloaded. For this to be effective we need to load
+the sound modules right after the kernel boots, either manually or by an
+init script, and keep them around until we shut down. This is a little
+wasteful of RAM, but it guarantees that sound always works.
+
+To make the sound driver use persistent DMA buffers we need to pass the
+sound.o module a "dmabuf=1" command-line argument. This is normally done
+in /etc/modules.conf like so:
+
+options sound		dmabuf=1
+
+If you have 16MB or less RAM or a PCI sound card, this is wasteful and
+unnecessary. It is possible that machine with 16MB or less RAM will find
+this option useful, but if your machine is so memory-starved that it
+cannot find a 64K block free, you will be wasting even more RAM by keeping
+the sound modules loaded and the DMA buffers allocated when they are not
+needed. The proper solution is to upgrade your RAM. But you do also have
+this improper solution as well. Use it wisely.
+
+  I'm afraid I know nothing about anything but my setup, being more of a
+text-mode guy anyway. If you have options for other cards or other helpful
+hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/README.ymfsb linux-2.5.6/Documentation/sound/oss/README.ymfsb
--- linux-2.5.6-pre3/Documentation/sound/oss/README.ymfsb	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/README.ymfsb	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,107 @@
+Legacy audio driver for YMF7xx PCI cards.
+
+
+FIRST OF ALL
+============
+
+  This code references YAMAHA's sample codes and data sheets.
+  I respect and thank for all people they made open the informations
+  about YMF7xx cards.
+
+  And this codes heavily based on Jeff Garzik <jgarzik@pobox.com>'s
+  old VIA 82Cxxx driver (via82cxxx.c). I also respect him.
+
+
+DISCLIMER
+=========
+
+ This driver is currently at early ALPHA stage. It may cause serious
+ damage to your computer when used.
+ PLEASE USE IT AT YOUR OWN RISK.
+
+
+ABOUT THIS DRIVER
+=================
+
+  This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754
+ cards. When enabled, your card acts as "SoundBlaster Pro" compatible card.
+ It can only play 22.05kHz / 8bit / Stereo samples, control external MIDI
+ port.
+ If you want to use your card as recent "16-bit" card, you should use
+ Alsa or OSS/Linux driver. Of course you can write native PCI driver for
+ your cards :)
+
+
+USAGE
+=====
+
+ # modprobe ymfsb (options)
+
+
+OPTIONS FOR MODULE
+==================
+
+  io           : SB base address     (0x220, 0x240, 0x260, 0x280)
+  synth_io     : OPL3 base address   (0x388, 0x398, 0x3a0, 0x3a8)
+  dma          : DMA number          (0,1,3)
+  master_volume: AC'97 PCM out Vol   (0-100)
+  spdif_out    : SPDIF-out flag      (0:disable 1:enable)
+
+ These options will change in future...
+
+
+FREQUENCY
+=========
+
+  When playing sounds via this driver, you will hear its pitch is slightly
+ lower than original sounds. Since this driver recognizes your card acts
+ with 21.739kHz sample rates rather than 22.050kHz (I think it must be
+ hardware restriction). So many players become tone deafness.
+ To prevent this, you should express some options to your sound player
+ that specify correct sample frequency. For example, to play your MP3 file
+ correctly with mpg123, specify the frequency like following:
+
+  %  mpg123 -r 21739 foo.mp3
+
+
+SPDIF OUT
+=========
+
+  With installing modules with option 'spdif_out=1', you can enjoy your
+ sounds from SPDIF-out of your card (if it had).
+ Its Fs is fixed to 48kHz (It never means the sample frequency become 
+ up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your
+ digital-in capable components has to be able to handle 48kHz Fs.
+
+
+COPYING
+=======
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+TODO
+====
+ * support for multiple cards
+   (set the different SB_IO,MPU_IO,OPL_IO for each cards)
+
+ * support for OPL (dmfm) : There will be no requirements... :-<
+
+
+AUTHOR
+======
+
+ Daisuke Nagano <breeze.nagano@nifty.ne.jp>
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/SoundPro linux-2.5.6/Documentation/sound/oss/SoundPro
--- linux-2.5.6-pre3/Documentation/sound/oss/SoundPro	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/SoundPro	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,105 @@
+Documentation for the SoundPro CMI8330 extensions in the WSS driver (ad1848.o)
+------------------------------------------------------------------------------
+
+( Be sure to read Documentation/sound/CMI8330 too )
+
+Ion Badulescu, ionut@cs.columbia.edu
+February 24, 1999
+
+(derived from the OPL3-SA2 documentation by Scott Murray)
+
+The SoundPro CMI8330 (ISA) is a chip usually found on some Taiwanese
+motherboards.  The official name in the documentation is CMI8330, SoundPro
+is the nickname and the big inscription on the chip itself.
+
+The chip emulates a WSS as well as a SB16, but it has certain differences
+in the mixer section which require separate support. It also emulates an
+MPU401 and an OPL3 synthesizer, so you probably want to enable support
+for these, too.
+
+The chip identifies itself as an AD1848, but its mixer is significantly
+more advanced than the original AD1848 one. If your system works with
+either WSS or SB16 and you are having problems with some mixer controls
+(no CD audio, no line-in, etc), you might want to give this driver a try.
+Detection should work, but it hasn't been widely tested, so it might still
+mis-identify the chip. You can still force soundpro=1 in the modprobe
+parameters for ad1848. Please let me know if it happens to you, so I can
+adjust the detection routine.
+
+The chip is capable of doing full-duplex, but since the driver sees it as an
+AD1848, it cannot take advantage of this.  Moreover, the full-duplex mode is
+not achievable through the WSS interface, b/c it needs a dma16 line which is
+assigned only to the SB16 subdevice (with isapnp). Windows documentation
+says the user must use WSS Playback and SB16 Recording for full-duplex, so
+it might be possible to do the same thing under Linux. You can try loading
+up both ad1848 and sb then use one for playback and the other for
+recording. I don't know if this works, b/c I haven't tested it. Anyway, if
+you try it, be very careful: the SB16 mixer *mostly* works, but certain
+settings can have unexpected effects. Use the WSS mixer for best results.
+
+There is also a PCI SoundPro chip. I have not seen this chip, so I have
+no idea if the driver will work with it. I suspect it won't.
+
+As with PnP cards, some configuration is required.  There are two ways
+of doing this.  The most common is to use the isapnptools package to
+initialize the card, and use the kernel module form of the sound
+subsystem and sound drivers.  Alternatively, some BIOS's allow manual
+configuration of installed PnP devices in a BIOS menu, which should
+allow using the non-modular sound drivers, i.e. built into the kernel.
+Since in this latter case you cannot use module parameters, you will
+have to enable support for the SoundPro at compile time.
+
+The IRQ and DMA values can be any that are considered acceptable for a
+WSS.  Assuming you've got isapnp all happy, then you should be able to
+do something like the following (which *must* match the isapnp/BIOS
+configuration):
+
+modprobe ad1848 io=0x530 irq=11 dma=0 soundpro=1
+-and maybe-
+modprobe sb io=0x220 irq=5 dma=1 dma16=5
+
+-then-
+modprobe mpu401 io=0x330 irq=9
+modprobe opl3 io=0x388
+
+If all goes well and you see no error messages, you should be able to
+start using the sound capabilities of your system.  If you get an
+error message while trying to insert the module(s), then make
+sure that the values of the various arguments match what you specified
+in your isapnp configuration file, and that there is no conflict with
+another device for an I/O port or interrupt.  Checking the contents of
+/proc/ioports and /proc/interrupts can be useful to see if you're
+butting heads with another device.
+
+If you do not see the chipset version message, and none of the other
+messages present in the system log are helpful, try adding 'debug=1'
+to the ad1848 parameters, email me the syslog results and I'll do
+my best to help. 
+
+Lastly, if you're using modules and want to set up automatic module
+loading with kmod, the kernel module loader, here is the section I
+currently use in my conf.modules file:
+
+# Sound
+post-install sound modprobe -k ad1848; modprobe -k mpu401; modprobe -k opl3
+options ad1848 io=0x530 irq=11 dma=0
+options sb io=0x220 irq=5 dma=1 dma16=5
+options mpu401 io=0x330 irq=9
+options opl3 io=0x388
+
+The above ensures that ad1848 will be loaded whenever the sound system
+is being used.
+
+Good luck.
+
+Ion
+
+NOT REALLY TESTED:
+- recording
+- recording device selection
+- full-duplex
+
+TODO:
+- implement mixer support for surround, loud, digital CD switches.
+- come up with a scheme which allows recording volumes for each subdevice.
+This is a major OSS API change.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Soundblaster linux-2.5.6/Documentation/sound/oss/Soundblaster
--- linux-2.5.6-pre3/Documentation/sound/oss/Soundblaster	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Soundblaster	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,53 @@
+modprobe sound
+insmod uart401
+insmod sb ...
+
+This loads the driver for the Sound Blaster and assorted clones. Cards that
+are covered by other drivers should not be using this driver.
+
+The Sound Blaster module takes the following arguments
+
+io		I/O address of the Sound Blaster chip (0x220,0x240,0x260,0x280)
+irq		IRQ of the Sound Blaster chip (5,7,9,10)
+dma		8-bit DMA channel for the Sound Blaster (0,1,3)
+dma16		16-bit DMA channel for SB16 and equivalent cards (5,6,7)
+mpu_io		I/O for MPU chip if present (0x300,0x330)
+
+sm_games=1	Set if you have a Logitech soundman games
+acer=1		Set this to detect cards in some ACER notebooks
+mwave_bug=1	Set if you are trying to use this driver with mwave (see on)
+type		Use this to specify a specific card type
+
+The following arguments are taken if ISAPnP support is compiled in
+
+isapnp=0	Set this to disable ISAPnP detection (use io=0xXXX etc. above)
+multiple=0	Set to disable detection of multiple Soundblaster cards.
+		Consider it a bug if this option is needed, and send in a
+		report.
+pnplegacy=1	Set this to be able to use a PnP card(s) along with a single
+		non-PnP (legacy) card.  Above options for io, irq, etc. are
+		needed, and will apply only to the legacy card.
+reverse=1	Reverses the order of the search in the PnP table.
+uart401=1	Set to enable detection of mpu devices on some clones.
+isapnpjump=n	Jumps to slot n in the driver's PnP table. Use the source,
+		Luke.
+
+You may well want to load the opl3 driver for synth music on most SB and
+clone SB devices
+
+insmod opl3 io=0x388
+
+Using Mwave
+
+To make this driver work with Mwave you must set mwave_bug. You also need
+to warm boot from DOS/Windows with the required firmware loaded under this
+OS. IBM are being difficult about documenting how to load this firmware.
+
+Avance Logic ALS007
+
+This card is supported; see the separate file ALS007 for full details.
+
+Avance Logic ALS100
+
+This card is supported; setup should be as for a standard Sound Blaster 16.
+The driver will identify the audio device as a "Sound Blaster 16 (ALS-100)".
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Tropez+ linux-2.5.6/Documentation/sound/oss/Tropez+
--- linux-2.5.6-pre3/Documentation/sound/oss/Tropez+	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Tropez+	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,26 @@
+From: Paul Barton-Davis <pbd@op.net>
+
+Here is the configuration I use with a Tropez+ and my modular
+driver:
+
+  alias char-major-14 wavefront
+  alias synth0 wavefront
+  alias mixer0 cs4232
+  alias audio0 cs4232
+  pre-install wavefront modprobe "-k" "cs4232"
+  post-install wavefront modprobe "-k" "opl3"
+  options wavefront io=0x200 irq=9
+  options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
+  options opl3 io=0x388
+
+Things to note: 
+
+       the wavefront options "io" and "irq" ***MUST*** match the "synthio"
+       and "synthirq" cs4232 options.
+
+       you can do without the opl3 module if you don't
+       want to use the OPL/[34] synth on the soundcard
+
+       the opl3 io parameter is conventionally not adjustable.
+
+Please see drivers/sound/README.wavefront for more details.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/VIA-chipset linux-2.5.6/Documentation/sound/oss/VIA-chipset
--- linux-2.5.6-pre3/Documentation/sound/oss/VIA-chipset	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/VIA-chipset	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,43 @@
+Running sound cards on VIA chipsets
+
+o	There are problems with VIA chipsets and sound cards that appear to
+	lock the hardware solidly. Test programs under DOS have verified the
+	problem exists on at least some (but apparently not all) VIA boards
+
+o	VIA have so far failed to bother to answer support mail on the subject
+	so if you are a VIA engineer feeling aggrieved as you read this 
+	document go chase your own people. If there is a workaround please
+	let us know so we can implement it.
+
+
+Certain patterns of ISA DMA access used for most PC sound cards cause the
+VIA chipsets to lock up. From the collected reports this appears to cover a
+wide range of boards. Some also lock up with sound cards under Win* as well.
+
+Linux implements a workaround providing your chipset is PCI and you compiled
+with PCI Quirks enabled. If so you will see a message
+	"Activating ISA DMA bug workarounds"
+
+during booting. If you have a VIA PCI chipset that hangs when you use the
+sound and is not generating this message even with PCI quirks enabled
+please report the information to the linux-kernel list (see REPORTING-BUGS).
+
+If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA
+chipset board you need to do the following to build a special kernel for
+your board
+
+	edit linux/include/asm-i386/dma.h
+
+change
+
+#define isa_dma_bridge_buggy 	(0)
+
+to
+
+#define isa_dma_bridge_buggy 	(1)
+
+and rebuild a kernel without PCI quirk support.
+
+
+Other than this particular glitch the VIA [M]VP* chipsets appear to work
+perfectly with Linux.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/VIBRA16 linux-2.5.6/Documentation/sound/oss/VIBRA16
--- linux-2.5.6-pre3/Documentation/sound/oss/VIBRA16	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/VIBRA16	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,80 @@
+Sound Blaster 16X Vibra addendum
+--------------------------------
+by Marius Ilioaea <mariusi@protv.ro>
+   Stefan Laudat  <stefan@asit.ro>
+
+Sat Mar 6 23:55:27 EET 1999
+
+			Hello again,
+	
+	Playing with a SB Vibra 16x soundcard we found it very difficult
+to setup because the kernel reported a lot of DMA errors and wouldn't
+simply play any sound.
+	A good starting point is that the vibra16x chip full-duplex facility
+is neither still exploited by the sb driver found in the linux kernel 
+(tried it with a 2.2.2-ac7), nor in the commercial OSS package (it reports
+it as half-duplex soundcard). Oh, I almost forgot, the RedHat sndconfig
+failed detecting it ;)
+	So, the big problem still remains, because the sb module wants a
+8-bit and a 16-bit dma, which we could not allocate for vibra... it supports
+only two 8-bit dma channels, the second one will be passed to the module
+as a 16 bit channel, the kernel will yield about that but everything will
+be okay, trust us. 
+	The only inconvenient you may find is that you will have
+some sound playing jitters if you have HDD dma support enabled - but this
+will happen with almost all soundcards...
+
+	A fully working isapnp.conf is just here:
+
+<snip here>
+
+(READPORT 0x0203)
+(ISOLATE PRESERVE)
+(IDENTIFY *)
+(VERBOSITY 2)
+(CONFLICT (IO FATAL)(IRQ FATAL)(DMA FATAL)(MEM FATAL)) # or WARNING
+# SB 16 and OPL3 devices
+(CONFIGURE CTL00f0/-1 (LD 0
+(INT 0 (IRQ 5 (MODE +E)))
+(DMA 0 (CHANNEL 1))
+(DMA 1 (CHANNEL 3))
+(IO 0 (SIZE 16) (BASE 0x0220))
+(IO 2 (SIZE 4) (BASE 0x0388))
+(NAME "CTL00f0/-1[0]{Audio               }")
+(ACT Y)
+))
+
+# Joystick device - only if you need it :-/
+
+(CONFIGURE CTL00f0/-1 (LD 1
+(IO 0 (SIZE 1) (BASE 0x0200))
+(NAME "CTL00f0/-1[1]{Game                }")
+(ACT Y)
+))
+(WAITFORKEY)
+
+<end of snipping>
+
+	So, after a good kernel modules compilation and a 'depmod -a kernel_ver'
+you may want to:
+
+modprobe sb io=0x220 irq=5 dma=1 dma16=3
+
+	Or, take the hard way:
+
+insmod souncore
+insmod sound
+insmod uart401
+insmod sb io=0x220 irq=5 dma=1 dma16=3
+# do you need MIDI?
+insmod opl3=0x388
+
+	Just in case, the kernel sound support should be:
+
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS=m
+CONFIG_SOUND_SB=m
+	
+	Enjoy your new noisy Linux box! ;)
+	
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/WaveArtist linux-2.5.6/Documentation/sound/oss/WaveArtist
--- linux-2.5.6-pre3/Documentation/sound/oss/WaveArtist	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/WaveArtist	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,170 @@
+
+ (the following is from the armlinux CVS)
+
+ WaveArtist mixer and volume levels can be accessed via these commands:
+
+  nn30	read registers nn, where nn = 00 - 09 for mixer settings
+		                              0a - 13 for channel volumes
+  mm31	write the volume setting in pairs, where mm = (nn - 10) / 2
+  rr32	write the mixer settings in pairs, where rr = nn/2
+  xx33	reset all settings to default
+  0y34	select mono source, y=0 = left, y=1 = right
+
+                                           bits
+ nn  15  14 13 12 11   10    9     8     7    6     5     4     3     2     1     0
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 00 | 0 | 0  0  1  1 | left line mixer gain       | left aux1 mixer gain        |lmute|
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 01 | 0 | 0  1  0  1 | left aux2 mixer gain       | right 2 left mic gain       |mmute|
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 02 | 0 | 0  1  1  1 | left mic mixer gain        | left mic  | left mixer gain |dith |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 03 | 0 | 1  0  0  1 | left mixer input select                |lrfg | left ADC gain   |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 04 | 0 | 1  0  1  1 | right line mixer gain      | right aux1 mixer gain       |rmute|
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 05 | 0 | 1  1  0  1 | right aux2 mixer gain      | left 2 right mic gain       |test |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 06 | 0 | 1  1  1  1 | right mic mixer gain       | right mic |right mixer gain |rbyps|
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 07 | 1 | 0  0  0  1 | right mixer select                     |rrfg | right ADC gain  |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 08 | 1 | 0  0  1  1 | mono mixer gain            |right ADC mux sel|left ADC mux sel |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 09 | 1 | 0  1  0  1 |loopb|left linout|loop|ADCch|TxFch|OffCD|test |loopb|loopb|osamp|
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0a | 0 | left PCM channel volume                                                     |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0b | 0 | right PCM channel volume                                                    |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0c | 0 | left FM channel volume                                                      |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0d | 0 | right FM channel volume                                                     |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0e | 0 | left wavetable channel volume                                               |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 0f | 0 | right wavetable channel volume                                              |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 10 | 0 | left PCM expansion channel volume                                           |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 11 | 0 | right PCM expansion channel volume                                          |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 12 | 0 | left FM expansion channel volume                                            |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+ 13 | 0 | right FM expansion channel volume                                           |
+----+---+------------+-----+-----+-----+----+-----+-----+-----+-----+-----+-----+-----+
+
+ lmute: left mute
+ mmute: mono mute
+ dith: dithds
+ lrfg:
+ rmute: right mute
+ rbyps: right bypass
+ rrfg:
+ ADCch:
+ TxFch:
+ OffCD:
+ osamp:
+
+ And the following diagram is derived from the description in the CVS archive:
+
+ MIC L (mouthpiece)
+   +------+
+ -->PreAmp>-\
+   +--^---+ |
+      |     |
+    r2b4-5  |                                +--------+
+       /----*-------------------------------->5       |
+       |                                     |        |
+       | /----------------------------------->4       |
+       | |                                   |        |
+       | | /--------------------------------->3 1of5  |  +---+
+       | | |                                 |  mux   >-->AMP>--> ADC L
+       | | | /------------------------------->2       |  +-^-+
+       | | | |                               |        |    |
+ Line  | | | | +----+  +------+  +---+  /---->1       |  r3b3-0
+ ------------*->mute>--> Gain >-->   |  |    |        |
+  L    | | |   +----+  +------+  |   |  |  *->0       |
+       | | |                     |   |  |    +---^----+
+ Aux2  | | |   +----+  +------+  |   |  |        |
+ ----------*--->mute>--> Gain >--> M |  |     r8b0-2
+  L    | |     +----+  +------+  |   |  |
+       | |                       |   |  \------\
+ Aux1  | |     +----+  +------+  |   |         |
+ --------*----->mute>--> Gain >--> I |         |
+  L    |       +----+  +------+  |   |         |
+       |                         |   |         |
+       |       +----+  +------+  |   |  +---+  |
+       *------->mute>--> Gain >--> X >-->AMP>--*
+       |       +----+  +------+  |   |  +-^-+  |
+       |                         |   |    |    |
+       |       +----+  +------+  |   |  r2b1-3 |  
+       | /----->mute>--> Gain >--> E |         |
+       | |     +----+  +------+  |   |         |
+       | |                       |   |         |
+       | |     +----+  +------+  |   |         |
+       | | /--->mute>--> Gain >--> R |         |
+       | | |   +----+  +------+  |   |         |
+       | | |                     |   |         |   r9b8-9
+       | | |   +----+  +------+  |   |         |     |
+       | | | /->mute>--> Gain >-->   |         | +---v---+
+       | | | | +----+  +------+  +---+       /-*->0      |
+ DAC   | | | |                               |   |       |
+ ------------*----------------------------------->?      |  +----+
+  L    | | |                                 |   |  Mux  >-->mute>--> L output
+       | | |                                 | /->?      |  +--^-+
+       | | |                                 | | |       |     |
+       | | |                           /--------->?      |   r0b0
+       | | |                           |     | | +-------+
+       | | |                           |     | |
+ Mono  | | |                           |     | | +-------+
+ ----------*                           |     \--->       |  +----+
+       | | |                           |       | |  Mix  >-->mute>--> Mono output
+       | | |                           |       *->       |  +--^-+
+       | | |                           |       | +-------+     |
+       | | |                           |       |             r1b0
+ DAC   | | |                           |       | +-------+
+ ------------*-------------------------*--------->1      |  +----+
+  R    | | | |                                 | |  Mux  >-->mute>--> R output
+       | | | | +----+  +------+  +---+         *->0      |  +--^-+
+       | | | \->mute>--> Gain >-->   |         | +---^---+     |
+       | | |   +----+  +------+  |   |         |     |       r5b0
+       | | |                     |   |         |   r6b0
+       | | |   +----+  +------+  |   |         |
+       | | \--->mute>--> Gain >--> M |         |
+       | |     +----+  +------+  |   |         |
+       | |                       |   |         |
+       | |     +----+  +------+  |   |         |
+       | *----->mute>--> Gain >--> I |         |
+       | |     +----+  +------+  |   |         |
+       | |                       |   |         |
+       | |     +----+  +------+  |   |  +---+  |
+       \------->mute>--> Gain >--> X >-->AMP>--*
+         |     +----+  +------+  |   |  +-^-+  |
+      /--/                       |   |    |    |
+ Aux1 |        +----+  +------+  |   |  r6b1-3 |
+ -------*------>mute>--> Gain >--> E |         |
+  R   | |      +----+  +------+  |   |         |
+      | |                        |   |         |
+ Aux2 | |      +----+  +------+  |   |  /------/
+ ---------*---->mute>--> Gain >--> R |  |
+  R   | | |    +----+  +------+  |   |  |
+      | | |                      |   |  |    +--------+
+ Line | | |    +----+  +------+  |   |  |  *->0       |
+ -----------*-->mute>--> Gain >-->   |  |    |        |
+  R   | | | |  +----+  +------+  +---+  \---->1       |
+      | | | |                                |        |
+      | | | \-------------------------------->2       |  +---+
+      | | |                                  |  Mux   >-->AMP>--> ADC R
+      | | \---------------------------------->3       |  +-^-+
+      | |                                    |        |    |
+      | \------------------------------------>4       |  r7b3-0
+      |                                      |        |
+      \-----*-------------------------------->5       |
+            |                                +---^----+
+    r6b4-5  |                                    |
+      |     |                                  r8b3-5
+   +--v---+ |
+ -->PreAmp>-/
+   +------+
+ MIC R (electret mic)
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/Wavefront linux-2.5.6/Documentation/sound/oss/Wavefront
--- linux-2.5.6-pre3/Documentation/sound/oss/Wavefront	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/Wavefront	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,341 @@
+	     An OSS/Free Driver for WaveFront soundcards
+	       (Turtle Beach Maui, Tropez, Tropez Plus)
+
+		     Paul Barton-Davis, July 1998
+
+			  VERSION 0.2.5
+
+Driver Status
+-------------
+
+Requires: Kernel 2.1.106 or later (the driver is included with kernels
+2.1.109 and above)
+	  
+As of 7/22/1998, this driver is currently in *BETA* state. This means
+that it compiles and runs, and that I use it on my system (Linux
+2.1.106) with some reasonably demanding applications and uses.  I
+believe the code is approaching an initial "finished" state that
+provides bug-free support for the Tropez Plus.
+
+Please note that to date, the driver has ONLY been tested on a Tropez
+Plus. I would very much like to hear (and help out) people with Tropez
+and Maui cards, since I think the driver can support those cards as
+well. 
+
+Finally, the driver has not been tested (or even compiled) as a static
+(non-modular) part of the kernel. Alan Cox's good work in modularizing
+OSS/Free for Linux makes this rather unnecessary.
+
+Some Questions
+--------------
+
+**********************************************************************
+0) What does this driver do that the maui driver did not ?
+**********************************************************************
+
+* can fully initialize a WaveFront card from cold boot - no DOS 
+          utilities needed
+* working patch/sample/program loading and unloading (the maui
+      driver didn't document how to make this work, and assumed
+      user-level preparation of the patch data for writing
+      to the board. ick.)
+* full user-level access to all WaveFront commands
+* for the Tropez Plus, (primitive) control of the YSS225 FX processor
+* Virtual MIDI mode supported - 2 MIDI devices accessible via the
+          WaveFront's MPU401/UART emulation. One
+	  accesses the WaveFront synth, the other accesses the
+	  external MIDI connector. Full MIDI read/write semantics
+	  for both devices.
+* OSS-compliant /dev/sequencer interface for the WaveFront synth,
+	  including native and GUS-format patch downloading.
+* semi-intelligent patch management (prototypical at this point)
+
+**********************************************************************
+1) What to do about MIDI interfaces ?
+**********************************************************************
+
+The Tropez Plus (and perhaps other WF cards) can in theory support up
+to 2 physical MIDI interfaces. One of these is connected to the
+ICS2115 chip (the WaveFront synth itself) and is controlled by
+MPU/UART-401 emulation code running as part of the WaveFront OS.  The
+other is controlled by the CS4232 chip present on the board. However,
+physical access to the CS4232 connector is difficult, and it is
+unlikely (though not impossible) that you will want to use it.
+
+An older version of this driver introduced an additional kernel config
+variable which controlled whether or not the CS4232 MIDI interface was
+configured. Because of Alan Cox's work on modularizing the sound
+drivers, and now backporting them to 2.0.34 kernels, there seems to be
+little reason to support "static" configuration variables, and so this
+has been abandoned in favor of *only* module parameters. Specifying
+"mpuio" and "mpuirq" for the cs4232 parameter will result in the
+CS4232 MIDI interface being configured; leaving them unspecified will
+leave it unconfigured (and thus unusable).
+
+BTW, I have heard from one Tropez+ user that the CS4232 interface is
+more reliable than the ICS2115 one. I have had no problems with the
+latter, and I don't have the right cable to test the former one
+out. Reports welcome.
+
+**********************************************************************
+2) Why does line XXX of the code look like this .... ?
+**********************************************************************
+
+Either because its not finished yet, or because you're a better coder
+than I am, or because you don't understand some aspect of how the card
+or the code works. 
+
+I absolutely welcome comments, criticisms and suggestions about the
+design and implementation of the driver. 
+
+**********************************************************************
+3) What files are included ?
+**********************************************************************
+
+   drivers/sound/README.wavefront       -- this file
+
+   drivers/sound/wavefront.patch	-- patches for the 2.1.106 sound drivers
+					   needed to make the rest of this work
+				           DO NOT USE IF YOU'VE APPLIED THEM 
+					   BEFORE, OR HAVE 2.1.109 OR ABOVE
+
+   drivers/sound/wavfront.c             -- the driver
+   drivers/sound/ys225.h                -- data declarations for FX config
+   drivers/sound/ys225.c                -- data definitions for FX config
+   drivers/sound/wf_midi.c              -- the "uart401" driver 
+   				              to support virtual MIDI mode.
+   include/wavefront.h                  -- the header file
+   Documentation/sound/Tropez+          -- short docs on configuration
+
+**********************************************************************
+4) How do I compile/install/use it ?
+**********************************************************************
+
+PART ONE: install the source code into your sound driver directory
+
+  cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
+  tar -zxvf <where-you-put/wavefront.tar.gz>
+
+PART TWO: apply the patches
+
+     DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
+     AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
+
+  cd drivers/sound
+  patch < wavefront.patch
+
+PART THREE: configure your kernel
+
+  cd <top of your kernel tree>
+  make xconfig (or whichever config option you use)
+
+         - choose YES for Sound Support	      
+         - choose MODULE (M) for OSS Sound Modules
+         - choose MODULE(M) to YM3812/OPL3 support
+	 - choose MODULE(M) for WaveFront support
+	 - choose MODULE(M) for CS4232 support
+
+	 - choose "N" for everything else (unless you have other
+	      soundcards you want support for)
+
+
+   make dep
+   make boot
+   .
+   .
+   .
+   <whatever you normally do for a kernel install>
+   make modules
+   .
+   .
+   .
+   make modules_install
+
+Here's my autoconf.h SOUND section:
+
+/*
+ * Sound
+ */
+#define CONFIG_SOUND 1
+#undef  CONFIG_SOUND_OSS
+#define CONFIG_SOUND_OSS_MODULE 1
+#undef  CONFIG_SOUND_PAS
+#undef  CONFIG_SOUND_SB
+#undef  CONFIG_SOUND_ADLIB
+#undef  CONFIG_SOUND_GUS
+#undef  CONFIG_SOUND_MPU401
+#undef  CONFIG_SOUND_PSS
+#undef  CONFIG_SOUND_MSS
+#undef  CONFIG_SOUND_SSCAPE
+#undef  CONFIG_SOUND_TRIX
+#undef  CONFIG_SOUND_MAD16
+#undef  CONFIG_SOUND_WAVEFRONT
+#define CONFIG_SOUND_WAVEFRONT_MODULE 1
+#undef  CONFIG_SOUND_CS4232
+#define CONFIG_SOUND_CS4232_MODULE 1
+#undef  CONFIG_SOUND_MAUI
+#undef  CONFIG_SOUND_SGALAXY
+#undef  CONFIG_SOUND_OPL3SA1
+#undef  CONFIG_SOUND_SOFTOSS
+#undef  CONFIG_SOUND_YM3812
+#define CONFIG_SOUND_YM3812_MODULE 1
+#undef  CONFIG_SOUND_VMIDI
+#undef  CONFIG_SOUND_UART6850
+/*
+ * Additional low level sound drivers
+ */
+#undef  CONFIG_LOWLEVEL_SOUND
+
+************************************************************
+6) How do I configure my card ?
+************************************************************
+
+You need to edit /etc/modules.conf. Here's mine (edited to show the
+relevant details):
+
+  # Sound system
+  alias char-major-14 wavefront
+  alias synth0 wavefront
+  alias mixer0 cs4232
+  alias audio0 cs4232
+  pre-install wavefront modprobe "-k" "cs4232"
+  post-install wavefront modprobe "-k" "opl3"
+  options wavefront io=0x200 irq=9
+  options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
+  options opl3 io=0x388
+
+Things to note: 
+
+       the wavefront options "io" and "irq" ***MUST*** match the "synthio"
+       and "synthirq" cs4232 options.
+
+       you can do without the opl3 module if you don't
+       want to use the OPL/[34] FM synth on the soundcard
+
+       the opl3 io parameter is conventionally not adjustable.
+       In theory, any not-in-use IO port address would work, but
+       just use 0x388 and stick with the crowd.
+
+**********************************************************************
+7) What about firmware ?
+**********************************************************************
+
+Turtle Beach have not given me permission to distribute their firmware
+for the ICS2115. However, if you have a WaveFront card, then you
+almost certainly have the firmware, and if not, its freely available
+on their website, at:
+
+   http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus 
+
+The file is called WFOS2001.MOT (for the Tropez+).
+
+This driver, however, doesn't use the pure firmware as distributed,
+but instead relies on a somewhat processed form of it. You can
+generate this very easily. Following an idea from Andrew Veliath's
+Pinnacle driver, the following flex program will generate the
+processed version:
+
+---- cut here -------------------------
+%option main
+%%
+^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
+<<EOF>> { fputc ('\0', stdout); return; }
+\n {} 
+.  {}
+---- cut here -------------------------
+
+To use it, put the above in file (say, ws.l) compile it like this:
+
+      shell> flex -ows.c ws.l
+      shell> cc -o ws ws.c
+      
+and then use it like this:
+
+    ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
+
+If you put it somewhere else, you'll always have to use the wf_ospath
+module parameter (see below) or alter the source code.
+
+**********************************************************************
+7) How do I get it working ?
+**********************************************************************
+
+Optionally, you can reboot with the "new" kernel (even though the only
+changes have really been made to a module).
+
+Then, as root do:
+
+     modprobe wavefront
+
+You should get something like this in /var/log/messages:
+
+    WaveFront: firmware 1.20 already loaded.
+
+or 
+
+    WaveFront: no response to firmware probe, assume raw.
+
+then:
+
+    WaveFront: waiting for memory configuration ...
+    WaveFront: hardware version 1.64
+    WaveFront: available DRAM 8191k
+    WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
+    WaveFront: 128 programs slots in use
+    WaveFront: 256 patch slots filled, 142 in use
+
+The whole process takes about 16 seconds, the longest waits being
+after reporting the hardware version (during the firmware download),
+and after reporting program status (during patch status inquiry).  Its
+shorter (about 10 secs) if the firmware is already loaded (i.e. only
+warm reboots since the last firmware load).
+
+The "available DRAM" line will vary depending on how much added RAM
+your card has. Mine has 8MB.
+
+To check basically functionality, use play(1) or splay(1) to send a
+.WAV or other audio file through the audio portion. Then use playmidi
+to play a General MIDI file. Try the "-D 0" to hear the
+difference between sending MIDI to the WaveFront and using the OPL/3,
+which is the default (I think ...). If you have an external synth(s)
+hooked to the soundcard, you can use "-e" to route to the
+external synth(s) (in theory, -D 1 should work as well, but I think
+there is a bug in playmidi which prevents this from doing what it
+should). 
+
+**********************************************************************
+8) What are the module parameters ?
+**********************************************************************
+
+Its best to read wavefront.c for this, but here is a summary:
+
+integers: 
+	  wf_raw  - if set, ignore apparent presence of firmware
+		    loaded onto the ICS2115, reset the whole
+		    board, and initialize it from scratch. (default = 0)
+
+          fx_raw  - if set, always initialize the YSS225 processor
+		    on the Tropez plus. (default = 1)
+
+          < The next 4 are basically for kernel hackers to allow
+	    tweaking the driver for testing purposes. >		    
+
+          wait_usecs        -  loop timer used when waiting for
+			       status conditions on the board. 
+			       The default is 150.
+
+          debug_default    - debugging flags. See sound/wavefront.h
+			     for WF_DEBUG_* values. Default is zero.
+			     Setting this allows you to debug the
+			     driver during module installation.
+strings:
+	  ospath - path to get to the pre-processed OS firmware.
+		    (default: /etc/sound/wavefront.os)
+
+**********************************************************************
+9) Who should I contact if I have problems?
+**********************************************************************
+
+Just me: Paul Barton-Davis <pbd@op.net>
+
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/btaudio linux-2.5.6/Documentation/sound/oss/btaudio
--- linux-2.5.6-pre3/Documentation/sound/oss/btaudio	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/btaudio	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,92 @@
+
+Intro
+=====
+
+people start bugging me about this with questions, looks like I
+should write up some documentation for this beast.  That way I
+don't have to answer that much mails I hope.  Yes, I'm lazy...
+
+
+You might have noticed that the bt878 grabber cards have actually
+_two_ PCI functions:
+
+$ lspci
+[ ... ]
+00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
+00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02)
+[ ... ]
+
+The first does video, it is backward compatible to the bt848.  The second
+does audio.  btaudio is a driver for the second function.  It's a sound
+driver which can be used for recording sound (and _only_ recording, no
+playback).  As most TV cards come with a short cable which can be plugged
+into your sound card's line-in you probably don't need this driver if all
+you want to do is just watching TV...
+
+
+Driver Status
+=============
+
+Still somewhat experimental.  The driver should work stable, i.e. it
+should'nt crash your box.  It might not work as expected, have bugs,
+not being fully OSS API compilant, ...
+
+Latest versions are available from http://bytesex.org/bttv/, the
+driver is in the bttv tarball.  Kernel patches might be available too,
+have a look at http://bytesex.org/bttv/listing.html.
+
+The chip knows two different modes.  btaudio registers two dsp
+devices, one for each mode.  They can not be used at the same time.
+
+
+Digital audio mode
+==================
+
+The chip gives you 16 bit stereo sound.  The sample rate depends on
+the external source which feeds the bt878 with digital sound via I2S
+interface.  There is a insmod option (rate) to tell the driver which
+sample rate the hardware uses (32000 is the default).
+
+One possible source for digital sound is the msp34xx audio processor
+chip which provides digital sound via I2S with 32 kHz sample rate.  My
+Hauppauge board works this way.
+
+The Osprey-200 reportly gives you digital sound with 44100 Hz sample
+rate.  It is also possible that you get no sound at all.
+
+
+analog mode (A/D)
+=================
+
+You can tell the driver to use this mode with the insmod option "analog=1".
+The chip has three analog inputs.  Consequently you'll get a mixer device
+to control these.
+
+The analog mode supports mono only.  Both 8 + 16 bit.  Both are _signed_
+int, which is uncommon for the 8 bit case.  Sample rate range is 119 kHz
+to 448 kHz.  Yes, the number of digits is correct.  The driver supports
+downsampling by powers of two, so you can ask for more usual sample rates
+like 44 kHz too.
+
+With my Hauppauge I get noisy sound on the second input (mapped to line2
+by the mixer device).  Others get a useable signal on line1.
+
+
+some examples
+=============
+
+* read audio data from btaudio (dsp2), send to es1730 (dsp,dsp1):
+  $ sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp
+
+* read audio data from btaudio, send to esound daemon (which might be
+  running on another host):
+  $ sox -c 2 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -r 32000
+  $ sox -c 1 -w -r 32000 -t ossdsp /dev/dsp2 -t sw - | esdcat -m -r 32000
+
+
+Have fun,
+
+  Gerd
+
+-- 
+Gerd Knorr <kraxel@bytesex.org>
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/cs46xx linux-2.5.6/Documentation/sound/oss/cs46xx
--- linux-2.5.6-pre3/Documentation/sound/oss/cs46xx	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/cs46xx	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,138 @@
+
+Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio 
+controller chips (2001/05/11)
+
+The cs46xx audio driver supports the DSP line of Cirrus controllers. 
+Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280
+products.  This driver uses the generic ac97_codec driver for AC97 codec
+support.  
+
+
+Features:
+
+Full Duplex Playback/Capture supported from 8k-48k.
+16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
+
+APM/PM - 2.2.x PM is enabled and functional. APM can also
+be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
+definition.
+
+DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg 
+(defaultorder=11).  DMA capture buffer size is fixed at a single 4k page as
+two 2k fragments.
+
+MMAP seems to work well with QuakeIII, and test XMMS plugin.
+
+Myth2 works, but the polling logic is not fully correct, but is functional.
+
+The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested 
+with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o).  This 
+audio driver must be loaded prior to the joystick driver to enable the
+DSP task image supporting the joystick device.
+
+
+Limitations:
+
+SPDIF is currently not supported.
+
+Primary codec support only.  No secondary codec support is implemented.
+
+
+
+NOTES:
+
+Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
+and has been tested.
+Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR
+to disable the external amplifier.
+
+VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
+the external amplifier for the "back" speakers, since we do not
+support the secondary codec then this external amp is not
+turned on.  The primary codec external amplifier is supported but
+note that the AC97 EAPD bit is inverted logic (amp_voyetra()).
+
+DMA buffer size - there are issues with many of the Linux applications
+concerning the optimal buffer size.  Several applications request a 
+certain fragment size and number and then do not verify that the driver
+has the ability to support the requested configuration.  
+SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and
+number of fragments.  Some applications exit if an error is returned
+on this particular ioctl. Therefore, in alignment with the other OSS audio 
+drivers, no error is returned when a SETFRAGs IOCTL is received, but the 
+values passed from the app are not used in any buffer calculation 
+(ossfragshift/ossmaxfrags are not used).
+Use the "defaultorder=N" module parameter to change the buffer size if
+you have an application that requires a specific number of fragments
+or a specific buffer size (see below).
+
+Debug Interface
+---------------
+There is an ioctl debug interface to allow runtime modification of the 
+debug print levels.  This debug interface code can be disabled from the 
+compilation process with commenting the following define:
+#define CSDEBUG_INTERFACE 1
+There is also a debug print methodolgy to select printf statements from
+different areas of the driver.  A debug print level is also used to allow
+additional printfs to be active.  Comment out the following line in the
+driver to disable compilation of the CS_DBGOUT print statements:
+#define CSDEBUG 1
+ 
+Please see the defintions for cs_debuglevel and cs_debugmask for additional
+information on the debug levels and sections.
+
+There is also a csdbg executable to allow runtime manipulation of these 
+parameters.  for a copy email: twoller@crystal.cirrus.com
+
+
+
+MODULE_PARMS definitions
+------------------------
+MODULE_PARM(defaultorder, "i");
+defaultorder=N
+where N is a value from 1 to 12
+The buffer order determines the size of the dma buffer for the driver.
+under Linux, a smaller buffer allows more responsiveness from many of the 
+applications (e.g. games).  A larger buffer allows some of the apps (esound) 
+to not underrun the dma buffer as easily.  As default, use 32k (order=3)
+rather than 64k as some of the games work more responsively.
+(2^N) * PAGE_SIZE = allocated buffer size
+
+MODULE_PARM(cs_debuglevel, "i");
+MODULE_PARM(cs_debugmask, "i");
+cs_debuglevel=N
+cs_debugmask=0xMMMMMMMM
+where N is a value from 0 (no debug printfs), to 9 (maximum)
+0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
+
+MODULE_PARM(hercules_egpio_disable, "i");
+hercules_egpio_disable=N
+where N is a 0 (enable egpio), or a 1 (disable egpio support)
+
+MODULE_PARM(initdelay, "i");
+initdelay=N
+This value is used to determine the millescond delay during the initialization
+code prior to powering up the PLL.  On laptops this value can be used to
+assist with errors on resume, mostly with IBM laptops.  Basically, if the 
+system is booted under battery power then the mdelay()/udelay() functions fail to 
+properly delay the required time.  Also, if the system is booted under AC power
+and then the power removed, the mdelay()/udelay() functions will not delay properly.
+ 
+MODULE_PARM(powerdown, "i");
+powerdown=N
+where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
+
+
+MODULE_PARM(external_amp, "i");
+external_amp=1
+if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
+override the detection logic and force the external amp bit in the AC97 0x26 register
+to be reset (0).  EAPD should be 0 for powerup, and 1 for powerdown.  The VTB Santa Cruz
+card has inverted logic, so there is a special function for these cards.
+
+MODULE_PARM(thinkpad, "i");
+thinkpad=1
+if N is set to 1, then force enabling the clkrun functionality.
+Currently, when the part is being used, then clkrun is disabled for the entire system,
+but re-enabled when the driver is released or there is no outstanding open count.
+
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/es1370 linux-2.5.6/Documentation/sound/oss/es1370
--- linux-2.5.6-pre3/Documentation/sound/oss/es1370	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/es1370	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,70 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
+ALaw/uLaw sample formats
+------------------------
+
+This driver does not support the ALaw/uLaw sample formats.
+ALaw is the default mode when opening a sound device
+using OSS/Free. The reason for the lack of support is
+that the hardware does not support these formats, and adding
+conversion routines to the kernel would lead to very ugly
+code in the presence of the mmap interface to the driver.
+And since xquake uses mmap, mmap is considered important :-)
+and no sane application uses ALaw/uLaw these days anyway.
+In short, playing a Sun .au file as follows:
+
+cat my_file.au > /dev/dsp
+
+does not work. Instead, you may use the play script from
+Chris Bagwell's sox-12.14 package (available from the URL
+below) to play many different audio file formats.
+The script automatically determines the audio format
+and does do audio conversions if necessary.
+http://home.sprynet.com/sprynet/cbagwell/projects.html
+
+
+Blocking vs. nonblocking IO
+---------------------------
+
+Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+not only during open, but also during read and write.
+This is an effort to make the sound driver interface more
+regular. Timidity has problems with this; a patch
+is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+(Timidity patched will also run on OSS/Free).
+
+
+MIDI UART
+---------
+
+The driver supports a simple MIDI UART interface, with
+no ioctl's supported.
+
+
+MIDI synthesizer
+----------------
+
+This soundcard does not have any hardware MIDI synthesizer;
+MIDI synthesis has to be done in software. To allow this
+the driver/soundcard supports two PCM (/dev/dsp) interfaces.
+The second one goes to the mixer "synth" setting and supports
+only a limited set of sampling rates (44100, 22050, 11025, 5512).
+By setting lineout to 1 on the driver command line
+(eg. insmod es1370 lineout=1) it is even possible on some
+cards to convert the LINEIN jack into a second LINEOUT jack, thus
+making it possible to output four independent audio channels!
+
+There is a freely available software package that allows
+MIDI file playback on this soundcard called Timidity.
+See http://www.cgs.fi/~tt/timidity/.
+
+
+
+Thomas Sailer
+t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/es1371 linux-2.5.6/Documentation/sound/oss/es1371
--- linux-2.5.6-pre3/Documentation/sound/oss/es1371	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/es1371	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,64 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
+ALaw/uLaw sample formats
+------------------------
+
+This driver does not support the ALaw/uLaw sample formats.
+ALaw is the default mode when opening a sound device
+using OSS/Free. The reason for the lack of support is
+that the hardware does not support these formats, and adding
+conversion routines to the kernel would lead to very ugly
+code in the presence of the mmap interface to the driver.
+And since xquake uses mmap, mmap is considered important :-)
+and no sane application uses ALaw/uLaw these days anyway.
+In short, playing a Sun .au file as follows:
+
+cat my_file.au > /dev/dsp
+
+does not work. Instead, you may use the play script from
+Chris Bagwell's sox-12.14 package (available from the URL
+below) to play many different audio file formats.
+The script automatically determines the audio format
+and does do audio conversions if necessary.
+http://home.sprynet.com/sprynet/cbagwell/projects.html
+
+
+Blocking vs. nonblocking IO
+---------------------------
+
+Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+not only during open, but also during read and write.
+This is an effort to make the sound driver interface more
+regular. Timidity has problems with this; a patch
+is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+(Timidity patched will also run on OSS/Free).
+
+
+MIDI UART
+---------
+
+The driver supports a simple MIDI UART interface, with
+no ioctl's supported.
+
+
+MIDI synthesizer
+----------------
+
+This soundcard does not have any hardware MIDI synthesizer;
+MIDI synthesis has to be done in software. To allow this
+the driver/soundcard supports two PCM (/dev/dsp) interfaces.
+
+There is a freely available software package that allows
+MIDI file playback on this soundcard called Timidity.
+See http://www.cgs.fi/~tt/timidity/.
+
+
+
+Thomas Sailer
+t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/mwave linux-2.5.6/Documentation/sound/oss/mwave
--- linux-2.5.6-pre3/Documentation/sound/oss/mwave	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/mwave	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,185 @@
+	How to try to survive an IBM Mwave under Linux SB drivers
+
+
++	IBM have now released documentation of sorts and Torsten is busy
+	trying to make the Mwave work. This is not however a trivial task.
+
+----------------------------------------------------------------------------
+
+OK, first thing - the IRQ problem IS a problem, whether the test is bypassed or
+not.  It is NOT a Linux problem, but an MWAVE problem that is fixed with the
+latest MWAVE patches. So, in other words, don't bypass the test for MWAVES!
+
+I have Windows 95 on /dev/hda1, swap on /dev/hda2, and Red Hat 5 on /dev/hda3.
+
+The steps, then:
+
+    Boot to Linux. 
+    Mount Windows 95 file system (assume mount point = /dos95).
+    mkdir /dos95/linux
+    mkdir /dos95/linux/boot
+    mkdir /dos95/linux/boot/parms
+
+    Copy the kernel, any initrd image, and loadlin to /dos95/linux/boot/.
+
+    Reboot to Windows 95.
+
+    Edit C:/msdos.sys and add or change the following:
+
+        Logo=0
+        BootGUI=0
+
+    Note that msdos.sys is a text file but it needs to be made 'unhidden',
+    readable and writable before it can be edited.  This can be done with
+    DOS' "attrib" command.
+
+    Edit config.sys to have multiple config menus. I have one for windows 95 and
+    five for Linux, like this:
+------------
+[menu]
+menuitem=W95, Windows 95
+menuitem=LINTP, Linux - ThinkPad
+menuitem=LINTP3, Linux - ThinkPad Console
+menuitem=LINDOC, Linux - Docked
+menuitem=LINDOC3, Linux - Docked Console
+menuitem=LIN1, Linux - Single User Mode
+REM menudefault=W95,10
+
+[W95]
+
+[LINTP]
+
+[LINDOC]
+
+[LINTP3]
+
+[LINDOC3]
+
+[LIN1]
+
+[COMMON]
+FILES=30
+REM Please read README.TXT in C:\MWW subdirectory before changing the DOS= statement.
+DOS=HIGH,UMB
+DEVICE=C:\MWW\MANAGER\MWD50430.EXE
+SHELL=c:\command.com /e:2048
+-------------------
+
+The important things are the SHELL and DEVICE statements.
+
+    Then change autoexec.bat. Basically everything in there originally should be
+    done ONLY when Windows 95 is booted. Then you add new things specifically
+    for Linux.  Mine is as follows
+
+---------------
+@ECHO OFF
+if "%CONFIG%" == "W95" goto W95
+
+REM
+REM Linux stuff
+REM
+SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
+SET BLASTER=A220 I5 D1
+SET MWROOT=C:\MWW
+SET LIBPATH=C:\MWW\DLL
+SET PATH=C:\WINDOWS;C:\MWW\DLL;
+CALL MWAVE START NOSHOW
+c:\linux\boot\loadlin.exe @c:\linux\boot\parms\%CONFIG%.par
+
+:W95
+REM
+REM Windows 95 stuff
+REM
+c:\toolkit\guard
+SET MSINPUT=C:\MSINPUT
+SET MWPATH=C:\MWW\DLL;C:\MWW\MWGAMES;C:\MWW\DSP
+REM The following is used by DOS games to recognize Sound Blaster hardware.
+REM If hardware settings are changed, please change this line as well.
+REM See the Mwave README file for instructions.
+SET BLASTER=A220 I5 D1
+SET MWROOT=C:\MWW
+SET LIBPATH=C:\MWW\DLL
+SET PATH=C:\WINDOWS;C:\WINDOWS\COMMAND;E:\ORAWIN95\BIN;f:\msdev\bin;e:\v30\bin.dbg;v:\devt\v30\bin;c:\JavaSDK\Bin;C:\MWW\DLL;
+SET INCLUDE=f:\MSDEV\INCLUDE;F:\MSDEV\MFC\INCLUDE
+SET LIB=F:\MSDEV\LIB;F:\MSDEV\MFC\LIB
+win
+
+------------------------
+
+Now build a file in c:\linux\boot\parms for each Linux config that you have.
+
+For example, my LINDOC3 config is for a docked Thinkpad at runlevel 3 with no
+initrd image, and has a parameter file named LINDOC3.PAR in c:\linux\boot\parms:
+
+-----------------------
+#   LOADLIN @param_file image=other_image root=/dev/other
+#
+#	Linux Console in docking station
+#
+c:\linux\boot\zImage.krn        # First value must be filename of Linux kernel.
+root=/dev/hda3                  # device which gets mounted as root FS
+ro                              # Other kernel arguments go here.
+apm=off
+doc=yes
+3
+-----------------------
+
+The doc=yes parameter is an environment variable used by my init scripts, not
+a kernel argument.
+
+However, the apm=off parameter IS a kernel argument!  APM, at least in my setup,
+causes the kernel to crash when loaded via loadlin (but NOT when loaded via
+LILO). The APM stuff COULD be forced out of the kernel via the kernel compile
+options. Instead, I got an unofficial patch to the APM drivers that allows them
+to be dynamically deactivated via kernel arguments. Whatever you chose to
+document, APM, it seems, MUST be off for setups like mine.
+
+Now make sure C:\MWW\MWCONFIG.REF looks like this:
+
+----------------------
+[NativeDOS]
+Default=SB1.5
+SBInputSource=CD
+SYNTH=FM
+QSound=OFF
+Reverb=OFF
+Chorus=OFF
+ReverbDepth=5
+ChorusDepth=5
+SBInputVolume=5
+SBMainVolume=10
+SBWaveVolume=10
+SBSynthVolume=10
+WaveTableVolume=10
+AudioPowerDriver=ON
+
+[FastCFG]
+Show=No
+HideOption=Off
+-----------------------------
+
+OR the Default= line COULD be
+
+Default=SBPRO
+
+Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure
+the sound modules and voilà - ThinkPad sound with Linux.
+
+Now the gotchas - you can either have CD sound OR Mixers but not both. That's a
+problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why
+this is!
+
+For some reason MPEG3 files, when played through mpg123, sound like they
+are playing at 1/8th speed - not very useful!  If you have ANY insight
+on why this second thing might be happening, I would be grateful.
+
+===========================================================
+    _/      _/_/_/_/
+   _/_/  _/_/     _/
+  _/ _/_/ _/_/_/_/      Martin John Bartlett
+ _/  _/  _/     _/      (martin@nitram.demon.co.uk)
+_/      _/_/_/_/
+       _/
+_/    _/
+ _/_/
+===========================================================
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/solo1 linux-2.5.6/Documentation/sound/oss/solo1
--- linux-2.5.6-pre3/Documentation/sound/oss/solo1	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/solo1	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,70 @@
+Recording
+---------
+
+Recording does not work on the author's card, but there
+is at least one report of it working on later silicon.
+The chip behaves differently than described in the data sheet,
+likely due to a chip bug. Working around this would require
+the help of ESS (for example by publishing an errata sheet),
+but ESS has not done so so far.
+
+Also, the chip only supports 24 bit addresses for recording,
+which means it cannot work on some Alpha mainboards.
+
+
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
+ALaw/uLaw sample formats
+------------------------
+
+This driver does not support the ALaw/uLaw sample formats.
+ALaw is the default mode when opening a sound device
+using OSS/Free. The reason for the lack of support is
+that the hardware does not support these formats, and adding
+conversion routines to the kernel would lead to very ugly
+code in the presence of the mmap interface to the driver.
+And since xquake uses mmap, mmap is considered important :-)
+and no sane application uses ALaw/uLaw these days anyway.
+In short, playing a Sun .au file as follows:
+
+cat my_file.au > /dev/dsp
+
+does not work. Instead, you may use the play script from
+Chris Bagwell's sox-12.14 package (or later, available from the URL
+below) to play many different audio file formats.
+The script automatically determines the audio format
+and does do audio conversions if necessary.
+http://home.sprynet.com/sprynet/cbagwell/projects.html
+
+
+Blocking vs. nonblocking IO
+---------------------------
+
+Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+not only during open, but also during read and write.
+This is an effort to make the sound driver interface more
+regular. Timidity has problems with this; a patch
+is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+(Timidity patched will also run on OSS/Free).
+
+
+MIDI UART
+---------
+
+The driver supports a simple MIDI UART interface, with
+no ioctl's supported.
+
+
+MIDI synthesizer
+----------------
+
+The card has an OPL compatible FM synthesizer.
+
+Thomas Sailer
+t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/sonicvibes linux-2.5.6/Documentation/sound/oss/sonicvibes
--- linux-2.5.6-pre3/Documentation/sound/oss/sonicvibes	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/sonicvibes	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,81 @@
+/proc/sound, /dev/sndstat
+-------------------------
+
+/proc/sound and /dev/sndstat is not supported by the
+driver. To find out whether the driver succeeded loading,
+check the kernel log (dmesg).
+
+
+ALaw/uLaw sample formats
+------------------------
+
+This driver does not support the ALaw/uLaw sample formats.
+ALaw is the default mode when opening a sound device
+using OSS/Free. The reason for the lack of support is
+that the hardware does not support these formats, and adding
+conversion routines to the kernel would lead to very ugly
+code in the presence of the mmap interface to the driver.
+And since xquake uses mmap, mmap is considered important :-)
+and no sane application uses ALaw/uLaw these days anyway.
+In short, playing a Sun .au file as follows:
+
+cat my_file.au > /dev/dsp
+
+does not work. Instead, you may use the play script from
+Chris Bagwell's sox-12.14 package (available from the URL
+below) to play many different audio file formats.
+The script automatically determines the audio format
+and does do audio conversions if necessary.
+http://home.sprynet.com/sprynet/cbagwell/projects.html
+
+
+Blocking vs. nonblocking IO
+---------------------------
+
+Unlike OSS/Free this driver honours the O_NONBLOCK file flag
+not only during open, but also during read and write.
+This is an effort to make the sound driver interface more
+regular. Timidity has problems with this; a patch
+is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
+(Timidity patched will also run on OSS/Free).
+
+
+MIDI UART
+---------
+
+The driver supports a simple MIDI UART interface, with
+no ioctl's supported.
+
+
+MIDI synthesizer
+----------------
+
+The card both has an OPL compatible FM synthesizer as well as
+a wavetable synthesizer.
+
+I haven't managed so far to get the OPL synth running.
+
+Using the wavetable synthesizer requires allocating
+1-4MB of physically contiguous memory, which isn't possible
+currently on Linux without ugly hacks like the bigphysarea
+patch. Therefore, the driver doesn't support wavetable
+synthesis.
+
+
+No support from S3
+------------------
+
+I do not get any support from S3. Therefore, the driver
+still has many problems. For example, although the manual
+states that the chip should be able to access the sample
+buffer anywhere in 32bit address space, I haven't managed to
+get it working with buffers above 16M. Therefore, the card
+has the same disadvantages as ISA soundcards.
+
+Given that the card is also very noisy, and if you haven't
+already bought it, you should strongly opt for one of the
+comparatively priced Ensoniq products.
+
+
+Thomas Sailer
+t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/ultrasound linux-2.5.6/Documentation/sound/oss/ultrasound
--- linux-2.5.6-pre3/Documentation/sound/oss/ultrasound	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/ultrasound	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,30 @@
+modprobe sound
+insmod ad1848
+insmod gus io=* irq=* dma=* ...
+
+This loads the driver for the Gravis Ultrasound family of sound cards.
+
+The gus module takes the following arguments
+
+io		I/O address of the Ultrasound card (eg. io=0x220)
+irq		IRQ of the Sound Blaster card 
+dma     	DMA channel for the Sound Blaster
+dma16   	2nd DMA channel, only needed for full duplex operation
+type		1 for PnP card
+gus16		1 for using 16 bit sampling daughter board
+no_wave_dma	Set to disable DMA usage for wavetable (see note)
+db16		???
+
+
+no_wave_dma option
+
+This option defaults to a value of 0, which allows the Ultrasound wavetable
+DSP to use DMA for for playback and downloading samples. This is the same
+as the old behaviour. If set to 1, no DMA is needed for downloading samples,
+and allows owners of a GUS MAX to make use of simultaneous digital audio
+(/dev/dsp), MIDI, and wavetable playback.
+
+
+If you have problems in recording with GUS MAX, you could try to use
+just one 8 bit DMA channel. Recording will not work with one DMA
+channel if it's a 16 bit one.
diff -urN linux-2.5.6-pre3/Documentation/sound/oss/vwsnd linux-2.5.6/Documentation/sound/oss/vwsnd
--- linux-2.5.6-pre3/Documentation/sound/oss/vwsnd	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/Documentation/sound/oss/vwsnd	Thu Mar  7 18:24:41 2002
@@ -0,0 +1,293 @@
+vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual
+Workstations' onboard audio.
+
+Copyright 1999 Silicon Graphics, Inc.  All rights reserved.
+
+
+At the time of this writing, March 1999, there are two models of
+Visual Workstation, the 320 and the 540.  This document only describes
+those models.  Future Visual Workstation models may have different
+sound capabilities, and this driver will probably not work on those
+boxes.
+
+The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
+codec chip.  The AD1843 is accessed through the Cobalt I/O ASIC, also
+known as Lithium.  This driver programs both both chips.
+
+==============================================================================
+QUICK CONFIGURATION
+
+	# insmod soundcore
+	# insmod vwsnd
+
+==============================================================================
+I/O CONNECTIONS
+
+On the Visual Workstation, only three of the AD1843 inputs are hooked
+up.  The analog line in jacks are connected to the AD1843's AUX1
+input.  The CD audio lines are connected to the AD1843's AUX2 input.
+The microphone jack is connected to the AD1843's MIC input.  The mic
+jack is mono, but the signal is delivered to both the left and right
+MIC inputs.  You can record in stereo from the mic input, but you will
+get the same signal on both channels (within the limits of A/D
+accuracy).  Full scale on the Line input is +/- 2.0 V.  Full scale on
+the MIC input is 20 dB less, or +/- 0.2 V.
+
+The AD1843's LOUT1 outputs are connected to the Line Out jacks.  The
+AD1843's HPOUT outputs are connected to the speaker/headphone jack.
+LOUT2 is not connected.  Line out's maximum level is +/- 2.0 V peak to
+peak.  The speaker/headphone out's maximum is +/- 4.0 V peak to peak.
+
+The AD1843's PCM input channel and one of its output channels (DAC1)
+are connected to Lithium.  The other output channel (DAC2) is not
+connected.
+
+==============================================================================
+CAPABILITIES
+
+The AD1843 has PCM input and output (Pulse Code Modulation, also known
+as wavetable).  PCM input and output can be mono or stereo in any of
+four formats.  The formats are 16 bit signed and 8 bit unsigned,
+u-Law, and A-Law format.  Any sample rate from 4 KHz to 49 KHz is
+available, in 1 Hz increments.
+
+The AD1843 includes an analog mixer that can mix all three input
+signals (line, mic and CD) into the analog outputs.  The mixer has a
+separate gain control and mute switch for each input.
+
+There are two outputs, line out and speaker/headphone out.  They
+always produce the same signal, and the speaker always has 3 dB more
+gain than the line out.  The speaker/headphone output can be muted,
+but this driver does not export that function.
+
+The hardware can sync audio to the video clock, but this driver does
+not have a way to specify syncing to video.
+
+==============================================================================
+PROGRAMMING
+
+This section explains the API supported by the driver.  Also see the
+Open Sound Programming Guide at http://www.opensound.com/pguide/ .
+This section assumes familiarity with that document.
+
+The driver has two interfaces, an I/O interface and a mixer interface.
+There is no MIDI or sequencer capability.
+
+==============================================================================
+PROGRAMMING PCM I/O
+
+The I/O interface is usually accessed as /dev/audio or /dev/dsp.
+Using the standard Open Sound System (OSS) ioctl calls, the sample
+rate, number of channels, and sample format may be set within the
+limitations described above.  The driver supports triggering.  It also
+supports getting the input and output pointers with one-sample
+accuracy.
+
+The SNDCTL_DSP_GETCAP ioctl returns these capabilities.
+
+	DSP_CAP_DUPLEX - driver supports full duplex.
+
+	DSP_CAP_TRIGGER - driver supports triggering.
+
+	DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR
+	and SNDCTL_DSP_GETOPTR are accurate to a few samples.
+
+Memory mapping (mmap) is not implemented.
+
+The driver permits subdivided fragment sizes from 64 to 4096 bytes.
+The number of fragments can be anything from 3 fragments to however
+many fragments fit into 124 kilobytes.  It is up to the user to
+determine how few/small fragments can be used without introducing
+glitches with a given workload.  Linux is not realtime, so we can't
+promise anything.  (sigh...)
+
+When this driver is switched into or out of mu-Law or A-Law mode on
+output, it may produce an audible click.  This is unavoidable.  To
+prevent clicking, use signed 16-bit mode instead, and convert from
+mu-Law or A-Law format in software.
+
+==============================================================================
+PROGRAMMING THE MIXER INTERFACE
+
+The mixer interface is usually accessed as /dev/mixer.  It is accessed
+through ioctls.  The mixer allows the application to control gain or
+mute several audio signal paths, and also allows selection of the
+recording source.
+
+Each of the constants described here can be read using the
+MIXER_READ(SOUND_MIXER_xxx) ioctl.  Those that are not read-only can
+also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl.  In most
+cases, <sys/soundcard.h> defines constants SOUND_MIXER_READ_xxx and
+SOUND_MIXER_WRITE_xxx which work just as well.
+
+SOUND_MIXER_CAPS	Read-only
+
+This is a mask of optional driver capabilities that are implemented.
+This driver's only capability is SOUND_CAP_EXCL_INPUT, which means
+that only one recording source can be active at a time.
+
+SOUND_MIXER_DEVMASK	Read-only
+
+This is a mask of the sound channels.  This driver's channels are PCM,
+LINE, MIC, CD, and RECLEV.
+
+SOUND_MIXER_STEREODEVS	Read-only
+
+This is a mask of which sound channels are capable of stereo.  All
+channels are capable of stereo.  (But see caveat on MIC input in I/O
+CONNECTIONS section above).
+
+SOUND_MIXER_OUTMASK	Read-only
+
+This is a mask of channels that route inputs through to outputs.
+Those are LINE, MIC, and CD.
+
+SOUND_MIXER_RECMASK	Read-only
+
+This is a mask of channels that can be recording sources.  Those are
+PCM, LINE, MIC, CD.
+
+SOUND_MIXER_PCM		Default: 0x5757 (0 dB)
+
+This is the gain control for PCM output.  The left and right channel
+gain are controlled independently.  This gain control has 64 levels,
+which range from -82.5 dB to +12.0 dB in 1.5 dB steps.  Those 64
+levels are mapped onto 100 levels at the ioctl, see below.
+
+SOUND_MIXER_LINE	Default: 0x4a4a (0 dB)
+
+This is the gain control for mixing the Line In source into the
+outputs.  The left and right channel gain are controlled
+independently.  This gain control has 32 levels, which range from
+-34.5 dB to +12.0 dB in 1.5 dB steps.  Those 32 levels are mapped onto
+100 levels at the ioctl, see below.
+
+SOUND_MIXER_MIC		Default: 0x4a4a (0 dB)
+
+This is the gain control for mixing the MIC source into the outputs.
+The left and right channel gain are controlled independently.  This
+gain control has 32 levels, which range from -34.5 dB to +12.0 dB in
+1.5 dB steps.  Those 32 levels are mapped onto 100 levels at the
+ioctl, see below.
+
+SOUND_MIXER_CD		Default: 0x4a4a (0 dB)
+
+This is the gain control for mixing the CD audio source into the
+outputs.  The left and right channel gain are controlled
+independently.  This gain control has 32 levels, which range from
+-34.5 dB to +12.0 dB in 1.5 dB steps.  Those 32 levels are mapped onto
+100 levels at the ioctl, see below.
+
+SOUND_MIXER_RECLEV	 Default: 0 (0 dB)
+
+This is the gain control for PCM input (RECording LEVel).  The left
+and right channel gain are controlled independently.  This gain
+control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB
+steps.  Those 16 levels are mapped onto 100 levels at the ioctl, see
+below.
+
+SOUND_MIXER_RECSRC	 Default: SOUND_MASK_LINE
+
+This is a mask of currently selected PCM input sources (RECording
+SouRCes).  Because the AD1843 can only have a single recording source
+at a time, only one bit at a time can be set in this mask.  The
+allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC,
+or SOUND_MASK_CD.  Selecting SOUND_MASK_PCM sets up internal
+resampling which is useful for loopback testing and for hardware
+sample rate conversion.  But software sample rate conversion is
+probably faster, so I don't know how useful that is.
+
+SOUND_MIXER_OUTSRC	DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD
+
+This is a mask of sources that are currently passed through to the
+outputs.  Those sources whose bits are not set are muted.
+
+==============================================================================
+GAIN CONTROL
+
+There are five gain controls listed above.  Each has 16, 32, or 64
+steps.  Each control has 1.5 dB of gain per step.  Each control is
+stereo.
+
+The OSS defines the argument to a channel gain ioctl as having two
+components, left and right, each of which ranges from 0 to 100.  The
+two components are packed into the same word, with the left side gain
+in the least significant byte, and the right side gain in the second
+least significant byte.  In C, we would say this.
+
+	#include <assert.h>
+
+	...
+
+	 	assert(leftgain >= 0 && leftgain <= 100);
+		assert(rightgain >= 0 && rightgain <= 100);
+		arg = leftgain | rightgain << 8;
+
+So each OSS gain control has 101 steps.  But the hardware has 16, 32,
+or 64 steps.  The hardware steps are spread across the 101 OSS steps
+nearly evenly.  The conversion formulas are like this, given N equals
+16, 32, or 64.
+
+	int round = N/2 - 1;
+	OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1);
+	hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100;
+
+Here is a snippet of C code that will return the left and right gain
+of any channel in dB.  Pass it one of the predefined gain_desc_t
+structures to access any of the five channels' gains.
+
+	typedef struct gain_desc {
+		float min_gain;
+		float gain_step;
+		int nbits;
+		int chan;
+	} gain_desc_t;
+
+	const gain_desc_t gain_pcm    = { -82.5, 1.5, 6, SOUND_MIXER_PCM    };
+	const gain_desc_t gain_line   = { -34.5, 1.5, 5, SOUND_MIXER_LINE   };
+	const gain_desc_t gain_mic    = { -34.5, 1.5, 5, SOUND_MIXER_MIC    };
+	const gain_desc_t gain_cd     = { -34.5, 1.5, 5, SOUND_MIXER_CD     };
+	const gain_desc_t gain_reclev = {   0.0, 1.5, 4, SOUND_MIXER_RECLEV };
+
+	int get_gain_dB(int fd, const gain_desc_t *gp,
+			float *left, float *right)
+	{
+		int word;
+		int lg, rg;
+		int mask = (1 << gp->nbits) - 1;
+
+		if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0)
+			return -1;	/* fail */
+		lg = word & 0xFF;
+		rg = word >> 8 & 0xFF;
+		lg = (lg * mask + mask / 2) / 100;
+		rg = (rg * mask + mask / 2) / 100;
+		*left = gp->min_gain + gp->gain_step * lg;
+		*right = gp->min_gain + gp->gain_step * rg;
+		return 0;
+	}	
+
+And here is the corresponding routine to set a channel's gain in dB.
+
+	int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right)
+	{
+		float max_gain =
+			gp->min_gain + (1 << gp->nbits) * gp->gain_step;
+		float round = gp->gain_step / 2;
+		int mask = (1 << gp->nbits) - 1;
+		int word;
+		int lg, rg;
+
+		if (left < gp->min_gain || right < gp->min_gain)
+			return EINVAL;
+		lg = (left - gp->min_gain + round) / gp->gain_step;
+		rg = (right - gp->min_gain + round) / gp->gain_step;
+		if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits))
+			return EINVAL;
+		lg = (100 * lg + mask / 2) / mask;
+		rg = (100 * rg + mask / 2) / mask;
+		word = lg | rg << 8;
+
+		return ioctl(fd, MIXER_WRITE(gp->chan), &word);
+	}
+
diff -urN linux-2.5.6-pre3/Documentation/sound/solo1 linux-2.5.6/Documentation/sound/solo1
--- linux-2.5.6-pre3/Documentation/sound/solo1	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/Documentation/sound/solo1	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-Recording
----------
-
-Recording does not work on the author's card, but there
-is at least one report of it working on later silicon.
-The chip behaves differently than described in the data sheet,
-likely due to a chip bug. Working around this would require
-the help of ESS (for example by publishing an errata sheet),
-but ESS has not done so so far.
-
-Also, the chip only supports 24 bit addresses for recording,
-which means it cannot work on some Alpha mainboards.
-
-
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (or later, available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card has an OPL compatible FM synthesizer.
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/sonicvibes linux-2.5.6/Documentation/sound/sonicvibes
--- linux-2.5.6-pre3/Documentation/sound/sonicvibes	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/Documentation/sound/sonicvibes	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card both has an OPL compatible FM synthesizer as well as
-a wavetable synthesizer.
-
-I haven't managed so far to get the OPL synth running.
-
-Using the wavetable synthesizer requires allocating
-1-4MB of physically contiguous memory, which isn't possible
-currently on Linux without ugly hacks like the bigphysarea
-patch. Therefore, the driver doesn't support wavetable
-synthesis.
-
-
-No support from S3
-------------------
-
-I do not get any support from S3. Therefore, the driver
-still has many problems. For example, although the manual
-states that the chip should be able to access the sample
-buffer anywhere in 32bit address space, I haven't managed to
-get it working with buffers above 16M. Therefore, the card
-has the same disadvantages as ISA soundcards.
-
-Given that the card is also very noisy, and if you haven't
-already bought it, you should strongly opt for one of the
-comparatively priced Ensoniq products.
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff -urN linux-2.5.6-pre3/Documentation/sound/ultrasound linux-2.5.6/Documentation/sound/ultrasound
--- linux-2.5.6-pre3/Documentation/sound/ultrasound	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/Documentation/sound/ultrasound	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-modprobe sound
-insmod ad1848
-insmod gus io=* irq=* dma=* ...
-
-This loads the driver for the Gravis Ultrasound family of sound cards.
-
-The gus module takes the following arguments
-
-io		I/O address of the Ultrasound card (eg. io=0x220)
-irq		IRQ of the Sound Blaster card 
-dma     	DMA channel for the Sound Blaster
-dma16   	2nd DMA channel, only needed for full duplex operation
-type		1 for PnP card
-gus16		1 for using 16 bit sampling daughter board
-no_wave_dma	Set to disable DMA usage for wavetable (see note)
-db16		???
-
-
-no_wave_dma option
-
-This option defaults to a value of 0, which allows the Ultrasound wavetable
-DSP to use DMA for for playback and downloading samples. This is the same
-as the old behaviour. If set to 1, no DMA is needed for downloading samples,
-and allows owners of a GUS MAX to make use of simultaneous digital audio
-(/dev/dsp), MIDI, and wavetable playback.
-
-
-If you have problems in recording with GUS MAX, you could try to use
-just one 8 bit DMA channel. Recording will not work with one DMA
-channel if it's a 16 bit one.
diff -urN linux-2.5.6-pre3/Documentation/sound/vwsnd linux-2.5.6/Documentation/sound/vwsnd
--- linux-2.5.6-pre3/Documentation/sound/vwsnd	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/Documentation/sound/vwsnd	Wed Dec 31 16:00:00 1969
@@ -1,293 +0,0 @@
-vwsnd - Sound driver for the Silicon Graphics 320 and 540 Visual
-Workstations' onboard audio.
-
-Copyright 1999 Silicon Graphics, Inc.  All rights reserved.
-
-
-At the time of this writing, March 1999, there are two models of
-Visual Workstation, the 320 and the 540.  This document only describes
-those models.  Future Visual Workstation models may have different
-sound capabilities, and this driver will probably not work on those
-boxes.
-
-The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
-codec chip.  The AD1843 is accessed through the Cobalt I/O ASIC, also
-known as Lithium.  This driver programs both both chips.
-
-==============================================================================
-QUICK CONFIGURATION
-
-	# insmod soundcore
-	# insmod vwsnd
-
-==============================================================================
-I/O CONNECTIONS
-
-On the Visual Workstation, only three of the AD1843 inputs are hooked
-up.  The analog line in jacks are connected to the AD1843's AUX1
-input.  The CD audio lines are connected to the AD1843's AUX2 input.
-The microphone jack is connected to the AD1843's MIC input.  The mic
-jack is mono, but the signal is delivered to both the left and right
-MIC inputs.  You can record in stereo from the mic input, but you will
-get the same signal on both channels (within the limits of A/D
-accuracy).  Full scale on the Line input is +/- 2.0 V.  Full scale on
-the MIC input is 20 dB less, or +/- 0.2 V.
-
-The AD1843's LOUT1 outputs are connected to the Line Out jacks.  The
-AD1843's HPOUT outputs are connected to the speaker/headphone jack.
-LOUT2 is not connected.  Line out's maximum level is +/- 2.0 V peak to
-peak.  The speaker/headphone out's maximum is +/- 4.0 V peak to peak.
-
-The AD1843's PCM input channel and one of its output channels (DAC1)
-are connected to Lithium.  The other output channel (DAC2) is not
-connected.
-
-==============================================================================
-CAPABILITIES
-
-The AD1843 has PCM input and output (Pulse Code Modulation, also known
-as wavetable).  PCM input and output can be mono or stereo in any of
-four formats.  The formats are 16 bit signed and 8 bit unsigned,
-u-Law, and A-Law format.  Any sample rate from 4 KHz to 49 KHz is
-available, in 1 Hz increments.
-
-The AD1843 includes an analog mixer that can mix all three input
-signals (line, mic and CD) into the analog outputs.  The mixer has a
-separate gain control and mute switch for each input.
-
-There are two outputs, line out and speaker/headphone out.  They
-always produce the same signal, and the speaker always has 3 dB more
-gain than the line out.  The speaker/headphone output can be muted,
-but this driver does not export that function.
-
-The hardware can sync audio to the video clock, but this driver does
-not have a way to specify syncing to video.
-
-==============================================================================
-PROGRAMMING
-
-This section explains the API supported by the driver.  Also see the
-Open Sound Programming Guide at http://www.opensound.com/pguide/ .
-This section assumes familiarity with that document.
-
-The driver has two interfaces, an I/O interface and a mixer interface.
-There is no MIDI or sequencer capability.
-
-==============================================================================
-PROGRAMMING PCM I/O
-
-The I/O interface is usually accessed as /dev/audio or /dev/dsp.
-Using the standard Open Sound System (OSS) ioctl calls, the sample
-rate, number of channels, and sample format may be set within the
-limitations described above.  The driver supports triggering.  It also
-supports getting the input and output pointers with one-sample
-accuracy.
-
-The SNDCTL_DSP_GETCAP ioctl returns these capabilities.
-
-	DSP_CAP_DUPLEX - driver supports full duplex.
-
-	DSP_CAP_TRIGGER - driver supports triggering.
-
-	DSP_CAP_REALTIME - values returned by SNDCTL_DSP_GETIPTR
-	and SNDCTL_DSP_GETOPTR are accurate to a few samples.
-
-Memory mapping (mmap) is not implemented.
-
-The driver permits subdivided fragment sizes from 64 to 4096 bytes.
-The number of fragments can be anything from 3 fragments to however
-many fragments fit into 124 kilobytes.  It is up to the user to
-determine how few/small fragments can be used without introducing
-glitches with a given workload.  Linux is not realtime, so we can't
-promise anything.  (sigh...)
-
-When this driver is switched into or out of mu-Law or A-Law mode on
-output, it may produce an audible click.  This is unavoidable.  To
-prevent clicking, use signed 16-bit mode instead, and convert from
-mu-Law or A-Law format in software.
-
-==============================================================================
-PROGRAMMING THE MIXER INTERFACE
-
-The mixer interface is usually accessed as /dev/mixer.  It is accessed
-through ioctls.  The mixer allows the application to control gain or
-mute several audio signal paths, and also allows selection of the
-recording source.
-
-Each of the constants described here can be read using the
-MIXER_READ(SOUND_MIXER_xxx) ioctl.  Those that are not read-only can
-also be written using the MIXER_WRITE(SOUND_MIXER_xxx) ioctl.  In most
-cases, <sys/soundcard.h> defines constants SOUND_MIXER_READ_xxx and
-SOUND_MIXER_WRITE_xxx which work just as well.
-
-SOUND_MIXER_CAPS	Read-only
-
-This is a mask of optional driver capabilities that are implemented.
-This driver's only capability is SOUND_CAP_EXCL_INPUT, which means
-that only one recording source can be active at a time.
-
-SOUND_MIXER_DEVMASK	Read-only
-
-This is a mask of the sound channels.  This driver's channels are PCM,
-LINE, MIC, CD, and RECLEV.
-
-SOUND_MIXER_STEREODEVS	Read-only
-
-This is a mask of which sound channels are capable of stereo.  All
-channels are capable of stereo.  (But see caveat on MIC input in I/O
-CONNECTIONS section above).
-
-SOUND_MIXER_OUTMASK	Read-only
-
-This is a mask of channels that route inputs through to outputs.
-Those are LINE, MIC, and CD.
-
-SOUND_MIXER_RECMASK	Read-only
-
-This is a mask of channels that can be recording sources.  Those are
-PCM, LINE, MIC, CD.
-
-SOUND_MIXER_PCM		Default: 0x5757 (0 dB)
-
-This is the gain control for PCM output.  The left and right channel
-gain are controlled independently.  This gain control has 64 levels,
-which range from -82.5 dB to +12.0 dB in 1.5 dB steps.  Those 64
-levels are mapped onto 100 levels at the ioctl, see below.
-
-SOUND_MIXER_LINE	Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the Line In source into the
-outputs.  The left and right channel gain are controlled
-independently.  This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps.  Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_MIC		Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the MIC source into the outputs.
-The left and right channel gain are controlled independently.  This
-gain control has 32 levels, which range from -34.5 dB to +12.0 dB in
-1.5 dB steps.  Those 32 levels are mapped onto 100 levels at the
-ioctl, see below.
-
-SOUND_MIXER_CD		Default: 0x4a4a (0 dB)
-
-This is the gain control for mixing the CD audio source into the
-outputs.  The left and right channel gain are controlled
-independently.  This gain control has 32 levels, which range from
--34.5 dB to +12.0 dB in 1.5 dB steps.  Those 32 levels are mapped onto
-100 levels at the ioctl, see below.
-
-SOUND_MIXER_RECLEV	 Default: 0 (0 dB)
-
-This is the gain control for PCM input (RECording LEVel).  The left
-and right channel gain are controlled independently.  This gain
-control has 16 levels, which range from 0 dB to +22.5 dB in 1.5 dB
-steps.  Those 16 levels are mapped onto 100 levels at the ioctl, see
-below.
-
-SOUND_MIXER_RECSRC	 Default: SOUND_MASK_LINE
-
-This is a mask of currently selected PCM input sources (RECording
-SouRCes).  Because the AD1843 can only have a single recording source
-at a time, only one bit at a time can be set in this mask.  The
-allowable values are SOUND_MASK_PCM, SOUND_MASK_LINE, SOUND_MASK_MIC,
-or SOUND_MASK_CD.  Selecting SOUND_MASK_PCM sets up internal
-resampling which is useful for loopback testing and for hardware
-sample rate conversion.  But software sample rate conversion is
-probably faster, so I don't know how useful that is.
-
-SOUND_MIXER_OUTSRC	DEFAULT: SOUND_MASK_LINE|SOUND_MASK_MIC|SOUND_MASK_CD
-
-This is a mask of sources that are currently passed through to the
-outputs.  Those sources whose bits are not set are muted.
-
-==============================================================================
-GAIN CONTROL
-
-There are five gain controls listed above.  Each has 16, 32, or 64
-steps.  Each control has 1.5 dB of gain per step.  Each control is
-stereo.
-
-The OSS defines the argument to a channel gain ioctl as having two
-components, left and right, each of which ranges from 0 to 100.  The
-two components are packed into the same word, with the left side gain
-in the least significant byte, and the right side gain in the second
-least significant byte.  In C, we would say this.
-
-	#include <assert.h>
-
-	...
-
-	 	assert(leftgain >= 0 && leftgain <= 100);
-		assert(rightgain >= 0 && rightgain <= 100);
-		arg = leftgain | rightgain << 8;
-
-So each OSS gain control has 101 steps.  But the hardware has 16, 32,
-or 64 steps.  The hardware steps are spread across the 101 OSS steps
-nearly evenly.  The conversion formulas are like this, given N equals
-16, 32, or 64.
-
-	int round = N/2 - 1;
-	OSS_gain_steps = (hw_gain_steps * 100 + round) / (N - 1);
-	hw_gain_steps = (OSS_gain_steps * (N - 1) + round) / 100;
-
-Here is a snippet of C code that will return the left and right gain
-of any channel in dB.  Pass it one of the predefined gain_desc_t
-structures to access any of the five channels' gains.
-
-	typedef struct gain_desc {
-		float min_gain;
-		float gain_step;
-		int nbits;
-		int chan;
-	} gain_desc_t;
-
-	const gain_desc_t gain_pcm    = { -82.5, 1.5, 6, SOUND_MIXER_PCM    };
-	const gain_desc_t gain_line   = { -34.5, 1.5, 5, SOUND_MIXER_LINE   };
-	const gain_desc_t gain_mic    = { -34.5, 1.5, 5, SOUND_MIXER_MIC    };
-	const gain_desc_t gain_cd     = { -34.5, 1.5, 5, SOUND_MIXER_CD     };
-	const gain_desc_t gain_reclev = {   0.0, 1.5, 4, SOUND_MIXER_RECLEV };
-
-	int get_gain_dB(int fd, const gain_desc_t *gp,
-			float *left, float *right)
-	{
-		int word;
-		int lg, rg;
-		int mask = (1 << gp->nbits) - 1;
-
-		if (ioctl(fd, MIXER_READ(gp->chan), &word) != 0)
-			return -1;	/* fail */
-		lg = word & 0xFF;
-		rg = word >> 8 & 0xFF;
-		lg = (lg * mask + mask / 2) / 100;
-		rg = (rg * mask + mask / 2) / 100;
-		*left = gp->min_gain + gp->gain_step * lg;
-		*right = gp->min_gain + gp->gain_step * rg;
-		return 0;
-	}	
-
-And here is the corresponding routine to set a channel's gain in dB.
-
-	int set_gain_dB(int fd, const gain_desc_t *gp, float left, float right)
-	{
-		float max_gain =
-			gp->min_gain + (1 << gp->nbits) * gp->gain_step;
-		float round = gp->gain_step / 2;
-		int mask = (1 << gp->nbits) - 1;
-		int word;
-		int lg, rg;
-
-		if (left < gp->min_gain || right < gp->min_gain)
-			return EINVAL;
-		lg = (left - gp->min_gain + round) / gp->gain_step;
-		rg = (right - gp->min_gain + round) / gp->gain_step;
-		if (lg >= (1 << gp->nbits) || rg >= (1 << gp->nbits))
-			return EINVAL;
-		lg = (100 * lg + mask / 2) / mask;
-		rg = (100 * rg + mask / 2) / mask;
-		word = lg | rg << 8;
-
-		return ioctl(fd, MIXER_WRITE(gp->chan), &word);
-	}
-
diff -urN linux-2.5.6-pre3/MAINTAINERS linux-2.5.6/MAINTAINERS
--- linux-2.5.6-pre3/MAINTAINERS	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/MAINTAINERS	Thu Mar  7 18:24:42 2002
@@ -1722,12 +1722,12 @@
 S:	Maintained
 
 USB SERIAL KEYSPAN DRIVER
-P:	Hugh Blemings
-M:	hugh@misc.nu
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
+W:	http://www.kroah.com/linux/
 S:	Maintained
-W:	http://misc.nu/hugh/keyspan/
 
 USB SUBSYSTEM
 P:	Greg Kroah-Hartman
diff -urN linux-2.5.6-pre3/Makefile linux-2.5.6/Makefile
--- linux-2.5.6-pre3/Makefile	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/Makefile	Thu Mar  7 18:24:42 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 6
-EXTRAVERSION =-pre3
+EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -162,6 +162,7 @@
 DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
 DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
 DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
+DRIVERS-$(CONFIG_NET_TULIP) += drivers/net/tulip/tulip_net.o
 DRIVERS-$(CONFIG_PCMCIA_CHRDEV) += drivers/char/pcmcia/pcmcia_char.o
 DRIVERS-$(CONFIG_DIO) += drivers/dio/dio.a
 DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus_all.o
diff -urN linux-2.5.6-pre3/arch/alpha/Makefile linux-2.5.6/arch/alpha/Makefile
--- linux-2.5.6-pre3/arch/alpha/Makefile	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/alpha/Makefile	Thu Mar  7 18:24:42 2002
@@ -45,22 +45,22 @@
     CFLAGS := $(CFLAGS) -mcpu=pca56
     mcpu_done := y
   endif
-  ifeq ($(mcpu_done)$(CONFIG_ALPHA_PYXIS),ny)
-    CFLAGS := $(CFLAGS) -mcpu=ev56
-    mcpu_done := y
-  endif
-  ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS),ny)
-    ifeq ($(have_mcpu_pca56),y)
-      CFLAGS := $(CFLAGS) -mcpu=pca56
-    else
-      CFLAGS := $(CFLAGS) -mcpu=ev56
-    endif
+  ifeq ($(mcpu_done)$(CONFIG_ALPHA_POLARIS)$(have_mcpu_pca56),nyy)
+    CFLAGS := $(CFLAGS) -mcpu=pca56
     mcpu_done := y
   endif
   ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV4),ny)
     CFLAGS := $(CFLAGS) -mcpu=ev4
     mcpu_done := y
   endif
+  ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV56),ny)
+    CFLAGS := $(CFLAGS) -mcpu=ev56
+    mcpu_done := y
+  endif
+  ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV5),ny)
+    CFLAGS := $(CFLAGS) -mcpu=ev5
+    mcpu_done := y
+  endif
   ifeq ($(mcpu_done)$(CONFIG_ALPHA_EV67)$(have_mcpu_ev67),nyy)
     CFLAGS := $(CFLAGS) -mcpu=ev67
     mcpu_done := y
diff -urN linux-2.5.6-pre3/arch/alpha/config.in linux-2.5.6/arch/alpha/config.in
--- linux-2.5.6-pre3/arch/alpha/config.in	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/arch/alpha/config.in	Thu Mar  7 18:24:42 2002
@@ -88,19 +88,43 @@
 then
 	define_bool CONFIG_ALPHA_EB64P y
 fi
-if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-	-o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ]
+if [ "$CONFIG_ALPHA_ALCOR" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
 	define_bool CONFIG_ALPHA_CIA y
+	bool 'EV56 CPU (speed >= 366MHz)?' CONFIG_ALPHA_EV56
 fi
-if [ "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" ]
+if [ "$CONFIG_ALPHA_EB164" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV5 y
+	define_bool CONFIG_ALPHA_CIA y
+fi
+if [ "$CONFIG_ALPHA_PC164" = "y" -o "$CONFIG_ALPHA_TAKARA" = "y" ]
+then
+	define_bool CONFIG_ALPHA_EV5 y
+	define_bool CONFIG_ALPHA_EV56 y
+	define_bool CONFIG_ALPHA_CIA y
+fi
+if [ "$CONFIG_ALPHA_MIKASA" = "y" ]
+then
+	bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO
+	if [ "$CONFIG_ALPHA_PRIMO" = "y" ]
+	then
+		define_bool CONFIG_ALPHA_EV5 y
+		define_bool CONFIG_ALPHA_CIA y
+	else
+		define_bool CONFIG_ALPHA_EV4 y
+		define_bool CONFIG_ALPHA_APECS y
+	fi
+fi
+if [ "$CONFIG_ALPHA_NORITAKE" = "y" ]
 then
 	bool 'EV5 CPU daughtercard (model 5/xxx)?' CONFIG_ALPHA_PRIMO
 	if [ "$CONFIG_ALPHA_PRIMO" = "y" ]
 	then
 		define_bool CONFIG_ALPHA_EV5 y
 		define_bool CONFIG_ALPHA_CIA y
+		bool 'EV56 CPU (speed >= 333MHz)?' CONFIG_ALPHA_EV56
 	else
 		define_bool CONFIG_ALPHA_EV4 y
 		define_bool CONFIG_ALPHA_APECS y
@@ -121,6 +145,7 @@
 	-o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
+	define_bool CONFIG_ALPHA_EV56 y
 	define_bool CONFIG_ALPHA_CIA y
 	define_bool CONFIG_ALPHA_PYXIS y
 fi
@@ -145,10 +170,12 @@
 then
 	define_bool CONFIG_ALPHA_EV5 y
 	define_bool CONFIG_ALPHA_MCPCIA y
+	bool 'EV56 CPU (speed >= 400MHz)?' CONFIG_ALPHA_EV56
 fi
 if [ "$CONFIG_ALPHA_RX164" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV5 y
+	define_bool CONFIG_ALPHA_EV56 y
 	define_bool CONFIG_ALPHA_POLARIS y
 fi
 if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
diff -urN linux-2.5.6-pre3/arch/alpha/kernel/core_irongate.c linux-2.5.6/arch/alpha/kernel/core_irongate.c
--- linux-2.5.6-pre3/arch/alpha/kernel/core_irongate.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/arch/alpha/kernel/core_irongate.c	Thu Mar  7 18:24:42 2002
@@ -455,7 +455,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		irongate_remap_area_pte(pte, address, end - address, 
diff -urN linux-2.5.6-pre3/arch/alpha/kernel/process.c linux-2.5.6/arch/alpha/kernel/process.c
--- linux-2.5.6-pre3/arch/alpha/kernel/process.c	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/alpha/kernel/process.c	Thu Mar  7 18:24:42 2002
@@ -64,7 +64,6 @@
 		while (!need_resched())
 			barrier();
 		schedule();
-		check_pgt_cache();
 	}
 }
 
diff -urN linux-2.5.6-pre3/arch/alpha/mm/init.c linux-2.5.6/arch/alpha/mm/init.c
--- linux-2.5.6-pre3/arch/alpha/mm/init.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/arch/alpha/mm/init.c	Thu Mar  7 18:24:42 2002
@@ -42,12 +42,8 @@
 
 static struct pcb_struct original_pcb;
 
-#ifndef CONFIG_SMP
-struct pgtable_cache_struct quicklists;
-#endif
-
 pgd_t *
-get_pgd_slow(void)
+pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *ret, *init;
 
@@ -69,28 +65,26 @@
 	return ret;
 }
 
-int do_check_pgt_cache(int low, int high)
+pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-	int freed = 0;
-	if(pgtable_cache_size > high) {
-		do {
-			if(pgd_quicklist) {
-				free_pgd_slow(get_pgd_fast());
-				freed++;
-			}
-			if(pmd_quicklist) {
-				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-			if(pte_quicklist) {
-				pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-		} while(pgtable_cache_size > low);
+	pte_t *pte;
+	long timeout = 10;
+
+ retry:
+	pte = (pte_t *) __get_free_page(GFP_KERNEL);
+	if (pte)
+		clear_page(pte);
+	else if (--timeout >= 0) {
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ);
+		goto retry;
 	}
-	return freed;
+
+	return pte;
 }
 
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -145,7 +139,6 @@
 	printk("%ld reserved pages\n",reserved);
 	printk("%ld pages shared\n",shared);
 	printk("%ld pages swap cached\n",cached);
-	printk("%ld pages in page table cache\n",pgtable_cache_size);
 	show_buffers();
 }
 #endif
@@ -260,7 +253,7 @@
 			unsigned long paddr = crb->map[i].pa;
 			crb->map[i].va = vaddr;
 			for (j = 0; j < crb->map[i].count; ++j) {
-				set_pte(pte_offset(pmd, vaddr),
+				set_pte(pte_offset_kernel(pmd, vaddr),
 					mk_pte_phys(paddr, PAGE_KERNEL));
 				paddr += PAGE_SIZE;
 				vaddr += PAGE_SIZE;
diff -urN linux-2.5.6-pre3/arch/i386/defconfig linux-2.5.6/arch/i386/defconfig
--- linux-2.5.6-pre3/arch/i386/defconfig	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/i386/defconfig	Thu Mar  7 18:24:42 2002
@@ -435,12 +435,9 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DE2104X is not set
-# CONFIG_TULIP is not set
-# CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
-# CONFIG_DM9102 is not set
-CONFIG_EEPRO100=y
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -459,7 +456,6 @@
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
-# CONFIG_WINBOND_840 is not set
 # CONFIG_NET_POCKET is not set
 
 #
@@ -473,6 +469,7 @@
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 # CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
@@ -495,6 +492,11 @@
 # CONFIG_WAN is not set
 
 #
+# "Tulip" family network device support
+#
+# CONFIG_NET_TULIP is not set
+
+#
 # PCMCIA network device support
 #
 CONFIG_NET_PCMCIA=y
@@ -508,8 +510,6 @@
 # CONFIG_PCMCIA_AXNET is not set
 # CONFIG_ARCNET_COM20020_CS is not set
 # CONFIG_PCMCIA_IBMTR is not set
-# CONFIG_PCMCIA_XIRCOM is not set
-# CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
 # CONFIG_AIRONET4500_CS is not set
diff -urN linux-2.5.6-pre3/arch/i386/kernel/Makefile linux-2.5.6/arch/i386/kernel/Makefile
--- linux-2.5.6-pre3/arch/i386/kernel/Makefile	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/arch/i386/kernel/Makefile	Thu Mar  7 18:24:42 2002
@@ -14,7 +14,7 @@
 
 O_TARGET := kernel.o
 
-export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o
+export-objs     := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
diff -urN linux-2.5.6-pre3/arch/i386/kernel/apm.c linux-2.5.6/arch/i386/kernel/apm.c
--- linux-2.5.6-pre3/arch/i386/kernel/apm.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/arch/i386/kernel/apm.c	Thu Mar  7 18:24:42 2002
@@ -812,7 +812,7 @@
 
 	t1 = IDLE_LEAKY_MAX;
 
-	while (need_resched()) {
+	while (!need_resched()) {
 		if (use_apm_idle) {
 			unsigned int t;
 
diff -urN linux-2.5.6-pre3/arch/i386/kernel/mpparse.c linux-2.5.6/arch/i386/kernel/mpparse.c
--- linux-2.5.6-pre3/arch/i386/kernel/mpparse.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/arch/i386/kernel/mpparse.c	Thu Mar  7 18:24:42 2002
@@ -37,6 +37,8 @@
 int apic_version [MAX_APICS];
 int mp_bus_id_to_type [MAX_MP_BUSSES];
 int mp_bus_id_to_node [MAX_MP_BUSSES];
+int mp_bus_id_to_local [MAX_MP_BUSSES];
+int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
 
@@ -241,13 +243,17 @@
 static void __init MP_bus_info (struct mpc_config_bus *m)
 {
 	char str[7];
+	int quad;
 
 	memcpy(str, m->mpc_bustype, 6);
 	str[6] = 0;
 	
 	if (clustered_apic_mode) {
-		mp_bus_id_to_node[m->mpc_busid] = translation_table[mpc_record]->trans_quad;
-		printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, mp_bus_id_to_node[m->mpc_busid]);
+		quad = translation_table[mpc_record]->trans_quad;
+		mp_bus_id_to_node[m->mpc_busid] = quad;
+		mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
+		quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid;
+		printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad);
 	} else {
 		Dprintk("Bus #%d is %s\n", m->mpc_busid, str);
 	}
@@ -324,13 +330,14 @@
 
 static void __init MP_translation_info (struct mpc_config_translation *m)
 {
-	printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, 
-		m->trans_quad, m->trans_global, m->trans_local);
+	printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local);
 
 	if (mpc_record >= MAX_MPC_ENTRY) 
 		printk("MAX_MPC_ENTRY exceeded!\n");
 	else
 		translation_table[mpc_record] = m; /* stash this for later */
+	if (m->trans_quad+1 > numnodes)
+		numnodes = m->trans_quad+1;
 }
 
 /*
@@ -495,10 +502,6 @@
 		}
 		++mpc_record;
 	}
-	if (clustered_apic_mode && nr_ioapics > 2) {
-		/* don't initialise IO apics on secondary quads */
-		nr_ioapics = 2;
-	}
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
diff -urN linux-2.5.6-pre3/arch/i386/kernel/pci-pc.c linux-2.5.6/arch/i386/kernel/pci-pc.c
--- linux-2.5.6-pre3/arch/i386/kernel/pci-pc.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/arch/i386/kernel/pci-pc.c	Thu Mar  7 18:24:42 2002
@@ -14,6 +14,7 @@
 
 #include <asm/segment.h>
 #include <asm/io.h>
+#include <asm/smp.h>
 
 #include "pci-i386.h"
 
@@ -26,6 +27,16 @@
 int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL;
 int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL;
 
+#ifdef CONFIG_MULTIQUAD
+#define BUS2QUAD(global) (mp_bus_id_to_node[global])
+#define BUS2LOCAL(global) (mp_bus_id_to_local[global])
+#define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local])
+#else
+#define BUS2QUAD(global) (0)
+#define BUS2LOCAL(global) (global)
+#define QUADLOCAL2BUS(quad,local) (local)
+#endif
+
 /*
  * This interrupt-safe spinlock protects all accesses to PCI
  * configuration space.
@@ -39,10 +50,71 @@
 
 #ifdef CONFIG_PCI_DIRECT
 
+#ifdef CONFIG_MULTIQUAD
+#define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
+	(0x80000000 | (BUS2LOCAL(bus) << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
+
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* CONFIG_MULTIQUAD */
+{
+	unsigned long flags;
+
+	if (!value || (bus > 255) || (dev > 31) || (fn > 7) || (reg > 255))
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+	switch (len) {
+	case 1:
+		*value = inb_quad(0xCFC + (reg & 3), BUS2QUAD(bus));
+		break;
+	case 2:
+		*value = inw_quad(0xCFC + (reg & 2), BUS2QUAD(bus));
+		break;
+	case 4:
+		*value = inl_quad(0xCFC, BUS2QUAD(bus));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* CONFIG_MULTIQUAD */
+{
+	unsigned long flags;
+
+	if ((bus > 255) || (dev > 31) || (fn > 7) || (reg > 255)) 
+		return -EINVAL;
+
+	spin_lock_irqsave(&pci_config_lock, flags);
+
+	outl_quad(PCI_CONF1_ADDRESS(bus, dev, fn, reg), 0xCF8, BUS2QUAD(bus));
+
+	switch (len) {
+	case 1:
+		outb_quad((u8)value, 0xCFC + (reg & 3), BUS2QUAD(bus));
+		break;
+	case 2:
+		outw_quad((u16)value, 0xCFC + (reg & 2), BUS2QUAD(bus));
+		break;
+	case 4:
+		outl_quad((u32)value, 0xCFC, BUS2QUAD(bus));
+		break;
+	}
+
+	spin_unlock_irqrestore(&pci_config_lock, flags);
+
+	return 0;
+}
+
+#else /* !CONFIG_MULTIQUAD */
 #define PCI_CONF1_ADDRESS(bus, dev, fn, reg) \
 	(0x80000000 | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
 
-static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value)
+static int pci_conf1_read (int seg, int bus, int dev, int fn, int reg, int len, u32 *value) /* !CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
@@ -70,7 +142,7 @@
 	return 0;
 }
 
-static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value)
+static int pci_conf1_write (int seg, int bus, int dev, int fn, int reg, int len, u32 value) /* !CONFIG_MULTIQUAD */
 {
 	unsigned long flags;
 
@@ -98,6 +170,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_MULTIQUAD */
+
 #undef PCI_CONF1_ADDRESS
 
 static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
@@ -1017,6 +1091,8 @@
 	 */
 	int pxb, reg;
 	u8 busno, suba, subb;
+	int quad = BUS2QUAD(d->bus->number);
+
 	printk("PCI: Searching for i450NX host bridges on %s\n", d->slot_name);
 	reg = 0xd0;
 	for(pxb=0; pxb<2; pxb++) {
@@ -1025,9 +1101,9 @@
 		pci_read_config_byte(d, reg++, &subb);
 		DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb);
 		if (busno)
-			pci_scan_bus(busno, pci_root_ops, NULL);	/* Bus A */
+			pci_scan_bus(QUADLOCAL2BUS(quad,busno), pci_root_ops, NULL);	/* Bus A */
 		if (suba < subb)
-			pci_scan_bus(suba+1, pci_root_ops, NULL);	/* Bus B */
+			pci_scan_bus(QUADLOCAL2BUS(quad,suba+1), pci_root_ops, NULL);	/* Bus B */
 	}
 	pcibios_last_bus = -1;
 }
@@ -1199,6 +1275,8 @@
 
 void __init pcibios_init(void)
 {
+	int quad;
+
 	if (!pci_root_ops)
 		pcibios_config_init();
 	if (!pci_root_ops) {
@@ -1208,6 +1286,14 @@
 
 	printk("PCI: Probing PCI hardware\n");
 	pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
+	if (clustered_apic_mode && (numnodes > 1)) {
+		for (quad = 1; quad < numnodes; ++quad) {
+			printk("Scanning PCI bus %d for quad %d\n", 
+				QUADLOCAL2BUS(quad,0), quad);
+			pci_scan_bus(QUADLOCAL2BUS(quad,0), 
+				pci_root_ops, NULL);
+		}
+	}
 
 	pcibios_irq_init();
 	pcibios_fixup_peer_bridges();
diff -urN linux-2.5.6-pre3/arch/i386/kernel/smpboot.c linux-2.5.6/arch/i386/kernel/smpboot.c
--- linux-2.5.6-pre3/arch/i386/kernel/smpboot.c	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/i386/kernel/smpboot.c	Thu Mar  7 18:24:42 2002
@@ -1012,11 +1012,14 @@
 {
 	int apicid, cpu, bit;
 
-        if (clustered_apic_mode) {
-                /* remap the 1st quad's 256k range for cross-quad I/O */
-                xquad_portio = ioremap (XQUAD_PORTIO_BASE, XQUAD_PORTIO_LEN);
-                printk("Cross quad port I/O vaddr 0x%08lx, len %08lx\n",
-                        (u_long) xquad_portio, (u_long) XQUAD_PORTIO_LEN);
+        if (clustered_apic_mode && (numnodes > 1)) {
+                printk("Remapping cross-quad port I/O for %d quads\n",
+			numnodes);
+                printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
+                        (u_long) xquad_portio, 
+			(u_long) numnodes * XQUAD_PORTIO_LEN);
+                xquad_portio = ioremap (XQUAD_PORTIO_BASE, 
+			numnodes * XQUAD_PORTIO_LEN);
         }
 
 #ifdef CONFIG_MTRR
diff -urN linux-2.5.6-pre3/arch/i386/kernel/time.c linux-2.5.6/arch/i386/kernel/time.c
--- linux-2.5.6-pre3/arch/i386/kernel/time.c	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/i386/kernel/time.c	Thu Mar  7 18:24:42 2002
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
diff -urN linux-2.5.6-pre3/arch/i386/kernel/traps.c linux-2.5.6/arch/i386/kernel/traps.c
--- linux-2.5.6-pre3/arch/i386/kernel/traps.c	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/arch/i386/kernel/traps.c	Thu Mar  7 18:24:42 2002
@@ -557,6 +557,8 @@
 		 * allowing programs to debug themselves without the ptrace()
 		 * interface.
 		 */
+		if ((regs->xcs & 3) == 0)
+			goto clear_TF;
 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
 			goto clear_TF;
 	}
diff -urN linux-2.5.6-pre3/arch/mips64/sgi-ip27/ip27-rtc.c linux-2.5.6/arch/mips64/sgi-ip27/ip27-rtc.c
--- linux-2.5.6-pre3/arch/mips64/sgi-ip27/ip27-rtc.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/arch/mips64/sgi-ip27/ip27-rtc.c	Thu Mar  7 18:24:42 2002
@@ -201,7 +201,8 @@
 	    KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0;
 
 	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
-	misc_register(&rtc_dev);
+	if (misc_register(&rtc_dev))
+		return -ENODEV;
 	create_proc_read_entry ("rtc", 0, NULL, rtc_read_proc, NULL);
 
 	save_flags(flags);
diff -urN linux-2.5.6-pre3/arch/ppc/iSeries/rtc.c linux-2.5.6/arch/ppc/iSeries/rtc.c
--- linux-2.5.6-pre3/arch/ppc/iSeries/rtc.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/arch/ppc/iSeries/rtc.c	Thu Mar  7 18:24:42 2002
@@ -192,7 +192,8 @@
 
 static int __init rtc_init(void)
 {
-	misc_register(&rtc_dev);
+	if (misc_register(&rtc_dev))
+		return -ENODEV;
 	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
 
 	printk(KERN_INFO "iSeries Real Time Clock Driver v" RTC_VERSION "\n");
diff -urN linux-2.5.6-pre3/arch/x86_64/kernel/entry.S linux-2.5.6/arch/x86_64/kernel/entry.S
--- linux-2.5.6-pre3/arch/x86_64/kernel/entry.S	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/arch/x86_64/kernel/entry.S	Thu Mar  7 18:24:42 2002
@@ -102,8 +102,6 @@
  * A newly forked process directly context switches into this.
  */ 	
 ENTRY(ret_from_fork)
-	movq %rbx, %rdi
-	call schedule_tail
 	GET_THREAD_INFO(%rcx)
 	bt $TIF_SYSCALL_TRACE,threadinfo_flags(%rcx)
 	jc rff_trace
diff -urN linux-2.5.6-pre3/drivers/acorn/char/mouse_ps2.c linux-2.5.6/drivers/acorn/char/mouse_ps2.c
--- linux-2.5.6-pre3/drivers/acorn/char/mouse_ps2.c	Thu Mar  7 18:24:24 2002
+++ linux-2.5.6/drivers/acorn/char/mouse_ps2.c	Thu Mar  7 18:24:42 2002
@@ -271,7 +271,8 @@
 	iomd_writeb(0, IOMD_MSECTL);
 	iomd_writeb(8, IOMD_MSECTL);
   
-	misc_register(&psaux_mouse);
+	if (misc_register(&psaux_mouse))
+		return -ENODEV;
 	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
 	memset(queue, 0, sizeof(*queue));
 	queue->head = queue->tail = 0;
diff -urN linux-2.5.6-pre3/drivers/acorn/scsi/ecoscsi.c linux-2.5.6/drivers/acorn/scsi/ecoscsi.c
--- linux-2.5.6-pre3/drivers/acorn/scsi/ecoscsi.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/drivers/acorn/scsi/ecoscsi.c	Thu Mar  7 18:24:42 2002
@@ -125,7 +125,11 @@
     }
 
     NCR5380_init(instance, 0);
-    request_region (instance->io_port, instance->n_io_port, "ecoscsi");
+    if (request_region (instance->io_port, instance->n_io_port, "ecoscsi") == NULL)
+    	{
+	scsi_unregister(instance);
+	return 0;
+	}
 
     if (instance->irq != IRQ_NONE)
 	if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
diff -urN linux-2.5.6-pre3/drivers/char/acquirewdt.c linux-2.5.6/drivers/char/acquirewdt.c
--- linux-2.5.6-pre3/drivers/char/acquirewdt.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/drivers/char/acquirewdt.c	Thu Mar  7 18:24:43 2002
@@ -207,7 +207,8 @@
 	printk("WDT driver for Acquire single board computer initialising.\n");
 
 	spin_lock_init(&acq_lock);
-	misc_register(&acq_miscdev);
+	if (misc_register(&acq_miscdev))
+		return -ENODEV;
 	request_region(WDT_STOP, 1, "Acquire WDT");
 	request_region(WDT_START, 1, "Acquire WDT");
 	register_reboot_notifier(&acq_notifier);
diff -urN linux-2.5.6-pre3/drivers/ide/ide.c linux-2.5.6/drivers/ide/ide.c
--- linux-2.5.6-pre3/drivers/ide/ide.c	Thu Mar  7 18:24:27 2002
+++ linux-2.5.6/drivers/ide/ide.c	Thu Mar  7 18:24:43 2002
@@ -1435,7 +1435,7 @@
 				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
 				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
 				{
-					ide_stall_queue(best, min(t, 10 * WAIT_MIN_SLEEP));
+					ide_stall_queue(best, min(t, 10L * WAIT_MIN_SLEEP));
 					goto repeat;
 				}
 			} while ((drive = drive->next) != best);
diff -urN linux-2.5.6-pre3/drivers/isdn/act2000/act2000_isa.c linux-2.5.6/drivers/isdn/act2000/act2000_isa.c
--- linux-2.5.6-pre3/drivers/isdn/act2000/act2000_isa.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/drivers/isdn/act2000/act2000_isa.c	Thu Mar  7 18:24:44 2002
@@ -178,7 +178,8 @@
                 card->flags &= ~ACT2000_FLAGS_PVALID;
         }
         if (!check_region(portbase, ISA_REGION)) {
-                request_region(portbase, ACT2000_PORTLEN, card->regname);
+                if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
+			return -EIO;
                 card->port = portbase;
                 card->flags |= ACT2000_FLAGS_PVALID;
                 return 0;
diff -urN linux-2.5.6-pre3/drivers/net/3c503.c linux-2.5.6/drivers/net/3c503.c
--- linux-2.5.6-pre3/drivers/net/3c503.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/3c503.c	Thu Mar  7 18:24:44 2002
@@ -692,9 +692,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_EL2_CARDS) "i");
-MODULE_PARM_DESC(io, "EtherLink II I/O base address(es)");
-MODULE_PARM_DESC(irq, "EtherLink II IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr, "EtherLink II tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)");
+MODULE_DESCRIPTION("3Com ISA EtherLink II, II/16 (3c503, 3c503/16) driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -742,7 +744,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/3c505.c linux-2.5.6/drivers/net/3c505.c
--- linux-2.5.6-pre3/drivers/net/3c505.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/drivers/net/3c505.c	Thu Mar  7 18:24:45 2002
@@ -1350,87 +1350,6 @@
 	}
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
-
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
-{
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		sprintf(info.bus_info, "ISA 0x%lx", dev->base_addr);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
-}
-
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * Process the various out-of-band ioctls passed to this driver.
- */
-
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	int rc = 0;
-
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
-}
- 
-
 /******************************************************
  *
  * initialise Etherlink Plus board
diff -urN linux-2.5.6-pre3/drivers/net/3c509.c linux-2.5.6/drivers/net/3c509.c
--- linux-2.5.6-pre3/drivers/net/3c509.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/drivers/net/3c509.c	Thu Mar  7 18:24:45 2002
@@ -1103,14 +1103,15 @@
 MODULE_PARM(irq,"1-8i");
 MODULE_PARM(xcvr,"1-8i");
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM_DESC(debug, "EtherLink III debug level (0-6)");
-MODULE_PARM_DESC(irq, "EtherLink III IRQ number(s) (assigned)");
-MODULE_PARM_DESC(xcvr,"EtherLink III tranceiver(s) (0=internal, 1=external)");
-MODULE_PARM_DESC(max_interrupt_work, "EtherLink III maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "debug level (0-6)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_PARM_DESC(xcvr,"tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
 #ifdef __ISAPNP__
 MODULE_PARM(nopnp, "i");
-MODULE_PARM_DESC(nopnp, "EtherLink III disable ISA PnP support (0-1)");
+MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 #endif	/* __ISAPNP__ */
+MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
 
 int
 init_module(void)
diff -urN linux-2.5.6-pre3/drivers/net/8139cp.c linux-2.5.6/drivers/net/8139cp.c
--- linux-2.5.6-pre3/drivers/net/8139cp.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/8139cp.c	Thu Mar  7 18:24:45 2002
@@ -2,6 +2,7 @@
 /*
 	Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com>
 
+	Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com) [tg3.c]
 	Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
 	Copyright 2001 Manfred Spraul				    [natsemi.c]
 	Copyright 1999-2001 by Donald Becker.			    [natsemi.c]
@@ -29,8 +30,8 @@
 	* Consider Rx interrupt mitigation using TimerIntr
 	* Implement 8139C+ statistics dump; maybe not...
 	  h/w stats can be reset only by software reset
-	* Rx checksumming
 	* Tx checksumming
+	* Handle netif_rx return value
 	* ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
 	* Investigate using skb->priority with h/w VLAN priority
 	* Investigate using High Priority Tx Queue with skb->priority
@@ -38,8 +39,8 @@
 	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
         * Implement Tx software interrupt mitigation via
 	          Tx descriptor bit
-	* Determine correct value for CP_{MIN,MAX}_MTU, instead of
-	  using conservative guesses.
+	* The real minimum of CP_MIN_MTU is 4 bytes.  However,
+	  for this to be supported, one must(?) turn on packet padding.
 
  */
 
@@ -48,8 +49,10 @@
 #define DRV_RELDATE		"Feb 27, 2002"
 
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/compiler.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
@@ -57,9 +60,15 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+#define CP_VLAN_TAG_USED 0
+#define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
+	do { (tx_desc)->opts2 = 0; } while (0)
+
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -110,8 +119,8 @@
 #define TX_TIMEOUT		(6*HZ)
 
 /* hardware minimum and maximum for a single frame's data payload */
-#define CP_MIN_MTU		60	/* FIXME: this is a guess */
-#define CP_MAX_MTU		1500	/* FIXME: this is a guess */
+#define CP_MIN_MTU		60	/* TODO: allow lower, but pad */
+#define CP_MAX_MTU		4096
 
 enum {
 	/* NIC register offsets */
@@ -153,12 +162,17 @@
 	IPCS		= (1 << 18), /* Calculate IP checksum */
 	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */
 	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */
+	TxVlanTag	= (1 << 17), /* Add VLAN tag */
+	RxVlanTagged	= (1 << 16), /* Rx VLAN tag available */
 	IPFail		= (1 << 15), /* IP checksum failed */
 	UDPFail		= (1 << 14), /* UDP/IP checksum failed */
 	TCPFail		= (1 << 13), /* TCP/IP checksum failed */
 	NormalTxPoll	= (1 << 6),  /* One or more normal Tx packets to send */
 	PID1		= (1 << 17), /* 2 protocol id bits:  0==non-IP, */
 	PID0		= (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
+	RxProtoTCP	= 2,
+	RxProtoUDP	= 1,
+	RxProtoIP	= 3,
 	TxFIFOUnder	= (1 << 25), /* Tx FIFO underrun */
 	TxOWC		= (1 << 22), /* Tx Out-of-window collision */
 	TxLinkFail	= (1 << 21), /* Link failed during Tx of packet */
@@ -208,6 +222,7 @@
 	TxOn		= (1 << 2),  /* Tx mode enable */
 
 	/* C+ mode command register */
+	RxVlanOn	= (1 << 6),  /* Rx VLAN de-tagging enable */
 	RxChkSum	= (1 << 5),  /* Rx checksum offload enable */
 	PCIMulRW	= (1 << 3),  /* Enable PCI read/write multiple */
 	CpRxOn		= (1 << 1),  /* Rx mode enable */
@@ -278,6 +293,10 @@
 	unsigned		rx_buf_sz;
 	dma_addr_t		ring_dma;
 
+#if CP_VLAN_TAG_USED
+	struct vlan_group	*vlgrp;
+#endif
+
 	u32			msg_enable;
 
 	struct net_device_stats net_stats;
@@ -335,14 +354,21 @@
 		cp->rx_buf_sz = PKT_BUF_SZ;
 }
 
-static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb)
+static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb,
+			      struct cp_desc *desc)
 {
 	skb->protocol = eth_type_trans (skb, cp->dev);
 
 	cp->net_stats.rx_packets++;
 	cp->net_stats.rx_bytes += skb->len;
 	cp->dev->last_rx = jiffies;
-	netif_rx (skb);
+
+#if CP_VLAN_TAG_USED
+	if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
+		vlan_hwaccel_rx(skb, cp->vlgrp, desc->opts2 & 0xffff);
+	} else
+#endif
+		netif_rx(skb);
 }
 
 static void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
@@ -425,13 +451,26 @@
 			cp_rx_err_acct(cp, rx_tail, status, len);
 			dev_kfree_skb_irq(copy_skb);
 		} else
-			cp_rx_skb(cp, copy_skb);
+			cp_rx_skb(cp, copy_skb, &cp->rx_ring[rx_tail]);
 		cp->frag_skb = NULL;
 	} else {
 		cp->frag_skb = copy_skb;
 	}
 }
 
+static inline unsigned int cp_rx_csum_ok (u32 status)
+{
+	unsigned int protocol = (status >> 16) & 0x3;
+	
+	if (likely((protocol == RxProtoTCP) && (!(status & TCPFail))))
+		return 1;
+	else if ((protocol == RxProtoUDP) && (!(status & UDPFail)))
+		return 1;
+	else if ((protocol == RxProtoIP) && (!(status & IPFail)))
+		return 1;
+	return 0;
+}
+
 static void cp_rx (struct cp_private *cp)
 {
 	unsigned rx_tail = cp->rx_tail;
@@ -441,13 +480,15 @@
 		u32 status, len;
 		dma_addr_t mapping;
 		struct sk_buff *skb, *new_skb;
+		struct cp_desc *desc;
 		unsigned buflen;
 
 		skb = cp->rx_skb[rx_tail].skb;
 		if (!skb)
 			BUG();
-		rmb();
-		status = le32_to_cpu(cp->rx_ring[rx_tail].opts1);
+
+		desc = &cp->rx_ring[rx_tail];
+		status = le32_to_cpu(desc->opts1);
 		if (status & DescOwn)
 			break;
 
@@ -480,7 +521,13 @@
 
 		pci_unmap_single(cp->pdev, mapping,
 				 buflen, PCI_DMA_FROMDEVICE);
-		skb->ip_summed = CHECKSUM_NONE;
+
+		/* Handle checksum offloading for incoming packets. */
+		if (cp_rx_csum_ok(status))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+
 		skb_put(skb, len);
 
 		mapping =
@@ -489,15 +536,14 @@
 				       buflen, PCI_DMA_FROMDEVICE);
 		cp->rx_skb[rx_tail].skb = new_skb;
 
-		cp_rx_skb(cp, skb);
+		cp_rx_skb(cp, skb, desc);
 
 rx_next:
 		if (rx_tail == (CP_RX_RING_SIZE - 1))
-			cp->rx_ring[rx_tail].opts1 =
-				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+			desc->opts1 = cpu_to_le32(DescOwn | RingEnd |
+						  cp->rx_buf_sz);
 		else
-			cp->rx_ring[rx_tail].opts1 =
-				cpu_to_le32(DescOwn | cp->rx_buf_sz);
+			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		cp->rx_ring[rx_tail].opts2 = 0;
 		cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
 		rx_tail = NEXT_RX(rx_tail);
@@ -606,6 +652,9 @@
 	struct cp_private *cp = dev->priv;
 	unsigned entry;
 	u32 eor;
+#if CP_VLAN_TAG_USED
+	u32 vlan_tag = 0;
+#endif
 
 	spin_lock_irq(&cp->lock);
 
@@ -615,6 +664,11 @@
 		return 1;
 	}
 
+#if CP_VLAN_TAG_USED
+	if (cp->vlgrp && vlan_tx_tag_present(skb))
+		vlan_tag = TxVlanTag | vlan_tx_tag_get(skb);
+#endif
+
 	entry = cp->tx_head;
 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 	if (skb_shinfo(skb)->nr_frags == 0) {
@@ -624,7 +678,7 @@
 		len = skb->len;
 		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
-		txd->opts2 = 0;
+		CP_VLAN_TX_TAG(txd, vlan_tag);
 		txd->addr_lo = cpu_to_le32(mapping);
 		wmb();
 
@@ -677,7 +731,7 @@
 				ctrl |= LastFrag;
 
 			txd = &cp->tx_ring[entry];
-			txd->opts2 = 0;
+			CP_VLAN_TX_TAG(txd, vlan_tag);
 			txd->addr_lo = cpu_to_le32(mapping);
 			wmb();
 
@@ -691,7 +745,7 @@
 		}
 
 		txd = &cp->tx_ring[first_entry];
-		txd->opts2 = 0;
+		CP_VLAN_TX_TAG(txd, vlan_tag);
 		txd->addr_lo = cpu_to_le32(first_mapping);
 		wmb();
 
@@ -826,7 +880,7 @@
 static inline void cp_start_hw (struct cp_private *cp)
 {
 	cpw8(Cmd, RxOn | TxOn);
-	cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn);
+	cpw16(CpCmd, PCIMulRW | RxChkSum | CpRxOn | CpTxOn);
 }
 
 static void cp_init_hw (struct cp_private *cp)
@@ -1171,7 +1225,30 @@
 	return rc;
 }
 
+#if CP_VLAN_TAG_USED
+static int cp_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct cp_private *cp = dev->priv;
+
+	spin_lock_irq(&cp->lock);
+	cp->vlgrp = grp;
+	cpw16(CpCmd, cpr16(CpCmd) | RxVlanOn);
+	spin_unlock_irq(&cp->lock);
 
+	return 0;
+}
+
+static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct cp_private *cp = dev->priv;
+
+	spin_lock_irq(&cp->lock);
+	cpw16(CpCmd, cpr16(CpCmd) & ~RxVlanOn);
+	if (cp->vlgrp)
+		cp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_irq(&cp->lock);
+}
+#endif
 
 /* Serial EEPROM section. */
 
@@ -1337,6 +1414,11 @@
 #ifdef CP_TX_CHECKSUM
 	dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
 #endif
+#if CP_VLAN_TAG_USED
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register = cp_vlan_rx_register;
+	dev->vlan_rx_kill_vid = cp_vlan_rx_kill_vid;
+#endif
 
 	dev->irq = pdev->irq;
 
diff -urN linux-2.5.6-pre3/drivers/net/Config.help linux-2.5.6/drivers/net/Config.help
--- linux-2.5.6-pre3/drivers/net/Config.help	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/Config.help	Thu Mar  7 18:24:45 2002
@@ -797,6 +797,14 @@
   Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
   <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
 
+CONFIG_TIGON3
+  This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  This is
+  recommended.  The module will be called tg3.o.
+
 CONFIG_MYRI_SBUS
   This driver supports MyriCOM Sbus gigabit Ethernet cards.
 
@@ -1325,71 +1333,6 @@
   <file:Documentation/networking/net-modules.txt>.  The module will be
   called apricot.o.
 
-CONFIG_DE4X5
-  This is support for the DIGITAL series of PCI/EISA Ethernet cards.
-  These include the DE425, DE434, DE435, DE450 and DE500 models.  If
-  you have a network card of this type, say Y and read the
-  Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>. More specific
-  information is contained in
-  <file:Documentation/networking/de4x5.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called de4x5.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-CONFIG_DE2104X
-  This driver is developed for the SMC EtherPower series Ethernet
-  cards and also works with cards based on the DECchip
-  21040 (Tulip series) chips.  Some LinkSys PCI cards are
-  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
-  (smc9332dst), you can also try the driver for "Generic DECchip"
-  cards, above.  However, most people with a network card of this type
-  will say Y here.) Do read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  More specific
-  information is contained in
-  <file:Documentation/DocBook/tulip-user.tmpl>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tulip.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-CONFIG_TULIP
-  This driver is developed for the SMC EtherPower series Ethernet
-  cards and also works with cards based on the DECchip 
-  21040/21041/21140 (Tulip series) chips.  Some LinkSys PCI cards are
-  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
-  (smc9332dst), you can also try the driver for "Generic DECchip"
-  cards, above.  However, most people with a network card of this type
-  will say Y here.) Do read the Ethernet-HOWTO, available from
-  <http://www.linuxdoc.org/docs.html#howto>.  More specific
-  information is contained in 
-  <file:Documentation/networking/tulip.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called tulip.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
-CONFIG_TULIP_MWI
-  This configures your Tulip card specifically for the card and
-  system cache line size type you are using.
-
-  This is experimental code, not yet tested on many boards.
-
-  If unsure, say N.
-
-CONFIG_TULIP_MMIO
-  Use PCI shared memory for the NIC registers, rather than going through
-  the Tulip's PIO (programmed I/O ports).  Faster, but could produce
-  obscure bugs if your mainboard has memory controller timing issues.
-  If in doubt, say N.
-
 CONFIG_DGRS
   This is support for the Digi International RightSwitch series of
   PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
@@ -1474,18 +1417,6 @@
 
   If unsure, say N.
 
-CONFIG_DM9102
-  This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
-  Davicom (<http://www.davicom.com.tw/>).  If you have such a network
-  (Ethernet) card, say Y.  Some information is contained in the file
-  <file:Documentation/networking/dmfe.txt>.
-
-  This driver is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called dmfe.o.  If you want to compile it as a
-  module, say M here and read <file:Documentation/modules.txt> as well
-  as <file:Documentation/networking/net-modules.txt>.
-
 CONFIG_ES3210
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available from
@@ -1517,12 +1448,6 @@
   More specific information and updates are available from
   <http://www.scyld.com/network/sundance.html>.
 
-CONFIG_WINBOND_840
-  This driver is for the Winbond W89c840 chip.  It also works with
-  the TX9882 chip on the Compex RL100-ATX board.
-  More specific information and updates are available from
-  <http://www.scyld.com/network/drivers.html>.
-
 CONFIG_ZNET
   The Zenith Z-Note notebook computer has a built-in network
   (Ethernet) card, and this is the Linux driver for it. Note that the
diff -urN linux-2.5.6-pre3/drivers/net/Config.in linux-2.5.6/drivers/net/Config.in
--- linux-2.5.6-pre3/drivers/net/Config.in	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/Config.in	Thu Mar  7 18:24:45 2002
@@ -148,25 +148,18 @@
    fi
    if [ "$CONFIG_NET_PCI" = "y" ]; then
       dep_tristate '    AMD PCnet32 PCI support' CONFIG_PCNET32 $CONFIG_PCI
-      dep_tristate '    Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI $CONFIG_EXPERIMENTAL
+      dep_tristate '    Adaptec Starfire/DuraLAN support' CONFIG_ADAPTEC_STARFIRE $CONFIG_PCI
       if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
 	 dep_tristate '    Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200 $CONFIG_EXPERIMENTAL
       fi
 
       dep_tristate '    Apricot Xen-II on board Ethernet' CONFIG_APRICOT $CONFIG_ISA
       dep_tristate '    CS89x0 support' CONFIG_CS89x0 $CONFIG_ISA
-      dep_tristate '    Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)' CONFIG_DE2104X $CONFIG_PCI $CONFIG_EXPERIMENTAL
-      dep_tristate '    DECchip Tulip (dc2114x) PCI support' CONFIG_TULIP $CONFIG_PCI
-      if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
-         dep_bool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
-         bool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
-      fi
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
-         tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
          tristate '    Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
       fi
-      dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
-      dep_tristate '    EtherExpressPro/100 support' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (eepro100, original Becker driver)' CONFIG_EEPRO100 $CONFIG_PCI
+      dep_tristate '    EtherExpressPro/100 support (e100, Alternate Intel driver)' CONFIG_E100 $CONFIG_PCI
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
@@ -190,7 +183,6 @@
       fi
       dep_tristate '    VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI
       dep_mbool '      Use MMIO instead of PIO (EXPERIMENTAL)' CONFIG_VIA_RHINE_MMIO $CONFIG_VIA_RHINE $CONFIG_EXPERIMENTAL
-      dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
       if [ "$CONFIG_OBSOLETE" = "y" ]; then
 	 dep_bool '    Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET $CONFIG_ISA
       fi
@@ -237,6 +229,7 @@
 dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI
 dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI $CONFIG_EXPERIMENTAL
 dep_tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN $CONFIG_PCI
+dep_tristate 'Broadcom Tigon3 support' CONFIG_TIGON3 $CONFIG_PCI
 
 endmenu
 
@@ -326,6 +319,9 @@
 
 source drivers/net/wan/Config.in
 
+if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" -o "$CONFIG_CARDBUS" != "n" ]; then
+   source drivers/net/tulip/Config.in
+fi
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/net/pcmcia/Config.in
 fi
diff -urN linux-2.5.6-pre3/drivers/net/Makefile linux-2.5.6/drivers/net/Makefile
--- linux-2.5.6-pre3/drivers/net/Makefile	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/Makefile	Thu Mar  7 18:24:45 2002
@@ -8,7 +8,7 @@
 obj-n           :=
 obj-            :=
 
-mod-subdirs     := appletalk arcnet fc irda tokenring pcmcia wireless wan
+mod-subdirs     := appletalk arcnet fc irda tokenring tulip pcmcia wireless wan
 
 O_TARGET := net.o
 
@@ -21,10 +21,9 @@
 list-multi	:=	rcpci.o
 rcpci-objs	:=	rcpci45.o rclanmtl.o
 
-ifeq ($(CONFIG_TULIP),y)
-  obj-y += tulip/tulip.o
+ifeq ($(CONFIG_E100),y)
+  obj-y += e100/e100.o
 endif
-
 ifeq ($(CONFIG_E1000),y)
   obj-y += e1000/e1000.o
 endif
@@ -35,7 +34,8 @@
 
 subdir-$(CONFIG_NET_PCMCIA) += pcmcia
 subdir-$(CONFIG_NET_WIRELESS) += wireless
-subdir-$(CONFIG_TULIP) += tulip
+subdir-$(CONFIG_NET_TULIP) += tulip
+subdir-$(CONFIG_E100) += e100
 subdir-$(CONFIG_E1000) += e1000
 subdir-$(CONFIG_IRDA) += irda
 subdir-$(CONFIG_TR) += tokenring
@@ -74,7 +74,6 @@
 obj-$(CONFIG_TLAN) += tlan.o
 obj-$(CONFIG_EPIC100) += epic100.o mii.o
 obj-$(CONFIG_SIS900) += sis900.o
-obj-$(CONFIG_DM9102) += dmfe.o
 obj-$(CONFIG_YELLOWFIN) += yellowfin.o
 obj-$(CONFIG_ACENIC) += acenic.o
 obj-$(CONFIG_VETH) += veth.o
@@ -82,6 +81,7 @@
 obj-$(CONFIG_NS83820) += ns83820.o
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o mii.o
+obj-$(CONFIG_TIGON3) += tg3.o
 
 ifeq ($(CONFIG_SK98LIN),y)
 obj-y += sk98lin/sk98lin.o
@@ -104,7 +104,7 @@
 obj-$(CONFIG_AIRONET4500_PROC)	+= aironet4500_proc.o
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_proc.o
 
-obj-$(CONFIG_WINBOND_840) += winbond-840.o mii.o
+obj-$(CONFIG_WINBOND_840) += mii.o
 obj-$(CONFIG_SUNDANCE) += sundance.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
@@ -176,8 +176,6 @@
 obj-$(CONFIG_DEPCA) += depca.o
 obj-$(CONFIG_EWRK3) += ewrk3.o
 obj-$(CONFIG_ATP) += atp.o
-obj-$(CONFIG_DE4X5) += de4x5.o
-obj-$(CONFIG_DE2104X) += de2104x.o
 obj-$(CONFIG_NI5010) += ni5010.o
 obj-$(CONFIG_NI52) += ni52.o
 obj-$(CONFIG_NI65) += ni65.o
diff -urN linux-2.5.6-pre3/drivers/net/ac3200.c linux-2.5.6/drivers/net/ac3200.c
--- linux-2.5.6-pre3/drivers/net/ac3200.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/drivers/net/ac3200.c	Thu Mar  7 18:24:45 2002
@@ -346,9 +346,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_AC32_CARDS) "i");
-MODULE_PARM_DESC(io, "ac3200 I/O base adress(es)");
-MODULE_PARM_DESC(irq, "ac3200 IRQ number(s)");
-MODULE_PARM_DESC(mem, "ac3200 Memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base adress(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "Memory base address(es)");
+MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
@@ -395,7 +397,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/de2104x.c linux-2.5.6/drivers/net/de2104x.c
--- linux-2.5.6-pre3/drivers/net/de2104x.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/de2104x.c	Wed Dec 31 16:00:00 1969
@@ -1,2240 +0,0 @@
-/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. */
-/*
-	Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
-
-	Copyright 1994, 1995 Digital Equipment Corporation.	    [de4x5.c]
-	Written/copyright 1994-2001 by Donald Becker.		    [tulip.c]
-
-	This software may be used and distributed according to the terms of
-	the GNU General Public License (GPL), incorporated herein by reference.
-	Drivers based on or derived from this code fall under the GPL and must
-	retain the authorship, copyright and license notice.  This file is not
-	a complete program and may only be used when the entire operating
-	system is licensed under the GPL.
-
-	See the file COPYING in this distribution for more information.
-
-	TODO, in rough priority order:
-	* Support forcing media type with a module parameter,
-	  like dl2k.c/sundance.c
-	* Constants (module parms?) for Rx work limit
-	* Complete reset on PciErr
-	* Jumbo frames / dev->change_mtu
-	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
-	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
-	* Implement Tx software interrupt mitigation via
-	  Tx descriptor bit
-
- */
-
-#define DRV_NAME		"de2104x"
-#define DRV_VERSION		"0.5.4"
-#define DRV_RELDATE		"Jan 1, 2002"
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/compiler.h>
-#include <linux/sched.h>
-#include <linux/rtnetlink.h>
-#include <linux/crc32.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-
-/* These identify the driver base version and may not be removed. */
-static char version[] __initdata =
-KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
-
-MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
-MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");
-MODULE_LICENSE("GPL");
-
-static int debug = -1;
-MODULE_PARM (debug, "i");
-MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
-        || defined(__sparc_) || defined(__ia64__) \
-        || defined(__sh__) || defined(__mips__)
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-MODULE_PARM (rx_copybreak, "i");
-MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");
-
-#define PFX			DRV_NAME ": "
-
-#define DE_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
-				 NETIF_MSG_PROBE 	| \
-				 NETIF_MSG_LINK		| \
-				 NETIF_MSG_TIMER	| \
-				 NETIF_MSG_IFDOWN	| \
-				 NETIF_MSG_IFUP		| \
-				 NETIF_MSG_RX_ERR	| \
-				 NETIF_MSG_TX_ERR)
-
-#define DE_RX_RING_SIZE		64
-#define DE_TX_RING_SIZE		64
-#define DE_RING_BYTES		\
-		((sizeof(struct de_desc) * DE_RX_RING_SIZE) +	\
-		(sizeof(struct de_desc) * DE_TX_RING_SIZE))
-#define NEXT_TX(N)		(((N) + 1) & (DE_TX_RING_SIZE - 1))
-#define NEXT_RX(N)		(((N) + 1) & (DE_RX_RING_SIZE - 1))
-#define TX_BUFFS_AVAIL(CP)					\
-	(((CP)->tx_tail <= (CP)->tx_head) ?			\
-	  (CP)->tx_tail + (DE_TX_RING_SIZE - 1) - (CP)->tx_head :	\
-	  (CP)->tx_tail - (CP)->tx_head - 1)
-
-#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
-#define RX_OFFSET		2
-
-#define DE_SETUP_SKB		((struct sk_buff *) 1)
-#define DE_DUMMY_SKB		((struct sk_buff *) 2)
-#define DE_SETUP_FRAME_WORDS	96
-#define DE_EEPROM_WORDS		256
-#define DE_EEPROM_SIZE		(DE_EEPROM_WORDS * sizeof(u16))
-#define DE_MAX_MEDIA		5
-
-#define DE_MEDIA_TP_AUTO	0
-#define DE_MEDIA_BNC		1
-#define DE_MEDIA_AUI		2
-#define DE_MEDIA_TP		3
-#define DE_MEDIA_TP_FD		4
-#define DE_MEDIA_INVALID	DE_MAX_MEDIA
-#define DE_MEDIA_FIRST		0
-#define DE_MEDIA_LAST		(DE_MAX_MEDIA - 1)
-#define DE_AUI_BNC		(SUPPORTED_AUI | SUPPORTED_BNC)
-
-#define DE_TIMER_LINK		(60 * HZ)
-#define DE_TIMER_NO_LINK	(5 * HZ)
-
-#define DE_NUM_REGS		16
-#define DE_REGS_SIZE		(DE_NUM_REGS * sizeof(u32))
-#define DE_REGS_VER		1
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT		(6*HZ)
-
-#define DE_UNALIGNED_16(a)	(u16)(get_unaligned((u16 *)(a)))
-
-/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
-   to support a pre-NWay full-duplex signaling mechanism using short frames.
-   No one knows what it should be, but if left at its default value some
-   10base2(!) packets trigger a full-duplex-request interrupt. */
-#define FULL_DUPLEX_MAGIC	0x6969
-
-enum {
-	/* NIC registers */
-	BusMode			= 0x00,
-	TxPoll			= 0x08,
-	RxPoll			= 0x10,
-	RxRingAddr		= 0x18,
-	TxRingAddr		= 0x20,
-	MacStatus		= 0x28,
-	MacMode			= 0x30,
-	IntrMask		= 0x38,
-	RxMissed		= 0x40,
-	ROMCmd			= 0x48,
-	CSR11			= 0x58,
-	SIAStatus		= 0x60,
-	CSR13			= 0x68,
-	CSR14			= 0x70,
-	CSR15			= 0x78,
-	PCIPM			= 0x40,
-
-	/* BusMode bits */
-	CmdReset		= (1 << 0),
-	CacheAlign16		= 0x00008000,
-	BurstLen4		= 0x00000400,
-
-	/* Rx/TxPoll bits */
-	NormalTxPoll		= (1 << 0),
-	NormalRxPoll		= (1 << 0),
-
-	/* Tx/Rx descriptor status bits */
-	DescOwn			= (1 << 31),
-	RxError			= (1 << 15),
-	RxErrLong		= (1 << 7),
-	RxErrCRC		= (1 << 1),
-	RxErrFIFO		= (1 << 0),
-	RxErrRunt		= (1 << 11),
-	RxErrFrame		= (1 << 14),
-	RingEnd			= (1 << 25),
-	FirstFrag		= (1 << 29),
-	LastFrag		= (1 << 30),
-	TxError			= (1 << 15),
-	TxFIFOUnder		= (1 << 1),
-	TxLinkFail		= (1 << 2) | (1 << 10) | (1 << 11),
-	TxMaxCol		= (1 << 8),
-	TxOWC			= (1 << 9),
-	TxJabber		= (1 << 14),
-	SetupFrame		= (1 << 27),
-	TxSwInt			= (1 << 31),
-
-	/* MacStatus bits */
-	IntrOK			= (1 << 16),
-	IntrErr			= (1 << 15),
-	RxIntr			= (1 << 6),
-	RxEmpty			= (1 << 7),
-	TxIntr			= (1 << 0),
-	TxEmpty			= (1 << 2),
-	PciErr			= (1 << 13),
-	TxState			= (1 << 22) | (1 << 21) | (1 << 20),
-	RxState			= (1 << 19) | (1 << 18) | (1 << 17),
-	LinkFail		= (1 << 12),
-	LinkPass		= (1 << 4),
-	RxStopped		= (1 << 8),
-	TxStopped		= (1 << 1),
-
-	/* MacMode bits */
-	TxEnable		= (1 << 13),
-	RxEnable		= (1 << 1),
-	RxTx			= TxEnable | RxEnable,
-	FullDuplex		= (1 << 9),
-	AcceptAllMulticast	= (1 << 7),
-	AcceptAllPhys		= (1 << 6),
-	BOCnt			= (1 << 5),
-	MacModeClear		= (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) |
-				  RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast,
-
-	/* ROMCmd bits */
-	EE_SHIFT_CLK		= 0x02,	/* EEPROM shift clock. */
-	EE_CS			= 0x01,	/* EEPROM chip select. */
-	EE_DATA_WRITE		= 0x04,	/* Data from the Tulip to EEPROM. */
-	EE_WRITE_0		= 0x01,
-	EE_WRITE_1		= 0x05,
-	EE_DATA_READ		= 0x08,	/* Data from the EEPROM chip. */
-	EE_ENB			= (0x4800 | EE_CS),
-
-	/* The EEPROM commands include the alway-set leading bit. */
-	EE_READ_CMD		= 6,
-
-	/* RxMissed bits */
-	RxMissedOver		= (1 << 16),
-	RxMissedMask		= 0xffff,
-
-	/* SROM-related bits */
-	SROMC0InfoLeaf		= 27,
-	MediaBlockMask		= 0x3f,
-	MediaCustomCSRs		= (1 << 6),
-	
-	/* PCIPM bits */
-	PM_Sleep		= (1 << 31),
-	PM_Snooze		= (1 << 30),
-	PM_Mask			= PM_Sleep | PM_Snooze,
-	
-	/* SIAStatus bits */
-	NWayState		= (1 << 14) | (1 << 13) | (1 << 12),
-	NWayRestart		= (1 << 12),
-	NonselPortActive	= (1 << 9),
-	LinkFailStatus		= (1 << 2),
-	NetCxnErr		= (1 << 1),
-};
-
-static const u32 de_intr_mask =
-	IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty |
-	LinkPass | LinkFail | PciErr;
-
-/*
- * Set the programmable burst length to 4 longwords for all:
- * DMA errors result without these values. Cache align 16 long.
- */
-static const u32 de_bus_mode = CacheAlign16 | BurstLen4;
-
-struct de_srom_media_block {
-	u8			opts;
-	u16			csr13;
-	u16			csr14;
-	u16			csr15;
-} __attribute__((packed));
-
-struct de_srom_info_leaf {
-	u16			default_media;
-	u8			n_blocks;
-	u8			unused;
-} __attribute__((packed));
-
-struct de_desc {
-	u32			opts1;
-	u32			opts2;
-	u32			addr1;
-	u32			addr2;
-};
-
-struct media_info {
-	u16			type;	/* DE_MEDIA_xxx */
-	u16			csr13;
-	u16			csr14;
-	u16			csr15;
-};
-
-struct ring_info {
-	struct sk_buff		*skb;
-	dma_addr_t		mapping;
-};
-
-struct de_private {
-	unsigned		tx_head;
-	unsigned		tx_tail;
-	unsigned		rx_tail;
-
-	void			*regs;
-	struct net_device	*dev;
-	spinlock_t		lock;
-
-	struct de_desc		*rx_ring;
-	struct de_desc		*tx_ring;
-	struct ring_info	tx_skb[DE_TX_RING_SIZE];
-	struct ring_info	rx_skb[DE_RX_RING_SIZE];
-	unsigned		rx_buf_sz;
-	dma_addr_t		ring_dma;
-
-	u32			msg_enable;
-
-	struct net_device_stats net_stats;
-
-	struct pci_dev		*pdev;
-	u32			macmode;
-
-	u16			setup_frame[DE_SETUP_FRAME_WORDS];
-
-	u32			media_type;
-	u32			media_supported;
-	u32			media_advertise;
-	struct media_info	media[DE_MAX_MEDIA];
-	struct timer_list	media_timer;
-
-	u8			*ee_data;
-	unsigned		board_idx;
-	unsigned		de21040 : 1;
-	unsigned		media_lock : 1;
-};
-
-
-static void de_set_rx_mode (struct net_device *dev);
-static void de_tx (struct de_private *de);
-static void de_clean_rings (struct de_private *de);
-static void de_media_interrupt (struct de_private *de, u32 status);
-static void de21040_media_timer (unsigned long data);
-static void de21041_media_timer (unsigned long data);
-static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
-
-
-static struct pci_device_id de_pci_tbl[] __initdata = {
-	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-	{ },
-};
-MODULE_DEVICE_TABLE(pci, de_pci_tbl);
-
-static const char * const media_name[DE_MAX_MEDIA] = {
-	"10baseT auto",
-	"BNC",
-	"AUI",
-	"10baseT-HD",
-	"10baseT-FD"
-};
-
-/* 21040 transceiver register settings:
- * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/
-static u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, };
-static u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, };
-static u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, };
-
-/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/
-static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
-static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x6F3F, 0x6F3D, };
-static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
-
-
-static inline unsigned long
-msec_to_jiffies(unsigned long ms)
-{
-	return (((ms)*HZ+999)/1000);
-}
-
-
-#define dr32(reg)		readl(de->regs + (reg))
-#define dw32(reg,val)		writel((val), de->regs + (reg))
-
-
-static void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
-			    u32 status, u32 len)
-{
-	if (netif_msg_rx_err (de))
-		printk (KERN_DEBUG
-			"%s: rx err, slot %d status 0x%x len %d\n",
-			de->dev->name, rx_tail, status, len);
-
-	if ((status & 0x38000300) != 0x0300) {
-		/* Ingore earlier buffers. */
-		if ((status & 0xffff) != 0x7fff) {
-			if (netif_msg_rx_err(de))
-				printk(KERN_WARNING "%s: Oversized Ethernet frame "
-					   "spanned multiple buffers, status %8.8x!\n",
-					   de->dev->name, status);
-			de->net_stats.rx_length_errors++;
-		}
-	} else if (status & RxError) {
-		/* There was a fatal error. */
-		de->net_stats.rx_errors++; /* end of a packet.*/
-		if (status & 0x0890) de->net_stats.rx_length_errors++;
-		if (status & RxErrCRC) de->net_stats.rx_crc_errors++;
-		if (status & RxErrFIFO) de->net_stats.rx_fifo_errors++;
-	}
-}
-
-static void de_rx (struct de_private *de)
-{
-	unsigned rx_tail = de->rx_tail;
-	unsigned rx_work = DE_RX_RING_SIZE;
-	unsigned drop = 0;
-	int rc;
-
-	while (rx_work--) {
-		u32 status, len;
-		dma_addr_t mapping;
-		struct sk_buff *skb, *copy_skb;
-		unsigned copying_skb, buflen;
-
-		skb = de->rx_skb[rx_tail].skb;
-		if (!skb)
-			BUG();
-		rmb();
-		status = le32_to_cpu(de->rx_ring[rx_tail].opts1);
-		if (status & DescOwn)
-			break;
-
-		len = ((status >> 16) & 0x7ff) - 4;
-		mapping = de->rx_skb[rx_tail].mapping;
-
-		if (unlikely(drop)) {
-			de->net_stats.rx_dropped++;
-			goto rx_next;
-		}
-
-		if (unlikely((status & 0x38008300) != 0x0300)) {
-			de_rx_err_acct(de, rx_tail, status, len);
-			goto rx_next;
-		}
-
-		copying_skb = (len <= rx_copybreak);
-
-		if (unlikely(netif_msg_rx_status(de)))
-			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
-			       de->dev->name, rx_tail, status, len,
-			       copying_skb);
-
-		buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz;
-		copy_skb = dev_alloc_skb (buflen);
-		if (unlikely(!copy_skb)) {
-			de->net_stats.rx_dropped++;
-			drop = 1;
-			rx_work = 100;
-			goto rx_next;
-		}
-		copy_skb->dev = de->dev;
-
-		if (!copying_skb) {
-			pci_unmap_single(de->pdev, mapping,
-					 buflen, PCI_DMA_FROMDEVICE);
-			skb_put(skb, len);
-
-			mapping =
-			de->rx_skb[rx_tail].mapping =
-				pci_map_single(de->pdev, copy_skb->tail,
-					       buflen, PCI_DMA_FROMDEVICE);
-			de->rx_skb[rx_tail].skb = copy_skb;
-		} else {
-			pci_dma_sync_single(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
-			skb_reserve(copy_skb, RX_OFFSET);
-			memcpy(skb_put(copy_skb, len), skb->tail, len);
-
-			/* We'll reuse the original ring buffer. */
-			skb = copy_skb;
-		}
-
-		skb->protocol = eth_type_trans (skb, de->dev);
-
-		de->net_stats.rx_packets++;
-		de->net_stats.rx_bytes += skb->len;
-		de->dev->last_rx = jiffies;
-		rc = netif_rx (skb);
-		if (rc == NET_RX_DROP)
-			drop = 1;
-
-rx_next:
-		de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn);
-		if (rx_tail == (DE_RX_RING_SIZE - 1))
-			de->rx_ring[rx_tail].opts2 =
-				cpu_to_le32(RingEnd | de->rx_buf_sz);
-		else
-			de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz);
-		de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping);
-		rx_tail = NEXT_RX(rx_tail);
-	}
-
-	if (!rx_work)
-		printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name);
-
-	de->rx_tail = rx_tail;
-}
-
-static void de_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_instance;
-	struct de_private *de = dev->priv;
-	u32 status;
-
-	status = dr32(MacStatus);
-	if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF))
-		return;
-
-	if (netif_msg_intr(de))
-		printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n",
-		        dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail);
-
-	dw32(MacStatus, status);
-
-	if (status & (RxIntr | RxEmpty)) {
-		de_rx(de);
-		if (status & RxEmpty)
-			dw32(RxPoll, NormalRxPoll);
-	}
-
-	spin_lock(&de->lock);
-
-	if (status & (TxIntr | TxEmpty))
-		de_tx(de);
-
-	if (status & (LinkPass | LinkFail))
-		de_media_interrupt(de, status);
-
-	spin_unlock(&de->lock);
-
-	if (status & PciErr) {
-		u16 pci_status;
-
-		pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
-		pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
-		printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n",
-		       dev->name, status, pci_status);
-	}
-}
-
-static void de_tx (struct de_private *de)
-{
-	unsigned tx_head = de->tx_head;
-	unsigned tx_tail = de->tx_tail;
-
-	while (tx_tail != tx_head) {
-		struct sk_buff *skb;
-		u32 status;
-
-		rmb();
-		status = le32_to_cpu(de->tx_ring[tx_tail].opts1);
-		if (status & DescOwn)
-			break;
-
-		skb = de->tx_skb[tx_tail].skb;
-		if (!skb)
-			BUG();
-		if (unlikely(skb == DE_DUMMY_SKB))
-			goto next;
-
-		if (unlikely(skb == DE_SETUP_SKB)) {
-			pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
-					 sizeof(de->setup_frame), PCI_DMA_TODEVICE);
-			goto next;
-		}
-
-		pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
-				 skb->len, PCI_DMA_TODEVICE);
-
-		if (status & LastFrag) {
-			if (status & TxError) {
-				if (netif_msg_tx_err(de))
-					printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
-					       de->dev->name, status);
-				de->net_stats.tx_errors++;
-				if (status & TxOWC)
-					de->net_stats.tx_window_errors++;
-				if (status & TxMaxCol)
-					de->net_stats.tx_aborted_errors++;
-				if (status & TxLinkFail)
-					de->net_stats.tx_carrier_errors++;
-				if (status & TxFIFOUnder)
-					de->net_stats.tx_fifo_errors++;
-			} else {
-				de->net_stats.tx_packets++;
-				de->net_stats.tx_bytes += skb->len;
-				if (netif_msg_tx_done(de))
-					printk(KERN_DEBUG "%s: tx done, slot %d\n", de->dev->name, tx_tail);
-			}
-			dev_kfree_skb_irq(skb);
-		}
-
-next:
-		de->tx_skb[tx_tail].skb = NULL;
-
-		tx_tail = NEXT_TX(tx_tail);
-	}
-
-	de->tx_tail = tx_tail;
-
-	if (netif_queue_stopped(de->dev) && (TX_BUFFS_AVAIL(de) > (DE_TX_RING_SIZE / 4)))
-		netif_wake_queue(de->dev);
-}
-
-static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	unsigned int entry, tx_free;
-	u32 mapping, len, flags = FirstFrag | LastFrag;
-	struct de_desc *txd;
-
-	spin_lock_irq(&de->lock);
-
-	tx_free = TX_BUFFS_AVAIL(de);
-	if (tx_free == 0) {
-		netif_stop_queue(dev);
-		spin_unlock_irq(&de->lock);
-		return 1;
-	}
-	tx_free--;
-
-	entry = de->tx_head;
-
-	txd = &de->tx_ring[entry];
-
-	len = skb->len;
-	mapping = pci_map_single(de->pdev, skb->data, len, PCI_DMA_TODEVICE);
-	if (entry == (DE_TX_RING_SIZE - 1))
-		flags |= RingEnd;
-	if (!tx_free || (tx_free == (DE_TX_RING_SIZE / 2)))
-		flags |= TxSwInt;
-	flags |= len;
-	txd->opts2 = cpu_to_le32(flags);
-	txd->addr1 = cpu_to_le32(mapping);
-
-	de->tx_skb[entry].skb = skb;
-	de->tx_skb[entry].mapping = mapping;
-	wmb();
-
-	txd->opts1 = cpu_to_le32(DescOwn);
-	wmb();
-
-	de->tx_head = NEXT_TX(entry);
-	if (netif_msg_tx_queued(de))
-		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
-		       dev->name, entry, skb->len);
-
-	if (tx_free == 0)
-		netif_stop_queue(dev);
-
-	spin_unlock_irq(&de->lock);
-
-	/* Trigger an immediate transmit demand. */
-	dw32(TxPoll, NormalTxPoll);
-	dev->trans_start = jiffies;
-
-	return 0;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   Note that we only use exclusion around actually queueing the
-   new frame, not around filling de->setup_frame.  This is non-deterministic
-   when re-entered but still correct. */
-
-#undef set_bit_le
-#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
-
-static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	u16 hash_table[32];
-	struct dev_mc_list *mclist;
-	int i;
-	u16 *eaddrs;
-
-	memset(hash_table, 0, sizeof(hash_table));
-	set_bit_le(255, hash_table); 			/* Broadcast entry */
-	/* This should work on big-endian machines as well. */
-	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-	     i++, mclist = mclist->next) {
-		int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
-
-		set_bit_le(index, hash_table);
-
-		for (i = 0; i < 32; i++) {
-			*setup_frm++ = hash_table[i];
-			*setup_frm++ = hash_table[i];
-		}
-		setup_frm = &de->setup_frame[13*6];
-	}
-
-	/* Fill the final entry with our physical address. */
-	eaddrs = (u16 *)dev->dev_addr;
-	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-}
-
-static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	struct dev_mc_list *mclist;
-	int i;
-	u16 *eaddrs;
-
-	/* We have <= 14 addresses so we can use the wonderful
-	   16 address perfect filtering of the Tulip. */
-	for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
-	     i++, mclist = mclist->next) {
-		eaddrs = (u16 *)mclist->dmi_addr;
-		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
-		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
-		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
-	}
-	/* Fill the unused entries with the broadcast address. */
-	memset(setup_frm, 0xff, (15-i)*12);
-	setup_frm = &de->setup_frame[15*6];
-
-	/* Fill the final entry with our physical address. */
-	eaddrs = (u16 *)dev->dev_addr;
-	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
-	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
-	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
-}
-
-
-static void __de_set_rx_mode (struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	u32 macmode;
-	unsigned int entry;
-	u32 mapping;
-	struct de_desc *txd;
-	struct de_desc *dummy_txd = NULL;
-
-	macmode = de->macmode & ~(AcceptAllMulticast | AcceptAllPhys);
-
-	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
-		macmode |= AcceptAllMulticast | AcceptAllPhys;
-		goto out;
-	}
-
-	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to filter well -- accept all multicasts. */
-		macmode |= AcceptAllMulticast;
-		goto out;
-	}
-
-	/* Note that only the low-address shortword of setup_frame is valid!
-	   The values are doubled for big-endian architectures. */
-	if (dev->mc_count > 14)	/* Must use a multicast hash table. */
-		build_setup_frame_hash (de->setup_frame, dev);
-	else
-		build_setup_frame_perfect (de->setup_frame, dev);
-
-	/*
-	 * Now add this frame to the Tx list.
-	 */
-
-	entry = de->tx_head;
-
-	/* Avoid a chip errata by prefixing a dummy entry. */
-	if (entry != 0) {
-		de->tx_skb[entry].skb = DE_DUMMY_SKB;
-
-		dummy_txd = &de->tx_ring[entry];
-		dummy_txd->opts2 = (entry == (DE_TX_RING_SIZE - 1)) ?
-				   cpu_to_le32(RingEnd) : 0;
-		dummy_txd->addr1 = 0;
-
-		/* Must set DescOwned later to avoid race with chip */
-
-		entry = NEXT_TX(entry);
-	}
-
-	de->tx_skb[entry].skb = DE_SETUP_SKB;
-	de->tx_skb[entry].mapping = mapping =
-	    pci_map_single (de->pdev, de->setup_frame,
-			    sizeof (de->setup_frame), PCI_DMA_TODEVICE);
-
-	/* Put the setup frame on the Tx list. */
-	txd = &de->tx_ring[entry];
-	if (entry == (DE_TX_RING_SIZE - 1))
-		txd->opts2 = cpu_to_le32(SetupFrame | RingEnd | sizeof (de->setup_frame));
-	else
-		txd->opts2 = cpu_to_le32(SetupFrame | sizeof (de->setup_frame));
-	txd->addr1 = cpu_to_le32(mapping);
-	wmb();
-
-	txd->opts1 = cpu_to_le32(DescOwn);
-	wmb();
-
-	if (dummy_txd) {
-		dummy_txd->opts1 = cpu_to_le32(DescOwn);
-		wmb();
-	}
-
-	de->tx_head = NEXT_TX(entry);
-
-	if (TX_BUFFS_AVAIL(de) < 0)
-		BUG();
-	if (TX_BUFFS_AVAIL(de) == 0)
-		netif_stop_queue(dev);
-
-	/* Trigger an immediate transmit demand. */
-	dw32(TxPoll, NormalTxPoll);
-
-out:
-	if (macmode != de->macmode) {
-		dw32 (MacMode, macmode);
-		de->macmode = macmode;
-	}
-}
-
-static void de_set_rx_mode (struct net_device *dev)
-{
-	unsigned long flags;
-	struct de_private *de = dev->priv;
-
-	spin_lock_irqsave (&de->lock, flags);
-	__de_set_rx_mode(dev);
-	spin_unlock_irqrestore (&de->lock, flags);
-}
-
-static inline void de_rx_missed(struct de_private *de, u32 rx_missed)
-{
-	if (unlikely(rx_missed & RxMissedOver))
-		de->net_stats.rx_missed_errors += RxMissedMask;
-	else
-		de->net_stats.rx_missed_errors += (rx_missed & RxMissedMask);
-}
-
-static void __de_get_stats(struct de_private *de)
-{
-	u32 tmp = dr32(RxMissed); /* self-clearing */
-
-	de_rx_missed(de, tmp);
-}
-
-static struct net_device_stats *de_get_stats(struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-
-	/* The chip only need report frame silently dropped. */
-	spin_lock_irq(&de->lock);
- 	if (netif_running(dev) && netif_device_present(dev))
- 		__de_get_stats(de);
-	spin_unlock_irq(&de->lock);
-
-	return &de->net_stats;
-}
-
-static inline int de_is_running (struct de_private *de)
-{
-	return (dr32(MacStatus) & (RxState | TxState)) ? 1 : 0;
-}
-
-static void de_stop_rxtx (struct de_private *de)
-{
-	u32 macmode;
-	unsigned int work = 1000;
-
-	macmode = dr32(MacMode);
-	if (macmode & RxTx) {
-		dw32(MacMode, macmode & ~RxTx);
-		dr32(MacMode);
-	}
-
-	while (--work > 0) {
-		if (!de_is_running(de))
-			return;
-		cpu_relax();
-	}
-	
-	printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name);
-}
-
-static inline void de_start_rxtx (struct de_private *de)
-{
-	u32 macmode;
-
-	macmode = dr32(MacMode);
-	if ((macmode & RxTx) != RxTx) {
-		dw32(MacMode, macmode | RxTx);
-		dr32(MacMode);
-	}
-}
-
-static void de_stop_hw (struct de_private *de)
-{
-
-	udelay(5);
-	dw32(IntrMask, 0);
-
-	de_stop_rxtx(de);
-
-	dw32(MacStatus, dr32(MacStatus));
-
-	udelay(10);
-
-	de->rx_tail = 0;
-	de->tx_head = de->tx_tail = 0;
-}
-
-static void de_link_up(struct de_private *de)
-{
-	if (!netif_carrier_ok(de->dev)) {
-		netif_carrier_on(de->dev);
-		if (netif_msg_link(de))
-			printk(KERN_INFO "%s: link up, media %s\n",
-			       de->dev->name, media_name[de->media_type]);
-	}
-}
-
-static void de_link_down(struct de_private *de)
-{
-	if (netif_carrier_ok(de->dev)) {
-		netif_carrier_off(de->dev);
-		if (netif_msg_link(de))
-			printk(KERN_INFO "%s: link down\n", de->dev->name);
-	}
-}
-
-static void de_set_media (struct de_private *de)
-{
-	unsigned media = de->media_type;
-
-	if (de_is_running(de))
-		BUG();
-
-	if (de->de21040)
-		dw32(CSR11, FULL_DUPLEX_MAGIC);
-	dw32(CSR13, 0); /* Reset phy */
-	dw32(CSR14, de->media[media].csr14);
-	dw32(CSR15, de->media[media].csr15);
-	dw32(CSR13, de->media[media].csr13);
-
-	/* must delay 10ms before writing to other registers,
-	 * especially CSR6
-	 */
-	mdelay(10);
-
-	if (media == DE_MEDIA_TP_FD)
-		de->macmode |= FullDuplex;
-	else
-		de->macmode &= ~FullDuplex;
-	
-	if (netif_msg_link(de)) {
-		printk(KERN_INFO "%s: set link %s\n"
-		       KERN_INFO "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
-		       KERN_INFO "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
-		       de->dev->name, media_name[media],
-		       de->dev->name, dr32(MacMode), dr32(SIAStatus),
-		       dr32(CSR13), dr32(CSR14), dr32(CSR15),
-		       de->dev->name, de->macmode, de->media[media].csr13,
-		       de->media[media].csr14, de->media[media].csr15);
-	}
-}
-
-static void de_next_media (struct de_private *de, u32 *media,
-			   unsigned int n_media)
-{
-	unsigned int i;
-
-	for (i = 0; i < n_media; i++) {
-		if (de_ok_to_advertise(de, media[i])) {
-			de->media_type = media[i];
-			return;
-		}
-	}
-}
-
-static void de21040_media_timer (unsigned long data)
-{
-	struct de_private *de = (struct de_private *) data;
-	struct net_device *dev = de->dev;
-	u32 status = dr32(SIAStatus);
-	unsigned int carrier;
-	unsigned long flags;
-	
-	carrier = (status & NetCxnErr) ? 0 : 1;
-		
-	if (carrier) {
-		if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus))
-			goto no_link_yet;
-
-		de->media_timer.expires = jiffies + DE_TIMER_LINK;
-		add_timer(&de->media_timer);
-		if (!netif_carrier_ok(dev))
-			de_link_up(de);
-		else
-			if (netif_msg_timer(de))
-				printk(KERN_INFO "%s: %s link ok, status %x\n",
-				       dev->name, media_name[de->media_type],
-				       status);
-		return;
-	}
-
-	de_link_down(de);	
-
-	if (de->media_lock)
-		return;
-
-	if (de->media_type == DE_MEDIA_AUI) {
-		u32 next_state = DE_MEDIA_TP;
-		de_next_media(de, &next_state, 1);
-	} else {
-		u32 next_state = DE_MEDIA_AUI;
-		de_next_media(de, &next_state, 1);
-	}
-
-	spin_lock_irqsave(&de->lock, flags);
-	de_stop_rxtx(de);
-	spin_unlock_irqrestore(&de->lock, flags);
-	de_set_media(de);
-	de_start_rxtx(de);
-
-no_link_yet:
-	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
-	add_timer(&de->media_timer);
-
-	if (netif_msg_timer(de))
-		printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
-		       dev->name, media_name[de->media_type], status);
-}
-
-static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
-{
-	switch (new_media) {
-	case DE_MEDIA_TP_AUTO:
-		if (!(de->media_advertise & ADVERTISED_Autoneg))
-			return 0;
-		if (!(de->media_advertise & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full)))
-			return 0;
-		break;
-	case DE_MEDIA_BNC:
-		if (!(de->media_advertise & ADVERTISED_BNC))
-			return 0;
-		break;
-	case DE_MEDIA_AUI:
-		if (!(de->media_advertise & ADVERTISED_AUI))
-			return 0;
-		break;
-	case DE_MEDIA_TP:
-		if (!(de->media_advertise & ADVERTISED_10baseT_Half))
-			return 0;
-		break;
-	case DE_MEDIA_TP_FD:
-		if (!(de->media_advertise & ADVERTISED_10baseT_Full))
-			return 0;
-		break;
-	}
-	
-	return 1;
-}
-
-static void de21041_media_timer (unsigned long data)
-{
-	struct de_private *de = (struct de_private *) data;
-	struct net_device *dev = de->dev;
-	u32 status = dr32(SIAStatus);
-	unsigned int carrier;
-	unsigned long flags;
-	
-	carrier = (status & NetCxnErr) ? 0 : 1;
-		
-	if (carrier) {
-		if ((de->media_type == DE_MEDIA_TP_AUTO ||
-		     de->media_type == DE_MEDIA_TP ||
-		     de->media_type == DE_MEDIA_TP_FD) &&
-		    (status & LinkFailStatus))
-			goto no_link_yet;
-
-		de->media_timer.expires = jiffies + DE_TIMER_LINK;
-		add_timer(&de->media_timer);
-		if (!netif_carrier_ok(dev))
-			de_link_up(de);
-		else
-			if (netif_msg_timer(de))
-				printk(KERN_INFO "%s: %s link ok, mode %x status %x\n",
-				       dev->name, media_name[de->media_type],
-				       dr32(MacMode), status);
-		return;
-	}
-
-	de_link_down(de);	
-
-	/* if media type locked, don't switch media */
-	if (de->media_lock)
-		goto set_media;
-
-	/* if activity detected, use that as hint for new media type */
-	if (status & NonselPortActive) {
-		unsigned int have_media = 1;
-
-		/* if AUI/BNC selected, then activity is on TP port */
-		if (de->media_type == DE_MEDIA_AUI ||
-		    de->media_type == DE_MEDIA_BNC) {
-			if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
-				de->media_type = DE_MEDIA_TP_AUTO;
-			else
-				have_media = 0;
-		}
-
-		/* TP selected.  If there is only TP and BNC, then it's BNC */
-		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
-			 de_ok_to_advertise(de, DE_MEDIA_BNC))
-			de->media_type = DE_MEDIA_BNC;
-
-		/* TP selected.  If there is only TP and AUI, then it's AUI */
-		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
-			 de_ok_to_advertise(de, DE_MEDIA_AUI))
-			de->media_type = DE_MEDIA_AUI;
-
-		/* otherwise, ignore the hint */
-		else
-			have_media = 0;
-
-		if (have_media)
-			goto set_media;
-	}
-
-	/*
-	 * Absent or ambiguous activity hint, move to next advertised
-	 * media state.  If de->media_type is left unchanged, this
-	 * simply resets the PHY and reloads the current media settings.
-	 */
-	if (de->media_type == DE_MEDIA_AUI) {
-		u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
-		de_next_media(de, next_states, ARRAY_SIZE(next_states));
-	} else if (de->media_type == DE_MEDIA_BNC) {
-		u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI };
-		de_next_media(de, next_states, ARRAY_SIZE(next_states));
-	} else {
-		u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
-		de_next_media(de, next_states, ARRAY_SIZE(next_states));
-	}
-	
-set_media:
-	spin_lock_irqsave(&de->lock, flags);
-	de_stop_rxtx(de);
-	spin_unlock_irqrestore(&de->lock, flags);
-	de_set_media(de);
-	de_start_rxtx(de);
-
-no_link_yet:
-	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
-	add_timer(&de->media_timer);
-
-	if (netif_msg_timer(de))
-		printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
-		       dev->name, media_name[de->media_type], status);
-}
-
-static void de_media_interrupt (struct de_private *de, u32 status)
-{
-	if (status & LinkPass) {
-		de_link_up(de);
-		mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
-		return;
-	}
-	
-	if (!(status & LinkFail))
-		BUG();
-
-	if (netif_carrier_ok(de->dev)) {
-		de_link_down(de);
-		mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
-	}
-}
-
-static int de_reset_mac (struct de_private *de)
-{
-	u32 status, tmp;
-
-	/*
-	 * Reset MAC.  Copied from de4x5.c.
-	 */
-
-	tmp = dr32 (BusMode);
-	if (tmp == 0xffffffff)
-		return -ENODEV;
-	mdelay (1);
-
-	dw32 (BusMode, tmp | CmdReset);
-	mdelay (1);
-
-	dw32 (BusMode, tmp);
-	mdelay (1);
-
-	for (tmp = 0; tmp < 5; tmp++) {
-		dr32 (BusMode);
-		mdelay (1);
-	}
-
-	mdelay (1);
-
-	status = dr32(MacStatus);
-	if (status & (RxState | TxState))
-		return -EBUSY;
-	if (status == 0xffffffff)
-		return -ENODEV;
-	return 0;
-}
-
-static void de_adapter_wake (struct de_private *de)
-{
-	u32 pmctl;
-
-	if (de->de21040)
-		return;
-
-	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
-	if (pmctl & PM_Mask) {
-		pmctl &= ~PM_Mask;
-		pci_write_config_dword(de->pdev, PCIPM, pmctl);
-
-		/* de4x5.c delays, so we do too */
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(msec_to_jiffies(10));
-	}
-}
-
-static void de_adapter_sleep (struct de_private *de)
-{
-	u32 pmctl;
-
-	if (de->de21040)
-		return;
-
-	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
-	pmctl |= PM_Sleep;
-	pci_write_config_dword(de->pdev, PCIPM, pmctl);
-}
-
-static int de_init_hw (struct de_private *de)
-{
-	struct net_device *dev = de->dev;
-	int rc;
-
-	de_adapter_wake(de);
-	
-	de->macmode = dr32(MacMode) & ~MacModeClear;
-
-	rc = de_reset_mac(de);
-	if (rc)
-		return rc;
-
-	de_set_media(de); /* reset phy */
-
-	dw32(RxRingAddr, de->ring_dma);
-	dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
-
-	dw32(MacMode, RxTx | de->macmode);
-
-	dr32(RxMissed); /* self-clearing */
-
-	dw32(IntrMask, de_intr_mask);
-
-	de_set_rx_mode(dev);
-
-	return 0;
-}
-
-static int de_refill_rx (struct de_private *de)
-{
-	unsigned i;
-
-	for (i = 0; i < DE_RX_RING_SIZE; i++) {
-		struct sk_buff *skb;
-
-		skb = dev_alloc_skb(de->rx_buf_sz);
-		if (!skb)
-			goto err_out;
-
-		skb->dev = de->dev;
-
-		de->rx_skb[i].mapping = pci_map_single(de->pdev,
-			skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
-		de->rx_skb[i].skb = skb;
-
-		de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
-		if (i == (DE_RX_RING_SIZE - 1))
-			de->rx_ring[i].opts2 =
-				cpu_to_le32(RingEnd | de->rx_buf_sz);
-		else
-			de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz);
-		de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping);
-		de->rx_ring[i].addr2 = 0;
-	}
-
-	return 0;
-
-err_out:
-	de_clean_rings(de);
-	return -ENOMEM;
-}
-
-static int de_init_rings (struct de_private *de)
-{
-	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
-	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
-
-	de->rx_tail = 0;
-	de->tx_head = de->tx_tail = 0;
-
-	return de_refill_rx (de);
-}
-
-static int de_alloc_rings (struct de_private *de)
-{
-	de->rx_ring = pci_alloc_consistent(de->pdev, DE_RING_BYTES, &de->ring_dma);
-	if (!de->rx_ring)
-		return -ENOMEM;
-	de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE];
-	return de_init_rings(de);
-}
-
-static void de_clean_rings (struct de_private *de)
-{
-	unsigned i;
-
-	memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE);
-	de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
-	wmb();
-	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
-	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
-	wmb();
-
-	for (i = 0; i < DE_RX_RING_SIZE; i++) {
-		if (de->rx_skb[i].skb) {
-			pci_unmap_single(de->pdev, de->rx_skb[i].mapping,
-					 de->rx_buf_sz, PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(de->rx_skb[i].skb);
-		}
-	}
-
-	for (i = 0; i < DE_TX_RING_SIZE; i++) {
-		struct sk_buff *skb = de->tx_skb[i].skb;
-		if ((skb) && (skb != DE_DUMMY_SKB)) {
-			if (skb != DE_SETUP_SKB) {
-				dev_kfree_skb(skb);
-				de->net_stats.tx_dropped++;
-				pci_unmap_single(de->pdev,
-					de->tx_skb[i].mapping,
-					skb->len, PCI_DMA_TODEVICE);
-			} else {
-				pci_unmap_single(de->pdev,
-					de->tx_skb[i].mapping,
-					sizeof(de->setup_frame),
-					PCI_DMA_TODEVICE);
-			}
-		}
-	}
-
-	memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE);
-	memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE);
-}
-
-static void de_free_rings (struct de_private *de)
-{
-	de_clean_rings(de);
-	pci_free_consistent(de->pdev, DE_RING_BYTES, de->rx_ring, de->ring_dma);
-	de->rx_ring = NULL;
-	de->tx_ring = NULL;
-}
-
-static int de_open (struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	int rc;
-	unsigned long flags;
-
-	if (netif_msg_ifup(de))
-		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
-
-	de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-
-	rc = de_alloc_rings(de);
-	if (rc) {
-		printk(KERN_ERR "%s: ring allocation failure, err=%d\n",
-		       dev->name, rc);
-		return rc;
-	}
-
-	rc = de_init_hw(de);
-	if (rc) {
-		printk(KERN_ERR "%s: h/w init failure, err=%d\n",
-		       dev->name, rc);
-		goto err_out_free;
-	}
-
-	rc = request_irq(dev->irq, de_interrupt, SA_SHIRQ, dev->name, dev);
-	if (rc) {
-		printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n",
-		       dev->name, dev->irq, rc);
-		goto err_out_hw;
-	}
-
-	netif_start_queue(dev);
-	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
-
-	return 0;
-
-err_out_hw:
-	spin_lock_irqsave(&de->lock, flags);
-	de_stop_hw(de);
-	spin_unlock_irqrestore(&de->lock, flags);
-
-err_out_free:
-	de_free_rings(de);
-	return rc;
-}
-
-static int de_close (struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-	unsigned long flags;
-
-	if (netif_msg_ifdown(de))
-		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
-
-	del_timer_sync(&de->media_timer);
-
-	spin_lock_irqsave(&de->lock, flags);
-	de_stop_hw(de);
-	netif_stop_queue(dev);
-	netif_carrier_off(dev);
-	spin_unlock_irqrestore(&de->lock, flags);
-	
-	free_irq(dev->irq, dev);
-
-	de_free_rings(de);
-	de_adapter_sleep(de);
-	pci_disable_device(de->pdev);
-	return 0;
-}
-
-static void de_tx_timeout (struct net_device *dev)
-{
-	struct de_private *de = dev->priv;
-
-	printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
-	       dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
-	       de->rx_tail, de->tx_head, de->tx_tail);
-
-	del_timer_sync(&de->media_timer);
-
-	disable_irq(dev->irq);
-	spin_lock_irq(&de->lock);
-
-	de_stop_hw(de);
-	netif_stop_queue(dev);
-	netif_carrier_off(dev);
-
-	spin_unlock_irq(&de->lock);
-	enable_irq(dev->irq);
-		
-	/* Update the error counts. */
-	__de_get_stats(de);
-
-	synchronize_irq();
-	de_clean_rings(de);
-
-	de_init_hw(de);
-	
-	netif_wake_queue(dev);
-}
-
-static int de_get_regs(struct de_private *de, u8 *buf)
-{
-	int i;
-	u32 *rbuf = (u32 *)buf;
-	
-	/* read all CSRs */
-	for (i = 0; i < DE_NUM_REGS; i++)
-		rbuf[i] = dr32(i * 8);
-
-	/* handle self-clearing RxMissed counter, CSR8 */
-	de_rx_missed(de, rbuf[8]);
-
-	return 0;
-}
-
-static int de_ethtool_gset(struct de_private *de, struct ethtool_cmd *ecmd)
-{
-	ecmd->supported = de->media_supported;
-	ecmd->transceiver = XCVR_INTERNAL;
-	ecmd->phy_address = 0;
-	ecmd->advertising = de->media_advertise;
-	
-	switch (de->media_type) {
-	case DE_MEDIA_AUI:
-		ecmd->port = PORT_AUI;
-		ecmd->speed = 5;
-		break;
-	case DE_MEDIA_BNC:
-		ecmd->port = PORT_BNC;
-		ecmd->speed = 2;
-		break;
-	default:
-		ecmd->port = PORT_TP;
-		ecmd->speed = SPEED_10;
-		break;
-	}
-	
-	if (de->macmode & FullDuplex)
-		ecmd->duplex = DUPLEX_FULL;
-	else
-		ecmd->duplex = DUPLEX_HALF;
-
-	if (de->media_lock)
-		ecmd->autoneg = AUTONEG_DISABLE;
-	else
-		ecmd->autoneg = AUTONEG_ENABLE;
-
-	/* ignore maxtxpkt, maxrxpkt for now */
-
-	return 0;
-}
-
-static int de_ethtool_sset(struct de_private *de, struct ethtool_cmd *ecmd)
-{
-	u32 new_media;
-	unsigned int media_lock;
-
-	if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2)
-		return -EINVAL;
-	if (de->de21040 && ecmd->speed == 2)
-		return -EINVAL;
-	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
-		return -EINVAL;
-	if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI && ecmd->port != PORT_BNC)
-		return -EINVAL;
-	if (de->de21040 && ecmd->port == PORT_BNC)
-		return -EINVAL;
-	if (ecmd->transceiver != XCVR_INTERNAL)
-		return -EINVAL;
-	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
-		return -EINVAL;
-	if (ecmd->advertising & ~de->media_supported)
-		return -EINVAL;
-	if (ecmd->autoneg == AUTONEG_ENABLE &&
-	    (!(ecmd->advertising & ADVERTISED_Autoneg)))
-		return -EINVAL;
-	
-	switch (ecmd->port) {
-	case PORT_AUI:
-		new_media = DE_MEDIA_AUI;
-		if (!(ecmd->advertising & ADVERTISED_AUI))
-			return -EINVAL;
-		break;
-	case PORT_BNC:
-		new_media = DE_MEDIA_BNC;
-		if (!(ecmd->advertising & ADVERTISED_BNC))
-			return -EINVAL;
-		break;
-	default:
-		if (ecmd->autoneg == AUTONEG_ENABLE)
-			new_media = DE_MEDIA_TP_AUTO;
-		else if (ecmd->duplex == DUPLEX_FULL)
-			new_media = DE_MEDIA_TP_FD;
-		else
-			new_media = DE_MEDIA_TP;
-		if (!(ecmd->advertising & ADVERTISED_TP))
-			return -EINVAL;
-		if (!(ecmd->advertising & (ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half)))
-			return -EINVAL;
-		break;
-	}
-	
-	media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1;
-	
-	if ((new_media == de->media_type) &&
-	    (media_lock == de->media_lock) &&
-	    (ecmd->advertising == de->media_advertise))
-		return 0; /* nothing to change */
-	    
-	de_link_down(de);
-	de_stop_rxtx(de);
-	
-	de->media_type = new_media;
-	de->media_lock = media_lock;
-	de->media_advertise = ecmd->advertising;
-	de_set_media(de);
-	
-	return 0;
-}
-
-static int de_ethtool_ioctl (struct de_private *de, void *useraddr)
-{
-	u32 ethcmd;
-
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		strcpy (info.bus_info, de->pdev->slot_name);
-		info.eedump_len = DE_EEPROM_SIZE;
-		info.regdump_len = DE_REGS_SIZE;
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&de->lock);
-		de_ethtool_gset(de, &ecmd);
-		spin_unlock_irq(&de->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		struct ethtool_cmd ecmd;
-		int r;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&de->lock);
-		r = de_ethtool_sset(de, &ecmd);
-		spin_unlock_irq(&de->lock);
-		return r;
-	}
-
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		u32 status;
-
-		if (de->media_type != DE_MEDIA_TP_AUTO)
-			return -EINVAL;
-		if (netif_carrier_ok(de->dev))
-			de_link_down(de);
-
-		status = dr32(SIAStatus);
-		dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
-		if (netif_msg_link(de))
-			printk(KERN_INFO "%s: link nway restart, status %x,%x\n",
-			       de->dev->name, status, dr32(SIAStatus));
-		return 0;
-	}
-
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = (netif_carrier_ok(de->dev)) ? 1 : 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = de->msg_enable;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		de->msg_enable = edata.data;
-		return 0;
-	}
-
-	/* get registers */
-	case ETHTOOL_GREGS: {
-		struct ethtool_regs regs;
-		u8 regbuf[DE_REGS_SIZE];
-		int r;
-
-		if (copy_from_user(&regs, useraddr, sizeof(regs)))
-			return -EFAULT;
-		
-		if (regs.len > DE_REGS_SIZE) {
-			regs.len = DE_REGS_SIZE;
-		}
-		regs.version = (DE_REGS_VER << 2) | de->de21040;
-		if (copy_to_user(useraddr, &regs, sizeof(regs)))
-			return -EFAULT;
-
-		useraddr += offsetof(struct ethtool_regs, data);
-
-		spin_lock_irq(&de->lock);
-		r = de_get_regs(de, regbuf);
-		spin_unlock_irq(&de->lock);
-
-		if (r)
-			return r;
-		if (copy_to_user(useraddr, regbuf, regs.len))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get SROM dump */
-	case ETHTOOL_GEEPROM: {
-		struct ethtool_eeprom eeprom;
-
-		if (!de->ee_data)
-			break;
-		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
-			return -EFAULT;
-		if ((eeprom.offset != 0) || (eeprom.magic != 0) ||
-		    (eeprom.len != DE_EEPROM_SIZE))
-			return -EINVAL;
-
-		useraddr += offsetof(struct ethtool_regs, data);
-		if (copy_to_user(useraddr, de->ee_data, DE_EEPROM_SIZE))
-			return -EFAULT;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
-}
-
-
-static int de_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct de_private *de = dev->priv;
-	int rc = 0;
-
-	if (!netif_running(dev))
-		return -EINVAL;
-		
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return de_ethtool_ioctl(de, (void *) rq->ifr_data);
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-
-	return rc;
-}
-
-static void __init de21040_get_mac_address (struct de_private *de)
-{
-	unsigned i;
-
-	dw32 (ROMCmd, 0);	/* Reset the pointer with a dummy write. */
-
-	for (i = 0; i < 6; i++) {
-		int value, boguscnt = 100000;
-		do
-			value = dr32(ROMCmd);
-		while (value < 0 && --boguscnt > 0);
-		de->dev->dev_addr[i] = value;
-		if (boguscnt <= 0)
-			printk(KERN_WARNING PFX "timeout reading 21040 MAC address byte %u\n", i);
-	}
-}
-
-static void __init de21040_get_media_info(struct de_private *de)
-{
-	unsigned int i;
-
-	de->media_type = DE_MEDIA_TP;
-	de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
-			       SUPPORTED_10baseT_Half | SUPPORTED_AUI;
-	de->media_advertise = de->media_supported;
-
-	for (i = 0; i < DE_MAX_MEDIA; i++) {
-		switch (i) {
-		case DE_MEDIA_AUI:
-		case DE_MEDIA_TP:
-		case DE_MEDIA_TP_FD:
-			de->media[i].type = i;
-			de->media[i].csr13 = t21040_csr13[i];
-			de->media[i].csr14 = t21040_csr14[i];
-			de->media[i].csr15 = t21040_csr15[i];
-			break;
-		default:
-			de->media[i].type = DE_MEDIA_INVALID;
-			break;
-		}
-	}
-}
-
-/* Note: this routine returns extra data bits for size detection. */
-static unsigned __init tulip_read_eeprom(void *regs, int location, int addr_len)
-{
-	int i;
-	unsigned retval = 0;
-	void *ee_addr = regs + ROMCmd;
-	int read_cmd = location | (EE_READ_CMD << addr_len);
-
-	writel(EE_ENB & ~EE_CS, ee_addr);
-	writel(EE_ENB, ee_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 4 + addr_len; i >= 0; i--) {
-		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
-		writel(EE_ENB | dataval, ee_addr);
-		readl(ee_addr);
-		writel(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		readl(ee_addr);
-		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
-	}
-	writel(EE_ENB, ee_addr);
-	readl(ee_addr);
-
-	for (i = 16; i > 0; i--) {
-		writel(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		readl(ee_addr);
-		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
-		writel(EE_ENB, ee_addr);
-		readl(ee_addr);
-	}
-
-	/* Terminate the EEPROM access. */
-	writel(EE_ENB & ~EE_CS, ee_addr);
-	return retval;
-}
-
-static void __init de21041_get_srom_info (struct de_private *de)
-{
-	unsigned i, sa_offset = 0, ofs;
-	u8 ee_data[DE_EEPROM_SIZE + 6] = {};
-	unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
-	struct de_srom_info_leaf *il;
-	void *bufp;
-
-	/* download entire eeprom */
-	for (i = 0; i < DE_EEPROM_WORDS; i++)
-		((u16 *)ee_data)[i] =
-			le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
-
-	/* DEC now has a specification but early board makers
-	   just put the address in the first EEPROM locations. */
-	/* This does  memcmp(eedata, eedata+16, 8) */
-	for (i = 0; i < 8; i ++)
-		if (ee_data[i] != ee_data[16+i])
-			sa_offset = 20;
-
-	/* store MAC address */
-	for (i = 0; i < 6; i ++)
-		de->dev->dev_addr[i] = ee_data[i + sa_offset];
-
-	/* get offset of controller 0 info leaf.  ignore 2nd byte. */
-	ofs = ee_data[SROMC0InfoLeaf];
-	if (ofs >= (sizeof(ee_data) - sizeof(struct de_srom_info_leaf) - sizeof(struct de_srom_media_block)))
-		goto bad_srom;
-
-	/* get pointer to info leaf */
-	il = (struct de_srom_info_leaf *) &ee_data[ofs];
-
-	/* paranoia checks */
-	if (il->n_blocks == 0)
-		goto bad_srom;
-	if ((sizeof(ee_data) - ofs) <
-	    (sizeof(struct de_srom_info_leaf) + (sizeof(struct de_srom_media_block) * il->n_blocks)))
-		goto bad_srom;
-
-	/* get default media type */
-	switch (DE_UNALIGNED_16(&il->default_media)) {
-	case 0x0001:  de->media_type = DE_MEDIA_BNC; break;
-	case 0x0002:  de->media_type = DE_MEDIA_AUI; break;
-	case 0x0204:  de->media_type = DE_MEDIA_TP_FD; break;
-	default: de->media_type = DE_MEDIA_TP_AUTO; break;
-	}
-	
-	if (netif_msg_probe(de))
-		printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
-		       de->board_idx, ofs,
-		       media_name[de->media_type]);
-
-	/* init SIA register values to defaults */
-	for (i = 0; i < DE_MAX_MEDIA; i++) {
-		de->media[i].type = DE_MEDIA_INVALID;
-		de->media[i].csr13 = 0xffff;
-		de->media[i].csr14 = 0xffff;
-		de->media[i].csr15 = 0xffff;
-	}
-
-	/* parse media blocks to see what medias are supported,
-	 * and if any custom CSR values are provided
-	 */
-	bufp = ((void *)il) + sizeof(*il);
-	for (i = 0; i < il->n_blocks; i++) {
-		struct de_srom_media_block *ib = bufp;
-		unsigned idx;
-
-		/* index based on media type in media block */
-		switch(ib->opts & MediaBlockMask) {
-		case 0: /* 10baseT */
-			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half
-					  | SUPPORTED_Autoneg;
-			idx = DE_MEDIA_TP;
-			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
-			break;
-		case 1: /* BNC */
-			de->media_supported |= SUPPORTED_BNC;
-			idx = DE_MEDIA_BNC;
-			break;
-		case 2: /* AUI */
-			de->media_supported |= SUPPORTED_AUI;
-			idx = DE_MEDIA_AUI;
-			break;
-		case 4: /* 10baseT-FD */
-			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full
-					  | SUPPORTED_Autoneg;
-			idx = DE_MEDIA_TP_FD;
-			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
-			break;
-		default:
-			goto bad_srom;
-		}
-
-		de->media[idx].type = idx;
-
-		if (netif_msg_probe(de))
-			printk(KERN_INFO "de%d:   media block #%u: %s",
-			       de->board_idx, i,
-			       media_name[de->media[idx].type]);
-
-		bufp += sizeof (ib->opts);
-
-		if (ib->opts & MediaCustomCSRs) {
-			de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13);
-			de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14);
-			de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15);
-			bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
-				sizeof(ib->csr15);
-
-			if (netif_msg_probe(de))
-				printk(" (%x,%x,%x)\n",
-				       de->media[idx].csr13,
-				       de->media[idx].csr14,
-				       de->media[idx].csr15);
-				       
-		} else if (netif_msg_probe(de))
-			printk("\n");
-
-		if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
-			break;
-	}
-
-	de->media_advertise = de->media_supported;
-
-fill_defaults:
-	/* fill in defaults, for cases where custom CSRs not used */
-	for (i = 0; i < DE_MAX_MEDIA; i++) {
-		if (de->media[i].csr13 == 0xffff)
-			de->media[i].csr13 = t21041_csr13[i];
-		if (de->media[i].csr14 == 0xffff)
-			de->media[i].csr14 = t21041_csr14[i];
-		if (de->media[i].csr15 == 0xffff)
-			de->media[i].csr15 = t21041_csr15[i];
-	}
-
-	de->ee_data = kmalloc(DE_EEPROM_SIZE, GFP_KERNEL);
-	if (de->ee_data)
-		memcpy(de->ee_data, &ee_data[0], DE_EEPROM_SIZE);
-
-	return;
-
-bad_srom:
-	/* for error cases, it's ok to assume we support all these */
-	for (i = 0; i < DE_MAX_MEDIA; i++)
-		de->media[i].type = i;
-	de->media_supported =
-		SUPPORTED_10baseT_Half |
-		SUPPORTED_10baseT_Full |
-		SUPPORTED_Autoneg |
-		SUPPORTED_TP |
-		SUPPORTED_AUI |
-		SUPPORTED_BNC;
-	goto fill_defaults;
-}
-
-static int __init de_init_one (struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	struct net_device *dev;
-	struct de_private *de;
-	int rc;
-	void *regs;
-	long pciaddr;
-	static int board_idx = -1;
-
-	board_idx++;
-
-#ifndef MODULE
-	if (board_idx == 0)
-		printk("%s", version);
-#endif
-
-	/* allocate a new ethernet device structure, and fill in defaults */
-	dev = alloc_etherdev(sizeof(struct de_private));
-	if (!dev)
-		return -ENOMEM;
-
-	SET_MODULE_OWNER(dev);
-	dev->open = de_open;
-	dev->stop = de_close;
-	dev->set_multicast_list = de_set_rx_mode;
-	dev->hard_start_xmit = de_start_xmit;
-	dev->get_stats = de_get_stats;
-	dev->do_ioctl = de_ioctl;
-	dev->tx_timeout = de_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	dev->irq = pdev->irq;
-
-	de = dev->priv;
-	de->de21040 = ent->driver_data == 0 ? 1 : 0;
-	de->pdev = pdev;
-	de->dev = dev;
-	de->msg_enable = (debug < 0 ? DE_DEF_MSG_ENABLE : debug);
-	de->board_idx = board_idx;
-	spin_lock_init (&de->lock);
-	init_timer(&de->media_timer);
-	if (de->de21040)
-		de->media_timer.function = de21040_media_timer;
-	else
-		de->media_timer.function = de21041_media_timer;
-	de->media_timer.data = (unsigned long) de;
-
-	netif_carrier_off(dev);
-	netif_stop_queue(dev);
-
-	/* wake up device, assign resources */
-	rc = pci_enable_device(pdev);
-	if (rc)
-		goto err_out_free;
-
-	/* reserve PCI resources to ensure driver atomicity */
-	rc = pci_request_regions(pdev, DRV_NAME);
-	if (rc)
-		goto err_out_disable;
-
-	/* check for invalid IRQ value */
-	if (pdev->irq < 2) {
-		rc = -EIO;
-		printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
-		       pdev->irq, pdev->slot_name);
-		goto err_out_res;
-	}
-
-	/* obtain and check validity of PCI I/O address */
-	pciaddr = pci_resource_start(pdev, 1);
-	if (!pciaddr) {
-		rc = -EIO;
-		printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
-		       pdev->slot_name);
-		goto err_out_res;
-	}
-	if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
-		rc = -EIO;
-		printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
-		       pci_resource_len(pdev, 1), pdev->slot_name);
-		goto err_out_res;
-	}
-
-	/* remap CSR registers */
-	regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
-	if (!regs) {
-		rc = -EIO;
-		printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
-		       pci_resource_len(pdev, 1), pciaddr, pdev->slot_name);
-		goto err_out_res;
-	}
-	dev->base_addr = (unsigned long) regs;
-	de->regs = regs;
-
-	de_adapter_wake(de);
-
-	/* make sure hardware is not running */
-	rc = de_reset_mac(de);
-	if (rc) {
-		printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
-		       pdev->slot_name);
-		goto err_out_iomap;
-	}
-
-	/* get MAC address, initialize default media type and
-	 * get list of supported media
-	 */
-	if (de->de21040) {
-		de21040_get_mac_address(de);
-		de21040_get_media_info(de);
-	} else {
-		de21041_get_srom_info(de);
-	}
-
-	/* register new network interface with kernel */
-	rc = register_netdev(dev);
-	if (rc)
-		goto err_out_iomap;
-
-	/* print info about board and interface just registered */
-	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%02x:%02x:%02x:%02x:%02x:%02x, "
-		"IRQ %d\n",
-		dev->name,
-		de->de21040 ? "21040" : "21041",
-		dev->base_addr,
-		dev->dev_addr[0], dev->dev_addr[1],
-		dev->dev_addr[2], dev->dev_addr[3],
-		dev->dev_addr[4], dev->dev_addr[5],
-		dev->irq);
-
-	pci_set_drvdata(pdev, dev);
-
-	/* enable busmastering */
-	pci_set_master(pdev);
-
-	/* put adapter to sleep */
-	de_adapter_sleep(de);
-
-	return 0;
-
-err_out_iomap:
-	if (de->ee_data)
-		kfree(de->ee_data);
-	iounmap(regs);
-err_out_res:
-	pci_release_regions(pdev);
-err_out_disable:
-	pci_disable_device(pdev);
-err_out_free:
-	kfree(dev);
-	return rc;
-}
-
-static void __exit de_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct de_private *de = dev->priv;
-
-	if (!dev)
-		BUG();
-	unregister_netdev(dev);
-	if (de->ee_data)
-		kfree(de->ee_data);
-	iounmap(de->regs);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
-	kfree(dev);
-}
-
-#ifdef CONFIG_PM
-
-static int de_suspend (struct pci_dev *pdev, u32 state)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct de_private *de = dev->priv;
-
-	rtnl_lock();
-	if (netif_running (dev)) {
-		del_timer_sync(&de->media_timer);
-
-		disable_irq(dev->irq);
-		spin_lock_irq(&de->lock);
-
-		de_stop_hw(de);
-		netif_stop_queue(dev);
-		netif_device_detach(dev);
-		netif_carrier_off(dev);
-
-		spin_unlock_irq(&de->lock);
-		enable_irq(dev->irq);
-		
-		/* Update the error counts. */
-		__de_get_stats(de);
-
-		synchronize_irq();
-		de_clean_rings(de);
-
-		de_adapter_sleep(de);
-		pci_disable_device(pdev);
-	} else {
-		netif_device_detach(dev);
-	}
-	rtnl_unlock();
-	return 0;
-}
-
-static int de_resume (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct de_private *de = dev->priv;
-
-	rtnl_lock();
-	if (netif_device_present(dev))
-		goto out;
-	if (netif_running(dev)) {
-		pci_enable_device(pdev);
-		de_init_hw(de);
-		netif_device_attach(dev);
-	} else {
-		netif_device_attach(dev);
-	}
-out:
-	rtnl_unlock();
-	return 0;
-}
-
-#endif /* CONFIG_PM */
-
-static struct pci_driver de_driver = {
-	name:		DRV_NAME,
-	id_table:	de_pci_tbl,
-	probe:		de_init_one,
-	remove:		de_remove_one,
-#ifdef CONFIG_PM
-	suspend:	de_suspend,
-	resume:		de_resume,
-#endif
-};
-
-static int __init de_init (void)
-{
-#ifdef MODULE
-	printk("%s", version);
-#endif
-	return pci_module_init (&de_driver);
-}
-
-static void __exit de_exit (void)
-{
-	pci_unregister_driver (&de_driver);
-}
-
-module_init(de_init);
-module_exit(de_exit);
diff -urN linux-2.5.6-pre3/drivers/net/de4x5.c linux-2.5.6/drivers/net/de4x5.c
--- linux-2.5.6-pre3/drivers/net/de4x5.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/drivers/net/de4x5.c	Wed Dec 31 16:00:00 1969
@@ -1,5918 +0,0 @@
-/*  de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500
-             ethernet driver for Linux.
-
-    Copyright 1994, 1995 Digital Equipment Corporation.
-
-    Testing resources for this driver have been made available
-    in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
-
-    The author may be reached at davies@maniac.ultranet.com.
-
-    This program is free software; you can redistribute  it and/or modify it
-    under  the terms of  the GNU General  Public License as published by the
-    Free Software Foundation;  either version 2 of the  License, or (at your
-    option) any later version.
-
-    THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
-    WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
-    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
-    NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
-    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-    NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
-    USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-    ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
-    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    You should have received a copy of the  GNU General Public License along
-    with this program; if not, write  to the Free Software Foundation, Inc.,
-    675 Mass Ave, Cambridge, MA 02139, USA.
-
-    Originally,   this  driver  was    written  for the  Digital   Equipment
-    Corporation series of EtherWORKS ethernet cards:
-
-        DE425 TP/COAX EISA
-	DE434 TP PCI
-	DE435 TP/COAX/AUI PCI
-	DE450 TP/COAX/AUI PCI
-	DE500 10/100 PCI Fasternet
-
-    but it  will  now attempt  to  support all  cards which   conform to the
-    Digital Semiconductor   SROM   Specification.    The  driver   currently
-    recognises the following chips:
-
-        DC21040  (no SROM) 
-	DC21041[A]  
-	DC21140[A] 
-	DC21142 
-	DC21143 
-
-    So far the driver is known to work with the following cards:
-
-        KINGSTON
-	Linksys
-	ZNYX342
-	SMC8432
-	SMC9332 (w/new SROM)
-	ZNYX31[45]
-	ZNYX346 10/100 4 port (can act as a 10/100 bridge!) 
-
-    The driver has been tested on a relatively busy network using the DE425,
-    DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
-    16M of data to a DECstation 5000/200 as follows:
-
-                TCP           UDP
-             TX     RX     TX     RX
-    DE425   1030k  997k   1170k  1128k
-    DE434   1063k  995k   1170k  1125k
-    DE435   1063k  995k   1170k  1125k
-    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode
-
-    All  values are typical (in   kBytes/sec) from a  sample  of 4 for  each
-    measurement. Their error is +/-20k on a quiet (private) network and also
-    depend on what load the CPU has.
-
-    =========================================================================
-    This driver  has been written substantially  from  scratch, although its
-    inheritance of style and stack interface from 'ewrk3.c' and in turn from
-    Donald Becker's 'lance.c' should be obvious. With the module autoload of
-    every  usable DECchip board,  I  pinched Donald's 'next_module' field to
-    link my modules together.
-
-    Upto 15 EISA cards can be supported under this driver, limited primarily
-    by the available IRQ lines.  I have  checked different configurations of
-    multiple depca, EtherWORKS 3 cards and de4x5 cards and  have not found a
-    problem yet (provided you have at least depca.c v0.38) ...
-
-    PCI support has been added  to allow the driver  to work with the DE434,
-    DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due
-    to the differences in the EISA and PCI CSR address offsets from the base
-    address.
-
-    The ability to load this  driver as a loadable  module has been included
-    and used extensively  during the driver development  (to save those long
-    reboot sequences).  Loadable module support  under PCI and EISA has been
-    achieved by letting the driver autoprobe as if it were compiled into the
-    kernel. Do make sure  you're not sharing  interrupts with anything  that
-    cannot accommodate  interrupt  sharing!
-
-    To utilise this ability, you have to do 8 things:
-
-    0) have a copy of the loadable modules code installed on your system.
-    1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
-    temporary directory.
-    2) for fixed  autoprobes (not  recommended),  edit the source code  near
-    line 5594 to reflect the I/O address  you're using, or assign these when
-    loading by:
-
-                   insmod de4x5 io=0xghh           where g = bus number
-		                                        hh = device number   
-
-       NB: autoprobing for modules is now supported by default. You may just
-           use:
-
-                   insmod de4x5
-
-           to load all available boards. For a specific board, still use
-	   the 'io=?' above.
-    3) compile  de4x5.c, but include -DMODULE in  the command line to ensure
-    that the correct bits are compiled (see end of source code).
-    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
-    kernel with the de4x5 configuration turned off and reboot.
-    5) insmod de4x5 [io=0xghh]
-    6) run the net startup bits for your new eth?? interface(s) manually 
-    (usually /etc/rc.inet[12] at boot time). 
-    7) enjoy!
-
-    To unload a module, turn off the associated interface(s) 
-    'ifconfig eth?? down' then 'rmmod de4x5'.
-
-    Automedia detection is included so that in  principal you can disconnect
-    from, e.g.  TP, reconnect  to BNC  and  things will still work  (after a
-    pause whilst the   driver figures out   where its media went).  My tests
-    using ping showed that it appears to work....
-
-    By  default,  the driver will  now   autodetect any  DECchip based card.
-    Should you have a need to restrict the driver to DIGITAL only cards, you
-    can compile with a  DEC_ONLY define, or if  loading as a module, use the
-    'dec_only=1'  parameter. 
-
-    I've changed the timing routines to  use the kernel timer and scheduling
-    functions  so that the  hangs  and other assorted problems that occurred
-    while autosensing the  media  should be gone.  A  bonus  for the DC21040
-    auto  media sense algorithm is  that it can now  use one that is more in
-    line with the  rest (the DC21040  chip doesn't  have a hardware  timer).
-    The downside is the 1 'jiffies' (10ms) resolution.
-
-    IEEE 802.3u MII interface code has  been added in anticipation that some
-    products may use it in the future.
-
-    The SMC9332 card  has a non-compliant SROM  which needs fixing -  I have
-    patched this  driver to detect it  because the SROM format used complies
-    to a previous DEC-STD format.
-
-    I have removed the buffer copies needed for receive on Intels.  I cannot
-    remove them for   Alphas since  the  Tulip hardware   only does longword
-    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
-    longword aligned data copies (which makes them really slow). No comment.
-
-    I  have added SROM decoding  routines to make this  driver work with any
-    card that  supports the Digital  Semiconductor SROM spec. This will help
-    all  cards running the dc2114x  series chips in particular.  Cards using
-    the dc2104x  chips should run correctly with  the basic  driver.  I'm in
-    debt to <mjacob@feral.com> for the  testing and feedback that helped get
-    this feature working.  So far we have  tested KINGSTON, SMC8432, SMC9332
-    (with the latest SROM complying  with the SROM spec  V3: their first was
-    broken), ZNYX342  and  LinkSys. ZYNX314 (dual  21041  MAC) and  ZNYX 315
-    (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
-    wired IRQs.
-
-    I have added a temporary fix for interrupt problems when some SCSI cards
-    share the same interrupt as the DECchip based  cards. The problem occurs
-    because  the SCSI card wants to  grab the interrupt  as a fast interrupt
-    (runs the   service routine with interrupts turned   off) vs.  this card
-    which really needs to run the service routine with interrupts turned on.
-    This driver will  now   add the interrupt service   routine  as  a  fast
-    interrupt if it   is bounced from the   slow interrupt.  THIS IS NOT   A
-    RECOMMENDED WAY TO RUN THE DRIVER  and has been done  for a limited time
-    until  people   sort  out their  compatibility    issues and the  kernel
-    interrupt  service code  is  fixed.   YOU  SHOULD SEPARATE OUT  THE FAST
-    INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
-    run on the same interrupt. PCMCIA/CardBus is another can of worms...
-
-    Finally, I think  I have really  fixed  the module  loading problem with
-    more than one DECchip based  card.  As a  side effect, I don't mess with
-    the  device structure any  more which means that  if more than 1 card in
-    2.0.x is    installed (4  in   2.1.x),  the  user   will have   to  edit
-    linux/drivers/net/Space.c  to make room for  them. Hence, module loading
-    is  the preferred way to use   this driver, since  it  doesn't have this
-    limitation.
-
-    Where SROM media  detection is used and  full duplex is specified in the
-    SROM,  the feature is  ignored unless  lp->params.fdx  is set at compile
-    time  OR during  a   module load  (insmod  de4x5   args='eth??:fdx' [see
-    below]).  This is because there  is no way  to automatically detect full
-    duplex   links  except through   autonegotiation.    When I  include the
-    autonegotiation feature in  the SROM autoconf  code, this detection will
-    occur automatically for that case.
-
-    Command  line arguments are  now  allowed, similar  to passing arguments
-    through LILO. This will allow a per adapter board  set up of full duplex
-    and media. The only lexical constraints  are: the board name (dev->name)
-    appears in the list before its  parameters.  The list of parameters ends
-    either at the end of the parameter list or with another board name.  The
-    following parameters are allowed:
-
-            fdx        for full duplex
-	    autosense  to set the media/speed; with the following 
-	               sub-parameters:
-		       TP, TP_NW, BNC, AUI, BNC_AUI, 100Mb, 10Mb, AUTO
-
-    Case sensitivity is important  for  the sub-parameters. They *must*   be
-    upper case. Examples:
-
-        insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
-
-    For a compiled in driver, at or above line 548, place e.g.
-	#define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
-
-    Yes,  I know full duplex isn't  permissible on BNC  or AUI; they're just
-    examples. By default, full duplex is turned off and  AUTO is the default
-    autosense setting.  In reality, I expect only  the full duplex option to
-    be used. Note the use of single quotes in the two examples above and the
-    lack of commas to separate items. ALSO, you must get the requested media
-    correct in relation to what the adapter SROM says it has. There's no way
-    to  determine this in  advance other than by  trial and error and common
-    sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
-
-    Changed the bus probing.  EISA used to be  done first,  followed by PCI.
-    Most people probably don't even know  what a de425 is today and the EISA
-    probe has messed  up some SCSI cards  in the past,  so now PCI is always
-    probed  first  followed by  EISA if  a) the architecture allows EISA and
-    either  b) there have been no PCI cards detected or  c) an EISA probe is
-    forced by  the user.  To force  a probe  include  "force_eisa"  in  your
-    insmod "args" line;  for built-in kernels either change the driver to do
-    this  automatically  or include  #define DE4X5_FORCE_EISA  on or  before
-    line 1040 in the driver.
-
-    TO DO: 
-    ------
-
-    Revision History
-    ----------------
-
-    Version   Date        Description
-  
-      0.1     17-Nov-94   Initial writing. ALPHA code release.
-      0.2     13-Jan-95   Added PCI support for DE435's.
-      0.21    19-Jan-95   Added auto media detection.
-      0.22    10-Feb-95   Fix interrupt handler call <chris@cosy.sbg.ac.at>.
-                          Fix recognition bug reported by <bkm@star.rl.ac.uk>.
-			  Add request/release_region code.
-			  Add loadable modules support for PCI.
-			  Clean up loadable modules support.
-      0.23    28-Feb-95   Added DC21041 and DC21140 support. 
-                          Fix missed frame counter value and initialisation.
-			  Fixed EISA probe.
-      0.24    11-Apr-95   Change delay routine to use <linux/udelay>.
-                          Change TX_BUFFS_AVAIL macro.
-			  Change media autodetection to allow manual setting.
-			  Completed DE500 (DC21140) support.
-      0.241   18-Apr-95   Interim release without DE500 Autosense Algorithm.
-      0.242   10-May-95   Minor changes.
-      0.30    12-Jun-95   Timer fix for DC21140.
-                          Portability changes.
-			  Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
-			  Add DE500 semi automatic autosense.
-			  Add Link Fail interrupt TP failure detection.
-			  Add timer based link change detection.
-			  Plugged a memory leak in de4x5_queue_pkt().
-      0.31    13-Jun-95   Fixed PCI stuff for 1.3.1.
-      0.32    26-Jun-95   Added verify_area() calls in de4x5_ioctl() from a
-                          suggestion by <heiko@colossus.escape.de>.
-      0.33     8-Aug-95   Add shared interrupt support (not released yet).
-      0.331   21-Aug-95   Fix de4x5_open() with fast CPUs.
-                          Fix de4x5_interrupt().
-                          Fix dc21140_autoconf() mess.
-			  No shared interrupt support.
-      0.332   11-Sep-95   Added MII management interface routines.
-      0.40     5-Mar-96   Fix setup frame timeout <maartenb@hpkuipc.cern.ch>.
-                          Add kernel timer code (h/w is too flaky).
-			  Add MII based PHY autosense.
-			  Add new multicasting code.
-			  Add new autosense algorithms for media/mode 
-			  selection using kernel scheduling/timing.
-			  Re-formatted.
-			  Made changes suggested by <jeff@router.patch.net>:
-			    Change driver to detect all DECchip based cards
-			    with DEC_ONLY restriction a special case.
-			    Changed driver to autoprobe as a module. No irq
-			    checking is done now - assume BIOS is good!
-			  Added SMC9332 detection <manabe@Roy.dsl.tutics.ac.jp>
-      0.41    21-Mar-96   Don't check for get_hw_addr checksum unless DEC card
-                          only <niles@axp745gsfc.nasa.gov>
-			  Fix for multiple PCI cards reported by <jos@xos.nl>
-			  Duh, put the SA_SHIRQ flag into request_interrupt().
-			  Fix SMC ethernet address in enet_det[].
-			  Print chip name instead of "UNKNOWN" during boot.
-      0.42    26-Apr-96   Fix MII write TA bit error.
-                          Fix bug in dc21040 and dc21041 autosense code.
-			  Remove buffer copies on receive for Intels.
-			  Change sk_buff handling during media disconnects to
-			   eliminate DUP packets.
-			  Add dynamic TX thresholding.
-			  Change all chips to use perfect multicast filtering.
-			  Fix alloc_device() bug <jari@markkus2.fimr.fi>
-      0.43   21-Jun-96    Fix unconnected media TX retry bug.
-                          Add Accton to the list of broken cards.
-			  Fix TX under-run bug for non DC21140 chips.
-			  Fix boot command probe bug in alloc_device() as
-			   reported by <koen.gadeyne@barco.com> and 
-			   <orava@nether.tky.hut.fi>.
-			  Add cache locks to prevent a race condition as
-			   reported by <csd@microplex.com> and 
-			   <baba@beckman.uiuc.edu>.
-			  Upgraded alloc_device() code.
-      0.431  28-Jun-96    Fix potential bug in queue_pkt() from discussion
-                          with <csd@microplex.com>
-      0.44   13-Aug-96    Fix RX overflow bug in 2114[023] chips.
-                          Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
-			  and <michael@compurex.com>.
-      0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
-                           with a loopback packet.
-      0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
-                           by <bhat@mundook.cs.mu.OZ.AU>
-      0.45    8-Dec-96    Include endian functions for PPC use, from work 
-                           by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
-      0.451  28-Dec-96    Added fix to allow autoprobe for modules after
-                           suggestion from <mjacob@feral.com>.
-      0.5    30-Jan-97    Added SROM decoding functions.
-                          Updated debug flags.
-			  Fix sleep/wakeup calls for PCI cards, bug reported
-			   by <cross@gweep.lkg.dec.com>.
-			  Added multi-MAC, one SROM feature from discussion
-			   with <mjacob@feral.com>.
-			  Added full module autoprobe capability.
-			  Added attempt to use an SMC9332 with broken SROM.
-			  Added fix for ZYNX multi-mac cards that didn't
-			   get their IRQs wired correctly.
-      0.51   13-Feb-97    Added endian fixes for the SROM accesses from
-			   <paubert@iram.es>
-			  Fix init_connection() to remove extra device reset.
-			  Fix MAC/PHY reset ordering in dc21140m_autoconf().
-			  Fix initialisation problem with lp->timeout in
-			   typeX_infoblock() from <paubert@iram.es>.
-			  Fix MII PHY reset problem from work done by
-			   <paubert@iram.es>.
-      0.52   26-Apr-97    Some changes may not credit the right people -
-                           a disk crash meant I lost some mail.
-			  Change RX interrupt routine to drop rather than 
-			   defer packets to avoid hang reported by 
-			   <g.thomas@opengroup.org>.
-			  Fix srom_exec() to return for COMPACT and type 1
-			   infoblocks.
-			  Added DC21142 and DC21143 functions.
-			  Added byte counters from <phil@tazenda.demon.co.uk>
-			  Added SA_INTERRUPT temporary fix from 
-			   <mjacob@feral.com>.
-      0.53   12-Nov-97    Fix the *_probe() to include 'eth??' name during
-                           module load: bug reported by
-			   <Piete.Brooks@cl.cam.ac.uk>
-			  Fix multi-MAC, one SROM, to work with 2114x chips:
-			   bug reported by <cmetz@inner.net>.
-			  Make above search independent of BIOS device scan
-			   direction.
-			  Completed DC2114[23] autosense functions.
-      0.531  21-Dec-97    Fix DE500-XA 100Mb/s bug reported by 
-                           <robin@intercore.com
-			  Fix type1_infoblock() bug introduced in 0.53, from
-			   problem reports by 
-			   <parmee@postecss.ncrfran.france.ncr.com> and
-			   <jo@ice.dillingen.baynet.de>.
-			  Added argument list to set up each board from either
-			   a module's command line or a compiled in #define.
-			  Added generic MII PHY functionality to deal with
-			   newer PHY chips.
-			  Fix the mess in 2.1.67.
-      0.532   5-Jan-98    Fix bug in mii_get_phy() reported by 
-                           <redhat@cococo.net>.
-                          Fix bug in pci_probe() for 64 bit systems reported
-			   by <belliott@accessone.com>.
-      0.533   9-Jan-98    Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
-      0.534  24-Jan-98    Fix last (?) endian bug from <geert@linux-m68k.org>
-      0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
-      0.536  21-Mar-98    Change pci_probe() to use the pci_dev structure.
-			  **Incompatible with 2.0.x from here.**
-      0.540   5-Jul-98    Atomicize assertion of dev->interrupt for SMP
-                           from <lma@varesearch.com>
-			  Add TP, AUI and BNC cases to 21140m_autoconf() for
-			   case where a 21140 under SROM control uses, e.g. AUI
-			   from problem report by <delchini@lpnp09.in2p3.fr>
-			  Add MII parallel detection to 2114x_autoconf() for
-			   case where no autonegotiation partner exists from
-			   problem report by <mlapsley@ndirect.co.uk>.
-			  Add ability to force connection type directly even
-			   when using SROM control from problem report by
-			   <earl@exis.net>.
-			  Updated the PCI interface to conform with the latest
-			   version. I hope nothing is broken...
-          		  Add TX done interrupt modification from suggestion
-			   by <Austin.Donnelly@cl.cam.ac.uk>.
-			  Fix is_anc_capable() bug reported by 
-			   <Austin.Donnelly@cl.cam.ac.uk>.
-			  Fix type[13]_infoblock() bug: during MII search, PHY
-			   lp->rst not run because lp->ibn not initialised -
-			   from report & fix by <paubert@iram.es>.
-			  Fix probe bug with EISA & PCI cards present from
-                           report by <eirik@netcom.com>.
-      0.541  24-Aug-98    Fix compiler problems associated with i386-string
-                           ops from multiple bug reports and temporary fix
-			   from <paubert@iram.es>.
-			  Fix pci_probe() to correctly emulate the old
-			   pcibios_find_class() function.
-			  Add an_exception() for old ZYNX346 and fix compile
-			   warning on PPC & SPARC, from <ecd@skynet.be>.
-			  Fix lastPCI to correctly work with compiled in
-			   kernels and modules from bug report by 
-			   <Zlatko.Calusic@CARNet.hr> et al.
-      0.542  15-Sep-98    Fix dc2114x_autoconf() to stop multiple messages
-                           when media is unconnected.
-			  Change dev->interrupt to lp->interrupt to ensure
-			   alignment for Alpha's and avoid their unaligned
-			   access traps. This flag is merely for log messages:
-			   should do something more definitive though...
-      0.543  30-Dec-98    Add SMP spin locking.
-      0.544   8-May-99    Fix for buggy SROM in Motorola embedded boards using
-                           a 21143 by <mmporter@home.com>.
-			  Change PCI/EISA bus probing order.
-      0.545  28-Nov-99    Further Moto SROM bug fix from 
-                           <mporter@eng.mcd.mot.com>
-                          Remove double checking for DEBUG_RX in de4x5_dbg_rx()
-			   from report by <geert@linux-m68k.org>
-      0.546  22-Feb-01    Fixes Alpha XP1000 oops.  The srom_search function
-                           was causing a page fault when initializing the
-                           variable 'pb', on a non de4x5 PCI device, in this
-                           case a PCI bridge (DEC chip 21152). The value of
-                           'pb' is now only initialized if a de4x5 chip is
-                           present. 
-                           <france@handhelds.org>  
-      0.547  08-Nov-01    Use library crc32 functions by <Matt_Domsch@dell.com>
-    =========================================================================
-*/
-
-static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/spinlock.h>
-#include <linux/crc32.h>
-
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
-#ifdef CONFIG_PPC
-#include <asm/machdep.h>
-#endif /* CONFIG_PPC */
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-
-#include "de4x5.h"
-
-#define c_char const char
-#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
-
-/*
-** MII Information
-*/
-struct phy_table {
-    int reset;              /* Hard reset required?                         */
-    int id;                 /* IEEE OUI                                     */
-    int ta;                 /* One cycle TA time - 802.3u is confusing here */
-    struct {                /* Non autonegotiation (parallel) speed det.    */
-	int reg;
-	int mask;
-	int value;
-    } spd;
-};
-
-struct mii_phy {
-    int reset;              /* Hard reset required?                      */
-    int id;                 /* IEEE OUI                                  */
-    int ta;                 /* One cycle TA time                         */
-    struct {                /* Non autonegotiation (parallel) speed det. */
-	int reg;
-	int mask;
-	int value;
-    } spd;
-    int addr;               /* MII address for the PHY                   */
-    u_char  *gep;           /* Start of GEP sequence block in SROM       */
-    u_char  *rst;           /* Start of reset sequence in SROM           */
-    u_int mc;               /* Media Capabilities                        */
-    u_int ana;              /* NWay Advertisement                        */
-    u_int fdx;              /* Full DupleX capabilites for each media    */
-    u_int ttm;              /* Transmit Threshold Mode for each media    */
-    u_int mci;              /* 21142 MII Connector Interrupt info        */
-};
-
-#define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
-
-struct sia_phy {
-    u_char mc;              /* Media Code                                */
-    u_char ext;             /* csr13-15 valid when set                   */
-    int csr13;              /* SIA Connectivity Register                 */
-    int csr14;              /* SIA TX/RX Register                        */
-    int csr15;              /* SIA General Register                      */
-    int gepc;               /* SIA GEP Control Information               */
-    int gep;                /* SIA GEP Data                              */
-};
-
-/*
-** Define the know universe of PHY devices that can be
-** recognised by this driver.
-*/
-static struct phy_table phy_info[] = {
-    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},       /* National TX      */
-    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},       /* Broadcom T4      */
-    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},       /* SEEQ T4          */
-    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}},       /* Cypress T4       */
-    {0, 0x7810     , 1, {0x14, 0x0800, 0x0800}}    /* Level One LTX970 */
-};
-
-/*
-** These GENERIC values assumes that the PHY devices follow 802.3u and
-** allow parallel detection to set the link partner ability register.
-** Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported.
-*/
-#define GENERIC_REG   0x05      /* Autoneg. Link Partner Advertisement Reg. */
-#define GENERIC_MASK  MII_ANLPA_100M /* All 100Mb/s Technologies            */
-#define GENERIC_VALUE MII_ANLPA_100M /* 100B-TX, 100B-TX FDX, 100B-T4       */
-
-/*
-** Define special SROM detection cases
-*/
-static c_char enet_det[][ETH_ALEN] = {
-    {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00},
-    {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00}
-};
-
-#define SMC    1
-#define ACCTON 2
-
-/*
-** SROM Repair definitions. If a broken SROM is detected a card may
-** use this information to help figure out what to do. This is a
-** "stab in the dark" and so far for SMC9332's only.
-*/
-static c_char srom_repair_info[][100] = {
-    {0x00,0x1e,0x00,0x00,0x00,0x08,             /* SMC9332 */
-     0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02,
-     0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50,
-     0x00,0x18,}
-};
-
-
-#ifdef DE4X5_DEBUG
-static int de4x5_debug = DE4X5_DEBUG;
-#else
-/*static int de4x5_debug = (DEBUG_MII | DEBUG_SROM | DEBUG_PCICFG | DEBUG_MEDIA | DEBUG_VERSION);*/
-static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
-#endif
-
-/*
-** Allow per adapter set up. For modules this is simply a command line
-** parameter, e.g.: 
-** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
-**
-** For a compiled in driver, place e.g.
-**     #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
-** here
-*/
-#ifdef DE4X5_PARM
-static char *args = DE4X5_PARM;
-#else
-static char *args;
-#endif
-
-struct parameters {
-    int fdx;
-    int autosense;
-};
-
-#define DE4X5_AUTOSENSE_MS 250      /* msec autosense tick (DE500) */
-
-#define DE4X5_NDA 0xffe0            /* No Device (I/O) Address */
-
-/*
-** Ethernet PROM defines
-*/
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-/*
-** Ethernet Info
-*/
-#define PKT_BUF_SZ	1536            /* Buffer size for each Tx/Rx buffer */
-#define IEEE802_3_SZ    1518            /* Packet + CRC */
-#define MAX_PKT_SZ   	1514            /* Maximum ethernet packet length */
-#define MAX_DAT_SZ   	1500            /* Maximum ethernet data length */
-#define MIN_DAT_SZ   	1               /* Minimum ethernet data length */
-#define PKT_HDR_LEN     14              /* Addresses and data length info */
-#define FAKE_FRAME_LEN  (MAX_PKT_SZ + 1)
-#define QUEUE_PKT_TIMEOUT (3*HZ)        /* 3 second timeout */
-
-
-/*
-** EISA bus defines
-*/
-#define DE4X5_EISA_IO_PORTS   0x0c00    /* I/O port base address, slot 0 */
-#define DE4X5_EISA_TOTAL_SIZE 0x100     /* I/O address extent */
-
-#define MAX_EISA_SLOTS 16
-#define EISA_SLOT_INC 0x1000
-#define EISA_ALLOWED_IRQ_LIST  {5, 9, 10, 11}
-
-#define DE4X5_SIGNATURE {"DE425","DE434","DE435","DE450","DE500"}
-#define DE4X5_NAME_LENGTH 8
-
-/*
-** Ethernet PROM defines for DC21040
-*/
-#define PROBE_LENGTH    32
-#define ETH_PROM_SIG    0xAA5500FFUL
-
-/*
-** PCI Bus defines
-*/
-#define PCI_MAX_BUS_NUM      8
-#define DE4X5_PCI_TOTAL_SIZE 0x80       /* I/O address extent */
-#define DE4X5_CLASS_CODE     0x00020000 /* Network controller, Ethernet */
-#define NO_MORE_PCI          -2         /* PCI bus search all done */
-
-/*
-** Memory Alignment. Each descriptor is 4 longwords long. To force a
-** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry. 
-*/
-#define ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
-#define ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
-#define ALIGN16     ((u_long)16 - 1)    /* 4 longword align */
-#define ALIGN32     ((u_long)32 - 1)    /* 8 longword align */
-#define ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
-#define ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
-
-#define ALIGN         ALIGN32           /* Keep the DC21040 happy... */
-#define CACHE_ALIGN   CAL_16LONG
-#define DESC_SKIP_LEN DSL_0             /* Must agree with DESC_ALIGN */
-/*#define DESC_ALIGN    u32 dummy[4];  / * Must agree with DESC_SKIP_LEN */
-#define DESC_ALIGN
-
-#ifndef DEC_ONLY                        /* See README.de4x5 for using this */
-static int dec_only;
-#else
-static int dec_only = 1;
-#endif
-
-/*
-** DE4X5 IRQ ENABLE/DISABLE
-*/
-#define ENABLE_IRQs { \
-    imr |= lp->irq_en;\
-    outl(imr, DE4X5_IMR);               /* Enable the IRQs */\
-}
-
-#define DISABLE_IRQs {\
-    imr = inl(DE4X5_IMR);\
-    imr &= ~lp->irq_en;\
-    outl(imr, DE4X5_IMR);               /* Disable the IRQs */\
-}
-
-#define UNMASK_IRQs {\
-    imr |= lp->irq_mask;\
-    outl(imr, DE4X5_IMR);               /* Unmask the IRQs */\
-}
-
-#define MASK_IRQs {\
-    imr = inl(DE4X5_IMR);\
-    imr &= ~lp->irq_mask;\
-    outl(imr, DE4X5_IMR);               /* Mask the IRQs */\
-}
-
-/*
-** DE4X5 START/STOP
-*/
-#define START_DE4X5 {\
-    omr = inl(DE4X5_OMR);\
-    omr |= OMR_ST | OMR_SR;\
-    outl(omr, DE4X5_OMR);               /* Enable the TX and/or RX */\
-}
-
-#define STOP_DE4X5 {\
-    omr = inl(DE4X5_OMR);\
-    omr &= ~(OMR_ST|OMR_SR);\
-    outl(omr, DE4X5_OMR);               /* Disable the TX and/or RX */ \
-}
-
-/*
-** DE4X5 SIA RESET
-*/
-#define RESET_SIA outl(0, DE4X5_SICR);  /* Reset SIA connectivity regs */
-
-/*
-** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
-*/
-#define DE4X5_AUTOSENSE_MS  250
-
-/*
-** SROM Structure
-*/
-struct de4x5_srom {
-    char sub_vendor_id[2];
-    char sub_system_id[2];
-    char reserved[12];
-    char id_block_crc;
-    char reserved2;
-    char version;
-    char num_controllers;
-    char ieee_addr[6];
-    char info[100];
-    short chksum;
-};
-#define SUB_VENDOR_ID 0x500a
-
-/*
-** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
-** and have sizes of both a power of 2 and a multiple of 4.
-** A size of 256 bytes for each buffer could be chosen because over 90% of
-** all packets in our network are <256 bytes long and 64 longword alignment
-** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
-** descriptors are needed for machines with an ALPHA CPU.
-*/
-#define NUM_RX_DESC 8                   /* Number of RX descriptors   */
-#define NUM_TX_DESC 32                  /* Number of TX descriptors   */
-#define RX_BUFF_SZ  1536                /* Power of 2 for kmalloc and */
-                                        /* Multiple of 4 for DC21040  */
-                                        /* Allows 512 byte alignment  */
-struct de4x5_desc {
-    volatile s32 status;
-    u32 des1;
-    u32 buf;
-    u32 next;
-    DESC_ALIGN
-};
-
-/*
-** The DE4X5 private structure
-*/
-#define DE4X5_PKT_STAT_SZ 16
-#define DE4X5_PKT_BIN_SZ  128            /* Should be >=100 unless you
-                                            increase DE4X5_PKT_STAT_SZ */
-
-struct pkt_stats {
-	u_int bins[DE4X5_PKT_STAT_SZ];      /* Private stats counters       */
-	u_int unicast;
-	u_int multicast;
-	u_int broadcast;
-	u_int excessive_collisions;
-	u_int tx_underruns;
-	u_int excessive_underruns;
-	u_int rx_runt_frames;
-	u_int rx_collision;
-	u_int rx_dribble;
-	u_int rx_overflow;
-};
-
-struct de4x5_private {
-    char adapter_name[80];                  /* Adapter name                 */
-    u_long interrupt;                       /* Aligned ISR flag             */
-    struct de4x5_desc *rx_ring;		    /* RX descriptor ring           */
-    struct de4x5_desc *tx_ring;		    /* TX descriptor ring           */
-    struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
-    struct sk_buff *rx_skb[NUM_RX_DESC];    /* RX skb's                     */
-    int rx_new, rx_old;                     /* RX descriptor ring pointers  */
-    int tx_new, tx_old;                     /* TX descriptor ring pointers  */
-    char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
-    char frame[64];                         /* Min sized packet for loopback*/
-    spinlock_t lock;                        /* Adapter specific spinlock    */
-    struct net_device_stats stats;          /* Public stats                 */
-    struct pkt_stats pktStats;	            /* Private stats counters	    */
-    char rxRingSize;
-    char txRingSize;
-    int  bus;                               /* EISA or PCI                  */
-    int  bus_num;                           /* PCI Bus number               */
-    int  device;                            /* Device number on PCI bus     */
-    int  state;                             /* Adapter OPENED or CLOSED     */
-    int  chipset;                           /* DC21040, DC21041 or DC21140  */
-    s32  irq_mask;                          /* Interrupt Mask (Enable) bits */
-    s32  irq_en;                            /* Summary interrupt bits       */
-    int  media;                             /* Media (eg TP), mode (eg 100B)*/
-    int  c_media;                           /* Remember the last media conn */
-    int  fdx;                               /* media full duplex flag       */
-    int  linkOK;                            /* Link is OK                   */
-    int  autosense;                         /* Allow/disallow autosensing   */
-    int  tx_enable;                         /* Enable descriptor polling    */
-    int  setup_f;                           /* Setup frame filtering type   */
-    int  local_state;                       /* State within a 'media' state */
-    struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
-    struct sia_phy sia;                     /* SIA PHY Information          */
-    int  active;                            /* Index to active PHY device   */
-    int  mii_cnt;                           /* Number of attached PHY's     */
-    int  timeout;                           /* Scheduling counter           */
-    struct timer_list timer;                /* Timer info for kernel        */
-    int tmp;                                /* Temporary global per card    */
-    struct {
-	void *priv;                         /* Original kmalloc'd mem addr  */
-	u_long lock;                        /* Lock the cache accesses      */
-	s32 csr0;                           /* Saved Bus Mode Register      */
-	s32 csr6;                           /* Saved Operating Mode Reg.    */
-	s32 csr7;                           /* Saved IRQ Mask Register      */
-	s32 gep;                            /* Saved General Purpose Reg.   */
-	s32 gepc;                           /* Control info for GEP         */
-	s32 csr13;                          /* Saved SIA Connectivity Reg.  */
-	s32 csr14;                          /* Saved SIA TX/RX Register     */
-	s32 csr15;                          /* Saved SIA General Register   */
-	int save_cnt;                       /* Flag if state already saved  */
-	struct sk_buff *skb;                /* Save the (re-ordered) skb's  */
-    } cache;
-    struct de4x5_srom srom;                 /* A copy of the SROM           */
-    struct net_device *next_module;             /* Link to the next module      */
-    int rx_ovf;                             /* Check for 'RX overflow' tag  */
-    int useSROM;                            /* For non-DEC card use SROM    */
-    int useMII;                             /* Infoblock using the MII      */
-    int asBitValid;                         /* Autosense bits in GEP?       */
-    int asPolarity;                         /* 0 => asserted high           */
-    int asBit;                              /* Autosense bit number in GEP  */
-    int defMedium;                          /* SROM default medium          */
-    int tcount;                             /* Last infoblock number        */
-    int infoblock_init;                     /* Initialised this infoblock?  */
-    int infoleaf_offset;                    /* SROM infoleaf for controller */
-    s32 infoblock_csr6;                     /* csr6 value in SROM infoblock */
-    int infoblock_media;                    /* infoblock media              */
-    int (*infoleaf_fn)(struct net_device *);    /* Pointer to infoleaf function */
-    u_char *rst;                            /* Pointer to Type 5 reset info */
-    u_char  ibn;                            /* Infoblock number             */
-    struct parameters params;               /* Command line/ #defined params */
-    struct pci_dev *pdev;		    /* Device cookie for DMA alloc  */
-    dma_addr_t dma_rings;		    /* DMA handle for rings	    */
-    int dma_size;			    /* Size of the DMA area	    */
-    char *rx_bufs;			    /* rx bufs on alpha, sparc, ... */
-};
-
-/*
-** Kludge to get around the fact that the CSR addresses have different
-** offsets in the PCI and EISA boards. Also note that the ethernet address
-** PROM is accessed differently.
-*/
-static struct bus_type {
-    int bus;
-    int bus_num;
-    int device;
-    int chipset;
-    struct de4x5_srom srom;
-    int autosense;
-    int useSROM;
-} bus;
-
-/*
-** To get around certain poxy cards that don't provide an SROM
-** for the second and more DECchip, I have to key off the first
-** chip's address. I'll assume there's not a bad SROM iff:
-**
-**      o the chipset is the same
-**      o the bus number is the same and > 0
-**      o the sum of all the returned hw address bytes is 0 or 0x5fa
-**
-** Also have to save the irq for those cards whose hardware designers
-** can't follow the PCI to PCI Bridge Architecture spec.
-*/
-static struct {
-    int chipset;
-    int bus;
-    int irq;
-    u_char addr[ETH_ALEN];
-} last = {0,};
-
-/*
-** The transmit ring full condition is described by the tx_old and tx_new
-** pointers by:
-**    tx_old            = tx_new    Empty ring
-**    tx_old            = tx_new+1  Full ring
-**    tx_old+txRingSize = tx_new+1  Full ring  (wrapped condition)
-*/
-#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
-			lp->tx_old+lp->txRingSize-lp->tx_new-1:\
-			lp->tx_old               -lp->tx_new-1)
-
-#define TX_PKT_PENDING (lp->tx_old != lp->tx_new)
-
-/*
-** Public Functions
-*/
-static int     de4x5_open(struct net_device *dev);
-static int     de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static void    de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int     de4x5_close(struct net_device *dev);
-static struct  net_device_stats *de4x5_get_stats(struct net_device *dev);
-static void    de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len);
-static void    set_multicast_list(struct net_device *dev);
-static int     de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-
-/*
-** Private functions
-*/
-static int     de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev);
-static int     de4x5_init(struct net_device *dev);
-static int     de4x5_sw_reset(struct net_device *dev);
-static int     de4x5_rx(struct net_device *dev);
-static int     de4x5_tx(struct net_device *dev);
-static int     de4x5_ast(struct net_device *dev);
-static int     de4x5_txur(struct net_device *dev);
-static int     de4x5_rx_ovfc(struct net_device *dev);
-
-static int     autoconf_media(struct net_device *dev);
-static void    create_packet(struct net_device *dev, char *frame, int len);
-static void    load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb);
-static int     dc21040_autoconf(struct net_device *dev);
-static int     dc21041_autoconf(struct net_device *dev);
-static int     dc21140m_autoconf(struct net_device *dev);
-static int     dc2114x_autoconf(struct net_device *dev);
-static int     srom_autoconf(struct net_device *dev);
-static int     de4x5_suspect_state(struct net_device *dev, int timeout, int prev_state, int (*fn)(struct net_device *, int), int (*asfn)(struct net_device *));
-static int     dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct net_device *, int));
-static int     test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
-static int     test_for_100Mb(struct net_device *dev, int msec);
-static int     wait_for_link(struct net_device *dev);
-static int     test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec);
-static int     is_spd_100(struct net_device *dev);
-static int     is_100_up(struct net_device *dev);
-static int     is_10_up(struct net_device *dev);
-static int     is_anc_capable(struct net_device *dev);
-static int     ping_media(struct net_device *dev, int msec);
-static struct sk_buff *de4x5_alloc_rx_buff(struct net_device *dev, int index, int len);
-static void    de4x5_free_rx_buffs(struct net_device *dev);
-static void    de4x5_free_tx_buffs(struct net_device *dev);
-static void    de4x5_save_skbs(struct net_device *dev);
-static void    de4x5_rst_desc_ring(struct net_device *dev);
-static void    de4x5_cache_state(struct net_device *dev, int flag);
-static void    de4x5_put_cache(struct net_device *dev, struct sk_buff *skb);
-static void    de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb);
-static struct  sk_buff *de4x5_get_cache(struct net_device *dev);
-static void    de4x5_setup_intr(struct net_device *dev);
-static void    de4x5_init_connection(struct net_device *dev);
-static int     de4x5_reset_phy(struct net_device *dev);
-static void    reset_init_sia(struct net_device *dev, s32 sicr, s32 strr, s32 sigr);
-static int     test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec);
-static int     test_tp(struct net_device *dev, s32 msec);
-static int     EISA_signature(char *name, s32 eisa_id);
-static int     PCI_signature(char *name, struct bus_type *lp);
-static void    DevicePresent(u_long iobase);
-static void    enet_addr_rst(u_long aprom_addr);
-static int     de4x5_bad_srom(struct bus_type *lp);
-static short   srom_rd(u_long address, u_char offset);
-static void    srom_latch(u_int command, u_long address);
-static void    srom_command(u_int command, u_long address);
-static void    srom_address(u_int command, u_long address, u_char offset);
-static short   srom_data(u_int command, u_long address);
-/*static void    srom_busy(u_int command, u_long address);*/
-static void    sendto_srom(u_int command, u_long addr);
-static int     getfrom_srom(u_long addr);
-static int     srom_map_media(struct net_device *dev);
-static int     srom_infoleaf_info(struct net_device *dev);
-static void    srom_init(struct net_device *dev);
-static void    srom_exec(struct net_device *dev, u_char *p);
-static int     mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
-static void    mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
-static int     mii_rdata(u_long ioaddr);
-static void    mii_wdata(int data, int len, u_long ioaddr);
-static void    mii_ta(u_long rw, u_long ioaddr);
-static int     mii_swap(int data, int len);
-static void    mii_address(u_char addr, u_long ioaddr);
-static void    sendto_mii(u32 command, int data, u_long ioaddr);
-static int     getfrom_mii(u32 command, u_long ioaddr);
-static int     mii_get_oui(u_char phyaddr, u_long ioaddr);
-static int     mii_get_phy(struct net_device *dev);
-static void    SetMulticastFilter(struct net_device *dev);
-static int     get_hw_addr(struct net_device *dev);
-static void    srom_repair(struct net_device *dev, int card);
-static int     test_bad_enet(struct net_device *dev, int status);
-static int     an_exception(struct bus_type *lp);
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-static void    eisa_probe(struct net_device *dev, u_long iobase);
-#endif
-static void    pci_probe(struct net_device *dev, u_long iobase);
-static void    srom_search(struct pci_dev *pdev);
-static char    *build_setup_frame(struct net_device *dev, int mode);
-static void    disable_ast(struct net_device *dev);
-static void    enable_ast(struct net_device *dev, u32 time_out);
-static long    de4x5_switch_mac_port(struct net_device *dev);
-static int     gep_rd(struct net_device *dev);
-static void    gep_wr(s32 data, struct net_device *dev);
-static void    timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec);
-static void    yawn(struct net_device *dev, int state);
-static void    link_modules(struct net_device *dev, struct net_device *tmp);
-static void    de4x5_parse_params(struct net_device *dev);
-static void    de4x5_dbg_open(struct net_device *dev);
-static void    de4x5_dbg_mii(struct net_device *dev, int k);
-static void    de4x5_dbg_media(struct net_device *dev);
-static void    de4x5_dbg_srom(struct de4x5_srom *p);
-static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
-static int     de4x5_strncmp(char *a, char *b, int n);
-static int     dc21041_infoleaf(struct net_device *dev);
-static int     dc21140_infoleaf(struct net_device *dev);
-static int     dc21142_infoleaf(struct net_device *dev);
-static int     dc21143_infoleaf(struct net_device *dev);
-static int     type0_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     type1_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     type2_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     type3_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     type4_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     type5_infoblock(struct net_device *dev, u_char count, u_char *p);
-static int     compact_infoblock(struct net_device *dev, u_char count, u_char *p);
-
-#ifdef MODULE
-int  init_module(void);
-void cleanup_module(void);
-static struct net_device *unlink_modules(struct net_device *p);
-static struct net_device *insert_device(struct net_device *dev, u_long iobase,
-				     int (*init)(struct net_device *));
-static int count_adapters(void);
-static int loading_module = 1;
-MODULE_PARM(de4x5_debug, "i");
-MODULE_PARM(dec_only, "i");
-MODULE_PARM(args, "s");
-MODULE_PARM_DESC(de4x5_debug, "de4x5 debug mask");
-MODULE_PARM_DESC(dec_only, "de4x5 probe only for Digital boards (0-1)");
-MODULE_PARM_DESC(args, "de4x5 full duplex and media type settings; see de4x5.c for details");
-MODULE_LICENSE("GPL");
-
-# else
-static int loading_module;
-#endif /* MODULE */
-
-static char name[DE4X5_NAME_LENGTH + 1];
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
-static int lastEISA;
-#  ifdef DE4X5_FORCE_EISA                 /* Force an EISA bus probe or not */
-static int forceEISA = 1;
-#  else
-static int forceEISA;
-#  endif
-#endif
-static int num_de4x5s;
-static int cfrv, useSROM;
-static int lastPCI = -1;
-static struct net_device *lastModule;
-static struct pci_dev *pdev;
-
-/*
-** List the SROM infoleaf functions and chipsets
-*/
-struct InfoLeaf {
-    int chipset;
-    int (*fn)(struct net_device *);
-};
-static struct InfoLeaf infoleaf_array[] = {
-    {DC21041, dc21041_infoleaf},
-    {DC21140, dc21140_infoleaf},
-    {DC21142, dc21142_infoleaf},
-    {DC21143, dc21143_infoleaf}
-};
-#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
-
-/*
-** List the SROM info block functions
-*/
-static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
-    type0_infoblock,
-    type1_infoblock,
-    type2_infoblock,
-    type3_infoblock,
-    type4_infoblock,
-    type5_infoblock,
-    compact_infoblock
-};
-
-#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
-
-/*
-** Miscellaneous defines...
-*/
-#define RESET_DE4X5 {\
-    int i;\
-    i=inl(DE4X5_BMR);\
-    mdelay(1);\
-    outl(i | BMR_SWR, DE4X5_BMR);\
-    mdelay(1);\
-    outl(i, DE4X5_BMR);\
-    mdelay(1);\
-    for (i=0;i<5;i++) {inl(DE4X5_BMR); mdelay(1);}\
-    mdelay(1);\
-}
-
-#define PHY_HARD_RESET {\
-    outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */\
-    mdelay(1);                           /* Assert for 1ms */\
-    outl(0x00, DE4X5_GEP);\
-    mdelay(2);                           /* Wait for 2ms */\
-}
-
-
-/*
-** Autoprobing in modules is allowed here. See the top of the file for
-** more info.
-*/
-int __init 
-de4x5_probe(struct net_device *dev)
-{
-    u_long iobase = dev->base_addr;
-
-    pci_probe(dev, iobase);
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-    if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) {
-        eisa_probe(dev, iobase);
-    }
-#endif
-    
-    return (dev->priv ? 0 : -ENODEV);
-}
-
-static int __init 
-de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev)
-{
-    struct bus_type *lp = &bus;
-    int i, status=0;
-    char *tmp;
-    
-    /* Ensure we're not sleeping */
-    if (lp->bus == EISA) {
-	outb(WAKEUP, PCI_CFPM);
-    } else {
-	pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
-				  PCI_CFDA_PSM, WAKEUP);
-    }
-    mdelay(10);
-
-    RESET_DE4X5;
-    
-    if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
-	return -ENXIO;                       /* Hardware could not reset */
-    }
-    
-    /* 
-    ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
-    */
-    useSROM = FALSE;
-    if (lp->bus == PCI) {
-	PCI_signature(name, lp);
-    } else {
-	EISA_signature(name, EISA_ID0);
-    }
-    
-    if (*name == '\0') {                     /* Not found a board signature */
-	return -ENXIO;
-    }
-    
-    dev->base_addr = iobase;
-    if (lp->bus == EISA) {
-	printk("%s: %s at 0x%04lx (EISA slot %ld)", 
-	       dev->name, name, iobase, ((iobase>>12)&0x0f));
-    } else {                                 /* PCI port address */
-	printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
-	       iobase, lp->bus_num, lp->device);
-    }
-    
-    printk(", h/w address ");
-    status = get_hw_addr(dev);
-    for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
-	printk("%2.2x:", dev->dev_addr[i]);
-    }
-    printk("%2.2x,\n", dev->dev_addr[i]);
-    
-    if (status != 0) {
-	printk("      which has an Ethernet PROM CRC error.\n");
-	return -ENXIO;
-    } else {
-	struct de4x5_private *lp;
-	
-	/* 
-	** Reserve a section of kernel memory for the adapter
-	** private area and the TX/RX descriptor rings.
-	*/
-	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + ALIGN, 
-				     GFP_KERNEL);
-	if (dev->priv == NULL) {
-	    return -ENOMEM;
-	}
-	
-	/*
-	** Align to a longword boundary
-	*/
-	tmp = dev->priv;
-	dev->priv = (void *)(((u_long)dev->priv + ALIGN) & ~ALIGN);
-	lp = (struct de4x5_private *)dev->priv;
-	memset(dev->priv, 0, sizeof(struct de4x5_private));
-	lp->bus = bus.bus;
-	lp->bus_num = bus.bus_num;
-	lp->device = bus.device;
-	lp->chipset = bus.chipset;
-	lp->cache.priv = tmp;
-	lp->cache.gepc = GEP_INIT;
-	lp->asBit = GEP_SLNK;
-	lp->asPolarity = GEP_SLNK;
-	lp->asBitValid = TRUE;
-	lp->timeout = -1;
-	lp->useSROM = useSROM;
-	lp->pdev = pdev;
-	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
-	lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-	de4x5_parse_params(dev);
-
-	/*
-	** Choose correct autosensing in case someone messed up
-	*/
-        lp->autosense = lp->params.autosense;
-        if (lp->chipset != DC21140) {
-            if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
-                lp->params.autosense = TP;
-            }
-            if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
-                lp->params.autosense = BNC;
-            }
-        }
-	lp->fdx = lp->params.fdx;
-	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
-
-	lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
-#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY)
-	lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + ALIGN;
-#endif
-	lp->rx_ring = pci_alloc_consistent(pdev, lp->dma_size, &lp->dma_rings);
-	if (lp->rx_ring == NULL) {
-	    kfree(lp->cache.priv);
-	    lp->cache.priv = NULL;
-	    return -ENOMEM;
-	}
-
-	lp->tx_ring = lp->rx_ring + NUM_RX_DESC;
-	    
-	/*
-	** Set up the RX descriptor ring (Intels)
-	** Allocate contiguous receive buffers, long word aligned (Alphas) 
-	*/
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
-	for (i=0; i<NUM_RX_DESC; i++) {
-	    lp->rx_ring[i].status = 0;
-	    lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
-	    lp->rx_ring[i].buf = 0;
-	    lp->rx_ring[i].next = 0;
-	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
-	}
-
-#else
-	{
-		dma_addr_t dma_rx_bufs;
-
-		dma_rx_bufs = lp->dma_rings + (NUM_RX_DESC + NUM_TX_DESC)
-		      	* sizeof(struct de4x5_desc);
-		dma_rx_bufs = (dma_rx_bufs + ALIGN) & ~ALIGN;
-		lp->rx_bufs = (char *)(((long)(lp->rx_ring + NUM_RX_DESC
-		      	+ NUM_TX_DESC) + ALIGN) & ~ALIGN);
-		for (i=0; i<NUM_RX_DESC; i++) {
-	    		lp->rx_ring[i].status = 0;
-	    		lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
-	    		lp->rx_ring[i].buf =
-				cpu_to_le32(dma_rx_bufs+i*RX_BUFF_SZ);
-	    		lp->rx_ring[i].next = 0;
-	    		lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
-		}
-
-	}
-#endif
-
-	barrier();
-	    
-	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
-				DE4X5_EISA_TOTAL_SIZE), 
-		       lp->adapter_name);
-	    
-	lp->rxRingSize = NUM_RX_DESC;
-	lp->txRingSize = NUM_TX_DESC;
-	    
-	/* Write the end of list marker to the descriptor lists */
-	lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
-	lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
-
-	/* Tell the adapter where the TX/RX rings are located. */
-	outl(lp->dma_rings, DE4X5_RRBA);
-	outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
-	     DE4X5_TRBA);
-	    
-	/* Initialise the IRQ mask and Enable/Disable */
-	lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
-	lp->irq_en   = IMR_NIM | IMR_AIM;
-
-	/* Create a loopback packet frame for later media probing */
-	create_packet(dev, lp->frame, sizeof(lp->frame));
-
-	/* Check if the RX overflow bug needs testing for */
-	i = cfrv & 0x000000fe;
-	if ((lp->chipset == DC21140) && (i == 0x20)) {
-	    lp->rx_ovf = 1;
-	}
-
-	/* Initialise the SROM pointers if possible */
-	if (lp->useSROM) {
-	    lp->state = INITIALISED;
-	    if (srom_infoleaf_info(dev)) {
-		return -ENXIO;
-	    }
-	    srom_init(dev);
-	}
-
-	lp->state = CLOSED;
-
-	/*
-	** Check for an MII interface
-	*/
-	if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
-	    mii_get_phy(dev);
-	}
-	
-#ifndef __sparc_v9__
-	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
-#else
-	printk("      and requires IRQ%x (provided by %s).\n", dev->irq,
-#endif
-	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
-    }
-    
-    if (de4x5_debug & DEBUG_VERSION) {
-	printk(version);
-    }
-    
-    /* The DE4X5-specific entries in the device structure. */
-    dev->open = &de4x5_open;
-    dev->hard_start_xmit = &de4x5_queue_pkt;
-    dev->stop = &de4x5_close;
-    dev->get_stats = &de4x5_get_stats;
-    dev->set_multicast_list = &set_multicast_list;
-    dev->do_ioctl = &de4x5_ioctl;
-    
-    dev->mem_start = 0;
-    
-    /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
-    
-    /* Let the adapter sleep to save power */
-    yawn(dev, SLEEP);
-    
-    return status;
-}
-
-
-static int
-de4x5_open(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int i, status = 0;
-    s32 omr;
-
-    /* Allocate the RX buffers */
-    for (i=0; i<lp->rxRingSize; i++) {
-	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
-	    de4x5_free_rx_buffs(dev);
-	    return -EAGAIN;
-	}
-    }
-
-    /*
-    ** Wake up the adapter
-    */
-    yawn(dev, WAKEUP);
-
-    /* 
-    ** Re-initialize the DE4X5... 
-    */
-    status = de4x5_init(dev);
-    lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
-    lp->state = OPEN;
-    de4x5_dbg_open(dev);
-    
-    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
-		                                     lp->adapter_name, dev)) {
-	printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
-	if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
-			                             lp->adapter_name, dev)) {
-	    printk("\n              Cannot get IRQ- reconfigure your hardware.\n");
-	    disable_ast(dev);
-	    de4x5_free_rx_buffs(dev);
-	    de4x5_free_tx_buffs(dev);
-	    yawn(dev, SLEEP);
-	    lp->state = CLOSED;
-	    return -EAGAIN;
-	} else {
-	    printk("\n              Succeeded, but you should reconfigure your hardware to avoid this.\n");
-	    printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
-	}
-    }
-
-    lp->interrupt = UNMASK_INTERRUPTS;
-    dev->trans_start = jiffies;
-    
-    START_DE4X5;
-	
-    de4x5_setup_intr(dev);
-    
-    if (de4x5_debug & DEBUG_OPEN) {
-	printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
-	printk("\tbmr:  0x%08x\n", inl(DE4X5_BMR));
-	printk("\timr:  0x%08x\n", inl(DE4X5_IMR));
-	printk("\tomr:  0x%08x\n", inl(DE4X5_OMR));
-	printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR));
-	printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR));
-	printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
-	printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
-    }
-    
-    MOD_INC_USE_COUNT;
-    
-    return status;
-}
-
-/*
-** Initialize the DE4X5 operating conditions. NB: a chip problem with the
-** DC21140 requires using perfect filtering mode for that chip. Since I can't
-** see why I'd want > 14 multicast addresses, I have changed all chips to use
-** the perfect filtering mode. Keep the DMA burst length at 8: there seems
-** to be data corruption problems if it is larger (UDP errors seen from a
-** ttcp source).
-*/
-static int
-de4x5_init(struct net_device *dev)
-{  
-    /* Lock out other processes whilst setting up the hardware */
-    netif_stop_queue(dev);
-    
-    de4x5_sw_reset(dev);
-    
-    /* Autoconfigure the connected port */
-    autoconf_media(dev);
-    
-    return 0;
-}
-
-static int
-de4x5_sw_reset(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int i, j, status = 0;
-    s32 bmr, omr;
-    
-    /* Select the MII or SRL port now and RESET the MAC */
-    if (!lp->useSROM) {
-	if (lp->phy[lp->active].id != 0) {
-	    lp->infoblock_csr6 = OMR_SDP | OMR_PS | OMR_HBD;
-	} else {
-	    lp->infoblock_csr6 = OMR_SDP | OMR_TTM;
-	}
-	de4x5_switch_mac_port(dev);
-    }
-
-    /* 
-    ** Set the programmable burst length to 8 longwords for all the DC21140
-    ** Fasternet chips and 4 longwords for all others: DMA errors result
-    ** without these values. Cache align 16 long.
-    */
-    bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN;
-    bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
-    outl(bmr, DE4X5_BMR);
-
-    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
-    if (lp->chipset == DC21140) {
-	omr |= (OMR_SDP | OMR_SB);
-    }
-    lp->setup_f = PERFECT;
-    outl(lp->dma_rings, DE4X5_RRBA);
-    outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
-	 DE4X5_TRBA);
-    
-    lp->rx_new = lp->rx_old = 0;
-    lp->tx_new = lp->tx_old = 0;
-    
-    for (i = 0; i < lp->rxRingSize; i++) {
-	lp->rx_ring[i].status = cpu_to_le32(R_OWN);
-    }
-    
-    for (i = 0; i < lp->txRingSize; i++) {
-	lp->tx_ring[i].status = cpu_to_le32(0);
-    }
-    
-    barrier();
-
-    /* Build the setup frame depending on filtering mode */
-    SetMulticastFilter(dev);
-    
-    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, (struct sk_buff *)1);
-    outl(omr|OMR_ST, DE4X5_OMR);
-
-    /* Poll for setup frame completion (adapter interrupts are disabled now) */
-    sti();                                       /* Ensure timer interrupts */
-    for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
-	mdelay(1);
-	if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
-    }
-    outl(omr, DE4X5_OMR);                        /* Stop everything! */
-
-    if (j == 0) {
-	printk("%s: Setup frame timed out, status %08x\n", dev->name, 
-	       inl(DE4X5_STS));
-	status = -EIO;
-    }
-    
-    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-    lp->tx_old = lp->tx_new;
-
-    return status;
-}
-
-/* 
-** Writes a socket buffer address to the next available transmit descriptor.
-*/
-static int
-de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int status = 0;
-    u_long flags = 0;
-
-    netif_stop_queue(dev);
-    if (lp->tx_enable == NO) {                   /* Cannot send for now */
-	return -1;                                
-    }
-    
-    /*
-    ** Clean out the TX ring asynchronously to interrupts - sometimes the
-    ** interrupts are lost by delayed descriptor status updates relative to
-    ** the irq assertion, especially with a busy PCI bus.
-    */
-    spin_lock_irqsave(&lp->lock, flags);
-    de4x5_tx(dev);
-    spin_unlock_irqrestore(&lp->lock, flags);
-
-    /* Test if cache is already locked - requeue skb if so */
-    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) 
-	return -1;
-
-    /* Transmit descriptor ring full or stale skb */
-    if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) {
-	if (lp->interrupt) {
-	    de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
-	} else {
-	    de4x5_put_cache(dev, skb);
-	}
-	if (de4x5_debug & DEBUG_TX) {
-	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), netif_queue_stopped(dev), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
-	}
-    } else if (skb->len > 0) {
-	/* If we already have stuff queued locally, use that first */
-	if (lp->cache.skb && !lp->interrupt) {
-	    de4x5_put_cache(dev, skb);
-	    skb = de4x5_get_cache(dev);
-	}
-
-	while (skb && !netif_queue_stopped(dev) &&
-	       (u_long) lp->tx_skb[lp->tx_new] <= 1) {
-	    spin_lock_irqsave(&lp->lock, flags);
-	    netif_stop_queue(dev);
-	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
- 	    lp->stats.tx_bytes += skb->len;
-	    outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
-		
-	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	    dev->trans_start = jiffies;
-		    
-	    if (TX_BUFFS_AVAIL) {
-		netif_start_queue(dev);         /* Another pkt may be queued */
-	    }
-	    skb = de4x5_get_cache(dev);
-	    spin_unlock_irqrestore(&lp->lock, flags);
-	}
-	if (skb) de4x5_putb_cache(dev, skb);
-    }
-    
-    lp->cache.lock = 0;
-
-    return status;
-}
-
-/*
-** The DE4X5 interrupt handler. 
-** 
-** I/O Read/Writes through intermediate PCI bridges are never 'posted',
-** so that the asserted interrupt always has some real data to work with -
-** if these I/O accesses are ever changed to memory accesses, ensure the
-** STS write is read immediately to complete the transaction if the adapter
-** is not on bus 0. Lost interrupts can still occur when the PCI bus load
-** is high and descriptor status bits cannot be set before the associated
-** interrupt is asserted and this routine entered.
-*/
-static void
-de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-    struct net_device *dev = (struct net_device *)dev_id;
-    struct de4x5_private *lp;
-    s32 imr, omr, sts, limit;
-    u_long iobase;
-    
-    if (dev == NULL) {
-	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
-	return;
-    }
-    lp = (struct de4x5_private *)dev->priv;
-    spin_lock(&lp->lock);
-    iobase = dev->base_addr;
-	
-    DISABLE_IRQs;                        /* Ensure non re-entrancy */
-
-    if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt))
-	printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
-    synchronize_irq();
-	
-    for (limit=0; limit<8; limit++) {
-	sts = inl(DE4X5_STS);            /* Read IRQ status */
-	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
-	    
-	if (!(sts & lp->irq_mask)) break;/* All done */
-	    
-	if (sts & (STS_RI | STS_RU))     /* Rx interrupt (packet[s] arrived) */
-	  de4x5_rx(dev);
-	    
-	if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
-	  de4x5_tx(dev); 
-	    
-	if (sts & STS_LNF) {             /* TP Link has failed */
-	    lp->irq_mask &= ~IMR_LFM;
-	}
-	    
-	if (sts & STS_UNF) {             /* Transmit underrun */
-	    de4x5_txur(dev);
-	}
-	    
-	if (sts & STS_SE) {              /* Bus Error */
-	    STOP_DE4X5;
-	    printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
-		   dev->name, sts);
-	    spin_unlock(&lp->lock);
-	    return;
-	}
-    }
-
-    /* Load the TX ring with any locally stored packets */
-    if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
-	while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) {
-	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
-	}
-	lp->cache.lock = 0;
-    }
-
-    lp->interrupt = UNMASK_INTERRUPTS;
-    ENABLE_IRQs;
-    spin_unlock(&lp->lock);
-    
-    return;
-}
-
-static int
-de4x5_rx(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int entry;
-    s32 status;
-    
-    for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
-	                                                    entry=lp->rx_new) {
-	status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
-	
-	if (lp->rx_ovf) {
-	    if (inl(DE4X5_MFC) & MFC_FOCM) {
-		de4x5_rx_ovfc(dev);
-		break;
-	    }
-	}
-
-	if (status & RD_FS) {                 /* Remember the start of frame */
-	    lp->rx_old = entry;
-	}
-	
-	if (status & RD_LS) {                 /* Valid frame status */
-	    if (lp->tx_enable) lp->linkOK++;
-	    if (status & RD_ES) {	      /* There was an error. */
-		lp->stats.rx_errors++;        /* Update the error stats. */
-		if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++;
-		if (status & RD_CE)           lp->stats.rx_crc_errors++;
-		if (status & RD_OF)           lp->stats.rx_fifo_errors++;
-		if (status & RD_TL)           lp->stats.rx_length_errors++;
-		if (status & RD_RF)           lp->pktStats.rx_runt_frames++;
-		if (status & RD_CS)           lp->pktStats.rx_collision++;
-		if (status & RD_DB)           lp->pktStats.rx_dribble++;
-		if (status & RD_OF)           lp->pktStats.rx_overflow++;
-	    } else {                          /* A valid frame received */
-		struct sk_buff *skb;
-		short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
-					                            >> 16) - 4;
-		
-		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
-		    printk("%s: Insufficient memory; nuking packet.\n", 
-			                                            dev->name);
-		    lp->stats.rx_dropped++;
-		} else {
-		    de4x5_dbg_rx(skb, pkt_len);
-
-		    /* Push up the protocol stack */
-		    skb->protocol=eth_type_trans(skb,dev);
-		    de4x5_local_stats(dev, skb->data, pkt_len);
-		    netif_rx(skb);
-		    
-		    /* Update stats */
-		    dev->last_rx = jiffies;
-		    lp->stats.rx_packets++;
- 		    lp->stats.rx_bytes += pkt_len;
-		}
-	    }
-	    
-	    /* Change buffer ownership for this frame, back to the adapter */
-	    for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
-		lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
-		barrier();
-	    }
-	    lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
-	    barrier();
-	}
-	
-	/*
-	** Update entry information
-	*/
-	lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
-    }
-    
-    return 0;
-}
-
-static inline void
-de4x5_free_tx_buff(struct de4x5_private *lp, int entry)
-{
-    pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf),
-		     le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1,
-		     PCI_DMA_TODEVICE);
-    if ((u_long) lp->tx_skb[entry] > 1)
-	dev_kfree_skb_irq(lp->tx_skb[entry]);
-    lp->tx_skb[entry] = NULL;
-}
-
-/*
-** Buffer sent - check for TX buffer errors.
-*/
-static int
-de4x5_tx(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int entry;
-    s32 status;
-    
-    for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
-	status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
-	if (status < 0) {                     /* Buffer not sent yet */
-	    break;
-	} else if (status != 0x7fffffff) {    /* Not setup frame */
-	    if (status & TD_ES) {             /* An error happened */
-		lp->stats.tx_errors++; 
-		if (status & TD_NC) lp->stats.tx_carrier_errors++;
-		if (status & TD_LC) lp->stats.tx_window_errors++;
-		if (status & TD_UF) lp->stats.tx_fifo_errors++;
-		if (status & TD_EC) lp->pktStats.excessive_collisions++;
-		if (status & TD_DE) lp->stats.tx_aborted_errors++;
-	    
-		if (TX_PKT_PENDING) {
-		    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
-		}
-	    } else {                      /* Packet sent */
-		lp->stats.tx_packets++;
-		if (lp->tx_enable) lp->linkOK++;
-	    }
-	    /* Update the collision counter */
-	    lp->stats.collisions += ((status & TD_EC) ? 16 : 
-				                      ((status & TD_CC) >> 3));
-
-	    /* Free the buffer. */
-	    if (lp->tx_skb[entry] != NULL)
-	    	de4x5_free_tx_buff(lp, entry);
-	}
-	
-	/* Update all the pointers */
-	lp->tx_old = (++lp->tx_old) % lp->txRingSize;
-    }
-
-    /* Any resources available? */
-    if (TX_BUFFS_AVAIL && netif_queue_stopped(dev)) {
-	if (lp->interrupt)
-	    netif_wake_queue(dev);
-	else
-	    netif_start_queue(dev);
-    }
-	
-    return 0;
-}
-
-static int
-de4x5_ast(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    
-    disable_ast(dev);
-    
-    if (lp->useSROM) {
-	next_tick = srom_autoconf(dev);
-    } else if (lp->chipset == DC21140) {
-	next_tick = dc21140m_autoconf(dev);
-    } else if (lp->chipset == DC21041) {
-	next_tick = dc21041_autoconf(dev);
-    } else if (lp->chipset == DC21040) {
-	next_tick = dc21040_autoconf(dev);
-    }
-    lp->linkOK = 0;
-    enable_ast(dev, next_tick);
-    
-    return 0;
-}
-
-static int
-de4x5_txur(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int omr;
-
-    omr = inl(DE4X5_OMR);
-    if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) {
-	omr &= ~(OMR_ST|OMR_SR);
-	outl(omr, DE4X5_OMR);
-	while (inl(DE4X5_STS) & STS_TS);
-	if ((omr & OMR_TR) < OMR_TR) {
-	    omr += 0x4000;
-	} else {
-	    omr |= OMR_SF;
-	}
-	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
-    }
-    
-    return 0;
-}
-
-static int 
-de4x5_rx_ovfc(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int omr;
-
-    omr = inl(DE4X5_OMR);
-    outl(omr & ~OMR_SR, DE4X5_OMR);
-    while (inl(DE4X5_STS) & STS_RS);
-
-    for (; (s32)le32_to_cpu(lp->rx_ring[lp->rx_new].status)>=0;) {
-	lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN);
-	lp->rx_new = (++lp->rx_new % lp->rxRingSize);
-    }
-
-    outl(omr, DE4X5_OMR);
-    
-    return 0;
-}
-
-static int
-de4x5_close(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 imr, omr;
-    
-    disable_ast(dev);
-
-    netif_stop_queue(dev);
-    
-    if (de4x5_debug & DEBUG_CLOSE) {
-	printk("%s: Shutting down ethercard, status was %8.8x.\n",
-	       dev->name, inl(DE4X5_STS));
-    }
-    
-    /* 
-    ** We stop the DE4X5 here... mask interrupts and stop TX & RX
-    */
-    DISABLE_IRQs;
-    STOP_DE4X5;
-    
-    /* Free the associated irq */
-    free_irq(dev->irq, dev);
-    lp->state = CLOSED;
-
-    /* Free any socket buffers */
-    de4x5_free_rx_buffs(dev);
-    de4x5_free_tx_buffs(dev);
-    
-    MOD_DEC_USE_COUNT;
-    
-    /* Put the adapter to sleep to save power */
-    yawn(dev, SLEEP);
-    
-    return 0;
-}
-
-static struct net_device_stats *
-de4x5_get_stats(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    
-    lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
-    
-    return &lp->stats;
-}
-
-static void
-de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i;
-
-    for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
-        if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
-	    lp->pktStats.bins[i]++;
-	    i = DE4X5_PKT_STAT_SZ;
-	}
-    }
-    if (buf[0] & 0x01) {          /* Multicast/Broadcast */
-        if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
-	    lp->pktStats.broadcast++;
-	} else {
-	    lp->pktStats.multicast++;
-	}
-    } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
-	       (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
-        lp->pktStats.unicast++;
-    }
-		
-    lp->pktStats.bins[0]++;       /* Duplicates stats.rx_packets */
-    if (lp->pktStats.bins[0] == 0) { /* Reset counters */
-        memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
-    }
-
-    return;
-}
-
-/*
-** Removes the TD_IC flag from previous descriptor to improve TX performance.
-** If the flag is changed on a descriptor that is being read by the hardware,
-** I assume PCI transaction ordering will mean you are either successful or
-** just miss asserting the change to the hardware. Anyway you're messing with
-** a descriptor you don't own, but this shouldn't kill the chip provided
-** the descriptor register is read only to the hardware.
-*/
-static void
-load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
-    dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1, PCI_DMA_TODEVICE);
-
-    lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma);
-    lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
-    lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
-    lp->tx_skb[lp->tx_new] = skb;
-    lp->tx_ring[entry].des1 &= cpu_to_le32(~TD_IC);
-    barrier();
-
-    lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
-    barrier();
-}
-
-/*
-** Set or clear the multicast filter for this adaptor.
-*/
-static void
-set_multicast_list(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    /* First, double check that the adapter is open */
-    if (lp->state == OPEN) {
-	if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */
-	    u32 omr;
-	    omr = inl(DE4X5_OMR);
-	    omr |= OMR_PR;
-	    outl(omr, DE4X5_OMR);
-	} else { 
-	    SetMulticastFilter(dev);
-	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-			                                SETUP_FRAME_LEN, (struct sk_buff *)1);
-	    
-	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	    outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
-	    dev->trans_start = jiffies;
-	}
-    }
-    
-    return;
-}
-
-/*
-** Calculate the hash code and update the logical address filter
-** from a list of ethernet multicast addresses.
-** Little endian crc one liner from Matt Thomas, DEC.
-*/
-static void
-SetMulticastFilter(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct dev_mc_list *dmi=dev->mc_list;
-    u_long iobase = dev->base_addr;
-    int i, j, bit, byte;
-    u16 hashcode;
-    u32 omr, crc;
-    char *pa;
-    unsigned char *addrs;
-
-    omr = inl(DE4X5_OMR);
-    omr &= ~(OMR_PR | OMR_PM);
-    pa = build_setup_frame(dev, ALL);        /* Build the basic frame */
-    
-    if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
-	omr |= OMR_PM;                       /* Pass all multicasts */
-    } else if (lp->setup_f == HASH_PERF) {   /* Hash Filtering */
-	for (i=0;i<dev->mc_count;i++) {      /* for each address in the list */
-	    addrs=dmi->dmi_addr;
-	    dmi=dmi->next;
-	    if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
-		crc = ether_crc_le(ETH_ALEN, addrs);
-		hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
-		
-		byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
-		bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
-		
-		byte <<= 1;                  /* calc offset into setup frame */
-		if (byte & 0x02) {
-		    byte -= 1;
-		}
-		lp->setup_frame[byte] |= bit;
-	    }
-	}
-    } else {                                 /* Perfect filtering */
-	for (j=0; j<dev->mc_count; j++) {
-	    addrs=dmi->dmi_addr;
-	    dmi=dmi->next;
-	    for (i=0; i<ETH_ALEN; i++) { 
-		*(pa + (i&1)) = *addrs++;
-		if (i & 0x01) pa += 4;
-	    }
-	}
-    }
-    outl(omr, DE4X5_OMR);
-    
-    return;
-}
-
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-/*
-** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard. Upto 15 EISA devices are supported.
-*/
-static void __init 
-eisa_probe(struct net_device *dev, u_long ioaddr)
-{
-    int i, maxSlots, status, device;
-    u_char irq;
-    u_short vendor;
-    u32 cfid;
-    u_long iobase;
-    struct bus_type *lp = &bus;
-    char name[DE4X5_STRLEN];
-
-    if (lastEISA == MAX_EISA_SLOTS) return;/* No more EISA devices to search */
-
-    lp->bus = EISA;
-    
-    if (ioaddr == 0) {                     /* Autoprobing */
-	iobase = EISA_SLOT_INC;            /* Get the first slot address */
-	i = 1;
-	maxSlots = MAX_EISA_SLOTS;
-    } else {                               /* Probe a specific location */
-	iobase = ioaddr;
-	i = (ioaddr >> 12);
-	maxSlots = i + 1;
-    }
-    
-    for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
-	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue;
-	if (!EISA_signature(name, EISA_ID)) continue;
-
-	cfid = (u32) inl(PCI_CFID);
-	cfrv = (u_short) inl(PCI_CFRV);
-	device = (cfid >> 8) & 0x00ffff00;
-	vendor = (u_short) cfid;
-	    
-	/* Read the EISA Configuration Registers */
-	irq = inb(EISA_REG0);
-	irq = de4x5_irq[(irq >> 1) & 0x03];
-
-	if (is_DC2114x) {
-	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
-	}
-	lp->chipset = device;
-
-	/* Write the PCI Configuration Registers */
-	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
-	outl(0x00006000, PCI_CFLT);
-	outl(iobase, PCI_CBIO);
-	    
-	DevicePresent(EISA_APROM);
-
-	dev->irq = irq;
-	if ((status = de4x5_hw_init(dev, iobase, NULL)) == 0) {
-	    num_de4x5s++;
-	    if (loading_module) link_modules(lastModule, dev);
-	    lastEISA = i;
-	    return;
-	}
-    }
-
-    if (ioaddr == 0) lastEISA = i;
-
-    return;
-}
-#endif          /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__) */
-
-/*
-** PCI bus I/O device probe
-** NB: PCI I/O accesses and Bus Mastering are enabled by the PCI BIOS, not
-** the driver. Some PCI BIOS's, pre V2.1, need the slot + features to be
-** enabled by the user first in the set up utility. Hence we just check for
-** enabled features and silently ignore the card if they're not.
-**
-** STOP PRESS: Some BIOS's __require__ the driver to enable the bus mastering
-** bit. Here, check for I/O accesses and then set BM. If you put the card in
-** a non BM slot, you're on your own (and complain to the PC vendor that your
-** PC doesn't conform to the PCI standard)!
-**
-** This function is only compatible with the *latest* 2.1.x kernels. For 2.0.x
-** kernels use the V0.535[n] drivers.
-*/
-#define PCI_LAST_DEV  32
-
-static void __init 
-pci_probe(struct net_device *dev, u_long ioaddr)
-{
-    u_char pb, pbus, dev_num, dnum, timer;
-    u_short vendor, index, status;
-    u_int irq = 0, device, class = DE4X5_CLASS_CODE;
-    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
-    struct bus_type *lp = &bus;
-
-    if (lastPCI == NO_MORE_PCI) return;
-
-    if (!pcibios_present()) {
-	lastPCI = NO_MORE_PCI;
-	return;          /* No PCI bus in this machine! */
-    }
-    
-    lp->bus = PCI;
-    lp->bus_num = 0;
-
-    if ((ioaddr < 0x1000) && loading_module) {
-	pbus = (u_short)(ioaddr >> 8);
-	dnum = (u_short)(ioaddr & 0xff);
-    } else {
-	pbus = 0;
-	dnum = 0;
-    }
-
-    for (index=lastPCI+1;(pdev = pci_find_class(class, pdev))!=NULL;index++) {
-	dev_num = PCI_SLOT(pdev->devfn);
-	pb = pdev->bus->number;
-	if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue;
-
-	vendor = pdev->vendor;
-	device = pdev->device << 8;
-	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
-
-	/* Search for an SROM on this bus */
-	if (lp->bus_num != pb) {
-	    lp->bus_num = pb;
-	    srom_search(pdev);
-	}
-
-	/* Get the chip configuration revision register */
-	pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv);
-
-	/* Set the device number information */
-	lp->device = dev_num;
-	lp->bus_num = pb;
-	    
-	/* Set the chipset information */
-	if (is_DC2114x) {
-	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
-	}
-	lp->chipset = device;
-
-	/* Get the board I/O address (64 bits on sparc64) */
-	iobase = pci_resource_start(pdev, 0);
-
-	/* Fetch the IRQ to be used */
-	irq = pdev->irq;
-	if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
-	    
-	/* Check if I/O accesses and Bus Mastering are enabled */
-	pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
-#ifdef __powerpc__
-	if (!(status & PCI_COMMAND_IO)) {
-	    status |= PCI_COMMAND_IO;
-	    pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
-	    pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
-	}
-#endif /* __powerpc__ */
-	if (!(status & PCI_COMMAND_IO)) continue;
-
-	if (!(status & PCI_COMMAND_MASTER)) {
-	    status |= PCI_COMMAND_MASTER;
-	    pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
-	    pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
-	}
-	if (!(status & PCI_COMMAND_MASTER)) continue;
-
-	/* Check the latency timer for values >= 0x60 */
-	pcibios_read_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, &timer);
-	if (timer < 0x60) {
-	    pcibios_write_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, 0x60);
-	}
-
-	DevicePresent(DE4X5_APROM);
-	if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
-	    dev->irq = irq;
-	    if ((status = de4x5_hw_init(dev, iobase, pdev)) == 0) {
-		num_de4x5s++;
-		lastPCI = index;
-		if (loading_module) link_modules(lastModule, dev);
-		return;
-	    }
-	} else if (ioaddr != 0) {
-	    printk("%s: region already allocated at 0x%04lx.\n", dev->name,
-		   iobase);
-	}
-    }
-
-    lastPCI = NO_MORE_PCI;
-
-    return;
-}
-
-/*
-** This function searches the current bus (which is >0) for a DECchip with an
-** SROM, so that in multiport cards that have one SROM shared between multiple 
-** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
-** For single port cards this is a time waster...
-*/
-static void __init 
-srom_search(struct pci_dev *dev)
-{
-    u_char pb;
-    u_short vendor, status;
-    u_int irq = 0, device;
-    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
-    int i, j;
-    struct bus_type *lp = &bus;
-    struct list_head *walk = &dev->bus_list;
-
-    for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) {
-	struct pci_dev *this_dev = pci_dev_b(walk);
-
-	/* Skip the pci_bus list entry */
-	if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue;
-
-	vendor = this_dev->vendor;
-	device = this_dev->device << 8;
-	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
-
-	/* Get the chip configuration revision register */
-	pb = this_dev->bus->number;
-	pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv);
-
-	/* Set the device number information */
-	lp->device = PCI_SLOT(this_dev->devfn);
-	lp->bus_num = pb;
-	    
-	/* Set the chipset information */
-	if (is_DC2114x) {
-	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
-	}
-	lp->chipset = device;
-
-	/* Get the board I/O address (64 bits on sparc64) */
-	iobase = pci_resource_start(this_dev, 0);
-
-	/* Fetch the IRQ to be used */
-	irq = this_dev->irq;
-	if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
-	    
-	/* Check if I/O accesses are enabled */
-	pcibios_read_config_word(pb, this_dev->devfn, PCI_COMMAND, &status);
-	if (!(status & PCI_COMMAND_IO)) continue;
-
-	/* Search for a valid SROM attached to this DECchip */
-	DevicePresent(DE4X5_APROM);
-	for (j=0, i=0; i<ETH_ALEN; i++) {
-	    j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
-	}
-	if ((j != 0) && (j != 0x5fa)) {
-	    last.chipset = device;
-	    last.bus = pb;
-	    last.irq = irq;
-	    for (i=0; i<ETH_ALEN; i++) {
-		last.addr[i] = (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
-	    }
-	    return;
-	}
-    }
-
-    return;
-}
-
-static void __init 
-link_modules(struct net_device *dev, struct net_device *tmp)
-{
-    struct net_device *p=dev;
-
-    if (p) {
-	while (((struct de4x5_private *)(p->priv))->next_module) {
-	    p = ((struct de4x5_private *)(p->priv))->next_module;
-	}
-
-	if (dev != tmp) {
-	    ((struct de4x5_private *)(p->priv))->next_module = tmp;
-	} else {
-	    ((struct de4x5_private *)(p->priv))->next_module = NULL;
-	}
-    }
-
-    return;
-}
-
-/*
-** Auto configure the media here rather than setting the port at compile
-** time. This routine is called by de4x5_init() and when a loss of media is
-** detected (excessive collisions, loss of carrier, no carrier or link fail
-** [TP] or no recent receive activity) to check whether the user has been 
-** sneaky and changed the port on us.
-*/
-static int
-autoconf_media(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-
-    lp->linkOK = 0;
-    lp->c_media = AUTO;                     /* Bogus last media */
-    disable_ast(dev);
-    inl(DE4X5_MFC);                         /* Zero the lost frames counter */
-    lp->media = INIT;
-    lp->tcount = 0;
-
-    if (lp->useSROM) {
-	next_tick = srom_autoconf(dev);
-    } else if (lp->chipset == DC21040) {
-	next_tick = dc21040_autoconf(dev);
-    } else if (lp->chipset == DC21041) {
-	next_tick = dc21041_autoconf(dev);
-    } else if (lp->chipset == DC21140) {
-	next_tick = dc21140m_autoconf(dev);
-    }
-
-    enable_ast(dev, next_tick);
-    
-    return (lp->media);
-}
-
-/*
-** Autoconfigure the media when using the DC21040. AUI cannot be distinguished
-** from BNC as the port has a jumper to set thick or thin wire. When set for
-** BNC, the BNC port will indicate activity if it's not terminated correctly.
-** The only way to test for that is to place a loopback packet onto the
-** network and watch for errors. Since we're messing with the interrupt mask
-** register, disable the board interrupts and do not allow any more packets to
-** be queued to the hardware. Re-enable everything only when the media is
-** found.
-** I may have to "age out" locally queued packets so that the higher layer
-** timeouts don't effectively duplicate packets on the network.
-*/
-static int
-dc21040_autoconf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    s32 imr;
-    
-    switch (lp->media) {
-    case INIT:
-	DISABLE_IRQs;
-	lp->tx_enable = NO;
-	lp->timeout = -1;
-	de4x5_save_skbs(dev);
-	if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
-	    lp->media = TP;
-	} else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) {
-	    lp->media = BNC_AUI;
-	} else if (lp->autosense == EXT_SIA) {
-	    lp->media = EXT_SIA;
-	} else {
-	    lp->media = NC;
-	}
-	lp->local_state = 0;
-	next_tick = dc21040_autoconf(dev);
-	break;
-	
-    case TP:
-	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
-		                                         TP_SUSPECT, test_tp);
-	break;
-	
-    case TP_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
-	break;
-	
-    case BNC:
-    case AUI:
-    case BNC_AUI:
-	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
-		                                  BNC_AUI_SUSPECT, ping_media);
-	break;
-	
-    case BNC_AUI_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
-	break;
-	
-    case EXT_SIA:
-	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
-		                              NC, EXT_SIA_SUSPECT, ping_media);
-	break;
-	
-    case EXT_SIA_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
-	break;
-	
-    case NC:
-	/* default to TP for all */
-	reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
-	if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tx_enable = NO;
-	break;
-    }
-    
-    return next_tick;
-}
-
-static int
-dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeout,
-	      int next_state, int suspect_state, 
-	      int (*fn)(struct net_device *, int))
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    int linkBad;
-
-    switch (lp->local_state) {
-    case 0:
-	reset_init_sia(dev, csr13, csr14, csr15);
-	lp->local_state++;
-	next_tick = 500;
-	break;
-	    
-    case 1:
-	if (!lp->tx_enable) {
-	    linkBad = fn(dev, timeout);
-	    if (linkBad < 0) {
-		next_tick = linkBad & ~TIMER_CB;
-	    } else {
-		if (linkBad && (lp->autosense == AUTO)) {
-		    lp->local_state = 0;
-		    lp->media = next_state;
-		} else {
-		    de4x5_init_connection(dev);
-		}
-	    }
-	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
-	    lp->media = suspect_state;
-	    next_tick = 3000;
-	}
-	break;
-    }
-    
-    return next_tick;
-}
-
-static int
-de4x5_suspect_state(struct net_device *dev, int timeout, int prev_state,
-		      int (*fn)(struct net_device *, int),
-		      int (*asfn)(struct net_device *))
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    int linkBad;
-
-    switch (lp->local_state) {
-    case 1:
-	if (lp->linkOK) {
-	    lp->media = prev_state;
-	} else {
-	    lp->local_state++;
-	    next_tick = asfn(dev);
-	}
-	break;
-
-    case 2:
-	linkBad = fn(dev, timeout);
-	if (linkBad < 0) {
-	    next_tick = linkBad & ~TIMER_CB;
-	} else if (!linkBad) {
-	    lp->local_state--;
-	    lp->media = prev_state;
-	} else {
-	    lp->media = INIT;
-	    lp->tcount++;
-	}
-    }
-
-    return next_tick;
-}
-
-/*
-** Autoconfigure the media when using the DC21041. AUI needs to be tested
-** before BNC, because the BNC port will indicate activity if it's not
-** terminated correctly. The only way to test for that is to place a loopback
-** packet onto the network and watch for errors. Since we're messing with
-** the interrupt mask register, disable the board interrupts and do not allow
-** any more packets to be queued to the hardware. Re-enable everything only
-** when the media is found.
-*/
-static int
-dc21041_autoconf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 sts, irqs, irq_mask, imr, omr;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    
-    switch (lp->media) {
-    case INIT:
-	DISABLE_IRQs;
-	lp->tx_enable = NO;
-	lp->timeout = -1;
-	de4x5_save_skbs(dev);          /* Save non transmitted skb's */
-	if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
-	    lp->media = TP;            /* On chip auto negotiation is broken */
-	} else if (lp->autosense == TP) {
-	    lp->media = TP;
-	} else if (lp->autosense == BNC) {
-	    lp->media = BNC;
-	} else if (lp->autosense == AUI) {
-	    lp->media = AUI;
-	} else {
-	    lp->media = NC;
-	}
-	lp->local_state = 0;
-	next_tick = dc21041_autoconf(dev);
-	break;
-	
-    case TP_NW:
-	if (lp->timeout < 0) {
-	    omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
-	    outl(omr | OMR_FDX, DE4X5_OMR);
-	}
-	irqs = STS_LNF | STS_LNP;
-	irq_mask = IMR_LFM | IMR_LPM;
-	sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
-	if (sts < 0) {
-	    next_tick = sts & ~TIMER_CB;
-	} else {
-	    if (sts & STS_LNP) {
-		lp->media = ANS;
-	    } else {
-		lp->media = AUI;
-	    }
-	    next_tick = dc21041_autoconf(dev);
-	}
-	break;
-	
-    case ANS:
-	if (!lp->tx_enable) {
-	    irqs = STS_LNP;
-	    irq_mask = IMR_LPM;
-	    sts = test_ans(dev, irqs, irq_mask, 3000);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
-		    lp->media = TP;
-		    next_tick = dc21041_autoconf(dev);
-		} else {
-		    lp->local_state = 1;
-		    de4x5_init_connection(dev);
-		}
-	    }
-	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
-	    lp->media = ANS_SUSPECT;
-	    next_tick = 3000;
-	}
-	break;
-	
-    case ANS_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
-	break;
-	
-    case TP:
-	if (!lp->tx_enable) {
-	    if (lp->timeout < 0) {
-		omr = inl(DE4X5_OMR);          /* Set up half duplex for TP */
-		outl(omr & ~OMR_FDX, DE4X5_OMR);
-	    }
-	    irqs = STS_LNF | STS_LNP;
-	    irq_mask = IMR_LFM | IMR_LPM;
-	    sts = test_media(dev,irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
-		    if (inl(DE4X5_SISR) & SISR_NRA) {
-			lp->media = AUI;       /* Non selected port activity */
-		    } else {
-			lp->media = BNC;
-		    }
-		    next_tick = dc21041_autoconf(dev);
-		} else {
-		    lp->local_state = 1;
-		    de4x5_init_connection(dev);
-		}
-	    }
-	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
-	    lp->media = TP_SUSPECT;
-	    next_tick = 3000;
-	}
-	break;
-	
-    case TP_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
-	break;
-	
-    case AUI:
-	if (!lp->tx_enable) {
-	    if (lp->timeout < 0) {
-		omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
-		outl(omr & ~OMR_FDX, DE4X5_OMR);
-	    }
-	    irqs = 0;
-	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
-		    lp->media = BNC;
-		    next_tick = dc21041_autoconf(dev);
-		} else {
-		    lp->local_state = 1;
-		    de4x5_init_connection(dev);
-		}
-	    }
-	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
-	    lp->media = AUI_SUSPECT;
-	    next_tick = 3000;
-	}
-	break;
-	
-    case AUI_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
-	break;
-	
-    case BNC:
-	switch (lp->local_state) {
-	case 0:
-	    if (lp->timeout < 0) {
-		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
-		outl(omr & ~OMR_FDX, DE4X5_OMR);
-	    }
-	    irqs = 0;
-	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		lp->local_state++;             /* Ensure media connected */
-		next_tick = dc21041_autoconf(dev);
-	    }
-	    break;
-	    
-	case 1:
-	    if (!lp->tx_enable) {
-		if ((sts = ping_media(dev, 3000)) < 0) {
-		    next_tick = sts & ~TIMER_CB;
-		} else {
-		    if (sts) {
-			lp->local_state = 0;
-			lp->media = NC;
-		    } else {
-			de4x5_init_connection(dev);
-		    }
-		}
-	    } else if (!lp->linkOK && (lp->autosense == AUTO)) {
-		lp->media = BNC_SUSPECT;
-		next_tick = 3000;
-	    }
-	    break;
-	}
-	break;
-	
-    case BNC_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
-	break;
-	
-    case NC:
-	omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
-	outl(omr | OMR_FDX, DE4X5_OMR);
-	reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
-	if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tx_enable = NO;
-	break;
-    }
-    
-    return next_tick;
-}
-
-/*
-** Some autonegotiation chips are broken in that they do not return the
-** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
-** register, except at the first power up negotiation.
-*/
-static int
-dc21140m_autoconf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int ana, anlpa, cap, cr, slnk, sr;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-    u_long imr, omr, iobase = dev->base_addr;
-    
-    switch(lp->media) {
-    case INIT: 
-        if (lp->timeout < 0) {
-	    DISABLE_IRQs;
-	    lp->tx_enable = FALSE;
-	    lp->linkOK = 0;
-	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
-	}
-	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
-	    next_tick &= ~TIMER_CB;
-	} else {
-	    if (lp->useSROM) {
-		if (srom_map_media(dev) < 0) {
-		    lp->tcount++;
-		    return next_tick;
-		}
-		srom_exec(dev, lp->phy[lp->active].gep);
-		if (lp->infoblock_media == ANS) {
-		    ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
-		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		}
-	    } else {
-		lp->tmp = MII_SR_ASSC;     /* Fake out the MII speed set */
-		SET_10Mb;
-		if (lp->autosense == _100Mb) {
-		    lp->media = _100Mb;
-		} else if (lp->autosense == _10Mb) {
-		    lp->media = _10Mb;
-		} else if ((lp->autosense == AUTO) && 
-			            ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
-		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
-		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
-		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    lp->media = ANS;
-		} else if (lp->autosense == AUTO) {
-		    lp->media = SPD_DET;
-		} else if (is_spd_100(dev) && is_100_up(dev)) {
-		    lp->media = _100Mb;
-		} else {
-		    lp->media = NC;
-		}
-	    }
-	    lp->local_state = 0;
-	    next_tick = dc21140m_autoconf(dev);
-	}
-	break;
-	
-    case ANS:
-	switch (lp->local_state) {
-	case 0:
-	    if (lp->timeout < 0) {
-		mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
-	    }
-	    cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
-	    if (cr < 0) {
-		next_tick = cr & ~TIMER_CB;
-	    } else {
-		if (cr) {
-		    lp->local_state = 0;
-		    lp->media = SPD_DET;
-		} else {
-		    lp->local_state++;
-		}
-		next_tick = dc21140m_autoconf(dev);
-	    }
-	    break;
-	    
-	case 1:
-	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
-		next_tick = sr & ~TIMER_CB;
-	    } else {
-		lp->media = SPD_DET;
-		lp->local_state = 0;
-		if (sr) {                         /* Success! */
-		    lp->tmp = MII_SR_ASSC;
-		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
-		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    if (!(anlpa & MII_ANLPA_RF) && 
-			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
-			if (cap & MII_ANA_100M) {
-			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
-			    lp->media = _100Mb;
-			} else if (cap & MII_ANA_10M) {
-			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
-
-			    lp->media = _10Mb;
-			}
-		    }
-		}                       /* Auto Negotiation failed to finish */
-		next_tick = dc21140m_autoconf(dev);
-	    }                           /* Auto Negotiation failed to start */
-	    break;
-	}
-	break;
-	
-    case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
-        if (lp->timeout < 0) {
-	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : 
-		                                  (~gep_rd(dev) & GEP_LNP));
-	    SET_100Mb_PDET;
-	}
-        if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
-	    next_tick = slnk & ~TIMER_CB;
-	} else {
-	    if (is_spd_100(dev) && is_100_up(dev)) {
-		lp->media = _100Mb;
-	    } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
-		lp->media = _10Mb;
-	    } else {
-		lp->media = NC;
-	    }
-	    next_tick = dc21140m_autoconf(dev);
-	}
-	break;
-	
-    case _100Mb:                               /* Set 100Mb/s */
-        next_tick = 3000;
-	if (!lp->tx_enable) {
-	    SET_100Mb;
-	    de4x5_init_connection(dev);
-	} else {
-	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
-		    lp->media = INIT;
-		    lp->tcount++;
-		    next_tick = DE4X5_AUTOSENSE_MS;
-		}
-	    }
-	}
-	break;
-
-    case BNC:
-    case AUI:
-    case _10Mb:                                /* Set 10Mb/s */
-        next_tick = 3000;
-	if (!lp->tx_enable) {
-	    SET_10Mb;
-	    de4x5_init_connection(dev);
-	} else {
-	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
-		    lp->media = INIT;
-		    lp->tcount++;
-		    next_tick = DE4X5_AUTOSENSE_MS;
-		}
-	    }
-	}
-	break;
-	
-    case NC:
-        if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tx_enable = FALSE;
-	break;
-    }
-    
-    return next_tick;
-}
-
-/*
-** This routine may be merged into dc21140m_autoconf() sometime as I'm
-** changing how I figure out the media - but trying to keep it backwards
-** compatible with the de500-xa and de500-aa.
-** Whether it's BNC, AUI, SYM or MII is sorted out in the infoblock
-** functions and set during de4x5_mac_port() and/or de4x5_reset_phy().
-** This routine just has to figure out whether 10Mb/s or 100Mb/s is
-** active.
-** When autonegotiation is working, the ANS part searches the SROM for
-** the highest common speed (TP) link that both can run and if that can
-** be full duplex. That infoblock is executed and then the link speed set.
-**
-** Only _10Mb and _100Mb are tested here.
-*/
-static int
-dc2114x_autoconf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-
-    switch (lp->media) {
-    case INIT:
-        if (lp->timeout < 0) {
-	    DISABLE_IRQs;
-	    lp->tx_enable = FALSE;
-	    lp->linkOK = 0;
-            lp->timeout = -1;
-	    de4x5_save_skbs(dev);            /* Save non transmitted skb's */
-	    if (lp->params.autosense & ~AUTO) {
-		srom_map_media(dev);         /* Fixed media requested      */
-		if (lp->media != lp->params.autosense) {
-		    lp->tcount++;
-		    lp->media = INIT;
-		    return next_tick;
-		}
-		lp->media = INIT;
-	    }
-	}
-	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
-	    next_tick &= ~TIMER_CB;
-	} else {
-	    if (lp->autosense == _100Mb) {
-		lp->media = _100Mb;
-	    } else if (lp->autosense == _10Mb) {
-		lp->media = _10Mb;
-	    } else if (lp->autosense == TP) {
-		lp->media = TP;
-	    } else if (lp->autosense == BNC) {
-		lp->media = BNC;
-	    } else if (lp->autosense == AUI) {
-		lp->media = AUI;
-	    } else {
-		lp->media = SPD_DET;
-		if ((lp->infoblock_media == ANS) && 
-		                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
-		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
-		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
-		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    lp->media = ANS;
-		}
-	    }
-	    lp->local_state = 0;
-	    next_tick = dc2114x_autoconf(dev);
-        }
-	break;
-	
-    case ANS:
-	switch (lp->local_state) {
-	case 0:
-	    if (lp->timeout < 0) {
-		mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
-	    }
-	    cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
-	    if (cr < 0) {
-		next_tick = cr & ~TIMER_CB;
-	    } else {
-		if (cr) {
-		    lp->local_state = 0;
-		    lp->media = SPD_DET;
-		} else {
-		    lp->local_state++;
-		}
-		next_tick = dc2114x_autoconf(dev);
-	    }
-	    break;
-	    
-	case 1:
-	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
-		next_tick = sr & ~TIMER_CB;
-	    } else {
-		lp->media = SPD_DET;
-		lp->local_state = 0;
-		if (sr) {                         /* Success! */
-		    lp->tmp = MII_SR_ASSC;
-		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
-		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
-		    if (!(anlpa & MII_ANLPA_RF) && 
-			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
-			if (cap & MII_ANA_100M) {
-			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
-			    lp->media = _100Mb;
-			} else if (cap & MII_ANA_10M) {
-			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
-			    lp->media = _10Mb;
-			}
-		    }
-		}                       /* Auto Negotiation failed to finish */
-		next_tick = dc2114x_autoconf(dev);
-	    }                           /* Auto Negotiation failed to start  */
-	    break;
-	}
-	break;
-
-    case AUI:
-	if (!lp->tx_enable) {
-	    if (lp->timeout < 0) {
-		omr = inl(DE4X5_OMR);   /* Set up half duplex for AUI        */
-		outl(omr & ~OMR_FDX, DE4X5_OMR);
-	    }
-	    irqs = 0;
-	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
-		    lp->media = BNC;
-		    next_tick = dc2114x_autoconf(dev);
-		} else {
-		    lp->local_state = 1;
-		    de4x5_init_connection(dev);
-		}
-	    }
-	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
-	    lp->media = AUI_SUSPECT;
-	    next_tick = 3000;
-	}
-	break;
-	
-    case AUI_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
-	break;
-	
-    case BNC:
-	switch (lp->local_state) {
-	case 0:
-	    if (lp->timeout < 0) {
-		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
-		outl(omr & ~OMR_FDX, DE4X5_OMR);
-	    }
-	    irqs = 0;
-	    irq_mask = 0;
-	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
-	    if (sts < 0) {
-		next_tick = sts & ~TIMER_CB;
-	    } else {
-		lp->local_state++;             /* Ensure media connected */
-		next_tick = dc2114x_autoconf(dev);
-	    }
-	    break;
-	    
-	case 1:
-	    if (!lp->tx_enable) {
-		if ((sts = ping_media(dev, 3000)) < 0) {
-		    next_tick = sts & ~TIMER_CB;
-		} else {
-		    if (sts) {
-			lp->local_state = 0;
-			lp->tcount++;
-			lp->media = INIT;
-		    } else {
-			de4x5_init_connection(dev);
-		    }
-		}
-	    } else if (!lp->linkOK && (lp->autosense == AUTO)) {
-		lp->media = BNC_SUSPECT;
-		next_tick = 3000;
-	    }
-	    break;
-	}
-	break;
-	
-    case BNC_SUSPECT:
-	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
-	break;
-	
-    case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
-	  if (srom_map_media(dev) < 0) {
-	      lp->tcount++;
-	      lp->media = INIT;
-	      return next_tick;
-	  }
-	  if (lp->media == _100Mb) {
-	      if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
-		  lp->media = SPD_DET;
-		  return  (slnk & ~TIMER_CB);
-	      }
-	  } else {
-	      if (wait_for_link(dev) < 0) {
-		  lp->media = SPD_DET;
-		  return PDET_LINK_WAIT;
-	      }
-	  }
-	  if (lp->media == ANS) {           /* Do MII parallel detection */
-	      if (is_spd_100(dev)) {
-		  lp->media = _100Mb;
-	      } else {
-		  lp->media = _10Mb;
-	      }
-	      next_tick = dc2114x_autoconf(dev);
-	  } else if (((lp->media == _100Mb) && is_100_up(dev)) ||
-		     (((lp->media == _10Mb) || (lp->media == TP) ||
-		       (lp->media == BNC)   || (lp->media == AUI)) && 
-		      is_10_up(dev))) {
-	      next_tick = dc2114x_autoconf(dev);
-	  } else {
-	      lp->tcount++;
-	      lp->media = INIT;
-	  }
-	  break;
-	
-    case _10Mb:
-        next_tick = 3000;
-	if (!lp->tx_enable) {
-	    SET_10Mb;
-	    de4x5_init_connection(dev);
-	} else {
-	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
-		    lp->media = INIT;
-		    lp->tcount++;
-		    next_tick = DE4X5_AUTOSENSE_MS;
-		}
-	    }
-	}
-	break;
-
-    case _100Mb:
-        next_tick = 3000;
-	if (!lp->tx_enable) {
-	    SET_100Mb;
-	    de4x5_init_connection(dev);
-	} else {
-	    if (!lp->linkOK && (lp->autosense == AUTO)) {
-		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
-		    lp->media = INIT;
-		    lp->tcount++;
-		    next_tick = DE4X5_AUTOSENSE_MS;
-		}
-	    }
-	}
-	break;
-
-    default:
-	lp->tcount++;
-printk("Huh?: media:%02x\n", lp->media);
-	lp->media = INIT;
-	break;
-    }
-    
-    return next_tick;
-}
-
-static int
-srom_autoconf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
-    return lp->infoleaf_fn(dev);
-}
-
-/*
-** This mapping keeps the original media codes and FDX flag unchanged.
-** While it isn't strictly necessary, it helps me for the moment...
-** The early return avoids a media state / SROM media space clash.
-*/
-static int
-srom_map_media(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
-    lp->fdx = 0;
-    if (lp->infoblock_media == lp->media) 
-      return 0;
-
-    switch(lp->infoblock_media) {
-      case SROM_10BASETF:
-	if (!lp->params.fdx) return -1;
-	lp->fdx = TRUE;
-      case SROM_10BASET:
-	if (lp->params.fdx && !lp->fdx) return -1;
-	if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
-	    lp->media = _10Mb;
-	} else {
-	    lp->media = TP;
-	}
-	break;
-
-      case SROM_10BASE2:
-	lp->media = BNC;
-	break;
-
-      case SROM_10BASE5:
-	lp->media = AUI;
-	break;
-
-      case SROM_100BASETF:
-        if (!lp->params.fdx) return -1;
-	lp->fdx = TRUE;
-      case SROM_100BASET:
-	if (lp->params.fdx && !lp->fdx) return -1;
-	lp->media = _100Mb;
-	break;
-
-      case SROM_100BASET4:
-	lp->media = _100Mb;
-	break;
-
-      case SROM_100BASEFF:
-	if (!lp->params.fdx) return -1;
-	lp->fdx = TRUE;
-      case SROM_100BASEF: 
-	if (lp->params.fdx && !lp->fdx) return -1;
-	lp->media = _100Mb;
-	break;
-
-      case ANS:
-	lp->media = ANS;
-	lp->fdx = lp->params.fdx;
-	break;
-
-      default: 
-	printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
-	                                                  lp->infoblock_media);
-	return -1;
-	break;
-    }
-
-    return 0;
-}
-
-static void
-de4x5_init_connection(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    u_long flags = 0;
-
-    if (lp->media != lp->c_media) {
-        de4x5_dbg_media(dev);
-	lp->c_media = lp->media;          /* Stop scrolling media messages */
-    }
-
-    spin_lock_irqsave(&lp->lock, flags);
-    de4x5_rst_desc_ring(dev);
-    de4x5_setup_intr(dev);
-    lp->tx_enable = YES;
-    spin_unlock_irqrestore(&lp->lock, flags);
-    outl(POLL_DEMAND, DE4X5_TPD);
-
-    netif_wake_queue(dev);
-
-    return;
-}
-
-/*
-** General PHY reset function. Some MII devices don't reset correctly
-** since their MII address pins can float at voltages that are dependent
-** on the signal pin use. Do a double reset to ensure a reset.
-*/
-static int
-de4x5_reset_phy(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int next_tick = 0;
-
-    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
-	if (lp->timeout < 0) {
-	    if (lp->useSROM) {
-		if (lp->phy[lp->active].rst) {
-		    srom_exec(dev, lp->phy[lp->active].rst);
-		    srom_exec(dev, lp->phy[lp->active].rst);
-		} else if (lp->rst) {          /* Type 5 infoblock reset */
-		    srom_exec(dev, lp->rst);
-		    srom_exec(dev, lp->rst);
-		}
-	    } else {
-		PHY_HARD_RESET;
-	    }
-	    if (lp->useMII) {
-	        mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
-            }
-        }
-	if (lp->useMII) {
-	    next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
-	}
-    } else if (lp->chipset == DC21140) {
-	PHY_HARD_RESET;
-    }
-
-    return next_tick;
-}
-
-static int
-test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 sts, csr12;
-    
-    if (lp->timeout < 0) {
-	lp->timeout = msec/100;
-	if (!lp->useSROM) {      /* Already done if by SROM, else dc2104[01] */
-	    reset_init_sia(dev, csr13, csr14, csr15);
-	}
-
-	/* set up the interrupt mask */
-	outl(irq_mask, DE4X5_IMR);
-
-	/* clear all pending interrupts */
-	sts = inl(DE4X5_STS);
-	outl(sts, DE4X5_STS);
-	
-	/* clear csr12 NRA and SRA bits */
-	if ((lp->chipset == DC21041) || lp->useSROM) {
-	    csr12 = inl(DE4X5_SISR);
-	    outl(csr12, DE4X5_SISR);
-	}
-    }
-    
-    sts = inl(DE4X5_STS) & ~TIMER_CB;
-    
-    if (!(sts & irqs) && --lp->timeout) {
-	sts = 100 | TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return sts;
-}
-
-static int
-test_tp(struct net_device *dev, s32 msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int sisr;
-    
-    if (lp->timeout < 0) {
-	lp->timeout = msec/100;
-    }
-    
-    sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
-
-    if (sisr && --lp->timeout) {
-	sisr = 100 | TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return sisr;
-}
-
-/*
-** Samples the 100Mb Link State Signal. The sample interval is important
-** because too fast a rate can give erroneous results and confuse the
-** speed sense algorithm.
-*/
-#define SAMPLE_INTERVAL 500  /* ms */
-#define SAMPLE_DELAY    2000 /* ms */
-static int
-test_for_100Mb(struct net_device *dev, int msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
-
-    if (lp->timeout < 0) {
-	if ((msec/SAMPLE_INTERVAL) <= 0) return 0;
-	if (msec > SAMPLE_DELAY) {
-	    lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
-	    gep = SAMPLE_DELAY | TIMER_CB;
-	    return gep;
-	} else {
-	    lp->timeout = msec/SAMPLE_INTERVAL;
-	}
-    }
-    
-    if (lp->phy[lp->active].id || lp->useSROM) {
-	gep = is_100_up(dev) | is_spd_100(dev);
-    } else {
-	gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
-    }
-    if (!(gep & ret) && --lp->timeout) {
-	gep = SAMPLE_INTERVAL | TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return gep;
-}
-
-static int
-wait_for_link(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-
-    if (lp->timeout < 0) {
-	lp->timeout = 1;
-    }
-    
-    if (lp->timeout--) {
-	return TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return 0;
-}
-
-/*
-**
-**
-*/
-static int
-test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int test;
-    u_long iobase = dev->base_addr;
-    
-    if (lp->timeout < 0) {
-	lp->timeout = msec/100;
-    }
-    
-    if (pol) pol = ~0;
-    reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
-    test = (reg ^ pol) & mask;
-    
-    if (test && --lp->timeout) {
-	reg = 100 | TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return reg;
-}
-
-static int
-is_spd_100(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int spd;
-    
-    if (lp->useMII) {
-	spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
-	spd = ~(spd ^ lp->phy[lp->active].spd.value);
-	spd &= lp->phy[lp->active].spd.mask;
-    } else if (!lp->useSROM) {                      /* de500-xa */
-	spd = ((~gep_rd(dev)) & GEP_SLNK);
-    } else {
-	if ((lp->ibn == 2) || !lp->asBitValid)
-	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
-
-	spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
-	          (lp->linkOK & ~lp->asBitValid);
-    }
-    
-    return spd;
-}
-
-static int
-is_100_up(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    
-    if (lp->useMII) {
-	/* Double read for sticky bits & temporary drops */
-	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
-	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
-    } else if (!lp->useSROM) {                       /* de500-xa */
-	return ((~gep_rd(dev)) & GEP_SLNK);
-    } else {
-	if ((lp->ibn == 2) || !lp->asBitValid)
-	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
-
-        return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
-		(lp->linkOK & ~lp->asBitValid));
-    }
-}
-
-static int
-is_10_up(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    
-    if (lp->useMII) {
-	/* Double read for sticky bits & temporary drops */
-	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
-	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
-    } else if (!lp->useSROM) {                       /* de500-xa */
-	return ((~gep_rd(dev)) & GEP_LNP);
-    } else {
-	if ((lp->ibn == 2) || !lp->asBitValid)
-	    return (((lp->chipset & ~0x00ff) == DC2114x) ?
-		    (~inl(DE4X5_SISR)&SISR_LS10):
-		    0);
-
-	return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
-		(lp->linkOK & ~lp->asBitValid));
-    }
-}
-
-static int
-is_anc_capable(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    
-    if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
-	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
-    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-	return (inl(DE4X5_SISR) & SISR_LPN) >> 12;
-    } else {
-	return 0;
-    }
-}
-
-/*
-** Send a packet onto the media and watch for send errors that indicate the
-** media is bad or unconnected.
-*/
-static int
-ping_media(struct net_device *dev, int msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int sisr;
-    
-    if (lp->timeout < 0) {
-	lp->timeout = msec/100;
-	
-	lp->tmp = lp->tx_new;                /* Remember the ring position */
-	load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), (struct sk_buff *)1);
-	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	outl(POLL_DEMAND, DE4X5_TPD);
-    }
-    
-    sisr = inl(DE4X5_SISR);
-
-    if ((!(sisr & SISR_NCR)) && 
-	((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && 
-	 (--lp->timeout)) {
-	sisr = 100 | TIMER_CB;
-    } else {
-	if ((!(sisr & SISR_NCR)) && 
-	    !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
-	    lp->timeout) {
-	    sisr = 0;
-	} else {
-	    sisr = 1;
-	}
-	lp->timeout = -1;
-    }
-    
-    return sisr;
-}
-
-/*
-** This function does 2 things: on Intels it kmalloc's another buffer to
-** replace the one about to be passed up. On Alpha's it kmallocs a buffer
-** into which the packet is copied.
-*/
-static struct sk_buff *
-de4x5_alloc_rx_buff(struct net_device *dev, int index, int len)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct sk_buff *p;
-
-#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
-    struct sk_buff *ret;
-    u_long i=0, tmp;
-
-    p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2);
-    if (!p) return NULL;
-
-    p->dev = dev;
-    tmp = virt_to_bus(p->data);
-    i = ((tmp + ALIGN) & ~ALIGN) - tmp;
-    skb_reserve(p, i);
-    lp->rx_ring[index].buf = cpu_to_le32(tmp + i);
-
-    ret = lp->rx_skb[index];
-    lp->rx_skb[index] = p;
-
-    if ((u_long) ret > 1) {
-	skb_put(ret, len);
-    }
-
-    return ret;
-
-#else
-    if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
-
-    p = dev_alloc_skb(len + 2);
-    if (!p) return NULL;
-
-    p->dev = dev;
-    skb_reserve(p, 2);	                               /* Align */
-    if (index < lp->rx_old) {                          /* Wrapped buffer */
-	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
-	memcpy(skb_put(p,tlen),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,tlen);
-	memcpy(skb_put(p,len-tlen),lp->rx_bufs,len-tlen);
-    } else {                                           /* Linear buffer */
-	memcpy(skb_put(p,len),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,len);
-    }
-		    
-    return p;
-#endif
-}
-
-static void
-de4x5_free_rx_buffs(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i;
-
-    for (i=0; i<lp->rxRingSize; i++) {
-	if ((u_long) lp->rx_skb[i] > 1) {
-	    dev_kfree_skb(lp->rx_skb[i]);
-	}
-	lp->rx_ring[i].status = 0;
-	lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
-    }
-
-    return;
-}
-
-static void
-de4x5_free_tx_buffs(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i;
-
-    for (i=0; i<lp->txRingSize; i++) {
-	if (lp->tx_skb[i])
-	    de4x5_free_tx_buff(lp, i);
-	lp->tx_ring[i].status = 0;
-    }
-
-    /* Unload the locally queued packets */
-    while (lp->cache.skb) {
-	dev_kfree_skb(de4x5_get_cache(dev));
-    }
-
-    return;
-}
-
-/*
-** When a user pulls a connection, the DECchip can end up in a
-** 'running - waiting for end of transmission' state. This means that we
-** have to perform a chip soft reset to ensure that we can synchronize
-** the hardware and software and make any media probes using a loopback
-** packet meaningful.
-*/
-static void
-de4x5_save_skbs(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 omr;
-
-    if (!lp->cache.save_cnt) {
-	STOP_DE4X5;
-	de4x5_tx(dev);                          /* Flush any sent skb's */
-	de4x5_free_tx_buffs(dev);
-	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
-	de4x5_sw_reset(dev);
-	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
-	lp->cache.save_cnt++;
-	START_DE4X5;
-    }
-
-    return;
-}
-
-static void
-de4x5_rst_desc_ring(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int i;
-    s32 omr;
-
-    if (lp->cache.save_cnt) {
-	STOP_DE4X5;
-	outl(lp->dma_rings, DE4X5_RRBA);
-	outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
-	     DE4X5_TRBA);
-    
-	lp->rx_new = lp->rx_old = 0;
-	lp->tx_new = lp->tx_old = 0;
-    
-	for (i = 0; i < lp->rxRingSize; i++) {
-	    lp->rx_ring[i].status = cpu_to_le32(R_OWN);
-	}
-    
-	for (i = 0; i < lp->txRingSize; i++) {
-	    lp->tx_ring[i].status = cpu_to_le32(0);
-	}
-    
-	barrier();
-	lp->cache.save_cnt--;
-	START_DE4X5;
-    }
-        
-    return;
-}
-
-static void
-de4x5_cache_state(struct net_device *dev, int flag)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    switch(flag) {
-      case DE4X5_SAVE_STATE:
-	lp->cache.csr0 = inl(DE4X5_BMR);
-	lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
-	lp->cache.csr7 = inl(DE4X5_IMR);
-	break;
-
-      case DE4X5_RESTORE_STATE:
-	outl(lp->cache.csr0, DE4X5_BMR);
-	outl(lp->cache.csr6, DE4X5_OMR);
-	outl(lp->cache.csr7, DE4X5_IMR);
-	if (lp->chipset == DC21140) {
-	    gep_wr(lp->cache.gepc, dev);
-	    gep_wr(lp->cache.gep, dev);
-	} else {
-	    reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
-			                                      lp->cache.csr15);
-	}
-	break;
-    }
-
-    return;
-}
-
-static void
-de4x5_put_cache(struct net_device *dev, struct sk_buff *skb)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct sk_buff *p;
-
-    if (lp->cache.skb) {
-	for (p=lp->cache.skb; p->next; p=p->next);
-	p->next = skb;
-    } else {
-	lp->cache.skb = skb;
-    }
-    skb->next = NULL;
-
-    return;
-}
-
-static void
-de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct sk_buff *p = lp->cache.skb;
-
-    lp->cache.skb = skb;
-    skb->next = p;
-
-    return;
-}
-
-static struct sk_buff *
-de4x5_get_cache(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct sk_buff *p = lp->cache.skb;
-
-    if (p) {
-	lp->cache.skb = p->next;
-	p->next = NULL;
-    }
-
-    return p;
-}
-
-/*
-** Check the Auto Negotiation State. Return OK when a link pass interrupt
-** is received and the auto-negotiation status is NWAY OK.
-*/
-static int
-test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 sts, ans;
-    
-    if (lp->timeout < 0) {
-	lp->timeout = msec/100;
-	outl(irq_mask, DE4X5_IMR);
-	
-	/* clear all pending interrupts */
-	sts = inl(DE4X5_STS);
-	outl(sts, DE4X5_STS);
-    }
-    
-    ans = inl(DE4X5_SISR) & SISR_ANS;
-    sts = inl(DE4X5_STS) & ~TIMER_CB;
-    
-    if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
-	sts = 100 | TIMER_CB;
-    } else {
-	lp->timeout = -1;
-    }
-    
-    return sts;
-}
-
-static void
-de4x5_setup_intr(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 imr, sts;
-    
-    if (inl(DE4X5_OMR) & OMR_SR) {   /* Only unmask if TX/RX is enabled */
-	imr = 0;
-	UNMASK_IRQs;
-	sts = inl(DE4X5_STS);        /* Reset any pending (stale) interrupts */
-	outl(sts, DE4X5_STS);
-	ENABLE_IRQs;
-    }
-    
-    return;
-}
-
-/*
-**
-*/
-static void
-reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    RESET_SIA;
-    if (lp->useSROM) {
-	if (lp->ibn == 3) {
-	    srom_exec(dev, lp->phy[lp->active].rst);
-	    srom_exec(dev, lp->phy[lp->active].gep);
-	    outl(1, DE4X5_SICR);
-	    return;
-	} else {
-	    csr15 = lp->cache.csr15;
-	    csr14 = lp->cache.csr14;
-	    csr13 = lp->cache.csr13;
-	    outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
-	    outl(csr15 | lp->cache.gep, DE4X5_SIGR);
-	}
-    } else {
-	outl(csr15, DE4X5_SIGR);
-    }
-    outl(csr14, DE4X5_STRR);
-    outl(csr13, DE4X5_SICR);
-
-    mdelay(10);
-
-    return;
-}
-
-/*
-** Create a loopback ethernet packet
-*/
-static void
-create_packet(struct net_device *dev, char *frame, int len)
-{
-    int i;
-    char *buf = frame;
-    
-    for (i=0; i<ETH_ALEN; i++) {             /* Use this source address */
-	*buf++ = dev->dev_addr[i];
-    }
-    for (i=0; i<ETH_ALEN; i++) {             /* Use this destination address */
-	*buf++ = dev->dev_addr[i];
-    }
-    
-    *buf++ = 0;                              /* Packet length (2 bytes) */
-    *buf++ = 1;
-    
-    return;
-}
-
-/*
-** Look for a particular board name in the EISA configuration space
-*/
-static int
-EISA_signature(char *name, s32 eisa_id)
-{
-    static c_char *signatures[] = DE4X5_SIGNATURE;
-    char ManCode[DE4X5_STRLEN];
-    union {
-	s32 ID;
-	char Id[4];
-    } Eisa;
-    int i, status = 0, siglen = sizeof(signatures)/sizeof(c_char *);
-    
-    *name = '\0';
-    Eisa.ID = inl(eisa_id);
-    
-    ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
-    ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
-    ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
-    ManCode[3]=((Eisa.Id[2]&0x0f)+0x30);
-    ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
-    ManCode[5]='\0';
-    
-    for (i=0;i<siglen;i++) {
-	if (strstr(ManCode, signatures[i]) != NULL) {
-	    strcpy(name,ManCode);
-	    status = 1;
-	    break;
-	}
-    }
-    
-    return status;                         /* return the device name string */
-}
-
-/*
-** Look for a particular board name in the PCI configuration space
-*/
-static int
-PCI_signature(char *name, struct bus_type *lp)
-{
-    static c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
-    int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
-    
-    if (lp->chipset == DC21040) {
-	strcpy(name, "DE434/5");
-	return status;
-    } else {                           /* Search for a DEC name in the SROM */
-	int i = *((char *)&lp->srom + 19) * 3;
-	strncpy(name, (char *)&lp->srom + 26 + i, 8);
-    }
-    name[8] = '\0';
-    for (i=0; i<siglen; i++) {
-	if (strstr(name,de4x5_signatures[i])!=NULL) break;
-    }
-    if (i == siglen) {
-	if (dec_only) {
-	    *name = '\0';
-	} else {                        /* Use chip name to avoid confusion */
-	    strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
-			   ((lp->chipset == DC21041) ? "DC21041" :
-			    ((lp->chipset == DC21140) ? "DC21140" :
-			     ((lp->chipset == DC21142) ? "DC21142" :
-			      ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
-			     )))))));
-	}
-	if (lp->chipset != DC21041) {
-	    useSROM = TRUE;             /* card is not recognisably DEC */
-	}
-    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-	useSROM = TRUE;
-    }
-    
-    return status;
-}
-
-/*
-** Set up the Ethernet PROM counter to the start of the Ethernet address on
-** the DC21040, else  read the SROM for the other chips.
-** The SROM may not be present in a multi-MAC card, so first read the
-** MAC address and check for a bad address. If there is a bad one then exit
-** immediately with the prior srom contents intact (the h/w address will
-** be fixed up later).
-*/
-static void
-DevicePresent(u_long aprom_addr)
-{
-    int i, j=0;
-    struct bus_type *lp = &bus;
-    
-    if (lp->chipset == DC21040) {
-	if (lp->bus == EISA) {
-	    enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */
-	} else {
-	    outl(0, aprom_addr);       /* Reset Ethernet Address ROM Pointer */
-	}
-    } else {                           /* Read new srom */
-	u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
-	for (i=0; i<(ETH_ALEN>>1); i++) {
-	    tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
-	    *p = le16_to_cpu(tmp);
-	    j += *p++;
-	}
-	if ((j == 0) || (j == 0x2fffd)) {
-	    return;
-	}
-
-	p=(short *)&lp->srom;
-	for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
-	    tmp = srom_rd(aprom_addr, i);
-	    *p++ = le16_to_cpu(tmp);
-	}
-	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
-    }
-    
-    return;
-}
-
-/*
-** Since the write on the Enet PROM register doesn't seem to reset the PROM
-** pointer correctly (at least on my DE425 EISA card), this routine should do
-** it...from depca.c.
-*/
-static void
-enet_addr_rst(u_long aprom_addr)
-{
-    union {
-	struct {
-	    u32 a;
-	    u32 b;
-	} llsig;
-	char Sig[sizeof(u32) << 1];
-    } dev;
-    short sigLength=0;
-    s8 data;
-    int i, j;
-    
-    dev.llsig.a = ETH_PROM_SIG;
-    dev.llsig.b = ETH_PROM_SIG;
-    sigLength = sizeof(u32) << 1;
-    
-    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
-	data = inb(aprom_addr);
-	if (dev.Sig[j] == data) {    /* track signature */
-	    j++;
-	} else {                     /* lost signature; begin search again */
-	    if (data == dev.Sig[0]) {  /* rare case.... */
-		j=1;
-	    } else {
-		j=0;
-	    }
-	}
-    }
-    
-    return;
-}
-
-/*
-** For the bad status case and no SROM, then add one to the previous
-** address. However, need to add one backwards in case we have 0xff
-** as one or more of the bytes. Only the last 3 bytes should be checked
-** as the first three are invariant - assigned to an organisation.
-*/
-static int
-get_hw_addr(struct net_device *dev)
-{
-    u_long iobase = dev->base_addr;
-    int broken, i, k, tmp, status = 0;
-    u_short j,chksum;
-    struct bus_type *lp = &bus;
-
-    broken = de4x5_bad_srom(lp);
-
-    for (i=0,k=0,j=0;j<3;j++) {
-	k <<= 1;
-	if (k > 0xffff) k-=0xffff;
-	
-	if (lp->bus == PCI) {
-	    if (lp->chipset == DC21040) {
-		while ((tmp = inl(DE4X5_APROM)) < 0);
-		k += (u_char) tmp;
-		dev->dev_addr[i++] = (u_char) tmp;
-		while ((tmp = inl(DE4X5_APROM)) < 0);
-		k += (u_short) (tmp << 8);
-		dev->dev_addr[i++] = (u_char) tmp;
-	    } else if (!broken) {
-		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
-		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
-	    } else if ((broken == SMC) || (broken == ACCTON)) {
-		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
-		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
-	    }
-	} else {
-	    k += (u_char) (tmp = inb(EISA_APROM));
-	    dev->dev_addr[i++] = (u_char) tmp;
-	    k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
-	    dev->dev_addr[i++] = (u_char) tmp;
-	}
-	
-	if (k > 0xffff) k-=0xffff;
-    }
-    if (k == 0xffff) k=0;
-    
-    if (lp->bus == PCI) {
-	if (lp->chipset == DC21040) {
-	    while ((tmp = inl(DE4X5_APROM)) < 0);
-	    chksum = (u_char) tmp;
-	    while ((tmp = inl(DE4X5_APROM)) < 0);
-	    chksum |= (u_short) (tmp << 8);
-	    if ((k != chksum) && (dec_only)) status = -1;
-	}
-    } else {
-	chksum = (u_char) inb(EISA_APROM);
-	chksum |= (u_short) (inb(EISA_APROM) << 8);
-	if ((k != chksum) && (dec_only)) status = -1;
-    }
-
-    /* If possible, try to fix a broken card - SMC only so far */
-    srom_repair(dev, broken);
-
-#ifdef CONFIG_PPC
-    /* 
-    ** If the address starts with 00 a0, we have to bit-reverse
-    ** each byte of the address.
-    */
-    if ( (ppc_md.ppc_machine & _MACH_Pmac) &&
-	 (dev->dev_addr[0] == 0) &&
-	 (dev->dev_addr[1] == 0xa0) )
-    {
-	    for (i = 0; i < ETH_ALEN; ++i)
-	    {
-		    int x = dev->dev_addr[i];
-		    x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4);
-		    x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2);
-		    dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
-	    }
-    }
-#endif /* CONFIG_PPC */
-
-    /* Test for a bad enet address */
-    status = test_bad_enet(dev, status);
-
-    return status;
-}
-
-/*
-** Test for enet addresses in the first 32 bytes. The built-in strncmp
-** didn't seem to work here...?
-*/
-static int
-de4x5_bad_srom(struct bus_type *lp)
-{
-    int i, status = 0;
-
-    for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) {
-	if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) &&
-	    !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) {
-	    if (i == 0) {
-		status = SMC;
-	    } else if (i == 1) {
-		status = ACCTON;
-	    }
-	    break;
-	}
-    }
-
-    return status;
-}
-
-static int
-de4x5_strncmp(char *a, char *b, int n)
-{
-    int ret=0;
-
-    for (;n && !ret;n--) {
-	ret = *a++ - *b++;
-    }
-
-    return ret;
-}
-
-static void
-srom_repair(struct net_device *dev, int card)
-{
-    struct bus_type *lp = &bus;
-
-    switch(card) {
-      case SMC:
-	memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom));
-	memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
-	memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
-	useSROM = TRUE;
-	break;
-    }
-
-    return;
-}
-
-/*
-** Assume that the irq's do not follow the PCI spec - this is seems
-** to be true so far (2 for 2).
-*/
-static int
-test_bad_enet(struct net_device *dev, int status)
-{
-    struct bus_type *lp = &bus;
-    int i, tmp;
-
-    for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
-    if ((tmp == 0) || (tmp == 0x5fa)) {
-	if ((lp->chipset == last.chipset) && 
-	    (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
-	    for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
-	    for (i=ETH_ALEN-1; i>2; --i) {
-		dev->dev_addr[i] += 1;
-		if (dev->dev_addr[i] != 0) break;
-	    }
-	    for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
-	    if (!an_exception(lp)) {
-		dev->irq = last.irq;
-	    }
-
-	    status = 0;
-	}
-    } else if (!status) {
-	last.chipset = lp->chipset;
-	last.bus = lp->bus_num;
-	last.irq = dev->irq;
-	for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
-    }
-
-    return status;
-}
-
-/*
-** List of board exceptions with correctly wired IRQs
-*/
-static int
-an_exception(struct bus_type *lp)
-{
-    if ((*(u_short *)lp->srom.sub_vendor_id == 0x00c0) && 
-	(*(u_short *)lp->srom.sub_system_id == 0x95e0)) {
-	return -1;
-    }
-
-    return 0;
-}
-
-/*
-** SROM Read
-*/
-static short
-srom_rd(u_long addr, u_char offset)
-{
-    sendto_srom(SROM_RD | SROM_SR, addr);
-    
-    srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
-    srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
-    srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
-    
-    return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
-}
-
-static void
-srom_latch(u_int command, u_long addr)
-{
-    sendto_srom(command, addr);
-    sendto_srom(command | DT_CLK, addr);
-    sendto_srom(command, addr);
-    
-    return;
-}
-
-static void
-srom_command(u_int command, u_long addr)
-{
-    srom_latch(command, addr);
-    srom_latch(command, addr);
-    srom_latch((command & 0x0000ff00) | DT_CS, addr);
-    
-    return;
-}
-
-static void
-srom_address(u_int command, u_long addr, u_char offset)
-{
-    int i, a;
-    
-    a = offset << 2;
-    for (i=0; i<6; i++, a <<= 1) {
-	srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr);
-    }
-    udelay(1);
-    
-    i = (getfrom_srom(addr) >> 3) & 0x01;
-    
-    return;
-}
-
-static short
-srom_data(u_int command, u_long addr)
-{
-    int i;
-    short word = 0;
-    s32 tmp;
-    
-    for (i=0; i<16; i++) {
-	sendto_srom(command  | DT_CLK, addr);
-	tmp = getfrom_srom(addr);
-	sendto_srom(command, addr);
-	
-	word = (word << 1) | ((tmp >> 3) & 0x01);
-    }
-    
-    sendto_srom(command & 0x0000ff00, addr);
-    
-    return word;
-}
-
-/*
-static void
-srom_busy(u_int command, u_long addr)
-{
-   sendto_srom((command & 0x0000ff00) | DT_CS, addr);
-   
-   while (!((getfrom_srom(addr) >> 3) & 0x01)) {
-       mdelay(1);
-   }
-   
-   sendto_srom(command & 0x0000ff00, addr);
-   
-   return;
-}
-*/
-
-static void
-sendto_srom(u_int command, u_long addr)
-{
-    outl(command, addr);
-    udelay(1);
-    
-    return;
-}
-
-static int
-getfrom_srom(u_long addr)
-{
-    s32 tmp;
-    
-    tmp = inl(addr);
-    udelay(1);
-    
-    return tmp;
-}
-
-static int
-srom_infoleaf_info(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i, count;
-    u_char *p;
-
-    /* Find the infoleaf decoder function that matches this chipset */
-    for (i=0; i<INFOLEAF_SIZE; i++) {
-	if (lp->chipset == infoleaf_array[i].chipset) break;
-    }
-    if (i == INFOLEAF_SIZE) {
-	lp->useSROM = FALSE;
-	printk("%s: Cannot find correct chipset for SROM decoding!\n", 
-	                                                          dev->name);
-	return -ENXIO;
-    }
-
-    lp->infoleaf_fn = infoleaf_array[i].fn;
-
-    /* Find the information offset that this function should use */
-    count = *((u_char *)&lp->srom + 19);
-    p  = (u_char *)&lp->srom + 26;
-
-    if (count > 1) {
-	for (i=count; i; --i, p+=3) {
-	    if (lp->device == *p) break;
-	}
-	if (i == 0) {
-	    lp->useSROM = FALSE;
-	    printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", 
-	                                               dev->name, lp->device);
-	    return -ENXIO;
-	}
-    }
-
-    lp->infoleaf_offset = TWIDDLE(p+1);
-
-    return 0;
-}
-
-/*
-** This routine loads any type 1 or 3 MII info into the mii device
-** struct and executes any type 5 code to reset PHY devices for this
-** controller.
-** The info for the MII devices will be valid since the index used
-** will follow the discovery process from MII address 1-31 then 0.
-*/
-static void
-srom_init(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
-    u_char count;
-
-    p+=2;
-    if (lp->chipset == DC21140) {
-	lp->cache.gepc = (*p++ | GEP_CTRL);
-	gep_wr(lp->cache.gepc, dev);
-    }
-
-    /* Block count */
-    count = *p++;
-
-    /* Jump the infoblocks to find types */
-    for (;count; --count) {
-	if (*p < 128) {
-	    p += COMPACT_LEN;
-	} else if (*(p+1) == 5) {
-	    type5_infoblock(dev, 1, p);
-	    p += ((*p & BLOCK_LEN) + 1);
-	} else if (*(p+1) == 4) {
-	    p += ((*p & BLOCK_LEN) + 1);
-	} else if (*(p+1) == 3) {
-	    type3_infoblock(dev, 1, p);
-	    p += ((*p & BLOCK_LEN) + 1);
-	} else if (*(p+1) == 2) {
-	    p += ((*p & BLOCK_LEN) + 1);
-	} else if (*(p+1) == 1) {
-	    type1_infoblock(dev, 1, p);
-	    p += ((*p & BLOCK_LEN) + 1);
-	} else {
-	    p += ((*p & BLOCK_LEN) + 1);
-	}
-    }
-
-    return;
-}
-
-/*
-** A generic routine that writes GEP control, data and reset information
-** to the GEP register (21140) or csr15 GEP portion (2114[23]).
-*/
-static void
-srom_exec(struct net_device *dev, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    u_char count = (p ? *p++ : 0);
-    u_short *w = (u_short *)p;
-
-    if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
-
-    if (lp->chipset != DC21140) RESET_SIA;
- 
-    while (count--) {
-	gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? 
-		                                   *p++ : TWIDDLE(w++)), dev);
-	mdelay(2);                          /* 2ms per action */
-    }
-
-    if (lp->chipset != DC21140) {
-	outl(lp->cache.csr14, DE4X5_STRR);
-	outl(lp->cache.csr13, DE4X5_SICR);
-    }
-
-    return;
-}
-
-/*
-** Basically this function is a NOP since it will never be called,
-** unless I implement the DC21041 SROM functions. There's no need
-** since the existing code will be satisfactory for all boards.
-*/
-static int 
-dc21041_infoleaf(struct net_device *dev)
-{
-    return DE4X5_AUTOSENSE_MS;
-}
-
-static int 
-dc21140_infoleaf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char count = 0;
-    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-
-    /* Read the connection type */
-    p+=2;
-
-    /* GEP control */
-    lp->cache.gepc = (*p++ | GEP_CTRL);
-
-    /* Block count */
-    count = *p++;
-
-    /* Recursively figure out the info blocks */
-    if (*p < 128) {
-	next_tick = dc_infoblock[COMPACT](dev, count, p);
-    } else {
-	next_tick = dc_infoblock[*(p+1)](dev, count, p);
-    }
-
-    if (lp->tcount == count) {
-	lp->media = NC;
-        if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tcount = 0;
-	lp->tx_enable = FALSE;
-    }
-
-    return next_tick & ~TIMER_CB;
-}
-
-static int 
-dc21142_infoleaf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char count = 0;
-    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-
-    /* Read the connection type */
-    p+=2;
-
-    /* Block count */
-    count = *p++;
-
-    /* Recursively figure out the info blocks */
-    if (*p < 128) {
-	next_tick = dc_infoblock[COMPACT](dev, count, p);
-    } else {
-	next_tick = dc_infoblock[*(p+1)](dev, count, p);
-    }
-
-    if (lp->tcount == count) {
-	lp->media = NC;
-        if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tcount = 0;
-	lp->tx_enable = FALSE;
-    }
-
-    return next_tick & ~TIMER_CB;
-}
-
-static int 
-dc21143_infoleaf(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char count = 0;
-    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
-    int next_tick = DE4X5_AUTOSENSE_MS;
-
-    /* Read the connection type */
-    p+=2;
-
-    /* Block count */
-    count = *p++;
-
-    /* Recursively figure out the info blocks */
-    if (*p < 128) {
-	next_tick = dc_infoblock[COMPACT](dev, count, p);
-    } else {
-	next_tick = dc_infoblock[*(p+1)](dev, count, p);
-    }
-    if (lp->tcount == count) {
-	lp->media = NC;
-        if (lp->media != lp->c_media) {
-	    de4x5_dbg_media(dev);
-	    lp->c_media = lp->media;
-	}
-	lp->media = INIT;
-	lp->tcount = 0;
-	lp->tx_enable = FALSE;
-    }
-
-    return next_tick & ~TIMER_CB;
-}
-
-/*
-** The compact infoblock is only designed for DC21140[A] chips, so
-** we'll reuse the dc21140m_autoconf function. Non MII media only.
-*/
-static int 
-compact_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char flags, csr6;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+COMPACT_LEN) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN);
-	} else {
-	    return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN);
-	}
-    }
-
-    if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = COMPACT;
-        lp->active = 0;
-	gep_wr(lp->cache.gepc, dev);
-	lp->infoblock_media = (*p++) & COMPACT_MC;
-	lp->cache.gep = *p++;
-	csr6 = *p++;
-	flags = *p++;
-
-	lp->asBitValid = (flags & 0x80) ? 0 : -1;
-	lp->defMedium = (flags & 0x40) ? -1 : 0;
-	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
-	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-	lp->useMII = FALSE;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc21140m_autoconf(dev);
-}
-
-/*
-** This block describes non MII media for the DC21140[A] only.
-*/
-static int 
-type0_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = 0;
-        lp->active = 0;
-        gep_wr(lp->cache.gepc, dev);
-	p+=2;
-	lp->infoblock_media = (*p++) & BLOCK0_MC;
-	lp->cache.gep = *p++;
-	csr6 = *p++;
-	flags = *p++;
-
-	lp->asBitValid = (flags & 0x80) ? 0 : -1;
-	lp->defMedium = (flags & 0x40) ? -1 : 0;
-	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
-	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-	lp->useMII = FALSE;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc21140m_autoconf(dev);
-}
-
-/* These functions are under construction! */
-
-static int 
-type1_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    p += 2;
-    if (lp->state == INITIALISED) {
-        lp->ibn = 1;
-	lp->active = *p++;
-	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
-	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
-	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].ttm = TWIDDLE(p);
-	return 0;
-    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = 1;
-        lp->active = *p;
-	lp->infoblock_csr6 = OMR_MII_100;
-	lp->useMII = TRUE;
-	lp->infoblock_media = ANS;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc21140m_autoconf(dev);
-}
-
-static int 
-type2_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = 2;
-        lp->active = 0;
-	p += 2;
-	lp->infoblock_media = (*p) & MEDIA_CODE;
-
-        if ((*p++) & EXT_FIELD) {
-	    lp->cache.csr13 = TWIDDLE(p); p += 2;
-	    lp->cache.csr14 = TWIDDLE(p); p += 2;
-	    lp->cache.csr15 = TWIDDLE(p); p += 2;
-	} else {
-	    lp->cache.csr13 = CSR13;
-	    lp->cache.csr14 = CSR14;
-	    lp->cache.csr15 = CSR15;
-	}
-        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
-        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16);
-	lp->infoblock_csr6 = OMR_SIA;
-	lp->useMII = FALSE;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc2114x_autoconf(dev);
-}
-
-static int 
-type3_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    p += 2;
-    if (lp->state == INITIALISED) {
-        lp->ibn = 3;
-        lp->active = *p++;
-	if (MOTO_SROM_BUG) lp->active = 0;
-	lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
-	lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
-	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
-	lp->phy[lp->active].mci = *p;
-	return 0;
-    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = 3;
-	lp->active = *p;
-	if (MOTO_SROM_BUG) lp->active = 0;
-	lp->infoblock_csr6 = OMR_MII_100;
-	lp->useMII = TRUE;
-	lp->infoblock_media = ANS;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc2114x_autoconf(dev);
-}
-
-static int 
-type4_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    if ((lp->media == INIT) && (lp->timeout < 0)) {
-        lp->ibn = 4;
-        lp->active = 0;
-	p+=2;
-	lp->infoblock_media = (*p++) & MEDIA_CODE;
-        lp->cache.csr13 = CSR13;              /* Hard coded defaults */
-	lp->cache.csr14 = CSR14;
-	lp->cache.csr15 = CSR15;
-        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
-        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16); p += 2;
-	csr6 = *p++;
-	flags = *p++;
-
-	lp->asBitValid = (flags & 0x80) ? 0 : -1;
-	lp->defMedium = (flags & 0x40) ? -1 : 0;
-	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
-	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
-	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
-	lp->useMII = FALSE;
-
-	de4x5_switch_mac_port(dev);
-    }
-
-    return dc2114x_autoconf(dev);
-}
-
-/*
-** This block type provides information for resetting external devices
-** (chips) through the General Purpose Register.
-*/
-static int 
-type5_infoblock(struct net_device *dev, u_char count, u_char *p)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_char len = (*p & BLOCK_LEN)+1;
-
-    /* Recursively figure out the info blocks */
-    if (--count > lp->tcount) {
-	if (*(p+len) < 128) {
-	    return dc_infoblock[COMPACT](dev, count, p+len);
-	} else {
-	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
-	}
-    }
-
-    /* Must be initializing to run this code */
-    if ((lp->state == INITIALISED) || (lp->media == INIT)) {
-	p+=2;
-        lp->rst = p;
-        srom_exec(dev, lp->rst);
-    }
-
-    return DE4X5_AUTOSENSE_MS;
-}
-
-/*
-** MII Read/Write
-*/
-
-static int
-mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
-{
-    mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
-    mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
-    mii_wdata(MII_STRD, 4, ioaddr);        /* SFD and Read operation         */
-    mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
-    mii_address(phyreg, ioaddr);           /* PHY Register to read           */
-    mii_ta(MII_STRD, ioaddr);              /* Turn around time - 2 MDC       */
-    
-    return mii_rdata(ioaddr);              /* Read data                      */
-}
-
-static void
-mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
-{
-    mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
-    mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
-    mii_wdata(MII_STWR, 4, ioaddr);        /* SFD and Write operation        */
-    mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
-    mii_address(phyreg, ioaddr);           /* PHY Register to write          */
-    mii_ta(MII_STWR, ioaddr);              /* Turn around time - 2 MDC       */
-    data = mii_swap(data, 16);             /* Swap data bit ordering         */
-    mii_wdata(data, 16, ioaddr);           /* Write data                     */
-    
-    return;
-}
-
-static int
-mii_rdata(u_long ioaddr)
-{
-    int i;
-    s32 tmp = 0;
-    
-    for (i=0; i<16; i++) {
-	tmp <<= 1;
-	tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
-    }
-    
-    return tmp;
-}
-
-static void
-mii_wdata(int data, int len, u_long ioaddr)
-{
-    int i;
-    
-    for (i=0; i<len; i++) {
-	sendto_mii(MII_MWR | MII_WR, data, ioaddr);
-	data >>= 1;
-    }
-    
-    return;
-}
-
-static void
-mii_address(u_char addr, u_long ioaddr)
-{
-    int i;
-    
-    addr = mii_swap(addr, 5);
-    for (i=0; i<5; i++) {
-	sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
-	addr >>= 1;
-    }
-    
-    return;
-}
-
-static void
-mii_ta(u_long rw, u_long ioaddr)
-{
-    if (rw == MII_STWR) {
-	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
-	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
-    } else {
-	getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
-    }
-    
-    return;
-}
-
-static int
-mii_swap(int data, int len)
-{
-    int i, tmp = 0;
-    
-    for (i=0; i<len; i++) {
-	tmp <<= 1;
-	tmp |= (data & 1);
-	data >>= 1;
-    }
-    
-    return tmp;
-}
-
-static void
-sendto_mii(u32 command, int data, u_long ioaddr)
-{
-    u32 j;
-    
-    j = (data & 1) << 17;
-    outl(command | j, ioaddr);
-    udelay(1);
-    outl(command | MII_MDC | j, ioaddr);
-    udelay(1);
-    
-    return;
-}
-
-static int
-getfrom_mii(u32 command, u_long ioaddr)
-{
-    outl(command, ioaddr);
-    udelay(1);
-    outl(command | MII_MDC, ioaddr);
-    udelay(1);
-    
-    return ((inl(ioaddr) >> 19) & 1);
-}
-
-/*
-** Here's 3 ways to calculate the OUI from the ID registers.
-*/
-static int
-mii_get_oui(u_char phyaddr, u_long ioaddr)
-{
-/*
-    union {
-	u_short reg;
-	u_char breg[2];
-    } a;
-    int i, r2, r3, ret=0;*/
-    int r2, r3;
-
-    /* Read r2 and r3 */
-    r2 = mii_rd(MII_ID0, phyaddr, ioaddr);
-    r3 = mii_rd(MII_ID1, phyaddr, ioaddr);
-                                                /* SEEQ and Cypress way * /
-    / * Shuffle r2 and r3 * /
-    a.reg=0;
-    r3 = ((r3>>10)|(r2<<6))&0x0ff;
-    r2 = ((r2>>2)&0x3fff);
-
-    / * Bit reverse r3 * /
-    for (i=0;i<8;i++) {
-	ret<<=1;
-	ret |= (r3&1);
-	r3>>=1;
-    }
-
-    / * Bit reverse r2 * /
-    for (i=0;i<16;i++) {
-	a.reg<<=1;
-	a.reg |= (r2&1);
-	r2>>=1;
-    }
-
-    / * Swap r2 bytes * /
-    i=a.breg[0];
-    a.breg[0]=a.breg[1];
-    a.breg[1]=i;
-
-    return ((a.reg<<8)|ret); */                 /* SEEQ and Cypress way */
-/*    return ((r2<<6)|(u_int)(r3>>10)); */      /* NATIONAL and BROADCOM way */
-    return r2;                                  /* (I did it) My way */
-}
-
-/*
-** The SROM spec forces us to search addresses [1-31 0]. Bummer.
-*/
-static int
-mii_get_phy(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
-    int id;
-    
-    lp->active = 0;
-    lp->useMII = TRUE;
-
-    /* Search the MII address space for possible PHY devices */
-    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
-	lp->phy[lp->active].addr = i;
-	if (i==0) n++;                             /* Count cycles */
-	while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
-	id = mii_get_oui(i, DE4X5_MII); 
-	if ((id == 0) || (id == 65535)) continue;  /* Valid ID? */
-	for (j=0; j<limit; j++) {                  /* Search PHY table */
-	    if (id != phy_info[j].id) continue;    /* ID match? */
-	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
-	    if (k < DE4X5_MAX_PHY) {
-		memcpy((char *)&lp->phy[k],
-		       (char *)&phy_info[j], sizeof(struct phy_table));
-		lp->phy[k].addr = i;
-		lp->mii_cnt++;
-		lp->active++;
-	    } else {
-		goto purgatory;                    /* Stop the search */
-	    }
-	    break;
-	}
-	if ((j == limit) && (i < DE4X5_MAX_MII)) {
-	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
-	    lp->phy[k].addr = i;
-	    lp->phy[k].id = id;
-	    lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */
-	    lp->phy[k].spd.mask = GENERIC_MASK;    /* 100Mb/s technologies   */
-	    lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
-	    lp->mii_cnt++;
-	    lp->active++;
-	    printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name);
-	    j = de4x5_debug;
-	    de4x5_debug |= DEBUG_MII;
-	    de4x5_dbg_mii(dev, k);
-	    de4x5_debug = j;
-	    printk("\n");
-	}
-    }
-  purgatory:
-    lp->active = 0;
-    if (lp->phy[0].id) {                           /* Reset the PHY devices */
-	for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
-	    mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
-	    while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
-	    
-	    de4x5_dbg_mii(dev, k);
-	}
-    }
-    if (!lp->mii_cnt) lp->useMII = FALSE;
-
-    return lp->mii_cnt;
-}
-
-static char *
-build_setup_frame(struct net_device *dev, int mode)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i;
-    char *pa = lp->setup_frame;
-    
-    /* Initialise the setup frame */
-    if (mode == ALL) {
-	memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
-    }
-    
-    if (lp->setup_f == HASH_PERF) {
-	for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
-	    *(pa + i) = dev->dev_addr[i];                 /* Host address */
-	    if (i & 0x01) pa += 2;
-	}
-	*(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
-    } else {
-	for (i=0; i<ETH_ALEN; i++) { /* Host address */
-	    *(pa + (i&1)) = dev->dev_addr[i];
-	    if (i & 0x01) pa += 4;
-	}
-	for (i=0; i<ETH_ALEN; i++) { /* Broadcast address */
-	    *(pa + (i&1)) = (char) 0xff;
-	    if (i & 0x01) pa += 4;
-	}
-    }
-    
-    return pa;                     /* Points to the next entry */
-}
-
-static void
-enable_ast(struct net_device *dev, u32 time_out)
-{
-    timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
-    
-    return;
-}
-
-static void
-disable_ast(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    
-    del_timer(&lp->timer);
-    
-    return;
-}
-
-static long
-de4x5_switch_mac_port(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    s32 omr;
-
-    STOP_DE4X5;
-
-    /* Assert the OMR_PS bit in CSR6 */
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
-			                                             OMR_FDX));
-    omr |= lp->infoblock_csr6;
-    if (omr & OMR_PS) omr |= OMR_HBD;
-    outl(omr, DE4X5_OMR);
-    
-    /* Soft Reset */
-    RESET_DE4X5;
-    
-    /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
-    if (lp->chipset == DC21140) {
-	gep_wr(lp->cache.gepc, dev);
-	gep_wr(lp->cache.gep, dev);
-    } else if ((lp->chipset & ~0x0ff) == DC2114x) {
-	reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
-    }
-
-    /* Restore CSR6 */
-    outl(omr, DE4X5_OMR);
-
-    /* Reset CSR8 */
-    inl(DE4X5_MFC);
-
-    return omr;
-}
-
-static void
-gep_wr(s32 data, struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    if (lp->chipset == DC21140) {
-	outl(data, DE4X5_GEP);
-    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-	outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
-    }
-
-    return;
-}
-
-static int
-gep_rd(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    if (lp->chipset == DC21140) {
-	return inl(DE4X5_GEP);
-    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
-	return (inl(DE4X5_SIGR) & 0x000fffff);
-    }
-
-    return 0;
-}
-
-static void
-timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int dt;
-    
-    /* First, cancel any pending timer events */
-    del_timer(&lp->timer);
-    
-    /* Convert msec to ticks */
-    dt = (msec * HZ) / 1000;
-    if (dt==0) dt=1;
-    
-    /* Set up timer */
-    lp->timer.expires = jiffies + dt;
-    lp->timer.function = fn;
-    lp->timer.data = data;
-    add_timer(&lp->timer);
-    
-    return;
-}
-
-static void
-yawn(struct net_device *dev, int state)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-
-    if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
-
-    if(lp->bus == EISA) {
-	switch(state) {
-	  case WAKEUP:
-	    outb(WAKEUP, PCI_CFPM);
-	    mdelay(10);
-	    break;
-
-	  case SNOOZE:
-	    outb(SNOOZE, PCI_CFPM);
-	    break;
-
-	  case SLEEP:
-	    outl(0, DE4X5_SICR);
-	    outb(SLEEP, PCI_CFPM);
-	    break;
-	}
-    } else {
-	switch(state) {
-	  case WAKEUP:
-	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
-				      PCI_CFDA_PSM, WAKEUP);
-	    mdelay(10);
-	    break;
-
-	  case SNOOZE:
-	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
-				      PCI_CFDA_PSM, SNOOZE);
-	    break;
-
-	  case SLEEP:
-	    outl(0, DE4X5_SICR);
-	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
-				      PCI_CFDA_PSM, SLEEP);
-	    break;
-	}
-    }
-
-    return;
-}
-
-static void
-de4x5_parse_params(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    char *p, *q, t;
-
-    lp->params.fdx = 0;
-    lp->params.autosense = AUTO;
-
-    if (args == NULL) return;
-
-    if ((p = strstr(args, dev->name))) {
-	if (!(q = strstr(p+strlen(dev->name), "eth"))) q = p + strlen(p);
-	t = *q;
-	*q = '\0';
-
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-	if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1;
-#endif
-	if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
-
-	if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
-	    if (strstr(p, "TP")) {
-		lp->params.autosense = TP;
-	    } else if (strstr(p, "TP_NW")) {
-		lp->params.autosense = TP_NW;
-	    } else if (strstr(p, "BNC")) {
-		lp->params.autosense = BNC;
-	    } else if (strstr(p, "AUI")) {
-		lp->params.autosense = AUI;
-	    } else if (strstr(p, "BNC_AUI")) {
-		lp->params.autosense = BNC;
-	    } else if (strstr(p, "10Mb")) {
-		lp->params.autosense = _10Mb;
-	    } else if (strstr(p, "100Mb")) {
-		lp->params.autosense = _100Mb;
-	    } else if (strstr(p, "AUTO")) {
-		lp->params.autosense = AUTO;
-	    }
-	}
-	*q = t;
-    }
-
-    return;
-}
-
-static void
-de4x5_dbg_open(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    int i;
-    
-    if (de4x5_debug & DEBUG_OPEN) {
-	printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
-	printk("\tphysical address: ");
-	for (i=0;i<6;i++) {
-	    printk("%2.2x:",(short)dev->dev_addr[i]);
-	}
-	printk("\n");
-	printk("Descriptor head addresses:\n");
-	printk("\t0x%8.8lx  0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
-	printk("Descriptor addresses:\nRX: ");
-	for (i=0;i<lp->rxRingSize-1;i++){
-	    if (i < 3) {
-		printk("0x%8.8lx  ",(u_long)&lp->rx_ring[i].status);
-	    }
-	}
-	printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
-	printk("TX: ");
-	for (i=0;i<lp->txRingSize-1;i++){
-	    if (i < 3) {
-		printk("0x%8.8lx  ", (u_long)&lp->tx_ring[i].status);
-	    }
-	}
-	printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
-	printk("Descriptor buffers:\nRX: ");
-	for (i=0;i<lp->rxRingSize-1;i++){
-	    if (i < 3) {
-		printk("0x%8.8x  ",le32_to_cpu(lp->rx_ring[i].buf));
-	    }
-	}
-	printk("...0x%8.8x\n",le32_to_cpu(lp->rx_ring[i].buf));
-	printk("TX: ");
-	for (i=0;i<lp->txRingSize-1;i++){
-	    if (i < 3) {
-		printk("0x%8.8x  ", le32_to_cpu(lp->tx_ring[i].buf));
-	    }
-	}
-	printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
-	printk("Ring size: \nRX: %d\nTX: %d\n", 
-	       (short)lp->rxRingSize, 
-	       (short)lp->txRingSize); 
-    }
-    
-    return;
-}
-
-static void
-de4x5_dbg_mii(struct net_device *dev, int k)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    u_long iobase = dev->base_addr;
-    
-    if (de4x5_debug & DEBUG_MII) {
-	printk("\nMII device address: %d\n", lp->phy[k].addr);
-	printk("MII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
-	printk("MII SR:  %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
-	printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
-	printk("MII ID1: %x\n",mii_rd(MII_ID1,lp->phy[k].addr,DE4X5_MII));
-	if (lp->phy[k].id != BROADCOM_T4) {
-	    printk("MII ANA: %x\n",mii_rd(0x04,lp->phy[k].addr,DE4X5_MII));
-	    printk("MII ANC: %x\n",mii_rd(0x05,lp->phy[k].addr,DE4X5_MII));
-	}
-	printk("MII 16:  %x\n",mii_rd(0x10,lp->phy[k].addr,DE4X5_MII));
-	if (lp->phy[k].id != BROADCOM_T4) {
-	    printk("MII 17:  %x\n",mii_rd(0x11,lp->phy[k].addr,DE4X5_MII));
-	    printk("MII 18:  %x\n",mii_rd(0x12,lp->phy[k].addr,DE4X5_MII));
-	} else {
-	    printk("MII 20:  %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
-	}
-    }
-    
-    return;
-}
-
-static void
-de4x5_dbg_media(struct net_device *dev)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    
-    if (lp->media != lp->c_media) {
-	if (de4x5_debug & DEBUG_MEDIA) {
-	    printk("%s: media is %s%s\n", dev->name,
-		   (lp->media == NC  ? "unconnected, link down or incompatible connection" :
-		    (lp->media == TP  ? "TP" :
-		     (lp->media == ANS ? "TP/Nway" :
-		      (lp->media == BNC ? "BNC" : 
-		       (lp->media == AUI ? "AUI" : 
-			(lp->media == BNC_AUI ? "BNC/AUI" : 
-			 (lp->media == EXT_SIA ? "EXT SIA" : 
-			  (lp->media == _100Mb  ? "100Mb/s" :
-			   (lp->media == _10Mb   ? "10Mb/s" :
-			    "???"
-			    ))))))))), (lp->fdx?" full duplex.":"."));
-	}
-	lp->c_media = lp->media;
-    }
-    
-    return;
-}
-
-static void
-de4x5_dbg_srom(struct de4x5_srom *p)
-{
-    int i;
-
-    if (de4x5_debug & DEBUG_SROM) {
-	printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
-	printk("Sub-system ID:        %04x\n", *((u_short *)p->sub_system_id));
-	printk("ID Block CRC:         %02x\n", (u_char)(p->id_block_crc));
-	printk("SROM version:         %02x\n", (u_char)(p->version));
-	printk("# controllers:         %02x\n", (u_char)(p->num_controllers));
-
-	printk("Hardware Address:     ");
-	for (i=0;i<ETH_ALEN-1;i++) {
-	    printk("%02x:", (u_char)*(p->ieee_addr+i));
-	}
-	printk("%02x\n", (u_char)*(p->ieee_addr+i));
-	printk("CRC checksum:         %04x\n", (u_short)(p->chksum));
-	for (i=0; i<64; i++) {
-	    printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
-	}
-    }
-
-    return;
-}
-
-static void
-de4x5_dbg_rx(struct sk_buff *skb, int len)
-{
-    int i, j;
-
-    if (de4x5_debug & DEBUG_RX) {
-	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
-	       (u_char)skb->data[0],
-	       (u_char)skb->data[1],
-	       (u_char)skb->data[2],
-	       (u_char)skb->data[3],
-	       (u_char)skb->data[4],
-	       (u_char)skb->data[5],
-	       (u_char)skb->data[6],
-	       (u_char)skb->data[7],
-	       (u_char)skb->data[8],
-	       (u_char)skb->data[9],
-	       (u_char)skb->data[10],
-	       (u_char)skb->data[11],
-	       (u_char)skb->data[12],
-	       (u_char)skb->data[13],
-	       len);
-	for (j=0; len>0;j+=16, len-=16) {
-	  printk("    %03x: ",j);
-	  for (i=0; i<16 && i<len; i++) {
-	    printk("%02x ",(u_char)skb->data[i+j]);
-	  }
-	  printk("\n");
-	}
-    }
-
-    return;
-}
-
-/*
-** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases. In the normal course of events
-** this function is only used for my testing.
-*/
-static int
-de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
-    struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
-    u_long iobase = dev->base_addr;
-    int i, j, status = 0;
-    s32 omr;
-    union {
-	u8  addr[144];
-	u16 sval[72];
-	u32 lval[36];
-    } tmp;
-    u_long flags = 0;
-    
-    switch(ioc->cmd) {
-    case DE4X5_GET_HWADDR:           /* Get the hardware address */
-	ioc->len = ETH_ALEN;
-	for (i=0; i<ETH_ALEN; i++) {
-	    tmp.addr[i] = dev->dev_addr[i];
-	}
-	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
-	break;
-
-    case DE4X5_SET_HWADDR:           /* Set the hardware address */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT;
-	if (netif_queue_stopped(dev))
-		return -EBUSY;
-	netif_stop_queue(dev);
-	for (i=0; i<ETH_ALEN; i++) {
-	    dev->dev_addr[i] = tmp.addr[i];
-	}
-	build_setup_frame(dev, PHYS_ADDR_ONLY);
-	/* Set up the descriptor and give ownership to the card */
-	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
-		                                       SETUP_FRAME_LEN, (struct sk_buff *)1);
-	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
-	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
-	netif_wake_queue(dev);                      /* Unlock the TX ring */
-	break;
-
-    case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	omr = inl(DE4X5_OMR);
-	omr |= OMR_PR;
-	outl(omr, DE4X5_OMR);
-	dev->flags |= IFF_PROMISC;
-	break;
-
-    case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	omr = inl(DE4X5_OMR);
-	omr &= ~OMR_PR;
-	outl(omr, DE4X5_OMR);
-	dev->flags &= ~IFF_PROMISC;
-	break;
-
-    case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	printk("%s: Boo!\n", dev->name);
-	break;
-
-    case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	omr = inl(DE4X5_OMR);
-	omr |= OMR_PM;
-	outl(omr, DE4X5_OMR);
-	break;
-
-    case DE4X5_GET_STATS:            /* Get the driver statistics */
-    {
-        struct pkt_stats statbuf;
-	ioc->len = sizeof(statbuf);
-	spin_lock_irqsave(&lp->lock, flags);
-	memcpy(&statbuf, &lp->pktStats, ioc->len);
-	spin_unlock_irqrestore(&lp->lock, flags);
-	if (copy_to_user(ioc->data, &statbuf, ioc->len)) 
-		return -EFAULT; 
-	break;
-    }
-    case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	spin_lock_irqsave(&lp->lock, flags);
-	memset(&lp->pktStats, 0, sizeof(lp->pktStats));
-	spin_unlock_irqrestore(&lp->lock, flags);
-	break;
-
-    case DE4X5_GET_OMR:              /* Get the OMR Register contents */
-	tmp.addr[0] = inl(DE4X5_OMR);
-	if (copy_to_user(ioc->data, tmp.addr, 1)) return -EFAULT;
-	break;
-
-    case DE4X5_SET_OMR:              /* Set the OMR Register contents */
-	if (!capable(CAP_NET_ADMIN)) return -EPERM;
-	if (copy_from_user(tmp.addr, ioc->data, 1)) return -EFAULT;
-	outl(tmp.addr[0], DE4X5_OMR);
-	break;
-
-    case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
-	j = 0;
-	tmp.lval[0] = inl(DE4X5_STS); j+=4;
-	tmp.lval[1] = inl(DE4X5_BMR); j+=4;
-	tmp.lval[2] = inl(DE4X5_IMR); j+=4;
-	tmp.lval[3] = inl(DE4X5_OMR); j+=4;
-	tmp.lval[4] = inl(DE4X5_SISR); j+=4;
-	tmp.lval[5] = inl(DE4X5_SICR); j+=4;
-	tmp.lval[6] = inl(DE4X5_STRR); j+=4;
-	tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
-	ioc->len = j;
-	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
-	break;
-	
-#define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
-/*	
-      case DE4X5_DUMP:
-	j = 0;
-	tmp.addr[j++] = dev->irq;
-	for (i=0; i<ETH_ALEN; i++) {
-	    tmp.addr[j++] = dev->dev_addr[i];
-	}
-	tmp.addr[j++] = lp->rxRingSize;
-	tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
-	tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
-	
-	for (i=0;i<lp->rxRingSize-1;i++){
-	    if (i < 3) {
-		tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
-	    }
-	}
-	tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
-	for (i=0;i<lp->txRingSize-1;i++){
-	    if (i < 3) {
-		tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-	    }
-	}
-	tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-	
-	for (i=0;i<lp->rxRingSize-1;i++){
-	    if (i < 3) {
-		tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
-	    }
-	}
-	tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
-	for (i=0;i<lp->txRingSize-1;i++){
-	    if (i < 3) {
-		tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-	    }
-	}
-	tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
-	
-	for (i=0;i<lp->rxRingSize;i++){
-	    tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
-	}
-	for (i=0;i<lp->txRingSize;i++){
-	    tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
-	}
-	
-	tmp.lval[j>>2] = inl(DE4X5_BMR);  j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_TPD);  j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_RPD);  j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_STS);  j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_OMR);  j+=4;
-	tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
-	tmp.lval[j>>2] = lp->chipset; j+=4; 
-	if (lp->chipset == DC21140) {
-	    tmp.lval[j>>2] = gep_rd(dev);  j+=4;
-	} else {
-	    tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
-	    tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
-	    tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
-	    tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
-	}
-	tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; 
-	if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
-	    tmp.lval[j>>2] = lp->active; j+=4; 
-	    tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    if (lp->phy[lp->active].id != BROADCOM_T4) {
-		tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-		tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    }
-	    tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    if (lp->phy[lp->active].id != BROADCOM_T4) {
-		tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-		tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    } else {
-		tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
-	    }
-	}
-	
-	tmp.addr[j++] = lp->txRingSize;
-	tmp.addr[j++] = netif_queue_stopped(dev);
-	
-	ioc->len = j;
-	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
-	break;
-
-*/
-    default:
-	return -EOPNOTSUPP;
-    }
-    
-    return status;
-}
-
-#ifdef MODULE
-/*
-** Note now that module autoprobing is allowed under EISA and PCI. The
-** IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
-** to "do the right thing".
-*/
-#define LP(a) ((struct de4x5_private *)(a))
-static struct net_device *mdev = NULL;
-static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
-MODULE_PARM(io, "i");
-MODULE_PARM_DESC(io, "de4x5 I/O base address");
-
-int
-init_module(void)
-{
-    int i, num, status = -EIO;
-    struct net_device *p;
-
-    num = count_adapters();
-
-    for (i=0; i<num; i++) {
-	if ((p = insert_device(NULL, io, de4x5_probe)) == NULL) 
-	    return -ENOMEM;
-
-	if (!mdev) mdev = p;
-
-	if (register_netdev(p) != 0) {
-	    struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-	    if (lp) {
-		release_region(p->base_addr, (lp->bus == PCI ? 
-					      DE4X5_PCI_TOTAL_SIZE :
-					      DE4X5_EISA_TOTAL_SIZE));
-		if (lp->cache.priv) {       /* Private area allocated?   */
-		    kfree(lp->cache.priv);  /* Free the private area     */
-		}
-		if (lp->rx_ring) {
-		    pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring,
-					lp->dma_rings);
-		}
-	    }
-	    kfree(p);
-	} else {
-	    status = 0;                 /* At least one adapter will work */
-	    lastModule = p;
-	}
-    }
-
-    return status;
-}
-
-void
-cleanup_module(void)
-{
-    while (mdev != NULL) {
-	mdev = unlink_modules(mdev);
-    }
-
-    return;
-}
-
-static struct net_device *
-unlink_modules(struct net_device *p)
-{
-    struct net_device *next = NULL;
-
-    if (p->priv) {                          /* Private areas allocated?  */
-	struct de4x5_private *lp = (struct de4x5_private *)p->priv;
-
-	next = lp->next_module;
-	if (lp->rx_ring) {
-		pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring,
-				    lp->dma_rings);
-	}
-	release_region(p->base_addr, (lp->bus == PCI ? 
-				      DE4X5_PCI_TOTAL_SIZE :
-				      DE4X5_EISA_TOTAL_SIZE));
-	kfree(lp->cache.priv);              /* Free the private area     */
-    }
-    unregister_netdev(p);
-    kfree(p);                               /* Free the device structure */
-    
-    return next;
-}
-
-static int
-count_adapters(void)
-{
-    int i, j=0;
-    u_short vendor;
-    u_int class = DE4X5_CLASS_CODE;
-    u_int device;
-
-#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-    char name[DE4X5_STRLEN];
-    u_long iobase = 0x1000;
-
-    for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
-	if (EISA_signature(name, EISA_ID)) j++;
-    }
-#endif
-    if (!pcibios_present()) return j;
-
-    for (i=0; (pdev=pci_find_class(class, pdev))!= NULL; i++) {
-	vendor = pdev->vendor;
-	device = pdev->device << 8;
-	if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
-    }
-
-    return j;
-}
-
-/*
-** If at end of eth device list and can't use current entry, malloc
-** one up. If memory could not be allocated, print an error message.
-*/
-static struct net_device * __init 
-insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *))
-{
-    struct net_device *new;
-
-    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
-    if (new == NULL) {
-	printk("de4x5.c: Device not initialised, insufficient memory\n");
-	return NULL;
-    } else {
-	memset((char *)new, 0, sizeof(struct net_device));
-	new->base_addr = iobase;       /* assign the io address */
-	new->init = init;              /* initialisation routine */
-    }
-
-    return new;
-}
-
-#endif /* MODULE */
-
-
-/*
- * Local variables:
- *
- * Delete -DMODVERSIONS below if you didn't define this in your kernel
- *
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
- * End:
- */
diff -urN linux-2.5.6-pre3/drivers/net/de4x5.h linux-2.5.6/drivers/net/de4x5.h
--- linux-2.5.6-pre3/drivers/net/de4x5.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/de4x5.h	Wed Dec 31 16:00:00 1969
@@ -1,1031 +0,0 @@
-/*
-    Copyright 1994 Digital Equipment Corporation.
-
-    This software may be used and distributed according to  the terms of the
-    GNU General Public License, incorporated herein by reference.
-
-    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
-    Equipment Corporation, 550 King Street, Littleton MA 01460.
-
-    =========================================================================
-*/
-
-/*
-** DC21040 CSR<1..15> Register Address Map
-*/
-#define DE4X5_BMR    iobase+(0x000 << lp->bus)  /* Bus Mode Register */
-#define DE4X5_TPD    iobase+(0x008 << lp->bus)  /* Transmit Poll Demand Reg */
-#define DE4X5_RPD    iobase+(0x010 << lp->bus)  /* Receive Poll Demand Reg */
-#define DE4X5_RRBA   iobase+(0x018 << lp->bus)  /* RX Ring Base Address Reg */
-#define DE4X5_TRBA   iobase+(0x020 << lp->bus)  /* TX Ring Base Address Reg */
-#define DE4X5_STS    iobase+(0x028 << lp->bus)  /* Status Register */
-#define DE4X5_OMR    iobase+(0x030 << lp->bus)  /* Operation Mode Register */
-#define DE4X5_IMR    iobase+(0x038 << lp->bus)  /* Interrupt Mask Register */
-#define DE4X5_MFC    iobase+(0x040 << lp->bus)  /* Missed Frame Counter */
-#define DE4X5_APROM  iobase+(0x048 << lp->bus)  /* Ethernet Address PROM */
-#define DE4X5_BROM   iobase+(0x048 << lp->bus)  /* Boot ROM Register */
-#define DE4X5_SROM   iobase+(0x048 << lp->bus)  /* Serial ROM Register */
-#define DE4X5_MII    iobase+(0x048 << lp->bus)  /* MII Interface Register */
-#define DE4X5_DDR    iobase+(0x050 << lp->bus)  /* Data Diagnostic Register */
-#define DE4X5_FDR    iobase+(0x058 << lp->bus)  /* Full Duplex Register */
-#define DE4X5_GPT    iobase+(0x058 << lp->bus)  /* General Purpose Timer Reg.*/
-#define DE4X5_GEP    iobase+(0x060 << lp->bus)  /* General Purpose Register */
-#define DE4X5_SISR   iobase+(0x060 << lp->bus)  /* SIA Status Register */
-#define DE4X5_SICR   iobase+(0x068 << lp->bus)  /* SIA Connectivity Register */
-#define DE4X5_STRR   iobase+(0x070 << lp->bus)  /* SIA TX/RX Register */
-#define DE4X5_SIGR   iobase+(0x078 << lp->bus)  /* SIA General Register */
-
-/*
-** EISA Register Address Map
-*/
-#define EISA_ID      iobase+0x0c80   /* EISA ID Registers */ 
-#define EISA_ID0     iobase+0x0c80   /* EISA ID Register 0 */ 
-#define EISA_ID1     iobase+0x0c81   /* EISA ID Register 1 */ 
-#define EISA_ID2     iobase+0x0c82   /* EISA ID Register 2 */ 
-#define EISA_ID3     iobase+0x0c83   /* EISA ID Register 3 */ 
-#define EISA_CR      iobase+0x0c84   /* EISA Control Register */
-#define EISA_REG0    iobase+0x0c88   /* EISA Configuration Register 0 */
-#define EISA_REG1    iobase+0x0c89   /* EISA Configuration Register 1 */
-#define EISA_REG2    iobase+0x0c8a   /* EISA Configuration Register 2 */
-#define EISA_REG3    iobase+0x0c8f   /* EISA Configuration Register 3 */
-#define EISA_APROM   iobase+0x0c90   /* Ethernet Address PROM */
-
-/*
-** PCI/EISA Configuration Registers Address Map
-*/
-#define PCI_CFID     iobase+0x0008   /* PCI Configuration ID Register */
-#define PCI_CFCS     iobase+0x000c   /* PCI Command/Status Register */
-#define PCI_CFRV     iobase+0x0018   /* PCI Revision Register */
-#define PCI_CFLT     iobase+0x001c   /* PCI Latency Timer Register */
-#define PCI_CBIO     iobase+0x0028   /* PCI Base I/O Register */
-#define PCI_CBMA     iobase+0x002c   /* PCI Base Memory Address Register */
-#define PCI_CBER     iobase+0x0030   /* PCI Expansion ROM Base Address Reg. */
-#define PCI_CFIT     iobase+0x003c   /* PCI Configuration Interrupt Register */
-#define PCI_CFDA     iobase+0x0040   /* PCI Driver Area Register */
-#define PCI_CFDD     iobase+0x0041   /* PCI Driver Dependent Area Register */
-#define PCI_CFPM     iobase+0x0043   /* PCI Power Management Area Register */
-
-/*
-** EISA Configuration Register 0 bit definitions
-*/
-#define ER0_BSW       0x80           /* EISA Bus Slave Width, 1: 32 bits */
-#define ER0_BMW       0x40           /* EISA Bus Master Width, 1: 32 bits */
-#define ER0_EPT       0x20           /* EISA PREEMPT Time, 0: 23 BCLKs */
-#define ER0_ISTS      0x10           /* Interrupt Status (X) */
-#define ER0_LI        0x08           /* Latch Interrupts */
-#define ER0_INTL      0x06           /* INTerrupt Level */
-#define ER0_INTT      0x01           /* INTerrupt Type, 0: Level, 1: Edge */
-
-/*
-** EISA Configuration Register 1 bit definitions
-*/
-#define ER1_IAM       0xe0           /* ISA Address Mode */
-#define ER1_IAE       0x10           /* ISA Addressing Enable */
-#define ER1_UPIN      0x0f           /* User Pins */
-
-/*
-** EISA Configuration Register 2 bit definitions
-*/
-#define ER2_BRS       0xc0           /* Boot ROM Size */
-#define ER2_BRA       0x3c           /* Boot ROM Address <16:13> */
-
-/*
-** EISA Configuration Register 3 bit definitions
-*/
-#define ER3_BWE       0x40           /* Burst Write Enable */
-#define ER3_BRE       0x04           /* Burst Read Enable */
-#define ER3_LSR       0x02           /* Local Software Reset */
-
-/*
-** PCI Configuration ID Register (PCI_CFID). The Device IDs are left
-** shifted 8 bits to allow detection of DC21142 and DC21143 variants with
-** the configuration revision register step number.
-*/
-#define CFID_DID    0xff00           /* Device ID */
-#define CFID_VID    0x00ff           /* Vendor ID */
-#define DC21040_DID 0x0200           /* Unique Device ID # */
-#define DC21040_VID 0x1011           /* DC21040 Manufacturer */
-#define DC21041_DID 0x1400           /* Unique Device ID # */
-#define DC21041_VID 0x1011           /* DC21041 Manufacturer */
-#define DC21140_DID 0x0900           /* Unique Device ID # */
-#define DC21140_VID 0x1011           /* DC21140 Manufacturer */
-#define DC2114x_DID 0x1900           /* Unique Device ID # */
-#define DC2114x_VID 0x1011           /* DC2114[23] Manufacturer */
-
-/*
-** Chipset defines
-*/
-#define DC21040     DC21040_DID
-#define DC21041     DC21041_DID
-#define DC21140     DC21140_DID
-#define DC2114x     DC2114x_DID
-#define DC21142     (DC2114x_DID | 0x0010)
-#define DC21143     (DC2114x_DID | 0x0030)
-#define DC2114x_BRK 0x0020           /* CFRV break between DC21142 & DC21143 */
-
-#define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
-#define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
-#define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
-#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID))
-#define is_DC21142 ((vendor == DC2114x_VID) && (device == DC21142))
-#define is_DC21143 ((vendor == DC2114x_VID) && (device == DC21143))
-
-/*
-** PCI Configuration Command/Status Register (PCI_CFCS)
-*/
-#define CFCS_DPE    0x80000000       /* Detected Parity Error (S) */
-#define CFCS_SSE    0x40000000       /* Signal System Error   (S) */
-#define CFCS_RMA    0x20000000       /* Receive Master Abort  (S) */
-#define CFCS_RTA    0x10000000       /* Receive Target Abort  (S) */
-#define CFCS_DST    0x06000000       /* DEVSEL Timing         (S) */
-#define CFCS_DPR    0x01000000       /* Data Parity Report    (S) */
-#define CFCS_FBB    0x00800000       /* Fast Back-To-Back     (S) */
-#define CFCS_SEE    0x00000100       /* System Error Enable   (C) */
-#define CFCS_PER    0x00000040       /* Parity Error Response (C) */
-#define CFCS_MO     0x00000004       /* Master Operation      (C) */
-#define CFCS_MSA    0x00000002       /* Memory Space Access   (C) */
-#define CFCS_IOSA   0x00000001       /* I/O Space Access      (C) */
-
-/*
-** PCI Configuration Revision Register (PCI_CFRV)
-*/
-#define CFRV_BC     0xff000000       /* Base Class */
-#define CFRV_SC     0x00ff0000       /* Subclass */
-#define CFRV_RN     0x000000f0       /* Revision Number */
-#define CFRV_SN     0x0000000f       /* Step Number */
-#define BASE_CLASS  0x02000000       /* Indicates Network Controller */
-#define SUB_CLASS   0x00000000       /* Indicates Ethernet Controller */
-#define STEP_NUMBER 0x00000020       /* Increments for future chips */
-#define REV_NUMBER  0x00000003       /* 0x00, 0x01, 0x02, 0x03: Rev in Step */
-#define CFRV_MASK   0xffff0000       /* Register mask */
-
-/*
-** PCI Configuration Latency Timer Register (PCI_CFLT)
-*/
-#define CFLT_BC     0x0000ff00       /* Latency Timer bits */
-
-/*
-** PCI Configuration Base I/O Address Register (PCI_CBIO)
-*/
-#define CBIO_MASK   -128             /* Base I/O Address Mask */
-#define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
-
-/*
-** PCI Configuration Card Information Structure Register (PCI_CCIS)
-*/
-#define CCIS_ROMI   0xf0000000       /* ROM Image */
-#define CCIS_ASO    0x0ffffff8       /* Address Space Offset */
-#define CCIS_ASI    0x00000007       /* Address Space Indicator */
-
-/*
-** PCI Configuration Subsystem ID Register (PCI_SSID)
-*/
-#define SSID_SSID   0xffff0000       /* Subsystem ID */
-#define SSID_SVID   0x0000ffff       /* Subsystem Vendor ID */
-
-/*
-** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
-*/
-#define CBER_MASK   0xfffffc00       /* Expansion ROM Base Address Mask */
-#define CBER_ROME   0x00000001       /* ROM Enable */
-
-/*
-** PCI Configuration Interrupt Register (PCI_CFIT)
-*/
-#define CFIT_MXLT   0xff000000       /* MAX_LAT Value (0.25us periods) */
-#define CFIT_MNGT   0x00ff0000       /* MIN_GNT Value (0.25us periods) */
-#define CFIT_IRQP   0x0000ff00       /* Interrupt Pin */
-#define CFIT_IRQL   0x000000ff       /* Interrupt Line */
-
-/*
-** PCI Configuration Power Management Area Register (PCI_CFPM)
-*/
-#define SLEEP       0x80             /* Power Saving Sleep Mode */
-#define SNOOZE      0x40             /* Power Saving Snooze Mode */
-#define WAKEUP      0x00             /* Power Saving Wakeup */
-
-#define PCI_CFDA_DSU 0x41            /* 8 bit Configuration Space Address */
-#define PCI_CFDA_PSM 0x43            /* 8 bit Configuration Space Address */
-
-/*
-** DC21040 Bus Mode Register (DE4X5_BMR)
-*/
-#define BMR_RML    0x00200000       /* [Memory] Read Multiple */
-#define BMR_DBO    0x00100000       /* Descriptor Byte Ordering (Endian) */
-#define BMR_TAP    0x000e0000       /* Transmit Automatic Polling */
-#define BMR_DAS    0x00010000       /* Diagnostic Address Space */
-#define BMR_CAL    0x0000c000       /* Cache Alignment */
-#define BMR_PBL    0x00003f00       /* Programmable Burst Length */
-#define BMR_BLE    0x00000080       /* Big/Little Endian */
-#define BMR_DSL    0x0000007c       /* Descriptor Skip Length */
-#define BMR_BAR    0x00000002       /* Bus ARbitration */
-#define BMR_SWR    0x00000001       /* Software Reset */
-
-                                    /* Timings here are for 10BASE-T/AUI only*/
-#define TAP_NOPOLL 0x00000000       /* No automatic polling */
-#define TAP_200US  0x00020000       /* TX automatic polling every 200us */
-#define TAP_800US  0x00040000       /* TX automatic polling every 800us */
-#define TAP_1_6MS  0x00060000       /* TX automatic polling every 1.6ms */
-#define TAP_12_8US 0x00080000       /* TX automatic polling every 12.8us */
-#define TAP_25_6US 0x000a0000       /* TX automatic polling every 25.6us */
-#define TAP_51_2US 0x000c0000       /* TX automatic polling every 51.2us */
-#define TAP_102_4US 0x000e0000      /* TX automatic polling every 102.4us */
-
-#define CAL_NOUSE  0x00000000       /* Not used */
-#define CAL_8LONG  0x00004000       /* 8-longword alignment */
-#define CAL_16LONG 0x00008000       /* 16-longword alignment */
-#define CAL_32LONG 0x0000c000       /* 32-longword alignment */
-
-#define PBL_0      0x00000000       /*  DMA burst length = amount in RX FIFO */
-#define PBL_1      0x00000100       /*  1 longword  DMA burst length */
-#define PBL_2      0x00000200       /*  2 longwords DMA burst length */
-#define PBL_4      0x00000400       /*  4 longwords DMA burst length */
-#define PBL_8      0x00000800       /*  8 longwords DMA burst length */
-#define PBL_16     0x00001000       /* 16 longwords DMA burst length */
-#define PBL_32     0x00002000       /* 32 longwords DMA burst length */
-
-#define DSL_0      0x00000000       /*  0 longword  / descriptor */
-#define DSL_1      0x00000004       /*  1 longword  / descriptor */
-#define DSL_2      0x00000008       /*  2 longwords / descriptor */
-#define DSL_4      0x00000010       /*  4 longwords / descriptor */
-#define DSL_8      0x00000020       /*  8 longwords / descriptor */
-#define DSL_16     0x00000040       /* 16 longwords / descriptor */
-#define DSL_32     0x00000080       /* 32 longwords / descriptor */
-
-/*
-** DC21040 Transmit Poll Demand Register (DE4X5_TPD)
-*/
-#define TPD        0x00000001       /* Transmit Poll Demand */
-
-/*
-** DC21040 Receive Poll Demand Register (DE4X5_RPD)
-*/
-#define RPD        0x00000001       /* Receive Poll Demand */
-
-/*
-** DC21040 Receive Ring Base Address Register (DE4X5_RRBA)
-*/
-#define RRBA       0xfffffffc       /* RX Descriptor List Start Address */
-
-/*
-** DC21040 Transmit Ring Base Address Register (DE4X5_TRBA)
-*/
-#define TRBA       0xfffffffc       /* TX Descriptor List Start Address */
-
-/*
-** Status Register (DE4X5_STS)
-*/
-#define STS_GPI    0x04000000       /* General Purpose Port Interrupt */
-#define STS_BE     0x03800000       /* Bus Error Bits */
-#define STS_TS     0x00700000       /* Transmit Process State */
-#define STS_RS     0x000e0000       /* Receive Process State */
-#define STS_NIS    0x00010000       /* Normal Interrupt Summary */
-#define STS_AIS    0x00008000       /* Abnormal Interrupt Summary */
-#define STS_ER     0x00004000       /* Early Receive */
-#define STS_FBE    0x00002000       /* Fatal Bus Error */
-#define STS_SE     0x00002000       /* System Error */
-#define STS_LNF    0x00001000       /* Link Fail */
-#define STS_FD     0x00000800       /* Full-Duplex Short Frame Received */
-#define STS_TM     0x00000800       /* Timer Expired (DC21041) */
-#define STS_ETI    0x00000400       /* Early Transmit Interrupt */
-#define STS_AT     0x00000400       /* AUI/TP Pin */
-#define STS_RWT    0x00000200       /* Receive Watchdog Time-Out */
-#define STS_RPS    0x00000100       /* Receive Process Stopped */
-#define STS_RU     0x00000080       /* Receive Buffer Unavailable */
-#define STS_RI     0x00000040       /* Receive Interrupt */
-#define STS_UNF    0x00000020       /* Transmit Underflow */
-#define STS_LNP    0x00000010       /* Link Pass */
-#define STS_ANC    0x00000010       /* Autonegotiation Complete */
-#define STS_TJT    0x00000008       /* Transmit Jabber Time-Out */
-#define STS_TU     0x00000004       /* Transmit Buffer Unavailable */
-#define STS_TPS    0x00000002       /* Transmit Process Stopped */
-#define STS_TI     0x00000001       /* Transmit Interrupt */
-
-#define EB_PAR     0x00000000       /* Parity Error */
-#define EB_MA      0x00800000       /* Master Abort */
-#define EB_TA      0x01000000       /* Target Abort */
-#define EB_RES0    0x01800000       /* Reserved */
-#define EB_RES1    0x02000000       /* Reserved */
-
-#define TS_STOP    0x00000000       /* Stopped */
-#define TS_FTD     0x00100000       /* Fetch Transmit Descriptor */
-#define TS_WEOT    0x00200000       /* Wait for End Of Transmission */
-#define TS_QDAT    0x00300000       /* Queue skb data into TX FIFO */
-#define TS_RES     0x00400000       /* Reserved */
-#define TS_SPKT    0x00500000       /* Setup Packet */
-#define TS_SUSP    0x00600000       /* Suspended */
-#define TS_CLTD    0x00700000       /* Close Transmit Descriptor */
-
-#define RS_STOP    0x00000000       /* Stopped */
-#define RS_FRD     0x00020000       /* Fetch Receive Descriptor */
-#define RS_CEOR    0x00040000       /* Check for End of Receive Packet */
-#define RS_WFRP    0x00060000       /* Wait for Receive Packet */
-#define RS_SUSP    0x00080000       /* Suspended */
-#define RS_CLRD    0x000a0000       /* Close Receive Descriptor */
-#define RS_FLUSH   0x000c0000       /* Flush RX FIFO */
-#define RS_QRFS    0x000e0000       /* Queue RX FIFO into RX Skb */
-
-#define INT_CANCEL 0x0001ffff       /* For zeroing all interrupt sources */
-
-/*
-** Operation Mode Register (DE4X5_OMR)
-*/
-#define OMR_SC     0x80000000       /* Special Capture Effect Enable */
-#define OMR_RA     0x40000000       /* Receive All */
-#define OMR_SDP    0x02000000       /* SD Polarity - MUST BE ASSERTED */
-#define OMR_SCR    0x01000000       /* Scrambler Mode */
-#define OMR_PCS    0x00800000       /* PCS Function */
-#define OMR_TTM    0x00400000       /* Transmit Threshold Mode */
-#define OMR_SF     0x00200000       /* Store and Forward */
-#define OMR_HBD    0x00080000       /* HeartBeat Disable */
-#define OMR_PS     0x00040000       /* Port Select */
-#define OMR_CA     0x00020000       /* Capture Effect Enable */
-#define OMR_BP     0x00010000       /* Back Pressure */
-#define OMR_TR     0x0000c000       /* Threshold Control Bits */
-#define OMR_ST     0x00002000       /* Start/Stop Transmission Command */
-#define OMR_FC     0x00001000       /* Force Collision Mode */
-#define OMR_OM     0x00000c00       /* Operating Mode */
-#define OMR_FDX    0x00000200       /* Full Duplex Mode */
-#define OMR_FKD    0x00000100       /* Flaky Oscillator Disable */
-#define OMR_PM     0x00000080       /* Pass All Multicast */
-#define OMR_PR     0x00000040       /* Promiscuous Mode */
-#define OMR_SB     0x00000020       /* Start/Stop Backoff Counter */
-#define OMR_IF     0x00000010       /* Inverse Filtering */
-#define OMR_PB     0x00000008       /* Pass Bad Frames */
-#define OMR_HO     0x00000004       /* Hash Only Filtering Mode */
-#define OMR_SR     0x00000002       /* Start/Stop Receive */
-#define OMR_HP     0x00000001       /* Hash/Perfect Receive Filtering Mode */
-
-#define TR_72      0x00000000       /* Threshold set to 72 (128) bytes */
-#define TR_96      0x00004000       /* Threshold set to 96 (256) bytes */
-#define TR_128     0x00008000       /* Threshold set to 128 (512) bytes */
-#define TR_160     0x0000c000       /* Threshold set to 160 (1024) bytes */
-
-#define OMR_DEF     (OMR_SDP)
-#define OMR_SIA     (OMR_SDP | OMR_TTM)
-#define OMR_SYM     (OMR_SDP | OMR_SCR | OMR_PCS | OMR_HBD | OMR_PS)
-#define OMR_MII_10  (OMR_SDP | OMR_TTM | OMR_PS)
-#define OMR_MII_100 (OMR_SDP | OMR_HBD | OMR_PS)
-
-/*
-** DC21040 Interrupt Mask Register (DE4X5_IMR)
-*/
-#define IMR_GPM    0x04000000       /* General Purpose Port Mask */
-#define IMR_NIM    0x00010000       /* Normal Interrupt Summary Mask */
-#define IMR_AIM    0x00008000       /* Abnormal Interrupt Summary Mask */
-#define IMR_ERM    0x00004000       /* Early Receive Mask */
-#define IMR_FBM    0x00002000       /* Fatal Bus Error Mask */
-#define IMR_SEM    0x00002000       /* System Error Mask */
-#define IMR_LFM    0x00001000       /* Link Fail Mask */
-#define IMR_FDM    0x00000800       /* Full-Duplex (Short Frame) Mask */
-#define IMR_TMM    0x00000800       /* Timer Expired Mask (DC21041) */
-#define IMR_ETM    0x00000400       /* Early Transmit Interrupt Mask */
-#define IMR_ATM    0x00000400       /* AUI/TP Switch Mask */
-#define IMR_RWM    0x00000200       /* Receive Watchdog Time-Out Mask */
-#define IMR_RSM    0x00000100       /* Receive Stopped Mask */
-#define IMR_RUM    0x00000080       /* Receive Buffer Unavailable Mask */
-#define IMR_RIM    0x00000040       /* Receive Interrupt Mask */
-#define IMR_UNM    0x00000020       /* Underflow Interrupt Mask */
-#define IMR_ANM    0x00000010       /* Autonegotiation Complete Mask */
-#define IMR_LPM    0x00000010       /* Link Pass */
-#define IMR_TJM    0x00000008       /* Transmit Time-Out Jabber Mask */
-#define IMR_TUM    0x00000004       /* Transmit Buffer Unavailable Mask */
-#define IMR_TSM    0x00000002       /* Transmission Stopped Mask */
-#define IMR_TIM    0x00000001       /* Transmit Interrupt Mask */
-
-/*
-** Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
-*/
-#define MFC_FOCO   0x10000000       /* FIFO Overflow Counter Overflow Bit */
-#define MFC_FOC    0x0ffe0000       /* FIFO Overflow Counter Bits */
-#define MFC_OVFL   0x00010000       /* Missed Frames Counter Overflow Bit */
-#define MFC_CNTR   0x0000ffff       /* Missed Frames Counter Bits */
-#define MFC_FOCM   0x1ffe0000       /* FIFO Overflow Counter Mask */
-
-/*
-** DC21040 Ethernet Address PROM (DE4X5_APROM)
-*/
-#define APROM_DN   0x80000000       /* Data Not Valid */
-#define APROM_DT   0x000000ff       /* Address Byte */
-
-/*
-** DC21041 Boot/Ethernet Address ROM (DE4X5_BROM)
-*/
-#define BROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
-#define BROM_RD   0x00004000       /* Read from Boot ROM */
-#define BROM_WR   0x00002000       /* Write to Boot ROM */
-#define BROM_BR   0x00001000       /* Select Boot ROM when set */
-#define BROM_SR   0x00000800       /* Select Serial ROM when set */
-#define BROM_REG  0x00000400       /* External Register Select */
-#define BROM_DT   0x000000ff       /* Data Byte */
-
-/*
-** DC21041 Serial/Ethernet Address ROM (DE4X5_SROM, DE4X5_MII)
-*/
-#define MII_MDI   0x00080000       /* MII Management Data In */
-#define MII_MDO   0x00060000       /* MII Management Mode/Data Out */
-#define MII_MRD   0x00040000       /* MII Management Define Read Mode */
-#define MII_MWR   0x00000000       /* MII Management Define Write Mode */
-#define MII_MDT   0x00020000       /* MII Management Data Out */
-#define MII_MDC   0x00010000       /* MII Management Clock */
-#define MII_RD    0x00004000       /* Read from MII */
-#define MII_WR    0x00002000       /* Write to MII */
-#define MII_SEL   0x00000800       /* Select MII when RESET */
-
-#define SROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
-#define SROM_RD   0x00004000       /* Read from Boot ROM */
-#define SROM_WR   0x00002000       /* Write to Boot ROM */
-#define SROM_BR   0x00001000       /* Select Boot ROM when set */
-#define SROM_SR   0x00000800       /* Select Serial ROM when set */
-#define SROM_REG  0x00000400       /* External Register Select */
-#define SROM_DT   0x000000ff       /* Data Byte */
-
-#define DT_OUT    0x00000008       /* Serial Data Out */
-#define DT_IN     0x00000004       /* Serial Data In */
-#define DT_CLK    0x00000002       /* Serial ROM Clock */
-#define DT_CS     0x00000001       /* Serial ROM Chip Select */
-
-#define MII_PREAMBLE 0xffffffff    /* MII Management Preamble */
-#define MII_TEST     0xaaaaaaaa    /* MII Test Signal */
-#define MII_STRD     0x06          /* Start of Frame+Op Code: use low nibble */
-#define MII_STWR     0x0a          /* Start of Frame+Op Code: use low nibble */
-
-#define MII_CR       0x00          /* MII Management Control Register */
-#define MII_SR       0x01          /* MII Management Status Register */
-#define MII_ID0      0x02          /* PHY Identifier Register 0 */
-#define MII_ID1      0x03          /* PHY Identifier Register 1 */
-#define MII_ANA      0x04          /* Auto Negotiation Advertisement */
-#define MII_ANLPA    0x05          /* Auto Negotiation Link Partner Ability */
-#define MII_ANE      0x06          /* Auto Negotiation Expansion */
-#define MII_ANP      0x07          /* Auto Negotiation Next Page TX */
-
-#define DE4X5_MAX_MII 32           /* Maximum address of MII PHY devices */
-
-/*
-** MII Management Control Register
-*/
-#define MII_CR_RST  0x8000         /* RESET the PHY chip */
-#define MII_CR_LPBK 0x4000         /* Loopback enable */
-#define MII_CR_SPD  0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
-#define MII_CR_10   0x0000         /* Set 10Mb/s */
-#define MII_CR_100  0x2000         /* Set 100Mb/s */
-#define MII_CR_ASSE 0x1000         /* Auto Speed Select Enable */
-#define MII_CR_PD   0x0800         /* Power Down */
-#define MII_CR_ISOL 0x0400         /* Isolate Mode */
-#define MII_CR_RAN  0x0200         /* Restart Auto Negotiation */
-#define MII_CR_FDM  0x0100         /* Full Duplex Mode */
-#define MII_CR_CTE  0x0080         /* Collision Test Enable */
-
-/*
-** MII Management Status Register
-*/
-#define MII_SR_T4C  0x8000         /* 100BASE-T4 capable */
-#define MII_SR_TXFD 0x4000         /* 100BASE-TX Full Duplex capable */
-#define MII_SR_TXHD 0x2000         /* 100BASE-TX Half Duplex capable */
-#define MII_SR_TFD  0x1000         /* 10BASE-T Full Duplex capable */
-#define MII_SR_THD  0x0800         /* 10BASE-T Half Duplex capable */
-#define MII_SR_ASSC 0x0020         /* Auto Speed Selection Complete*/
-#define MII_SR_RFD  0x0010         /* Remote Fault Detected */
-#define MII_SR_ANC  0x0008         /* Auto Negotiation capable */
-#define MII_SR_LKS  0x0004         /* Link Status */
-#define MII_SR_JABD 0x0002         /* Jabber Detect */
-#define MII_SR_XC   0x0001         /* Extended Capabilities */
-
-/*
-** MII Management Auto Negotiation Advertisement Register
-*/
-#define MII_ANA_TAF  0x03e0        /* Technology Ability Field */
-#define MII_ANA_T4AM 0x0200        /* T4 Technology Ability Mask */
-#define MII_ANA_TXAM 0x0180        /* TX Technology Ability Mask */
-#define MII_ANA_FDAM 0x0140        /* Full Duplex Technology Ability Mask */
-#define MII_ANA_HDAM 0x02a0        /* Half Duplex Technology Ability Mask */
-#define MII_ANA_100M 0x0380        /* 100Mb Technology Ability Mask */
-#define MII_ANA_10M  0x0060        /* 10Mb Technology Ability Mask */
-#define MII_ANA_CSMA 0x0001        /* CSMA-CD Capable */
-
-/*
-** MII Management Auto Negotiation Remote End Register
-*/
-#define MII_ANLPA_NP   0x8000      /* Next Page (Enable) */
-#define MII_ANLPA_ACK  0x4000      /* Remote Acknowledge */
-#define MII_ANLPA_RF   0x2000      /* Remote Fault */
-#define MII_ANLPA_TAF  0x03e0      /* Technology Ability Field */
-#define MII_ANLPA_T4AM 0x0200      /* T4 Technology Ability Mask */
-#define MII_ANLPA_TXAM 0x0180      /* TX Technology Ability Mask */
-#define MII_ANLPA_FDAM 0x0140      /* Full Duplex Technology Ability Mask */
-#define MII_ANLPA_HDAM 0x02a0      /* Half Duplex Technology Ability Mask */
-#define MII_ANLPA_100M 0x0380      /* 100Mb Technology Ability Mask */
-#define MII_ANLPA_10M  0x0060      /* 10Mb Technology Ability Mask */
-#define MII_ANLPA_CSMA 0x0001      /* CSMA-CD Capable */
-
-/*
-** SROM Media Definitions (ABG SROM Section)
-*/
-#define MEDIA_NWAY     0x0080      /* Nway (Auto Negotiation) on PHY */
-#define MEDIA_MII      0x0040      /* MII Present on the adapter */
-#define MEDIA_FIBRE    0x0008      /* Fibre Media present */
-#define MEDIA_AUI      0x0004      /* AUI Media present */
-#define MEDIA_TP       0x0002      /* TP Media present */
-#define MEDIA_BNC      0x0001      /* BNC Media present */
-
-/*
-** SROM Definitions (Digital Semiconductor Format)
-*/
-#define SROM_SSVID     0x0000      /* Sub-system Vendor ID offset */
-#define SROM_SSID      0x0002      /* Sub-system ID offset */
-#define SROM_CISPL     0x0004      /* CardBus CIS Pointer low offset */
-#define SROM_CISPH     0x0006      /* CardBus CIS Pointer high offset */
-#define SROM_IDCRC     0x0010      /* ID Block CRC offset*/
-#define SROM_RSVD2     0x0011      /* ID Reserved 2 offset */
-#define SROM_SFV       0x0012      /* SROM Format Version offset */
-#define SROM_CCNT      0x0013      /* Controller Count offset */
-#define SROM_HWADD     0x0014      /* Hardware Address offset */
-#define SROM_MRSVD     0x007c      /* Manufacturer Reserved offset*/
-#define SROM_CRC       0x007e      /* SROM CRC offset */
-
-/*
-** SROM Media Connection Definitions
-*/
-#define SROM_10BT      0x0000      /*  10BASE-T half duplex */
-#define SROM_10BTN     0x0100      /*  10BASE-T with Nway */
-#define SROM_10BTF     0x0204      /*  10BASE-T full duplex */
-#define SROM_10BTNLP   0x0400      /*  10BASE-T without Link Pass test */
-#define SROM_10B2      0x0001      /*  10BASE-2 (BNC) */
-#define SROM_10B5      0x0002      /*  10BASE-5 (AUI) */
-#define SROM_100BTH    0x0003      /*  100BASE-T half duplex */
-#define SROM_100BTF    0x0205      /*  100BASE-T full duplex */
-#define SROM_100BT4    0x0006      /*  100BASE-T4 */
-#define SROM_100BFX    0x0007      /*  100BASE-FX half duplex (Fiber) */
-#define SROM_M10BT     0x0009      /*  MII 10BASE-T half duplex */
-#define SROM_M10BTF    0x020a      /*  MII 10BASE-T full duplex */
-#define SROM_M100BT    0x000d      /*  MII 100BASE-T half duplex */
-#define SROM_M100BTF   0x020e      /*  MII 100BASE-T full duplex */
-#define SROM_M100BT4   0x000f      /*  MII 100BASE-T4 */
-#define SROM_M100BF    0x0010      /*  MII 100BASE-FX half duplex */
-#define SROM_M100BFF   0x0211      /*  MII 100BASE-FX full duplex */
-#define SROM_PDA       0x0800      /*  Powerup & Dynamic Autosense */
-#define SROM_PAO       0x8800      /*  Powerup Autosense Only */
-#define SROM_NSMI      0xffff      /*  No Selected Media Information */
-
-/*
-** SROM Media Definitions
-*/
-#define SROM_10BASET   0x0000      /*  10BASE-T half duplex */
-#define SROM_10BASE2   0x0001      /*  10BASE-2 (BNC) */
-#define SROM_10BASE5   0x0002      /*  10BASE-5 (AUI) */
-#define SROM_100BASET  0x0003      /*  100BASE-T half duplex */
-#define SROM_10BASETF  0x0004      /*  10BASE-T full duplex */
-#define SROM_100BASETF 0x0005      /*  100BASE-T full duplex */
-#define SROM_100BASET4 0x0006      /*  100BASE-T4 */
-#define SROM_100BASEF  0x0007      /*  100BASE-FX half duplex */
-#define SROM_100BASEFF 0x0008      /*  100BASE-FX full duplex */
-
-#define BLOCK_LEN      0x7f        /* Extended blocks length mask */
-#define EXT_FIELD      0x40        /* Extended blocks extension field bit */
-#define MEDIA_CODE     0x3f        /* Extended blocks media code mask */
-
-/*
-** SROM Compact Format Block Masks
-*/
-#define COMPACT_FI      0x80       /* Format Indicator */
-#define COMPACT_LEN     0x04       /* Length */
-#define COMPACT_MC      0x3f       /* Media Code */
-
-/*
-** SROM Extended Format Block Type 0 Masks
-*/
-#define BLOCK0_FI      0x80        /* Format Indicator */
-#define BLOCK0_MCS     0x80        /* Media Code byte Sign */
-#define BLOCK0_MC      0x3f        /* Media Code */
-
-/*
-** DC21040 Full Duplex Register (DE4X5_FDR)
-*/
-#define FDR_FDACV  0x0000ffff      /* Full Duplex Auto Configuration Value */
-
-/*
-** DC21041 General Purpose Timer Register (DE4X5_GPT)
-*/
-#define GPT_CON  0x00010000        /* One shot: 0,  Continuous: 1 */
-#define GPT_VAL  0x0000ffff        /* Timer Value */
-
-/*
-** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
-*/
-/* Valid ONLY for DE500 hardware */
-#define GEP_LNP  0x00000080        /* Link Pass               (input)        */
-#define GEP_SLNK 0x00000040        /* SYM LINK                (input)        */
-#define GEP_SDET 0x00000020        /* Signal Detect           (input)        */
-#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output)       */
-#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output)       */
-#define GEP_PHYL 0x00000004        /* PHY Loopback            (output)       */
-#define GEP_FLED 0x00000002        /* Force Activity LED on   (output)       */
-#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s                 */
-#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1)       */
-#define GEP_CTRL 0x00000100        /* GEP control bit                        */
-
-/*
-** SIA Register Defaults
-*/
-#define CSR13 0x00000001
-#define CSR14 0x0003ff7f           /* Autonegotiation disabled               */
-#define CSR15 0x00000008
-
-/*
-** SIA Status Register (DE4X5_SISR)
-*/
-#define SISR_LPC   0xffff0000      /* Link Partner's Code Word               */
-#define SISR_LPN   0x00008000      /* Link Partner Negotiable                */
-#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State     */
-#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041)     */
-#define SISR_TRF   0x00000800      /* Transmit Remote Fault                  */
-#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142)     */
-#define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
-#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity         */
-#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity     */
-#define SISR_ARA   0x00000100      /* AUI Receive Port Activity              */
-#define SISR_SRA   0x00000100      /* Selected Port Receive Activity         */
-#define SISR_DAO   0x00000080      /* PLL All One                            */
-#define SISR_DAZ   0x00000040      /* PLL All Zero                           */
-#define SISR_DSP   0x00000020      /* PLL Self-Test Pass                     */
-#define SISR_DSD   0x00000010      /* PLL Self-Test Done                     */
-#define SISR_APS   0x00000008      /* Auto Polarity State                    */
-#define SISR_LKF   0x00000004      /* Link Fail Status                       */
-#define SISR_LS10  0x00000004      /* 10Mb/s Link Fail Status                */
-#define SISR_NCR   0x00000002      /* Network Connection Error               */
-#define SISR_LS100 0x00000002      /* 100Mb/s Link Fail Status               */
-#define SISR_PAUI  0x00000001      /* AUI_TP Indication                      */
-#define SISR_MRA   0x00000001      /* MII Receive Port Activity              */
-
-#define ANS_NDIS   0x00000000      /* Nway disable                           */
-#define ANS_TDIS   0x00001000      /* Transmit Disable                       */
-#define ANS_ADET   0x00002000      /* Ability Detect                         */
-#define ANS_ACK    0x00003000      /* Acknowledge                            */
-#define ANS_CACK   0x00004000      /* Complete Acknowledge                   */
-#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good                */
-#define ANS_LCHK   0x00006000      /* Link Check                             */
-
-#define SISR_RST   0x00000301      /* CSR12 reset                            */
-#define SISR_ANR   0x00001301      /* Autonegotiation restart                */
-
-/*
-** SIA Connectivity Register (DE4X5_SICR)
-*/
-#define SICR_SDM   0xffff0000       /* SIA Diagnostics Mode */
-#define SICR_OE57  0x00008000       /* Output Enable 5 6 7 */
-#define SICR_OE24  0x00004000       /* Output Enable 2 4 */
-#define SICR_OE13  0x00002000       /* Output Enable 1 3 */
-#define SICR_IE    0x00001000       /* Input Enable */
-#define SICR_EXT   0x00000000       /* SIA MUX Select External SIA Mode */
-#define SICR_D_SIA 0x00000400       /* SIA MUX Select Diagnostics - SIA Sigs */
-#define SICR_DPLL  0x00000800       /* SIA MUX Select Diagnostics - DPLL Sigs*/
-#define SICR_APLL  0x00000a00       /* SIA MUX Select Diagnostics - DPLL Sigs*/
-#define SICR_D_RxM 0x00000c00       /* SIA MUX Select Diagnostics - RxM Sigs */
-#define SICR_M_RxM 0x00000d00       /* SIA MUX Select Diagnostics - RxM Sigs */
-#define SICR_LNKT  0x00000e00       /* SIA MUX Select Diagnostics - Link Test*/
-#define SICR_SEL   0x00000f00       /* SIA MUX Select AUI or TP with LEDs */
-#define SICR_ASE   0x00000080       /* APLL Start Enable*/
-#define SICR_SIM   0x00000040       /* Serial Interface Input Multiplexer */
-#define SICR_ENI   0x00000020       /* Encoder Input Multiplexer */
-#define SICR_EDP   0x00000010       /* SIA PLL External Input Enable */
-#define SICR_AUI   0x00000008       /* 10Base-T (0) or AUI (1) */
-#define SICR_CAC   0x00000004       /* CSR Auto Configuration */
-#define SICR_PS    0x00000002       /* Pin AUI/TP Selection */
-#define SICR_SRL   0x00000001       /* SIA Reset */
-#define SIA_RESET  0x00000000       /* SIA Reset Value */
-
-/*
-** SIA Transmit and Receive Register (DE4X5_STRR)
-*/
-#define STRR_TAS   0x00008000       /* 10Base-T/AUI Autosensing Enable */
-#define STRR_SPP   0x00004000       /* Set Polarity Plus */
-#define STRR_APE   0x00002000       /* Auto Polarity Enable */
-#define STRR_LTE   0x00001000       /* Link Test Enable */
-#define STRR_SQE   0x00000800       /* Signal Quality Enable */
-#define STRR_CLD   0x00000400       /* Collision Detect Enable */
-#define STRR_CSQ   0x00000200       /* Collision Squelch Enable */
-#define STRR_RSQ   0x00000100       /* Receive Squelch Enable */
-#define STRR_ANE   0x00000080       /* Auto Negotiate Enable */
-#define STRR_HDE   0x00000040       /* Half Duplex Enable */
-#define STRR_CPEN  0x00000030       /* Compensation Enable */
-#define STRR_LSE   0x00000008       /* Link Pulse Send Enable */
-#define STRR_DREN  0x00000004       /* Driver Enable */
-#define STRR_LBK   0x00000002       /* Loopback Enable */
-#define STRR_ECEN  0x00000001       /* Encoder Enable */
-#define STRR_RESET 0xffffffff       /* Reset value for STRR */
-
-/*
-** SIA General Register (DE4X5_SIGR)
-*/
-#define SIGR_RMI   0x40000000       /* Receive Match Interrupt */
-#define SIGR_GI1   0x20000000       /* General Port Interrupt 1 */
-#define SIGR_GI0   0x10000000       /* General Port Interrupt 0 */
-#define SIGR_CWE   0x08000000       /* Control Write Enable */
-#define SIGR_RME   0x04000000       /* Receive Match Enable */
-#define SIGR_GEI1  0x02000000       /* GEP Interrupt Enable on Port 1 */
-#define SIGR_GEI0  0x01000000       /* GEP Interrupt Enable on Port 0 */
-#define SIGR_LGS3  0x00800000       /* LED/GEP3 Select */
-#define SIGR_LGS2  0x00400000       /* LED/GEP2 Select */
-#define SIGR_LGS1  0x00200000       /* LED/GEP1 Select */
-#define SIGR_LGS0  0x00100000       /* LED/GEP0 Select */
-#define SIGR_MD    0x000f0000       /* General Purpose Mode and Data */
-#define SIGR_LV2   0x00008000       /* General Purpose LED2 value */
-#define SIGR_LE2   0x00004000       /* General Purpose LED2 enable */
-#define SIGR_FRL   0x00002000       /* Force Receiver Low */
-#define SIGR_DPST  0x00001000       /* PLL Self Test Start */
-#define SIGR_LSD   0x00000800       /* LED Stretch Disable */
-#define SIGR_FLF   0x00000400       /* Force Link Fail */
-#define SIGR_FUSQ  0x00000200       /* Force Unsquelch */
-#define SIGR_TSCK  0x00000100       /* Test Clock */
-#define SIGR_LV1   0x00000080       /* General Purpose LED1 value */
-#define SIGR_LE1   0x00000040       /* General Purpose LED1 enable */
-#define SIGR_RWR   0x00000020       /* Receive Watchdog Release */
-#define SIGR_RWD   0x00000010       /* Receive Watchdog Disable */
-#define SIGR_ABM   0x00000008       /* BNC: 0,  AUI:1 */
-#define SIGR_JCK   0x00000004       /* Jabber Clock */
-#define SIGR_HUJ   0x00000002       /* Host Unjab */
-#define SIGR_JBD   0x00000001       /* Jabber Disable */
-#define SIGR_RESET 0xffff0000       /* Reset value for SIGR */
-
-/*
-** Receive Descriptor Bit Summary
-*/
-#define R_OWN      0x80000000       /* Own Bit */
-#define RD_FF      0x40000000       /* Filtering Fail */
-#define RD_FL      0x3fff0000       /* Frame Length */
-#define RD_ES      0x00008000       /* Error Summary */
-#define RD_LE      0x00004000       /* Length Error */
-#define RD_DT      0x00003000       /* Data Type */
-#define RD_RF      0x00000800       /* Runt Frame */
-#define RD_MF      0x00000400       /* Multicast Frame */
-#define RD_FS      0x00000200       /* First Descriptor */
-#define RD_LS      0x00000100       /* Last Descriptor */
-#define RD_TL      0x00000080       /* Frame Too Long */
-#define RD_CS      0x00000040       /* Collision Seen */
-#define RD_FT      0x00000020       /* Frame Type */
-#define RD_RJ      0x00000010       /* Receive Watchdog */
-#define RD_RE      0x00000008       /* Report on MII Error */
-#define RD_DB      0x00000004       /* Dribbling Bit */
-#define RD_CE      0x00000002       /* CRC Error */
-#define RD_OF      0x00000001       /* Overflow */
-
-#define RD_RER     0x02000000       /* Receive End Of Ring */
-#define RD_RCH     0x01000000       /* Second Address Chained */
-#define RD_RBS2    0x003ff800       /* Buffer 2 Size */
-#define RD_RBS1    0x000007ff       /* Buffer 1 Size */
-
-/*
-** Transmit Descriptor Bit Summary
-*/
-#define T_OWN      0x80000000       /* Own Bit */
-#define TD_ES      0x00008000       /* Error Summary */
-#define TD_TO      0x00004000       /* Transmit Jabber Time-Out */
-#define TD_LO      0x00000800       /* Loss Of Carrier */
-#define TD_NC      0x00000400       /* No Carrier */
-#define TD_LC      0x00000200       /* Late Collision */
-#define TD_EC      0x00000100       /* Excessive Collisions */
-#define TD_HF      0x00000080       /* Heartbeat Fail */
-#define TD_CC      0x00000078       /* Collision Counter */
-#define TD_LF      0x00000004       /* Link Fail */
-#define TD_UF      0x00000002       /* Underflow Error */
-#define TD_DE      0x00000001       /* Deferred */
-
-#define TD_IC      0x80000000       /* Interrupt On Completion */
-#define TD_LS      0x40000000       /* Last Segment */
-#define TD_FS      0x20000000       /* First Segment */
-#define TD_FT1     0x10000000       /* Filtering Type */
-#define TD_SET     0x08000000       /* Setup Packet */
-#define TD_AC      0x04000000       /* Add CRC Disable */
-#define TD_TER     0x02000000       /* Transmit End Of Ring */
-#define TD_TCH     0x01000000       /* Second Address Chained */
-#define TD_DPD     0x00800000       /* Disabled Padding */
-#define TD_FT0     0x00400000       /* Filtering Type */
-#define TD_TBS2    0x003ff800       /* Buffer 2 Size */
-#define TD_TBS1    0x000007ff       /* Buffer 1 Size */
-
-#define PERFECT_F  0x00000000
-#define HASH_F     TD_FT0
-#define INVERSE_F  TD_FT1
-#define HASH_O_F   (TD_FT1 | TD_F0)
-
-/*
-** Media / mode state machine definitions
-** User selectable:
-*/
-#define TP              0x0040     /* 10Base-T (now equiv to _10Mb)        */
-#define TP_NW           0x0002     /* 10Base-T with Nway                   */
-#define BNC             0x0004     /* Thinwire                             */
-#define AUI             0x0008     /* Thickwire                            */
-#define BNC_AUI         0x0010     /* BNC/AUI on DC21040 indistinguishable */
-#define _10Mb           0x0040     /* 10Mb/s Ethernet                      */
-#define _100Mb          0x0080     /* 100Mb/s Ethernet                     */
-#define AUTO            0x4000     /* Auto sense the media or speed        */
-
-/*
-** Internal states
-*/
-#define NC              0x0000     /* No Connection                        */
-#define ANS             0x0020     /* Intermediate AutoNegotiation State   */
-#define SPD_DET         0x0100     /* Parallel speed detection             */
-#define INIT            0x0200     /* Initial state                        */
-#define EXT_SIA         0x0400     /* External SIA for motherboard chip    */
-#define ANS_SUSPECT     0x0802     /* Suspect the ANS (TP) port is down    */
-#define TP_SUSPECT      0x0803     /* Suspect the TP port is down          */
-#define BNC_AUI_SUSPECT 0x0804     /* Suspect the BNC or AUI port is down  */
-#define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down     */
-#define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down         */
-#define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down         */
-#define MII             0x1000     /* MII on the 21143                     */
-
-#define TIMER_CB        0x80000000 /* Timer callback detection             */
-
-/*
-** DE4X5 DEBUG Options
-*/
-#define DEBUG_NONE      0x0000     /* No DEBUG messages */
-#define DEBUG_VERSION   0x0001     /* Print version message */
-#define DEBUG_MEDIA     0x0002     /* Print media messages */
-#define DEBUG_TX        0x0004     /* Print TX (queue_pkt) messages */
-#define DEBUG_RX        0x0008     /* Print RX (de4x5_rx) messages */
-#define DEBUG_SROM      0x0010     /* Print SROM messages */
-#define DEBUG_MII       0x0020     /* Print MII messages */
-#define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
-#define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
-#define DEBUG_PCICFG    0x0100
-#define DEBUG_ALL       0x01ff
-
-/*
-** Miscellaneous
-*/
-#define PCI  0
-#define EISA 1
-
-#define HASH_TABLE_LEN   512       /* Bits */
-#define HASH_BITS        0x01ff    /* 9 LS bits */
-
-#define SETUP_FRAME_LEN  192       /* Bytes */
-#define IMPERF_PA_OFFSET 156       /* Bytes */
-
-#define POLL_DEMAND          1
-
-#define LOST_MEDIA_THRESHOLD 3
-
-#define MASK_INTERRUPTS      1
-#define UNMASK_INTERRUPTS    0
-
-#define DE4X5_STRLEN         8
-
-#define DE4X5_INIT           0     /* Initialisation time */
-#define DE4X5_RUN            1     /* Run time */
-
-#define DE4X5_SAVE_STATE     0
-#define DE4X5_RESTORE_STATE  1
-
-/*
-** Address Filtering Modes
-*/
-#define PERFECT              0     /* 16 perfect physical addresses */
-#define HASH_PERF            1     /* 1 perfect, 512 multicast addresses */
-#define PERFECT_REJ          2     /* Reject 16 perfect physical addresses */
-#define ALL_HASH             3     /* Hashes all physical & multicast addrs */
-
-#define ALL                  0     /* Clear out all the setup frame */
-#define PHYS_ADDR_ONLY       1     /* Update the physical address only */
-
-/*
-** Booleans
-*/
-#define NO                   0
-#define FALSE                0
-
-#define YES                  ~0
-#define TRUE                 ~0
-
-/*
-** Adapter state
-*/
-#define INITIALISED          0     /* After h/w initialised and mem alloc'd */
-#define CLOSED               1     /* Ready for opening */
-#define OPEN                 2     /* Running */
-
-/*
-** Various wait times
-*/
-#define PDET_LINK_WAIT    1200    /* msecs to wait for link detect bits     */
-#define ANS_FINISH_WAIT   1000    /* msecs to wait for link detect bits     */
-
-/*
-** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
-** the vendors seem split 50-50 on how to calculate the OUI register values
-** anyway, just reading Reg2 seems reasonable for now [see de4x5_get_oui()].
-*/
-#define NATIONAL_TX 0x2000
-#define BROADCOM_T4 0x03e0
-#define SEEQ_T4     0x0016
-#define CYPRESS_T4  0x0014
-
-/*
-** Speed Selection stuff
-*/
-#define SET_10Mb {\
-  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
-    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
-      mii_wr(MII_CR_10|(lp->fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    }\
-    omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
-    outl(omr, DE4X5_OMR);\
-    if (!lp->useSROM) lp->cache.gep = 0;\
-  } else if (lp->useSROM && !lp->useMII) {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
-  } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | OMR_SDP | OMR_TTM, DE4X5_OMR);\
-    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
-    gep_wr(lp->cache.gep, dev);\
-  }\
-}
-
-#define SET_100Mb {\
-  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
-    int fdx=0;\
-    if (lp->phy[lp->active].id == NATIONAL_TX) {\
-        mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
-                      0x18, lp->phy[lp->active].addr, DE4X5_MII);\
-    }\
-    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
-    sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
-    if (!(sr & MII_ANA_T4AM) && lp->fdx) fdx=1;\
-    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
-      mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    }\
-    if (fdx) omr |= OMR_FDX;\
-    outl(omr, DE4X5_OMR);\
-    if (!lp->useSROM) lp->cache.gep = 0;\
-  } else if (lp->useSROM && !lp->useMII) {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
-  } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    omr |= (lp->fdx ? OMR_FDX : 0);\
-    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
-    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
-    gep_wr(lp->cache.gep, dev);\
-  }\
-}
-
-/* FIX ME so I don't jam 10Mb networks */
-#define SET_100Mb_PDET {\
-  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
-    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
-    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    outl(omr, DE4X5_OMR);\
-  } else if (lp->useSROM && !lp->useMII) {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    outl(omr, DE4X5_OMR);\
-  } else {\
-    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
-    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS, DE4X5_OMR);\
-    lp->cache.gep = (GEP_FDXD | GEP_MODE);\
-    gep_wr(lp->cache.gep, dev);\
-  }\
-}
-
-/*
-** Include the IOCTL stuff
-*/
-#include <linux/sockios.h>
-
-#define	DE4X5IOCTL	SIOCDEVPRIVATE
-
-struct de4x5_ioctl {
-	unsigned short cmd;                /* Command to run */
-	unsigned short len;                /* Length of the data buffer */
-	unsigned char  *data;              /* Pointer to the data buffer */
-};
-
-/* 
-** Recognised commands for the driver 
-*/
-#define DE4X5_GET_HWADDR	0x01 /* Get the hardware address */
-#define DE4X5_SET_HWADDR	0x02 /* Set the hardware address */
-#define DE4X5_SET_PROM  	0x03 /* Set Promiscuous Mode */
-#define DE4X5_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
-#define DE4X5_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
-#define DE4X5_GET_MCA   	0x06 /* Get a multicast address */
-#define DE4X5_SET_MCA   	0x07 /* Set a multicast address */
-#define DE4X5_CLR_MCA    	0x08 /* Clear a multicast address */
-#define DE4X5_MCA_EN    	0x09 /* Enable a multicast address group */
-#define DE4X5_GET_STATS  	0x0a /* Get the driver statistics */
-#define DE4X5_CLR_STATS 	0x0b /* Zero out the driver statistics */
-#define DE4X5_GET_OMR           0x0c /* Get the OMR Register contents */
-#define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
-#define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff -urN linux-2.5.6-pre3/drivers/net/dmfe.c linux-2.5.6/drivers/net/dmfe.c
--- linux-2.5.6-pre3/drivers/net/dmfe.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/drivers/net/dmfe.c	Wed Dec 31 16:00:00 1969
@@ -1,2070 +0,0 @@
-/*
-    A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
-    ethernet driver for Linux.
-    Copyright (C) 1997  Sten Wang
-
-    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.
-
-    DAVICOM Web-Site: www.davicom.com.tw
-
-    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
-    Maintainer: Tobias Ringstrom <tori@unhappy.mine.nu>
-
-    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
-
-    Marcelo Tosatti <marcelo@conectiva.com.br> :
-    Made it compile in 2.3 (device to net_device)
-
-    Alan Cox <alan@redhat.com> :
-    Cleaned up for kernel merge.
-    Removed the back compatibility support
-    Reformatted, fixing spelling etc as I went
-    Removed IRQ 0-15 assumption
-
-    Jeff Garzik <jgarzik@mandrakesoft.com> :
-    Updated to use new PCI driver API.
-    Resource usage cleanups.
-    Report driver version to user.
-
-    Tobias Ringstrom <tori@unhappy.mine.nu> :
-    Cleaned up and added SMP safety.  Thanks go to Jeff Garzik,
-    Andrew Morton and Frank Davis for the SMP safety fixes.
-
-    Vojtech Pavlik <vojtech@suse.cz> :
-    Cleaned up pointer arithmetics.
-    Fixed a lot of 64bit issues.
-    Cleaned up printk()s a bit.
-    Fixed some obvious big endian problems.
-
-    Tobias Ringstrom <tori@unhappy.mine.nu> :
-    Use time_after for jiffies calculation.  Added ethtool
-    support.  Updated PCI resource allocation.  Do not
-    forget to unmap PCI mapped skbs.
-
-    TODO
-
-    Implement pci_driver::suspend() and pci_driver::resume()
-    power management methods.
-
-    Check on 64 bit boxes.
-    Check and fix on big endian boxes.
-
-    Test and make sure PCI latency is now correct for all cases.
-*/
-
-#define DRV_NAME	"dmfe"
-#define DRV_VERSION	"1.36.4"
-#define DRV_RELDATE	"2002-01-17"
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/crc32.h>
-
-#include <asm/processor.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-
-/* Board/System/Debug information/definition ---------------- */
-#define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
-#define PCI_DM9102_ID   0x91021282      /* Davicom DM9102 ID */
-#define PCI_DM9100_ID   0x91001282      /* Davicom DM9100 ID */
-#define PCI_DM9009_ID   0x90091282      /* Davicom DM9009 ID */
-
-#define DM9102_IO_SIZE  0x80
-#define DM9102A_IO_SIZE 0x100
-#define TX_MAX_SEND_CNT 0x1             /* Maximum tx packet per time */
-#define TX_DESC_CNT     0x10            /* Allocated Tx descriptors */
-#define RX_DESC_CNT     0x20            /* Allocated Rx descriptors */
-#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
-#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
-#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
-#define TX_BUF_ALLOC    0x600
-#define RX_ALLOC_SIZE   0x620
-#define DM910X_RESET    1
-#define CR0_DEFAULT     0x00E00000      /* TX & RX burst mode */
-#define CR6_DEFAULT     0x00080000      /* HD */
-#define CR7_DEFAULT     0x180c1
-#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
-#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
-#define MAX_PACKET_SIZE 1514
-#define DMFE_MAX_MULTICAST 14
-#define RX_COPY_SIZE	100
-#define MAX_CHECK_PACKET 0x8000
-#define DM9801_NOISE_FLOOR 8
-#define DM9802_NOISE_FLOOR 5
-
-#define DMFE_10MHF      0
-#define DMFE_100MHF     1
-#define DMFE_10MFD      4
-#define DMFE_100MFD     5
-#define DMFE_AUTO       8
-#define DMFE_1M_HPNA    0x10
-
-#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
-#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
-#define DMFE_TXTH_128	0x0000		/* TX TH 128 byte */
-#define DMFE_TXTH_256	0x4000		/* TX TH 256 byte */
-#define DMFE_TXTH_512	0x8000		/* TX TH 512 byte */
-#define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
-
-#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
-#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
-#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
-
-#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
-
-#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
-
-
-/* CR9 definition: SROM/MII */
-#define CR9_SROM_READ   0x4800
-#define CR9_SRCS        0x1
-#define CR9_SRCLK       0x2
-#define CR9_CRDOUT      0x8
-#define SROM_DATA_0     0x0
-#define SROM_DATA_1     0x4
-#define PHY_DATA_1      0x20000
-#define PHY_DATA_0      0x00000
-#define MDCLKH          0x10000
-
-#define PHY_POWER_DOWN	0x800
-
-#define SROM_V41_CODE   0x14
-
-#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);
-
-#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
-#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
-
-/* Sten Check */
-#define DEVICE net_device
-
-/* Structure/enum declaration ------------------------------- */
-struct tx_desc {
-        u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
-        char *tx_buf_ptr;               /* Data for us */
-        struct tx_desc *next_tx_desc;
-} __attribute__(( aligned(32) ));
-
-struct rx_desc {
-	u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
-	struct sk_buff *rx_skb_ptr;	/* Data for us */
-	struct rx_desc *next_rx_desc;
-} __attribute__(( aligned(32) ));
-
-struct dmfe_board_info {
-	u32 chip_id;			/* Chip vendor/Device ID */
-	u32 chip_revision;		/* Chip revision */
-	struct DEVICE *next_dev;	/* next device */
-	struct pci_dev *pdev;		/* PCI device */
-	spinlock_t lock;
-
-	long ioaddr;			/* I/O base address */
-	u32 cr0_data;
-	u32 cr5_data;
-	u32 cr6_data;
-	u32 cr7_data;
-	u32 cr15_data;
-
-	/* pointer for memory physical address */
-	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
-	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
-	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
-	dma_addr_t first_tx_desc_dma;
-	dma_addr_t first_rx_desc_dma;
-
-	/* descriptor pointer */
-	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
-	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
-	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
-	struct tx_desc *first_tx_desc;
-	struct tx_desc *tx_insert_ptr;
-	struct tx_desc *tx_remove_ptr;
-	struct rx_desc *first_rx_desc;
-	struct rx_desc *rx_insert_ptr;
-	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
-	unsigned long tx_packet_cnt;	/* transmitted packet count */
-	unsigned long tx_queue_cnt;	/* wait to send packet count */
-	unsigned long rx_avail_cnt;	/* available rx descriptor count */
-	unsigned long interval_rx_cnt;	/* rx packet count a callback time */
-
-	u16 HPNA_command;		/* For HPNA register 16 */
-	u16 HPNA_timer;			/* For HPNA remote device check */
-	u16 dbug_cnt;
-	u16 NIC_capability;		/* NIC media capability */
-	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
-
-	u8 HPNA_present;		/* 0:none, 1:DM9801, 2:DM9802 */
-	u8 chip_type;			/* Keep DM9102A chip type */
-	u8 media_mode;			/* user specify media mode */
-	u8 op_mode;			/* real work media mode */
-	u8 phy_addr;
-	u8 link_failed;			/* Ever link failed */
-	u8 wait_reset;			/* Hardware failed, need to reset */
-	u8 dm910x_chk_mode;		/* Operating mode check */
-	u8 first_in_callback;		/* Flag to record state */
-	struct timer_list timer;
-
-	/* System defined statistic counter */
-	struct net_device_stats stats;
-
-	/* Driver defined statistic counter */
-	unsigned long tx_fifo_underrun;
-	unsigned long tx_loss_carrier;
-	unsigned long tx_no_carrier;
-	unsigned long tx_late_collision;
-	unsigned long tx_excessive_collision;
-	unsigned long tx_jabber_timeout;
-	unsigned long reset_count;
-	unsigned long reset_cr8;
-	unsigned long reset_fatal;
-	unsigned long reset_TXtimeout;
-
-	/* NIC SROM data */
-	unsigned char srom[128];
-};
-
-enum dmfe_offsets {
-	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
-	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
-	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
-	DCR15 = 0x78
-};
-
-enum dmfe_CR6_bits {
-	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
-	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
-	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
-};
-
-/* Global variable declaration ----------------------------- */
-static int __devinitdata printed_version;
-static char version[] __devinitdata =
-	KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version "
-	DRV_VERSION " (" DRV_RELDATE ")\n";
-
-static int dmfe_debug;
-static unsigned char dmfe_media_mode = DMFE_AUTO;
-static u32 dmfe_cr6_user_set;
-
-/* For module input parameter */
-static int debug;
-static u32 cr6set;
-static unsigned char mode = 8;
-static u8 chkmode = 1;
-static u8 HPNA_mode;		/* Default: Low Power/High Speed */
-static u8 HPNA_rx_cmd;		/* Default: Disable Rx remote command */
-static u8 HPNA_tx_cmd;		/* Default: Don't issue remote command */
-static u8 HPNA_NoiseFloor;	/* Default: HPNA NoiseFloor */
-static u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
-				   4: TX pause packet */
-
-
-/* function declaration ------------------------------------- */
-static int dmfe_open(struct DEVICE *);
-static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *);
-static int dmfe_stop(struct DEVICE *);
-static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
-static void dmfe_set_filter_mode(struct DEVICE *);
-static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int);
-static u16 read_srom_word(long ,int);
-static void dmfe_interrupt(int , void *, struct pt_regs *);
-static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long);
-static void allocate_rx_buffer(struct dmfe_board_info *);
-static void update_cr6(u32, unsigned long);
-static void send_filter_frame(struct DEVICE * ,int);
-static void dm9132_id_table(struct DEVICE * ,int);
-static u16 phy_read(unsigned long, u8, u8, u32);
-static void phy_write(unsigned long, u8, u8, u16, u32);
-static void phy_write_1bit(unsigned long, u32);
-static u16 phy_read_1bit(unsigned long);
-static u8 dmfe_sense_speed(struct dmfe_board_info *);
-static void dmfe_process_mode(struct dmfe_board_info *);
-static void dmfe_timer(unsigned long);
-static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *);
-static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *);
-static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
-static void dmfe_dynamic_reset(struct DEVICE *);
-static void dmfe_free_rxbuffer(struct dmfe_board_info *);
-static void dmfe_init_dm910x(struct DEVICE *);
-static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
-static void dmfe_parse_srom(struct dmfe_board_info *);
-static void dmfe_program_DM9801(struct dmfe_board_info *, int);
-static void dmfe_program_DM9802(struct dmfe_board_info *);
-static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
-static void dmfe_set_phyxcer(struct dmfe_board_info *);
-
-/* DM910X network baord routine ---------------------------- */
-
-/*
- *	Search DM910X board ,allocate space and register it
- */
-
-static int __devinit dmfe_init_one (struct pci_dev *pdev,
-				    const struct pci_device_id *ent)
-{
-	struct dmfe_board_info *db;	/* board information structure */
-	struct net_device *dev;
-	u32 dev_rev, pci_pmr;
-	int i, err;
-
-	DMFE_DBUG(0, "dmfe_init_one()", 0);
-
-	if (!printed_version++)
-		printk(version);
-
-	/* Init network device */
-	dev = alloc_etherdev(sizeof(*db));
-	if (dev == NULL)
-		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
-
-	if (pci_set_dma_mask(pdev, 0xffffffff)) {
-		printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
-		err = -ENODEV;
-		goto err_out_free;
-	}
-
-	/* Enable Master/IO access, Disable memory access */
-	err = pci_enable_device(pdev);
-	if (err)
-		goto err_out_free;
-
-	if (!pci_resource_start(pdev, 0)) {
-		printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
-		err = -ENODEV;
-		goto err_out_disable;
-	}
-
-	/* Read Chip revision */
-	pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
-
-	if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {
-		printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
-		err = -ENODEV;
-		goto err_out_disable;
-	}
-
-#if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
-
-	/* Set Latency Timer 80h */
-	/* FIXME: setting values > 32 breaks some SiS 559x stuff.
-	   Need a PCI quirk.. */
-
-	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
-#endif
-
-	if (pci_request_regions(pdev, DRV_NAME)) {
-		printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
-		err = -ENODEV;
-		goto err_out_disable;
-	}
-
-	/* Init system & device */
-	db = dev->priv;
-
-	/* Allocate Tx/Rx descriptor memory */
-	db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
-	db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
-
-	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
-	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
-	db->buf_pool_start = db->buf_pool_ptr;
-	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
-
-	db->chip_id = ent->driver_data;
-	db->ioaddr = pci_resource_start(pdev, 0);
-	db->chip_revision = dev_rev;
-
-	db->pdev = pdev;
-
-	dev->base_addr = db->ioaddr;
-	dev->irq = pdev->irq;
-	pci_set_drvdata(pdev, dev);
-	dev->open = &dmfe_open;
-	dev->hard_start_xmit = &dmfe_start_xmit;
-	dev->stop = &dmfe_stop;
-	dev->get_stats = &dmfe_get_stats;
-	dev->set_multicast_list = &dmfe_set_filter_mode;
-	dev->do_ioctl = &dmfe_do_ioctl;
-	spin_lock_init(&db->lock);
-
-	pci_read_config_dword(pdev, 0x50, &pci_pmr);
-	pci_pmr &= 0x70000;
-	if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) )
-		db->chip_type = 1;	/* DM9102A E3 */
-	else
-		db->chip_type = 0;
-
-	/* read 64 word srom data */
-	for (i = 0; i < 64; i++)
-		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
-
-	/* Set Node address */
-	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = db->srom[20 + i];
-
-	err = register_netdev (dev);
-	if (err)
-		goto err_out_res;
-
-	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,",
-		dev->name,
-		ent->driver_data >> 16,
-		pdev->slot_name);
-	for (i = 0; i < 6; i++)
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-	printk(", irq %d.\n", dev->irq);
-
-	pci_set_master(pdev);
-
-	return 0;
-
-err_out_res:
-	pci_release_regions(pdev);
-err_out_disable:
-	pci_disable_device(pdev);
-err_out_free:
-	pci_set_drvdata(pdev, NULL);
-	kfree(dev);
-
-	return err;
-}
-
-
-static void __exit dmfe_remove_one (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct dmfe_board_info *db = dev->priv;
-
-	DMFE_DBUG(0, "dmfe_remove_one()", 0);
-
- 	if (dev) {
-		pci_free_consistent(db->pdev, sizeof(struct tx_desc) *
-					DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
- 					db->desc_pool_dma_ptr);
-		pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
-					db->buf_pool_ptr, db->buf_pool_dma_ptr);
-		unregister_netdev(dev);
-		pci_release_regions(pdev);
-		kfree(dev);	/* free board information */
-		pci_set_drvdata(pdev, NULL);
-	}
-
-	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
-}
-
-
-/*
- *	Open the interface.
- *	The interface is opened whenever "ifconfig" actives it.
- */
-
-static int dmfe_open(struct DEVICE *dev)
-{
-	int ret;
-	struct dmfe_board_info *db = dev->priv;
-
-	DMFE_DBUG(0, "dmfe_open", 0);
-
-	ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
-	if (ret)
-		return ret;
-
-	/* system variable init */
-	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
-	db->tx_packet_cnt = 0;
-	db->tx_queue_cnt = 0;
-	db->rx_avail_cnt = 0;
-	db->link_failed = 1;
-	db->wait_reset = 0;
-
-	db->first_in_callback = 0;
-	db->NIC_capability = 0xf;	/* All capability*/
-	db->PHY_reg4 = 0x1e0;
-
-	/* CR6 operation mode decision */
-	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
-		(db->chip_revision >= 0x02000030) ) {
-    		db->cr6_data |= DMFE_TXTH_256;
-		db->cr0_data = CR0_DEFAULT;
-		db->dm910x_chk_mode=4;		/* Enter the normal mode */
- 	} else {
-		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
-		db->cr0_data = 0;
-		db->dm910x_chk_mode = 1;	/* Enter the check mode */
-	}
-
-	/* Initilize DM910X board */
-	dmfe_init_dm910x(dev);
-
-	/* Active System Interface */
-	netif_wake_queue(dev);
-
-	/* set and active a timer process */
-	init_timer(&db->timer);
-	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
-	db->timer.data = (unsigned long)dev;
-	db->timer.function = &dmfe_timer;
-	add_timer(&db->timer);
-
-	return 0;
-}
-
-
-/*	Initilize DM910X board
- *	Reset DM910X board
- *	Initilize TX/Rx descriptor chain structure
- *	Send the set-up frame
- *	Enable Tx/Rx machine
- */
-
-static void dmfe_init_dm910x(struct DEVICE *dev)
-{
-	struct dmfe_board_info *db = dev->priv;
-	unsigned long ioaddr = db->ioaddr;
-
-	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
-
-	/* Reset DM910x MAC controller */
-	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
-	udelay(100);
-	outl(db->cr0_data, ioaddr + DCR0);
-	udelay(5);
-
-	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
-	db->phy_addr = 1;
-
-	/* Parser SROM and media mode */
-	dmfe_parse_srom(db);
-	db->media_mode = dmfe_media_mode;
-
-	/* RESET Phyxcer Chip by GPR port bit 7 */
-	outl(0x180, ioaddr + DCR12);		/* Let bit 7 output port */
-	if (db->chip_id == PCI_DM9009_ID) {
-		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */
-		mdelay(300);			/* Delay 300 ms */
-	}
-	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */
-
-	/* Process Phyxcer Media Mode */
-	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
-		dmfe_set_phyxcer(db);
-
-	/* Media Mode Process */
-	if ( !(db->media_mode & DMFE_AUTO) )
-		db->op_mode = db->media_mode; 	/* Force Mode */
-
-	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
-	dmfe_descriptor_init(db, ioaddr);
-
-	/* Init CR6 to program DM910x operation */
-	update_cr6(db->cr6_data, ioaddr);
-
-	/* Send setup frame */
-	if (db->chip_id == PCI_DM9132_ID)
-		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
-	else
-		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */
-
-	/* Init CR7, interrupt active bit */
-	db->cr7_data = CR7_DEFAULT;
-	outl(db->cr7_data, ioaddr + DCR7);
-
-	/* Init CR15, Tx jabber and Rx watchdog timer */
-	outl(db->cr15_data, ioaddr + DCR15);
-
-	/* Enable DM910X Tx/Rx function */
-	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
-	update_cr6(db->cr6_data, ioaddr);
-}
-
-
-/*
- *	Hardware start transmission.
- *	Send a packet to media from the upper layer.
- */
-
-static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
-{
-	struct dmfe_board_info *db = dev->priv;
-	struct tx_desc *txptr;
-	unsigned long flags;
-
-	DMFE_DBUG(0, "dmfe_start_xmit", 0);
-
-	/* Resource flag check */
-	netif_stop_queue(dev);
-
-	/* Too large packet check */
-	if (skb->len > MAX_PACKET_SIZE) {
-		printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	spin_lock_irqsave(&db->lock, flags);
-
-	/* No Tx resource check, it never happen nromally */
-	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
-		spin_unlock_irqrestore(&db->lock, flags);
-		printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);
-		return 1;
-	}
-
-	/* Disable NIC interrupt */
-	outl(0, dev->base_addr + DCR7);
-
-	/* transmit this packet */
-	txptr = db->tx_insert_ptr;
-	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
-	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
-
-	/* Point to next transmit free descriptor */
-	db->tx_insert_ptr = txptr->next_tx_desc;
-
-	/* Transmit Packet Process */
-	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
-		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
-		db->tx_packet_cnt++;			/* Ready to send */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
-		dev->trans_start = jiffies;		/* saved time stamp */
-	} else {
-		db->tx_queue_cnt++;			/* queue TX packet */
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
-	}
-
-	/* Tx resource check */
-	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
-		netif_wake_queue(dev);
-
-	/* free this SKB */
-	dev_kfree_skb(skb);
-
-	/* Restore CR7 to enable interrupt */
-	spin_unlock_irqrestore(&db->lock, flags);
-	outl(db->cr7_data, dev->base_addr + DCR7);
-
-	return 0;
-}
-
-
-/*
- *	Stop the interface.
- *	The interface is stopped when it is brought.
- */
-
-static int dmfe_stop(struct DEVICE *dev)
-{
-	struct dmfe_board_info *db = dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-
-	DMFE_DBUG(0, "dmfe_stop", 0);
-
-	/* disable system */
-	netif_stop_queue(dev);
-
-	/* deleted timer */
-	del_timer_sync(&db->timer);
-
-	/* Reset & stop DM910X board */
-	outl(DM910X_RESET, ioaddr + DCR0);
-	udelay(5);
-	phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
-
-	/* free interrupt */
-	free_irq(dev->irq, dev);
-
-	/* free allocated rx buffer */
-	dmfe_free_rxbuffer(db);
-
-#if 0
-	/* show statistic counter */
-	printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
-		db->tx_fifo_underrun, db->tx_excessive_collision,
-		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
-		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
-		db->reset_fatal, db->reset_TXtimeout);
-#endif
-
-	return 0;
-}
-
-
-/*
- *	DM9102 insterrupt handler
- *	receive the packet to upper layer, free the transmitted packet
- */
-
-static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct DEVICE *dev = dev_id;
-	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
-	unsigned long ioaddr = dev->base_addr;
-	unsigned long flags;
-
-	DMFE_DBUG(0, "dmfe_interrupt()", 0);
-
-	if (!dev) {
-		DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
-		return;
-	}
-
-	spin_lock_irqsave(&db->lock, flags);
-
-	/* Got DM910X status */
-	db->cr5_data = inl(ioaddr + DCR5);
-	outl(db->cr5_data, ioaddr + DCR5);
-	if ( !(db->cr5_data & 0xc1) ) {
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
-	}
-
-	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
-	outl(0, ioaddr + DCR7);
-
-	/* Check system status */
-	if (db->cr5_data & 0x2000) {
-		/* system bus error happen */
-		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
-		db->reset_fatal++;
-		db->wait_reset = 1;	/* Need to RESET */
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
-	}
-
-	 /* Received the coming packet */
-	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
-		dmfe_rx_packet(dev, db);
-
-	/* reallocate rx descriptor buffer */
-	if (db->rx_avail_cnt<RX_DESC_CNT)
-		allocate_rx_buffer(db);
-
-	/* Free the transmitted descriptor */
-	if ( db->cr5_data & 0x01)
-		dmfe_free_tx_pkt(dev, db);
-
-	/* Mode Check */
-	if (db->dm910x_chk_mode & 0x2) {
-		db->dm910x_chk_mode = 0x4;
-		db->cr6_data |= 0x100;
-		update_cr6(db->cr6_data, db->ioaddr);
-	}
-
-	/* Restore CR7 to enable interrupt mask */
-	outl(db->cr7_data, ioaddr + DCR7);
-
-	spin_unlock_irqrestore(&db->lock, flags);
-}
-
-
-/*
- *	Free TX resource after TX complete
- */
-
-static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
-{
-	struct tx_desc *txptr;
-	unsigned long ioaddr = dev->base_addr;
-	u32 tdes0;
-
-	txptr = db->tx_remove_ptr;
-	while(db->tx_packet_cnt) {
-		tdes0 = le32_to_cpu(txptr->tdes0);
-		/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
-		if (tdes0 & 0x80000000)
-			break;
-
-		/* A packet sent completed */
-		db->tx_packet_cnt--;
-		db->stats.tx_packets++;
-
-		/* Transmit statistic counter */
-		if ( tdes0 != 0x7fffffff ) {
-			/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
-			db->stats.collisions += (tdes0 >> 3) & 0xf;
-			db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
-			if (tdes0 & TDES0_ERR_MASK) {
-				db->stats.tx_errors++;
-
-				if (tdes0 & 0x0002) {	/* UnderRun */
-					db->tx_fifo_underrun++;
-					if ( !(db->cr6_data & CR6_SFT) ) {
-						db->cr6_data = db->cr6_data | CR6_SFT;
-						update_cr6(db->cr6_data, db->ioaddr);
-					}
-				}
-				if (tdes0 & 0x0100)
-					db->tx_excessive_collision++;
-				if (tdes0 & 0x0200)
-					db->tx_late_collision++;
-				if (tdes0 & 0x0400)
-					db->tx_no_carrier++;
-				if (tdes0 & 0x0800)
-					db->tx_loss_carrier++;
-				if (tdes0 & 0x4000)
-					db->tx_jabber_timeout++;
-			}
-		}
-
-    		txptr = txptr->next_tx_desc;
-	}/* End of while */
-
-	/* Update TX remove pointer to next */
-	db->tx_remove_ptr = txptr;
-
-	/* Send the Tx packet in queue */
-	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
-		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
-		db->tx_packet_cnt++;			/* Ready to send */
-		db->tx_queue_cnt--;
-		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */
-		dev->trans_start = jiffies;		/* saved time stamp */
-	}
-
-	/* Resource available check */
-	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
-		netif_wake_queue(dev);	/* Active upper layer, send again */
-}
-
-
-/*
- *	Receive the come packet and pass to upper layer
- */
-
-static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
-{
-	struct rx_desc *rxptr;
-	struct sk_buff *skb;
-	int rxlen;
-	u32 rdes0;
-
-	rxptr = db->rx_ready_ptr;
-
-	while(db->rx_avail_cnt) {
-		rdes0 = le32_to_cpu(rxptr->rdes0);
-		if (rdes0 & 0x80000000)	/* packet owner check */
-			break;
-
-		db->rx_avail_cnt--;
-		db->interval_rx_cnt++;
-
-		pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
-		if ( (rdes0 & 0x300) != 0x300) {
-			/* A packet without First/Last flag */
-			/* reuse this SKB */
-			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
-			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
-		} else {
-			/* A packet with First/Last flag */
-			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
-
-			/* error summary bit check */
-			if (rdes0 & 0x8000) {
-				/* This is a error packet */
-				//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
-				db->stats.rx_errors++;
-				if (rdes0 & 1)
-					db->stats.rx_fifo_errors++;
-				if (rdes0 & 2)
-					db->stats.rx_crc_errors++;
-				if (rdes0 & 0x80)
-					db->stats.rx_length_errors++;
-			}
-
-			if ( !(rdes0 & 0x8000) ||
-				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
-				skb = rxptr->rx_skb_ptr;
-
-				/* Received Packet CRC check need or not */
-				if ( (db->dm910x_chk_mode & 1) &&
-					(cal_CRC(skb->tail, rxlen, 1) !=
-					(*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
-					/* Found a error received packet */
-					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
-					db->dm910x_chk_mode = 3;
-				} else {
-					/* Good packet, send to upper layer */
-					/* Shorst packet used new SKB */
-					if ( (rxlen < RX_COPY_SIZE) &&
-						( (skb = dev_alloc_skb(rxlen + 2) )
-						!= NULL) ) {
-						/* size less than COPY_SIZE, allocate a rxlen SKB */
-						skb->dev = dev;
-						skb_reserve(skb, 2); /* 16byte align */
-						memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
-						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
-					} else {
-						skb->dev = dev;
-						skb_put(skb, rxlen);
-					}
-					skb->protocol = eth_type_trans(skb, dev);
-					netif_rx(skb);
-					dev->last_rx = jiffies;
-					db->stats.rx_packets++;
-					db->stats.rx_bytes += rxlen;
-				}
-			} else {
-				/* Reuse SKB buffer when the packet is error */
-				DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
-				dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
-			}
-		}
-
-		rxptr = rxptr->next_rx_desc;
-	}
-
-	db->rx_ready_ptr = rxptr;
-}
-
-
-/*
- *	Get statistics from driver.
- */
-
-static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
-{
-	struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;
-
-	DMFE_DBUG(0, "dmfe_get_stats", 0);
-	return &db->stats;
-}
-
-
-/*
- * Set DM910X multicast address
- */
-
-static void dmfe_set_filter_mode(struct DEVICE * dev)
-{
-	struct dmfe_board_info *db = dev->priv;
-	unsigned long flags;
-
-	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
-	spin_lock_irqsave(&db->lock, flags);
-
-	if (dev->flags & IFF_PROMISC) {
-		DMFE_DBUG(0, "Enable PROM Mode", 0);
-		db->cr6_data |= CR6_PM | CR6_PBF;
-		update_cr6(db->cr6_data, db->ioaddr);
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
-	}
-
-	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
-		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
-		db->cr6_data &= ~(CR6_PM | CR6_PBF);
-		db->cr6_data |= CR6_PAM;
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
-	}
-
-	DMFE_DBUG(0, "Set multicast address", dev->mc_count);
-	if (db->chip_id == PCI_DM9132_ID)
-		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
-	else
-		send_filter_frame(dev, dev->mc_count); 	/* DM9102/DM9102A */
-	spin_unlock_irqrestore(&db->lock, flags);
-}
-
-
-/*
- *	Process the ethtool ioctl command
- */
-
-static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
-{
-	struct dmfe_board_info *db = dev->priv;
-	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO:
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		if (db->pdev)
-			strcpy(info.bus_info, db->pdev->slot_name);
-		else
-			sprintf(info.bus_info, "EISA 0x%lx %d",
-				dev->base_addr, dev->irq);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-        }
-
-	return -EOPNOTSUPP;
-}
-
-
-/*
- *	Process the upper socket ioctl command
- */
-
-static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
-{
-	int retval = -EOPNOTSUPP;
-	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
-
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data);
-	}
-
-	return retval;
-}
-
-
-/*
- *	A periodic timer routine
- *	Dynamic media sense, allocate Rx buffer...
- */
-
-static void dmfe_timer(unsigned long data)
-{
-	u32 tmp_cr8;
-	unsigned char tmp_cr12;
-	struct DEVICE *dev = (struct DEVICE *) data;
-	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
- 	unsigned long flags;
-
-	DMFE_DBUG(0, "dmfe_timer()", 0);
-	spin_lock_irqsave(&db->lock, flags);
-
-	/* Media mode process when Link OK before enter this route */
-	if (db->first_in_callback == 0) {
-		db->first_in_callback = 1;
-		if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
-			db->cr6_data &= ~0x40000;
-			update_cr6(db->cr6_data, db->ioaddr);
-			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
-			db->cr6_data |= 0x40000;
-			update_cr6(db->cr6_data, db->ioaddr);
-			db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
-			add_timer(&db->timer);
-			spin_unlock_irqrestore(&db->lock, flags);
-			return;
-		}
-	}
-
-
-	/* Operating Mode Check */
-	if ( (db->dm910x_chk_mode & 0x1) &&
-		(db->stats.rx_packets > MAX_CHECK_PACKET) )
-		db->dm910x_chk_mode = 0x4;
-
-	/* Dynamic reset DM910X : system error or transmit time-out */
-	tmp_cr8 = inl(db->ioaddr + DCR8);
-	if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
-		db->reset_cr8++;
-		db->wait_reset = 1;
-	}
-	db->interval_rx_cnt = 0;
-
-	/* TX polling kick monitor */
-	if ( db->tx_packet_cnt &&
-	     time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) {
-		outl(0x1, dev->base_addr + DCR1);   /* Tx polling again */
-
-		/* TX Timeout */
-		if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
-			db->reset_TXtimeout++;
-			db->wait_reset = 1;
-			printk(KERN_WARNING "%s: Tx timeout - resetting\n",
-			       dev->name);
-		}
-	}
-
-	if (db->wait_reset) {
-		DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
-		db->reset_count++;
-		dmfe_dynamic_reset(dev);
-		db->first_in_callback = 0;
-		db->timer.expires = DMFE_TIMER_WUT;
-		add_timer(&db->timer);
-		spin_unlock_irqrestore(&db->lock, flags);
-		return;
-	}
-
-	/* Link status check, Dynamic media type change */
-	if (db->chip_id == PCI_DM9132_ID)
-		tmp_cr12 = inb(db->ioaddr + DCR9 + 3);	/* DM9132 */
-	else
-		tmp_cr12 = inb(db->ioaddr + DCR12);	/* DM9102/DM9102A */
-
-	if ( ((db->chip_id == PCI_DM9102_ID) &&
-		(db->chip_revision == 0x02000030)) ||
-		((db->chip_id == PCI_DM9132_ID) &&
-		(db->chip_revision == 0x02000010)) ) {
-		/* DM9102A Chip */
-		if (tmp_cr12 & 2)
-			tmp_cr12 = 0x0;		/* Link failed */
-		else
-			tmp_cr12 = 0x3;	/* Link OK */
-	}
-
-	if ( !(tmp_cr12 & 0x3) && !db->link_failed ) {
-		/* Link Failed */
-		DMFE_DBUG(0, "Link Failed", tmp_cr12);
-		db->link_failed = 1;
-
-		/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
-		/* AUTO or force 1M Homerun/Longrun don't need */
-		if ( !(db->media_mode & 0x38) )
-			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
-
-		/* AUTO mode, if INT phyxcer link failed, select EXT device */
-		if (db->media_mode & DMFE_AUTO) {
-			/* 10/100M link failed, used 1M Home-Net */
-			db->cr6_data|=0x00040000;	/* bit18=1, MII */
-			db->cr6_data&=~0x00000200;	/* bit9=0, HD mode */
-			update_cr6(db->cr6_data, db->ioaddr);
-		}
-	} else
-		if ((tmp_cr12 & 0x3) && db->link_failed) {
-			DMFE_DBUG(0, "Link link OK", tmp_cr12);
-			db->link_failed = 0;
-
-			/* Auto Sense Speed */
-			if ( (db->media_mode & DMFE_AUTO) &&
-				dmfe_sense_speed(db) )
-				db->link_failed = 1;
-			dmfe_process_mode(db);
-			/* SHOW_MEDIA_TYPE(db->op_mode); */
-		}
-
-	/* HPNA remote command check */
-	if (db->HPNA_command & 0xf00) {
-		db->HPNA_timer--;
-		if (!db->HPNA_timer)
-			dmfe_HPNA_remote_cmd_chk(db);
-	}
-
-	/* Timer active again */
-	db->timer.expires = DMFE_TIMER_WUT;
-	add_timer(&db->timer);
-	spin_unlock_irqrestore(&db->lock, flags);
-}
-
-
-/*
- *	Dynamic reset the DM910X board
- *	Stop DM910X board
- *	Free Tx/Rx allocated memory
- *	Reset DM910X board
- *	Re-initilize DM910X board
- */
-
-static void dmfe_dynamic_reset(struct DEVICE *dev)
-{
-	struct dmfe_board_info *db = dev->priv;
-
-	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
-
-	/* Sopt MAC controller */
-	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
-	update_cr6(db->cr6_data, dev->base_addr);
-	outl(0, dev->base_addr + DCR7);		/* Disable Interrupt */
-	outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
-
-	/* Disable upper layer interface */
-	netif_stop_queue(dev);
-
-	/* Free Rx Allocate buffer */
-	dmfe_free_rxbuffer(db);
-
-	/* system variable init */
-	db->tx_packet_cnt = 0;
-	db->tx_queue_cnt = 0;
-	db->rx_avail_cnt = 0;
-	db->link_failed = 1;
-	db->wait_reset = 0;
-
-	/* Re-initilize DM910X board */
-	dmfe_init_dm910x(dev);
-
-	/* Restart upper layer interface */
-	netif_wake_queue(dev);
-}
-
-
-/*
- *	free all allocated rx buffer
- */
-
-static void dmfe_free_rxbuffer(struct dmfe_board_info * db)
-{
-	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
-
-	/* free allocated rx buffer */
-	while (db->rx_avail_cnt) {
-		dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
-		db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
-		db->rx_avail_cnt--;
-	}
-}
-
-
-/*
- *	Reuse the SK buffer
- */
-
-static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
-{
-	struct rx_desc *rxptr = db->rx_insert_ptr;
-
-	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
-		rxptr->rx_skb_ptr = skb;
-		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
-		wmb();
-		rxptr->rdes0 = cpu_to_le32(0x80000000);
-		db->rx_avail_cnt++;
-		db->rx_insert_ptr = rxptr->next_rx_desc;
-	} else
-		DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
-}
-
-
-/*
- *	Initialize transmit/Receive descriptor
- *	Using Chain structure, and allocate Tx/Rx buffer
- */
-
-static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr)
-{
-	struct tx_desc *tmp_tx;
-	struct rx_desc *tmp_rx;
-	unsigned char *tmp_buf;
-	dma_addr_t tmp_tx_dma, tmp_rx_dma;
-	dma_addr_t tmp_buf_dma;
-	int i;
-
-	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);
-
-	/* tx descriptor start pointer */
-	db->tx_insert_ptr = db->first_tx_desc;
-	db->tx_remove_ptr = db->first_tx_desc;
-	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
-
-	/* rx descriptor start pointer */
-	db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT;
-	db->first_rx_desc_dma =  db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT;
-	db->rx_insert_ptr = db->first_rx_desc;
-	db->rx_ready_ptr = db->first_rx_desc;
-	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */
-
-	/* Init Transmit chain */
-	tmp_buf = db->buf_pool_start;
-	tmp_buf_dma = db->buf_pool_dma_start;
-	tmp_tx_dma = db->first_tx_desc_dma;
-	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
-		tmp_tx->tx_buf_ptr = tmp_buf;
-		tmp_tx->tdes0 = cpu_to_le32(0);
-		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
-		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
-		tmp_tx_dma += sizeof(struct tx_desc);
-		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
-		tmp_tx->next_tx_desc = tmp_tx + 1;
-		tmp_buf = tmp_buf + TX_BUF_ALLOC;
-		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
-	}
-	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
-	tmp_tx->next_tx_desc = db->first_tx_desc;
-
-	 /* Init Receive descriptor chain */
-	tmp_rx_dma=db->first_rx_desc_dma;
-	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
-		tmp_rx->rdes0 = cpu_to_le32(0);
-		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
-		tmp_rx_dma += sizeof(struct rx_desc);
-		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
-		tmp_rx->next_rx_desc = tmp_rx + 1;
-	}
-	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
-	tmp_rx->next_rx_desc = db->first_rx_desc;
-
-	/* pre-allocate Rx buffer */
-	allocate_rx_buffer(db);
-}
-
-
-/*
- *	Update CR6 value
- *	Firstly stop DM910X , then written value and start
- */
-
-static void update_cr6(u32 cr6_data, unsigned long ioaddr)
-{
-	u32 cr6_tmp;
-
-	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */
-	outl(cr6_tmp, ioaddr + DCR6);
-	udelay(5);
-	outl(cr6_data, ioaddr + DCR6);
-	udelay(5);
-}
-
-
-/*
- *	Send a setup frame for DM9132
- *	This setup frame initilize DM910X addres filter mode
-*/
-
-static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
-{
-	struct dev_mc_list *mcptr;
-	u16 * addrptr;
-	unsigned long ioaddr = dev->base_addr+0xc0;		/* ID Table */
-	u32 hash_val;
-	u16 i, hash_table[4];
-
-	DMFE_DBUG(0, "dm9132_id_table()", 0);
-
-	/* Node address */
-	addrptr = (u16 *) dev->dev_addr;
-	outw(addrptr[0], ioaddr);
-	ioaddr += 4;
-	outw(addrptr[1], ioaddr);
-	ioaddr += 4;
-	outw(addrptr[2], ioaddr);
-	ioaddr += 4;
-
-	/* Clear Hash Table */
-	for (i = 0; i < 4; i++)
-		hash_table[i] = 0x0;
-
-	/* broadcast address */
-	hash_table[3] = 0x8000;
-
-	/* the multicast address in Hash Table : 64 bits */
-	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
-		hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f;
-		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
-	}
-
-	/* Write the hash table to MAC MD table */
-	for (i = 0; i < 4; i++, ioaddr += 4)
-		outw(hash_table[i], ioaddr);
-}
-
-
-/*
- *	Send a setup frame for DM9102/DM9102A
- *	This setup frame initilize DM910X addres filter mode
- */
-
-static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
-{
-	struct dmfe_board_info *db = dev->priv;
-	struct dev_mc_list *mcptr;
-	struct tx_desc *txptr;
-	u16 * addrptr;
-	u32 * suptr;
-	int i;
-
-	DMFE_DBUG(0, "send_filter_frame()", 0);
-
-	txptr = db->tx_insert_ptr;
-	suptr = (u32 *) txptr->tx_buf_ptr;
-
-	/* Node address */
-	addrptr = (u16 *) dev->dev_addr;
-	*suptr++ = addrptr[0];
-	*suptr++ = addrptr[1];
-	*suptr++ = addrptr[2];
-
-	/* broadcast address */
-	*suptr++ = 0xffff;
-	*suptr++ = 0xffff;
-	*suptr++ = 0xffff;
-
-	/* fit the multicast address */
-	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
-		addrptr = (u16 *) mcptr->dmi_addr;
-		*suptr++ = addrptr[0];
-		*suptr++ = addrptr[1];
-		*suptr++ = addrptr[2];
-	}
-
-	for (; i<14; i++) {
-		*suptr++ = 0xffff;
-		*suptr++ = 0xffff;
-		*suptr++ = 0xffff;
-	}
-
-	/* prepare the setup frame */
-	db->tx_insert_ptr = txptr->next_tx_desc;
-	txptr->tdes1 = cpu_to_le32(0x890000c0);
-
-	/* Resource Check and Send the setup packet */
-	if (!db->tx_packet_cnt) {
-		/* Resource Empty */
-		db->tx_packet_cnt++;
-		txptr->tdes0 = cpu_to_le32(0x80000000);
-		update_cr6(db->cr6_data | 0x2000, dev->base_addr);
-		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
-		update_cr6(db->cr6_data, dev->base_addr);
-		dev->trans_start = jiffies;
-	} else
-		db->tx_queue_cnt++;	/* Put in TX queue */
-}
-
-
-/*
- *	Allocate rx buffer,
- *	As possible as allocate maxiumn Rx buffer
- */
-
-static void allocate_rx_buffer(struct dmfe_board_info *db)
-{
-	struct rx_desc *rxptr;
-	struct sk_buff *skb;
-
-	rxptr = db->rx_insert_ptr;
-
-	while(db->rx_avail_cnt < RX_DESC_CNT) {
-		if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
-			break;
-		rxptr->rx_skb_ptr = skb; /* FIXME (?) */
-		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
-		wmb();
-		rxptr->rdes0 = cpu_to_le32(0x80000000);
-		rxptr = rxptr->next_rx_desc;
-		db->rx_avail_cnt++;
-	}
-
-	db->rx_insert_ptr = rxptr;
-}
-
-
-/*
- *	Read one word data from the serial ROM
- */
-
-static u16 read_srom_word(long ioaddr, int offset)
-{
-	int i;
-	u16 srom_data = 0;
-	long cr9_ioaddr = ioaddr + DCR9;
-
-	outl(CR9_SROM_READ, cr9_ioaddr);
-	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
-
-	/* Send the Read Command 110b */
-	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
-	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
-	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
-
-	/* Send the offset */
-	for (i = 5; i >= 0; i--) {
-		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
-		SROM_CLK_WRITE(srom_data, cr9_ioaddr);
-	}
-
-	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
-
-	for (i = 16; i > 0; i--) {
-		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
-		udelay(5);
-		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
-		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
-		udelay(5);
-	}
-
-	outl(CR9_SROM_READ, cr9_ioaddr);
-	return srom_data;
-}
-
-
-/*
- *	Auto sense the media mode
- */
-
-static u8 dmfe_sense_speed(struct dmfe_board_info * db)
-{
-	u8 ErrFlag = 0;
-	u16 phy_mode;
-
-	/* CR6 bit18=0, select 10/100M */
-	update_cr6( (db->cr6_data & ~0x40000), db->ioaddr);
-
-	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
-
-	if ( (phy_mode & 0x24) == 0x24 ) {
-		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
-			phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
-		else 				/* DM9102/DM9102A */
-			phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;
-		/* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
-		switch (phy_mode) {
-		case 0x1000: db->op_mode = DMFE_10MHF; break;
-		case 0x2000: db->op_mode = DMFE_10MFD; break;
-		case 0x4000: db->op_mode = DMFE_100MHF; break;
-		case 0x8000: db->op_mode = DMFE_100MFD; break;
-		default: db->op_mode = DMFE_10MHF;
-			ErrFlag = 1;
-			break;
-		}
-	} else {
-		db->op_mode = DMFE_10MHF;
-		DMFE_DBUG(0, "Link Failed :", phy_mode);
-		ErrFlag = 1;
-	}
-
-	return ErrFlag;
-}
-
-
-/*
- *	Set 10/100 phyxcer capability
- *	AUTO mode : phyxcer register4 is NIC capability
- *	Force mode: phyxcer register4 is the force media
- */
-
-static void dmfe_set_phyxcer(struct dmfe_board_info *db)
-{
-	u16 phy_reg;
-
-	/* Select 10/100M phyxcer */
-	db->cr6_data &= ~0x40000;
-	update_cr6(db->cr6_data, db->ioaddr);
-
-	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
-	if (db->chip_id == PCI_DM9009_ID) {
-		phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
-		phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);
-	}
-
-	/* Phyxcer capability setting */
-	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
-
-	if (db->media_mode & DMFE_AUTO) {
-		/* AUTO Mode */
-		phy_reg |= db->PHY_reg4;
-	} else {
-		/* Force Mode */
-		switch(db->media_mode) {
-		case DMFE_10MHF: phy_reg |= 0x20; break;
-		case DMFE_10MFD: phy_reg |= 0x40; break;
-		case DMFE_100MHF: phy_reg |= 0x80; break;
-		case DMFE_100MFD: phy_reg |= 0x100; break;
-		}
-		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
-	}
-
-  	/* Write new capability to Phyxcer Reg4 */
-	if ( !(phy_reg & 0x01e0)) {
-		phy_reg|=db->PHY_reg4;
-		db->media_mode|=DMFE_AUTO;
-	}
-	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
-
- 	/* Restart Auto-Negotiation */
-	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
-		phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
-	if ( !db->chip_type )
-		phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
-}
-
-
-/*
- *	Process op-mode
- *	AUTO mode : PHY controller in Auto-negotiation Mode
- *	Force mode: PHY controller in force mode with HUB
- *			N-way force capability with SWITCH
- */
-
-static void dmfe_process_mode(struct dmfe_board_info *db)
-{
-	u16 phy_reg;
-
-	/* Full Duplex Mode Check */
-	if (db->op_mode & 0x4)
-		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
-	else
-		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
-
-	/* Transciver Selection */
-	if (db->op_mode & 0x10)		/* 1M HomePNA */
-		db->cr6_data |= 0x40000;/* External MII select */
-	else
-		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */
-
-	update_cr6(db->cr6_data, db->ioaddr);
-
-	/* 10/100M phyxcer force mode need */
-	if ( !(db->media_mode & 0x18)) {
-		/* Forece Mode */
-		phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
-		if ( !(phy_reg & 0x1) ) {
-			/* parter without N-Way capability */
-			phy_reg = 0x0;
-			switch(db->op_mode) {
-			case DMFE_10MHF: phy_reg = 0x0; break;
-			case DMFE_10MFD: phy_reg = 0x100; break;
-			case DMFE_100MHF: phy_reg = 0x2000; break;
-			case DMFE_100MFD: phy_reg = 0x2100; break;
-			}
-			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
-       			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
-				mdelay(20);
-			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
-		}
-	}
-}
-
-
-/*
- *	Write a word to Phy register
- */
-
-static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
-{
-	u16 i;
-	unsigned long ioaddr;
-
-	if (chip_id == PCI_DM9132_ID) {
-		ioaddr = iobase + 0x80 + offset * 4;
-		outw(phy_data, ioaddr);
-	} else {
-		/* DM9102/DM9102A Chip */
-		ioaddr = iobase + DCR9;
-
-		/* Send 33 synchronization clock to Phy controller */
-		for (i = 0; i < 35; i++)
-			phy_write_1bit(ioaddr, PHY_DATA_1);
-
-		/* Send start command(01) to Phy */
-		phy_write_1bit(ioaddr, PHY_DATA_0);
-		phy_write_1bit(ioaddr, PHY_DATA_1);
-
-		/* Send write command(01) to Phy */
-		phy_write_1bit(ioaddr, PHY_DATA_0);
-		phy_write_1bit(ioaddr, PHY_DATA_1);
-
-		/* Send Phy addres */
-		for (i = 0x10; i > 0; i = i >> 1)
-			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
-
-		/* Send register addres */
-		for (i = 0x10; i > 0; i = i >> 1)
-			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
-
-		/* written trasnition */
-		phy_write_1bit(ioaddr, PHY_DATA_1);
-		phy_write_1bit(ioaddr, PHY_DATA_0);
-
-		/* Write a word data to PHY controller */
-		for ( i = 0x8000; i > 0; i >>= 1)
-			phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
-	}
-}
-
-
-/*
- *	Read a word data from phy register
- */
-
-static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
-{
-	int i;
-	u16 phy_data;
-	unsigned long ioaddr;
-
-	if (chip_id == PCI_DM9132_ID) {
-		/* DM9132 Chip */
-		ioaddr = iobase + 0x80 + offset * 4;
-		phy_data = inw(ioaddr);
-	} else {
-		/* DM9102/DM9102A Chip */
-		ioaddr = iobase + DCR9;
-
-		/* Send 33 synchronization clock to Phy controller */
-		for (i = 0; i < 35; i++)
-			phy_write_1bit(ioaddr, PHY_DATA_1);
-
-		/* Send start command(01) to Phy */
-		phy_write_1bit(ioaddr, PHY_DATA_0);
-		phy_write_1bit(ioaddr, PHY_DATA_1);
-
-		/* Send read command(10) to Phy */
-		phy_write_1bit(ioaddr, PHY_DATA_1);
-		phy_write_1bit(ioaddr, PHY_DATA_0);
-
-		/* Send Phy addres */
-		for (i = 0x10; i > 0; i = i >> 1)
-			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
-
-		/* Send register addres */
-		for (i = 0x10; i > 0; i = i >> 1)
-			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
-
-		/* Skip transition state */
-		phy_read_1bit(ioaddr);
-
-		/* read 16bit data */
-		for (phy_data = 0, i = 0; i < 16; i++) {
-			phy_data <<= 1;
-			phy_data |= phy_read_1bit(ioaddr);
-		}
-	}
-
-	return phy_data;
-}
-
-
-/*
- *	Write one bit data to Phy Controller
- */
-
-static void phy_write_1bit(unsigned long ioaddr, u32 phy_data)
-{
-	outl(phy_data, ioaddr);			/* MII Clock Low */
-	udelay(1);
-	outl(phy_data | MDCLKH, ioaddr);	/* MII Clock High */
-	udelay(1);
-	outl(phy_data, ioaddr);			/* MII Clock Low */
-	udelay(1);
-}
-
-
-/*
- *	Read one bit phy data from PHY controller
- */
-
-static u16 phy_read_1bit(unsigned long ioaddr)
-{
-	u16 phy_data;
-
-	outl(0x50000, ioaddr);
-	udelay(1);
-	phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
-	outl(0x40000, ioaddr);
-	udelay(1);
-
-	return phy_data;
-}
-
-
-/*
- *	Calculate the CRC valude of the Rx packet
- *	flag = 	1 : return the reverse CRC (for the received packet CRC)
- *		0 : return the normal CRC (for Hash Table index)
- */
-
-static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
-{
-	u32 crc = crc32(~0, Data, Len);
-	if (flag) crc = ~crc;
-	return crc;
-}
-
-
-/*
- *	Parser SROM and media mode
- */
-
-static void dmfe_parse_srom(struct dmfe_board_info * db)
-{
-	char * srom = db->srom;
-	int dmfe_mode, tmp_reg;
-
-	DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
-
-	/* Init CR15 */
-	db->cr15_data = CR15_DEFAULT;
-
-	/* Check SROM Version */
-	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
-		/* SROM V4.01 */
-		/* Get NIC support media mode */
-		db->NIC_capability = le16_to_cpup(srom + 34);
-		db->PHY_reg4 = 0;
-		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
-			switch( db->NIC_capability & tmp_reg ) {
-			case 0x1: db->PHY_reg4 |= 0x0020; break;
-			case 0x2: db->PHY_reg4 |= 0x0040; break;
-			case 0x4: db->PHY_reg4 |= 0x0080; break;
-			case 0x8: db->PHY_reg4 |= 0x0100; break;
-			}
-		}
-
-		/* Media Mode Force or not check */
-		dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36);
-		switch(dmfe_mode) {
-		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
-		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
-		case 0x8: dmfe_media_mode = DMFE_100MFD; break;	/* 100MFD */
-		case 0x100:
-		case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */
-		}
-
-		/* Special Function setting */
-		/* VLAN function */
-		if ( (SF_mode & 0x1) || (srom[43] & 0x80) )
-			db->cr15_data |= 0x40;
-
-		/* Flow Control */
-		if ( (SF_mode & 0x2) || (srom[40] & 0x1) )
-			db->cr15_data |= 0x400;
-
-		/* TX pause packet */
-		if ( (SF_mode & 0x4) || (srom[40] & 0xe) )
-			db->cr15_data |= 0x9800;
-	}
-
-	/* Parse HPNA parameter */
-	db->HPNA_command = 1;
-
-	/* Accept remote command or not */
-	if (HPNA_rx_cmd == 0)
-		db->HPNA_command |= 0x8000;
-
-	 /* Issue remote command & operation mode */
-	if (HPNA_tx_cmd == 1)
-		switch(HPNA_mode) {	/* Issue Remote Command */
-		case 0: db->HPNA_command |= 0x0904; break;
-		case 1: db->HPNA_command |= 0x0a00; break;
-		case 2: db->HPNA_command |= 0x0506; break;
-		case 3: db->HPNA_command |= 0x0602; break;
-		}
-	else
-		switch(HPNA_mode) {	/* Don't Issue */
-		case 0: db->HPNA_command |= 0x0004; break;
-		case 1: db->HPNA_command |= 0x0000; break;
-		case 2: db->HPNA_command |= 0x0006; break;
-		case 3: db->HPNA_command |= 0x0002; break;
-		}
-
-	/* Check DM9801 or DM9802 present or not */
-	db->HPNA_present = 0;
-	update_cr6(db->cr6_data|0x40000, db->ioaddr);
-	tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
-	if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
-		/* DM9801 or DM9802 present */
-		db->HPNA_timer = 8;
-		if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
-			/* DM9801 HomeRun */
-			db->HPNA_present = 1;
-			dmfe_program_DM9801(db, tmp_reg);
-		} else {
-			/* DM9802 LongRun */
-			db->HPNA_present = 2;
-			dmfe_program_DM9802(db);
-		}
-	}
-
-}
-
-
-/*
- *	Init HomeRun DM9801
- */
-
-static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
-{
-	uint reg17, reg25;
-
-	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
-	switch(HPNA_rev) {
-	case 0xb900: /* DM9801 E3 */
-		db->HPNA_command |= 0x1000;
-		reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
-		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
-		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
-		break;
-	case 0xb901: /* DM9801 E4 */
-		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
-		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
-		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
-		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
-		break;
-	case 0xb902: /* DM9801 E5 */
-	case 0xb903: /* DM9801 E6 */
-	default:
-		db->HPNA_command |= 0x1000;
-		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
-		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
-		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
-		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
-		break;
-	}
-	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-	phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
-	phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
-}
-
-
-/*
- *	Init HomeRun DM9802
- */
-
-static void dmfe_program_DM9802(struct dmfe_board_info * db)
-{
-	uint phy_reg;
-
-	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
-	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-	phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
-	phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
-	phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
-}
-
-
-/*
- *	Check remote HPNA power and speed status. If not correct,
- *	issue command again.
-*/
-
-static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
-{
-	uint phy_reg;
-
-	/* Got remote device status */
-	phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
-	switch(phy_reg) {
-	case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
-	case 0x20: phy_reg = 0x0900;break; /* LP/HS */
-	case 0x40: phy_reg = 0x0600;break; /* HP/LS */
-	case 0x60: phy_reg = 0x0500;break; /* HP/HS */
-	}
-
-	/* Check remote device status match our setting ot not */
-	if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
-		phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
-		db->HPNA_timer=8;
-	} else
-		db->HPNA_timer=600;	/* Match, every 10 minutes, check */
-}
-
-
-
-static struct pci_device_id dmfe_pci_tbl[] __devinitdata = {
-	{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
-	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
-	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
-	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
-
-
-static struct pci_driver dmfe_driver = {
-	name:		"dmfe",
-	id_table:	dmfe_pci_tbl,
-	probe:		dmfe_init_one,
-	remove:		dmfe_remove_one,
-};
-
-MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
-MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(debug, "i");
-MODULE_PARM(mode, "i");
-MODULE_PARM(cr6set, "i");
-MODULE_PARM(chkmode, "i");
-MODULE_PARM(HPNA_mode, "i");
-MODULE_PARM(HPNA_rx_cmd, "i");
-MODULE_PARM(HPNA_tx_cmd, "i");
-MODULE_PARM(HPNA_NoiseFloor, "i");
-MODULE_PARM(SF_mode, "i");
-MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
-MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
-MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
-
-/*	Description:
- *	when user used insmod to add module, system invoked init_module()
- *	to initilize and register.
- */
-
-static int __init dmfe_init_module(void)
-{
-	int rc;
-
-	printk(version);
-	printed_version = 1;
-
-	DMFE_DBUG(0, "init_module() ", debug);
-
-	if (debug)
-		dmfe_debug = debug;	/* set debug flag */
-	if (cr6set)
-		dmfe_cr6_user_set = cr6set;
-
- 	switch(mode) {
-   	case DMFE_10MHF:
-	case DMFE_100MHF:
-	case DMFE_10MFD:
-	case DMFE_100MFD:
-	case DMFE_1M_HPNA:
-		dmfe_media_mode = mode;
-		break;
-	default:dmfe_media_mode = DMFE_AUTO;
-		break;
-	}
-
-	if (HPNA_mode > 4)
-		HPNA_mode = 0;		/* Default: LP/HS */
-	if (HPNA_rx_cmd > 1)
-		HPNA_rx_cmd = 0;	/* Default: Ignored remote cmd */
-	if (HPNA_tx_cmd > 1)
-		HPNA_tx_cmd = 0;	/* Default: Don't issue remote cmd */
-	if (HPNA_NoiseFloor > 15)
-		HPNA_NoiseFloor = 0;
-
-	rc = pci_module_init(&dmfe_driver);
-	if (rc < 0)
-		return rc;
-
-	return 0;
-}
-
-
-/*
- *	Description:
- *	when user used rmmod to delete module, system invoked clean_module()
- *	to un-register all registered services.
- */
-
-static void __exit dmfe_cleanup_module(void)
-{
-	DMFE_DBUG(0, "dmfe_clean_module() ", debug);
-	pci_unregister_driver(&dmfe_driver);
-}
-
-module_init(dmfe_init_module);
-module_exit(dmfe_cleanup_module);
diff -urN linux-2.5.6-pre3/drivers/net/e100/Makefile linux-2.5.6/drivers/net/e100/Makefile
--- linux-2.5.6-pre3/drivers/net/e100/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/Makefile	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,16 @@
+#
+# Makefile for the Intel's E100 ethernet driver
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := e100.o
+
+obj-y   := e100_main.o e100_config.o e100_proc.o e100_phy.o \
+	   e100_eeprom.o
+obj-m   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100.h linux-2.5.6/drivers/net/e100/e100.h
--- linux-2.5.6-pre3/drivers/net/e100/e100.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100.h	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,1033 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _E100_INC_
+#define _E100_INC_
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <asm/processor.h>
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#include <linux/inetdevice.h>
+#endif
+
+#include <linux/if.h>
+#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
+#include <linux/ip.h>
+
+/*
+ *  Configure parameters for buffers per controller.
+ *  If the machine this is being used on is a faster machine (i.e. > 150MHz)
+ *  and running on a 10MBS network then more queueing of data occurs. This
+ *  may indicate the some of the numbers below should be adjusted.  Here are
+ *  some typical numbers:
+ *                             MAX_TCB 64
+ *                             MAX_RFD 64
+ *  The default numbers give work well on most systems tests so no real
+ *  adjustments really need to take place.  Also, if the machine is connected
+ *  to a 100MBS network the numbers described above can be lowered from the
+ *  defaults as considerably less data will be queued.
+ */
+
+#define MAX_TCB        64	/* number of transmit control blocks */
+#define MAX_TBD        MAX_TCB
+#define TX_FRAME_CNT   8	/* consecutive transmit frames per interrupt */
+/* TX_FRAME_CNT must be less than MAX_TCB    */
+#define MAX_RFD      64
+
+#define E100_DEFAULT_TCB   MAX_TCB
+#define E100_MIN_TCB       2*TX_FRAME_CNT + 3	/* make room for at least 2 interrupts */
+
+#ifdef __ia64__
+ /* We can't use too many DMAble buffers on IA64 machines with >4 GB mem */
+#define E100_MAX_TCB       64
+#else
+#define E100_MAX_TCB       1024
+#endif /*  __ia64__ */
+
+#define E100_DEFAULT_RFD   MAX_RFD
+#define E100_MIN_RFD       8
+
+#ifdef __ia64__
+ /* We can't use too many DMAble buffers on IA64 machines with >4 GB mem */
+#define E100_MAX_RFD       64
+#else
+#define E100_MAX_RFD       1024
+#endif /*  __ia64__ */
+
+#define E100_DEFAULT_XSUM         true
+#define E100_DEFAULT_BER          ZLOCK_MAX_ERRORS
+#define E100_DEFAULT_SPEED_DUPLEX 0
+#define E100_DEFAULT_FC           0
+#define E100_DEFAULT_IFS          true
+#define E100_DEFAULT_UCODE        true
+
+#define TX_THRSHLD     8
+
+/* sleep time is at least 50 ms, in jiffies */
+#define SLEEP_TIME ((HZ / 20) + 1)
+#define CUS_TIMEOUT 1000
+
+/* IFS parameters */
+#define MIN_NUMBER_OF_TRANSMITS_100 1000
+#define MIN_NUMBER_OF_TRANSMITS_10  100
+
+#define E100_MAX_NIC 16
+
+#define E100_MAX_BUSY_WAIT 50	/*Max udelays in wait_scb and wait_cus_idle */
+
+/* CPUSAVER_BUNDLE_MAX: Sets the maximum number of frames that will be bundled.
+ * In some situations, such as the TCP windowing algorithm, it may be
+ * better to limit the growth of the bundle size than let it go as
+ * high as it can, because that could cause too much added latency.
+ * The default is six, because this is the number of packets in the
+ * default TCP window size.  A value of 1 would make CPUSaver indicate
+ * an interrupt for every frame received.  If you do not want to put
+ * a limit on the bundle size, set this value to xFFFF.
+ */
+#define E100_DEFAULT_CPUSAVER_BUNDLE_MAX	6
+#define E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY	0x600
+#define E100_DEFAULT_BUNDLE_SMALL_FR		false
+#define E100_DEFAULT_RX_CONGESTION_CONTROL	true
+
+/* end of configurables */
+
+/* ====================================================================== */
+/*                                hw                                      */
+/* ====================================================================== */
+
+/* timeout for command completion */
+#define E100_CMD_WAIT   100	/* iterations */
+
+struct driver_stats {
+	struct net_device_stats net_stats;
+
+	unsigned long tx_late_col;
+	unsigned long tx_ok_defrd;
+	unsigned long tx_one_retry;
+	unsigned long tx_mt_one_retry;
+	unsigned long rcv_cdt_frames;
+	unsigned long xmt_fc_pkts;
+	unsigned long rcv_fc_pkts;
+	unsigned long rcv_fc_unsupported;
+	unsigned long xmt_tco_pkts;
+	unsigned long rcv_tco_pkts;
+	unsigned long rx_intr_pkts;
+	unsigned long rx_tasklet_pkts;
+	unsigned long poll_intr_switch;
+};
+
+/* TODO: kill me when we can do C99 */
+#define false		(0)
+#define true		(1)
+
+/* Changed for 82558 and 82559 enhancements */
+/* defines for 82558/9 flow control CSR values */
+#define DFLT_FC_THLD       0x00	/* Rx FIFO threshold of 0.5KB free  */
+#define DFLT_FC_CMD        0x00	/* FC Command in CSR */
+
+/* ====================================================================== */
+/*                              equates                                   */
+/* ====================================================================== */
+
+/*
+ * These are general purpose defines 
+ */
+
+/* Bit Mask definitions */
+#define BIT_0       0x0001
+#define BIT_1       0x0002
+#define BIT_2       0x0004
+#define BIT_3       0x0008
+#define BIT_4       0x0010
+#define BIT_5       0x0020
+#define BIT_6       0x0040
+#define BIT_7       0x0080
+#define BIT_8       0x0100
+#define BIT_9       0x0200
+#define BIT_10      0x0400
+#define BIT_11      0x0800
+#define BIT_12      0x1000
+#define BIT_13      0x2000
+#define BIT_14      0x4000
+#define BIT_15      0x8000
+#define BIT_28      0x10000000
+
+#define BIT_0_2     0x0007
+#define BIT_0_3     0x000F
+#define BIT_0_4     0x001F
+#define BIT_0_5     0x003F
+#define BIT_0_6     0x007F
+#define BIT_0_7     0x00FF
+#define BIT_0_8     0x01FF
+#define BIT_0_13    0x3FFF
+#define BIT_0_15    0xFFFF
+#define BIT_1_2     0x0006
+#define BIT_1_3     0x000E
+#define BIT_2_5     0x003C
+#define BIT_3_4     0x0018
+#define BIT_4_5     0x0030
+#define BIT_4_6     0x0070
+#define BIT_4_7     0x00F0
+#define BIT_5_7     0x00E0
+#define BIT_5_12    0x1FE0
+#define BIT_5_15    0xFFE0
+#define BIT_6_7     0x00c0
+#define BIT_7_11    0x0F80
+#define BIT_8_10    0x0700
+#define BIT_9_13    0x3E00
+#define BIT_12_15   0xF000
+#define BIT_8_15    0xFF00
+
+#define BIT_16_20   0x001F0000
+#define BIT_21_25   0x03E00000
+#define BIT_26_27   0x0C000000
+
+/* Transmit Threshold related constants */
+#define DEFAULT_TX_PER_UNDERRUN         20000
+
+#define MAX_MULTICAST_ADDRS             64
+#define MAX_FILTER                      16
+
+#define FULL_DUPLEX      2
+#define HALF_DUPLEX      1
+
+/*
+ * These defines are specific to the 82557 
+ */
+
+/* E100 PORT functions -- lower 4 bits */
+#define PORT_SOFTWARE_RESET         0
+#define PORT_SELFTEST               1
+#define PORT_SELECTIVE_RESET        2
+#define PORT_DUMP                   3
+
+/* SCB Status Word bit definitions */
+/* Interrupt status/ack fields */
+/* ER and FCP interrupts for 82558 masks  */
+#define SCB_STATUS_ACK_MASK        BIT_8_15	/* Status Mask */
+#define SCB_STATUS_ACK_CX          BIT_15	/* CU Completed Action Cmd */
+#define SCB_STATUS_ACK_FR          BIT_14	/* RU Received A Frame */
+#define SCB_STATUS_ACK_CNA         BIT_13	/* CU Became Inactive (IDLE) */
+#define SCB_STATUS_ACK_RNR         BIT_12	/* RU Became Not Ready */
+#define SCB_STATUS_ACK_MDI         BIT_11	/* MDI read or write done */
+#define SCB_STATUS_ACK_SWI         BIT_10	/* S/W generated interrupt */
+#define SCB_STATUS_ACK_ER          BIT_9	/* Early Receive */
+#define SCB_STATUS_ACK_FCP         BIT_8	/* Flow Control Pause */
+
+/*- CUS Fields */
+#define SCB_CUS_MASK            (BIT_6 | BIT_7)	/* CUS 2-bit Mask */
+#define SCB_CUS_IDLE            0	/* CU Idle */
+#define SCB_CUS_SUSPEND         BIT_6	/* CU Suspended */
+#define SCB_CUS_ACTIVE          BIT_7	/* CU Active */
+
+/*- RUS Fields */
+#define SCB_RUS_IDLE            0	/* RU Idle */
+#define SCB_RUS_MASK            BIT_2_5	/* RUS 3-bit Mask */
+#define SCB_RUS_SUSPEND         BIT_2	/* RU Suspended */
+#define SCB_RUS_NO_RESOURCES    BIT_3	/* RU Out Of Resources */
+#define SCB_RUS_READY           BIT_4	/* RU Ready */
+#define SCB_RUS_SUSP_NO_RBDS    (BIT_2 | BIT_5)	/* RU No More RBDs */
+#define SCB_RUS_NO_RBDS         (BIT_3 | BIT_5)	/* RU No More RBDs */
+#define SCB_RUS_READY_NO_RBDS   (BIT_4 | BIT_5)	/* RU Ready, No RBDs */
+
+/* SCB Command Word bit definitions */
+/*- CUC fields */
+/* Changing mask to 4 bits */
+#define SCB_CUC_MASK            BIT_4_7	/* CUC 4-bit Mask */
+#define SCB_CUC_NOOP            0
+#define SCB_CUC_START           BIT_4	/* CU Start */
+#define SCB_CUC_RESUME          BIT_5	/* CU Resume */
+/* Changed for 82558 enhancements */
+#define SCB_CUC_STATIC_RESUME   (BIT_5 | BIT_7)	/* 82558/9 Static Resume */
+#define SCB_CUC_DUMP_ADDR       BIT_6	/* CU Dump Counters Address */
+#define SCB_CUC_DUMP_STAT       (BIT_4 | BIT_6)	/* CU Dump stat. counters */
+#define SCB_CUC_LOAD_BASE       (BIT_5 | BIT_6)	/* Load the CU base */
+/* Below was defined as BIT_4_7 */
+#define SCB_CUC_DUMP_RST_STAT   BIT_4_6	/* CU Dump & reset statistics cntrs */
+
+/*- RUC fields */
+#define SCB_RUC_MASK            BIT_0_2	/* RUC 3-bit Mask */
+#define SCB_RUC_START           BIT_0	/* RU Start */
+#define SCB_RUC_RESUME          BIT_1	/* RU Resume */
+#define SCB_RUC_ABORT           BIT_2	/* RU Abort */
+#define SCB_RUC_LOAD_HDS        (BIT_0 | BIT_2)	/* Load RFD Header Data Size */
+#define SCB_RUC_LOAD_BASE       (BIT_1 | BIT_2)	/* Load the RU base */
+#define SCB_RUC_RBD_RESUME      BIT_0_2	/* RBD resume */
+
+/* Interrupt fields (assuming byte addressing) */
+#define SCB_INT_MASK            BIT_0	/* Mask interrupts */
+#define SCB_SOFT_INT            BIT_1	/* Generate a S/W interrupt */
+/*  Specific Interrupt Mask Bits (upper byte of SCB Command word) */
+#define SCB_FCP_INT_MASK        BIT_2	/* Flow Control Pause */
+#define SCB_ER_INT_MASK         BIT_3	/* Early Receive */
+#define SCB_RNR_INT_MASK        BIT_4	/* RU Not Ready */
+#define SCB_CNA_INT_MASK        BIT_5	/* CU Not Active */
+#define SCB_FR_INT_MASK         BIT_6	/* Frame Received */
+#define SCB_CX_INT_MASK         BIT_7	/* CU eXecution w/ I-bit done */
+#define SCB_BACHELOR_INT_MASK   BIT_2_7	/* 82558 interrupt mask bits */
+
+#define SCB_GCR2_EEPROM_ACCESS_SEMAPHORE BIT_7
+
+/* EEPROM bit definitions */
+/*- EEPROM control register bits */
+#define EN_TRNF          0x10	/* Enable turnoff */
+#define EEDO             0x08	/* EEPROM data out */
+#define EEDI             0x04	/* EEPROM data in (set for writing data) */
+#define EECS             0x02	/* EEPROM chip select (1=hi, 0=lo) */
+#define EESK             0x01	/* EEPROM shift clock (1=hi, 0=lo) */
+
+/*- EEPROM opcodes */
+#define EEPROM_READ_OPCODE          06
+#define EEPROM_WRITE_OPCODE         05
+#define EEPROM_ERASE_OPCODE         07
+#define EEPROM_EWEN_OPCODE          19	/* Erase/write enable */
+#define EEPROM_EWDS_OPCODE          16	/* Erase/write disable */
+
+/*- EEPROM data locations */
+#define EEPROM_NODE_ADDRESS_BYTE_0      0
+#define EEPROM_COMPATIBILITY_WORD       3
+#define EEPROM_PWA_NO                   8
+#define EEPROM_ID_WORD			0x0A
+
+#define EEPROM_SUM                      0xbaba
+
+// Zero Locking Algorithm definitions:
+#define ZLOCK_ZERO_MASK		0x00F0
+#define ZLOCK_MAX_READS		50	
+#define ZLOCK_SET_ZERO		0x2010
+#define ZLOCK_MAX_SLEEP		300 * HZ	
+#define ZLOCK_MAX_ERRORS	300
+
+/* E100 Action Commands */
+#define CB_IA_ADDRESS           1
+#define CB_CONFIGURE            2
+#define CB_MULTICAST            3
+#define CB_TRANSMIT             4
+#define CB_LOAD_MICROCODE       5
+#define CB_LOAD_FILTER		8
+#define CB_MAX_NONTX_CMD        9
+#define CB_IPCB_TRANSMIT        9
+
+/* Pre-defined Filter Bits */
+#define CB_FILTER_EL            0x80000000
+#define CB_FILTER_FIX           0x40000000
+#define CB_FILTER_ARP           0x08000000
+#define CB_FILTER_IA_MATCH      0x02000000
+
+/* Command Block (CB) Field Definitions */
+/*- CB Command Word */
+#define CB_EL_BIT           BIT_15	/* CB EL Bit */
+#define CB_S_BIT            BIT_14	/* CB Suspend Bit */
+#define CB_I_BIT            BIT_13	/* CB Interrupt Bit */
+#define CB_TX_SF_BIT        BIT_3	/* TX CB Flexible Mode */
+#define CB_CMD_MASK         BIT_0_3	/* CB 4-bit CMD Mask */
+#define CB_CID_DEFAULT      (0x1f << 8)	/* CB 5-bit CID (max value) */
+
+/*- CB Status Word */
+#define CB_STATUS_MASK          BIT_12_15	/* CB Status Mask (4-bits) */
+#define CB_STATUS_COMPLETE      BIT_15	/* CB Complete Bit */
+#define CB_STATUS_OK            BIT_13	/* CB OK Bit */
+#define CB_STATUS_UNDERRUN      BIT_12	/* CB A Bit */
+#define CB_STATUS_FAIL          BIT_11	/* CB Fail (F) Bit */
+
+/*misc command bits */
+#define CB_TX_EOF_BIT           BIT_15	/* TX CB/TBD EOF Bit */
+
+/* Config params */
+#define CB_CFIG_BYTE_COUNT          22	/* 22 config bytes */
+#define CB_CFIG_D102_BYTE_COUNT    10
+
+/* Receive Frame Descriptor Fields */
+
+/*- RFD Status Bits */
+#define RFD_RECEIVE_COLLISION   BIT_0	/* Collision detected on Receive */
+#define RFD_IA_MATCH            BIT_1	/* Indv Address Match Bit */
+#define RFD_RX_ERR              BIT_4	/* RX_ERR pin on Phy was set */
+#define RFD_FRAME_TOO_SHORT     BIT_7	/* Receive Frame Short */
+#define RFD_DMA_OVERRUN         BIT_8	/* Receive DMA Overrun */
+#define RFD_NO_RESOURCES        BIT_9	/* No Buffer Space */
+#define RFD_ALIGNMENT_ERROR     BIT_10	/* Alignment Error */
+#define RFD_CRC_ERROR           BIT_11	/* CRC Error */
+#define RFD_STATUS_OK           BIT_13	/* RFD OK Bit */
+#define RFD_STATUS_COMPLETE     BIT_15	/* RFD Complete Bit */
+
+/*- RFD Command Bits*/
+#define RFD_EL_BIT      BIT_15	/* RFD EL Bit */
+#define RFD_S_BIT       BIT_14	/* RFD Suspend Bit */
+#define RFD_H_BIT       BIT_4	/* Header RFD Bit */
+#define RFD_SF_BIT      BIT_3	/* RFD Flexible Mode */
+
+/*- RFD misc bits*/
+#define RFD_EOF_BIT         BIT_15	/* RFD End-Of-Frame Bit */
+#define RFD_F_BIT           BIT_14	/* RFD Buffer Fetch Bit */
+#define RFD_ACT_COUNT_MASK  BIT_0_13	/* RFD Actual Count Mask */
+
+/* Receive Buffer Descriptor Fields*/
+#define RBD_EOF_BIT             BIT_15	/* RBD End-Of-Frame Bit */
+#define RBD_F_BIT               BIT_14	/* RBD Buffer Fetch Bit */
+#define RBD_ACT_COUNT_MASK      BIT_0_13	/* RBD Actual Count Mask */
+
+#define SIZE_FIELD_MASK     BIT_0_13	/* Size of the associated buffer */
+#define RBD_EL_BIT          BIT_15	/* RBD EL Bit */
+
+/* Self Test Results*/
+#define CB_SELFTEST_FAIL_BIT        BIT_12
+#define CB_SELFTEST_DIAG_BIT        BIT_5
+#define CB_SELFTEST_REGISTER_BIT    BIT_3
+#define CB_SELFTEST_ROM_BIT         BIT_2
+
+#define CB_SELFTEST_ERROR_MASK ( \
+                CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \
+                CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT)
+
+/* adapter vendor & device ids */
+#define PCI_OHIO_BOARD   0x10f0	/* subdevice ID, Ohio dual port nic */
+
+/* Values for PCI_REV_ID_REGISTER values */
+#define D101A4_REV_ID      4	/* 82558 A4 stepping */
+#define D101B0_REV_ID      5	/* 82558 B0 stepping */
+#define D101MA_REV_ID      8	/* 82559 A0 stepping */
+#define D101S_REV_ID      9	/* 82559S A-step */
+#define D102_REV_ID      12
+#define D102C_REV_ID     13	/* 82550 step C */
+#define D102E_REV_ID     15
+
+/* ############Start of 82555 specific defines################## */
+
+#define PHY_82555_LED_SWITCH_CONTROL    	0x1b	/* 82555 led switch control register */
+
+/* 82555 led switch control reg. opcodes */
+#define PHY_82555_LED_NORMAL_CONTROL    0	// control back to the 8255X
+#define PHY_82555_LED_DRIVER_CONTROL    BIT_2	// the driver is in control
+#define PHY_82555_LED_OFF               BIT_2	// activity LED is off
+#define PHY_82555_LED_ON_559           (BIT_0 | BIT_2)	// activity LED is on for 559 and later
+#define PHY_82555_LED_ON_PRE_559       (BIT_0 | BIT_1 | BIT_2)	// activity LED is on for 558 and before
+
+// Describe the state of the phy led.
+// needed for the function : 'e100_blink_timer'
+enum led_state_e {
+	LED_OFF = 0,
+	LED_ON,
+};
+
+/* ############End of 82555 specific defines##################### */
+
+#define RFD_PARSE_BIT			BIT_3
+#define RFD_TCP_PACKET			0x00
+#define RFD_UDP_PACKET			0x01
+#define TCPUDP_CHECKSUM_BIT_VALID	BIT_4
+#define TCPUDP_CHECKSUM_VALID		BIT_5
+#define CHECKSUM_PROTOCOL_MASK		0x03
+
+#define VLAN_SIZE   4
+#define CHKSUM_SIZE 2
+#define RFD_DATA_SIZE (ETH_FRAME_LEN + CHKSUM_SIZE + VLAN_SIZE)
+
+/* Bits for bdp->flags */
+#define DF_LINK_FC_CAP     0x00000001	/* Link is flow control capable */
+#define DF_CSUM_OFFLOAD    0x00000002
+#define DF_UCODE_LOADED    0x00000004
+#define USE_IPCB           0x00000008	/* set if using ipcb for transmits */
+#define IS_BACHELOR        0x00000010	/* set if 82558 or newer board */
+#define IS_ICH             0x00000020
+#define DF_SPEED_FORCED    0x00000040	/* set if speed is forced */
+
+typedef struct net_device_stats net_dev_stats_t;
+
+/* needed macros */
+/* These macros use the bdp pointer. If you use them it better be defined */
+#define PREV_TCB_USED(X)  ((X).tail ? (X).tail - 1 : bdp->params.TxDescriptors - 1)
+#define NEXT_TCB_TOUSE(X) ((((X) + 1) >= bdp->params.TxDescriptors) ? 0 : (X) + 1)
+#define TCB_TO_USE(X)     ((X).tail)
+#define TCBS_AVAIL(X)     (NEXT_TCB_TOUSE( NEXT_TCB_TOUSE((X).tail)) != (X).head)
+
+#define RFD_POINTER(skb,bdp)      ((rfd_t *) (((unsigned char *)((skb)->data))-((bdp)->rfd_size)))
+#define SKB_RFD_STATUS(skb,bdp)   ((RFD_POINTER((skb),(bdp)))->rfd_header.cb_status)
+#define GET_SKB_DMA_ADDR(skb)		( *(dma_addr_t *)( (skb)->cb) )
+#define SET_SKB_DMA_ADDR(skb,dma_addr)	( *(dma_addr_t *)( (skb)->cb) = (dma_addr) )
+
+/* ====================================================================== */
+/*                              82557                                     */
+/* ====================================================================== */
+
+/* Changed for 82558 enhancement */
+typedef struct _d101_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+} d101_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82559 enhancement */
+typedef struct _d101m_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+	u8 scb_gen_ctrl;	/* General Control */
+	u8 scb_gen_stat;	/* General Status */
+	u16 scb_reserved;	/* Reserved */
+	u32 scb_function_event;	/* Cardbus Function Event */
+	u32 scb_function_event_mask;	/* Cardbus Function Mask */
+	u32 scb_function_present_state;	/* Cardbus Function state */
+	u32 scb_force_event;	/* Cardbus Force Event */
+} d101m_scb_ext __attribute__ ((__packed__));
+
+/* Changed for 82550 enhancement */
+typedef struct _d102_scb_ext_t {
+	u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+	u8 scb_early_rx_int;	/* Early Rx DMA byte count */
+	u8 scb_fc_thld;	/* Flow Control threshold */
+	u8 scb_fc_xon_xoff;	/* Flow Control XON/XOFF values */
+	u8 scb_pmdr;	/* Power Mgmt. Driver Reg */
+	u8 scb_gen_ctrl;	/* General Control */
+	u8 scb_gen_stat;	/* General Status */
+	u8 scb_gen_ctrl2;
+	u8 scb_reserved;	/* Reserved */
+	u32 scb_scheduling_reg;
+	u32 scb_reserved2;
+	u32 scb_function_event;	/* Cardbus Function Event */
+	u32 scb_function_event_mask;	/* Cardbus Function Mask */
+	u32 scb_function_present_state;	/* Cardbus Function state */
+	u32 scb_force_event;	/* Cardbus Force Event */
+} d102_scb_ext __attribute__ ((__packed__));
+
+/*
+ * 82557 status control block. this will be memory mapped & will hang of the
+ * the bdp, which hangs of the bdp. This is the brain of it.
+ */
+typedef struct _scb_t {
+	u16 scb_status;	/* SCB Status register */
+	u8 scb_cmd_low;	/* SCB Command register (low byte) */
+	u8 scb_cmd_hi;	/* SCB Command register (high byte) */
+	u32 scb_gen_ptr;	/* SCB General pointer */
+	u32 scb_port;	/* PORT register */
+	u16 scb_flsh_cntrl;	/* Flash Control register */
+	u16 scb_eprm_cntrl;	/* EEPROM control register */
+	u32 scb_mdi_cntrl;	/* MDI Control Register */
+	/* Changed for 82558 enhancement */
+	union {
+		u32 scb_rx_dma_cnt;	/* Rx DMA byte count */
+		d101_scb_ext d101_scb;	/* 82558/9 specific fields */
+		d101m_scb_ext d101m_scb;	/* 82559 specific fields */
+		d102_scb_ext d102_scb;
+	} scb_ext;
+} scb_t __attribute__ ((__packed__));
+
+/* Self test
+ * This is used to dump results of the self test 
+ */
+typedef struct _self_test_t {
+	u32 st_sign;	/* Self Test Signature */
+	u32 st_result;	/* Self Test Results */
+} self_test_t __attribute__ ((__packed__));
+
+/* 
+ *  Statistical Counters 
+ */
+/* 82557 counters */
+typedef struct _basic_cntr_t {
+	u32 xmt_gd_frames;	/* Good frames transmitted */
+	u32 xmt_max_coll;	/* Fatal frames -- had max collisions */
+	u32 xmt_late_coll;	/* Fatal frames -- had a late coll. */
+	u32 xmt_uruns;	/* Xmit underruns (fatal or re-transmit) */
+	u32 xmt_lost_crs;	/* Frames transmitted without CRS */
+	u32 xmt_deferred;	/* Deferred transmits */
+	u32 xmt_sngl_coll;	/* Transmits that had 1 and only 1 coll. */
+	u32 xmt_mlt_coll;	/* Transmits that had multiple coll. */
+	u32 xmt_ttl_coll;	/* Transmits that had 1+ collisions. */
+	u32 rcv_gd_frames;	/* Good frames received */
+	u32 rcv_crc_errs;	/* Aligned frames that had a CRC error */
+	u32 rcv_algn_errs;	/* Receives that had alignment errors */
+	u32 rcv_rsrc_err;	/* Good frame dropped cuz no resources */
+	u32 rcv_oruns;	/* Overrun errors - bus was busy */
+	u32 rcv_err_coll;	/* Received frms. that encountered coll. */
+	u32 rcv_shrt_frames;	/* Received frames that were to short */
+} basic_cntr_t;
+
+/* 82558 extended statistic counters */
+typedef struct _ext_cntr_t {
+	u32 xmt_fc_frames;
+	u32 rcv_fc_frames;
+	u32 rcv_fc_unsupported;
+} ext_cntr_t;
+
+/* 82559 TCO statistic counters */
+typedef struct _tco_cntr_t {
+	u16 xmt_tco_frames;
+	u16 rcv_tco_frames;
+} tco_cntr_t;
+
+/* Structures to access thet physical dump area */
+/* Use one of these types, according to the statisitcal counters mode,
+   to cast the pointer to the physical dump area and access the cmd_complete
+   DWORD. */
+
+/* 557-mode : only basic counters + cmd_complete */
+typedef struct _err_cntr_557_t {
+	basic_cntr_t basic_stats;
+	u32 cmd_complete;
+} err_cntr_557_t;
+
+/* 558-mode : basic + extended counters + cmd_complete */
+typedef struct _err_cntr_558_t {
+	basic_cntr_t basic_stats;
+	ext_cntr_t extended_stats;
+	u32 cmd_complete;
+} err_cntr_558_t;
+
+/* 559-mode : basic + extended + TCO counters + cmd_complete */
+typedef struct _err_cntr_559_t {
+	basic_cntr_t basic_stats;
+	ext_cntr_t extended_stats;
+	tco_cntr_t tco_stats;
+	u32 cmd_complete;
+} err_cntr_559_t;
+
+/* This typedef defines the struct needed to hold the largest number of counters */
+typedef err_cntr_559_t max_counters_t;
+
+/* Different statistical-counters mode the controller may be in */
+typedef enum _stat_mode_t {
+	E100_BASIC_STATS = 0,	/* 82557 stats : 16 counters / 16 dw */
+	E100_EXTENDED_STATS,	/* 82558 stats : 19 counters / 19 dw */
+	E100_TCO_STATS		/* 82559 stats : 21 counters / 20 dw */
+} stat_mode_t;
+
+/* dump statistical counters complete codes */
+#define DUMP_STAT_COMPLETED	0xA005
+#define DUMP_RST_STAT_COMPLETED	0xA007
+
+/* Command Block (CB) Generic Header Structure*/
+typedef struct _cb_header_t {
+	u16 cb_status;	/* Command Block Status */
+	u16 cb_cmd;	/* Command Block Command */
+	u32 cb_lnk_ptr;	/* Link To Next CB */
+} cb_header_t __attribute__ ((__packed__));
+
+//* Individual Address Command Block (IA_CB)*/
+typedef struct _ia_cb_t {
+	cb_header_t ia_cb_hdr;
+	u8 ia_addr[ETH_ALEN];
+} ia_cb_t __attribute__ ((__packed__));
+
+/* Configure Command Block (CONFIG_CB)*/
+typedef struct _config_cb_t {
+	cb_header_t cfg_cbhdr;
+	u8 cfg_byte[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+} config_cb_t __attribute__ ((__packed__));
+
+/* MultiCast Command Block (MULTICAST_CB)*/
+typedef struct _multicast_cb_t {
+	cb_header_t mc_cbhdr;
+	u16 mc_count;	/* Number of multicast addresses */
+	u8 mc_addr[(ETH_ALEN * MAX_MULTICAST_ADDRS)];
+} mltcst_cb_t __attribute__ ((__packed__));
+
+#define UCODE_MAX_DWORDS	134
+/* Load Microcode Command Block (LOAD_UCODE_CB)*/
+typedef struct _load_ucode_cb_t {
+	cb_header_t load_ucode_cbhdr;
+	u32 ucode_dword[UCODE_MAX_DWORDS];
+} load_ucode_cb_t __attribute__ ((__packed__));
+
+/* Load Programmable Filter Data*/
+typedef struct _filter_cb_t {
+	cb_header_t filter_cb_hdr;
+	u32 filter_data[MAX_FILTER];
+} filter_cb_t __attribute__ ((__packed__));
+
+/* NON_TRANSMIT_CB -- Generic Non-Transmit Command Block 
+ */
+typedef struct _nxmit_cb_t {
+	union {
+		config_cb_t config;
+		ia_cb_t setup;
+		load_ucode_cb_t load_ucode;
+		mltcst_cb_t multicast;
+		filter_cb_t filter;
+	} ntcb;
+} nxmit_cb_t __attribute__ ((__packed__));
+
+/*Block for queuing for postponed execution of the non-transmit commands*/
+typedef struct _nxmit_cb_entry_t {
+	struct list_head list_elem;
+	nxmit_cb_t *non_tx_cmd;
+	dma_addr_t dma_addr;
+	unsigned long expiration_time;
+} nxmit_cb_entry_t;
+
+/* States for postponed non tx commands execution */
+typedef enum _non_tx_cmd_state_t {
+	E100_NON_TX_IDLE = 0,	/* No queued NON-TX commands */
+	E100_WAIT_TX_FINISH,	/* Wait for completion of the TX activities */
+	E100_WAIT_NON_TX_FINISH	/* Wait for completion of the non TX command */
+} non_tx_cmd_state_t;
+
+/* some defines for the ipcb */
+#define IPCB_IP_CHECKSUM_ENABLE 	BIT_4
+#define IPCB_TCPUDP_CHECKSUM_ENABLE	BIT_5
+#define IPCB_TCP_PACKET 		BIT_6
+#define IPCB_LARGESEND_ENABLE 		BIT_7
+#define IPCB_HARDWAREPARSING_ENABLE	BIT_0
+#define IPCB_INSERTVLAN_ENABLE 		BIT_1
+#define IPCB_IP_ACTIVATION_DEFAULT      IPCB_HARDWAREPARSING_ENABLE
+
+/* Transmit Buffer Descriptor (TBD)*/
+typedef struct _tbd_t {
+	u32 tbd_buf_addr;	/* Physical Transmit Buffer Address */
+	u16 tbd_buf_cnt;	/* Actual Count Of Bytes */
+	u16 padd;
+} tbd_t __attribute__ ((__packed__));
+
+/* d102 specific fields */
+typedef struct _tcb_ipcb_t {
+	u16 schedule_low;
+	u8 ip_schedule;
+	u8 ip_activation_high;
+	u16 vlan;
+	u8 ip_header_offset;
+	u8 tcp_header_offset;
+	union {
+		u32 sec_rec_phys_addr;
+		u32 tbd_zero_address;
+	} tbd_sec_addr;
+	union {
+		u16 sec_rec_size;
+		u16 tbd_zero_size;
+	} tbd_sec_size;
+	u16 total_tcp_payload;
+} tcb_ipcb_t __attribute__ ((__packed__));
+
+#ifdef MAX_SKB_FRAGS
+#define E100_ZEROCOPY
+#endif
+
+#ifdef E100_ZEROCOPY
+#define E100_TBD_ARRAY_SIZE (2+MAX_SKB_FRAGS)
+#else
+#define E100_TBD_ARRAY_SIZE 2
+#endif /*E100_ZEROCOPY */
+
+/* Transmit Command Block (TCB)*/
+struct _tcb_t {
+	cb_header_t tcb_hdr;
+	u32 tcb_tbd_ptr;	/* TBD address */
+	u16 tcb_cnt;	/* Data Bytes In TCB past header */
+	u8 tcb_thrshld;	/* TX Threshold for FIFO Extender */
+	u8 tcb_tbd_num;
+
+	union {
+		tcb_ipcb_t ipcb;	/* d102 ipcb fields */
+		tbd_t tbd_array[E100_TBD_ARRAY_SIZE];
+	} tcbu;
+
+	/* From here onward we can dump anything we want as long as the
+	 * size of the total structure is a multiple of a paragraph
+	 * boundary ( i.e. -16 bit aligned ).
+	 */
+	tbd_t *tbd_ptr;
+
+#ifdef E100_ZEROCOPY
+	u32 tcb_tbd_dflt_ptr;	/* TBD address for non-segmented packet */
+	u32 tcb_tbd_expand_ptr;	/* TBD address for segmented packet */
+#endif				/*E100_ZEROCOPY */
+
+	struct sk_buff *tcb_skb;	/* the associated socket buffer */
+	dma_addr_t tcb_phys;	/* phys addr of the TCB */
+} __attribute__ ((__packed__));
+
+#ifndef _TCB_T_
+#define _TCB_T_
+typedef struct _tcb_t tcb_t;
+#endif
+
+/* Receive Frame Descriptor (RFD) - will be using the simple model*/
+struct _rfd_t {
+	/* 8255x */
+	cb_header_t rfd_header;
+	u32 rfd_rbd_ptr;	/* Receive Buffer Descriptor Addr */
+	u16 rfd_act_cnt;	/* Number Of Bytes Received */
+	u16 rfd_sz;	/* Number Of Bytes In RFD */
+	/* D102 aka Gamla */
+	u16 vlanid;
+	u8 rcvparserstatus;
+	u8 reserved;
+	u16 securitystatus;
+	u8 checksumstatus;
+	u8 zerocopystatus;
+	u8 pad[8];	/* data should be 16 byte aligned */
+	u8 data[RFD_DATA_SIZE];
+
+} __attribute__ ((__packed__));
+
+#ifndef _RFD_T_
+#define _RFD_T_
+typedef struct _rfd_t rfd_t;
+#endif
+
+/* Receive Buffer Descriptor (RBD)*/
+typedef struct _rbd_t {
+	u16 rbd_act_cnt;	/* Number Of Bytes Received */
+	u16 rbd_filler;
+	u32 rbd_lnk_addr;	/* Link To Next RBD */
+	u32 rbd_rcb_addr;	/* Receive Buffer Address */
+	u16 rbd_sz;	/* Receive Buffer Size */
+	u16 rbd_filler1;
+} rbd_t __attribute__ ((__packed__));
+
+/*
+ * This structure is used to maintain a FIFO access to a resource that is 
+ * maintained as a circular queue. The resource to be maintained is pointed
+ * to by the "data" field in the structure below. In this driver the TCBs', 
+ * TBDs' & RFDs' are maintained  as a circular queue & are managed thru this
+ * structure.
+ */
+typedef struct _buf_pool_t {
+	unsigned int head;	/* index to first used resource */
+	unsigned int tail;	/* index to last used resource */
+	void *data;		/* points to resource pool */
+} buf_pool_t;
+
+/*Rx skb holding structure*/
+struct rx_list_elem {
+	struct list_head list_elem;
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+};
+
+enum next_cu_cmd_e { RESUME_NO_WAIT = 0, RESUME_WAIT, START_WAIT };
+enum zlock_state_e { ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING };
+enum tx_queue_stop_type { LONG_STOP = 0, SHORT_STOP };
+
+/* 64 bit aligned size */
+#define E100_SIZE_64A(X) ((sizeof(X) + 7) & ~0x7)
+
+typedef struct _bd_dma_able_t {
+	char selftest[E100_SIZE_64A(self_test_t)];
+	char stats_counters[E100_SIZE_64A(max_counters_t)];
+} bd_dma_able_t;
+
+/* bit masks for bool parameters */
+#define PRM_XSUMRX       0x00000001
+#define PRM_UCODE        0x00000002
+#define PRM_FC           0x00000004
+#define PRM_IFS          0x00000008
+#define PRM_BUNDLE_SMALL 0x00000010
+#define PRM_RX_CONG      0x00000020
+
+struct cfg_params {
+	int e100_speed_duplex;
+	int RxDescriptors;
+	int TxDescriptors;
+	int IntDelay;
+	int BundleMax;
+	int ber;
+	int PollingMaxWork;
+	u32 b_params;
+};
+
+struct e100_private {
+	u32 flags;		/* board management flags */
+	u32 tx_per_underrun;	/* number of good tx frames per underrun */
+	unsigned int tx_count;	/* count of tx frames, so we can request an interrupt */
+	u8 tx_thld;		/* stores transmit threshold */
+	u16 eeprom_size;
+	u32 pwa_no;		/* PWA: xxxxxx-0xx */
+	u8 perm_node_address[ETH_ALEN];
+	struct list_head active_rx_list;	/* list of rx buffers */
+	struct list_head rx_struct_pool;	/* pool of rx buffer struct headers */
+	u16 rfd_size;			/* size of the adapter's RFD struct */
+	int skb_req;			/* number of skbs neede by the adapter */
+	u8 intr_mask;			/* mask for interrupt status */
+
+	void *dma_able;			/* dma allocated structs */
+	dma_addr_t dma_able_phys;
+	self_test_t *selftest;		/* pointer to self test area */
+	dma_addr_t selftest_phys;	/* phys addr of selftest */
+	max_counters_t *stats_counters;	/* pointer to stats table */
+	dma_addr_t stat_cnt_phys;	/* phys addr of stat counter area */
+
+	stat_mode_t stat_mode;	/* statistics mode: extended, TCO, basic */
+	scb_t *scb;		/* memory mapped ptr to 82557 scb */
+
+	tcb_t *last_tcb;	/* pointer to last tcb sent */
+	buf_pool_t tcb_pool;	/* adapter's TCB array */
+	dma_addr_t tcb_phys;	/* phys addr of start of TCBs */
+
+	u16 cur_line_speed;
+	u16 cur_dplx_mode;
+
+	struct net_device *device;
+	struct pci_dev *pdev;
+	struct driver_stats drv_stats;
+
+	u8 rev_id;		/* adapter PCI revision ID */
+	unsigned long device_type;	/* device type from e100_vendor.h */
+
+	unsigned int phy_addr;	/* address of PHY component */
+	unsigned int PhyId;	/* ID of PHY component */
+	unsigned int PhyState;	/* state for the fix squelch algorithm */
+	unsigned int PhyDelay;	/* delay for the fix squelch algorithm */
+
+	/* Lock defintions for the driver */
+	spinlock_t bd_lock;		/* board lock */
+	spinlock_t bd_non_tx_lock;	/* Non transmit command lock  */
+	spinlock_t config_lock;		/* config block lock */
+	spinlock_t mdi_access_lock;	/* mdi lock */
+
+	struct timer_list watchdog_timer;	/* watchdog timer id */
+
+	/* non-tx commands parameters */
+	struct timer_list nontx_timer_id;	/* non-tx timer id */
+	struct list_head non_tx_cmd_list;
+	non_tx_cmd_state_t non_tx_command_state;
+	nxmit_cb_entry_t *same_cmd_entry[CB_MAX_NONTX_CMD];
+
+	enum next_cu_cmd_e next_cu_cmd;
+
+	/* Zero Locking Algorithm data members */
+	enum zlock_state_e zlock_state;
+	u8 zlock_read_data[16];	/* number of times each value 0-15 was read */
+	u16 zlock_read_cnt;	/* counts number of reads */
+	ulong zlock_sleep_cnt;	/* keeps track of "sleep" time */
+
+	u8 config[CB_CFIG_BYTE_COUNT + CB_CFIG_D102_BYTE_COUNT];
+
+	/* IFS params */
+	u8 ifs_state;
+	u8 ifs_value;
+
+	struct cfg_params params;	/* adapter's command line parameters */
+
+	struct proc_dir_entry *proc_parent;
+
+	rwlock_t isolate_lock;
+	int driver_isolated;
+
+	u32 speed_duplex_caps;	/* adapter's speed/duplex capabilities */
+
+	struct tasklet_struct polling_tasklet;
+
+#ifdef ETHTOOL_GWOL
+	/* WOL params for ethtool */
+	u32 wolsupported;
+	u32 wolopts;
+	u16 ip_lbytes;
+#endif
+};
+
+#define E100_AUTONEG        0
+#define E100_SPEED_10_HALF  1
+#define E100_SPEED_10_FULL  2
+#define E100_SPEED_100_HALF 3
+#define E100_SPEED_100_FULL 4
+
+/********* function prototypes *************/
+extern void e100_isolate_driver(struct e100_private *bdp);
+extern void e100_sw_reset(struct e100_private *bdp, u32 reset_cmd);
+extern void e100_start_cu(struct e100_private *bdp, tcb_t *tcb);
+extern void e100_free_non_tx_cmd(struct e100_private *bdp,
+				 nxmit_cb_entry_t *non_tx_cmd);
+extern nxmit_cb_entry_t *e100_alloc_non_tx_cmd(struct e100_private *bdp);
+extern unsigned char e100_exec_non_cu_cmd(struct e100_private *bdp,
+					  nxmit_cb_entry_t *cmd);
+extern unsigned char e100_selftest(struct e100_private *bdp, u32 *st_timeout,
+				   u32 *st_result);
+extern unsigned char e100_get_link_state(struct e100_private *bdp);
+extern unsigned char e100_wait_scb(struct e100_private *bdp);
+
+#endif
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_config.c linux-2.5.6/drivers/net/e100/e100_config.c
--- linux-2.5.6-pre3/drivers/net/e100/e100_config.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_config.c	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,596 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_config.c                                         *
+*                                                                     *
+* Abstract:     Functions for configuring the network adapter.        *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#ifdef SIOCETHTOOL
+#include <linux/ethtool.h>
+#endif
+
+#include "e100_config.h"
+
+static void e100_config_long_rx(struct e100_private *bdp, unsigned char enable);
+
+static const u8 def_config[] = {
+	CB_CFIG_BYTE_COUNT,
+	0x08, 0x00, 0x00, 0x00, 0x00, 0x32, 0x07, 0x01,
+	0x00, 0x2e, 0x00, 0x60, 0x00, 0xf2, 0xc8, 0x00,
+	0x40, 0xf2, 0x80, 0x3f, 0x05
+};
+
+/**
+ * e100_config_init_82557 - config the 82557 adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will initialize the 82557 configure block.
+ * All other init functions will only set values that are
+ * different from the 82557 default.
+ */
+static void __devinit
+e100_config_init_82557(struct e100_private *bdp)
+{
+	/* initialize config block */
+	memcpy(bdp->config, def_config, sizeof (def_config));
+	bdp->config[0] = CB_CFIG_BYTE_COUNT;	/* just in case */
+
+	e100_config_ifs(bdp);
+
+	/*
+	 * Enable extended statistical counters (82558 and up) and TCO counters
+	 * (82559 and up) and set the statistical counters' mode in bdp 
+	 *  
+	 *  stat. mode      |    TCO stat. bit (2)  |  Extended stat. bit (5)
+	 * ------------------------------------------------------------------
+	 *  Basic (557)     |       0               |         1
+	 * ------------------------------------------------------------------
+	 *  Extended (558)  |       0               |         0
+	 * ------------------------------------------------------------------
+	 *  TCO (559)       |       1               |         1
+	 * ------------------------------------------------------------------
+	 *  Reserved        |       1               |         0
+	 * ------------------------------------------------------------------
+	 */
+	bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+	bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+	bdp->stat_mode = E100_BASIC_STATS;
+
+	/* Setup for MII or 503 operation.  The CRS+CDT bit should only be set */
+	/* when operating in 503 mode. */
+	if (bdp->phy_addr == 32) {
+		bdp->config[8] &= ~CB_CFIG_503_MII;
+		bdp->config[15] |= CB_CFIG_CRS_OR_CDT;
+	} else {
+		bdp->config[8] |= CB_CFIG_503_MII;
+		bdp->config[15] &= ~CB_CFIG_CRS_OR_CDT;
+	}
+
+	e100_config_fc(bdp);
+	e100_config_force_dplx(bdp);
+	e100_config_promisc(bdp, false);
+	e100_config_mulcast_enbl(bdp, false);
+}
+
+static void __devinit
+e100_config_init_82558(struct e100_private *bdp)
+{
+	/* MWI enable. This should be turned on only if the adapter is a 82558/9
+	 * and if the PCI command reg. has enabled the MWI bit. */
+	bdp->config[3] |= CB_CFIG_MWI_EN;
+
+	bdp->config[6] &= ~CB_CFIG_EXT_TCB_DIS;
+
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		/* this is 82559 and up - enable TCO counters */
+		bdp->config[6] |= CB_CFIG_TCO_STAT;
+		bdp->config[6] |= CB_CFIG_EXT_STAT_DIS;
+		bdp->stat_mode = E100_TCO_STATS;
+
+		if ((bdp->rev_id < D102_REV_ID) &&
+		    (bdp->params.b_params & PRM_XSUMRX) &&
+		    (bdp->pdev->device != 0x1209)) {
+
+			bdp->flags |= DF_CSUM_OFFLOAD;
+			bdp->config[9] |= 1;
+		}
+	} else {
+		/* this is 82558 */
+		bdp->config[6] &= ~CB_CFIG_TCO_STAT;
+		bdp->config[6] &= ~CB_CFIG_EXT_STAT_DIS;
+		bdp->stat_mode = E100_EXTENDED_STATS;
+	}
+
+	e100_config_long_rx(bdp, true);
+}
+
+static void __devinit
+e100_config_init_82550(struct e100_private *bdp)
+{
+	/* The D102 chip allows for 32 config bytes.  This value is
+	 * supposed to be in Byte 0.  Just add the extra bytes to
+	 * what was already setup in the block. */
+	bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+
+	/* now we need to enable the extended RFD.  When this is
+	 * enabled, the immediated receive data buffer starts at offset
+	 * 32 from the RFD base address, instead of at offset 16. */
+	bdp->config[7] |= CB_CFIG_EXTENDED_RFD;
+
+	/* put the chip into D102 receive mode.  This is neccessary
+	 * for any parsing and offloading features. */
+	bdp->config[22] = CB_CFIG_RECEIVE_GAMLA_MODE;
+
+	/* set the flag if checksum offloading was enabled */
+	if (bdp->params.b_params & PRM_XSUMRX) {
+		bdp->flags |= DF_CSUM_OFFLOAD;
+	}
+}
+
+/* Initialize the adapter's configure block */
+void __devinit
+e100_config_init(struct e100_private *bdp)
+{
+	e100_config_init_82557(bdp);
+
+	if (bdp->flags & IS_BACHELOR)
+		e100_config_init_82558(bdp);
+
+	if (bdp->rev_id >= D102_REV_ID)
+		e100_config_init_82550(bdp);
+}
+
+/**
+ * e100_force_config - force a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will force a configure command to the adapter.
+ * The command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_force_config(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	bdp->config[0] = CB_CFIG_BYTE_COUNT;
+	if (bdp->rev_id >= D102_REV_ID) {
+		/* The D102 chip allows for 32 config bytes.  This value is
+		   supposed to be in Byte 0.  Just add the extra bytes to
+		   what was already setup in the block. */
+		bdp->config[0] += CB_CFIG_D102_BYTE_COUNT;
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+
+	// although we call config outside the lock, there is no
+	// race condition because config byte count has maximum value
+	return e100_config(bdp);
+}
+
+/**
+ * e100_config - issue a configure command
+ * @bdp: atapter's private data struct
+ *
+ * This routine will issue a configure command to the 82557.
+ * This command will be executed in polled mode as interrupts
+ * are _disabled_ at this time.
+ *
+ * Returns:
+ *      true: if the configure command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_config(struct e100_private *bdp)
+{
+	cb_header_t *pntcb_hdr;
+	unsigned char res = true;
+	nxmit_cb_entry_t *cmd;
+
+	if (bdp->config[0] == 0) {
+		goto exit;
+	}
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		res = false;
+		goto exit;
+	}
+
+	pntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	pntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_CONFIGURE);
+
+	spin_lock_bh(&bdp->config_lock);
+
+	if (bdp->config[0] < CB_CFIG_MIN_PARAMS) {
+		bdp->config[0] = CB_CFIG_MIN_PARAMS;
+	}
+
+	/* Copy the device's config block to the device's memory */
+	memcpy(cmd->non_tx_cmd->ntcb.config.cfg_byte, bdp->config,
+	       bdp->config[0]);
+	/* reset number of bytes to config next time */
+	bdp->config[0] = 0;
+
+	spin_unlock_bh(&bdp->config_lock);
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+
+exit:
+	if (netif_running(bdp->device))
+		netif_wake_queue(bdp->device);
+	return res;
+}
+
+/**
+ * e100_config_fc - config flow-control state
+ * @bdp: atapter's private data struct
+ *
+ * This routine will enable or disable flow control support in the adapter's
+ * config block. Flow control will be enable only if requested using the command
+ * line option, and if the link is flow-contorl capable (both us and the link
+ * partner).
+ *
+ * Returns:
+ *      true: if then option was indeed changed
+ *      false: if no change was needed
+ */
+unsigned char
+e100_config_fc(struct e100_private *bdp)
+{
+	unsigned char enable = false;
+	unsigned char changed = false;
+
+	/* 82557 doesn't support fc. Don't touch this option */
+	if (!(bdp->flags & IS_BACHELOR))
+		return false;
+
+	/* Enable fc if requested and if the link supports it */
+	if ((bdp->params.b_params & PRM_FC) && (bdp->flags & DF_LINK_FC_CAP)) {
+		enable = true;
+	}
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	if (enable) {
+
+		if (bdp->config[16] != DFLT_FC_DELAY_LSB) {
+			bdp->config[16] = DFLT_FC_DELAY_LSB;
+			E100_CONFIG(bdp, 16);
+			changed = true;
+		}
+
+		if (bdp->config[17] != DFLT_FC_DELAY_LSB) {
+			bdp->config[17] = DFLT_FC_DELAY_MSB;
+			E100_CONFIG(bdp, 17);
+			changed = true;
+		}
+
+		/* check if *all* fc config options were already set */
+		if (((bdp->config[19] & CB_CFIG_FC_OPTS) != CB_CFIG_FC_OPTS) ||
+		    (bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
+
+			bdp->config[19] |= CB_CFIG_FC_OPTS;
+			bdp->config[19] &= ~CB_CFIG_TX_FC_DIS;
+			E100_CONFIG(bdp, 19);
+			changed = true;
+		}
+
+	} else {
+		if (bdp->config[16] != DFLT_NO_FC_DELAY_LSB) {
+			bdp->config[16] = DFLT_NO_FC_DELAY_LSB;
+			E100_CONFIG(bdp, 16);
+			changed = true;
+		}
+
+		if (bdp->config[17] != DFLT_NO_FC_DELAY_MSB) {
+			bdp->config[17] = DFLT_NO_FC_DELAY_MSB;
+			E100_CONFIG(bdp, 17);
+			changed = true;
+		}
+
+		/* check if *any* fc config options was already set */
+		if ((bdp->config[19] & CB_CFIG_FC_OPTS) ||
+		    !(bdp->config[19] & CB_CFIG_TX_FC_DIS)) {
+
+			bdp->config[19] &= ~CB_CFIG_FC_OPTS;
+			bdp->config[19] |= CB_CFIG_TX_FC_DIS;
+			E100_CONFIG(bdp, 19);
+			changed = true;
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+
+	return changed;
+}
+
+/**
+ * e100_config_promisc - configure promiscuous mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable promiscuous mode
+ * in the adapter's config block.
+ */
+void
+e100_config_promisc(struct e100_private *bdp, unsigned char enable)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* if in promiscuous mode, save bad frames */
+	if (enable) {
+
+		if (!(bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES)) {
+			bdp->config[6] |= CB_CFIG_SAVE_BAD_FRAMES;
+			E100_CONFIG(bdp, 6);
+		}
+
+		if (bdp->config[7] & (u8) BIT_0) {
+			bdp->config[7] &= (u8) (~BIT_0);
+			E100_CONFIG(bdp, 7);
+		}
+
+		if (!(bdp->config[15] & CB_CFIG_PROMISCUOUS)) {
+			bdp->config[15] |= CB_CFIG_PROMISCUOUS;
+			E100_CONFIG(bdp, 15);
+		}
+
+	} else {		/* not in promiscuous mode */
+
+		if (bdp->config[6] & CB_CFIG_SAVE_BAD_FRAMES) {
+			bdp->config[6] &= ~CB_CFIG_SAVE_BAD_FRAMES;
+			E100_CONFIG(bdp, 6);
+		}
+
+		if (!(bdp->config[7] & (u8) BIT_0)) {
+			bdp->config[7] |= (u8) (BIT_0);
+			E100_CONFIG(bdp, 7);
+		}
+
+		if (bdp->config[15] & CB_CFIG_PROMISCUOUS) {
+			bdp->config[15] &= ~CB_CFIG_PROMISCUOUS;
+			E100_CONFIG(bdp, 15);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_mulcast_enbl - configure allmulti mode
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of all multicast packets
+ * in the adapter's config block.
+ */
+void
+e100_config_mulcast_enbl(struct e100_private *bdp, unsigned char enable)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* this flag is used to enable receiving all multicast packet */
+	if (enable) {
+		if (!(bdp->config[21] & CB_CFIG_MULTICAST_ALL)) {
+			bdp->config[21] |= CB_CFIG_MULTICAST_ALL;
+			E100_CONFIG(bdp, 21);
+		}
+
+	} else {
+		if (bdp->config[21] & CB_CFIG_MULTICAST_ALL) {
+			bdp->config[21] &= ~CB_CFIG_MULTICAST_ALL;
+			E100_CONFIG(bdp, 21);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_ifs - configure the IFS parameter
+ * @bdp: atapter's private data struct
+ *
+ * This routine will configure the adaptive IFS value
+ * in the adapter's config block. IFS values are only
+ * relevant in half duplex, so set to 0 in full duplex.
+ */
+void
+e100_config_ifs(struct e100_private *bdp)
+{
+	u8 value = 0;
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* IFS value is only needed to be specified at half-duplex mode */
+	if (bdp->cur_dplx_mode == HALF_DUPLEX) {
+		value = (u8) bdp->ifs_value;
+	}
+
+	if (bdp->config[2] != value) {
+		bdp->config[2] = value;
+		E100_CONFIG(bdp, 2);
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_force_dplx - configure the forced full duplex mode
+ * @bdp: atapter's private data struct
+ *
+ * This routine will enable or disable force full duplex
+ * in the adapter's config block. If the PHY is 503, and
+ * the duplex is full, consider the adapter forced.
+ */
+void
+e100_config_force_dplx(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	/* We must force full duplex on if we are using PHY 0, and we are */
+	/* supposed to run in FDX mode. We do this because the e100 has only */
+	/* one FDX# input pin, and that pin will be connected to PHY 1. */
+	/* Changed the 'if' condition below to fix performance problem * at 10
+	 * full. The Phy was getting forced to full duplex while the MAC * was
+	 * not, because the cur_dplx_mode was not being set to 2 by SetupPhy. *
+	 * This is how the condition was, initially. * This has been changed so
+	 * that the MAC gets forced to full duplex * simply if the user has
+	 * forced full duplex. * * if (( bdp->phy_addr == 0 ) && (
+	 * bdp->cur_dplx_mode == 2 )) */
+	/* The rest of the fix is in the PhyDetect code. */
+	if ((bdp->params.e100_speed_duplex == E100_SPEED_10_FULL) ||
+	    (bdp->params.e100_speed_duplex == E100_SPEED_100_FULL) ||
+	    ((bdp->phy_addr == 32) && (bdp->cur_dplx_mode == FULL_DUPLEX))) {
+		if (!(bdp->config[19] & (u8) CB_CFIG_FORCE_FDX)) {
+			bdp->config[19] |= (u8) CB_CFIG_FORCE_FDX;
+			E100_CONFIG(bdp, 19);
+		}
+
+	} else {
+		if (bdp->config[19] & (u8) CB_CFIG_FORCE_FDX) {
+			bdp->config[19] &= (u8) (~CB_CFIG_FORCE_FDX);
+			E100_CONFIG(bdp, 19);
+		}
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+
+/**
+ * e100_config_long_rx
+ * @bdp: atapter's private data struct
+ * @enable: should we enable this option or not
+ *
+ * This routine will enable or disable reception of larger packets.
+ * This is needed by VLAN implementations.
+ */
+static void
+e100_config_long_rx(struct e100_private *bdp, unsigned char enable)
+{
+	if (enable) {
+		if (!(bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+			bdp->config[18] |= CB_CFIG_LONG_RX_OK;
+			E100_CONFIG(bdp, 18);
+		}
+
+	} else {
+		if ((bdp->config[18] & CB_CFIG_LONG_RX_OK)) {
+			bdp->config[18] &= ~CB_CFIG_LONG_RX_OK;
+			E100_CONFIG(bdp, 18);
+		}
+	}
+}
+
+#ifdef ETHTOOL_GWOL
+/**
+ * e100_config_wol
+ * @bdp: atapter's private data struct
+ *
+ * This sets configuration options for Wake On LAN functionality (WOL) in the
+ * config record. WOL options are retrieved from wolinfo_wolopts in @bdp
+ */
+void
+e100_config_wol(struct e100_private *bdp)
+{
+	spin_lock_bh(&(bdp->config_lock));
+
+	if (bdp->wolopts & WAKE_PHY) {
+		bdp->config[9] |= CB_LINK_STATUS_WOL;
+		E100_CONFIG(bdp, 9);
+	}
+
+	if (!(bdp->wolopts & WAKE_MAGIC)) {
+		bdp->config[19] |= CB_DISABLE_MAGPAK_WAKE;
+		E100_CONFIG(bdp, 19);
+	}
+
+	spin_unlock_bh(&(bdp->config_lock));
+}
+#endif
+
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_config.h linux-2.5.6/drivers/net/e100/e100_config.h
--- linux-2.5.6-pre3/drivers/net/e100/e100_config.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_config.h	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,206 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _E100_CONFIG_INC_
+#define _E100_CONFIG_INC_
+
+#include "e100.h"
+
+#define E100_CONFIG(bdp, X) ((bdp)->config[0] = max_t(u8, (bdp)->config[0], (X)+1))
+
+#define CB_CFIG_MIN_PARAMS         8
+
+/* byte 0 bit definitions*/
+#define CB_CFIG_BYTE_COUNT_MASK     BIT_0_5	/* Byte count occupies bit 5-0 */
+
+/* byte 1 bit definitions*/
+#define CB_CFIG_RXFIFO_LIMIT_MASK   BIT_0_4	/* RxFifo limit mask */
+#define CB_CFIG_TXFIFO_LIMIT_MASK   BIT_4_7	/* TxFifo limit mask */
+
+/* byte 2 bit definitions -- ADAPTIVE_IFS*/
+
+/* word 3 bit definitions -- RESERVED*/
+/* Changed for 82558 enhancements */
+/* byte 3 bit definitions */
+#define CB_CFIG_MWI_EN      BIT_0	/* Enable MWI on PCI bus */
+#define CB_CFIG_TYPE_EN     BIT_1	/* Type Enable */
+#define CB_CFIG_READAL_EN   BIT_2	/* Enable Read Align */
+#define CB_CFIG_TERMCL_EN   BIT_3	/* Cache line write  */
+
+/* byte 4 bit definitions*/
+#define CB_CFIG_RX_MIN_DMA_MASK     BIT_0_6	/* Rx minimum DMA count mask */
+
+/* byte 5 bit definitions*/
+#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6	/* Tx minimum DMA count mask */
+#define CB_CFIG_DMBC_EN         BIT_7	/* Enable Tx/Rx min. DMA counts */
+
+/* Changed for 82558 enhancements */
+/* byte 6 bit definitions*/
+#define CB_CFIG_LATE_SCB           BIT_0	/* Update SCB After New Tx Start */
+#define CB_CFIG_DIRECT_DMA_DIS     BIT_1	/* Direct DMA mode */
+#define CB_CFIG_TNO_INT            BIT_2	/* Tx Not OK Interrupt */
+#define CB_CFIG_TCO_STAT           BIT_2	/* TCO statistics in 559 and above */
+#define CB_CFIG_CI_INT             BIT_3	/* Command Complete Interrupt */
+#define CB_CFIG_EXT_TCB_DIS        BIT_4	/* Extended TCB */
+#define CB_CFIG_EXT_STAT_DIS       BIT_5	/* Extended Stats */
+#define CB_CFIG_SAVE_BAD_FRAMES    BIT_7	/* Save Bad Frames Enabled */
+
+/* byte 7 bit definitions*/
+#define CB_CFIG_DISC_SHORT_FRAMES   BIT_0	/* Discard Short Frames */
+#define CB_CFIG_DYNTBD_EN           BIT_7	/* Enable dynamic TBD */
+/* Enable extended RFD's on D102 */
+#define CB_CFIG_EXTENDED_RFD        BIT_5
+
+/* byte 8 bit definitions*/
+#define CB_CFIG_503_MII             BIT_0	/* 503 vs. MII mode */
+
+/* byte 9 bit definitions -- pre-defined all zeros*/
+#define CB_LINK_STATUS_WOL	BIT_5
+
+/* byte 10 bit definitions*/
+#define CB_CFIG_NO_SRCADR       BIT_3	/* No Source Address Insertion */
+#define CB_CFIG_PREAMBLE_LEN    BIT_4_5	/* Preamble Length */
+#define CB_CFIG_LOOPBACK_MODE   BIT_6_7	/* Loopback Mode */
+#define CB_CFIG_LOOPBACK_NORMAL 0
+#define CB_CFIG_LOOPBACK_INTERNAL BIT_6
+#define CB_CFIG_LOOPBACK_EXTERNAL BIT_6_7
+
+/* byte 11 bit definitions*/
+#define CB_CFIG_LINEAR_PRIORITY     BIT_0_2	/* Linear Priority */
+
+/* byte 12 bit definitions*/
+#define CB_CFIG_LINEAR_PRI_MODE     BIT_0	/* Linear Priority mode */
+#define CB_CFIG_IFS_MASK            BIT_4_7	/* Interframe Spacing mask */
+
+/* byte 13 bit definitions -- pre-defined all zeros*/
+
+/* byte 14 bit definitions -- pre-defined 0xf2*/
+
+/* byte 15 bit definitions*/
+#define CB_CFIG_PROMISCUOUS         BIT_0	/* Promiscuous Mode Enable */
+#define CB_CFIG_BROADCAST_DIS       BIT_1	/* Broadcast Mode Disable */
+#define CB_CFIG_CRS_OR_CDT          BIT_7	/* CRS Or CDT */
+
+/* byte 16 bit definitions -- pre-defined all zeros*/
+#define DFLT_FC_DELAY_LSB  0x1f	/* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_LSB  0x00	/* no flow control default value */
+
+/* byte 17 bit definitions -- pre-defined 0x40*/
+#define DFLT_FC_DELAY_MSB  0x01	/* Delay for outgoing Pause frames */
+#define DFLT_NO_FC_DELAY_MSB  0x40	/* no flow control default value */
+
+/* byte 18 bit definitions*/
+#define CB_CFIG_STRIPPING           BIT_0	/* Padding Disabled */
+#define CB_CFIG_PADDING             BIT_1	/* Padding Disabled */
+#define CB_CFIG_CRC_IN_MEM          BIT_2	/* Transfer CRC To Memory */
+
+/* byte 19 bit definitions*/
+#define CB_CFIG_TX_ADDR_WAKE        BIT_0	/* Address Wakeup */
+#define CB_DISABLE_MAGPAK_WAKE      BIT_1	/* Magic Packet Wakeup disable */
+/* Changed TX_FC_EN to TX_FC_DIS because 0 enables, 1 disables. Jul 8, 1999 */
+#define CB_CFIG_TX_FC_DIS           BIT_2	/* Tx Flow Control Disable */
+#define CB_CFIG_FC_RESTOP           BIT_3	/* Rx Flow Control Restop */
+#define CB_CFIG_FC_RESTART          BIT_4	/* Rx Flow Control Restart */
+#define CB_CFIG_FC_REJECT           BIT_5	/* Rx Flow Control Restart */
+#define CB_CFIG_FC_OPTS (CB_CFIG_FC_RESTOP | CB_CFIG_FC_RESTART | CB_CFIG_FC_REJECT)
+
+/* end 82558/9 specifics */
+
+#define CB_CFIG_FORCE_FDX           BIT_6	/* Force Full Duplex */
+#define CB_CFIG_FDX_ENABLE          BIT_7	/* Full Duplex Enabled */
+
+/* byte 20 bit definitions*/
+#define CB_CFIG_MULTI_IA            BIT_6	/* Multiple IA Addr */
+
+/* byte 21 bit definitions*/
+#define CB_CFIG_MULTICAST_ALL       BIT_3	/* Multicast All */
+
+/* byte 22 bit defines */
+#define CB_CFIG_RECEIVE_GAMLA_MODE  BIT_0	/* D102 receive mode */
+#define CB_CFIG_VLAN_DROP_ENABLE    BIT_1	/* vlan stripping */
+
+#define CB_CFIG_LONG_RX_OK	    BIT_3
+
+/* function prototypes */
+extern void e100_config_init(struct e100_private *bdp);
+extern unsigned char e100_force_config(struct e100_private *bdp);
+extern unsigned char e100_config(struct e100_private *bdp);
+extern unsigned char e100_config_fc(struct e100_private *bdp);
+extern void e100_config_promisc(struct e100_private *bdp, unsigned char enable);
+extern void e100_config_brdcast_dsbl(struct e100_private *bdp);
+extern void e100_config_mulcast_enbl(struct e100_private *bdp,
+				     unsigned char enable);
+extern void e100_config_ifs(struct e100_private *bdp);
+extern void e100_config_force_dplx(struct e100_private *bdp);
+
+#endif /* _E100_CONFIG_INC_ */
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_eeprom.c linux-2.5.6/drivers/net/e100/e100_eeprom.c
--- linux-2.5.6-pre3/drivers/net/e100/e100_eeprom.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_eeprom.c	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,614 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_eeprom.c                                         *
+*                                                                     *
+* Abstract:     This module contains routines to read and write to a  *
+*               serial EEPROM                                         *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+#include "e100.h"
+
+#define CSR_EEPROM_CONTROL_FIELD(bdp) ((bdp)->scb->scb_eprm_cntrl)
+
+#define CSR_GENERAL_CONTROL2_FIELD(bdp) \
+	           ((bdp)->scb->scb_ext.d102_scb.scb_gen_ctrl2)
+
+#define EEPROM_STALL_TIME	4
+#define EEPROM_CHECKSUM		((u16) 0xBABA)
+#define EEPROM_MAX_WORD_SIZE	256
+
+void e100_eeprom_cleanup(struct e100_private *adapter);
+u16 e100_eeprom_calculate_chksum(struct e100_private *adapter);
+static void e100_eeprom_write_word(struct e100_private *adapter, u16 reg,
+				   u16 data);
+void e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+			     u16 size);
+u16 e100_eeprom_size(struct e100_private *adapter);
+u16 e100_eeprom_read(struct e100_private *adapter, u16 reg);
+
+static void shift_out_bits(struct e100_private *adapter, u16 data, u16 count);
+static u16 shift_in_bits(struct e100_private *adapter);
+static void raise_clock(struct e100_private *adapter, u16 *x);
+static void lower_clock(struct e100_private *adapter, u16 *x);
+static u16 eeprom_wait_cmd_done(struct e100_private *adapter);
+static void eeprom_stand_by(struct e100_private *adapter);
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_set_semaphore
+//
+// Description: This function set (write 1) Gamla EEPROM semaphore bit (bit 23 word 0x1C in the CSR).
+//
+// Arguments:
+//      Adapter                 - Adapter context
+//
+// Returns:  true if success
+//           else return false 
+//
+//----------------------------------------------------------------------------------------
+
+inline u8
+eeprom_set_semaphore(struct e100_private *adapter)
+{
+	u16 data = 0;
+	unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+	while (time_before(jiffies, expiration_time)) {
+		// Get current value of General Control 2
+		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		// Set bit 23 word 0x1C in the CSR.
+		data |= SCB_GCR2_EEPROM_ACCESS_SEMAPHORE;
+		writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		barrier();
+
+		// Check to see if this bit set or not.
+		data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+
+		if (data & SCB_GCR2_EEPROM_ACCESS_SEMAPHORE) {
+			return true;
+		}
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_reset_semaphore
+//
+// Description: This function reset (write 0) Gamla EEPROM semaphore bit 
+//              (bit 23 word 0x1C in the CSR).
+//
+// Arguments:  struct e100_private * adapter - Adapter context
+//----------------------------------------------------------------------------------------
+
+inline void
+eeprom_reset_semaphore(struct e100_private *adapter)
+{
+	u16 data = 0;
+
+	data = readb(&CSR_GENERAL_CONTROL2_FIELD(adapter));
+	data &= ~(SCB_GCR2_EEPROM_ACCESS_SEMAPHORE);
+	writeb(data, &CSR_GENERAL_CONTROL2_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_size
+//
+// Description: This routine determines the size of the EEPROM.  This value should be
+//              checked for validity - ie. is it too big or too small.  The size returned
+//              is then passed to the read/write functions.
+//
+// Returns:
+//      Size of the eeprom, or zero if an error occured
+//----------------------------------------------------------------------------------------
+u16
+e100_eeprom_size(struct e100_private *adapter)
+{
+	u16 x, size = 1;	// must be one to accumulate a product
+
+	// if we've already stored this data, read from memory
+	if (adapter->eeprom_size) {
+		return adapter->eeprom_size;
+	}
+	// otherwise, read from the eeprom
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return 0;
+	}
+	// enable the eeprom by setting EECS.
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDI | EEDO | EESK);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	// write the read opcode
+	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+
+	// experiment to discover the size of the eeprom.  request register zero
+	// and wait for the eeprom to tell us it has accepted the entire address.
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	do {
+		size *= 2;	// each bit of address doubles eeprom size
+		x |= EEDO;	// set bit to detect "dummy zero"
+		x &= ~EEDI;	// address consists of all zeros
+
+		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+		udelay(EEPROM_STALL_TIME);
+		raise_clock(adapter, &x);
+		lower_clock(adapter, &x);
+
+		// check for "dummy zero"
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+		if (size > EEPROM_MAX_WORD_SIZE) {
+			size = 0;
+			break;
+		}
+	} while (x & EEDO);
+
+	// read in the value requested
+	(void) shift_in_bits(adapter);
+	e100_eeprom_cleanup(adapter);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+
+	return size;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_address_size
+//
+// Description: determines the number of bits in an address for the eeprom acceptable
+//              values are 64, 128, and 256
+// Arguments: size of the eeprom
+// Returns: bits in an address for that size eeprom
+//----------------------------------------------------------------------------------------
+
+static u16
+eeprom_address_size(u16 size)
+{
+	switch (size) {
+	case 64:
+		return 6;
+	case 128:
+		return 7;
+	case 256:
+		return 8;
+	}
+
+	return 0;		//fix compiler warning or error!
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_read
+//
+// Description: This routine serially reads one word out of the EEPROM.
+//
+// Arguments:
+//      adapter - our adapter context
+//      reg - EEPROM word to read.
+//
+// Returns:
+//      Contents of EEPROM word (reg).
+//----------------------------------------------------------------------------------------
+
+u16
+e100_eeprom_read(struct e100_private *adapter, u16 reg)
+{
+	u16 x, data, bits;
+
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return 0;
+	}
+	// eeprom size is initialized to zero
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	bits = eeprom_address_size(adapter->eeprom_size);
+
+	// select EEPROM, reset bits, set EECS
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	x &= ~(EEDI | EEDO | EESK);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	// write the read opcode and register number in that order
+	// The opcode is 3bits in length, reg is 'bits' bits long
+	shift_out_bits(adapter, EEPROM_READ_OPCODE, 3);
+	shift_out_bits(adapter, reg, bits);
+
+	// Now read the data (16 bits) in from the selected EEPROM word
+	data = shift_in_bits(adapter);
+
+	e100_eeprom_cleanup(adapter);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+
+	return data;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_out_bits
+//
+// Description: This routine shifts data bits out to the EEPROM.
+//
+// Arguments:
+//      data - data to send to the EEPROM.
+//      count - number of data bits to shift out.
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+static void
+shift_out_bits(struct e100_private *adapter, u16 data, u16 count)
+{
+	u16 x, mask;
+
+	mask = 1 << (count - 1);
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDO | EEDI);
+
+	do {
+		x &= ~EEDI;
+		if (data & mask)
+			x |= EEDI;
+
+		writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+		udelay(EEPROM_STALL_TIME);
+		raise_clock(adapter, &x);
+		lower_clock(adapter, &x);
+		mask = mask >> 1;
+	} while (mask);
+
+	x &= ~EEDI;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   raise_clock
+//
+// Description: This routine raises the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+raise_clock(struct e100_private *adapter, u16 *x)
+{
+	*x = *x | EESK;
+	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   lower_clock
+//
+// Description: This routine lower's the EEPROM's clock input (EESK)
+//
+// Arguments:
+//      x - Ptr to the EEPROM control register's current value
+//
+// Returns: (none)
+//----------------------------------------------------------------------------------------
+
+void
+lower_clock(struct e100_private *adapter, u16 *x)
+{
+	*x = *x & ~EESK;
+	writew(*x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	udelay(EEPROM_STALL_TIME);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   shift_in_bits
+//
+// Description: This routine shifts data bits in from the EEPROM.
+//
+// Arguments:
+//
+// Returns:
+//      The contents of that particular EEPROM word
+//----------------------------------------------------------------------------------------
+
+static u16
+shift_in_bits(struct e100_private *adapter)
+{
+	u16 x, d, i;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDO | EEDI);
+	d = 0;
+
+	for (i = 0; i < 16; i++) {
+		d <<= 1;
+		raise_clock(adapter, &x);
+
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+		x &= ~EEDI;
+		if (x & EEDO)
+			d |= 1;
+
+		lower_clock(adapter, &x);
+	}
+
+	return d;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_cleanup
+//
+// Description: This routine returns the EEPROM to an idle state
+//----------------------------------------------------------------------------------------
+
+void
+e100_eeprom_cleanup(struct e100_private *adapter)
+{
+	u16 x;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	x &= ~(EECS | EEDI);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	raise_clock(adapter, &x);
+	lower_clock(adapter, &x);
+}
+
+//**********************************************************************************
+// Procedure:   e100_eeprom_update_chksum
+//
+// Description: Calculates the checksum and writes it to the EEProm. 
+//              It calculates the checksum accroding to the formula: 
+//                              Checksum = 0xBABA - (sum of first 63 words).
+//
+//-----------------------------------------------------------------------------------
+u16
+e100_eeprom_calculate_chksum(struct e100_private *adapter)
+{
+	u16 idx, xsum_index, checksum = 0;
+
+	// eeprom size is initialized to zero
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	xsum_index = adapter->eeprom_size - 1;
+	for (idx = 0; idx < xsum_index; idx++)
+		checksum += e100_eeprom_read(adapter, idx);
+
+	checksum = EEPROM_CHECKSUM - checksum;
+	return checksum;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_word
+//
+// Description: This routine writes a word to a specific EEPROM location without.
+//              taking EEPROM semaphore and updating checksum. 
+//              Use e100_eeprom_write_block for the EEPROM update
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+static void
+e100_eeprom_write_word(struct e100_private *adapter, u16 reg, u16 data)
+{
+	u16 x;
+	u16 bits;
+
+	bits = eeprom_address_size(adapter->eeprom_size);
+
+	/* select EEPROM, mask off ASIC and reset bits, set EECS */
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EEDI | EEDO | EESK);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	wmb();
+	udelay(EEPROM_STALL_TIME);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+
+	shift_out_bits(adapter, EEPROM_EWEN_OPCODE, 5);
+	shift_out_bits(adapter, reg, (u16) (bits - 2));
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	/* write the new word to the EEPROM & send the write opcode the EEPORM */
+	shift_out_bits(adapter, EEPROM_WRITE_OPCODE, 3);
+
+	/* select which word in the EEPROM that we are writing to */
+	shift_out_bits(adapter, reg, bits);
+
+	/* write the data to the selected EEPROM word */
+	shift_out_bits(adapter, data, 16);
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	shift_out_bits(adapter, EEPROM_EWDS_OPCODE, 5);
+	shift_out_bits(adapter, reg, (u16) (bits - 2));
+	if (!eeprom_wait_cmd_done(adapter))
+		return;
+
+	e100_eeprom_cleanup(adapter);
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   e100_eeprom_write_block
+//
+// Description: This routine writes a block of words starting from specified EEPROM 
+//              location and updates checksum
+// Arguments: reg - The EEPROM word that we are going to write to.
+//            data - The data (word) that we are going to write to the EEPROM.
+//----------------------------------------------------------------------------------------
+void
+e100_eeprom_write_block(struct e100_private *adapter, u16 start, u16 *data,
+			u16 size)
+{
+	u16 checksum;
+	u16 i;
+
+	if (!adapter->eeprom_size)
+		adapter->eeprom_size = e100_eeprom_size(adapter);
+
+	// Set EEPROM semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		if (!eeprom_set_semaphore(adapter))
+			return;
+	}
+
+	for (i = 0; i < size; i++) {
+		e100_eeprom_write_word(adapter, start + i, data[i]);
+	}
+	//Update checksum
+	checksum = e100_eeprom_calculate_chksum(adapter);
+	e100_eeprom_write_word(adapter, (adapter->eeprom_size - 1), checksum);
+
+	// Clear EEPROM Semaphore.
+	if (adapter->rev_id >= D102_REV_ID) {
+		eeprom_reset_semaphore(adapter);
+	}
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_wait_cmd_done
+//
+// Description: This routine waits for the the EEPROM to finish its command.  
+//                              Specifically, it waits for EEDO (data out) to go high.
+// Returns:     true - If the command finished
+//              false - If the command never finished (EEDO stayed low)
+//----------------------------------------------------------------------------------------
+static u16
+eeprom_wait_cmd_done(struct e100_private *adapter)
+{
+	u16 x;
+	unsigned long expiration_time = jiffies + HZ / 100 + 1;
+
+	eeprom_stand_by(adapter);
+
+	while (time_before(jiffies, expiration_time)) {
+		rmb();
+		x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+		if (x & EEDO)
+			return true;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	return false;
+}
+
+//----------------------------------------------------------------------------------------
+// Procedure:   eeprom_stand_by
+//
+// Description: This routine lowers the EEPROM chip select (EECS) for a few microseconds.
+//----------------------------------------------------------------------------------------
+static void
+eeprom_stand_by(struct e100_private *adapter)
+{
+	u16 x;
+
+	x = readw(&CSR_EEPROM_CONTROL_FIELD(adapter));
+	x &= ~(EECS | EESK);
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	wmb();
+	udelay(EEPROM_STALL_TIME);
+	x |= EECS;
+	writew(x, &CSR_EEPROM_CONTROL_FIELD(adapter));
+	udelay(EEPROM_STALL_TIME);
+}
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_main.c linux-2.5.6/drivers/net/e100/e100_main.c
--- linux-2.5.6-pre3/drivers/net/e100/e100_main.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_main.c	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,3797 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                     *
+* INTEL CORPORATION                                                   *
+*                                                                     *
+* This software is supplied under the terms of the license included   *
+* above.  All use of this driver must be in accordance with the terms *
+* of that license.                                                    *
+*                                                                     *
+* Module Name:  e100_main.c                                           *
+*                                                                     *
+* Abstract:     Functions for the driver entry points like load,      *
+*               unload, open and close. All board specific calls made *
+*               by the network interface section of the driver.       *
+*                                                                     *
+* Environment:  This file is intended to be specific to the Linux     *
+*               operating system.                                     *
+*                                                                     *
+**********************************************************************/
+
+#undef __NO_VERSION__
+
+#include <linux/config.h>
+#include <net/checksum.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include "e100.h"
+#include "e100_ucode.h"
+#include "e100_config.h"
+#include "e100_phy.h"
+#include "e100_vendor.h"
+
+#ifndef CONFIG_PROC_FS
+#undef E100_CONFIG_PROC_FS
+#endif
+
+#ifdef E100_CONFIG_PROC_FS
+extern int e100_create_proc_subdir(struct e100_private *);
+extern void e100_remove_proc_subdir(struct e100_private *);
+#else
+#define e100_create_proc_subdir(X) 0
+#define e100_remove_proc_subdir(X) do {} while(0)
+#endif
+
+#ifdef SIOCETHTOOL
+#define E100_ETHTOOL_IOCTL
+#endif
+#ifdef E100_ETHTOOL_IOCTL
+static int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);
+static void e100_get_speed_duplex_caps(struct e100_private *);
+static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);
+static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);
+static void e100_set_speed_duplex(struct e100_private *);
+
+#ifdef ETHTOOL_GDRVINFO
+static int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GEEPROM
+static int e100_ethtool_eeprom(struct net_device *, struct ifreq *);
+
+#define E100_EEPROM_MAGIC 0x1234
+#endif
+#ifdef ETHTOOL_GLINK
+static int e100_ethtool_glink(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_NWAY_RST
+static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GWOL
+static int e100_ethtool_wol(struct net_device *, struct ifreq *);
+static unsigned char e100_setup_filter(struct e100_private *bdp);
+static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
+static u16 e100_get_ip_lbytes(struct net_device *dev);
+extern void e100_config_wol(struct e100_private *bdp);
+#endif
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef SIOCGMIIPHY
+#define E100_MII_IOCTL
+#endif
+#ifdef E100_MII_IOCTL
+#include <linux/mii.h>
+static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);
+#endif /*E100_MII_IOCTL */
+
+static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,
+						  nxmit_cb_entry_t *);
+static void e100_free_nontx_list(struct e100_private *);
+static void e100_non_tx_background(unsigned long);
+
+/* Global Data structures and variables */
+char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
+
+#define E100_VERSION  "2.0.20-pre1"
+#define E100_FULL_DRIVER_NAME 	"Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
+
+const char *e100_version = E100_VERSION;
+const char *e100_full_driver_name = E100_FULL_DRIVER_NAME E100_VERSION;
+char *e100_short_driver_name = "e100";
+static int e100nics = 0;
+
+/*********************************************************************/
+/*! This is a GCC extension to ANSI C.
+ *  See the item "Labeled Elements in Initializers" in the section
+ *  "Extensions to the C Language Family" of the GCC documentation.
+ *********************************************************************/
+
+#define E100_PARAM_INIT { [0 ... E100_MAX_NIC-1] = -1 }
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+#define E100_PARAM(X, S)                                        \
+        static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \
+        MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \
+        MODULE_PARM_DESC(X, S);
+
+/* ====================================================================== */
+static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);
+static u8 e100_D102_check_checksum(rfd_t *);
+static int e100_ioctl(struct net_device *, struct ifreq *, int);
+static int e100_open(struct net_device *);
+static int e100_close(struct net_device *);
+static int e100_change_mtu(struct net_device *, int);
+static int e100_xmit_frame(struct sk_buff *, struct net_device *);
+static unsigned char e100_init(struct e100_private *);
+static int e100_set_mac(struct net_device *, void *);
+struct net_device_stats *e100_get_stats(struct net_device *);
+
+static void e100intr(int, void *, struct pt_regs *);
+static void e100_print_brd_conf(struct e100_private *);
+static void e100_set_multi(struct net_device *);
+
+char *e100_get_brand_msg(struct e100_private *);
+static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);
+static u8 e100_sw_init(struct e100_private *);
+static unsigned char e100_alloc_space(struct e100_private *);
+static void e100_dealloc_space(struct e100_private *);
+static int e100_alloc_tcb_pool(struct e100_private *);
+static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *);
+static void e100_free_tcb_pool(struct e100_private *);
+static int e100_alloc_rfd_pool(struct e100_private *);
+static void e100_free_rfd_pool(struct e100_private *);
+
+static void e100_rd_eaddr(struct e100_private *);
+static void e100_rd_pwa_no(struct e100_private *);
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);
+extern u16 e100_eeprom_size(struct e100_private *);
+
+static unsigned char e100_clr_cntrs(struct e100_private *);
+static unsigned char e100_load_microcode(struct e100_private *);
+static unsigned char e100_hw_init(struct e100_private *, u32);
+static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);
+static unsigned char e100_update_stats(struct e100_private *bdp);
+
+static void e100_start_ru(struct e100_private *);
+static void e100_dump_stats_cntrs(struct e100_private *);
+
+static void e100_check_options(int board, struct e100_private *bdp);
+static void e100_set_int_option(int *, int, int, int, int, char *);
+static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,
+				 char *);
+unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);
+void e100_exec_cmplx(struct e100_private *, u32, u8);
+
+/**
+ * e100_get_rx_struct - retrieve cell to hold skb buff from the pool
+ * @bdp: atapter's private data struct
+ *
+ * Returns the new cell to hold sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_get_rx_struct(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct = NULL;
+
+	if (!list_empty(&(bdp->rx_struct_pool))) {
+		rx_struct = list_entry(bdp->rx_struct_pool.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+	}
+
+	return rx_struct;
+}
+
+/**
+ * e100_alloc_skb - allocate an skb for the adapter
+ * @bdp: atapter's private data struct
+ *
+ * Allocates skb with enough room for rfd, and data, and reserve non-data space.
+ * Returns the new cell with sk_buff or %NULL.
+ */
+static inline struct rx_list_elem *
+e100_alloc_skb(struct e100_private *bdp)
+{
+	struct sk_buff *new_skb;
+	u32 skb_size = sizeof (rfd_t);
+	struct rx_list_elem *rx_struct;
+
+	new_skb = (struct sk_buff *) dev_alloc_skb(skb_size);
+	if (new_skb) {
+		/* The IP data should be 
+		   DWORD aligned. since the ethernet header is 14 bytes long, 
+		   we need to reserve 2 extra bytes so that the TCP/IP headers
+		   will be DWORD aligned. */
+		skb_reserve(new_skb, 2);
+		if ((rx_struct = e100_get_rx_struct(bdp)) == NULL)
+			goto err;
+		rx_struct->skb = new_skb;
+		rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data,
+						     sizeof (rfd_t),
+						     PCI_DMA_FROMDEVICE);
+		if (!rx_struct->dma_addr)
+			goto err;
+		skb_reserve(new_skb, bdp->rfd_size);
+		return rx_struct;
+	} else {
+		return NULL;
+	}
+
+err:
+	dev_kfree_skb_irq(new_skb);
+	return NULL;
+}
+
+/**
+ * e100_add_skb_to_end - add an skb to the end of our rfd list
+ * @bdp: atapter's private data struct
+ * @rx_struct: rx_list_elem with the new skb
+ *
+ * Adds a newly allocated skb to the end of our rfd list.
+ */
+inline void
+e100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct)
+{
+	rfd_t *rfdn;		/* The new rfd */
+	rfd_t *rfd;		/* The old rfd */
+	struct rx_list_elem *rx_struct_last;
+
+	(rx_struct->skb)->dev = bdp->device;
+	rfdn = RFD_POINTER(rx_struct->skb, bdp);
+	rfdn->rfd_header.cb_status = 0;
+	rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT);
+	rfdn->rfd_act_cnt = 0;
+	rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE);
+
+	pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size,
+			    PCI_DMA_TODEVICE);
+
+	if (!list_empty(&(bdp->active_rx_list))) {
+		rx_struct_last = list_entry(bdp->active_rx_list.prev,
+					    struct rx_list_elem, list_elem);
+		rfd = RFD_POINTER(rx_struct_last->skb, bdp);
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    4, PCI_DMA_FROMDEVICE);
+		put_unaligned(cpu_to_le32(rx_struct->dma_addr),
+			      ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr))));
+
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    8, PCI_DMA_TODEVICE);
+		rfd->rfd_header.cb_cmd &=
+			__constant_cpu_to_le16((u16) ~RFD_EL_BIT);
+
+		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,
+				    4, PCI_DMA_TODEVICE);
+	}
+
+	list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list));
+}
+
+static inline void
+e100_alloc_skbs(struct e100_private *bdp)
+{
+	for (; bdp->skb_req > 0; bdp->skb_req--) {
+		struct rx_list_elem *rx_struct;
+
+		if ((rx_struct = e100_alloc_skb(bdp)) == NULL)
+			return;
+
+		e100_add_skb_to_end(bdp, rx_struct);
+	}
+}
+
+void e100_tx_srv(struct e100_private *);
+u32 e100_rx_srv(struct e100_private *, u32, int *);
+
+void e100_polling_tasklet(unsigned long);
+
+void e100_watchdog(struct net_device *);
+void e100_refresh_txthld(struct e100_private *);
+void e100_manage_adaptive_ifs(struct e100_private *);
+void e100_clear_pools(struct e100_private *);
+static void e100_clear_structs(struct net_device *);
+static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,
+					    struct sk_buff *);
+static void e100_set_multi_exec(struct net_device *dev);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
+MODULE_LICENSE("Dual BSD/GPL");
+
+E100_PARAM(TxDescriptors, "Number of transmit descriptors");
+E100_PARAM(RxDescriptors, "Number of receive descriptors");
+E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
+E100_PARAM(e100_speed_duplex, "Speed and Duplex settings");
+E100_PARAM(ucode, "Disable or enable microcode loading");
+E100_PARAM(ber, "Value for the BER correction algorithm");
+E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing");
+E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay");
+E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");
+E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");
+E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");
+E100_PARAM(RxCongestionControl, "Disable or enable switch to polling mode");
+E100_PARAM(PollingMaxWork, "Max number of receive packets processed on single "
+	   "polling call");
+
+/**
+ * e100_exec_cmd - issue a comand
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100.
+ */
+static inline void
+e100_exec_cmd(struct e100_private *bdp, u8 cmd_low)
+{
+	writeb(cmd_low, &(bdp->scb->scb_cmd_low));
+}
+
+/**
+ * e100_wait_scb - wait for SCB to clear
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks to see if the e100 has accepted a command.
+ * It does so by checking the command field in the SCB, which will
+ * be zeroed by the e100 upon accepting a command.  The loop waits
+ * for up to 1 millisecond for command acceptance.
+ *
+ * Returns:
+ *      true if the SCB cleared within 1 millisecond.
+ *      false if it didn't clear within 1 millisecond
+ */
+unsigned char
+e100_wait_scb(struct e100_private *bdp)
+{
+	int i;
+
+	/* loop on the scb for a few times */
+	for (i = 0; i < 100; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			return true;
+		cpu_relax();
+	}
+
+	/* it didn't work. do it the slow way using udelay()s */
+	for (i = 0; i < E100_MAX_BUSY_WAIT; i++) {
+		if (!readb(&bdp->scb->scb_cmd_low))
+			return true;
+		cpu_relax();
+		udelay(1);
+	}
+
+	return false;
+}
+
+/**
+ * e100_wait_exec_simple - issue a command
+ * @bdp: atapter's private data struct
+ * @scb_cmd_low: the command that is to be issued
+ *
+ * This general routine will issue a command to the e100 after waiting for
+ * the previous command to finish.
+ *
+ * Returns:
+ *      true if the command was issued to the chip successfully
+ *      false if the command was not issued to the chip
+ */
+inline unsigned char
+e100_wait_exec_simple(struct e100_private *bdp, u8 scb_cmd_low)
+{
+	if (!e100_wait_scb(bdp)) {
+		printk(KERN_ERR "%s e100_wait_exec_simple: Wait failed\n",
+		       bdp->device->name);
+		return false;
+	}
+	e100_exec_cmd(bdp, scb_cmd_low);
+	return true;
+}
+
+void
+e100_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+	writel(phys_addr, &(bdp->scb->scb_gen_ptr));
+	readw(&(bdp->scb->scb_status));	/* flashes last write, read-safe */
+	e100_exec_cmd(bdp, cmd);
+}
+
+unsigned char
+e100_wait_exec_cmplx(struct e100_private *bdp, u32 phys_addr, u8 cmd)
+{
+	if (!e100_wait_scb(bdp)) {
+		return false;
+	}
+	e100_exec_cmplx(bdp, phys_addr, cmd);
+	return true;
+}
+
+inline u8
+e100_wait_cus_idle(struct e100_private *bdp)
+{
+	int i;
+
+	/* loop on the scb for a few times */
+	for (i = 0; i < 100; i++) {
+		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+		     SCB_CUS_ACTIVE)) {
+			return true;
+		}
+		cpu_relax();
+	}
+
+	for (i = 0; i < E100_MAX_BUSY_WAIT; i++) {
+		if (((readw(&(bdp->scb->scb_status)) & SCB_CUS_MASK) !=
+		     SCB_CUS_ACTIVE)) {
+			return true;
+		}
+		cpu_relax();
+		udelay(1);
+	}
+
+	return false;
+}
+
+/**
+ * e100_dis_intr - disable interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine disables interrupts at the hardware, by setting
+ * the M (mask) bit in the adapter's CSR SCB command word.
+ */
+static inline void
+e100_dis_intr(struct e100_private *bdp)
+{
+	/* Disable interrupts on our PCI board by setting the mask bit */
+	writeb(SCB_INT_MASK, &bdp->scb->scb_cmd_hi);
+}
+
+/**
+ * e100_set_intr_mask - set interrupts
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets interrupts at the hardware, by resetting
+ * the M (mask) bit in the adapter's CSR SCB command word
+ */
+static inline void
+e100_set_intr_mask(struct e100_private *bdp)
+{
+	writeb(bdp->intr_mask, &bdp->scb->scb_cmd_hi);
+}
+
+static inline void
+e100_trigger_SWI(struct e100_private *bdp)
+{
+	/* Trigger interrupt on our PCI board by asserting SWI bit */
+	writeb(SCB_SOFT_INT, &bdp->scb->scb_cmd_hi);
+}
+
+static int __devinit
+e100_found1(struct pci_dev *pcid, const struct pci_device_id *ent)
+{
+	static int first_time = true;
+	struct net_device *dev = NULL;
+	struct e100_private *bdp = NULL;
+	int rc = 0;
+
+	dev = alloc_etherdev(sizeof (struct e100_private));
+	if (dev == NULL) {
+		printk(KERN_ERR "Not able to alloc etherdev struct\n");
+		rc = -ENODEV;
+		goto out;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	if (first_time) {
+		first_time = false;
+		printk(KERN_NOTICE "%s\n", e100_full_driver_name);
+		printk(KERN_NOTICE "%s\n", e100_copyright);
+		printk(KERN_NOTICE "\n");
+	}
+
+	bdp = dev->priv;
+	bdp->pdev = pcid;
+	bdp->device = dev;
+
+	pci_set_drvdata(pcid, dev);
+
+	if ((rc = e100_alloc_space(bdp)) != 0) {
+		goto err_dev;
+	}
+
+	bdp->flags = 0;
+	bdp->ifs_state = 0;
+	bdp->ifs_value = 0;
+	bdp->scb = 0;
+
+	init_timer(&bdp->nontx_timer_id);
+	bdp->nontx_timer_id.data = (unsigned long) bdp;
+	bdp->nontx_timer_id.function = (void *) &e100_non_tx_background;
+	INIT_LIST_HEAD(&(bdp->non_tx_cmd_list));
+	bdp->non_tx_command_state = E100_NON_TX_IDLE;
+
+	init_timer(&bdp->watchdog_timer);
+	bdp->watchdog_timer.data = (unsigned long) dev;
+	bdp->watchdog_timer.function = (void *) &e100_watchdog;
+
+	if ((rc = e100_pci_setup(pcid, bdp)) != 0) {
+		goto err_dealloc;
+	}
+
+	if (((bdp->pdev->device > 0x1030)
+	     && (bdp->pdev->device < 0x103F))
+	    || (bdp->pdev->device == 0x2449)
+	    || (bdp->pdev->device == 0x2459)
+	    || (bdp->pdev->device == 0x245D)) {
+		bdp->rev_id = D101MA_REV_ID;	/* workaround for ICH3 */
+		bdp->flags |= IS_ICH;
+	}
+
+	if (bdp->rev_id == 0xff)
+		bdp->rev_id = 1;
+
+	if ((u8) bdp->rev_id >= D101A4_REV_ID)
+		bdp->flags |= IS_BACHELOR;
+
+	if ((u8) bdp->rev_id >= D102_REV_ID) {
+		bdp->flags |= USE_IPCB;
+		bdp->rfd_size = 32;
+	} else {
+		bdp->rfd_size = 16;
+	}
+
+	e100_check_options(e100nics, bdp);
+
+	if (!e100_init(bdp)) {
+		printk(KERN_ERR "Failed to initialize e100, instance #%d\n",
+		       e100nics);
+		rc = -ENODEV;
+		goto err_pci;
+	}
+
+	dev->irq = pcid->irq;
+	dev->open = &e100_open;
+	dev->hard_start_xmit = &e100_xmit_frame;
+	dev->stop = &e100_close;
+	dev->change_mtu = &e100_change_mtu;
+	dev->get_stats = &e100_get_stats;
+	dev->set_multicast_list = &e100_set_multi;
+	dev->set_mac_address = &e100_set_mac;
+	dev->do_ioctl = &e100_ioctl;
+#ifdef E100_ZEROCOPY
+	if (bdp->flags & USE_IPCB) {
+		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+	}
+#endif
+	e100nics++;
+
+#ifdef E100_ETHTOOL_IOCTL
+	e100_get_speed_duplex_caps(bdp);
+#endif /*E100_ETHTOOL_IOCTL */
+
+	if ((rc = register_netdev(dev)) != 0) {
+		goto err_pci;
+	}
+
+	bdp->device_type = ent->driver_data;
+	printk(KERN_NOTICE
+	       "%s: %s\n", bdp->device->name, e100_get_brand_msg(bdp));
+	e100_print_brd_conf(bdp);
+
+	if (e100_create_proc_subdir(bdp) < 0) {
+		printk(KERN_ERR "Failed to create proc directory for %s\n",
+		       bdp->device->name);
+	}
+
+#ifdef ETHTOOL_GWOL
+	/* Disabling all WOLs as initialization */
+	bdp->wolsupported = bdp->wolopts = 0;
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		bdp->wolsupported =
+			WAKE_PHY | WAKE_UCAST | WAKE_ARP | WAKE_MAGIC;
+		bdp->wolopts = WAKE_MAGIC;
+	}
+#endif
+
+	printk(KERN_NOTICE "\n");
+
+	goto out;
+
+err_pci:
+	iounmap(bdp->scb);
+	pci_release_regions(pcid);
+	pci_disable_device(pcid);
+err_dealloc:
+	e100_dealloc_space(bdp);
+err_dev:
+	pci_set_drvdata(pcid, NULL);
+	kfree(dev);
+out:
+	return rc;
+}
+
+/**
+ * e100_clear_structs - free resources
+ * @dev: adapter's net_device struct
+ *
+ * Free all device specific structs, unmap i/o address, etc.
+ */
+static void __devexit
+e100_clear_structs(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	iounmap(bdp->scb);
+	pci_release_regions(bdp->pdev);
+	pci_disable_device(bdp->pdev);
+
+	e100_dealloc_space(bdp);
+	pci_set_drvdata(bdp->pdev, NULL);
+	kfree(dev);
+}
+
+static void __devexit
+e100_remove1(struct pci_dev *pcid)
+{
+	struct net_device *dev;
+	struct e100_private *bdp;
+
+	if (!(dev = (struct net_device *) pci_get_drvdata(pcid)))
+		return;
+
+	bdp = dev->priv;
+
+	unregister_netdev(dev);
+
+	e100_remove_proc_subdir(bdp);
+
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+
+	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+		del_timer_sync(&bdp->nontx_timer_id);
+		e100_free_nontx_list(bdp);
+		bdp->non_tx_command_state = E100_NON_TX_IDLE;
+	}
+
+#ifdef ETHTOOL_GWOL
+	/* Set up wol options and enable PME */
+	e100_do_wol(pcid, bdp);
+#endif
+
+	e100_clear_structs(dev);
+
+	--e100nics;
+}
+
+MODULE_DEVICE_TABLE(pci, e100_id_table);
+
+static struct pci_driver e100_driver = {
+	name:           "e100",
+	id_table:       e100_id_table,
+	probe:          e100_found1,
+	remove:         __devexit_p(e100_remove1),
+	suspend:        NULL,
+	resume:         NULL,
+};
+
+static int __init
+e100_init_module(void)
+{
+	return pci_module_init(&e100_driver);
+
+}
+
+static void __exit
+e100_cleanup_module(void)
+{
+	pci_unregister_driver(&e100_driver);
+}
+
+module_init(e100_init_module);
+module_exit(e100_cleanup_module);
+
+/**
+ * e100_check_options - check command line options
+ * @board: board number
+ * @bdp: atapter's private data struct
+ *
+ * This routine does range checking on command-line options
+ */
+void __devinit
+e100_check_options(int board, struct e100_private *bdp)
+{
+	int val;
+
+	if (board >= E100_MAX_NIC) {
+		printk(KERN_NOTICE "No configuration available for board #%d\n",
+		       board);
+		printk(KERN_NOTICE "Using defaults for all values\n");
+	}
+
+	val = (board < E100_MAX_NIC) ? TxDescriptors[board] : -1;
+	e100_set_int_option(&(bdp->params.TxDescriptors), val, E100_MIN_TCB,
+			    E100_MAX_TCB, E100_DEFAULT_TCB,
+			    "TxDescriptor count");
+
+	val = (board < E100_MAX_NIC) ? RxDescriptors[board] : -1;
+	e100_set_int_option(&(bdp->params.RxDescriptors), val, E100_MIN_RFD,
+			    E100_MAX_RFD, E100_DEFAULT_RFD,
+			    "RxDescriptor count");
+
+	val = (board < E100_MAX_NIC) ? e100_speed_duplex[board] : -1;
+	e100_set_int_option(&(bdp->params.e100_speed_duplex), val, 0, 4,
+			    E100_DEFAULT_SPEED_DUPLEX, "speed/duplex mode");
+
+	val = (board < E100_MAX_NIC) ? ber[board] : -1;
+	e100_set_int_option(&(bdp->params.ber), val, 0, ZLOCK_MAX_ERRORS,
+			    E100_DEFAULT_BER, "Bit Error Rate count");
+
+	val = (board < E100_MAX_NIC) ? XsumRX[board] : -1;
+	e100_set_bool_option(bdp, val, PRM_XSUMRX, E100_DEFAULT_XSUM,
+			     "XsumRX value");
+
+	/* Default ucode value depended on controller revision */
+	val = (board < E100_MAX_NIC) ? ucode[board] : -1;
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		e100_set_bool_option(bdp, val, PRM_UCODE, E100_DEFAULT_UCODE,
+				     "ucode value");
+	} else {
+		e100_set_bool_option(bdp, val, PRM_UCODE, false, "ucode value");
+	}
+
+	val = (board < E100_MAX_NIC) ? flow_control[board] : -1;
+	e100_set_bool_option(bdp, val, PRM_FC, E100_DEFAULT_FC,
+			     "flow control value");
+
+	val = (board < E100_MAX_NIC) ? IFS[board] : -1;
+	e100_set_bool_option(bdp, val, PRM_IFS, E100_DEFAULT_IFS, "IFS value");
+
+	val = (board < E100_MAX_NIC) ? BundleSmallFr[board] : -1;
+	e100_set_bool_option(bdp, val, PRM_BUNDLE_SMALL,
+			     E100_DEFAULT_BUNDLE_SMALL_FR,
+			     "CPU saver bundle small frames value");
+
+	val = (board < E100_MAX_NIC) ? IntDelay[board] : -1;
+	e100_set_int_option(&(bdp->params.IntDelay), val, 0x0, 0xFFFF,
+			    E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY,
+			    "CPU saver interrupt delay value");
+
+	val = (board < E100_MAX_NIC) ? BundleMax[board] : -1;
+	e100_set_int_option(&(bdp->params.BundleMax), val, 0x1, 0xFFFF,
+			    E100_DEFAULT_CPUSAVER_BUNDLE_MAX,
+			    "CPU saver bundle max value");
+
+	val = (board < E100_MAX_NIC) ? RxCongestionControl[board] : -1;
+	e100_set_bool_option(bdp, val, PRM_RX_CONG,
+			     E100_DEFAULT_RX_CONGESTION_CONTROL,
+			     "Rx Congestion Control value");
+
+	val = (board < E100_MAX_NIC) ? PollingMaxWork[board] : -1;
+	e100_set_int_option(&(bdp->params.PollingMaxWork), val, 1, E100_MAX_RFD,
+			    RxDescriptors[board], "Polling Max Work value");
+
+	if (val <= 0) {
+		bdp->params.b_params &= ~PRM_RX_CONG;
+	}
+}
+
+/**
+ * e100_set_int_option - check and set an integer option
+ * @option: a pointer to the relevant option field
+ * @val: the value specified
+ * @min: the minimum valid value
+ * @max: the maximum valid value
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine does range checking on a command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid, change it to the default.
+ */
+void __devinit
+e100_set_int_option(int *option, int val, int min, int max, int default_val,
+		    char *name)
+{
+	if (val == -1) {	/* no value specified. use default */
+		*option = default_val;
+
+	} else if ((val < min) || (val > max)) {
+		printk(KERN_NOTICE
+		       "Invalid %s specified (%i). Valid range is %i-%i\n",
+		       name, val, min, max);
+		printk(KERN_NOTICE "Using default %s of %i\n", name,
+		       default_val);
+		*option = default_val;
+	} else {
+		printk(KERN_INFO "Using specified %s of %i\n", name, val);
+		*option = val;
+	}
+}
+
+/**
+ * e100_set_bool_option - check and set a boolean option
+ * @bdp: atapter's private data struct
+ * @val: the value specified
+ * @mask: the mask for the relevant option
+ * @default_val: the default value
+ * @name: the name of the option
+ *
+ * This routine checks a boolean command-line option.
+ * If the option's value is '-1' use the specified default.
+ * Otherwise, if the value is invalid (not 0 or 1), 
+ * change it to the default.
+ */
+void __devinit
+e100_set_bool_option(struct e100_private *bdp, int val, u32 mask,
+		     int default_val, char *name)
+{
+	if (val == -1) {
+		if (default_val)
+			bdp->params.b_params |= mask;
+
+	} else if ((val != true) && (val != false)) {
+		printk(KERN_NOTICE
+		       "Invalid %s specified (%i). Valid values are %i/%i\n",
+		       name, val, false, true);
+		printk(KERN_NOTICE "Using default %s of %i\n", name,
+		       default_val);
+
+		if (default_val)
+			bdp->params.b_params |= mask;
+	} else {
+		printk(KERN_INFO "Using specified %s of %i\n", name, val);
+		if (val)
+			bdp->params.b_params |= mask;
+	}
+}
+
+static int
+e100_open(struct net_device *dev)
+{
+	struct e100_private *bdp;
+	int rc = 0;
+
+	bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		rc = -EBUSY;
+		goto exit;
+	}
+
+	/* setup the tcb pool */
+	if (!e100_alloc_tcb_pool(bdp)) {
+		rc = -ENOMEM;
+		goto err_exit;
+	}
+	bdp->last_tcb = NULL;
+
+	bdp->tcb_pool.head = 0;
+	bdp->tcb_pool.tail = 1;	
+
+	e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data,
+			    bdp->params.TxDescriptors, bdp);
+
+	if (!e100_alloc_rfd_pool(bdp)) {
+		rc = -ENOMEM;
+		goto err_exit;
+	}
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) {
+		rc = -EAGAIN;
+		goto err_exit;
+	}
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) {
+		rc = -EAGAIN;
+		goto err_exit;
+	}
+
+	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+	netif_start_queue(dev);
+
+	e100_start_ru(bdp);
+	if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ,
+			      e100_short_driver_name, dev)) != 0) {
+		del_timer_sync(&bdp->watchdog_timer);
+		goto err_exit;
+	}
+	if (bdp->params.b_params & PRM_RX_CONG) {
+		DECLARE_TASKLET(polling_tasklet,
+				e100_polling_tasklet, (unsigned long) bdp);
+		bdp->polling_tasklet = polling_tasklet;
+	}
+	bdp->intr_mask = 0;
+	e100_set_intr_mask(bdp);
+
+	e100_force_config(bdp);
+
+	goto exit;
+
+err_exit:
+	e100_clear_pools(bdp);
+exit:
+	read_unlock(&(bdp->isolate_lock));
+	return rc;
+}
+
+static int
+e100_close(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	bdp->intr_mask = SCB_INT_MASK;
+	e100_isolate_driver(bdp);
+
+#ifdef ETHTOOL_GWOL
+	bdp->ip_lbytes = e100_get_ip_lbytes(dev);
+#endif
+	free_irq(dev->irq, dev);
+	e100_clear_pools(bdp);
+
+	if (bdp->params.b_params & PRM_RX_CONG) {
+		tasklet_kill(&(bdp->polling_tasklet));
+	}
+
+	/* set the isolate flag to false, so e100_open can be called */
+	bdp->driver_isolated = false;
+
+	return 0;
+}
+
+static int
+e100_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE)))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static int
+e100_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+{
+	int rc = 0;
+	int notify_stop = false;
+	struct e100_private *bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		rc = -EBUSY;
+		goto exit2;
+	}
+
+	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
+		notify_stop = true;
+		rc = 1;
+		goto exit2;
+	}
+
+	if (!TCBS_AVAIL(bdp->tcb_pool) ||
+	    (bdp->non_tx_command_state != E100_NON_TX_IDLE)) {
+		notify_stop = true;
+		rc = 1;
+		goto exit1;
+	}
+
+	e100_prepare_xmit_buff(bdp, skb);
+
+	bdp->drv_stats.net_stats.tx_bytes += skb->len;
+
+	dev->trans_start = jiffies;
+
+exit1:
+	spin_unlock(&bdp->bd_non_tx_lock);
+exit2:
+	read_unlock(&(bdp->isolate_lock));
+	if (notify_stop) {
+		netif_stop_queue(dev);
+	}
+
+	return rc;
+}
+
+/**
+ * e100_get_stats - get driver statistics
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called when the OS wants the adapter's stats returned.
+ * It returns the address of the net_device_stats stucture for the device.
+ * If the statistics are currently being updated, then they might be incorrect
+ * for a short while. However, since this cannot actually cause damage, no
+ * locking is used.
+ */
+struct net_device_stats *
+e100_get_stats(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	bdp->drv_stats.net_stats.tx_errors =
+		bdp->drv_stats.net_stats.tx_carrier_errors +
+		bdp->drv_stats.net_stats.tx_aborted_errors;
+
+	bdp->drv_stats.net_stats.rx_errors =
+		bdp->drv_stats.net_stats.rx_crc_errors +
+		bdp->drv_stats.net_stats.rx_frame_errors +
+		bdp->drv_stats.net_stats.rx_length_errors +
+		bdp->drv_stats.rcv_cdt_frames;
+
+	return &(bdp->drv_stats.net_stats);
+}
+
+/**
+ * e100_set_mac - set the MAC address
+ * @dev: adapter's net_device struct
+ * @addr: the new address
+ *
+ * This routine sets the ethernet address of the board
+ * Returns:
+ * 0  - if successful
+ * -1 - otherwise
+ */
+static int
+e100_set_mac(struct net_device *dev, void *addr)
+{
+	struct e100_private *bdp;
+	int rc = -1;
+	struct sockaddr *p_sockaddr = (struct sockaddr *) addr;
+
+	bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
+		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
+		rc = 0;
+	}
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+	return rc;
+}
+
+static void
+e100_set_multi_exec(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	mltcst_cb_t *mcast_buff;
+	cb_header_t *cb_hdr;
+	struct dev_mc_list *mc_list;
+	unsigned int i;
+	nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+	if (cmd != NULL) {
+		mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast);
+		cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr);
+	} else {
+		return;
+	}
+
+	/* initialize the multi cast command */
+	cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST);
+
+	/* now fill in the rest of the multicast command */
+	*(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6);
+	for (i = 0, mc_list = dev->mc_list;
+	     (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS);
+	     i++, mc_list = mc_list->next) {
+		/* copy into the command */
+		memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]),
+		       (u8 *) &(mc_list->dmi_addr), ETH_ALEN);
+	}
+
+	if (!e100_exec_non_cu_cmd(bdp, cmd)) {
+		printk(KERN_WARNING "%s: Multicast setup failed\n", dev->name);
+	}
+}
+
+/**
+ * e100_set_multi - set multicast status
+ * @dev: adapter's net_device struct
+ *
+ * This routine is called to add or remove multicast addresses, and/or to
+ * change the adapter's promiscuous state.
+ */
+static void
+e100_set_multi(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	unsigned char promisc_enbl;
+	unsigned char mulcast_enbl;
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	promisc_enbl = (dev->flags & IFF_PROMISC);
+	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
+			(dev->mc_count > MAX_MULTICAST_ADDRS));
+
+	e100_config_promisc(bdp, promisc_enbl);
+	e100_config_mulcast_enbl(bdp, mulcast_enbl);
+
+	/* reconfigure the chip if something has changed in its config space */
+	e100_config(bdp);
+
+	if ((promisc_enbl) || (mulcast_enbl)) {
+		goto exit;	/* no need for Multicast Cmd */
+	}
+
+	/* get the multicast CB */
+	e100_set_multi_exec(dev);
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+}
+
+static int
+e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+
+	switch (cmd) {
+
+#ifdef E100_ETHTOOL_IOCTL
+	case SIOCETHTOOL:
+		return e100_do_ethtool_ioctl(dev, ifr);
+		break;
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef E100_MII_IOCTL
+	case SIOCGMIIPHY:	/* Get address of MII PHY in use. */
+	case SIOCGMIIREG:	/* Read MII PHY register. */
+	case SIOCSMIIREG:	/* Write to MII PHY register. */
+		return e100_mii_ioctl(dev, ifr, cmd);
+		break;
+#endif /*E100_MII_IOCTL */
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+
+}
+
+/**
+ * e100init - initialize the adapter
+ * @bdp: atapter's private data struct
+ *
+ * This routine is called when this driver is loaded. This is the initialization
+ * routine which allocates memory, configures the adapter and determines the
+ * system resources.
+ *
+ * Returns:
+ *      true: if successful
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_init(struct e100_private *bdp)
+{
+	e100_sw_init(bdp);
+
+	if (!e100_selftest(bdp, NULL, NULL)) {
+		printk(KERN_ERR "selftest failed\n");
+		return false;
+	}
+
+	/* read the MAC address from the eprom */
+	e100_rd_eaddr(bdp);
+	/* read NIC's part number */
+	e100_rd_pwa_no(bdp);
+
+	if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) {
+		printk(KERN_ERR "hw init failed\n");
+		return false;
+	}
+	e100_dis_intr(bdp);
+
+	return true;
+}
+
+/**
+ * e100_sw_init - initialize software structs
+ * @bdp: atapter's private data struct
+ * 
+ * This routine initializes all software structures. Sets up the
+ * circular structures for the RFD's & TCB's. Allocates the per board
+ * structure for storing adapter information. The CSR is also memory 
+ * mapped in this routine.
+ *
+ * Returns :
+ *      true: if S/W was successfully initialized
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_sw_init(struct e100_private *bdp)
+{
+	bdp->next_cu_cmd = START_WAIT;	// init the next cu state
+
+	/* 
+	 * Set the value for # of good xmits per underrun. the value assigned
+	 * here is an intelligent  suggested default. Nothing magical about it.
+	 */
+	bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN;
+
+	/* get the default transmit threshold value */
+	bdp->tx_thld = TX_THRSHLD;
+
+	/* get the EPROM size */
+	bdp->eeprom_size = e100_eeprom_size(bdp);
+
+	/* Initialize our spinlocks */
+	spin_lock_init(&(bdp->bd_lock));
+	spin_lock_init(&(bdp->bd_non_tx_lock));
+	spin_lock_init(&(bdp->config_lock));
+	spin_lock_init(&(bdp->mdi_access_lock));
+	bdp->isolate_lock = RW_LOCK_UNLOCKED;
+	bdp->driver_isolated = false;
+
+	return 1;
+}
+
+/**
+ * e100_hw_init - initialized tthe hardware
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine performs a reset on the adapter, and configures the adapter.
+ * This includes configuring the 82557 LAN controller, validating and setting
+ * the node address, detecting and configuring the Phy chip on the adapter,
+ * and initializing all of the on chip counters.
+ *
+ * Returns:
+ *      true - If the adapter was initialized
+ *      false - If the adapter failed initialization
+ */
+unsigned char __devinit
+e100_hw_init(struct e100_private *bdp, u32 reset_cmd)
+{
+	if (!e100_phy_init(bdp))
+		return false;
+
+	/* Issue a software reset to the e100 */
+	e100_sw_reset(bdp, reset_cmd);
+
+	/* Load the CU BASE (set to 0, because we use linear mode) */
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+		return false;
+
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+		return false;
+
+	/* Load interrupt microcode  */
+	if (e100_load_microcode(bdp)) {
+		bdp->flags |= DF_UCODE_LOADED;
+	}
+
+	e100_config_init(bdp);
+	if (!e100_config(bdp)) {
+		return false;
+	}
+
+	if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr))
+		return false;
+
+	/* Clear the internal counters */
+	if (!e100_clr_cntrs(bdp))
+		return false;
+
+	/* Change for 82558 enhancement */
+	/* If 82558/9 and if the user has enabled flow control, set up the
+	 * Flow Control Reg. in the CSR */
+	if ((bdp->flags & IS_BACHELOR)
+	    && (bdp->params.b_params & PRM_FC)) {
+		writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld);
+		writeb(DFLT_FC_CMD,
+		       &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff);
+	}
+
+	return true;
+}
+
+/**
+ * e100_setup_tcb_pool - setup TCB circular list
+ * @head: Pointer to head of the allocated TCBs
+ * @qlen: Number of elements in the queue
+ * @bdp: atapter's private data struct
+ * 
+ * This routine arranges the contigiously allocated TCB's in a circular list.
+ * Also does the one time initialization of the TCBs.
+ */
+static void
+e100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp)
+{
+	int ele_no;
+	tcb_t *pcurr_tcb;	/* point to current tcb */
+	u32 next_phys;		/* the next phys addr */
+	u16 txcommand = CB_S_BIT | CB_TX_SF_BIT;
+
+	if (bdp->flags & USE_IPCB) {
+		txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT;
+	} else if (bdp->flags & IS_BACHELOR) {
+		txcommand |= CB_TRANSMIT | CB_CID_DEFAULT;
+	} else {
+		txcommand |= CB_TRANSMIT;
+	}
+
+	for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head;
+	     ele_no < qlen; ele_no++, pcurr_tcb++) {
+
+		/* set the phys addr for this TCB, next_phys has not incr. yet */
+		pcurr_tcb->tcb_phys = next_phys;
+		next_phys += sizeof (tcb_t);
+
+		/* set the link to next tcb */
+		if (ele_no == (qlen - 1))
+			pcurr_tcb->tcb_hdr.cb_lnk_ptr =
+				cpu_to_le32(bdp->tcb_phys);
+		else
+			pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys);
+
+		pcurr_tcb->tcb_hdr.cb_status = 0;
+		pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand);
+		pcurr_tcb->tcb_cnt = 0;	
+		pcurr_tcb->tcb_thrshld = bdp->tx_thld;	
+		if (ele_no < 2) {
+			pcurr_tcb->tcb_hdr.cb_status =
+				cpu_to_le16(CB_STATUS_COMPLETE);
+		}
+		pcurr_tcb->tcb_tbd_num = 1;
+
+		if (bdp->flags & IS_BACHELOR) {
+			pcurr_tcb->tcb_tbd_ptr =
+				__constant_cpu_to_le32(0xFFFFFFFF);
+		} else {
+			pcurr_tcb->tcb_tbd_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+		}
+
+#ifdef E100_ZEROCOPY
+		if (bdp->flags & IS_BACHELOR) {
+			pcurr_tcb->tcb_tbd_expand_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x20);
+		} else {
+			pcurr_tcb->tcb_tbd_expand_ptr =
+				cpu_to_le32(pcurr_tcb->tcb_phys + 0x10);
+		}
+		pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr;
+#endif
+
+		if (bdp->flags & USE_IPCB) {
+			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]);
+			pcurr_tcb->tcbu.ipcb.ip_activation_high =
+				IPCB_IP_ACTIVATION_DEFAULT;
+			pcurr_tcb->tcbu.ipcb.vlan = 0;
+		} else {
+			pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]);
+		}
+
+		pcurr_tcb->tcb_skb = NULL;
+	}
+
+	wmb();
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       Memory Management Routines                                        */
+/***************************************************************************/
+
+/**
+ * e100_alloc_space - allocate private driver data
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the driver. Memory allocated is for the
+ * selftest and statistics structures.
+ *
+ * Returns:
+ *      0: if the operation was successful
+ *      %-ENOMEM: if memory allocation failed
+ */
+unsigned char __devinit
+e100_alloc_space(struct e100_private *bdp)
+{
+	unsigned long off;
+
+	/* allocate all the dma-able structures in one call:
+	 * selftest results, adapter stats, and non-tx cb commands */
+	if (!(bdp->dma_able =
+	      pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+				   &(bdp->dma_able_phys)))) {
+		goto err;
+	}
+
+	/* now assign the various pointers into the struct we've just allocated */
+	off = offsetof(bd_dma_able_t, selftest);
+
+	bdp->selftest = (self_test_t *) (bdp->dma_able + off);
+	bdp->selftest_phys = bdp->dma_able_phys + off;
+
+	off = offsetof(bd_dma_able_t, stats_counters);
+
+	bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off);
+	bdp->stat_cnt_phys = bdp->dma_able_phys + off;
+
+	return 0;
+
+err:
+	printk(KERN_ERR
+	       "%s - Failed to allocate memory\n", e100_short_driver_name);
+	return -ENOMEM;
+}
+
+/**
+ * e100_alloc_tcb_pool - allocate TCB circular list
+ * @bdp: atapter's private data struct
+ *
+ * This routine allocates memory for the circular list of transmit descriptors.
+ *
+ * Returns:
+ *       0: if allocation has failed.
+ *       1: Otherwise. 
+ */
+int
+e100_alloc_tcb_pool(struct e100_private *bdp)
+{
+	int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors;
+
+	/* allocate space for the TCBs */
+	if (!(bdp->tcb_pool.data =
+	      pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys)))
+		return 0;
+
+	memset(bdp->tcb_pool.data, 0x00, stcb);
+
+	return 1;
+}
+
+void
+e100_free_tcb_pool(struct e100_private *bdp)
+{
+	pci_free_consistent(bdp->pdev,
+			    sizeof (tcb_t) * bdp->params.TxDescriptors,
+			    bdp->tcb_pool.data, bdp->tcb_phys);
+	bdp->tcb_phys = 0;
+}
+
+static void
+e100_dealloc_space(struct e100_private *bdp)
+{
+	if (bdp->dma_able) {
+		pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t),
+				    bdp->dma_able, bdp->dma_able_phys);
+	}
+
+	bdp->selftest_phys = 0;
+	bdp->stat_cnt_phys = 0;
+	bdp->dma_able_phys = 0;
+	bdp->dma_able = 0;
+}
+
+static void
+e100_free_rfd_pool(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct;
+
+	while (!list_empty(&(bdp->active_rx_list))) {
+
+		rx_struct = list_entry(bdp->active_rx_list.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+				 sizeof (rfd_t), PCI_DMA_TODEVICE);
+		dev_kfree_skb(rx_struct->skb);
+		kfree(rx_struct);
+	}
+
+	while (!list_empty(&(bdp->rx_struct_pool))) {
+		rx_struct = list_entry(bdp->rx_struct_pool.next,
+				       struct rx_list_elem, list_elem);
+		list_del(&(rx_struct->list_elem));
+		kfree(rx_struct);
+	}
+}
+
+/**
+ * e100_alloc_rfd_pool - allocate RFDs
+ * @bdp: atapter's private data struct
+ *
+ * Allocates initial pool of skb which holds both rfd and data,
+ * and return a pointer to the head of the list
+ */
+static int
+e100_alloc_rfd_pool(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct;
+	int i;
+
+	INIT_LIST_HEAD(&(bdp->active_rx_list));
+	INIT_LIST_HEAD(&(bdp->rx_struct_pool));
+	bdp->skb_req = bdp->params.RxDescriptors;
+	for (i = 0; i < bdp->skb_req; i++) {
+		rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC);
+		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+	}
+	e100_alloc_skbs(bdp);
+	return !list_empty(&(bdp->active_rx_list));
+
+}
+
+void
+e100_clear_pools(struct e100_private *bdp)
+{
+	bdp->last_tcb = NULL;
+	e100_free_rfd_pool(bdp);
+	e100_free_tcb_pool(bdp);
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*      Run Time Functions                                                   */
+/*****************************************************************************/
+
+/**
+ * e100_watchdog
+ * @dev: adapter's net_device struct
+ *
+ * This routine runs every 2 seconds and updates our statitics and link state,
+ * and refreshs txthld value.
+ */
+void
+e100_watchdog(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+	if (!netif_running(dev)) {
+		goto exit;
+	}
+	spin_lock_bh(&(bdp->mdi_access_lock));
+
+	/* check if link state has changed */
+	if (e100_phy_check(bdp)) {
+		if (netif_carrier_ok(dev)) {
+			printk(KERN_ERR
+			       "e100: %s NIC Link is Up %d Mbps %s duplex\n",
+			       bdp->device->name, bdp->cur_line_speed,
+			       (bdp->cur_dplx_mode == HALF_DUPLEX) ?
+			       "Half" : "Full");
+
+			e100_config_fc(bdp);
+			e100_config(bdp);	
+
+		} else {
+			printk(KERN_ERR "e100: %s NIC Link is Down\n",
+			       bdp->device->name);
+		}
+	}
+
+	// toggle the tx queue according to link status
+	// this also resolves a race condition between tx & non-cu cmd flows
+	if (netif_carrier_ok(dev)) {
+		if (netif_running(dev))
+			netif_wake_queue(dev);
+	} else {
+		netif_stop_queue(dev);
+	}
+
+	rmb();
+
+	if (e100_update_stats(bdp)) {
+
+		/* Check if a change in the IFS parameter is needed,
+		   and configure the device accordingly */
+		if (bdp->params.b_params & PRM_IFS)
+			e100_manage_adaptive_ifs(bdp);
+
+		/* Now adjust our dynamic tx threshold value */
+		e100_refresh_txthld(bdp);
+
+		/* Now if we are on a 557 and we havn't received any frames then we
+		 * should issue a multicast command to reset the RU */
+		if (bdp->rev_id < D101A4_REV_ID) {
+			if (!(bdp->stats_counters->basic_stats.rcv_gd_frames)) {
+				e100_set_multi(dev);
+			}
+		}
+
+		/* Update the statistics needed by the upper interface */
+		/* This should be the last statistic related command
+		 * as it's async. now */
+		e100_dump_stats_cntrs(bdp);
+	}
+
+	wmb();
+
+	spin_unlock_bh(&(bdp->mdi_access_lock));
+
+	/* relaunch watchdog timer in 2 sec */
+	mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ));
+
+	if (list_empty(&bdp->active_rx_list))
+		e100_trigger_SWI(bdp);
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_manage_adaptive_ifs
+ * @bdp: atapter's private data struct
+ *
+ * This routine manages the adaptive Inter-Frame Spacing algorithm
+ * using a state machine.
+ */
+void
+e100_manage_adaptive_ifs(struct e100_private *bdp)
+{
+	static u16 state_table[9][4] = {	// rows are states
+		{2, 0, 0, 0},	// state0   // column0: next state if increasing
+		{2, 0, 5, 30},	// state1   // column1: next state if decreasing
+		{5, 1, 5, 30},	// state2   // column2: IFS value for 100 mbit
+		{5, 3, 0, 0},	// state3   // column3: IFS value for 10 mbit
+		{5, 3, 10, 60},	// state4
+		{8, 4, 10, 60},	// state5
+		{8, 6, 0, 0},	// state6
+		{8, 6, 20, 60},	// state7
+		{8, 7, 20, 60}	// state8
+	};
+
+	u32 transmits =
+		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_gd_frames);
+	u32 collisions =
+		le32_to_cpu(bdp->stats_counters->basic_stats.xmt_ttl_coll);
+	u32 state = bdp->ifs_state;
+	u32 old_value = bdp->ifs_value;
+	int next_col;
+	u32 min_transmits;
+
+	if (bdp->cur_dplx_mode == FULL_DUPLEX) {
+		bdp->ifs_state = 0;
+		bdp->ifs_value = 0;
+
+	} else {		/* Half Duplex */
+		/* Set speed specific parameters */
+		if (bdp->cur_line_speed == 100) {
+			next_col = 2;
+			min_transmits = MIN_NUMBER_OF_TRANSMITS_100;
+
+		} else {	/* 10 Mbps */
+			next_col = 3;
+			min_transmits = MIN_NUMBER_OF_TRANSMITS_10;
+		}
+
+		if ((transmits / 32 < collisions)
+		    && (transmits > min_transmits)) {
+			state = state_table[state][0];	/* increment */
+
+		} else if (transmits < min_transmits) {
+			state = state_table[state][1];	/* decrement */
+		}
+
+		bdp->ifs_value = state_table[state][next_col];
+		bdp->ifs_state = state;
+	}
+
+	/* If the IFS value has changed, configure the device */
+	if (bdp->ifs_value != old_value) {
+		e100_config_ifs(bdp);
+		e100_config(bdp);
+	}
+}
+
+void
+e100_polling_tasklet(unsigned long ptr)
+{
+	struct e100_private *bdp = (struct e100_private *) ptr;
+	unsigned int rx_congestion = 0;
+	u32 skb_cnt;
+
+	/* the device is closed, don't continue or else bad things may happen. */
+	if (!netif_running(bdp->device)) {
+		return;
+	}
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		tasklet_schedule(&(bdp->polling_tasklet));
+		goto exit;
+	}
+
+	e100_alloc_skbs(bdp);
+
+	skb_cnt = e100_rx_srv(bdp, bdp->params.PollingMaxWork, &rx_congestion);
+
+	bdp->drv_stats.rx_tasklet_pkts += skb_cnt;
+
+	if (rx_congestion || skb_cnt) {
+		tasklet_schedule(&(bdp->polling_tasklet));
+	} else {
+		bdp->intr_mask &= ~SCB_INT_MASK;
+
+		bdp->drv_stats.poll_intr_switch++;
+	}
+
+	bdp->tx_count = 0;	/* restart tx interrupt batch count */
+	e100_tx_srv(bdp);
+
+	e100_set_intr_mask(bdp);
+
+exit:
+	read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100intr - interrupt handler
+ * @irq: the IRQ number
+ * @dev_inst: the net_device struct
+ * @regs: registers (unused)
+ *
+ * This routine is the ISR for the e100 board. It services
+ * the RX & TX queues & starts the RU if it has stopped due
+ * to no resources.
+ */
+void
+e100intr(int irq, void *dev_inst, struct pt_regs *regs)
+{
+	struct net_device *dev;
+	struct e100_private *bdp;
+	u16 intr_status;
+
+	dev = dev_inst;
+	bdp = dev->priv;
+
+	intr_status = readw(&bdp->scb->scb_status);
+	if (!intr_status || (intr_status == 0xffff)) {
+		return;
+	}
+
+	/* disable intr before we ack & after identifying the intr as ours */
+	e100_dis_intr(bdp);
+
+	writew(intr_status, &bdp->scb->scb_status);	/* ack intrs */
+
+	/* the device is closed, don't continue or else bad things may happen. */
+	if (!netif_running(dev)) {
+		e100_set_intr_mask(bdp);
+		return;
+	}
+
+	read_lock(&(bdp->isolate_lock));
+	if (bdp->driver_isolated) {
+		goto exit;
+	}
+
+	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
+	if (intr_status & SCB_STATUS_ACK_SWI) {
+		e100_alloc_skbs(bdp);
+	}
+
+	/* do recv work if any */
+	if (intr_status &
+	    (SCB_STATUS_ACK_FR | SCB_STATUS_ACK_RNR | SCB_STATUS_ACK_SWI)) {
+		int rx_congestion;
+
+		bdp->drv_stats.rx_intr_pkts +=
+			e100_rx_srv(bdp, 0, &rx_congestion);
+		if ((bdp->params.b_params & PRM_RX_CONG) && rx_congestion) {
+			bdp->intr_mask |= SCB_INT_MASK;
+			tasklet_schedule(&(bdp->polling_tasklet));
+
+			bdp->drv_stats.poll_intr_switch++;
+		}
+	}
+
+	/* clean up after tx'ed packets */
+	if (intr_status & (SCB_STATUS_ACK_CNA | SCB_STATUS_ACK_CX)) {
+		bdp->tx_count = 0;	/* restart tx interrupt batch count */
+		e100_tx_srv(bdp);
+	}
+
+exit:
+	e100_set_intr_mask(bdp);
+	read_unlock(&(bdp->isolate_lock));
+}
+
+/**
+ * e100_tx_skb_free - free TX skbs resources
+ * @bdp: atapter's private data struct
+ * @tcb: associated tcb of the freed skb
+ *
+ * This routine frees resources of TX skbs.
+ */
+static void inline
+e100_tx_skb_free(struct e100_private *bdp, tcb_t *tcb)
+{
+	if (tcb->tcb_skb) {
+#ifdef E100_ZEROCOPY
+		int i;
+		tbd_t *tbd_arr = tcb->tbd_ptr;
+		int frags = skb_shinfo(tcb->tcb_skb)->nr_frags;
+
+		for (i = 0; i <= frags; i++, tbd_arr++) {
+			pci_unmap_single(bdp->pdev,
+					 le32_to_cpu(tbd_arr->tbd_buf_addr),
+					 le16_to_cpu(tbd_arr->tbd_buf_cnt),
+					 PCI_DMA_TODEVICE);
+		}
+#else
+		pci_unmap_single(bdp->pdev,
+				 le32_to_cpu((tcb->tbd_ptr)->tbd_buf_addr),
+				 tcb->tcb_skb->len, PCI_DMA_TODEVICE);
+#endif
+		dev_kfree_skb_irq(tcb->tcb_skb);
+		tcb->tcb_skb = NULL;
+	}
+}
+
+/**
+ * e100_tx_srv - service TX queues
+ * @bdp: atapter's private data struct
+ *
+ * This routine services the TX queues. It reclaims the TCB's & TBD's & other
+ * resources used during the transmit of this buffer. It is called from the ISR.
+ * We don't need a tx_lock since we always access buffers which were already
+ * prepared.
+ */
+void
+e100_tx_srv(struct e100_private *bdp)
+{
+	tcb_t *tcb;
+	int i;
+
+	/* go over at most TxDescriptors buffers */
+	for (i = 0; i < bdp->params.TxDescriptors; i++) {
+		tcb = bdp->tcb_pool.data;
+		tcb += bdp->tcb_pool.head;
+
+		rmb();
+
+		/* if the buffer at 'head' is not complete, break */
+		if (!(tcb->tcb_hdr.cb_status &
+		      __constant_cpu_to_le16(CB_STATUS_COMPLETE)))
+			break;
+
+		/* service next buffer, clear the out of resource condition */
+		e100_tx_skb_free(bdp, tcb);
+
+		if (netif_running(bdp->device))
+			netif_wake_queue(bdp->device);
+
+		/* if we've caught up with 'tail', break */
+		if (NEXT_TCB_TOUSE(bdp->tcb_pool.head) == bdp->tcb_pool.tail) {
+			break;
+		}
+
+		bdp->tcb_pool.head = NEXT_TCB_TOUSE(bdp->tcb_pool.head);
+	}
+}
+
+/**
+ * e100_rx_srv - service RX queue
+ * @bdp: atapter's private data struct
+ * @max_number_of_rfds: max number of RFDs to process
+ * @rx_congestion: flag pointer, to inform the calling function of congestion.
+ *
+ * This routine processes the RX interrupt & services the RX queues.
+ * For each successful RFD, it allocates a new msg block, links that
+ * into the RFD list, and sends the old msg upstream.
+ * The new RFD is then put at the end of the free list of RFD's.
+ * It returns the number of serviced RFDs.
+ */
+u32
+e100_rx_srv(struct e100_private *bdp, u32 max_number_of_rfds,
+	    int *rx_congestion)
+{
+	rfd_t *rfd;		/* new rfd, received rfd */
+	int i;
+	u16 rfd_status;
+	struct sk_buff *skb;
+	struct net_device *dev;
+	unsigned int data_sz;
+	struct rx_list_elem *rx_struct;
+	u32 rfd_cnt = 0;
+
+	if (rx_congestion) {
+		*rx_congestion = 0;
+	}
+
+	dev = bdp->device;
+
+	/* current design of rx is as following:
+	 * 1. socket buffer (skb) used to pass network packet to upper layer
+	 * 2. all HW host memory structures (like RFDs, RBDs and data buffers)
+	 *    are placed in a skb's data room
+	 * 3. when rx process is complete, we change skb internal pointers to exclude
+	 *    from data area all unrelated things (RFD, RDB) and to leave
+	 *    just rx'ed packet netto
+	 * 4. for each skb passed to upper layer, new one is allocated instead.
+	 * 5. if no skb left, in 2 sec another atempt to allocate skbs will be made
+	 *    (watchdog trigger SWI intr and isr should allocate new skbs)
+	 */
+	for (i = 0; i < bdp->params.RxDescriptors; i++) {
+		if (max_number_of_rfds && (rfd_cnt >= max_number_of_rfds)) {
+			break;
+		}
+		if (list_empty(&(bdp->active_rx_list)))
+			break;
+
+		rx_struct = list_entry(bdp->active_rx_list.next,
+				       struct rx_list_elem, list_elem);
+		skb = rx_struct->skb;
+
+		rfd = RFD_POINTER(skb, bdp);	/* locate RFD within skb */
+
+		// sync only the RFD header
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
+		rfd_status = le16_to_cpu(rfd->rfd_header.cb_status);	/* get RFD's status */
+		if (!(rfd_status & RFD_STATUS_COMPLETE))	/* does not contains data yet - exit */
+			break;
+
+		/* to allow manipulation with current skb we need to unlink it */
+		list_del(&(rx_struct->list_elem));
+
+		/* do not free & unmap badly recieved packet.
+		 * move it to the end of skb list for reuse */
+		if (!(rfd_status & RFD_STATUS_OK)) {
+			e100_add_skb_to_end(bdp, rx_struct);
+			continue;
+		}
+
+		data_sz = min_t(u16, (le16_to_cpu(rfd->rfd_act_cnt) & 0x3fff),
+				(sizeof (rfd_t) - bdp->rfd_size));
+
+		/* now sync all the data */
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    (data_sz + bdp->rfd_size),
+				    PCI_DMA_FROMDEVICE);
+
+		// we unmap using DMA_TODEVICE to avoid another memcpy from the 
+		// bounce buffer
+		pci_unmap_single(bdp->pdev, rx_struct->dma_addr,
+				 sizeof (rfd_t), PCI_DMA_TODEVICE);
+
+		list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool));
+
+		/* end of dma access to rfd */
+		bdp->skb_req++;	/* incr number of requested skbs */
+		e100_alloc_skbs(bdp);	/* and get them */
+
+		/* set packet size, excluding checksum (2 last bytes) if it is present */
+		if ((bdp->flags & DF_CSUM_OFFLOAD)
+		    && (bdp->rev_id < D102_REV_ID))
+			skb_put(skb, (int) data_sz - 2);
+		else
+			skb_put(skb, (int) data_sz);
+
+		/* set the protocol */
+		skb->protocol = eth_type_trans(skb, dev);
+
+		/* set the checksum info */
+		if (bdp->flags & DF_CSUM_OFFLOAD) {
+			if (bdp->rev_id >= D102_REV_ID) {
+				skb->ip_summed = e100_D102_check_checksum(rfd);
+			} else {
+				skb->ip_summed = e100_D101M_checksum(bdp, skb);
+			}
+		} else {
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+
+		switch (netif_rx(skb)) {
+		case NET_RX_BAD:
+			break;
+
+		case NET_RX_DROP:
+		case NET_RX_CN_MOD:
+		case NET_RX_CN_HIGH:
+			if (bdp->params.b_params & PRM_RX_CONG) {
+				if (rx_congestion) {
+					*rx_congestion = 1;
+				}
+			}
+			/* FALL THROUGH TO STATISTICS UPDATE */
+		default:
+			bdp->drv_stats.net_stats.rx_bytes += skb->len;
+			break;
+		}
+
+		rfd_cnt++;
+	}			/* end of rfd loop */
+
+	/* restart the RU if it has stopped */
+	if ((readw(&bdp->scb->scb_status) & SCB_RUS_MASK) != SCB_RUS_READY) {
+		e100_start_ru(bdp);
+	}
+
+	return rfd_cnt;
+}
+
+void
+e100_refresh_txthld(struct e100_private *bdp)
+{
+	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+	/* as long as tx_per_underrun is not 0, we can go about dynamically *
+	 * adjusting the xmit threshold. we stop doing that & resort to defaults
+	 * * once the adjustments become meaningless. the value is adjusted by *
+	 * dumping the error counters & checking the # of xmit underrun errors *
+	 * we've had. */
+	if (bdp->tx_per_underrun) {
+		/* We are going to last values dumped from the dump statistics
+		 * command */
+		if (le32_to_cpu(pstat->xmt_gd_frames)) {
+			if (le32_to_cpu(pstat->xmt_uruns)) {
+				/* 
+				 * if we have had more than one underrun per "DEFAULT #
+				 * OF XMITS ALLOWED PER UNDERRUN" good xmits, raise the
+				 * THRESHOLD.
+				 */
+				if ((le32_to_cpu(pstat->xmt_gd_frames) /
+				     le32_to_cpu(pstat->xmt_uruns)) <
+				    bdp->tx_per_underrun) {
+					bdp->tx_thld += 3;
+				}
+			}
+
+			/* 
+			 * if we've had less than one underrun per the DEFAULT number of
+			 * of good xmits allowed, lower the THOLD but not less than 0 
+			 */
+			if (le32_to_cpu(pstat->xmt_gd_frames) >
+			    bdp->tx_per_underrun) {
+				bdp->tx_thld--;
+
+				if (bdp->tx_thld < 6)
+					bdp->tx_thld = 6;
+
+			}
+		}
+
+		/* end good xmits */
+		/* 
+		 * * if our adjustments are becoming unresonable, stop adjusting &
+		 * resort * to defaults & pray. A THOLD value > 190 means that the
+		 * adapter will * wait for 190*8=1520 bytes in TX FIFO before it
+		 * starts xmit. Since * MTU is 1514, it doesn't make any sense for
+		 * further increase. */
+		if (bdp->tx_thld >= 190) {
+			bdp->tx_per_underrun = 0;
+			bdp->tx_thld = 189;
+		}
+	}			/* end underrun check */
+}
+
+/**
+ * e100_prepare_xmit_buff - prepare a buffer for transmission
+ * @bdp: atapter's private data struct
+ * @skb: skb to send
+ *
+ * This routine prepare a buffer for transmission. It checks
+ * the message length for the appropiate size. It picks up a
+ * free tcb from the TCB pool and sets up the corresponding
+ * TBD's. If the number of fragments are more than the number
+ * of TBD/TCB it copies all the fragments in a coalesce buffer.
+ * It returns a pointer to the prepared TCB.
+ */
+static inline tcb_t *
+e100_prepare_xmit_buff(struct e100_private *bdp, struct sk_buff *skb)
+{
+	tcb_t *tcb, *prev_tcb;
+
+	tcb = bdp->tcb_pool.data;
+	tcb += TCB_TO_USE(bdp->tcb_pool);
+
+	tcb->tcb_hdr.cb_status = 0;
+	tcb->tcb_thrshld = bdp->tx_thld;
+	tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_S_BIT);
+
+	/* set the I bit on the modulo tcbs, so we will get an interrupt * to
+	 * clean things up */
+	if (!(++bdp->tx_count % TX_FRAME_CNT)) {
+		tcb->tcb_hdr.cb_cmd |= __constant_cpu_to_le16(CB_I_BIT);
+	}
+
+	tcb->tcb_skb = skb;
+
+#ifdef E100_ZEROCOPY
+	if (skb->ip_summed == CHECKSUM_HW) {
+		const struct iphdr *ip = skb->nh.iph;
+
+		if ((ip->protocol == IPPROTO_TCP) ||
+		    (ip->protocol == IPPROTO_UDP)) {
+			u16 *chksum;
+
+			tcb->tcbu.ipcb.ip_activation_high =
+				IPCB_HARDWAREPARSING_ENABLE;
+			tcb->tcbu.ipcb.ip_schedule |=
+				IPCB_TCPUDP_CHECKSUM_ENABLE;
+
+			if (ip->protocol == IPPROTO_TCP) {
+				struct tcphdr *tcp;
+
+				tcp = (struct tcphdr *) ((u32 *) ip + ip->ihl);
+				chksum = &(tcp->check);
+				tcb->tcbu.ipcb.ip_schedule |= IPCB_TCP_PACKET;
+			} else {
+				struct udphdr *udp;
+
+				udp = (struct udphdr *) ((u32 *) ip + ip->ihl);
+				chksum = &(udp->check);
+			}
+
+			*chksum = csum_tcpudp_magic(ip->daddr, ip->saddr,
+						    sizeof (struct tcphdr),
+						    ip->protocol, 0);
+		}
+	} else {
+		if (bdp->flags & USE_IPCB) {
+			tcb->tcbu.ipcb.ip_activation_high =
+				IPCB_IP_ACTIVATION_DEFAULT;
+			tcb->tcbu.ipcb.ip_schedule &= ~IPCB_TCP_PACKET;
+			tcb->tcbu.ipcb.ip_schedule &=
+				~IPCB_TCPUDP_CHECKSUM_ENABLE;
+		}
+	}
+
+	if (!skb_shinfo(skb)->nr_frags) {
+		(tcb->tbd_ptr)->tbd_buf_addr =
+			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+						   skb->len, PCI_DMA_TODEVICE));
+		(tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
+		tcb->tcb_tbd_num = 1;
+		tcb->tcb_tbd_ptr = tcb->tcb_tbd_dflt_ptr;
+	} else {
+		int i;
+		void *addr;
+		tbd_t *tbd_arr_ptr = &(tcb->tbd_ptr[1]);
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[0];
+
+		(tcb->tbd_ptr)->tbd_buf_addr =
+			cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+						   (skb->len - skb->data_len),
+						   PCI_DMA_TODEVICE));
+		(tcb->tbd_ptr)->tbd_buf_cnt =
+			cpu_to_le16(skb->len - skb->data_len);
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags;
+		     i++, tbd_arr_ptr++, frag++) {
+
+			addr = ((void *) page_address(frag->page) +
+				frag->page_offset);
+
+			tbd_arr_ptr->tbd_buf_addr =
+				cpu_to_le32(pci_map_single(bdp->pdev,
+							   addr, frag->size,
+							   PCI_DMA_TODEVICE));
+			tbd_arr_ptr->tbd_buf_cnt = cpu_to_le16(frag->size);
+		}
+		tcb->tcb_tbd_num = skb_shinfo(skb)->nr_frags + 1;
+		tcb->tcb_tbd_ptr = tcb->tcb_tbd_expand_ptr;
+	}
+#else
+	(tcb->tbd_ptr)->tbd_buf_addr =
+		cpu_to_le32(pci_map_single(bdp->pdev, skb->data,
+					   skb->len, PCI_DMA_TODEVICE));
+	(tcb->tbd_ptr)->tbd_buf_cnt = cpu_to_le16(skb->len);
+#endif
+
+	/* clear the S-BIT on the previous tcb */
+	prev_tcb = bdp->tcb_pool.data;
+	prev_tcb += PREV_TCB_USED(bdp->tcb_pool);
+	prev_tcb->tcb_hdr.cb_cmd &= __constant_cpu_to_le16((u16) ~CB_S_BIT);
+
+	bdp->tcb_pool.tail = NEXT_TCB_TOUSE(bdp->tcb_pool.tail);
+
+	wmb();
+
+	e100_start_cu(bdp, tcb);
+
+	return tcb;
+}
+
+/* Changed for 82558 enhancement */
+/**
+ * e100_start_cu - start the adapter's CU
+ * @bdp: atapter's private data struct
+ * @tcb: TCB to be transmitted
+ *
+ * This routine issues a CU Start or CU Resume command to the 82558/9.
+ * This routine was added because the prepare_ext_xmit_buff takes advantage
+ * of the 82558/9's Dynamic TBD chaining feature and has to start the CU as
+ * soon as the first TBD is ready. 
+ *
+ * e100_start_cu must be called while holding the tx_lock ! 
+ */
+void
+e100_start_cu(struct e100_private *bdp, tcb_t *tcb)
+{
+	unsigned long lock_flag;
+
+	spin_lock_irqsave(&(bdp->bd_lock), lock_flag);
+	switch (bdp->next_cu_cmd) {
+	case RESUME_NO_WAIT:
+		/*last cu command was a CU_RESMUE if this is a 558 or newer we dont need to
+		 * wait for command word to clear, we reach here only if we are bachlor
+		 */
+		e100_exec_cmd(bdp, SCB_CUC_RESUME);
+		break;
+
+	case RESUME_WAIT:
+		if ((bdp->flags & IS_ICH) &&
+		    (bdp->cur_line_speed == 10) &&
+		    (bdp->cur_dplx_mode == HALF_DUPLEX)) {
+			e100_wait_exec_simple(bdp, SCB_CUC_NOOP);
+			udelay(1);
+		}
+		if ((e100_wait_exec_simple(bdp, SCB_CUC_RESUME)) &&
+		    (bdp->flags & IS_BACHELOR) && (!(bdp->flags & IS_ICH))) {
+			bdp->next_cu_cmd = RESUME_NO_WAIT;
+		}
+		break;
+
+	case START_WAIT:
+		// The last command was a non_tx CU command
+		if (!e100_wait_cus_idle(bdp))
+			printk("%s cu_start: timeout waiting for cu\n",
+			       bdp->device->name);
+
+		if (!e100_wait_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+					 SCB_CUC_START)) {
+			printk("%s cu_start: timeout waiting for scb\n",
+			       bdp->device->name);
+			e100_exec_cmplx(bdp, (u32) (tcb->tcb_phys),
+					SCB_CUC_START);
+		}
+
+		bdp->next_cu_cmd = RESUME_WAIT;
+
+		break;
+	}
+
+	/* save the last tcb */
+	bdp->last_tcb = tcb;
+
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+}
+
+/* ====================================================================== */
+/* hw                                                                     */
+/* ====================================================================== */
+
+/**
+ * e100_selftest - perform H/W self test
+ * @bdp: atapter's private data struct
+ * @st_timeout: address to return timeout value, if fails
+ * @st_result: address to return selftest result, if fails
+ *
+ * This routine will issue PORT Self-test command to test the e100.
+ * The self-test will fail if the adapter's master-enable bit is not
+ * set in the PCI Command Register, or if the adapter is not seated
+ * in a PCI master-enabled slot. we also disable interrupts when the
+ * command is completed.
+ *
+ * Returns:
+ *      true: if adapter passes self_test
+ *      false: otherwise
+ */
+unsigned char
+e100_selftest(struct e100_private *bdp, u32 *st_timeout, u32 *st_result)
+{
+	u32 selftest_cmd;
+
+	/* initialize the nic state before running test */
+	e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
+	/* Setup the address of the self_test area */
+	selftest_cmd = bdp->selftest_phys;
+
+	/* Setup SELF TEST Command Code in D3 - D0 */
+	selftest_cmd |= PORT_SELFTEST;
+
+	/* Initialize the self-test signature and results DWORDS */
+	bdp->selftest->st_sign = 0;
+	bdp->selftest->st_result = 0xffffffff;
+
+	/* Do the port command */
+	writel(selftest_cmd, &bdp->scb->scb_port);
+
+	/* Wait at least 10 milliseconds for the self-test to complete */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 100 + 1);
+
+	/* disable interrupts since the're now enabled */
+	e100_dis_intr(bdp);
+
+	rmb();
+
+	/* if The First Self Test DWORD Still Zero, We've timed out. If the
+	 * second DWORD is not zero then we have an error. */
+	if ((bdp->selftest->st_sign == 0) || (bdp->selftest->st_result != 0)) {
+
+		if (st_timeout)
+			*st_timeout = !(le32_to_cpu(bdp->selftest->st_sign));
+
+		if (st_result)
+			*st_result = le32_to_cpu(bdp->selftest->st_result);
+
+		return false;
+	}
+
+	return true;
+}
+
+/**
+ * e100_setup_iaaddr - issue IA setup sommand
+ * @bdp: atapter's private data struct
+ * @eaddr: new ethernet address
+ *
+ * This routine will issue the IA setup command. This command
+ * will notify the 82557 (e100) of what its individual (node)
+ * address is. This command will be executed in polled mode.
+ *
+ * Returns:
+ *      true: if the IA setup command was successfully issued and completed
+ *      false: otherwise
+ */
+unsigned char
+e100_setup_iaaddr(struct e100_private *bdp, u8 *eaddr)
+{
+	unsigned int i;
+	cb_header_t *ntcb_hdr;
+	unsigned char res;
+	nxmit_cb_entry_t *cmd;
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		res = false;
+		goto exit;
+	}
+
+	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_IA_ADDRESS);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		(cmd->non_tx_cmd)->ntcb.setup.ia_addr[i] = eaddr[i];
+	}
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+	if (!res)
+		printk(KERN_WARNING "%s IA setup failed\n", bdp->device->name);
+
+exit:
+	return res;
+}
+
+/**
+ * e100_start_ru - start the RU if needed
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks the status of the 82557's receive unit(RU),
+ * and starts the RU if it was not already active.  However,
+ * before restarting the RU, the driver gives the RU the buffers
+ * it freed up during the servicing of the ISR. If there are
+ * no free buffers to give to the RU, (i.e. we have reached a
+ * no resource condition) the RU will not be started till the
+ * next ISR.
+ */
+void
+e100_start_ru(struct e100_private *bdp)
+{
+	struct rx_list_elem *rx_struct = NULL;
+	int buffer_found = 0;
+	struct list_head *entry_ptr;
+
+	list_for_each(entry_ptr, &(bdp->active_rx_list)) {
+		rx_struct =
+			list_entry(entry_ptr, struct rx_list_elem, list_elem);
+		pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr,
+				    bdp->rfd_size, PCI_DMA_FROMDEVICE);
+		if (!((SKB_RFD_STATUS(rx_struct->skb, bdp) &
+		       __constant_cpu_to_le16(RFD_STATUS_COMPLETE)))) {
+			buffer_found = 1;
+			break;
+		}
+	}
+
+	/* No available buffers */
+	if (!buffer_found) {
+		return;
+	}
+
+	spin_lock(&bdp->bd_lock);
+
+	if (!e100_wait_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START)) {
+		printk("%s start_ru: wait_scb failed\n", bdp->device->name);
+		e100_exec_cmplx(bdp, rx_struct->dma_addr, SCB_RUC_START);
+	}
+	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+		bdp->next_cu_cmd = RESUME_WAIT;
+	}
+	spin_unlock(&bdp->bd_lock);
+}
+
+/**
+ * e100_cmd_complete_location
+ * @bdp: atapter's private data struct
+ *
+ * This routine returns a pointer to the location of the command-complete
+ * DWord in the dump statistical counters area, according to the statistical
+ * counters mode (557 - basic, 558 - extended, or 559 - TCO mode).
+ * See e100_config_init() for the setting of the statistical counters mode.
+ */
+static u32 *
+e100_cmd_complete_location(struct e100_private *bdp)
+{
+	u32 *cmd_complete;
+	max_counters_t *stats = bdp->stats_counters;
+
+	switch (bdp->stat_mode) {
+	case E100_EXTENDED_STATS:
+		cmd_complete =
+			(u32 *) &(((err_cntr_558_t *) (stats))->cmd_complete);
+		break;
+
+	case E100_TCO_STATS:
+		cmd_complete =
+			(u32 *) &(((err_cntr_559_t *) (stats))->cmd_complete);
+		break;
+
+	case E100_BASIC_STATS:
+	default:		
+		cmd_complete =
+			(u32 *) &(((err_cntr_557_t *) (stats))->cmd_complete);
+		break;
+	}
+
+	return cmd_complete;
+}
+
+/**
+ * e100_clr_cntrs - clear statistics counters
+ * @bdp: atapter's private data struct
+ *
+ * This routine will clear the adapter error statistic counters.
+ *
+ * Returns:
+ *      true: if successfully cleared stat counters
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_clr_cntrs(struct e100_private *bdp)
+{
+	volatile u32 *pcmd_complete;
+
+	/* clear the dump counter complete word */
+	pcmd_complete = e100_cmd_complete_location(bdp);
+	*pcmd_complete = 0;
+	wmb();
+
+	if (!e100_wait_exec_cmplx(bdp, bdp->stat_cnt_phys, SCB_CUC_DUMP_ADDR))
+		return false;
+
+	/* wait 10 microseconds for the command to complete */
+	udelay(10);
+
+	if (!e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT))
+		return false;
+
+	if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+		bdp->next_cu_cmd = RESUME_WAIT;
+	}
+
+	return true;
+}
+
+static unsigned char
+e100_update_stats(struct e100_private *bdp)
+{
+	u32 *pcmd_complete;
+	basic_cntr_t *pstat = &(bdp->stats_counters->basic_stats);
+
+	// check if last dump command completed
+	pcmd_complete = e100_cmd_complete_location(bdp);
+	if (*pcmd_complete != le32_to_cpu(DUMP_RST_STAT_COMPLETED) &&
+	    *pcmd_complete != le32_to_cpu(DUMP_STAT_COMPLETED)) {
+		return false;
+	}
+
+	/* increment the statistics */
+	bdp->drv_stats.net_stats.rx_packets +=
+		le32_to_cpu(pstat->rcv_gd_frames);
+	bdp->drv_stats.net_stats.tx_packets +=
+		le32_to_cpu(pstat->xmt_gd_frames);
+	bdp->drv_stats.net_stats.rx_dropped += le32_to_cpu(pstat->rcv_rsrc_err);
+	bdp->drv_stats.net_stats.collisions += le32_to_cpu(pstat->xmt_ttl_coll);
+	bdp->drv_stats.net_stats.rx_length_errors +=
+		le32_to_cpu(pstat->rcv_shrt_frames);
+	bdp->drv_stats.net_stats.rx_over_errors +=
+		le32_to_cpu(pstat->rcv_rsrc_err);
+	bdp->drv_stats.net_stats.rx_crc_errors +=
+		le32_to_cpu(pstat->rcv_crc_errs);
+	bdp->drv_stats.net_stats.rx_frame_errors +=
+		le32_to_cpu(pstat->rcv_algn_errs);
+	bdp->drv_stats.net_stats.rx_fifo_errors +=
+		le32_to_cpu(pstat->rcv_oruns);
+	bdp->drv_stats.net_stats.tx_aborted_errors +=
+		le32_to_cpu(pstat->xmt_max_coll);
+	bdp->drv_stats.net_stats.tx_carrier_errors +=
+		le32_to_cpu(pstat->xmt_lost_crs);
+	bdp->drv_stats.net_stats.tx_fifo_errors +=
+		le32_to_cpu(pstat->xmt_uruns);
+
+	bdp->drv_stats.tx_late_col += le32_to_cpu(pstat->xmt_late_coll);
+	bdp->drv_stats.tx_ok_defrd += le32_to_cpu(pstat->xmt_deferred);
+	bdp->drv_stats.tx_one_retry += le32_to_cpu(pstat->xmt_sngl_coll);
+	bdp->drv_stats.tx_mt_one_retry += le32_to_cpu(pstat->xmt_mlt_coll);
+	bdp->drv_stats.rcv_cdt_frames += le32_to_cpu(pstat->rcv_err_coll);
+
+	if (bdp->stat_mode != E100_BASIC_STATS) {
+		ext_cntr_t *pex_stat = &bdp->stats_counters->extended_stats;
+
+		bdp->drv_stats.xmt_fc_pkts +=
+			le32_to_cpu(pex_stat->xmt_fc_frames);
+		bdp->drv_stats.rcv_fc_pkts +=
+			le32_to_cpu(pex_stat->rcv_fc_frames);
+		bdp->drv_stats.rcv_fc_unsupported +=
+			le32_to_cpu(pex_stat->rcv_fc_unsupported);
+	}
+
+	if (bdp->stat_mode == E100_TCO_STATS) {
+		tco_cntr_t *ptco_stat = &bdp->stats_counters->tco_stats;
+
+		bdp->drv_stats.xmt_tco_pkts +=
+			le16_to_cpu(ptco_stat->xmt_tco_frames);
+		bdp->drv_stats.rcv_tco_pkts +=
+			le16_to_cpu(ptco_stat->rcv_tco_frames);
+	}
+
+	*pcmd_complete = 0;
+	return true;
+}
+
+/**
+ * e100_dump_stat_cntrs
+ * @bdp: atapter's private data struct
+ *
+ * This routine will dump the board statistical counters without waiting
+ * for stat_dump to complete. Any access to this stats should verify the completion
+ * of the command
+ */
+void
+e100_dump_stats_cntrs(struct e100_private *bdp)
+{
+	unsigned long lock_flag_bd;
+
+	spin_lock_irqsave(&(bdp->bd_lock), lock_flag_bd);
+
+	/* dump h/w stats counters */
+	if (e100_wait_exec_simple(bdp, SCB_CUC_DUMP_RST_STAT)) {
+		if (bdp->next_cu_cmd == RESUME_NO_WAIT) {
+			bdp->next_cu_cmd = RESUME_WAIT;
+		}
+	}
+
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag_bd);
+}
+
+/**
+ * e100_exec_non_cu_cmd
+ * @bdp: atapter's private data struct
+ * @command: the non-cu command to execute
+ *
+ * This routine will submit a command block to be executed,
+ */
+unsigned char
+e100_exec_non_cu_cmd(struct e100_private *bdp, nxmit_cb_entry_t *command)
+{
+	cb_header_t *ntcb_hdr;
+	unsigned long lock_flag;
+	unsigned long expiration_time;
+	unsigned char rc = false;
+
+	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;	/* get hdr of non tcb cmd */
+
+	/* Set the Command Block to be the last command block */
+	ntcb_hdr->cb_cmd |= __constant_cpu_to_le16(CB_EL_BIT);
+	ntcb_hdr->cb_status = 0;
+	ntcb_hdr->cb_lnk_ptr = 0;
+
+	wmb();
+
+	if (in_interrupt())
+		return e100_delayed_exec_non_cu_cmd(bdp, command);
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	if (bdp->non_tx_command_state != E100_NON_TX_IDLE) {
+		goto delayed_exec;
+	}
+
+	if (bdp->last_tcb) {
+		rmb();
+		if ((bdp->last_tcb->tcb_hdr.cb_status &
+		     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+			goto delayed_exec;
+	}
+
+	if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) == SCB_CUS_ACTIVE) {
+		goto delayed_exec;
+	}
+
+	spin_lock_irqsave(&bdp->bd_lock, lock_flag);
+
+	if (!e100_wait_exec_cmplx(bdp, command->dma_addr, SCB_CUC_START)) {
+		spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+		goto exit;
+	}
+
+	bdp->next_cu_cmd = START_WAIT;
+	spin_unlock_irqrestore(&(bdp->bd_lock), lock_flag);
+
+	/* now wait for completion of non-cu CB up to 20 msec*/
+	expiration_time = jiffies + HZ / 50 + 1;
+	while (time_before(jiffies, expiration_time)) {
+		rmb();
+		if ((ntcb_hdr->cb_status &
+		     __constant_cpu_to_le16(CB_STATUS_COMPLETE))) {
+			rc = true;
+			goto exit;
+		}
+		spin_unlock_bh(&(bdp->bd_non_tx_lock));
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock_bh(&(bdp->bd_non_tx_lock));
+	}
+
+	/* didn't get a C bit assume command failed */
+exit:
+	e100_free_non_tx_cmd(bdp, command);
+
+	if (netif_running(bdp->device))
+		netif_wake_queue(bdp->device);
+
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return rc;
+
+delayed_exec:
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return e100_delayed_exec_non_cu_cmd(bdp, command);
+}
+
+/**
+ * e100_sw_reset
+ * @bdp: atapter's private data struct
+ * @reset_cmd: s/w reset or selective reset
+ *
+ * This routine will issue a software reset to the adapter. It 
+ * will also disable interrupts, as the are enabled after reset.
+ */
+void
+e100_sw_reset(struct e100_private *bdp, u32 reset_cmd)
+{
+	/* Do  a selective reset first to avoid a potential PCI hang */
+	writel(PORT_SELECTIVE_RESET, &bdp->scb->scb_port);
+
+	/* wait for the reset to take effect */
+	udelay(20);
+	if (reset_cmd == PORT_SOFTWARE_RESET) {
+		writel(PORT_SOFTWARE_RESET, &bdp->scb->scb_port);
+
+		/* wait 20 micro seconds for the reset to take effect */
+		udelay(20);
+	}
+
+	/* Mask off our interrupt line -- its unmasked after reset */
+	e100_dis_intr(bdp);
+}
+
+/**
+ * e100_load_microcode - Download microsocde to controller.
+ * @bdp: atapter's private data struct
+ *
+ * This routine downloads microcode on to the controller. This
+ * microcode is available for the 82558/9, 82550. Currently the
+ * microcode handles interrupt bundling and TCO workaround.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char
+e100_load_microcode(struct e100_private *bdp)
+{
+	static struct {
+		u8 rev_id;
+		u32 ucode[UCODE_MAX_DWORDS + 1];
+		int timer_dword;
+		int bundle_dword;
+		int min_size_dword;
+	} ucode_opts[] = {
+		{ D101A4_REV_ID,
+		  D101_A_RCVBUNDLE_UCODE,
+		  D101_CPUSAVER_TIMER_DWORD,
+		  D101_CPUSAVER_BUNDLE_DWORD,
+		  D101_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101B0_REV_ID,
+		  D101_B0_RCVBUNDLE_UCODE,
+		  D101_CPUSAVER_TIMER_DWORD,
+		  D101_CPUSAVER_BUNDLE_DWORD,
+		  D101_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101MA_REV_ID,
+		  D101M_B_RCVBUNDLE_UCODE,
+		  D101M_CPUSAVER_TIMER_DWORD,
+		  D101M_CPUSAVER_BUNDLE_DWORD,
+		  D101M_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101S_REV_ID,
+		  D101S_RCVBUNDLE_UCODE,
+		  D101S_CPUSAVER_TIMER_DWORD,
+		  D101S_CPUSAVER_BUNDLE_DWORD,
+		  D101S_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102_REV_ID,
+		  D102_B_RCVBUNDLE_UCODE,
+		  D102_B_CPUSAVER_TIMER_DWORD,
+		  D102_B_CPUSAVER_BUNDLE_DWORD,
+		  D102_B_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102C_REV_ID,
+		  D102_C_RCVBUNDLE_UCODE,
+		  D102_C_CPUSAVER_TIMER_DWORD,
+		  D102_C_CPUSAVER_BUNDLE_DWORD,
+		  D102_C_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102E_REV_ID,
+		  D102_E_RCVBUNDLE_UCODE,
+		  D102_E_CPUSAVER_TIMER_DWORD,
+		  D102_E_CPUSAVER_BUNDLE_DWORD,
+		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
+		{ 0, {0}, 0, 0, 0}
+	}, *opts;
+
+	opts = ucode_opts;
+
+	/* User turned ucode loading off */
+	if (!(bdp->params.b_params & PRM_UCODE))
+		return false;
+
+	/* These controllers do not need ucode */
+	if (bdp->flags & IS_ICH)
+		return false;
+
+	/* Search for ucode match against h/w rev_id */
+	while (opts->rev_id) {
+		if (bdp->rev_id == opts->rev_id) {
+			int i;
+			u32 *ucode_dword;
+			load_ucode_cb_t *ucode_cmd_ptr;
+			nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp);
+
+			if (cmd != NULL) {
+				ucode_cmd_ptr =
+					(load_ucode_cb_t *) cmd->non_tx_cmd;
+				ucode_dword = ucode_cmd_ptr->ucode_dword;
+			} else {
+				return false;
+			}
+
+			memcpy(ucode_dword, opts->ucode, sizeof (opts->ucode));
+
+			/* Insert user-tunable settings */
+			ucode_dword[opts->timer_dword] &= 0xFFFF0000;
+			ucode_dword[opts->timer_dword] |=
+				(u16) bdp->params.IntDelay;
+			ucode_dword[opts->bundle_dword] &= 0xFFFF0000;
+			ucode_dword[opts->bundle_dword] |=
+				(u16) bdp->params.BundleMax;
+			ucode_dword[opts->min_size_dword] &= 0xFFFF0000;
+			ucode_dword[opts->min_size_dword] |=
+				(bdp->params.b_params & PRM_BUNDLE_SMALL) ?
+				0xFFFF : 0xFF80;
+
+			for (i = 0; i < UCODE_MAX_DWORDS; i++)
+				cpu_to_le32s(&(ucode_dword[i]));
+
+			ucode_cmd_ptr->load_ucode_cbhdr.cb_cmd =
+				__constant_cpu_to_le16(CB_LOAD_MICROCODE);
+
+			return e100_exec_non_cu_cmd(bdp, cmd);
+		}
+		opts++;
+	}
+
+	return false;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/*       EEPROM  Functions                                                 */
+/***************************************************************************/
+
+/* Read PWA (printed wired assembly) number */
+void __devinit
+e100_rd_pwa_no(struct e100_private *bdp)
+{
+	bdp->pwa_no = e100_eeprom_read(bdp, EEPROM_PWA_NO);
+	bdp->pwa_no <<= 16;
+	bdp->pwa_no |= e100_eeprom_read(bdp, EEPROM_PWA_NO + 1);
+}
+
+/* Read the permanent ethernet address from the eprom. */
+void __devinit
+e100_rd_eaddr(struct e100_private *bdp)
+{
+	int i;
+	u16 eeprom_word;
+
+	for (i = 0; i < 6; i += 2) {
+		eeprom_word =
+			e100_eeprom_read(bdp,
+					 EEPROM_NODE_ADDRESS_BYTE_0 + (i / 2));
+
+		bdp->device->dev_addr[i] =
+			bdp->perm_node_address[i] = (u8) eeprom_word;
+		bdp->device->dev_addr[i + 1] =
+			bdp->perm_node_address[i + 1] = (u8) (eeprom_word >> 8);
+	}
+}
+
+/* Check the D102 RFD flags to see if the checksum passed */
+static unsigned char
+e100_D102_check_checksum(rfd_t *rfd)
+{
+	if (((le16_to_cpu(rfd->rfd_header.cb_status)) & RFD_PARSE_BIT)
+	    && (((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+		 RFD_TCP_PACKET)
+		|| ((rfd->rcvparserstatus & CHECKSUM_PROTOCOL_MASK) ==
+		    RFD_UDP_PACKET))
+	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_BIT_VALID)
+	    && (rfd->checksumstatus & TCPUDP_CHECKSUM_VALID)) {
+		return CHECKSUM_UNNECESSARY;
+	}
+	return CHECKSUM_NONE;
+}
+
+/**
+ * e100_D101M_checksum
+ * @bdp: atapter's private data struct
+ * @skb: skb received
+ *
+ * Sets the skb->csum value from D101 csum found at the end of the Rx frame. The
+ * D101M sums all words in frame excluding the ethernet II header (14 bytes) so
+ * in case the packet is ethernet II and the protocol is IP, all is need is to
+ * assign this value to skb->csum.
+ */
+static unsigned char
+e100_D101M_checksum(struct e100_private *bdp, struct sk_buff *skb)
+{
+	unsigned short proto = (skb->protocol);
+
+	if (proto == __constant_htons(ETH_P_IP)) {
+
+		skb->csum = get_unaligned((u16 *) (skb->tail));
+		return CHECKSUM_HW;
+	}
+	return CHECKSUM_NONE;
+}
+
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/*       Auxilary Functions                                                */
+/***************************************************************************/
+
+/* Print the board's configuration */
+void __devinit
+e100_print_brd_conf(struct e100_private *bdp)
+{
+	if (netif_carrier_ok(bdp->device)) {
+		printk(KERN_NOTICE
+		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+		       (unsigned long) bdp->device->mem_start,
+		       bdp->device->irq, bdp->cur_line_speed,
+		       (bdp->cur_dplx_mode == FULL_DUPLEX) ? "Full" : "Half");
+	} else {
+		printk(KERN_NOTICE
+		       "  Mem:0x%08lx  IRQ:%d  Speed:%d Mbps  Dx:%s\n",
+		       (unsigned long) bdp->device->mem_start,
+		       bdp->device->irq, 0, "N/A");
+
+		/* Auto negotiation failed so we should display an error */
+		printk(KERN_NOTICE "  Failed to detect cable link\n");
+		printk(KERN_NOTICE "  Speed and duplex will be determined "
+		       "at time of connection\n");
+	}
+
+	/* Print the string if checksum Offloading was enabled */
+	if (bdp->flags & DF_CSUM_OFFLOAD)
+		printk(KERN_NOTICE "  Hardware receive checksums enabled\n");
+	else
+		printk(KERN_NOTICE "  Hardware receive checksums disabled\n");
+
+	if ((bdp->flags & DF_UCODE_LOADED))
+		printk(KERN_NOTICE "  cpu cycle saver enabled\n");
+}
+
+/**
+ * e100_get_brand_msg
+ * @bdp: atapter's private data struct
+ *
+ * This routine checks if there is specified branding message for a given board
+ * type and returns a pointer to the string containing the branding message.
+ */
+char *
+e100_get_brand_msg(struct e100_private *bdp)
+{
+	int i;
+
+	for (i = 0; e100_vendor_info_array[i].idstr != NULL; i++) {
+		if (e100_vendor_info_array[i].device_type == bdp->device_type) {
+			return e100_vendor_info_array[i].idstr;
+		}
+	}
+
+	return e100_vendor_info_array[E100_ALL_BOARDS].idstr;
+}
+
+/**
+ * e100_pci_setup - setup the adapter's PCI information
+ * @pcid: adapter's pci_dev struct
+ * @bdp: atapter's private data struct
+ *
+ * This routine sets up all PCI information for the adapter. It enables the bus
+ * master bit (some BIOS don't do this), requests memory ans I/O regions, and
+ * calls ioremap() on the adapter's memory region.
+ *
+ * Returns:
+ *      true: if successfull
+ *      false: otherwise
+ */
+static unsigned char __devinit
+e100_pci_setup(struct pci_dev *pcid, struct e100_private *bdp)
+{
+	struct net_device *dev = bdp->device;
+	int rc = 0;
+
+	if ((rc = pci_enable_device(pcid)) != 0) {
+		goto err;
+	}
+
+	/* dev and ven ID have already been checked so it is our device */
+	pci_read_config_byte(pcid, PCI_REVISION_ID, (u8 *) &(bdp->rev_id));
+
+	/* address #0 is a memory region */
+	dev->mem_start = pci_resource_start(pcid, 0);
+	dev->mem_end = dev->mem_start + sizeof (scb_t);
+
+	/* address #1 is a IO region */
+	dev->base_addr = pci_resource_start(pcid, 1);
+
+	if ((rc = pci_request_regions(pcid, e100_short_driver_name)) != 0) {
+		goto err_disable;
+	}
+
+	pci_enable_wake(pcid, 0, 0);
+
+	/* if Bus Mastering is off, turn it on! */
+	pci_set_master(pcid);
+
+	/* address #0 is a memory mapping */
+	bdp->scb = (scb_t *) ioremap_nocache(dev->mem_start, sizeof (scb_t));
+
+	if (!bdp->scb) {
+		printk(KERN_ERR "%s - %s: Failed to map PCI address 0x%lX\n",
+		       e100_short_driver_name, dev->name,
+		       pci_resource_start(pcid, 0));
+		rc = -ENOMEM;
+		goto err_region;
+	}
+
+	return 0;
+
+err_region:
+	pci_release_regions(pcid);
+err_disable:
+	pci_disable_device(pcid);
+err:
+	return rc;
+}
+
+void
+e100_isolate_driver(struct e100_private *bdp)
+{
+	write_lock_irq(&(bdp->isolate_lock));
+	bdp->driver_isolated = true;
+	write_unlock_irq(&(bdp->isolate_lock));
+
+	del_timer_sync(&bdp->watchdog_timer);
+
+	netif_stop_queue(bdp->device);
+
+	bdp->last_tcb = NULL;
+
+	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
+}
+
+#ifdef E100_ETHTOOL_IOCTL
+static int
+e100_do_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_cmd ecmd;
+	int rc = -EOPNOTSUPP;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd.cmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+	case ETHTOOL_GSET:
+		rc = e100_ethtool_get_settings(dev, ifr);
+		break;
+	case ETHTOOL_SSET:
+		rc = e100_ethtool_set_settings(dev, ifr);
+		break;
+#ifdef ETHTOOL_GDRVINFO
+	case ETHTOOL_GDRVINFO:
+		rc = e100_ethtool_get_drvinfo(dev, ifr);
+		break;
+#endif
+#ifdef ETHTOOL_NWAY_RST
+	case ETHTOOL_NWAY_RST:
+		rc = e100_ethtool_nway_rst(dev, ifr);
+		break;
+#endif
+#ifdef ETHTOOL_GLINK
+	case ETHTOOL_GLINK:
+		rc = e100_ethtool_glink(dev, ifr);
+		break;
+#endif
+#ifdef ETHTOOL_GEEPROM
+	case ETHTOOL_GEEPROM:
+	case ETHTOOL_SEEPROM:
+		rc = e100_ethtool_eeprom(dev, ifr);
+		break;
+#endif
+#ifdef ETHTOOL_GWOL
+	case ETHTOOL_GWOL:
+	case ETHTOOL_SWOL:
+		rc = e100_ethtool_wol(dev, ifr);
+		break;
+#endif
+	default:
+		break;
+	}			//switch
+	return rc;
+}
+
+static int
+e100_ethtool_get_settings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_cmd ecmd;
+	u16 advert = 0;
+
+	memset((void *) &ecmd, 0, sizeof (ecmd));
+
+	bdp = dev->priv;
+
+	ecmd.supported = bdp->speed_duplex_caps;
+
+	ecmd.port =
+		(bdp->speed_duplex_caps & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+	ecmd.transceiver = XCVR_INTERNAL;
+	ecmd.phy_address = bdp->phy_addr;
+
+	ecmd.speed = bdp->cur_line_speed;
+	ecmd.duplex =
+		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+
+	ecmd.advertising = ADVERTISED_TP;
+
+	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+		ecmd.autoneg = AUTONEG_ENABLE;
+		ecmd.advertising |= ADVERTISED_Autoneg;
+	} else {
+		ecmd.autoneg = AUTONEG_DISABLE;
+	}
+
+	if (bdp->speed_duplex_caps & SUPPORTED_MII) {
+		spin_lock_bh(&(bdp->mdi_access_lock));
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &advert);
+		spin_unlock_bh(&(bdp->mdi_access_lock));
+
+		if (advert & ADVERTISE_10HALF)
+			ecmd.advertising |= ADVERTISED_10baseT_Half;
+		if (advert & ADVERTISE_10FULL)
+			ecmd.advertising |= ADVERTISED_10baseT_Full;
+		if (advert & ADVERTISE_100HALF)
+			ecmd.advertising |= ADVERTISED_100baseT_Half;
+		if (advert & ADVERTISE_100FULL)
+			ecmd.advertising |= ADVERTISED_100baseT_Full;
+	} else {
+		ecmd.autoneg = AUTONEG_DISABLE;
+		ecmd.advertising &= ~ADVERTISED_Autoneg;
+	}
+
+	if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int
+e100_ethtool_set_settings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	int current_duplex;
+	int e100_new_speed_duplex;
+	int ethtool_new_speed_duplex;
+	int speed_duplex_change_required;
+	struct ethtool_cmd ecmd;
+
+	if (!capable(CAP_NET_ADMIN)) {
+		return -EPERM;
+	}
+
+	bdp = dev->priv;
+	if (netif_running(dev)) {
+		return -EBUSY;
+	}
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) {
+		return -EFAULT;
+	}
+	current_duplex =
+		(bdp->cur_dplx_mode == HALF_DUPLEX) ? DUPLEX_HALF : DUPLEX_FULL;
+	speed_duplex_change_required = (ecmd.speed != bdp->cur_line_speed)
+		|| (ecmd.duplex != current_duplex);
+
+	if ((ecmd.autoneg == AUTONEG_ENABLE) && speed_duplex_change_required) {
+		return -EINVAL;
+	}
+
+	if ((ecmd.autoneg == AUTONEG_ENABLE)
+	    && (bdp->speed_duplex_caps & SUPPORTED_Autoneg)) {
+		bdp->params.e100_speed_duplex = E100_AUTONEG;
+		e100_set_speed_duplex(bdp);
+	} else {
+		if (speed_duplex_change_required) {
+			if (ecmd.speed == SPEED_10) {
+				if (ecmd.duplex == DUPLEX_HALF) {
+					e100_new_speed_duplex =
+						E100_SPEED_10_HALF;
+					ethtool_new_speed_duplex =
+						SUPPORTED_10baseT_Half;
+
+				} else {
+					e100_new_speed_duplex =
+						E100_SPEED_10_FULL;
+					ethtool_new_speed_duplex =
+						SUPPORTED_10baseT_Full;
+				}
+
+			} else {
+				if (ecmd.duplex == DUPLEX_HALF) {
+					e100_new_speed_duplex =
+						E100_SPEED_100_HALF;
+					ethtool_new_speed_duplex =
+						SUPPORTED_100baseT_Half;
+
+				} else {
+					e100_new_speed_duplex =
+						E100_SPEED_100_FULL;
+					ethtool_new_speed_duplex =
+						SUPPORTED_100baseT_Full;
+				}
+			}
+
+			if (bdp->speed_duplex_caps & ethtool_new_speed_duplex) {
+				bdp->params.e100_speed_duplex =
+					e100_new_speed_duplex;
+				e100_set_speed_duplex(bdp);
+			} else {
+				return -EOPNOTSUPP;
+			}
+		}
+	}
+
+	return 0;
+}
+
+#ifdef ETHTOOL_GLINK
+static int
+e100_ethtool_glink(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_value info;
+
+	memset((void *) &info, 0, sizeof (info));
+
+	bdp = dev->priv;
+	info.cmd = ETHTOOL_GLINK;
+
+	spin_lock_bh(&(bdp->mdi_access_lock));
+	info.data = e100_get_link_state(bdp);
+	spin_unlock_bh(&(bdp->mdi_access_lock));
+
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	return 0;
+}
+#endif
+
+#ifdef ETHTOOL_NWAY_RST
+static int
+e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if ((bdp->speed_duplex_caps & SUPPORTED_Autoneg) &&
+	    (bdp->params.e100_speed_duplex == E100_AUTONEG)) {
+		e100_set_speed_duplex(bdp);
+	} else {
+		return -EFAULT;
+	}
+	return 0;
+}
+#endif
+
+#ifdef ETHTOOL_GDRVINFO
+static int
+e100_ethtool_get_drvinfo(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_drvinfo info;
+
+	memset((void *) &info, 0, sizeof (info));
+
+	bdp = dev->priv;
+
+	strncpy(info.driver, e100_short_driver_name, sizeof (info.driver) - 1);
+	strncpy(info.version, e100_version, sizeof (info.version) - 1);
+	strncpy(info.fw_version, e100_get_brand_msg(bdp),
+		sizeof (info.fw_version) - 1);
+	strncpy(info.bus_info, bdp->pdev->slot_name,
+		sizeof (info.bus_info) - 1);
+#ifdef ETHTOOL_GEEPROM
+	info.eedump_len = (bdp->eeprom_size << 1);	
+#endif
+
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	return 0;
+}
+#endif //ETHTOOL_GDRVINFO
+
+#ifdef ETHTOOL_GEEPROM
+static int
+e100_ethtool_eeprom(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_eeprom ecmd;
+	u16 eeprom_data[256];
+	u16 *usr_eeprom_ptr;
+	u16 word_length, word_offset;
+	int i;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
+		return -EFAULT;
+
+	usr_eeprom_ptr =
+		(u16 *) (ifr->ifr_data + offsetof(struct ethtool_eeprom, data));
+
+	word_offset = (ecmd.offset >> 1);
+	if (word_offset >= bdp->eeprom_size)
+		return -EFAULT;
+
+	word_length =
+		min_t(u32, (ecmd.len >> 1), (bdp->eeprom_size - word_offset));
+
+	if (ecmd.cmd == ETHTOOL_GEEPROM) {
+		for (i = word_offset; i < (word_length + word_offset); i++)
+			eeprom_data[i] = e100_eeprom_read(bdp, i);
+
+		ecmd.len = (word_length << 1);
+		ecmd.magic = E100_EEPROM_MAGIC;
+
+		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+			return -EFAULT;
+
+		if (copy_to_user(usr_eeprom_ptr, &(eeprom_data[word_offset]),
+				 (ecmd.len << 1)))
+			return -EFAULT;
+	} else {
+		if (ecmd.magic != E100_EEPROM_MAGIC)
+			return -EFAULT;
+
+		if (copy_from_user(&(eeprom_data[word_offset]), usr_eeprom_ptr,
+				   (ecmd.len << 1)))
+			return -EFAULT;
+
+		e100_eeprom_write_block(bdp, word_offset,
+					&(eeprom_data[word_offset]),
+					word_length);
+
+		ecmd.len = (word_length << 1);
+
+		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
+			return -EFAULT;
+	}
+	return 0;
+}
+#endif
+
+static inline int __devinit
+e100_10BaseT_adapter(struct e100_private *bdp)
+{
+	return ((bdp->pdev->device == 0x1229) &&
+		(bdp->pdev->subsystem_vendor == 0x8086) &&
+		(bdp->pdev->subsystem_device == 0x0003));
+}
+
+static void __devinit
+e100_get_speed_duplex_caps(struct e100_private *bdp)
+{
+	u16 status;
+
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+	bdp->speed_duplex_caps = 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_ANEGCAPABLE) ? SUPPORTED_Autoneg : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_10HALF) ? SUPPORTED_10baseT_Half : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_10FULL) ? SUPPORTED_10baseT_Full : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_100HALF) ? SUPPORTED_100baseT_Half : 0;
+
+	bdp->speed_duplex_caps |=
+		(status & BMSR_100FULL) ? SUPPORTED_100baseT_Full : 0;
+
+	if (IS_NC3133(bdp))
+		bdp->speed_duplex_caps =
+			(SUPPORTED_FIBRE | SUPPORTED_100baseT_Full);
+	else
+		bdp->speed_duplex_caps |= SUPPORTED_TP;
+
+	if ((status == 0xFFFF) && e100_10BaseT_adapter(bdp)) {
+		bdp->speed_duplex_caps =
+			(SUPPORTED_10baseT_Half | SUPPORTED_TP);
+	} else {
+		bdp->speed_duplex_caps |= SUPPORTED_MII;
+	}
+
+}
+
+static void
+e100_set_speed_duplex(struct e100_private *bdp)
+{
+	e100_phy_set_speed_duplex(bdp, true);
+	e100_config_fc(bdp);	/* re-config flow-control if necessary */
+	e100_config(bdp);	
+}
+
+#ifdef ETHTOOL_GWOL
+static unsigned char
+e100_setup_filter(struct e100_private *bdp)
+{
+	cb_header_t *ntcb_hdr;
+	unsigned char res = false;
+	nxmit_cb_entry_t *cmd;
+
+	if ((cmd = e100_alloc_non_tx_cmd(bdp)) == NULL) {
+		goto exit;
+	}
+
+	ntcb_hdr = (cb_header_t *) cmd->non_tx_cmd;
+	ntcb_hdr->cb_cmd = __constant_cpu_to_le16(CB_LOAD_FILTER);
+
+	/* Set EL and FIX bit */
+	(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] =
+		__constant_cpu_to_le32(CB_FILTER_EL | CB_FILTER_FIX);
+
+	if (bdp->wolopts & WAKE_UCAST) {
+		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+			__constant_cpu_to_le32(CB_FILTER_IA_MATCH);
+	}
+
+	if (bdp->wolopts & WAKE_ARP) {
+		/* Setup ARP bit and lower IP parts */
+		/* bdp->ip_lbytes contains 2 lower bytes of IP address in network byte order */
+		(cmd->non_tx_cmd)->ntcb.filter.filter_data[0] |=
+			cpu_to_le32(CB_FILTER_ARP | bdp->ip_lbytes);
+	}
+
+	res = e100_exec_non_cu_cmd(bdp, cmd);
+	if (!res)
+		printk(KERN_WARNING "%s Filter setup failed\n",
+		       bdp->device->name);
+
+exit:
+	return res;
+
+}
+
+static void
+e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp)
+{
+	int enable = 0;
+	u32 state = 0;
+
+	if (bdp->wolopts) {
+		e100_config_wol(bdp);
+
+		if (!e100_config(bdp)) {
+			printk("e100_config WOL options failed\n");
+			goto exit;
+		}
+
+		if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
+			if (!e100_setup_filter(bdp)) {
+				printk("e100_config WOL options failed\n");
+				goto exit;
+			}
+			state = 1;
+			pci_set_power_state(pcid, state);
+		}
+		enable = 1;
+	}
+exit:
+	 pci_enable_wake(pcid, state, enable);
+}
+
+static u16 
+e100_get_ip_lbytes(struct net_device *dev)
+{
+	struct in_ifaddr *ifa;
+	struct in_device *in_dev;
+	u32 res = 0;
+
+	in_dev = (struct in_device *) dev->ip_ptr;
+	/* Check if any in_device bound to interface */
+	if (in_dev) {
+		/* Check if any IP address is bound to interface */
+		if ((ifa = in_dev->ifa_list) != NULL) {
+			res = __constant_ntohl(ifa->ifa_address);
+			res = __constant_htons(res & 0x0000ffff);
+		}
+	}
+	return res;
+}
+
+static int
+e100_ethtool_wol(struct net_device *dev, struct ifreq *ifr)
+{
+	struct e100_private *bdp;
+	struct ethtool_wolinfo wolinfo;
+	int res = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	bdp = dev->priv;
+
+	if (copy_from_user(&wolinfo, ifr->ifr_data, sizeof (wolinfo))) {
+		return -EFAULT;
+	}
+
+	switch (wolinfo.cmd) {
+	case ETHTOOL_GWOL:
+		wolinfo.supported = bdp->wolsupported;
+		wolinfo.wolopts = bdp->wolopts;
+		if (copy_to_user(ifr->ifr_data, &wolinfo, sizeof (wolinfo)))
+			res = -EFAULT;
+		break;
+
+	case ETHTOOL_SWOL:
+		/* If ALL requests are supported or request is DISABLE wol */
+		if (((wolinfo.wolopts & bdp->wolsupported) == wolinfo.wolopts)
+		    || (wolinfo.wolopts == 0)) {
+			bdp->wolopts = wolinfo.wolopts;
+		} else {
+			res = -EOPNOTSUPP;
+		}
+		break;
+	default:
+		break;
+	}
+	return res;
+}
+
+#endif
+#endif /*E100_ETHTOOL_IOCTL */
+
+#ifdef E100_MII_IOCTL
+static int
+e100_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct e100_private *bdp;
+	struct mii_ioctl_data *data_ptr =
+		(struct mii_ioctl_data *) &(ifr->ifr_data);
+
+	bdp = dev->priv;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data_ptr->phy_id = bdp->phy_addr & 0x1f;
+		break;
+
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_bh(&(bdp->mdi_access_lock));
+		e100_mdi_read(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+			      &(data_ptr->val_out));
+		spin_unlock_bh(&(bdp->mdi_access_lock));
+		break;
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (netif_running(dev)) {
+			return -EBUSY;
+		}
+		spin_lock_bh(&(bdp->mdi_access_lock));
+		e100_mdi_write(bdp, data_ptr->reg_num & 0x1f, bdp->phy_addr,
+			       data_ptr->val_in);
+		spin_unlock_bh(&(bdp->mdi_access_lock));
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+#endif //E100_MII_IOCTL
+
+nxmit_cb_entry_t *
+e100_alloc_non_tx_cmd(struct e100_private *bdp)
+{
+	nxmit_cb_entry_t *non_tx_cmd_elem;
+
+	if (!(non_tx_cmd_elem = (nxmit_cb_entry_t *)
+	      kmalloc(sizeof (nxmit_cb_entry_t), GFP_ATOMIC))) {
+		return NULL;
+	}
+	non_tx_cmd_elem->non_tx_cmd =
+		pci_alloc_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+				     &(non_tx_cmd_elem->dma_addr));
+	if (non_tx_cmd_elem->non_tx_cmd == NULL) {
+		kfree(non_tx_cmd_elem);
+		return NULL;
+	}
+	return non_tx_cmd_elem;
+}
+
+void
+e100_free_non_tx_cmd(struct e100_private *bdp,
+		     nxmit_cb_entry_t *non_tx_cmd_elem)
+{
+	pci_free_consistent(bdp->pdev, sizeof (nxmit_cb_t),
+			    non_tx_cmd_elem->non_tx_cmd,
+			    non_tx_cmd_elem->dma_addr);
+	kfree(non_tx_cmd_elem);
+}
+
+static void
+e100_free_nontx_list(struct e100_private *bdp)
+{
+	nxmit_cb_entry_t *command;
+	int i;
+
+	while (!list_empty(&bdp->non_tx_cmd_list)) {
+		command = list_entry(bdp->non_tx_cmd_list.next,
+				     nxmit_cb_entry_t, list_elem);
+		list_del(&(command->list_elem));
+		e100_free_non_tx_cmd(bdp, command);
+	}
+
+	for (i = 0; i < CB_MAX_NONTX_CMD; i++) {
+		bdp->same_cmd_entry[i] = NULL;
+	}
+}
+
+static unsigned char
+e100_delayed_exec_non_cu_cmd(struct e100_private *bdp,
+			     nxmit_cb_entry_t *command)
+{
+	nxmit_cb_entry_t *same_command;
+	cb_header_t *ntcb_hdr;
+	u16 cmd;
+
+	ntcb_hdr = (cb_header_t *) command->non_tx_cmd;
+
+	cmd = CB_CMD_MASK & le16_to_cpu(ntcb_hdr->cb_cmd);
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	same_command = bdp->same_cmd_entry[cmd];
+
+	if (same_command != NULL) {
+		memcpy((void *) (same_command->non_tx_cmd),
+		       (void *) (command->non_tx_cmd), sizeof (nxmit_cb_t));
+		e100_free_non_tx_cmd(bdp, command);
+	} else {
+		list_add_tail(&(command->list_elem), &(bdp->non_tx_cmd_list));
+		bdp->same_cmd_entry[cmd] = command;
+	}
+
+	if (bdp->non_tx_command_state == E100_NON_TX_IDLE) {
+		bdp->non_tx_command_state = E100_WAIT_TX_FINISH;
+		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+	}
+
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+	return true;
+}
+
+static void
+e100_non_tx_background(unsigned long ptr)
+{
+	struct e100_private *bdp = (struct e100_private *) ptr;
+	nxmit_cb_entry_t *active_command;
+	int restart = true;
+
+	spin_lock_bh(&(bdp->bd_non_tx_lock));
+
+	switch (bdp->non_tx_command_state) {
+	case E100_WAIT_TX_FINISH:
+		if (bdp->last_tcb != NULL) {
+			rmb();
+			if ((bdp->last_tcb->tcb_hdr.cb_status &
+			     __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+				goto exit;
+		}
+		if ((readw(&bdp->scb->scb_status) & SCB_CUS_MASK) ==
+		    SCB_CUS_ACTIVE) {
+			goto exit;
+		}
+		break;
+
+	case E100_WAIT_NON_TX_FINISH:
+		active_command = list_entry(bdp->non_tx_cmd_list.next,
+					    nxmit_cb_entry_t, list_elem);
+		rmb();
+
+		if (((((cb_header_t *) (active_command->non_tx_cmd))->cb_status
+		      & __constant_cpu_to_le16(CB_STATUS_COMPLETE)) == 0)
+		    && time_before(jiffies, active_command->expiration_time)) {
+			goto exit;
+		} else {
+			list_del(&(active_command->list_elem));
+			e100_free_non_tx_cmd(bdp, active_command);
+		}
+		break;
+
+	default:
+		break;
+	}			//switch
+
+	if (list_empty(&bdp->non_tx_cmd_list)) {
+		bdp->non_tx_command_state = E100_NON_TX_IDLE;
+		spin_lock_irq(&(bdp->bd_lock));
+		bdp->next_cu_cmd = START_WAIT;
+		spin_unlock_irq(&(bdp->bd_lock));
+		restart = false;
+		goto exit;
+	} else {
+		u16 cmd_type;
+
+		bdp->non_tx_command_state = E100_WAIT_NON_TX_FINISH;
+		active_command = list_entry(bdp->non_tx_cmd_list.next,
+					    nxmit_cb_entry_t, list_elem);
+		spin_lock_irq(&(bdp->bd_lock));
+		e100_wait_exec_cmplx(bdp, active_command->dma_addr,
+				     SCB_CUC_START);
+		spin_unlock_irq(&(bdp->bd_lock));
+		active_command->expiration_time = jiffies + HZ;
+		cmd_type = CB_CMD_MASK &
+			le16_to_cpu(((cb_header_t *)
+				     (active_command->non_tx_cmd))->cb_cmd);
+		bdp->same_cmd_entry[cmd_type] = NULL;
+	}
+
+exit:
+	if (restart) {
+		mod_timer(&(bdp->nontx_timer_id), jiffies + 1);
+	} else {
+		if (netif_running(bdp->device))
+			netif_wake_queue(bdp->device);
+	}
+	spin_unlock_bh(&(bdp->bd_non_tx_lock));
+}
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_phy.c linux-2.5.6/drivers/net/e100/e100_phy.c
--- linux-2.5.6-pre3/drivers/net/e100/e100_phy.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_phy.c	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,1133 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#include "e100_phy.h"
+
+void e100_handle_zlock(struct e100_private *bdp);
+
+/* 
+ * Procedure:	e100_mdi_write
+ *
+ * Description: This routine will write a value to the specified MII register
+ *		of an external MDI compliant device (e.g. PHY 100).  The
+ *		command will execute in polled mode.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *	reg_addr - The MII register that we are writing to
+ *	phy_addr - The MDI address of the Phy component.
+ *	data - The value that we are writing to the MII register.
+ *
+ * Returns:
+ *	NOTHING
+ */
+void
+e100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data)
+{
+	int e100_retry;
+	u32 temp_val;
+
+	temp_val = (((u32) data) | (reg_addr << 16) |
+		    (phy_addr << 21) | (MDI_WRITE << 26));
+	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+
+	/* wait 20usec before checking status */
+	udelay(20);
+
+	/* poll for the mdi write to complete */
+	e100_retry = E100_CMD_WAIT;
+	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
+	       (e100_retry)) {
+
+		udelay(20);
+		e100_retry--;
+	}
+}
+
+/* 
+ * Procedure:	e100_mdi_read
+ *
+ * Description: This routine will read a value from the specified MII register
+ *		of an external MDI compliant device (e.g. PHY 100), and return
+ *		it to the calling routine.  The command will execute in polled
+ *		mode.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *	reg_addr - The MII register that we are reading from
+ *	phy_addr - The MDI address of the Phy component.
+ *
+ * Results:
+ *	data - The value that we read from the MII register.
+ *
+ * Returns:
+ *	NOTHING
+ */
+void
+e100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data)
+{
+	int e100_retry;
+	u32 temp_val;
+
+	/* Issue the read command to the MDI control register. */
+	temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));
+	writel(temp_val, &bdp->scb->scb_mdi_cntrl);
+
+	/* wait 20usec before checking status */
+	udelay(20);
+
+	/* poll for the mdi read to complete */
+	e100_retry = E100_CMD_WAIT;
+	while ((!(readl(&bdp->scb->scb_mdi_cntrl) & MDI_PHY_READY)) &&
+	       (e100_retry)) {
+
+		udelay(20);
+		e100_retry--;
+	}
+
+	// return the lower word
+	*data = (u16) readl(&bdp->scb->scb_mdi_cntrl);
+}
+
+static unsigned char __devinit
+e100_phy_valid(struct e100_private *bdp, unsigned int phy_address)
+{
+	u16 ctrl_reg, stat_reg;
+
+	/* Read the MDI control register */
+	e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg);
+
+	/* Read the status register twice, bacause of sticky bits */
+	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);
+
+	if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0)))
+		return false;
+
+	return true;
+}
+
+static void __devinit
+e100_phy_address_detect(struct e100_private *bdp)
+{
+	unsigned int addr;
+	unsigned char valid_phy_found = false;
+
+	if (IS_NC3133(bdp)) {
+		bdp->phy_addr = 0;
+		return;
+	}
+
+	if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) {
+		bdp->phy_addr = PHY_DEFAULT_ADDRESS;
+		valid_phy_found = true;
+
+	} else {
+		for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) {
+			if (e100_phy_valid(bdp, addr)) {
+				bdp->phy_addr = addr;
+				valid_phy_found = true;
+				break;
+			}
+		}
+	}
+
+	if (!valid_phy_found) {
+		bdp->phy_addr = PHY_ADDRESS_503;
+	}
+}
+
+static void __devinit
+e100_phy_id_detect(struct e100_private *bdp)
+{
+	u16 low_id_reg, high_id_reg;
+
+	if (bdp->phy_addr == PHY_ADDRESS_503) {
+		bdp->PhyId = PHY_503;
+		return;
+	}
+	if (!(bdp->flags & IS_ICH)) {
+		if (bdp->rev_id >= D102_REV_ID) {
+			bdp->PhyId = PHY_82562ET;
+			return;
+		}
+	}
+
+	/* Read phy id from the MII register */
+	e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg);
+	e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg);
+
+	bdp->PhyId = ((unsigned int) low_id_reg |
+		      ((unsigned int) high_id_reg << 16));
+}
+
+static void __devinit
+e100_phy_isolate(struct e100_private *bdp)
+{
+	unsigned int phy_address;
+	u16 ctrl_reg;
+
+	/* Go over all phy addresses. Deisolate the selected one, and isolate
+	 * all the rest */
+	for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) {
+		if (phy_address != bdp->phy_addr) {
+			e100_mdi_write(bdp, MII_BMCR, phy_address,
+				       BMCR_ISOLATE);
+
+		} else {
+			e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg);
+			ctrl_reg &= ~BMCR_ISOLATE;
+			e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+		}
+
+		udelay(100);
+	}
+}
+
+static unsigned char __devinit
+e100_phy_specific_setup(struct e100_private *bdp)
+{
+	u16 misc_reg;
+
+	if (bdp->phy_addr == PHY_ADDRESS_503) {
+		switch (bdp->params.e100_speed_duplex) {
+		case E100_AUTONEG:
+			/* The adapter can't autoneg. so set to 10/HALF */
+			printk(KERN_INFO
+			       "503 serial component detected which "
+			       "cannot autonegotiate\n");
+			printk(KERN_INFO
+			       "speed/duplex forced to 10Mbps / Half duplex\n");
+			bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;
+			break;
+
+		case E100_SPEED_100_HALF:
+		case E100_SPEED_100_FULL:
+			printk(KERN_ERR
+			       "503 serial component detected which does not "
+			       "support 100Mbps\n");
+			printk(KERN_ERR
+			       "Change the forced speed/duplex to a supported "
+			       "setting\n");
+			return false;
+		}
+
+		return true;
+	}
+
+	if (IS_NC3133(bdp)) {
+		u16 int_reg;
+
+		/* enable 100BASE fiber interface */
+		e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr,
+			       MDI_NC3133_100FX_ENABLE);
+
+		if ((bdp->params.e100_speed_duplex != E100_AUTONEG) &&
+		    (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) {
+			/* just inform user about 100 full */
+			printk(KERN_ERR "NC3133 NIC can only run "
+			       "at 100Mbps full duplex\n");
+		}
+
+		bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;
+
+		/* enable interrupts */
+		e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG,
+			      bdp->phy_addr, &int_reg);
+		int_reg |= MDI_NC3133_INT_ENABLE;
+		e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG,
+			       bdp->phy_addr, int_reg);
+	}
+
+	/* Handle the National TX */
+	if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) {
+		e100_mdi_read(bdp, NSC_CONG_CONTROL_REG,
+			      bdp->phy_addr, &misc_reg);
+
+		misc_reg |= NSC_TX_CONG_TXREADY;
+
+		/* disable the congestion control bit in the National Phy */
+		misc_reg &= ~NSC_TX_CONG_ENABLE;
+
+		e100_mdi_write(bdp, NSC_CONG_CONTROL_REG,
+			       bdp->phy_addr, misc_reg);
+	}
+
+	return true;
+}
+
+/* 
+ * Procedure:	e100_phy_fix_squelch
+ *
+ * Description:
+ *	Help find link on certain rare scenarios.
+ *	NOTE: This routine must be called once per watchdog,
+ *	      and *after* setting the current link state.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_phy_fix_squelch(struct e100_private *bdp)
+{
+	if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED))
+		return;
+
+	if (netif_carrier_ok(bdp->device)) {
+		switch (bdp->PhyState) {
+		case 0:
+			break;
+		case 1:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, 0x0000);
+			break;
+		case 2:
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x3000);
+			break;
+		}
+		bdp->PhyState = 0;
+		bdp->PhyDelay = 0;
+
+	} else if (!bdp->PhyDelay--) {
+		switch (bdp->PhyState) {
+		case 0:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, EXTENDED_SQUELCH_BIT);
+			bdp->PhyState = 1;
+			break;
+		case 1:
+			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+				       bdp->phy_addr, 0x0000);
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x2010);
+			bdp->PhyState = 2;
+			break;
+		case 2:
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0x3000);
+			bdp->PhyState = 0;
+			break;
+		}
+
+		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+			       BMCR_ANENABLE | BMCR_ANRESTART);
+		bdp->PhyDelay = 3;
+	}
+}
+
+/* 
+ * Procedure:	e100_fix_polarity
+ *
+ * Description:
+ *	Fix for 82555 auto-polarity toggle problem. With a short cable 
+ *	connecting an 82555 with an 840A link partner, if the medium is noisy,
+ *	the 82555 sometime thinks that the polarity might be wrong and so 
+ *	toggles polarity. This happens repeatedly and results in a high bit 
+ *	error rate.
+ *	NOTE: This happens only at 10 Mbps
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void __devinit
+e100_fix_polarity(struct e100_private *bdp)
+{
+	u16 status;
+	u16 errors;
+	u16 misc_reg;
+	int speed;
+
+	if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) &&
+	    (bdp->PhyId != PHY_82562EM))
+		return;
+
+	/* If the user wants auto-polarity disabled, do only that and nothing *
+	 * else. * e100_autopolarity == 0 means disable --- we do just the
+	 * disabling * e100_autopolarity == 1 means enable  --- we do nothing at
+	 * all * e100_autopolarity >= 2 means we do the workaround code. */
+	/* Change for 82558 enhancement */
+	switch (E100_AUTOPOLARITY) {
+	case 0:
+		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+			      bdp->phy_addr, &misc_reg);
+		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+			       (u16) (misc_reg | DISABLE_AUTO_POLARITY));
+		break;
+
+	case 1:
+		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+			      bdp->phy_addr, &misc_reg);
+		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,
+			       (u16) (misc_reg & ~DISABLE_AUTO_POLARITY));
+		break;
+
+	case 2:
+		/* we do this only if link is up */
+		if (!netif_carrier_ok(bdp->device)) {
+			break;
+		}
+
+		e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status);
+		speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10;
+
+		/* we need to do this only if speed is 10 */
+		if (speed != 10) {
+			break;
+		}
+
+		/* see if we have any end of frame errors */
+		e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+			      bdp->phy_addr, &errors);
+
+		/* if non-zero, wait for 100 ms before reading again */
+		if (errors) {
+			udelay(200);
+			e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,
+				      bdp->phy_addr, &errors);
+
+			/* if non-zero again, we disable polarity */
+			if (errors) {
+				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+					      bdp->phy_addr, &misc_reg);
+				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+					       bdp->phy_addr,
+					       (u16) (misc_reg |
+						      DISABLE_AUTO_POLARITY));
+			}
+		}
+
+		if (!errors) {
+			/* it is safe to read the polarity now */
+			e100_mdi_read(bdp, PHY_82555_CSR,
+				      bdp->phy_addr, &status);
+
+			/* if polarity is normal, disable polarity */
+			if (!(status & PHY_82555_POLARITY_BIT)) {
+				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,
+					      bdp->phy_addr, &misc_reg);
+				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,
+					       bdp->phy_addr,
+					       (u16) (misc_reg |
+						      DISABLE_AUTO_POLARITY));
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+/* 
+ * Procedure:	e100_find_speed_duplex
+ *
+ * Description: This routine will figure out what line speed and duplex mode
+ *		the PHY is currently using.
+ *
+ * Arguments:
+ *	bdp - Ptr to this card's e100_bdconfig structure
+ *
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_find_speed_duplex(struct e100_private *bdp)
+{
+	unsigned int PhyId;
+	u16 stat_reg, misc_reg;
+	u16 ad_reg, lp_ad_reg;
+
+	PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK;
+
+	/* First we should check to see if we have link */
+	/* If we don't have a link no reason to print a speed and duplex */
+	if (!e100_update_link_state(bdp)) {
+		return;
+	}
+
+	if (bdp->flags & DF_SPEED_FORCED) {
+		return;
+	}
+
+	/* On the 82559 and later controllers, speed/duplex is part of the *
+	 * SCB. So, we save an mdi_read and get these from the SCB. * */
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		/* Read speed */
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1)
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Read duplex */
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2)
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		else
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+
+		return;
+	}
+
+	/* If this is a Phy 100, then read bits 1 and 0 of extended register 0,
+	 * to get the current speed and duplex settings. */
+	if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) ||
+	    (PhyId == PHY_82555_TX)) {
+
+		/* Read Phy 100 extended register 0 */
+		e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg);
+
+		/* Get current speed setting */
+		if (misc_reg & PHY_100_ER0_SPEED_INDIC)
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Get current duplex setting -- FDX enabled if bit is set */
+		if (misc_reg & PHY_100_ER0_FDX_INDIC)
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		else
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+
+		return;
+	}
+
+	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg);
+
+	/* See if Auto-Negotiation was complete (bit 5, reg 1) */
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+	/* If a True NWAY connection was made, then we can detect speed/dplx
+	 * by ANDing our adapter's advertised abilities with our link partner's
+	 * advertised ablilities, and then assuming that the highest common
+	 * denominator was chosed by NWAY. */
+	if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) {
+
+		/* Read our advertisement register */
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+		/* Read our link partner's advertisement register */
+		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+		/* AND the two advertisement registers together, and get rid
+		 * of any extraneous bits. */
+		ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY);
+
+		/* Get speed setting */
+		if (ad_reg &
+		    (ADVERTISE_100HALF | ADVERTISE_100FULL |
+		     ADVERTISE_100BASE4))
+
+			bdp->cur_line_speed = 100;
+		else
+			bdp->cur_line_speed = 10;
+
+		/* Get duplex setting -- use priority resolution algorithm */
+		if (ad_reg & ADVERTISE_100BASE4) {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		} else if (ad_reg & ADVERTISE_100FULL) {
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		} else if (ad_reg & ADVERTISE_100HALF) {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		} else if (ad_reg & ADVERTISE_10FULL) {
+			bdp->cur_dplx_mode = FULL_DUPLEX;
+		} else {
+			bdp->cur_dplx_mode = HALF_DUPLEX;
+		}
+
+		return;
+	}
+
+	/* If we are connected to a dumb (non-NWAY) repeater or hub, and the
+	 * line speed was determined automatically by parallel detection, then
+	 * we have no way of knowing exactly what speed the PHY is set to
+	 * unless that PHY has a propietary register which indicates speed in
+	 * this situation. The NSC TX PHY does have such a register. Also,
+	 * since NWAY didn't establish the connection, the duplex setting
+	 * should HALF duplex. */
+	bdp->cur_dplx_mode = HALF_DUPLEX;
+
+	if (PhyId == PHY_NSC_TX) {
+		/* Read register 25 to get the SPEED_10 bit */
+		e100_mdi_read(bdp, NSC_SPEED_IND_REG, bdp->phy_addr, &misc_reg);
+
+		/* If bit 6 was set then we're at 10Mbps */
+		if (misc_reg & NSC_TX_SPD_INDC_SPEED)
+			bdp->cur_line_speed = 10;
+		else
+			bdp->cur_line_speed = 100;
+
+	} else {
+		/* If we don't know the line speed, default to 10Mbps */
+		bdp->cur_line_speed = 10;
+	}
+}
+
+/* 
+ * Procedure: e100_force_speed_duplex
+ *
+ * Description: This routine forces line speed and duplex mode of the
+ * adapter based on the values the user has set in e100.c.
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: void
+ *
+ */
+static void
+e100_force_speed_duplex(struct e100_private *bdp)
+{
+	u16 control;
+	int neg_timeout = 2 * HZ;	//2 sec in jiffies
+
+	bdp->flags |= DF_SPEED_FORCED;
+
+	spin_lock_bh(&(bdp->mdi_access_lock));
+
+	e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &control);
+	control &= ~BMCR_ANENABLE;
+
+	/* Check e100.c values */
+	switch (bdp->params.e100_speed_duplex) {
+	case E100_SPEED_10_HALF:
+		control &= ~BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		bdp->cur_line_speed = 10;
+		bdp->cur_dplx_mode = HALF_DUPLEX;
+		break;
+
+	case E100_SPEED_10_FULL:
+		control &= ~BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		bdp->cur_line_speed = 10;
+		bdp->cur_dplx_mode = FULL_DUPLEX;
+		break;
+
+	case E100_SPEED_100_HALF:
+		control |= BMCR_SPEED100;
+		control &= ~BMCR_FULLDPLX;
+		bdp->cur_line_speed = 100;
+		bdp->cur_dplx_mode = HALF_DUPLEX;
+		break;
+
+	case E100_SPEED_100_FULL:
+		control |= BMCR_SPEED100;
+		control |= BMCR_FULLDPLX;
+		bdp->cur_line_speed = 100;
+		bdp->cur_dplx_mode = FULL_DUPLEX;
+		break;
+	}
+
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, control);
+
+	/* loop must run at least once */
+	do {
+		spin_unlock_bh(&(bdp->mdi_access_lock));
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(SLEEP_TIME);
+
+		spin_lock_bh(&(bdp->mdi_access_lock));
+
+		if (e100_update_link_state(bdp)) {
+			break;
+		}
+		neg_timeout -= SLEEP_TIME;
+
+	} while (neg_timeout > 0);
+
+	spin_unlock_bh(&(bdp->mdi_access_lock));
+}
+
+/* 
+ * Procedure: e100_set_fc
+ *
+ * Description: Checks the link's capability for flow control.
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ * Returns: void
+ *
+ */
+static void
+e100_set_fc(struct e100_private *bdp)
+{
+	u16 ad_reg;
+	u16 lp_ad_reg;
+	u16 exp_reg;
+
+	/* no flow control for 82557, forced links or half duplex */
+	if (!netif_carrier_ok(bdp->device) || (bdp->flags & DF_SPEED_FORCED) ||
+	    (bdp->cur_dplx_mode == HALF_DUPLEX) ||
+	    !(bdp->flags & IS_BACHELOR)) {
+
+		bdp->flags &= ~DF_LINK_FC_CAP;
+		return;
+	}
+
+	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */
+	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &exp_reg);
+
+	if (exp_reg & EXPANSION_NWAY) {
+		/* Read our advertisement register */
+		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);
+
+		/* Read our link partner's advertisement register */
+		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);
+
+		ad_reg &= lp_ad_reg;	/* AND the 2 ad registers */
+
+		if (ad_reg & NWAY_AD_FC_SUPPORTED)
+			bdp->flags |= DF_LINK_FC_CAP;
+		else
+			bdp->flags &= ~DF_LINK_FC_CAP;
+
+	} else {
+		bdp->flags &= ~DF_LINK_FC_CAP;
+	}
+}
+
+/* 
+ * Procedure: e100_phy_check
+ * 
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *
+ * Returns: true if link state was changed
+ *	    B_FLASE otherwise
+ *
+ */
+unsigned char
+e100_phy_check(struct e100_private *bdp)
+{
+	unsigned char old_link;
+	unsigned char changed = false;
+
+	old_link = netif_carrier_ok(bdp->device) ? 1 : 0;
+	e100_find_speed_duplex(bdp);
+
+	if (!old_link && netif_carrier_ok(bdp->device)) {
+		e100_set_fc(bdp);
+		changed = true;
+	}
+
+	if (old_link && !netif_carrier_ok(bdp->device)) {
+		/* reset the zero lock state */
+		bdp->zlock_state = ZLOCK_INITIAL;
+
+		// set auto lock for phy auto-negotiation on link up
+		if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_82555_TX)
+			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+				       bdp->phy_addr, 0);
+		changed = true;
+	}
+
+	e100_phy_fix_squelch(bdp);
+	e100_handle_zlock(bdp);
+
+	return changed;
+}
+
+/* 
+ * Procedure:	e100_auto_neg
+ *
+ * Description: This routine will start autonegotiation and wait
+ *		     for it to complete
+ *
+ * Arguments:
+ *	bdp		- pointer to this card's e100_bdconfig structure
+ *	force_restart	- defines if autoneg should be restarted even if it
+ *			has been completed before
+ * Returns:
+ *	NOTHING
+ */
+static void
+e100_auto_neg(struct e100_private *bdp, unsigned char force_restart)
+{
+	u16 stat_reg;
+	unsigned int i;
+
+	bdp->flags &= ~DF_SPEED_FORCED;
+
+	spin_lock_bh(&(bdp->mdi_access_lock));
+
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+	/* if we are capable of performing autoneg then we restart if needed */
+	if ((stat_reg != 0xFFFF) && (stat_reg & BMSR_ANEGCAPABLE)) {
+
+		if ((!force_restart) &&
+		    (stat_reg & BMSR_ANEGCOMPLETE)) {
+			goto exit;
+		}
+
+		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,
+			       BMCR_ANENABLE | BMCR_ANRESTART);
+
+		/* wait for autoneg to complete (up to 3 seconds) */
+		for (i = 0; i < 60; i++) {
+			/* now re-read the value. Sticky so read twice */
+			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+			e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);
+
+			if (stat_reg & BMSR_ANEGCOMPLETE)
+				goto exit;
+
+			spin_unlock_bh(&(bdp->mdi_access_lock));
+
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(SLEEP_TIME);
+
+			spin_lock_bh(&(bdp->mdi_access_lock));
+
+		}
+	}
+
+exit:
+	e100_find_speed_duplex(bdp);
+	spin_unlock_bh(&(bdp->mdi_access_lock));
+}
+
+void
+e100_phy_set_speed_duplex(struct e100_private *bdp, unsigned char force_restart)
+{
+	if (bdp->params.e100_speed_duplex == E100_AUTONEG) {
+		e100_auto_neg(bdp, force_restart);
+
+	} else {
+		e100_force_speed_duplex(bdp);
+	}
+
+	e100_set_fc(bdp);
+}
+
+void __devexit
+e100_phy_reset(struct e100_private *bdp)
+{
+	u16 ctrl_reg;
+
+	ctrl_reg = BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET;
+
+	e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);
+
+	udelay(100);
+}
+
+unsigned char __devinit
+e100_phy_init(struct e100_private *bdp)
+{
+	e100_phy_address_detect(bdp);
+	e100_phy_isolate(bdp);
+	e100_phy_id_detect(bdp);
+
+	if (!e100_phy_specific_setup(bdp))
+		return false;
+
+	bdp->PhyState = 0;
+	bdp->PhyDelay = 0;
+	bdp->zlock_state = ZLOCK_INITIAL;
+
+	e100_phy_set_speed_duplex(bdp, false);
+	e100_fix_polarity(bdp);
+
+	return true;
+}
+
+/* 
+ * Procedure: e100_get_link_state
+ * 
+ * Description: This routine checks the link status of the adapter
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ *
+ * Returns: true - If a link is found
+ *		false - If there is no link
+ *
+ */
+unsigned char
+e100_get_link_state(struct e100_private *bdp)
+{
+	unsigned char link = false;
+	u16 status;
+
+	/* Check link status */
+	/* If the controller is a 82559 or later one, link status is available
+	 * from the CSR. This avoids the mdi_read. */
+	if (bdp->rev_id >= D101MA_REV_ID) {
+		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_0) {
+			link = true;
+		} else {
+			link = false;
+		}
+
+	} else {
+		/* Read the status register twice because of sticky bits */
+		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+		e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &status);
+
+		if (status & BMSR_LSTATUS) {
+			link = true;
+		} else {
+			link = false;
+		}
+	}
+
+	return link;
+}
+
+/* 
+ * Procedure: e100_update_link_state
+ * 
+ * Description: This routine updates the link status of the adapter
+ *
+ * Arguments:  bdp - Pointer to the e100_private structure for the board
+ *		    
+ *
+ * Returns: true - If a link is found
+ *		false - If there is no link
+ *
+ */
+unsigned char
+e100_update_link_state(struct e100_private *bdp)
+{
+	unsigned char link;
+
+	link = e100_get_link_state(bdp);
+
+	if (link) {
+		if (!netif_carrier_ok(bdp->device))
+			netif_carrier_on(bdp->device);
+	} else {
+		if (netif_carrier_ok(bdp->device))
+			netif_carrier_off(bdp->device);
+	}
+
+	return link;
+}
+
+/**************************************************************************\
+ **
+ ** PROC NAME:     e100_handle_zlock
+ **    This function manages a state machine that controls
+ **    the driver's zero locking algorithm.
+ **    This function is called by e100_watchdog() every ~2 second.
+ ** States:
+ **    The current link handling state is stored in 
+ **    bdp->zlock_state, and is one of:
+ **    ZLOCK_INITIAL, ZLOCK_READING, ZLOCK_SLEEPING
+ **    Detailed description of the states and the transitions
+ **    between states is found below.
+ **    Note that any time the link is down / there is a reset
+ **    state will be changed outside this function to ZLOCK_INITIAL
+ ** Algorithm:
+ **    1. If link is up & 100 Mbps continue else stay in #1:
+ **    2. Set 'auto lock'
+ **    3. Read & Store 100 times 'Zero' locked in 1 sec interval
+ **    4. If max zero read >= 0xB continue else goto 1
+ **    5. Set most popular 'Zero' read in #3
+ **    6. Sleep 5 minutes
+ **    7. Read number of errors, if it is > 300 goto 2 else goto 6
+ ** Data Structures (in DRIVER_DATA):
+ **    zlock_state           - current state of the algorithm
+ **    zlock_read_cnt        - counts number of reads (up to 100)
+ **    zlock_read_data[i]    - counts number of times 'Zero' read was i, 0 <= i <= 15
+ **    zlock_sleep_cnt       - keeps track of "sleep" time (up to 300 secs = 5 minutes)
+ **                                
+ ** Parameters:    DRIVER_DATA    *bdp
+ **
+ **                bdp  - Pointer to HSM's adapter data space
+ **
+ ** Return Value:  NONE
+ **
+ ** See Also:      e100_watchdog()
+ **
+ \**************************************************************************/
+void
+e100_handle_zlock(struct e100_private *bdp)
+{
+	u16 pos;
+	u16 eq_reg;
+	u16 err_cnt;
+	u8 mpz;			/* Most Popular Zero */
+
+	switch (bdp->zlock_state) {
+	case ZLOCK_INITIAL:
+
+		if (((u8) bdp->rev_id <= D102_REV_ID) ||
+		    !(bdp->cur_line_speed == 100) ||
+		    !netif_carrier_ok(bdp->device)) {
+			break;
+		}
+
+		/* initialize hw and sw and start reading */
+		e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+			       bdp->phy_addr, 0);
+		/* reset read counters: */
+		bdp->zlock_read_cnt = 0;
+		for (pos = 0; pos < 16; pos++)
+			bdp->zlock_read_data[pos] = 0;
+		/* start reading in the next call back: */
+		bdp->zlock_state = ZLOCK_READING;
+
+		/* FALL THROUGH !! */
+
+	case ZLOCK_READING:
+		/* state: reading (100 times) zero locked in 1 sec interval
+		 * prev states: ZLOCK_INITIAL
+		 * next states: ZLOCK_INITIAL, ZLOCK_SLEEPING */
+
+		e100_mdi_read(bdp, PHY_82555_MDI_EQUALIZER_CSR,
+			      bdp->phy_addr, &eq_reg);
+		pos = (eq_reg & ZLOCK_ZERO_MASK) >> 4;
+		bdp->zlock_read_data[pos]++;
+		bdp->zlock_read_cnt++;
+
+		if (bdp->zlock_read_cnt == ZLOCK_MAX_READS) {
+			/* check if we read a 'Zero' value of 0xB or greater */
+			if ((bdp->zlock_read_data[0xB]) ||
+			    (bdp->zlock_read_data[0xC]) ||
+			    (bdp->zlock_read_data[0xD]) ||
+			    (bdp->zlock_read_data[0xE]) ||
+			    (bdp->zlock_read_data[0xF])) {
+
+				/* we've read 'Zero' value of 0xB or greater,
+				 * find most popular 'Zero' value and lock it */
+				mpz = 0;
+				/* this loop finds the most popular 'Zero': */
+				for (pos = 1; pos < 16; pos++) {
+					if (bdp->zlock_read_data[pos] >
+					    bdp->zlock_read_data[mpz])
+
+						mpz = pos;
+				}
+				/* now lock the most popular 'Zero': */
+				eq_reg = (ZLOCK_SET_ZERO | mpz);
+				e100_mdi_write(bdp,
+					       PHY_82555_MDI_EQUALIZER_CSR,
+					       bdp->phy_addr, eq_reg);
+
+				/* sleep for 5 minutes: */
+				bdp->zlock_sleep_cnt = jiffies;
+				bdp->zlock_state = ZLOCK_SLEEPING;
+				/* we will be reading the # of errors after 5
+				 * minutes, so we need to reset the error
+				 * counters - these registers are self clearing
+				 * on read, so read them */
+				e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+					      bdp->phy_addr, &err_cnt);
+
+			} else {
+				/* we did not read a 'Zero' value of 0xB or
+				 * above. go back to the start */
+				bdp->zlock_state = ZLOCK_INITIAL;
+			}
+
+		}
+		break;
+
+	case ZLOCK_SLEEPING:
+		/* state: sleeping for 5 minutes
+		 * prev states: ZLOCK_READING
+		 * next states: ZLOCK_READING, ZLOCK_SLEEPING */
+
+		/* if 5 minutes have passed: */
+		if ((jiffies - bdp->zlock_sleep_cnt) >= ZLOCK_MAX_SLEEP) {
+			/* read and sum up the number of errors:  */
+			e100_mdi_read(bdp, PHY_82555_SYMBOL_ERR,
+				      bdp->phy_addr, &err_cnt);
+			/* if we've more than 300 errors (this number was
+			 * calculated according to the spec max allowed errors
+			 * (80 errors per 1 million frames) for 5 minutes in
+			 * 100 Mbps (or the user specified max BER number) */
+			if (err_cnt > bdp->params.ber) {
+				/* start again in the next callback: */
+				bdp->zlock_state = ZLOCK_INITIAL;
+			} else {
+				/* we don't have more errors than allowed,
+				 * sleep for 5 minutes */
+				bdp->zlock_sleep_cnt = jiffies;
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+}
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_phy.h linux-2.5.6/drivers/net/e100/e100_phy.h
--- linux-2.5.6-pre3/drivers/net/e100/e100_phy.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_phy.h	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,183 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _E100_PHY_INC_
+#define _E100_PHY_INC_
+
+#include "e100.h"
+
+#include <linux/mii.h>
+
+/*
+ * Auto-polarity enable/disable
+ * e100_autopolarity = 0 => disable auto-polarity
+ * e100_autopolarity = 1 => enable auto-polarity
+ * e100_autopolarity = 2 => let software determine
+ */
+#define E100_AUTOPOLARITY 2
+
+#define IS_NC3133(bdp) (((bdp)->pdev->subsystem_vendor == 0x0E11) && \
+                        ((bdp)->pdev->subsystem_device == 0xB0E1))
+
+#define PHY_503                 0
+#define PHY_100_A               0x000003E0
+#define PHY_100_C               0x035002A8
+#define PHY_NSC_TX              0x5c002000
+#define PHY_82562ET             0x033002A8
+#define PHY_82562EM             0x032002A8
+#define PHY_82562EH             0x017002A8
+#define PHY_82555_TX            0x015002a8	/* added this for 82555 */
+#define PHY_OTHER               0xFFFF
+#define MAX_PHY_ADDR            31
+#define MIN_PHY_ADDR            0
+
+#define PHY_MODEL_REV_ID_MASK   0xFFF0FFFF
+
+#define PHY_DEFAULT_ADDRESS 1
+#define PHY_ADDRESS_503 32
+
+/* MDI Control register bit definitions */
+#define MDI_PHY_READY	    BIT_28	/* PHY is ready for next MDI cycle */
+
+#define MDI_NC3133_CONFIG_REG           0x19
+#define MDI_NC3133_100FX_ENABLE         BIT_2
+#define MDI_NC3133_INT_ENABLE_REG       0x17
+#define MDI_NC3133_INT_ENABLE           BIT_1
+
+/* MDI Control register opcode definitions */
+#define MDI_WRITE 1		/* Phy Write */
+#define MDI_READ  2		/* Phy read */
+
+/* MDI register set*/
+#define AUTO_NEG_NEXT_PAGE_REG	    0x07	/* Auto-negotiation next page xmit */
+#define EXTENDED_REG_0		    0x10	/* Extended reg 0 (Phy 100 modes) */
+#define EXTENDED_REG_1		    0x14	/* Extended reg 1 (Phy 100 error indications) */
+#define NSC_CONG_CONTROL_REG	    0x17	/* National (TX) congestion control */
+#define NSC_SPEED_IND_REG	    0x19	/* National (TX) speed indication */
+
+/* ############Start of 82555 specific defines################## */
+
+/* Intel 82555 specific registers */
+#define PHY_82555_CSR		    0x10	/* 82555 CSR */
+#define PHY_82555_SPECIAL_CONTROL   0x11	/* 82555 special control register */
+
+#define PHY_82555_RCV_ERR	    0x15	/* 82555 100BaseTx Receive Error
+						 * Frame Counter */
+#define PHY_82555_SYMBOL_ERR	    0x16	/* 82555 RCV Symbol Error Counter */
+#define PHY_82555_PREM_EOF_ERR	    0x17	/* 82555 100BaseTx RCV Premature End
+						 * of Frame Error Counter */
+#define PHY_82555_EOF_COUNTER	    0x18	/* 82555 end of frame error counter */
+#define PHY_82555_MDI_EQUALIZER_CSR 0x1a	/* 82555 specific equalizer reg. */
+
+/* 82555 CSR bits */
+#define PHY_82555_SPEED_BIT    BIT_1
+#define PHY_82555_POLARITY_BIT BIT_8
+
+/* 82555 equalizer reg. opcodes */
+#define ENABLE_ZERO_FORCING  0x2010	/* write to ASD conf. reg. 0 */
+#define DISABLE_ZERO_FORCING 0x2000	/* write to ASD conf. reg. 0 */
+
+/* 82555 special control reg. opcodes */
+#define DISABLE_AUTO_POLARITY 0x0010
+#define EXTENDED_SQUELCH_BIT  BIT_2
+
+/* ############End of 82555 specific defines##################### */
+
+/* Auto-Negotiation advertisement register bit definitions*/
+#define NWAY_AD_FC_SUPPORTED    0x0400	/* Flow Control supported */
+
+/* Auto-Negotiation link partner ability register bit definitions*/
+#define NWAY_LP_ABILITY	        0x07e0	/* technologies supported */
+
+/* PHY 100 Extended Register 0 bit definitions*/
+#define PHY_100_ER0_FDX_INDIC	BIT_0	/* 1 = FDX, 0 = half duplex */
+#define PHY_100_ER0_SPEED_INDIC BIT_1	/* 1 = 100Mbps, 0= 10Mbps */
+
+/* National Semiconductor TX phy congestion control register bit definitions*/
+#define NSC_TX_CONG_TXREADY  BIT_10	/* Makes TxReady an input */
+#define NSC_TX_CONG_ENABLE   BIT_8	/* Enables congestion control */
+
+/* National Semiconductor TX phy speed indication register bit definitions*/
+#define NSC_TX_SPD_INDC_SPEED BIT_6	/* 0 = 100Mbps, 1=10Mbps */
+
+/************* function prototypes ************/
+extern unsigned char e100_phy_init(struct e100_private *bdp);
+extern unsigned char e100_update_link_state(struct e100_private *bdp);
+extern unsigned char e100_phy_check(struct e100_private *bdp);
+extern void e100_phy_set_speed_duplex(struct e100_private *bdp,
+				      unsigned char force_restart);
+extern void e100_phy_reset(struct e100_private *bdp);
+extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+extern void e100_mdi_read(struct e100_private *, u32, u32, u16 *);
+
+#endif
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_proc.c linux-2.5.6/drivers/net/e100/e100_proc.c
--- linux-2.5.6-pre3/drivers/net/e100/e100_proc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_proc.c	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,925 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+/**********************************************************************
+*                                                                       *
+* INTEL CORPORATION                                                     *
+*                                                                       *
+* This software is supplied under the terms of the license included     *
+* above.  All use of this driver must be in accordance with the terms   *
+* of that license.                                                      *
+*                                                                       *
+* Module Name:  e100_proc.c                                             *
+*                                                                       *
+* Abstract:     Functions to handle the proc file system.               *
+*               Create the proc directories and files and run read and  *
+*               write requests from the user                            *
+*                                                                       *
+* Environment:  This file is intended to be specific to the Linux       *
+*               operating system.                                       *
+*                                                                       *
+**********************************************************************/
+
+#include <linux/config.h>
+
+#ifndef CONFIG_PROC_FS
+#undef E100_CONFIG_PROC_FS
+#endif
+
+#ifdef E100_CONFIG_PROC_FS
+#include "e100.h"
+
+/***************************************************************************/
+/*       /proc File System Interaface Support Functions                    */
+/***************************************************************************/
+
+static struct proc_dir_entry *adapters_proc_dir = 0;
+
+/* externs from e100_main.c */
+extern const char *e100_short_driver_name;
+extern const char *e100_version;
+extern struct net_device_stats *e100_get_stats(struct net_device *dev);
+extern char *e100_get_brand_msg(struct e100_private *bdp);
+extern void e100_mdi_write(struct e100_private *, u32, u32, u16);
+
+static void e100_proc_cleanup(void);
+static unsigned char e100_init_proc_dir(void);
+
+#define E100_EOU
+
+#define ADAPTERS_PROC_DIR "PRO_LAN_Adapters"
+#define WRITE_BUF_MAX_LEN 20	
+#define READ_BUF_MAX_LEN  256
+#define E100_PE_LEN       25
+
+#define bdp_drv_off(off) (unsigned long)(offsetof(struct e100_private, drv_stats.off))
+#define bdp_prm_off(off) (unsigned long)(offsetof(struct e100_private, params.off))
+
+typedef struct _e100_proc_entry {
+	char *name;
+	read_proc_t *read_proc;
+	write_proc_t *write_proc;
+	unsigned long offset;	/* offset into bdp. ~0 means no value, pass NULL. */
+} e100_proc_entry;
+
+static int
+generic_read(char *page, char **start, off_t off, int count, int *eof, int len)
+{
+	if (len <= off + count)
+		*eof = 1;
+
+	*start = page + off;
+	len -= off;
+	if (len > count)
+		len = count;
+
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+
+static int
+read_ulong(char *page, char **start, off_t off,
+	   int count, int *eof, unsigned long l)
+{
+	int len;
+
+	len = sprintf(page, "%lu\n", l);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_gen_ulong(char *page, char **start, off_t off,
+	       int count, int *eof, void *data)
+{
+	unsigned long val = 0;
+
+	if (data)
+		val = *((unsigned long *) data);
+
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_hwaddr(char *page, char **start, off_t off,
+	    int count, int *eof, unsigned char *hwaddr)
+{
+	int len;
+
+	len = sprintf(page, "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		      hwaddr[0], hwaddr[1], hwaddr[2],
+		      hwaddr[3], hwaddr[4], hwaddr[5]);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_descr(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	int len;
+
+	len = sprintf(page, "%s\n", e100_get_brand_msg(bdp));
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_permanent_hwaddr(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned char *hwaddr = bdp->perm_node_address;
+
+	return read_hwaddr(page, start, off, count, eof, hwaddr);
+}
+
+static int
+read_part_number(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	int len;
+
+	len = sprintf(page, "%06lx-%03x\n",
+		      (unsigned long) (bdp->pwa_no >> 8),
+		      (unsigned int) (bdp->pwa_no & 0xFF));
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static void
+set_led(struct e100_private *bdp, u16 led_mdi_op)
+{
+	spin_lock_bh(&bdp->mdi_access_lock);
+
+	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+		       bdp->phy_addr, led_mdi_op);
+
+	spin_unlock_bh(&bdp->mdi_access_lock);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(SLEEP_TIME);
+
+	spin_lock_bh(&bdp->mdi_access_lock);
+
+	/* turn led ownership to the chip */
+	e100_mdi_write(bdp, PHY_82555_LED_SWITCH_CONTROL,
+		       bdp->phy_addr, PHY_82555_LED_NORMAL_CONTROL);
+
+	spin_unlock_bh(&bdp->mdi_access_lock);
+}
+
+static int
+write_blink_led_timer(struct file *file, const char *buffer,
+		      unsigned long count, void *data)
+{
+	struct e100_private *bdp = data;
+	char s_blink_op[WRITE_BUF_MAX_LEN + 1];
+	char *res;
+	unsigned long i_blink_op;
+
+	if (!buffer)
+		return -EINVAL;
+
+	if (count > WRITE_BUF_MAX_LEN) {
+		count = WRITE_BUF_MAX_LEN;
+	}
+	copy_from_user(s_blink_op, buffer, count);
+	s_blink_op[count] = '\0';
+	i_blink_op = simple_strtoul(s_blink_op, &res, 0);
+	if (res == s_blink_op) {
+		return -EINVAL;
+	}
+
+	switch (i_blink_op) {
+
+	case LED_OFF:
+		set_led(bdp, PHY_82555_LED_OFF);
+		break;
+	case LED_ON:
+		if (bdp->rev_id >= D101MA_REV_ID)
+			set_led(bdp, PHY_82555_LED_ON_559);
+		else
+			set_led(bdp, PHY_82555_LED_ON_PRE_559);
+
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static e100_proc_entry e100_proc_list[] = {
+	{"Description",           read_descr,            0, 0},
+	{"Permanent_HWaddr",      read_permanent_hwaddr, 0, 0},
+	{"Part_Number",           read_part_number,      0, 0},
+	{"\n",},
+	{"Rx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+	{"Rx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+	{"Tx_TCP_Checksum_Good",  read_gen_ulong, 0, ~0},
+	{"Tx_TCP_Checksum_Bad",   read_gen_ulong, 0, ~0},
+	{"\n",},
+	{"Tx_Abort_Late_Coll",    read_gen_ulong, 0, bdp_drv_off(tx_late_col)},
+	{"Tx_Deferred_Ok",        read_gen_ulong, 0, bdp_drv_off(tx_ok_defrd)},
+	{"Tx_Single_Coll_Ok",     read_gen_ulong, 0, bdp_drv_off(tx_one_retry)},
+	{"Tx_Multi_Coll_Ok",      read_gen_ulong, 0, bdp_drv_off(tx_mt_one_retry)},
+	{"Rx_Long_Length_Errors", read_gen_ulong, 0, ~0},
+	{"\n",},
+	{"Tx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(xmt_fc_pkts)},
+	{"Rx_Flow_Control_Pause", read_gen_ulong, 0, bdp_drv_off(rcv_fc_pkts)},
+	{"Rx_Flow_Control_Unsup", read_gen_ulong, 0, bdp_drv_off(rcv_fc_unsupported)},
+	{"\n",},
+	{"Tx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(xmt_tco_pkts)},
+	{"Rx_TCO_Packets",        read_gen_ulong, 0, bdp_drv_off(rcv_tco_pkts)},
+	{"\n",},
+	{"Rx_Interrupt_Packets",  read_gen_ulong, 0, bdp_drv_off(rx_intr_pkts)},
+	{"Rx_Polling_Packets",    read_gen_ulong, 0, bdp_drv_off(rx_tasklet_pkts)},
+	{"Polling_Interrupt_Switch", read_gen_ulong, 0, bdp_drv_off(poll_intr_switch)},
+	{"Identify_Adapter", 0, write_blink_led_timer, 0},
+	{"", 0, 0, 0}
+};
+
+static int
+read_info(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	e100_proc_entry *pe;
+	int tmp;
+	void *val;
+	int len = 0;
+
+	for (pe = e100_proc_list; pe->name[0]; pe++) {
+		if (pe->name[0] == '\n') {
+			len += sprintf(page + len, "\n");
+			continue;
+		}
+
+		if (pe->read_proc) {
+			if ((len + READ_BUF_MAX_LEN + E100_PE_LEN + 1) >=
+			    PAGE_SIZE)
+				break;
+
+			if (pe->offset != ~0)
+				val = ((char *) bdp) + pe->offset;
+			else
+				val = NULL;
+
+			len += sprintf(page + len, "%-"
+				       __MODULE_STRING(E100_PE_LEN)
+				       "s ", pe->name);
+			len += pe->read_proc(page + len, start, 0,
+					     READ_BUF_MAX_LEN + 1, &tmp, val);
+		}
+	}
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+#ifdef E100_EOU
+/**********************
+ *  parameter entries
+ **********************/
+static int
+read_int_param(char *page, char *name, char *desc, int def, int min, int max)
+{
+	int len;
+
+	len = sprintf(page, "Name: %s\n", name);
+	len += sprintf(page + len, "Description: %s\n", desc);
+	len += sprintf(page + len, "Default_Value: %d\n", def);
+	len += sprintf(page + len, "Type: Range\n");
+	len += sprintf(page + len, "Min: %d\n", min);
+	len += sprintf(page + len, "Max: %d\n", max);
+	len += sprintf(page + len, "Step:1\n");
+	len += sprintf(page + len, "Radix: dec\n");
+
+	return len;
+}
+
+static int
+read_bool_param(char *page, char *name, char *desc, int def)
+{
+	int len;
+
+	len = sprintf(page, "Name: %s\n", name);
+	len += sprintf(page + len, "Description: %s\n", desc);
+	len += sprintf(page + len, "Default_Value: %d\n", def);
+	len += sprintf(page + len, "Type: Enum\n");
+	len += sprintf(page + len, "0: Off\n");
+	len += sprintf(page + len, "1: On\n");
+
+	return len;
+}
+
+static int
+read_speed_duplex_def(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	int len;
+
+	len = sprintf(page, "Name: Speed and Duplex\n");
+	len += sprintf(page + len, "Description: Sets the adapter's "
+		       "speed and duplex mode\n");
+	len += sprintf(page + len, "Default_Value: 0\n");
+	len += sprintf(page + len, "Type: Enum\n");
+	len += sprintf(page + len, "0: Auto-Negotiate\n");
+	len += sprintf(page + len, "1: 10 Mbps / Half Duplex\n");
+	len += sprintf(page + len, "2: 10 Mbps / Full Duplex\n");
+	len += sprintf(page + len, "3: 100 Mbps / Half Duplex\n");
+	len += sprintf(page + len, "4: 100 Mbps / Full Duplex\n");
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_tx_desc_def(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_int_param(page, "Transmit Descriptors",
+			     "Sets the number of Tx descriptors "
+			     "available for the adapter",
+			     E100_DEFAULT_TCB, E100_MIN_TCB, E100_MAX_TCB);
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_rx_desc_def(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_int_param(page, "Receive Descriptors",
+			     "Sets the number of Rx descriptors "
+			     "available for the adapter",
+			     E100_DEFAULT_RFD, E100_MIN_RFD, E100_MAX_RFD);
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ber_def(char *page, char **start, off_t off,
+	     int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_int_param(page, "Bit Error Rate",
+			     "Sets the value for the BER correction algorithm",
+			     E100_DEFAULT_BER, 0, ZLOCK_MAX_ERRORS);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_xsum_rx_def(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "RX Checksum",
+			      "Setting this value to \"On\" enables "
+			      "receive checksum", E100_DEFAULT_XSUM);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ucode_def(char *page, char **start, off_t off,
+	       int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "Microcode",
+			      "Setting this value to \"On\" enables "
+			      "the adapter's microcode", E100_DEFAULT_UCODE);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_bundle_small_def(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "Bundle Small Frames",
+			      "Setting this value to \"On\" enables "
+			      "interrupt bundling of small frames",
+			      E100_DEFAULT_BUNDLE_SMALL_FR);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_fc_def(char *page, char **start, off_t off,
+	    int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "Flow Control",
+			      "Setting this value to \"On\" enables processing "
+			      "flow-control packets", E100_DEFAULT_FC);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_rcv_cong_def(char *page, char **start, off_t off,
+		  int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "Receive Congestion Control",
+			      "Setting this value to \"On\" enables switching "
+			      "to polling mode on receive",
+			      E100_DEFAULT_RX_CONGESTION_CONTROL);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_poll_max_def(char *page, char **start, off_t off,
+		  int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+
+	int len;
+
+	len = read_int_param(page, "Maximum Polling Work",
+			     "Sets the max number of RX packets processed"
+			     " by single polling function call",
+			     bdp->params.RxDescriptors, 1, E100_MAX_RFD);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_int_delay_def(char *page, char **start, off_t off,
+		   int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_int_param(page, "CPU Saver Interrupt Delay",
+			     "Sets the value for CPU saver's interrupt delay",
+			     E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, 0x0,
+			     0xFFFF);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_bundle_max_def(char *page, char **start, off_t off,
+		    int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_int_param(page, "CPU Saver Maximum Bundle",
+			     "Sets the value for CPU saver's maximum value",
+			     E100_DEFAULT_CPUSAVER_BUNDLE_MAX, 0x1, 0xFFFF);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_ifs_def(char *page, char **start, off_t off,
+	     int count, int *eof, void *data)
+{
+	int len;
+
+	len = read_bool_param(page, "IFS",
+			      "Setting this value to \"On\" enables "
+			      "the adaptive IFS algorithm", E100_DEFAULT_IFS);
+
+	return generic_read(page, start, off, count, eof, len);
+}
+
+static int
+read_xsum_rx_val(char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_XSUMRX) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_ucode_val(char *page, char **start, off_t off,
+	       int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_UCODE) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_fc_val(char *page, char **start, off_t off,
+	    int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_FC) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_ifs_val(char *page, char **start, off_t off,
+	     int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_IFS) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_bundle_small_val(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_BUNDLE_SMALL) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_rcv_cong_val(char *page, char **start, off_t off,
+		  int count, int *eof, void *data)
+{
+	struct e100_private *bdp = data;
+	unsigned long val;
+
+	val = (bdp->params.b_params & PRM_RX_CONG) ? 1 : 0;
+	return read_ulong(page, start, off, count, eof, val);
+}
+
+static int
+read_gen_prm(char *page, char **start, off_t off,
+	     int count, int *eof, void *data)
+{
+	int val = 0;
+
+	if (data)
+		val = *((int *) data);
+
+	return read_ulong(page, start, off, count, eof, (unsigned long) val);
+}
+
+static e100_proc_entry e100_proc_params[] = { 
+	/* definitions */
+	{"e100_speed_duplex.def", read_speed_duplex_def, 0, 0},
+	{"RxDescriptors.def",     read_rx_desc_def,      0, 0},
+	{"TxDescriptors.def",     read_tx_desc_def,      0, 0},
+	{"XsumRX.def",            read_xsum_rx_def,      0, 0},
+	{"ucode.def",             read_ucode_def,        0, 0},
+	{"BundleSmallFr.def",     read_bundle_small_def, 0, 0},
+	{"IntDelay.def",          read_int_delay_def,    0, 0},
+	{"BundleMax.def",         read_bundle_max_def,   0, 0},
+	{"ber.def",               read_ber_def,          0, 0},
+	{"flow_control.def",      read_fc_def,           0, 0},
+	{"IFS.def",               read_ifs_def,          0, 0},
+	{"RxCongestionControl.def", read_rcv_cong_def,   0, 0},
+	{"PollingMaxWork.def",      read_poll_max_def,   0, 0},
+	/* values */
+	{"e100_speed_duplex.val", read_gen_prm, 0, bdp_prm_off(e100_speed_duplex)},
+	{"RxDescriptors.val",     read_gen_prm, 0, bdp_prm_off(RxDescriptors)},
+	{"TxDescriptors.val",     read_gen_prm, 0, bdp_prm_off(TxDescriptors)},
+	{"XsumRX.val",            read_xsum_rx_val,      0, 0},
+	{"ucode.val",             read_ucode_val,        0, 0},
+	{"BundleSmallFr.val",     read_bundle_small_val, 0, 0},
+	{"IntDelay.val",          read_gen_prm, 0, bdp_prm_off(IntDelay)},
+	{"BundleMax.val",         read_gen_prm, 0, bdp_prm_off(BundleMax)},
+	{"ber.val",               read_gen_prm, 0, bdp_prm_off(ber)},
+	{"flow_control.val",      read_fc_val,           0, 0},
+	{"IFS.val",               read_ifs_val,          0, 0},
+	{"RxCongestionControl.val", read_rcv_cong_val,   0, 0},
+	{"PollingMaxWork.val",      read_gen_prm, 0, bdp_prm_off(PollingMaxWork)},
+	{"", 0, 0, 0}
+};
+#endif /* E100_EOU */
+
+static struct proc_dir_entry * __devinit
+create_proc_rw(char *name, void *data, struct proc_dir_entry *parent,
+	       read_proc_t * read_proc, write_proc_t * write_proc)
+{
+	struct proc_dir_entry *pdep;
+	mode_t mode = S_IFREG;
+
+	if (write_proc) {
+		mode |= S_IWUSR;
+		if (read_proc) {
+			mode |= S_IRUSR;
+		}
+
+	} else if (read_proc) {
+		mode |= S_IRUGO;
+	}
+
+	if (!(pdep = create_proc_entry(name, mode, parent)))
+		return NULL;
+
+	pdep->read_proc = read_proc;
+	pdep->write_proc = write_proc;
+	pdep->data = data;
+	return pdep;
+}
+
+#ifdef E100_EOU
+static int __devinit
+create_proc_param_subdir(struct e100_private *bdp,
+			 struct proc_dir_entry *dev_dir)
+{
+	struct proc_dir_entry *param_dir;
+	e100_proc_entry *pe;
+	void *data;
+
+	param_dir = create_proc_entry("LoadParameters", S_IFDIR, dev_dir);
+	if (!param_dir)
+		return -ENOMEM;
+
+	for (pe = e100_proc_params; pe->name[0]; pe++) {
+
+		data = ((char *) bdp) + pe->offset;
+
+		if (!(create_proc_rw(pe->name, data, param_dir,
+				     pe->read_proc, pe->write_proc))) {
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+static void
+remove_proc_param_subdir(struct proc_dir_entry *parent)
+{
+	struct proc_dir_entry *de;
+	e100_proc_entry *pe;
+	int len;
+
+	len = strlen("LoadParameters");
+
+	for (de = parent->subdir; de; de = de->next) {
+		if ((de->namelen == len) &&
+		    (!memcmp(de->name, "LoadParameters", len)))
+			break;
+	}
+
+	if (!de)
+		return;
+
+	for (pe = e100_proc_params; pe->name[0]; pe++) {
+		remove_proc_entry(pe->name, de);
+	}
+
+	remove_proc_entry("LoadParameters", parent);
+}
+#endif /* E100_EOU */
+
+void
+e100_remove_proc_subdir(struct e100_private *bdp)
+{
+	e100_proc_entry *pe;
+	char info[256];
+	int len;
+
+	/* If our root /proc dir was not created, there is nothing to remove */
+	if (adapters_proc_dir == NULL) {
+		return;
+	}
+
+	len = strlen(bdp->device->name);
+	strncpy(info, bdp->device->name, sizeof (info));
+	strncat(info + len, ".info", sizeof (info) - len);
+
+	if (bdp->proc_parent) {
+		for (pe = e100_proc_list; pe->name[0]; pe++) {
+			if (pe->name[0] == '\n')
+				continue;
+
+			remove_proc_entry(pe->name, bdp->proc_parent);
+		}
+
+#ifdef E100_EOU
+		remove_proc_param_subdir(bdp->proc_parent);
+#endif
+		remove_proc_entry(bdp->device->name, adapters_proc_dir);
+		bdp->proc_parent = NULL;
+	}
+
+	remove_proc_entry(info, adapters_proc_dir);
+
+	/* try to remove the main /proc dir, if it's empty */
+	e100_proc_cleanup();
+}
+
+int __devinit
+e100_create_proc_subdir(struct e100_private *bdp)
+{
+	struct proc_dir_entry *dev_dir;
+	e100_proc_entry *pe;
+	char info[256];
+	int len;
+	void *data;
+
+	/* create the main /proc dir if needed */
+	if (!adapters_proc_dir) {
+		if (!e100_init_proc_dir())
+			return -ENOMEM;
+	}
+
+	strncpy(info, bdp->device->name, sizeof (info));
+	len = strlen(info);
+	strncat(info + len, ".info", sizeof (info) - len);
+
+	/* info */
+	if (!(create_proc_rw(info, bdp, adapters_proc_dir, read_info, 0))) {
+		e100_proc_cleanup();
+		return -ENOMEM;
+	}
+
+	dev_dir = create_proc_entry(bdp->device->name, S_IFDIR,
+				    adapters_proc_dir);
+	bdp->proc_parent = dev_dir;
+
+	if (!dev_dir) {
+		e100_remove_proc_subdir(bdp);
+		return -ENOMEM;
+	}
+
+	for (pe = e100_proc_list; pe->name[0]; pe++) {
+		if (pe->name[0] == '\n')
+			continue;
+
+		if (pe->offset != ~0)
+			data = ((char *) bdp) + pe->offset;
+		else
+			data = NULL;
+
+		if (!(create_proc_rw(pe->name, data, dev_dir,
+				     pe->read_proc, pe->write_proc))) {
+			e100_remove_proc_subdir(bdp);
+			return -ENOMEM;
+		}
+	}
+
+#ifdef E100_EOU
+	if (create_proc_param_subdir(bdp, dev_dir)) {
+		e100_remove_proc_subdir(bdp);
+		return -ENOMEM;
+	}
+#endif
+
+	return 0;
+}
+
+/****************************************************************************
+ * Name:          e100_init_proc_dir
+ *
+ * Description:   This routine creates the top-level /proc directory for the
+ *                driver in /proc/net
+ *
+ * Arguments:     none
+ *
+ * Returns:       true on success, false on fail
+ *
+ ***************************************************************************/
+static unsigned char
+e100_init_proc_dir(void)
+{
+	int len;
+
+	/* first check if adapters_proc_dir already exists */
+	len = strlen(ADAPTERS_PROC_DIR);
+	for (adapters_proc_dir = proc_net->subdir;
+	     adapters_proc_dir; adapters_proc_dir = adapters_proc_dir->next) {
+
+		if ((adapters_proc_dir->namelen == len) &&
+		    (!memcmp(adapters_proc_dir->name, ADAPTERS_PROC_DIR, len)))
+			break;
+	}
+
+	if (!adapters_proc_dir)
+		adapters_proc_dir =
+			create_proc_entry(ADAPTERS_PROC_DIR, S_IFDIR, proc_net);
+
+	if (!adapters_proc_dir)
+		return false;
+
+	return true;
+}
+
+/****************************************************************************
+ * Name:          e100_proc_cleanup
+ *
+ * Description:   This routine clears the top-level /proc directory, if empty.
+ *
+ * Arguments:     none
+ *
+ * Returns:       none
+ *
+ ***************************************************************************/
+static void
+e100_proc_cleanup(void)
+{
+	struct proc_dir_entry *de;
+
+	if (adapters_proc_dir == NULL) {
+		return;
+	}
+
+	/* check if subdir list is empty before removing adapters_proc_dir */
+	for (de = adapters_proc_dir->subdir; de; de = de->next) {
+		/* ignore . and .. */
+		if (*(de->name) != '.')
+			break;
+	}
+
+	if (de)
+		return;
+
+	remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
+	adapters_proc_dir = NULL;
+}
+
+#endif /* CONFIG_PROC_FS */
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_ucode.h linux-2.5.6/drivers/net/e100/e100_ucode.h
--- linux-2.5.6-pre3/drivers/net/e100/e100_ucode.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_ucode.h	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,411 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef _E100_UCODE_H_
+#define _E100_UCODE_H_
+
+/*
+e100_ucode.h
+
+This file contains the loadable micro code arrays to implement receive 
+bundling on the D101 A-step, D101 B-step, D101M (B-step only), D101S, 
+D102 B-step, D102 B-step with TCO work around and D102 C-step.
+
+Each controller has its own specific micro code array.  The array for one 
+controller is totally incompatible with any other controller, and if used 
+will most likely cause the controller to lock up and stop responding to 
+the driver.  Each micro code array has its own parameter offsets (described 
+below), and they each have their own version number.
+*/
+
+/*************************************************************************
+*  CPUSaver parameters
+*
+*  All CPUSaver parameters are 16-bit literals that are part of a
+*  "move immediate value" instruction.  By changing the value of
+*  the literal in the instruction before the code is loaded, the
+*  driver can change algorithm.
+*
+*  CPUSAVER_DWORD - This is the location of the instruction that loads
+*    the dead-man timer with its inital value.  By writing a 16-bit
+*    value to the low word of this instruction, the driver can change
+*    the timer value.  The current default is either x600 or x800;
+*    experiments show that the value probably should stay within the
+*    range of x200 - x1000.
+*
+*  CPUSAVER_BUNDLE_MAX_DWORD - This is the location of the instruction
+*    that sets the maximum number of frames that will be bundled.  In
+*    some situations, such as the TCP windowing algorithm, it may be
+*    better to limit the growth of the bundle size than let it go as
+*    high as it can, because that could cause too much added latency.
+*    The default is six, because this is the number of packets in the
+*    default TCP window size.  A value of 1 would make CPUSaver indicate
+*    an interrupt for every frame received.  If you do not want to put
+*    a limit on the bundle size, set this value to xFFFF.
+*
+*  CPUSAVER_MIN_SIZE_DWORD - This is the location of the instruction
+*    that contains a bit-mask describing the minimum size frame that
+*    will be bundled.  The default masks the lower 7 bits, which means
+*    that any frame less than 128 bytes in length will not be bundled,
+*    but will instead immediately generate an interrupt.  This does
+*    not affect the current bundle in any way.  Any frame that is 128
+*    bytes or large will be bundled normally.  This feature is meant
+*    to provide immediate indication of ACK frames in a TCP environment.
+*    Customers were seeing poor performance when a machine with CPUSaver
+*    enabled was sending but not receiving.  The delay introduced when
+*    the ACKs were received was enough to reduce total throughput, because
+*    the sender would sit idle until the ACK was finally seen.
+*
+*    The current default is 0xFF80, which masks out the lower 7 bits.
+*    This means that any frame which is x7F (127) bytes or smaller
+*    will cause an immediate interrupt.  Because this value must be a 
+*    bit mask, there are only a few valid values that can be used.  To
+*    turn this feature off, the driver can write the value xFFFF to the
+*    lower word of this instruction (in the same way that the other
+*    parameters are used).  Likewise, a value of 0xF800 (2047) would
+*    cause an interrupt to be generated for every frame, because all
+*    standard Ethernet frames are <= 2047 bytes in length.
+*************************************************************************/
+
+#ifndef UCODE_MAX_DWORDS
+#define UCODE_MAX_DWORDS	134
+#endif
+
+/********************************************************/
+/*  CPUSaver micro code for the D101A                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+/*  This value is the same for both A and B step of 558.  */
+
+#define D101_CPUSAVER_TIMER_DWORD		72
+#define D101_CPUSAVER_BUNDLE_DWORD		UCODE_MAX_DWORDS
+#define D101_CPUSAVER_MIN_SIZE_DWORD		UCODE_MAX_DWORDS
+
+#define     D101_A_RCVBUNDLE_UCODE \
+{\
+0x03B301BB, 0x0046FFFF, 0xFFFFFFFF, 0x051DFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101212, 0x000C0008, 0x003801BC, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B5, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x00130836, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130824, 0x00222819, \
+0x00101213, 0x00041000, 0x003A03B3, 0x00010200, \
+0x00101B13, 0x00238081, 0x00213049, 0x0038003B, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134824, 0x000C0001, \
+0x00101213, 0x00041000, 0x0038051E, 0x00101313, \
+0x00010400, 0x00380521, 0x00050600, 0x00100824, \
+0x00101310, 0x00041000, 0x00080600, 0x00101B10, \
+0x0038051E, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101B                   */
+/********************************************************/
+
+/*  Version 2.0  */
+
+#define     D101_B0_RCVBUNDLE_UCODE \
+{\
+0x03B401BC, 0x0047FFFF, 0xFFFFFFFF, 0x051EFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \
+0x000C0001, 0x00101B92, 0x000C0008, 0x003801BD, \
+0x00000000, 0x00124818, 0x000C1000, 0x00220809, \
+0x00010200, 0x00124818, 0x000CFFFC, 0x003803B6, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B81D, 0x0013082F, 0x000C0001, \
+0x0026081C, 0x0020C81B, 0x00130837, 0x00222819, \
+0x00101B93, 0x00041000, 0x003A03B4, 0x00010200, \
+0x00101793, 0x00238082, 0x0021304A, 0x0038003C, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x0024B83E, 0x00130826, 0x000C0001, \
+0x0026083B, 0x00010200, 0x00134837, 0x000C0001, \
+0x00101B93, 0x00041000, 0x0038051F, 0x00101313, \
+0x00010400, 0x00380522, 0x00050600, 0x00100837, \
+0x00101310, 0x00041000, 0x00080600, 0x00101790, \
+0x0038051F, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101M (B-step only)     */
+/********************************************************/
+
+/*  Version 2.10.1  */
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD		78
+#define D101M_CPUSAVER_BUNDLE_DWORD		65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD		126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D101S                   */
+/********************************************************/
+
+/*  Version 1.20.1  */
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD		78
+#define D101S_CPUSAVER_BUNDLE_DWORD		67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD		128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  CPUSaver micro code for the D102 B-step             */
+/********************************************************/
+
+/*  Version 2.0  */
+/*  Parameter values for the D102 B-step  */
+#define D102_B_CPUSAVER_TIMER_DWORD		82
+#define D102_B_CPUSAVER_BUNDLE_DWORD		106
+#define D102_B_CPUSAVER_MIN_SIZE_DWORD		70
+
+#define     D102_B_RCVBUNDLE_UCODE \
+{\
+0x006F0276, 0x0EF71FFF, 0x0ED30F86, 0x0D250ED9, 0x1FFF1FFF, 0x1FFF04D2, \
+0x00300001, 0x0140D871, 0x00300008, 0x00E00277, \
+0x01406C57, 0x00816073, 0x008700FA, 0x00E00070, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807F9A, 0x00901F9A, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912EFC, \
+0x00E00EF8, 0x00000000, 0x00000000, 0x00000000, \
+0x00906F8C, 0x00900F8C, 0x00E00F87, 0x00000000, \
+0x00906ED8, 0x01406C55, 0x00E00ED4, 0x00000000, \
+0x01406C51, 0x0080DFC2, 0x01406C52, 0x00815FC2, \
+0x01406C57, 0x00917FCC, 0x00E01FDD, 0x00000000, \
+0x00822D30, 0x01406C51, 0x0080CD26, 0x01406C52, \
+0x00814D26, 0x01406C57, 0x00916D26, 0x014C6FD7, \
+0x00300000, 0x00841FD2, 0x00300001, 0x0140D772, \
+0x00E012B3, 0x014C6F91, 0x0150710B, 0x01496F72, \
+0x0030FF80, 0x00940EDD, 0x00102000, 0x00038400, \
+0x00E00EDA, 0x00000000, 0x00000000, 0x00000000, \
+0x01406C57, 0x00917FE9, 0x00001000, 0x00E01FE9, \
+0x00200600, 0x0140D76F, 0x00138400, 0x01406FD8, \
+0x0140D96F, 0x00E01FDD, 0x00038400, 0x00102000, \
+0x00971FD7, 0x00101000, 0x00050200, 0x00E804D2, \
+0x014C6FD8, 0x00300001, 0x00840D26, 0x0140D872, \
+0x00E00D26, 0x014C6FD9, 0x00300001, 0x0140D972, \
+0x00941FBD, 0x00102000, 0x00038400, 0x014C6FD8, \
+0x00300006, 0x00840EDA, 0x014F71D8, 0x0140D872, \
+0x00E00EDA, 0x01496F50, 0x00E004D3, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for the D102 C-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 C-step  */
+#define D102_C_CPUSAVER_TIMER_DWORD		46
+#define D102_C_CPUSAVER_BUNDLE_DWORD		74
+#define D102_C_CPUSAVER_MIN_SIZE_DWORD		54
+
+#define     D102_C_RCVBUNDLE_UCODE \
+{ \
+0x00700279, 0x0E6604E2, 0x02BF0CAE, 0x1508150C, 0x15190E5B, 0x0E840F13, \
+0x00E014D8, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014DC, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014F4, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E0, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014E7, 0x00000000, 0x00000000, 0x00000000, \
+0x00141000, 0x015D6F0D, 0x00E002C0, 0x00000000, \
+0x00200600, 0x00E0150D, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E6A, 0x00038200, 0x00102000, \
+0x00E00E67, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E65, 0x00800E60, 0x00E00E5D, 0x00000000, \
+0x00300006, 0x00E0151A, 0x00000000, 0x00000000, \
+0x00906F19, 0x00900F19, 0x00E00F14, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x01406CBA, 0x00807FDA, 0x00901FDA, 0x0024FFFF, \
+0x014B6F6F, 0x0030FFFE, 0x01407172, 0x01496FBA, \
+0x014B6F72, 0x00308000, 0x01406C52, 0x00912E89, \
+0x00E00E85, 0x00000000, 0x00000000, 0x00000000  \
+}
+
+/********************************************************/
+/*  Micro code for the D102 E-step                      */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD		42
+#define D102_E_CPUSAVER_BUNDLE_DWORD		54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD		46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x1FFF1FFF, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000  \
+}
+
+#endif /* _E100_UCODE_H_ */
diff -urN linux-2.5.6-pre3/drivers/net/e100/e100_vendor.h linux-2.5.6/drivers/net/e100/e100_vendor.h
--- linux-2.5.6-pre3/drivers/net/e100/e100_vendor.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/e100/e100_vendor.h	Thu Mar  7 18:24:45 2002
@@ -0,0 +1,348 @@
+/*******************************************************************************
+
+This software program is available to you under a choice of one of two 
+licenses. You may choose to be licensed under either the GNU General Public 
+License (GPL) Version 2, June 1991, available at 
+http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the 
+text of which follows:
+
+Recipient has requested a license and Intel Corporation ("Intel") is willing
+to grant a license for the software entitled Linux Base Driver for the 
+Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided 
+by Intel Corporation. The following definitions apply to this license:
+
+"Licensed Patents" means patent claims licensable by Intel Corporation which 
+are necessarily infringed by the use of sale of the Software alone or when 
+combined with the operating system referred to below.
+
+"Recipient" means the party to whom Intel delivers this Software.
+
+"Licensee" means Recipient and those third parties that receive a license to 
+any operating system available under the GNU Public License version 2.0 or 
+later.
+
+Copyright (c) 1999 - 2002 Intel Corporation.
+All rights reserved.
+
+The license is provided to Recipient and Recipient's Licensees under the 
+following terms.
+
+Redistribution and use in source and binary forms of the Software, with or 
+without modification, are permitted provided that the following conditions 
+are met:
+
+Redistributions of source code of the Software may retain the above 
+copyright notice, this list of conditions and the following disclaimer.
+
+Redistributions in binary form of the Software may reproduce the above 
+copyright notice, this list of conditions and the following disclaimer in 
+the documentation and/or materials provided with the distribution.
+
+Neither the name of Intel Corporation nor the names of its contributors 
+shall be used to endorse or promote products derived from this Software 
+without specific prior written permission.
+
+Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, 
+royalty-free patent license under Licensed Patents to make, use, sell, offer 
+to sell, import and otherwise transfer the Software, if any, in source code 
+and object code form. This license shall include changes to the Software 
+that are error corrections or other minor changes to the Software that do 
+not add functionality or features when the Software is incorporated in any 
+version of an operating system that has been distributed under the GNU 
+General Public License 2.0 or later. This patent license shall apply to the 
+combination of the Software and any operating system licensed under the GNU 
+Public License version 2.0 or later if, at the time Intel provides the 
+Software to Recipient, such addition of the Software to the then publicly 
+available versions of such operating systems available under the GNU Public 
+License version 2.0 or later (whether in gold, beta or alpha form) causes 
+such combination to be covered by the Licensed Patents. The patent license 
+shall not apply to any other combinations which include the Software. NO 
+hardware per se is licensed hereunder.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
+(INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED 
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR 
+TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************/
+
+#ifndef E100_VENDOR_ID_INFO
+#define E100_VENDOR_ID_INFO
+/* ====================================================================== */
+/*                              vendor_info                               */
+/* ====================================================================== */
+
+struct e100_vendor_info {
+	unsigned long device_type;
+	char *idstr;
+};
+
+enum e100_device_type {
+	E100_BRD_100TX = 1,
+	E100_BRD_100T4,
+	E100_BRD_10T,
+	E100_BRD_100WFM,
+	E100_BRD_82557,
+	E100_BRD_82557_WOL,
+	E100_BRD_82558,
+	E100_BRD_82558_WOL,
+	E100_BRD_100,
+	E100_BRD_100M,
+	E100_BRD_AOL2,
+	E100_BRD_AOL,
+	E100_PROS_M,
+	E100_PROS_AM,
+	E100_PROS_AM_AOL,
+	E100_PROS_DT,
+	E100_PRO_DT,
+	E100_PROM_DT,
+	E100_PRO_SRV,
+	E100_PRO_SRVP,
+	E100_PROS_SRV,
+	E100_PRO_DUAL,
+	E100_PROS_DUAL,
+	E100_PROP_DUAL,
+	E100_PROP_WOL,
+	E100_PROS_MOB,
+	E100_PRO_CB,
+	E100_PRO_CB_M,
+	E100_PROSR_MOB,
+	E100_PROS_MC,
+	E100_PROSR_MC,
+	E100_PROP_MC,
+	E100_PROSP_MC,
+	E100_PROP_MOB,
+	E100_PROSP_MOB,
+	E100_PRO_MINI,
+	E100_PRO_NET,
+	E100_PROS_NET,
+	E100_PROVM_NET,
+	E100_PROVE_D,
+	E100_82559_LOM,
+	E100_82559_LOM_AOL,
+	E100_82559_LOM_AOL2,
+	E100_IBM_MDS,
+	E100_CMPQ_S,
+	E100_PROVE_DA,
+	E100_PROVM_DA,
+	E100_PROVE_LOM,
+	E100_PROVE_NET,
+	E100_82562,
+	E100_ALL_BOARDS,
+};
+
+struct e100_vendor_info e100_vendor_info_array[] = {
+	{ E100_BRD_100TX, "Intel(R) PRO/100B PCI Adapter (TX)"},
+	{ E100_BRD_100T4, "Intel(R) PRO/100B PCI Adapter (T4)"},
+	{ E100_BRD_10T, "Intel(R) PRO/10+ PCI Adapter"},
+	{ E100_BRD_100WFM, "Intel(R) PRO/100 WfM PCI Adapter"},
+	{ E100_BRD_82557, "Intel(R) 82557-based Integrated Ethernet PCI (10/100)"},
+	{ E100_BRD_82557_WOL, "Intel(R) 82557-based Integrated Ethernet with Wake on LAN*"},
+	{ E100_BRD_82558, "Intel(R) 82558-based Integrated Ethernet"},
+	{ E100_BRD_82558_WOL, "Intel(R) 82558-based Integrated Ethernet with Wake on LAN*"},
+	{ E100_BRD_100, "Intel(R) PRO/100+ PCI Adapter"},
+	{ E100_BRD_100M, "Intel(R) PRO/100+ Management Adapter"},
+	{ E100_BRD_AOL2, "Intel(R) PRO/100+ Alert on LAN* 2 Management Adapter"},
+	{ E100_BRD_AOL, "Intel(R) PRO/100+ Alert on LAN* Management Adapter"},
+	{ E100_PROS_M, "Intel(R) PRO/100 S Management Adapter"},
+	{ E100_PROS_AM, "Intel(R) PRO/100 S Advanced Management Adapter"},
+	{ E100_PROS_AM_AOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* GC"},
+	{ E100_PROS_DT, "Intel(R) PRO/100 S Desktop Adapter"},
+	{ E100_PRO_DT, "Intel(R) PRO/100 Desktop Adapter"},
+	{ E100_PROM_DT, "Intel(R) PRO/100 M Desktop Adapter"},
+	{ E100_PRO_SRV, "Intel(R) PRO/100+ Server Adapter"},
+	{ E100_PRO_SRVP, "Intel(R) PRO/100+ Server Adapter (PILA8470B)"},
+	{ E100_PROS_SRV, "Intel(R) PRO/100 S Server Adapter"},
+	{ E100_PRO_DUAL, "Intel(R) PRO/100 Dual Port Server Adapter"},
+	{ E100_PROS_DUAL, "Intel(R) PRO/100 S Dual Port Server Adapter"},
+	{ E100_PROP_DUAL, "Intel(R) PRO/100+ Dual Port Server Adapter"},
+	{ E100_PROP_WOL, "Intel(R) PRO/100+ Management Adapter with Alert On LAN* G Server"},
+	{ E100_PROS_MOB, "Intel(R) PRO/100 S Mobile Adapter"},
+	{ E100_PRO_CB, "Intel(R) PRO/100 CardBus II"},
+	{ E100_PRO_CB_M, "Intel(R) PRO/100 LAN+Modem56 CardBus II"},
+	{ E100_PROSR_MOB, "Intel(R) PRO/100 SR Mobile Adapter"},
+	{ E100_PROS_MC, "Intel(R) PRO/100 S Mobile Combo Adapter"},
+	{ E100_PROSR_MC, "Intel(R) PRO/100 SR Mobile Combo Adapter"},
+	{ E100_PROP_MC, "Intel(R) PRO/100 P Mobile Combo Adapter"},
+	{ E100_PROSP_MC, "Intel(R) PRO/100 SP Mobile Combo Adapter"},
+	{ E100_PROP_MOB, "Intel(R) PRO/100 P Mobile Adapter"},
+	{ E100_PROSP_MOB, "Intel(R) PRO/100 SP Mobile Adapter"},
+	{ E100_PRO_MINI, "Intel(R) PRO/100+ Mini PCI"},
+	{ E100_PRO_NET, "Intel(R) PRO/100 Network Connection" },
+	{ E100_PROS_NET, "Intel(R) PRO/100 S Network Connection" },
+	{ E100_PROVM_NET, "Intel(R) PRO/100 VM Network Connection"},
+	{ E100_PROVE_D, "Intel(R) PRO/100 VE Desktop Connection"},
+	{ E100_82559_LOM, "Intel(R) 82559 Fast Ethernet LAN on Motherboard"},
+	{ E100_82559_LOM_AOL, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN*" },
+	{ E100_82559_LOM_AOL2, "Intel(R) 82559 Fast Ethernet LOM with Alert on LAN* 2" },
+	{ E100_IBM_MDS, "IBM Mobile, Desktop & Server Adapters"},
+	{ E100_CMPQ_S, "Compaq Fast Ethernet Server Adapter" },
+	{ E100_PROVE_DA, "Intel(R) PRO/100 VE Desktop Adapter"},
+	{ E100_PROVM_DA, "Intel(R) PRO/100 VM Desktop Adapter"},
+	{ E100_PROVE_LOM, "Intel(R) PRO/100 VE Network ConnectionPLC LOM" },
+	{ E100_PROVE_NET, "Intel(R) PRO/100 VE Network Connection"},
+	{ E100_82562, "Intel(R)82562 based Fast Ethernet Connection"},
+	{ E100_ALL_BOARDS, "Intel(R) 8255x-based Ethernet Adapter"},
+	{0,NULL}
+};
+
+static struct pci_device_id e100_id_table[] __devinitdata = {
+	{0x8086, 0x1229, 0x8086, 0x0001, 0, 0, E100_BRD_100TX},
+	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0002, 0, 0, E100_BRD_100T4},
+	{0x8086, 0x1229, 0x8086, 0x0003, 0, 0, E100_BRD_10T},
+	{0x8086, 0x1229, 0x8086, 0x0004, 0, 0, E100_BRD_100WFM},
+	{0x8086, 0x1229, 0x8086, 0x0005, 0, 0, E100_BRD_82557},
+	{0x8086, 0x1229, 0x8086, 0x0006, 0, 0, E100_BRD_82557_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0007, 0, 0, E100_BRD_82558},
+	{0x8086, 0x1229, 0x8086, 0x0008, 0, 0, E100_BRD_82558_WOL},
+	{0x8086, 0x1229, 0x8086, 0x0009, 0, 0, E100_BRD_100},
+	{0x8086, 0x1229, 0x8086, 0x000A, 0, 0, E100_BRD_100M},
+	{0x8086, 0x1229, 0x8086, 0x000B, 0, 0, E100_BRD_100},
+	{0x8086, 0x1229, 0x8086, 0x000C, 0, 0, E100_BRD_100M},
+	{0x8086, 0x1229, 0x8086, 0x000D, 0, 0, E100_BRD_AOL2},
+	{0x8086, 0x1229, 0x8086, 0x000E, 0, 0, E100_BRD_AOL},
+	{0x8086, 0x1229, 0x8086, 0x0010, 0, 0, E100_PROS_M},
+	{0x8086, 0x1229, 0x8086, 0x0011, 0, 0, E100_PROS_M},
+	{0x8086, 0x1229, 0x8086, 0x0012, 0, 0, E100_PROS_AM},
+	{0x8086, 0x1229, 0x8086, 0x0013, 0, 0, E100_PROS_AM},
+	{0x8086, 0x1229, 0x8086, 0x0030, 0, 0, E100_PROS_AM_AOL},
+	{0x8086, 0x1229, 0x8086, 0x0040, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0041, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0042, 0, 0, E100_PRO_DT},
+	{0x8086, 0x1229, 0x8086, 0x0050, 0, 0, E100_PROS_DT},
+	{0x8086, 0x1229, 0x8086, 0x0070, 0, 0, E100_PROM_DT},
+	{0x8086, 0x1229, 0x8086, 0x1009, 0, 0, E100_PRO_SRV},
+	{0x8086, 0x1229, 0x8086, 0x100C, 0, 0, E100_PRO_SRVP},
+	{0x8086, 0x1229, 0x8086, 0x1012, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1013, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1014, 0, 0, E100_PRO_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1015, 0, 0, E100_PROS_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1016, 0, 0, E100_PROS_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1017, 0, 0, E100_PROP_DUAL},
+	{0x8086, 0x1229, 0x8086, 0x1030, 0, 0, E100_PROP_WOL},
+	{0x8086, 0x1229, 0x8086, 0x1040, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1041, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1042, 0, 0, E100_PRO_SRV},
+	{0x8086, 0x1229, 0x8086, 0x1050, 0, 0, E100_PROS_SRV},
+	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+	{0x8086, 0x1229, 0x8086, 0x10F0, 0, 0, E100_PROP_DUAL}, 
+	{0x8086, 0x1229, 0x8086, 0x2009, 0, 0, E100_PROS_MOB},
+	{0x8086, 0x1229, 0x8086, 0x200D, 0, 0, E100_PRO_CB},
+	{0x8086, 0x1229, 0x8086, 0x200E, 0, 0, E100_PRO_CB_M},
+	{0x8086, 0x1229, 0x8086, 0x200F, 0, 0, E100_PROSR_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2010, 0, 0, E100_PROS_MC},
+	{0x8086, 0x1229, 0x8086, 0x2013, 0, 0, E100_PROSR_MC},
+	{0x8086, 0x1229, 0x8086, 0x2016, 0, 0, E100_PROS_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2017, 0, 0, E100_PROS_MC},
+	{0x8086, 0x1229, 0x8086, 0x2018, 0, 0, E100_PROSR_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2019, 0, 0, E100_PROSR_MC},
+	{0x8086, 0x1229, 0x8086, 0x2101, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2102, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2103, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2104, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2105, 0, 0, E100_PROSP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2106, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x1229, 0x8086, 0x2107, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x2108, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x2200, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2201, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2202, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2203, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2204, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2205, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2206, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2207, 0, 0, E100_PROSP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2208, 0, 0, E100_PROP_MC},
+	{0x8086, 0x1229, 0x8086, 0x2408, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x240F, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x2411, 0, 0, E100_PRO_MINI},
+	{0x8086, 0x1229, 0x8086, 0x3400, 0, 0, E100_82559_LOM},
+	{0x8086, 0x1229, 0x8086, 0x3000, 0, 0, E100_82559_LOM},
+	{0x8086, 0x1229, 0x8086, 0x3001, 0, 0, E100_82559_LOM_AOL},
+	{0x8086, 0x1229, 0x8086, 0x3002, 0, 0, E100_82559_LOM_AOL2},
+	{0x8086, 0x1229, 0x8086, 0x3006, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3007, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3008, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x8086, 0x3010, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3011, 0, 0, E100_PROS_NET},
+	{0x8086, 0x1229, 0x8086, 0x3012, 0, 0, E100_PRO_NET},
+	{0x8086, 0x1229, 0x1014, 0x005C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x305C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x405C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x605C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x505C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x105C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x805C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x705C, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x01F1, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x0232, 0, 0, E100_IBM_MDS},   
+	{0x8086, 0x1229, 0x1014, 0x0207, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x023F, 0, 0, E100_PRO_NET},   
+	{0x8086, 0x1229, 0x1014, 0x01BC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01CE, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01DC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01EB, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x01EC, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0202, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0205, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x1014, 0x0217, 0, 0, E100_PRO_NET},     
+	{0x8086, 0x1229, 0x0E11, 0xB01E, 0, 0, E100_CMPQ_S},         
+	{0x8086, 0x1229, 0x0E11, 0xB02F, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB04A, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0C6, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0C7, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0D7, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0DD, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0DE, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB0E1, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB134, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB13C, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB144, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB163, 0, 0, E100_CMPQ_S},     
+	{0x8086, 0x1229, 0x0E11, 0xB164, 0, 0, E100_CMPQ_S},
+	{0x8086, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+
+	{0x8086, 0x2449, 0x1014, 0x0265, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x1014, 0x0267, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x1014, 0x026A, 0, 0, E100_PROVE_D},
+	{0x8086, 0x2449, 0x8086, 0x3010, 0, 0, E100_PROVE_DA},
+	{0x8086, 0x2449, 0x8086, 0x3011, 0, 0, E100_PROVM_DA},
+	{0x8086, 0x2449, 0x8086, 0x3013, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x2449, 0x8086, 0x3014, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2449, 0x8086, 0x3016, 0, 0, E100_PROP_MC},
+	{0x8086, 0x2449, 0x8086, 0x3017, 0, 0, E100_PROP_MOB},
+	{0x8086, 0x2449, 0x8086, 0x3018, 0, 0, E100_PRO_NET},
+	{0x8086, 0x2449, 0x0E11, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2449, 0x1014, PCI_ANY_ID, 0, 0, E100_PROVE_D},	
+	{0x8086, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+
+	{0x8086, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+  	{0x8086, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},
+	{0x8086, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_ALL_BOARDS},	
+	{0x8086, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET}, 
+	{0x8086, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+	{0x8086, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET}, 
+	{0x8086, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVE_NET},
+	{0x8086, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_PROVM_NET},
+	{0x8086, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+	{0x8086, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, E100_82562},
+	{0,} /* This has to be the last entry*/
+};
+
+#endif /* E100_VENDOR_ID_INFO */
diff -urN linux-2.5.6-pre3/drivers/net/e1000/e1000_main.c linux-2.5.6/drivers/net/e1000/e1000_main.c
--- linux-2.5.6-pre3/drivers/net/e1000/e1000_main.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/e1000/e1000_main.c	Thu Mar  7 18:24:45 2002
@@ -128,7 +128,7 @@
 	"IBM Mobile, Desktop & Server Adapters"
 };
 
-/* Local Function Prototypes */
+/* e1000_main.c Function Prototypes */
 
 int e1000_up(struct e1000_adapter *adapter);
 void e1000_down(struct e1000_adapter *adapter);
@@ -193,23 +193,6 @@
 MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
-#ifdef EXPORT_SYMTAB
-EXPORT_SYMBOL(e1000_init_module);
-EXPORT_SYMBOL(e1000_exit_module);
-EXPORT_SYMBOL(e1000_probe);
-EXPORT_SYMBOL(e1000_remove);
-EXPORT_SYMBOL(e1000_open);
-EXPORT_SYMBOL(e1000_close);
-EXPORT_SYMBOL(e1000_xmit_frame);
-EXPORT_SYMBOL(e1000_intr);
-EXPORT_SYMBOL(e1000_set_multi);
-EXPORT_SYMBOL(e1000_change_mtu);
-EXPORT_SYMBOL(e1000_set_mac);
-EXPORT_SYMBOL(e1000_get_stats);
-EXPORT_SYMBOL(e1000_watchdog);
-EXPORT_SYMBOL(e1000_ioctl);
-#endif
-
 /**
  * e1000_init_module - Driver Registration Routine
  *
diff -urN linux-2.5.6-pre3/drivers/net/e2100.c linux-2.5.6/drivers/net/e2100.c
--- linux-2.5.6-pre3/drivers/net/e2100.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/drivers/net/e2100.c	Thu Mar  7 18:24:45 2002
@@ -388,10 +388,12 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
 MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_E21_CARDS) "i");
-MODULE_PARM_DESC(io, "E2100 I/O base address(es)");
-MODULE_PARM_DESC(irq, "E2100 IRQ number(s)");
-MODULE_PARM_DESC(mem, " E2100 memory base address(es)");
-MODULE_PARM_DESC(xcvr, "E2100 tranceiver(s) (0=internal, 1=external)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, " memory base address(es)");
+MODULE_PARM_DESC(xcvr, "tranceiver(s) (0=internal, 1=external)");
+MODULE_DESCRIPTION("Cabletron E2100 ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -440,7 +442,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/eepro100.c linux-2.5.6/drivers/net/eepro100.c
--- linux-2.5.6-pre3/drivers/net/eepro100.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/eepro100.c	Thu Mar  7 18:24:45 2002
@@ -130,17 +130,17 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(multicast_filter_limit, "i");
-MODULE_PARM_DESC(debug, "eepro100 debug level (0-6)");
-MODULE_PARM_DESC(options, "eepro100: Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps");
-MODULE_PARM_DESC(full_duplex, "eepro100 full duplex setting(s) (1)");
-MODULE_PARM_DESC(congenb, "eepro100  Enable congestion control (1)");
-MODULE_PARM_DESC(txfifo, "eepro100 Tx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(rxfifo, "eepro100 Rx FIFO threshold in 4 byte units, (0-15)");
-MODULE_PARM_DESC(txdmaccount, "eepro100 Tx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rxdmaccount, "eepro100 Rx DMA burst length; 128 - disable (0-128)");
-MODULE_PARM_DESC(rx_copybreak, "eepro100 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(max_interrupt_work, "eepro100 maximum events handled per interrupt");
-MODULE_PARM_DESC(multicast_filter_limit, "eepro100 maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(debug, "debug level (0-6)");
+MODULE_PARM_DESC(options, "Bits 0-3: tranceiver type, bit 4: full duplex, bit 5: 100Mbps");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
+MODULE_PARM_DESC(congenb, "Enable congestion control (1)");
+MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)");
+MODULE_PARM_DESC(txdmaccount, "Tx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rxdmaccount, "Rx DMA burst length; 128 - disable (0-128)");
+MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt");
+MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses");
 
 #define RUN_AT(x) (jiffies + (x))
 
diff -urN linux-2.5.6-pre3/drivers/net/es3210.c linux-2.5.6/drivers/net/es3210.c
--- linux-2.5.6-pre3/drivers/net/es3210.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/es3210.c	Thu Mar  7 18:24:46 2002
@@ -383,9 +383,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_ES_CARDS) "i");
-MODULE_PARM_DESC(io, "ES3210 I/O base address(es)");
-MODULE_PARM_DESC(irq, "ES3210 IRQ number(s)");
-MODULE_PARM_DESC(mem, "ES3210 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)
@@ -429,5 +431,4 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/6pack.c linux-2.5.6/drivers/net/hamradio/6pack.c
--- linux-2.5.6-pre3/drivers/net/hamradio/6pack.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/hamradio/6pack.c	Thu Mar  7 18:24:46 2002
@@ -256,6 +256,7 @@
 	skb->mac.raw = skb->data;
 	skb->protocol = htons(ETH_P_AX25);
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	sp->stats.rx_packets++;
 }
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/baycom_epp.c linux-2.5.6/drivers/net/hamradio/baycom_epp.c
--- linux-2.5.6-pre3/drivers/net/hamradio/baycom_epp.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/net/hamradio/baycom_epp.c	Thu Mar  7 18:24:46 2002
@@ -706,6 +706,7 @@
 	skb->protocol = htons(ETH_P_AX25);
 	skb->mac.raw = skb->data;
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	bc->stats.rx_packets++;
 }
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/bpqether.c linux-2.5.6/drivers/net/hamradio/bpqether.c
--- linux-2.5.6-pre3/drivers/net/hamradio/bpqether.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/net/hamradio/bpqether.c	Thu Mar  7 18:24:46 2002
@@ -254,6 +254,7 @@
 	skb->pkt_type = PACKET_HOST;
 
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 
 	return 0;
 }
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/hdlcdrv.c linux-2.5.6/drivers/net/hamradio/hdlcdrv.c
--- linux-2.5.6-pre3/drivers/net/hamradio/hdlcdrv.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/hamradio/hdlcdrv.c	Thu Mar  7 18:24:46 2002
@@ -223,6 +223,7 @@
 	skb->protocol = htons(ETH_P_AX25);
 	skb->mac.raw = skb->data;
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	s->stats.rx_packets++;
 }
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/mkiss.c linux-2.5.6/drivers/net/hamradio/mkiss.c
--- linux-2.5.6-pre3/drivers/net/hamradio/mkiss.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/drivers/net/hamradio/mkiss.c	Thu Mar  7 18:24:46 2002
@@ -345,6 +345,7 @@
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_AX25);
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	tmp_ax->rx_packets++;
 }
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/scc.c linux-2.5.6/drivers/net/hamradio/scc.c
--- linux-2.5.6-pre3/drivers/net/hamradio/scc.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/drivers/net/hamradio/scc.c	Thu Mar  7 18:24:46 2002
@@ -1661,6 +1661,7 @@
 	skb->pkt_type = PACKET_HOST;
 	
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	return;
 }
 
diff -urN linux-2.5.6-pre3/drivers/net/hamradio/yam.c linux-2.5.6/drivers/net/hamradio/yam.c
--- linux-2.5.6-pre3/drivers/net/hamradio/yam.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/hamradio/yam.c	Thu Mar  7 18:24:46 2002
@@ -528,6 +528,7 @@
 				skb->protocol = htons(ETH_P_AX25);
 				skb->mac.raw = skb->data;
 				netif_rx(skb);
+				dev->last_rx = jiffies;
 				++yp->stats.rx_packets;
 			}
 		}
diff -urN linux-2.5.6-pre3/drivers/net/hp-plus.c linux-2.5.6/drivers/net/hp-plus.c
--- linux-2.5.6-pre3/drivers/net/hp-plus.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/drivers/net/hp-plus.c	Thu Mar  7 18:24:46 2002
@@ -408,8 +408,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HPP_CARDS) "i");
-MODULE_PARM_DESC(io, "HP PC-LAN+ I/O port address(es)");
-MODULE_PARM_DESC(irq, "HP PC-LAN+ IRQ number(s); ignored if properly detected");
+MODULE_PARM_DESC(io, "I/O port address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s); ignored if properly detected");
+MODULE_DESCRIPTION("HP PC-LAN+ ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -457,7 +459,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/hp.c linux-2.5.6/drivers/net/hp.c
--- linux-2.5.6-pre3/drivers/net/hp.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/hp.c	Thu Mar  7 18:24:46 2002
@@ -380,8 +380,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_HP_CARDS) "i");
-MODULE_PARM_DESC(io, "HP PC-LAN I/O base address(es)");
-MODULE_PARM_DESC(irq, "HP PC-LAN IRQ number(s) (assigned)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_DESCRIPTION("HP PC-LAN ISA ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
 ISA device autoprobes on a running machine are not recommended. */
@@ -429,7 +431,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/irda/ali-ircc.c linux-2.5.6/drivers/net/irda/ali-ircc.c
--- linux-2.5.6-pre3/drivers/net/irda/ali-ircc.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/drivers/net/irda/ali-ircc.c	Thu Mar  7 18:24:46 2002
@@ -1941,6 +1941,7 @@
 			skb->mac.raw  = skb->data;
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
+			self->netdev->last_rx = jiffies;
 		}
 	}
 	
diff -urN linux-2.5.6-pre3/drivers/net/irda/irda-usb.c linux-2.5.6/drivers/net/irda/irda-usb.c
--- linux-2.5.6-pre3/drivers/net/irda/irda-usb.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/irda/irda-usb.c	Thu Mar  7 18:24:46 2002
@@ -839,6 +839,7 @@
         new->mac.raw  = new->data;
         new->protocol = htons(ETH_P_IRDA);
         netif_rx(new);
+		self->netdev->last_rx = jiffies;
 
 done:
 	/* Note : at this point, the URB we've just received (urb)
diff -urN linux-2.5.6-pre3/drivers/net/irda/nsc-ircc.c linux-2.5.6/drivers/net/irda/nsc-ircc.c
--- linux-2.5.6-pre3/drivers/net/irda/nsc-ircc.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/net/irda/nsc-ircc.c	Thu Mar  7 18:24:46 2002
@@ -1570,6 +1570,7 @@
 			skb->mac.raw  = skb->data;
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
+			self->netdev->last_rx = jiffies;
 		}
 	}
 	/* Restore bank register */
diff -urN linux-2.5.6-pre3/drivers/net/irda/smc-ircc.c linux-2.5.6/drivers/net/irda/smc-ircc.c
--- linux-2.5.6-pre3/drivers/net/irda/smc-ircc.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/net/irda/smc-ircc.c	Thu Mar  7 18:24:46 2002
@@ -957,6 +957,7 @@
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_IRDA);
 	netif_rx(skb);
+	self->netdev->last_rx = jiffies;
 }
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/irda/toshoboe.c linux-2.5.6/drivers/net/irda/toshoboe.c
--- linux-2.5.6-pre3/drivers/net/irda/toshoboe.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/net/irda/toshoboe.c	Thu Mar  7 18:24:46 2002
@@ -433,8 +433,10 @@
           self->rxs++;
           self->rxs %= RX_SLOTS;
 
-          if (skb)
+          if (skb) {
             netif_rx (skb);
+            self->netdev->last_rx = jiffies;
+          }
 
         }
 
diff -urN linux-2.5.6-pre3/drivers/net/irda/vlsi_ir.c linux-2.5.6/drivers/net/irda/vlsi_ir.c
--- linux-2.5.6-pre3/drivers/net/irda/vlsi_ir.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/irda/vlsi_ir.c	Thu Mar  7 18:24:46 2002
@@ -637,6 +637,7 @@
 				skb->mac.raw = skb->data;
 				skb->protocol = htons(ETH_P_IRDA);
 				netif_rx(skb);				
+				ndev->last_rx = jiffies;
 			}
 			else {
 				idev->stats.rx_dropped++;
diff -urN linux-2.5.6-pre3/drivers/net/irda/w83977af_ir.c linux-2.5.6/drivers/net/irda/w83977af_ir.c
--- linux-2.5.6-pre3/drivers/net/irda/w83977af_ir.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/drivers/net/irda/w83977af_ir.c	Thu Mar  7 18:24:46 2002
@@ -923,6 +923,7 @@
 			skb->mac.raw  = skb->data;
 			skb->protocol = htons(ETH_P_IRDA);
 			netif_rx(skb);
+			self->netdev->last_rx = jiffies;
 		}
 	}
 	/* Restore set register */
diff -urN linux-2.5.6-pre3/drivers/net/lne390.c linux-2.5.6/drivers/net/lne390.c
--- linux-2.5.6-pre3/drivers/net/lne390.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/drivers/net/lne390.c	Thu Mar  7 18:24:46 2002
@@ -381,9 +381,10 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i");
-MODULE_PARM_DESC(io, "LNE390 I/O base address(es)");
-MODULE_PARM_DESC(irq, "LNE390 IRQ number(s)");
-MODULE_PARM_DESC(mem, "LNE390 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
 MODULE_LICENSE("GPL");
 
 int init_module(void)
diff -urN linux-2.5.6-pre3/drivers/net/lp486e.c linux-2.5.6/drivers/net/lp486e.c
--- linux-2.5.6-pre3/drivers/net/lp486e.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/lp486e.c	Thu Mar  7 18:24:46 2002
@@ -676,6 +676,7 @@
 
 		skb->protocol = eth_type_trans(skb,dev);
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
 	} else {
 #if 0
diff -urN linux-2.5.6-pre3/drivers/net/ne.c linux-2.5.6/drivers/net/ne.c
--- linux-2.5.6-pre3/drivers/net/ne.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/net/ne.c	Thu Mar  7 18:24:46 2002
@@ -737,9 +737,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
 MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i");
-MODULE_PARM_DESC(io, "NEx000 I/O base address(es),required");
-MODULE_PARM_DESC(irq, "NEx000 IRQ number(s)");
-MODULE_PARM_DESC(bad, "NEx000 accept bad clone(s)");
+MODULE_PARM_DESC(io, "I/O base address(es),required");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(bad, "Accept card(s) with bad signatures");
+MODULE_DESCRIPTION("NE1000/NE2000 ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
 
 /* This is set up so that no ISA autoprobe takes place. We can't guarantee
 that the ne2k probe is the last 8390 based probe to take place (as it
@@ -791,7 +793,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.5.6-pre3/drivers/net/ne2k-pci.c linux-2.5.6/drivers/net/ne2k-pci.c
--- linux-2.5.6-pre3/drivers/net/ne2k-pci.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/ne2k-pci.c	Thu Mar  7 18:24:46 2002
@@ -82,9 +82,9 @@
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(debug, "PCI NE2000 debug level (1-2)");
-MODULE_PARM_DESC(options, "PCI NE2000: Bit 5: full duplex");
-MODULE_PARM_DESC(full_duplex, "PCI NE2000 full duplex setting(s) (1)");
+MODULE_PARM_DESC(debug, "debug level (1-2)");
+MODULE_PARM_DESC(options, "Bit 5: full duplex");
+MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)");
 
 /* Some defines that people can play with if so inclined. */
 
diff -urN linux-2.5.6-pre3/drivers/net/ne3210.c linux-2.5.6/drivers/net/ne3210.c
--- linux-2.5.6-pre3/drivers/net/ne3210.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/drivers/net/ne3210.c	Thu Mar  7 18:24:46 2002
@@ -370,9 +370,11 @@
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_NE3210_CARDS) "i");
-MODULE_PARM_DESC(io, "NE3210 I/O base address(es)");
-MODULE_PARM_DESC(irq, "NE3210 IRQ number(s)");
-MODULE_PARM_DESC(mem, "NE3210 memory base address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s)");
+MODULE_PARM_DESC(mem, "memory base address(es)");
+MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
+MODULE_LICENSE("GPL");
 
 int init_module(void)
 {
@@ -415,7 +417,6 @@
 		}
 	}
 }
-MODULE_LICENSE("GPL");
 
 #endif /* MODULE */
 
diff -urN linux-2.5.6-pre3/drivers/net/pcmcia/Config.in linux-2.5.6/drivers/net/pcmcia/Config.in
--- linux-2.5.6-pre3/drivers/net/pcmcia/Config.in	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/pcmcia/Config.in	Thu Mar  7 18:24:47 2002
@@ -20,11 +20,6 @@
       dep_tristate '  IBM PCMCIA tokenring adapter support' CONFIG_PCMCIA_IBMTR $CONFIG_TR $CONFIG_PCMCIA
    fi
 
-   if [ "$CONFIG_CARDBUS" = "y" ]; then
-      tristate '  Xircom CardBus support (new driver)' CONFIG_PCMCIA_XIRCOM
-      tristate '  Xircom Tulip-like CardBus support (old driver)' CONFIG_PCMCIA_XIRTULIP
-   fi
-
    bool '  Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
    if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then
       dep_tristate '    Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
diff -urN linux-2.5.6-pre3/drivers/net/pcmcia/Makefile linux-2.5.6/drivers/net/pcmcia/Makefile
--- linux-2.5.6-pre3/drivers/net/pcmcia/Makefile	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/net/pcmcia/Makefile	Thu Mar  7 18:24:47 2002
@@ -29,11 +29,6 @@
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_cs.o
 
-# Cardbus client drivers
-obj-$(CONFIG_PCMCIA_XIRTULIP)	+= xircom_tulip_cb.o
-obj-$(CONFIG_PCMCIA_XIRCOM)	+= xircom_cb.o
-
 obj-$(CONFIG_PCMCIA_IBMTR)	+= ibmtr_cs.o
 
 include $(TOPDIR)/Rules.make
-
diff -urN linux-2.5.6-pre3/drivers/net/pcmcia/xircom_cb.c linux-2.5.6/drivers/net/pcmcia/xircom_cb.c
--- linux-2.5.6-pre3/drivers/net/pcmcia/xircom_cb.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/pcmcia/xircom_cb.c	Wed Dec 31 16:00:00 1969
@@ -1,1411 +0,0 @@
-/*
- * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 
- *
- * This software is Copyright 2001 by the respective authors, and licensed under the GPL
- * License.
- *
- * Written by Arjan van de Ven for Red Hat, Inc.
- * Based on work by Jeff Garzik, Doug Ledford, Donald Becker and Ion Badulescu
- *
- *  	This software may be used and distributed according to the terms
- *      of the GNU General Public License, incorporated herein by reference.
- *
- *
- * 	$Id: xircom_cb.c,v 1.11 2001/06/05 09:50:57 fenrus Exp $
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-
-
-
-#ifdef DEBUG
-#define enter()   printk("Enter: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
-#define leave()   printk("Leave: %s, %s line %i\n",__FUNCTION__,__FILE__,__LINE__)
-#else
-#define enter()   do {} while (0)
-#define leave()   do {} while (0)
-#endif
-
-
-MODULE_DESCRIPTION("Xircom Cardbus ethernet driver");
-MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");
-MODULE_LICENSE("GPL");
-
-
-
-/* IO registers on the card, offsets */
-#define CSR0	0x00
-#define CSR1	0x08
-#define CSR2	0x10
-#define CSR3	0x18
-#define CSR4	0x20
-#define CSR5	0x28
-#define CSR6	0x30
-#define CSR7	0x38
-#define CSR8	0x40
-#define CSR9	0x48
-#define CSR10	0x50
-#define CSR11	0x58
-#define CSR12	0x60
-#define CSR13	0x68
-#define CSR14	0x70
-#define CSR15	0x78
-#define CSR16	0x80
-
-/* PCI registers */
-#define PCI_POWERMGMT 	0x40
-
-/* Offsets of the buffers within the descriptor pages, in bytes */
-
-#define NUMDESCRIPTORS 4
-#define RXTXBUFSIZE 8192
-#define MAX_PACKETSIZE 1536
-
-
-#define DescOwnedCard	0x80000000
-#define DescOwnedDriver	0x00000000
-
-#define PromiscBit		(1<<6)
-#define CollisionBit 		(1<<8)
-#define TxActiveBit		(1<<13)
-#define RxActiveBit		(1<<1)
-#define LastDescBit	 	(1<<25)
-#define LinkStatusBit 		(1<<27)
-
-#define PowerMgmtBits		( (1<<31)|(1<<30) )
-
-static const unsigned int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
-
-/* note: this struct is assumed to be packed as this is the "hardware" layout */
-struct descriptor {
-	u32	status;
-	u32	control;
-	u32	address1;
-	u32	address2;
-};
-
-
-struct xircom_private {
-	/* Send and receive buffers, kernel-addressable and dma addressable forms */
-
-	unsigned char *rx_buffer;
-	unsigned char *tx_buffer;
-	
-	struct descriptor *rx_desc;
-	struct descriptor *tx_desc;
-
-	dma_addr_t rx_dma_handle;
-	dma_addr_t tx_dma_handle;
-
-	struct sk_buff *tx_skb[NUMDESCRIPTORS];
-
-	unsigned long io_port;
-	
-	/* transmit_used is the rotating counter that indicates which transmit
-	   descriptor has to be used next */
-	unsigned int transmit_used;
-
-	/* Spinlock to serialize register operations.
-	   It must be helt while manipulating the following registers:
-	   CSR0, CSR6, CSR7, CSR9, CSR10, CSR15
-	 */
-	spinlock_t lock;
-
-
-	struct pci_dev *pdev;
-	struct net_device *dev;
-	struct net_device_stats stats;
-};
-
-
-/* Function prototypes */
-static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);
-static void xircom_remove(struct pci_dev *pdev);
-static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int xircom_open(struct net_device *dev);
-static int xircom_close(struct net_device *dev);
-static void xircom_up(struct xircom_private *card);
-static struct net_device_stats *xircom_get_stats(struct net_device *dev);
-
-static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
-static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset);
-static void read_mac_address(struct xircom_private *card);
-static void tranceiver_voodoo(struct xircom_private *card);
-static void initialize_card(struct xircom_private *card);
-static inline void trigger_transmit(struct xircom_private *card);
-static inline void trigger_receive(struct xircom_private *card);
-static void setup_descriptors(struct xircom_private *card);
-static inline void remove_descriptors(struct xircom_private *card);
-static inline unsigned int link_status_changed(struct xircom_private *card);
-static void activate_receiver(struct xircom_private *card);
-static void deactivate_receiver(struct xircom_private *card);
-static void activate_transmitter(struct xircom_private *card);
-static void deactivate_transmitter(struct xircom_private *card);
-static void enable_transmit_interrupt(struct xircom_private *card);
-static void enable_receive_interrupt(struct xircom_private *card);
-static void enable_link_interrupt(struct xircom_private *card);
-static void disable_all_interrupts(struct xircom_private *card);
-static inline unsigned int link_status(struct xircom_private *card);
-static int mdio_read(struct xircom_private *card, int phy_id, int location);
-static void mdio_write(struct xircom_private *card, int phy_id, int location, int value);
-
-
-
-static struct pci_device_id xircom_pci_table[] __devinitdata = {
-	{0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},
-	{0,},
-};
-MODULE_DEVICE_TABLE(pci, xircom_pci_table);
-
-static struct pci_driver xircom_ops = {
-	name:		"xircom_cb", 
-	id_table:	xircom_pci_table, 
-	probe:		xircom_probe, 
-	remove:		__devexit_p(xircom_remove), 
-};
-
-
-#ifdef DEBUG
-static void print_binary(unsigned int number)
-{
-	int i,i2;
-	char buffer[64];
-	memset(buffer,0,64);
-	i2=0;
-	for (i=31;i>=0;i--) {
-		if (number & (1<<i))
-			buffer[i2++]='1';
-		else
-			buffer[i2++]='0';
-		if ((i&3)==0) 
-			buffer[i2++]=' ';
-	}
-	printk("%s\n",buffer);
-}
-#endif
-
-/* xircom_probe is the code that gets called on device insertion.
-   it sets up the hardware and registers the device to the networklayer.
-   
-   TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the
-         first two packets that get send, and pump hates that.
-         
- */
-static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct net_device *dev = NULL;
-	struct xircom_private *private;
-	u8 chip_rev;
-	unsigned long flags;
-	u32 tmp32;
-	u16 tmp16;
-	int ret;
-	enter();
-	
-	/* First do the PCI initialisation */
-
-	ret = pci_enable_device(pdev);
-	if (ret)
-		return ret;
-
-	/* disable all powermanagement */
-	pci_read_config_dword(pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(pdev, PCI_POWERMGMT, tmp32);
-	
-	pci_set_master(pdev); 
-
-	/* clear PCI status, if any */ 
-	pci_read_config_word (pdev,PCI_STATUS, &tmp16); 
-	pci_write_config_word (pdev, PCI_STATUS,tmp16);
-	
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
-	
-	if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
-		printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
-		return -ENODEV;
-	}
-
-	
-	dev = init_etherdev(dev, sizeof(*private));
-	if (dev == NULL) {
-		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
-		return -ENODEV;
-	}
-	SET_MODULE_OWNER(dev);
-	private = dev->priv;
-	if (private==NULL) {
-		printk(KERN_ERR "xircom_probe: failed to allocate private device struct\n");
-		return -ENODEV;
-	}
-		
-	/* Allocate the send/receive buffers */
-	private->rx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->rx_dma_handle);
-	if (private->rx_buffer == NULL) {
- 		printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
- 		kfree(private);
-		return -ENODEV;
-	}	
-	/* the descriptors are stored in the first bytes of the rx_buffer, hence the ugly cast */
-	private->rx_desc = (struct descriptor *)private->rx_buffer;
-
-	private->tx_buffer = pci_alloc_consistent(pdev,RXTXBUFSIZE,&private->tx_dma_handle);
-	if (private->tx_buffer == NULL) {
-		printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
-		kfree(private->rx_buffer);
-		kfree(private);
-		return -ENODEV;
-	}
-	/* the descriptors are stored in the first bytes of the tx_buffer, hence the ugly cast */
-	private->tx_desc = (struct descriptor *)private->tx_buffer;
-	
-	
-	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
-
-	private->dev = dev;
-	private->pdev = pdev;
-	private->io_port = pci_resource_start(pdev, 0);
-	private->lock = SPIN_LOCK_UNLOCKED;
-	dev->irq = pdev->irq;
-	dev->base_addr = private->io_port;
-	
-	
-	initialize_card(private);
-	read_mac_address(private);
-	setup_descriptors(private);
-	
-	dev->open = &xircom_open;
-	dev->hard_start_xmit = &xircom_start_xmit;
-	dev->stop = &xircom_close;
-	dev->get_stats = &xircom_get_stats;
-	dev->priv = private;
-	pci_set_drvdata(pdev,dev);
-
-	
-	/* start the transmitter to get a heartbeat; don't do
-	   that when there already is one though; Cisco's 
-	   really don't like that. */
-	if (!link_status(private))
-		tranceiver_voodoo(private);
-	
-	spin_lock_irqsave(&private->lock,flags);
-	  activate_transmitter(private);
-	  activate_receiver(private);
-	spin_unlock_irqrestore(&private->lock,flags);
-
-	/* TODO: send 2 dummy packets here */
-	
-	trigger_receive(private);
-	
-	leave();
-	return 0;
-}
-
-
-/*
- xircom_remove is called on module-unload or on device-eject.
- it unregisters the irq, io-region and network device.
- Interrupts and such are already stopped in the "ifconfig ethX down"
- code.
- */
-static void __devexit xircom_remove(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *card;
-	enter();
-	
-	card=dev->priv;
-
-	if (card->rx_buffer!=NULL)
-		pci_free_consistent(pdev,RXTXBUFSIZE,card->rx_buffer,card->rx_dma_handle);
-	card->rx_buffer = NULL;
-	card->rx_desc = NULL;
-	if (card->tx_buffer!=NULL)
-		pci_free_consistent(pdev,RXTXBUFSIZE,card->tx_buffer,card->tx_dma_handle);
-	card->tx_buffer = NULL;			
-	card->tx_desc = NULL;
-
-	release_region(dev->base_addr, 128);
-	unregister_netdev(dev);
-	kfree(dev);
-	pci_set_drvdata(pdev,NULL);
-	leave();
-} 
-
-static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_instance;
-	struct xircom_private *card = dev->priv;
-	u32 status;
-	unsigned int xmit_free_count;
-	unsigned int i;
-
-	enter();
-
-
-	spin_lock(&card->lock);
-	status = inl(card->io_port+CSR5);
-	if (status==0xffffffff) {/* card has been ejected / powered down */
-		spin_unlock(&card->lock);
-		return;
-	}
-
-	/* Todo: check if there were any events at all; to speed up
-	   returning if we're on a shared interrupt */	
-
-	if (link_status_changed(card)) {
-		int newlink;
-		printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
-		newlink = link_status(card);
-		if (newlink) {
-			printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
-			netif_carrier_on(dev);
-		} else {
-			printk(KERN_INFO  "xircom_cb: Link is absent \n");
-			netif_carrier_off(dev);
-		}
-	}
-
-	/* Clear all remaining interrupt events */	
-	status |= 0xffffffff; /* FIXME: make this clear only the
-				        real existing bits */
-	outl(status,card->io_port+CSR5);
-	
-	xmit_free_count = 0;
-
-	for (i=0;i<NUMDESCRIPTORS;i++) 
-		xmit_free_count += investigate_tx_descriptor(dev,card,i,bufferoffsets[i]);
-	for (i=0;i<NUMDESCRIPTORS;i++) 
-		investigate_rx_descriptor(dev,card,i,bufferoffsets[i]);
-
-	
-	if (xmit_free_count)
-		netif_start_queue(dev);
-		
-	spin_unlock(&card->lock);
-	leave();
-}
-
-static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct xircom_private *card;
-	unsigned long flags;
-	unsigned int nextdescriptor;
-	unsigned int desc;
-	enter();
-	
-	card = (struct xircom_private*)dev->priv;
-
-	spin_lock_irqsave(&card->lock,flags);
-	
-	nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS);
-	desc = card->transmit_used;
-	
-	/* only send the packet if the descriptor is free */
-	if (card->tx_desc[desc].status==0) {
-			/* Copy the packet data; zero the memory first as the card
-			   sometimes sends more than you ask it to. */
-			
-			memset(&card->tx_buffer[bufferoffsets[desc]],0,MAX_PACKETSIZE);
-			memcpy(&(card->tx_buffer[bufferoffsets[desc]]),skb->data,skb->len);
-	
-	
-			/* FIXME: The specification tells us that the length we send HAS to be a multiple of
-			   4 bytes. */
-			   
-			card->tx_desc[desc].control = skb->len;
-			if (desc == NUMDESCRIPTORS-1)
-				card->tx_desc[desc].control |= LastDescBit;  /* bit 25: last descriptor of the ring */
-
-			card->tx_desc[desc].control |= 0xF0000000;
-						 /* 0xF0... means want interrupts*/ 
-			card->tx_skb[desc] = skb;
-			
-			wmb();
-			/* This gives the descriptor to the card */
-			card->tx_desc[desc].status = DescOwnedCard;
-			trigger_transmit(card);
-			if (((int)card->tx_desc[nextdescriptor].status)<0) {	/* next descriptor is occupied... */
-				netif_stop_queue(dev);
-			}
-			card->transmit_used = nextdescriptor;
-			spin_unlock_irqrestore(&card->lock,flags);
-			leave();
-			return 0;
-	}
-	
-
-
-	/* Uh oh... no free descriptor... drop the packet */
-	/* This should not happen in theory...*/
-	netif_stop_queue(dev);
-	spin_unlock_irqrestore(&card->lock,flags);
-	trigger_transmit(card);
-	leave();
-	
-	return -EIO;
-}
-
-
-
-
-static int xircom_open(struct net_device *dev)
-{
-	struct xircom_private *xp = (struct xircom_private *) dev->priv;
-	int retval;
-	enter();
-	printk(KERN_INFO "Xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
-	retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev);
-	if (retval) {
-		printk(KERN_ERR "xircom_cb: Unable to aquire IRQ %i, aborting.\n",dev->irq);
-		leave();
-		return retval;
-	}
-	
-	xircom_up(xp);
-	leave();
-	return 0;
-}
-
-static int xircom_close(struct net_device *dev)
-{
-	struct xircom_private *card;
-	unsigned long flags;
-	
-	enter();
-	card = dev->priv;
-	netif_stop_queue(dev); /* we don't want to send new packets */
-
-	
-	spin_lock_irqsave(&card->lock,flags);
-	
-	disable_all_interrupts(card);
-#if 0	
-	/* We can enable this again once we send dummy packets on ifconfig ethX up */
-	deactivate_receiver(card);
-	deactivate_transmitter(card);
-#endif	
-	remove_descriptors(card);
-	
-	spin_unlock_irqrestore(&card->lock,flags);
-	
-	free_irq(dev->irq,dev);
-	
-	leave();
-		
-	return 0;
-	
-}
-
-
-
-static struct net_device_stats *xircom_get_stats(struct net_device *dev)
-{
-        struct xircom_private *card = (struct xircom_private *)dev->priv;
-        return &card->stats;
-} 
-                                                 
-
-
-
-static void initialize_card(struct xircom_private *card)
-{
-	unsigned int val;
-	unsigned long flags;
-	enter();
-
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	/* First: reset the card */
-	val = inl(card->io_port + CSR0);
-	val |= 0x01;		/* Software reset */
-	outl(val, card->io_port + CSR0);
-
-	udelay(100);		/* give the card some time to reset */
-
-	val = inl(card->io_port + CSR0);
-	val &= ~0x01;		/* disable Software reset */
-	outl(val, card->io_port + CSR0);
-
-
-	val = 0;		/* Value 0x00 is a safe and conservative value 
-				   for the PCI configuration settings */
-	outl(val, card->io_port + CSR0);
-
-
-	disable_all_interrupts(card);
-	deactivate_receiver(card);
-	deactivate_transmitter(card);
-
-	spin_unlock_irqrestore(&card->lock, flags);
-
-	leave();
-}
-
-/*
-trigger_transmit causes the card to check for frames to be transmitted.
-This is accomplished by writing to the CSR1 port. The documentation
-claims that the act of writing is sufficient and that the value is
-ignored; I chose zero.
-*/
-static inline void trigger_transmit(struct xircom_private *card)
-{
-	enter();
-	outl(0, card->io_port + CSR1);
-	leave();
-}
-
-/*
-trigger_receive causes the card to check for empty frames in the
-descriptor list in which packets can be received.
-This is accomplished by writing to the CSR2 port. The documentation
-claims that the act of writing is sufficient and that the value is
-ignored; I chose zero.
-*/
-static inline void trigger_receive(struct xircom_private *card)
-{
-	enter();
-	outl(0, card->io_port + CSR2);
-	leave();
-}
-
-/*
-setup_descriptors initializes the send and receive buffers to be valid
-descriptors and programs the addresses into the card.
-*/
-static void setup_descriptors(struct xircom_private *card)
-{
-	unsigned int val;
-	u32 address;
-	unsigned int i;
-	enter();
-
-
-	if (card->rx_buffer == NULL)
-		BUG();
-	if (card->tx_buffer == NULL)
-		BUG();
-
-	/* Receive descriptors */
-	memset(card->rx_desc, 0, 128);	/* clear the descriptors */
-	for (i=0;i<NUMDESCRIPTORS;i++ ) {
-
-		/* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */
-		card->rx_desc[i].status = DescOwnedCard;
-		/* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-		card->rx_desc[i].control = MAX_PACKETSIZE;
-		if (i==NUMDESCRIPTORS-1)
-			card->rx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
-
-		/* Rx Descr2: address of the buffer
-		   we store the buffer at the 2nd half of the page */
-	
-		address = card->rx_dma_handle;
-		
-		card->rx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
-		/* Rx Desc3: address of 2nd buffer -> 0 */
-		card->rx_desc[i].address2 = 0;
-	}
-	
-	wmb();
-	/* Write the receive descriptor ring address to the card */
-	address = card->rx_dma_handle;
-	val = cpu_to_le32(address); 
-	outl(val, card->io_port + CSR3);	/* Receive descr list address */
-
-
-	/* transmit descriptors */
-	memset(card->tx_desc, 0, 128);	/* clear the descriptors */
-	
-	for (i=0;i<NUMDESCRIPTORS;i++ ) {
-		/* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
-		card->tx_desc[i].status = DescOwnedDriver;
-		/* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
-		card->tx_desc[i].control = MAX_PACKETSIZE;
-		if (i==NUMDESCRIPTORS-1)
-			card->tx_desc[i].control |= LastDescBit; /* bit 25 is "last descriptor" */
-		
-		/* Tx Descr2: address of the buffer
-		   we store the buffer at the 2nd half of the page */
-		address = card->tx_dma_handle;
-		card->tx_desc[i].address1 = cpu_to_le32(address + bufferoffsets[i]);
-		/* Tx Desc3: address of 2nd buffer -> 0 */
-		card->tx_desc[i].address2 = 0;
-	}
-
-	wmb();
-	/* wite the transmit descriptor ring to the card */
-	address = card->tx_dma_handle;
-	val =cpu_to_le32(address);
-	outl(val, card->io_port + CSR4);	/* xmit descr list address */
-
-	leave();
-}
-
-/*
-remove_descriptors informs the card the descriptors are no longer
-valid by setting the address in the card to 0x00.
-*/
-static inline void remove_descriptors(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = 0;
-	outl(val, card->io_port + CSR3);	/* Receive descriptor address */
-	outl(val, card->io_port + CSR4);	/* Send descriptor address */
-
-	leave();
-}
-
-/*
-link_status_changed returns 1 if the card has indicated that
-the link status has changed. The new link status has to be read from CSR12.
-
-This function also clears the status-bit.
-*/
-static inline unsigned int link_status_changed(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR5);	/* Status register */
-
-	if ((val & LinkStatusBit) == 0) {	/* no change */
-		leave();
-		return 0;
-	}
-
-	/* clear the event by writing a 1 to the bit in the
-	   status register. */
-	val = LinkStatusBit;
-	outl(val, card->io_port + CSR5);
-
-	leave();
-	return 1;
-}
-
-
-/*
-transmit_active returns 1 if the transmitter on the card is
-in a non-stopped state.
-*/
-static inline int transmit_active(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR5);	/* Status register */
-
-	if ((val & (7 << 20)) == 0) {	/* transmitter disabled */
-		leave();
-		return 0;
-	}
-
-	leave();
-	return 1;
-}
-
-/*
-receive_active returns 1 if the receiver on the card is
-in a non-stopped state.
-*/
-static inline unsigned int receive_active(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-
-	val = inl(card->io_port + CSR5);	/* Status register */
-
-	if ((val & (7 << 17)) == 0) {	/* receiver disabled */
-		leave();
-		return 0;
-	}
-
-	leave();
-	return 1;
-}
-
-/*
-activate_receiver enables the receiver on the card.
-Before being allowed to active the receiver, the receiver
-must be completely de-activated. To achieve this,
-this code actually disables the receiver first; then it waits for the 
-receiver to become inactive, then it activates the receiver and then
-it waits for the receiver to be active.
-
-must be called with the lock held and interrupts disabled.
-*/
-static void activate_receiver(struct xircom_private *card)
-{
-	unsigned int val;
-	int counter;
-	enter();
-
-
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-	
-	/* If the "active" bit (1) is set and the receiver is already
-	   active, no need to do the expensive thing */
-	if ((val& RxActiveBit) && (receive_active(card)))
-		return;
-	
-	
-	val = val & ~RxActiveBit;		/* disable the receiver */
-	outl(val, card->io_port + CSR6);
-
-	counter = 10;
-	while (counter > 0) {
-		if (!receive_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
-	}
-
-	/* enable the receiver */
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val | RxActiveBit;		/* enable the receiver */
-	outl(val, card->io_port + CSR6);
-
-	/* now wait for the card to activate again */
-	counter = 10;
-	while (counter > 0) {
-		if (receive_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
-	}
-
-	leave();
-}
-
-/*
-deactivate_receiver disables the receiver on the card.
-To achieve this this code disables the receiver first; 
-then it waits for the receiver to become inactive.
-
-must be called with the lock held and interrupts disabled.
-*/
-static void deactivate_receiver(struct xircom_private *card)
-{
-	unsigned int val;
-	int counter;
-	enter();
-
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val & ~RxActiveBit;		/* disable the receiver */
-	outl(val, card->io_port + CSR6);
-
-	counter = 10;
-	while (counter > 0) {
-		if (!receive_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
-	}
-
-
-	leave();
-}
-
-
-/*
-activate_transmitter enables the transmitter on the card.
-Before being allowed to active the transmitter, the transmitter
-must be completely de-activated. To achieve this,
-this code actually disables the transmitter first; then it waits for the 
-transmitter to become inactive, then it activates the transmitter and then
-it waits for the transmitter to be active again.
-
-must be called with the lock held and interrupts disabled.
-*/
-static void activate_transmitter(struct xircom_private *card)
-{
-	unsigned int val;
-	int counter;
-	enter();
-
-
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-
-	/* If the "active" bit (13) is set and the receiver is already
-	   active, no need to do the expensive thing */	 
-	if ((val & TxActiveBit) && (transmit_active(card)))
-		return;
-
-	val = val & ~TxActiveBit;	/* disable the transmitter */
-	outl(val, card->io_port + CSR6);
-
-	counter = 10;
-	while (counter > 0) {
-		if (!transmit_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
-	}
-
-	/* enable the transmitter */
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val | TxActiveBit;	/* enable the transmitter */
-	outl(val, card->io_port + CSR6);
-
-	/* now wait for the card to activate again */
-	counter = 10;
-	while (counter > 0) {
-		if (transmit_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
-	}
-
-	leave();
-}
-
-/*
-deactivate_transmitter disables the transmitter on the card.
-To achieve this this code disables the transmitter first; 
-then it waits for the transmitter to become inactive.
-
-must be called with the lock held and interrupts disabled.
-*/
-static void deactivate_transmitter(struct xircom_private *card)
-{
-	unsigned int val;
-	int counter;
-	enter();
-
-	val = inl(card->io_port + CSR6);	/* Operation mode */
-	val = val & ~TxActiveBit;		/* disable the transmitter */
-	outl(val, card->io_port + CSR6);
-
-	counter = 20;
-	while (counter > 0) {
-		if (!transmit_active(card))
-			break;
-		/* wait a while */
-		udelay(50);
-		counter--;
-		if (counter <= 0)
-			printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
-	}
-
-
-	leave();
-}
-
-
-/*
-enable_transmit_interrupt enables the transmit interrupt
-
-must be called with the lock held and interrupts disabled.
-*/
-static void enable_transmit_interrupt(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
-	val |= 1;				/* enable the transmit interrupt */
-	outl(val, card->io_port + CSR7);
-
-	leave();
-}
-
-
-/*
-enable_receive_interrupt enables the receive interrupt
-
-must be called with the lock held and interrupts disabled.
-*/
-static void enable_receive_interrupt(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
-	val = val | (1 << 6);			/* enable the receive interrupt */
-	outl(val, card->io_port + CSR7);
-
-	leave();
-}
-
-/*
-enable_link_interrupt enables the link status change interrupt
-
-must be called with the lock held and interrupts disabled.
-*/
-static void enable_link_interrupt(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
-	val = val | LinkStatusBit;			/* enable the link status chage interrupt */
-	outl(val, card->io_port + CSR7);
-
-	leave();
-}
-
-
-
-/*
-disable_all_interrupts disables all interrupts
-
-must be called with the lock held and interrupts disabled.
-*/
-static void disable_all_interrupts(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-	
-	val = 0;				/* disable all interrupts */
-	outl(val, card->io_port + CSR7);
-
-	leave();
-}
-
-/*
-enable_common_interrupts enables several weird interrupts
-
-must be called with the lock held and interrupts disabled.
-*/
-static void enable_common_interrupts(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
-	val |= (1<<16); /* Normal Interrupt Summary */
-	val |= (1<<15); /* Abnormal Interrupt Summary */
-	val |= (1<<13); /* Fatal bus error */
-	val |= (1<<8);  /* Receive Process Stopped */
-	val |= (1<<7);  /* Receive Buffer Unavailable */
-	val |= (1<<5);  /* Transmit Underflow */
-	val |= (1<<2);  /* Transmit Buffer Unavailable */
-	val |= (1<<1);  /* Transmit Process Stopped */
-	outl(val, card->io_port + CSR7);
-
-	leave();
-}
-
-/*
-enable_promisc starts promisc mode
-
-must be called with the lock held and interrupts disabled.
-*/
-static inline void enable_promisc(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-
-	val = inl(card->io_port + CSR6);	
-	val = val | PromiscBit;	 /* Bit 6 */
-	outl(val, card->io_port + CSR6);
-
-	printk(KERN_INFO "xircom_cb: enabling promiscuous mode \n");
-	leave();
-}
-
-
-
-
-/* 
-link_status() checks the the links status and will return 0 for no link, 
-10 for 10mbit link and 100 for.. guess what.
-
-Must be called in locked state with interrupts disabled
-*/
-static inline unsigned int link_status(struct xircom_private *card)
-{
-	unsigned int val;
-	enter();
-	
-	val = inb(card->io_port + CSR12);
-	
-	if (!(val&(1<<2)))  /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */
-		return 10;
-	if (!(val&(1<<1)))  /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */
-		return 100;
-		
-	/* If we get here -> no link at all */	
-
-	leave();
-	return 0;
-}
-
-
-
-/* 
-
-set_half_duplex() sets the card to half duplex mode. In order to do this,
-set_half_duplex() has to deactivate the transmitter and receiver first. It
-will re-enable the transmitter and receiver if those were active from the
-beginning.
-
-Update: the above is not enough. It doesn't touch the MII, in fact it ensures
-the main chipset and the MII are never in sync if a full-duplex connection
-is negotiated. The proper fix is to tell the MII to force a half-duplex
-connection. -Ion
-
-Must be called in locked state
-*/
-static void set_half_duplex(struct xircom_private *card)
-{
-	unsigned int val;
-	int rx,tx,tmp;
-	enter();
-	
-	rx=receive_active(card);
-	tx=transmit_active(card);
-	
-	deactivate_transmitter(card);
-	deactivate_receiver(card);
-	
-	val = inb(card->io_port + CSR6);
-	val &= ~(1<<9);
-	outb(val,card->io_port + CSR6);
-
-	/* tell the MII not to advertise 10/100FDX */
-	tmp = mdio_read(card, 0, 4);
-	printk("xircom_cb: capabilities changed from %#x to %#x\n",
-	       tmp, tmp & ~0x140);
-	tmp &= ~0x140;
-	mdio_write(card, 0, 4, tmp);
-	/* restart autonegotiation */
-	tmp = mdio_read(card, 0, 0);
-	mdio_write(card, 0, 0, tmp | 0x1200);
-
-	if (rx)
-		activate_receiver(card);
-	if (tx)
-		activate_transmitter(card);	
-
-	leave();
-}
-
-
-/*
-  read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure.
- 
-  This function will take the spinlock itself and can, as a result, not be called with the lock helt.
- */
-static void read_mac_address(struct xircom_private *card)
-{
-	unsigned char j, tuple, link, data_id, data_count;
-	unsigned long flags;
-	int i;
-
-	enter();
-		
-	spin_lock_irqsave(&card->lock, flags);
-
-	outl(1 << 12, card->io_port + CSR9);	/* enable boot rom access */
-	for (i = 0x100; i < 0x1f7; i += link + 2) {
-		outl(i, card->io_port + CSR10);
-		tuple = inl(card->io_port + CSR9) & 0xff;
-		outl(i + 1, card->io_port + CSR10);
-		link = inl(card->io_port + CSR9) & 0xff;
-		outl(i + 2, card->io_port + CSR10);
-		data_id = inl(card->io_port + CSR9) & 0xff;
-		outl(i + 3, card->io_port + CSR10);
-		data_count = inl(card->io_port + CSR9) & 0xff;
-		if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) {
-			/* 
-			 * This is it.  We have the data we want.
-			 */
-			for (j = 0; j < 6; j++) {
-				outl(i + j + 4, card->io_port + CSR10);
-				card->dev->dev_addr[j] = inl(card->io_port + CSR9) & 0xff;
-			}
-			break;
-		} else if (link == 0) {
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&card->lock, flags);
-#ifdef DEBUG
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
-	printk("\n");
-#endif
-	leave();
-}
-
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
-
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues or future 66Mhz PCI. */
-#define mdio_delay() inl(mdio_addr)
-
-/* Read and write the MII registers using software-generated serial
-   MDIO protocol.  It is just different enough from the EEPROM protocol
-   to not share code.  The maxium data clock rate is 2.5 Mhz. */
-#define MDIO_SHIFT_CLK	0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB	0x00000		/* Ignore the 0x02000 databook setting. */
-#define MDIO_ENB_IN	0x40000
-#define MDIO_DATA_READ	0x80000
-
-static int mdio_read(struct xircom_private *card, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int retval = 0;
-	long mdio_addr = card->io_port + CSR9;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct xircom_private *card, int phy_id, int location, int value)
-{
-	int i;
-	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	long mdio_addr = card->io_port + CSR9;
-
-	/* Establish sync by sending 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-}
-
-
-/*
- tranceiver_voodoo() enables the external UTP plug thingy.
- it's called voodoo as I stole this code and cannot cross-reference
- it with the specification.
- */
-static void tranceiver_voodoo(struct xircom_private *card)
-{
-	unsigned long flags;
-	u32 tmp32;
-
-	enter();
-
-	/* disable all powermanagement */
-	pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
-
-	setup_descriptors(card);
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	outl(0x0008, card->io_port + CSR15);
-        udelay(25);  
-        outl(0xa8050000, card->io_port + CSR15);
-        udelay(25);
-        outl(0xa00f0000, card->io_port + CSR15);
-        udelay(25);
-        
-        spin_unlock_irqrestore(&card->lock, flags);
-
-	netif_start_queue(card->dev);
-	leave();
-}
-
-
-static void xircom_up(struct xircom_private *card)
-{
-	unsigned long flags;
-	int i;
-	u32 tmp32;
-
-	enter();
-
-	/* disable all powermanagement */
-	pci_read_config_dword(card->pdev, PCI_POWERMGMT,&tmp32);
-	tmp32 &= ~PowerMgmtBits; 
-	pci_write_config_dword(card->pdev, PCI_POWERMGMT, tmp32);
-
-	setup_descriptors(card);
-
-	spin_lock_irqsave(&card->lock, flags);
-
-	
-	enable_link_interrupt(card);
-	enable_transmit_interrupt(card);
-	enable_receive_interrupt(card);
-	enable_common_interrupts(card);
-	enable_promisc(card);
-	
-	/* The card can have received packets already, read them away now */
-	for (i=0;i<NUMDESCRIPTORS;i++) 
-		investigate_rx_descriptor(card->dev,card,i,bufferoffsets[i]);
-
-
-	set_half_duplex(card);
-	spin_unlock_irqrestore(&card->lock, flags);
-	trigger_receive(card);
-	trigger_transmit(card);
-	netif_start_queue(card->dev);
-	leave();
-}
-
-static void investigate_rx_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
-{
-		int status;		
-		
-		enter();
-		status = card->rx_desc[descnr].status;
-		
-		if ((status > 0)) {	/* packet received */
-		
-			/* TODO: discard error packets */
-			
-			short pkt_len = ((status >> 16) & 0x7ff) - 4;	/* minus 4, we don't want the CRC */
-			struct sk_buff *skb;
-
-			if (pkt_len > 1518) {
-				printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len);
-				pkt_len = 1518;
-			}
-
-			skb = dev_alloc_skb(pkt_len + 2);
-			if (skb == NULL) {
-				card->stats.rx_dropped++;
-				goto out;
-			}
-			skb->dev = dev;
-			skb_reserve(skb, 2);
-			eth_copy_and_sum(skb, &card->rx_buffer[bufferoffset], pkt_len, 0);
-			skb_put(skb, pkt_len);
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			card->stats.rx_packets++;
-			card->stats.rx_bytes += pkt_len;
-			
-		      out:
-			/* give the buffer back to the card */
-			card->rx_desc[descnr].status = DescOwnedCard;
-			trigger_receive(card);
-		}
-
-		leave();
-
-}
-
-
-/* Returns 1 if the descriptor is free or became free */
-static unsigned int investigate_tx_descriptor(struct net_device *dev, struct xircom_private *card, unsigned int descnr, unsigned int bufferoffset)
-{
-		int status,retval = 0;
-		enter();
-		
-		status = card->tx_desc[descnr].status;
-		
-		if (status == DescOwnedDriver)
-			return 1;
-#if 0		
-		if (status & 0x8000) {	/* Major error */
-			printk(KERN_ERR "Major transmit error status %x \n", status);
-			card->tx_desc[descnr].status = 0;
-			netif_wake_queue (dev);
-		}
-#endif
-		if (status > 0) {	/* bit 31 is 0 when done */
-			card->stats.tx_packets++;
-			if (card->tx_skb[descnr]!=NULL) {
-				card->stats.tx_bytes += card->tx_skb[descnr]->len;
-				dev_kfree_skb_irq(card->tx_skb[descnr]);
-			}
-			card->tx_skb[descnr] = NULL;
-			/* Bit 8 in the status field is 1 if there was a collision */
-			if (status & CollisionBit)
-				card->stats.collisions++;
-			card->tx_desc[descnr].status = DescOwnedDriver; /* descriptor is free again */
-			retval = 1;
-		}
-
-		leave();
-		return retval;		
-}
-
-
-static int __init xircom_init(void)
-{
-	pci_register_driver(&xircom_ops);
-	return 0;
-}
-
-static void __exit xircom_exit(void)
-{
-	pci_unregister_driver(&xircom_ops);
-} 
-
-module_init(xircom_init) 
-module_exit(xircom_exit)
diff -urN linux-2.5.6-pre3/drivers/net/pcmcia/xircom_tulip_cb.c linux-2.5.6/drivers/net/pcmcia/xircom_tulip_cb.c
--- linux-2.5.6-pre3/drivers/net/pcmcia/xircom_tulip_cb.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/pcmcia/xircom_tulip_cb.c	Wed Dec 31 16:00:00 1969
@@ -1,1744 +0,0 @@
-/* xircom_tulip_cb.c: A Xircom CBE-100 ethernet driver for Linux. */
-/*
-	Written/copyright 1994-1999 by Donald Becker.
-
-	This software may be used and distributed according to the terms
-	of the GNU General Public License, incorporated herein by reference.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	-----------------------------------------------------------
-
-	Linux kernel-specific changes:
-
-	LK1.0 (Ion Badulescu)
-	- Major cleanup
-	- Use 2.4 PCI API
-	- Support ethtool
-	- Rewrite perfect filter/hash code
-	- Use interrupts for media changes
-
-	LK1.1 (Ion Badulescu)
-	- Disallow negotiation of unsupported full-duplex modes
-*/
-
-#define DRV_NAME	"xircom_tulip_cb"
-#define DRV_VERSION	"0.91+LK1.1"
-#define DRV_RELDATE	"October 11, 2001"
-
-#define CARDBUS 1
-
-/* A few user-configurable values. */
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 25;
-
-#define MAX_UNITS 4
-/* Used to pass the full-duplex flag, etc. */
-static int full_duplex[MAX_UNITS];
-static int options[MAX_UNITS];
-static int mtu[MAX_UNITS];			/* Jumbo MTU for interfaces. */
-
-/* Keep the ring sizes a power of two for efficiency.
-   Making the Tx ring too large decreases the effectiveness of channel
-   bonding and packet priority.
-   There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	16
-#define RX_RING_SIZE	32
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
-#ifdef __alpha__
-static int rx_copybreak = 1518;
-#else
-static int rx_copybreak = 100;
-#endif
-
-/*
-  Set the bus performance register.
-	Typical: Set 16 longword cache alignment, no burst limit.
-	Cache alignment bits 15:14	     Burst length 13:8
-		0000	No alignment  0x00000000 unlimited		0800 8 longwords
-		4000	8  longwords		0100 1 longword		1000 16 longwords
-		8000	16 longwords		0200 2 longwords	2000 32 longwords
-		C000	32  longwords		0400 4 longwords
-	Warning: many older 486 systems are broken and require setting 0x00A04800
-	   8 longword cache alignment, 8 longword burst.
-	ToDo: Non-Intel setting could be better.
-*/
-
-#if defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
-static int csr0 = 0x01A00000 | 0xE000;
-#elif defined(__powerpc__)
-static int csr0 = 0x01B00000 | 0x8000;
-#elif defined(__sparc__)
-static int csr0 = 0x01B00080 | 0x8000;
-#elif defined(__i386__)
-static int csr0 = 0x01A00000 | 0x8000;
-#else
-#warning Processor architecture undefined!
-static int csr0 = 0x00A00000 | 0x4800;
-#endif
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT		(4 * HZ)
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
-#define PKT_SETUP_SZ		192			/* Size of the setup frame */
-
-/* PCI registers */
-#define PCI_POWERMGMT 	0x40
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/crc32.h>
-
-#include <asm/io.h>
-#include <asm/processor.h>	/* Processor type for cache alignment. */
-#include <asm/uaccess.h>
-
-
-/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c derived from tulip.c:v0.91 4/14/99 becker@scyld.com\n"
-KERN_INFO " unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("Xircom CBE-100 ethernet driver");
-MODULE_LICENSE("GPL v2");
-
-MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(csr0, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-
-#define RUN_AT(x) (jiffies + (x))
-
-#define xircom_debug debug
-#ifdef XIRCOM_DEBUG
-static int xircom_debug = XIRCOM_DEBUG;
-#else
-static int xircom_debug = 1;
-#endif
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This device driver was forked from the driver for the DECchip "Tulip",
-Digital's single-chip ethernet controllers for PCI.  It supports Xircom's
-almost-Tulip-compatible CBE-100 CardBus adapters.
-
-II. Board-specific settings
-
-PCI bus devices are configured by the system at boot time, so no jumpers
-need to be set on the board.  The system BIOS preferably should assign the
-PCI INTA signal to an otherwise unused system IRQ line.
-
-III. Driver operation
-
-IIIa. Ring buffers
-
-The Xircom can use either ring buffers or lists of Tx and Rx descriptors.
-This driver uses statically allocated rings of Rx and Tx descriptors, set at
-compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
-for the Rx ring buffers at open() time and passes the skb->data field to the
-Xircom as receive data buffers.  When an incoming frame is less than
-RX_COPYBREAK bytes long, 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 and replaced by a newly allocated
-skbuff.
-
-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
-frames.  For small frames the copying cost is negligible (esp. considering
-that we are pre-loading the cache with immediately useful header
-information).  For large frames the copying cost is non-trivial, and the
-larger copy might flush the cache of useful data.  A subtle aspect of this
-choice is that the Xircom only receives into longword aligned buffers, thus
-the IP header at offset 14 isn't longword aligned for further processing.
-Copied frames are put into the new skbuff at an offset of "+2", thus copying
-has the beneficial effect of aligning the IP header and preloading the
-cache.
-
-IIIC. Synchronization
-The driver runs as two independent, single-threaded flows of control.  One
-is the send-packet routine, which enforces single-threaded use by the
-dev->tbusy flag.  The other thread is the interrupt handler, which is single
-threaded by the hardware and other software.
-
-The send packet thread has partial control over the Tx ring and 'dev->tbusy'
-flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
-queue slot is empty, it clears the tbusy flag when finished otherwise it sets
-the 'tp->tx_full' flag.
-
-The interrupt handler has exclusive control over the Rx ring and records stats
-from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
-we can't avoid the interrupt overhead by having the Tx routine reap the Tx
-stats.)	 After reaping the stats, it marks the queue entry as empty by setting
-the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
-tx_full and tbusy flags.
-
-IV. Notes
-
-IVb. References
-
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
-http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
-http://www.national.com/pf/DP/DP83840A.html
-
-IVc. Errata
-
-*/
-
-/* A full-duplex map for media types. */
-enum MediaIs {
-	MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
-	MediaIs100=16};
-static const char media_cap[] =
-{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
-
-/* Offsets to the Command and Status Registers, "CSRs".  All accesses
-   must be longword instructions and quadword aligned. */
-enum xircom_offsets {
-	CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
-	CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
-	CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x04, };
-
-/* The bits in the CSR5 status registers, mostly interrupt sources. */
-enum status_bits {
-	LinkChange=0x08000000,
-	NormalIntr=0x10000, NormalIntrMask=0x00014045,
-	AbnormalIntr=0x8000, AbnormalIntrMask=0x0a00a5a2,
-	ReservedIntrMask=0xe0001a18,
-	EarlyRxIntr=0x4000, BusErrorIntr=0x2000,
-	EarlyTxIntr=0x400, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
-	TxFIFOUnderflow=0x20, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
-};
-
-enum csr0_control_bits {
-	EnableMWI=0x01000000, EnableMRL=0x00800000,
-	EnableMRM=0x00200000, EqualBusPrio=0x02,
-	SoftwareReset=0x01,
-};
-
-enum csr6_control_bits {
-	ReceiveAllBit=0x40000000, AllMultiBit=0x80, PromiscBit=0x40,
-	HashFilterBit=0x01, FullDuplexBit=0x0200,
-	TxThresh10=0x400000, TxStoreForw=0x200000,
-	TxThreshMask=0xc000, TxThreshShift=14,
-	EnableTx=0x2000, EnableRx=0x02,
-	ReservedZeroMask=0x8d930134, ReservedOneMask=0x320c0000,
-	EnableTxRx=(EnableTx | EnableRx),
-};
-
-
-enum tbl_flag {
-	HAS_MII=1, HAS_ACPI=2,
-};
-static struct xircom_chip_table {
-	char *chip_name;
-	int valid_intrs;			/* CSR7 interrupt enable settings */
-	int flags;
-} xircom_tbl[] = {
-  { "Xircom Cardbus Adapter",
-	LinkChange | NormalIntr | AbnormalIntr | BusErrorIntr |
-	RxDied | RxNoBuf | RxIntr | TxFIFOUnderflow | TxNoBuf | TxDied | TxIntr,
-	HAS_MII | HAS_ACPI, },
-  { NULL, },
-};
-/* This matches the table above. */
-enum chips {
-	X3201_3,
-};
-
-
-/* The Xircom Rx and Tx buffer descriptors. */
-struct xircom_rx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1, buffer2;
-};
-
-struct xircom_tx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1, buffer2;				/* We use only buffer 1.  */
-};
-
-enum tx_desc0_status_bits {
-	Tx0DescOwned=0x80000000, Tx0DescError=0x8000, Tx0NoCarrier=0x0800,
-	Tx0LateColl=0x0200, Tx0ManyColl=0x0100, Tx0Underflow=0x02,
-};
-enum tx_desc1_status_bits {
-	Tx1ComplIntr=0x80000000, Tx1LastSeg=0x40000000, Tx1FirstSeg=0x20000000,
-	Tx1SetupPkt=0x08000000, Tx1DisableCRC=0x04000000, Tx1RingWrap=0x02000000,
-	Tx1ChainDesc=0x01000000, Tx1NoPad=0x800000, Tx1HashSetup=0x400000,
-	Tx1WholePkt=(Tx1FirstSeg | Tx1LastSeg),
-};
-enum rx_desc0_status_bits {
-	Rx0DescOwned=0x80000000, Rx0DescError=0x8000, Rx0NoSpace=0x4000,
-	Rx0Runt=0x0800, Rx0McastPkt=0x0400, Rx0FirstSeg=0x0200, Rx0LastSeg=0x0100,
-	Rx0HugeFrame=0x80, Rx0CRCError=0x02,
-	Rx0WholePkt=(Rx0FirstSeg | Rx0LastSeg),
-};
-enum rx_desc1_status_bits {
-	Rx1RingWrap=0x02000000, Rx1ChainDesc=0x01000000,
-};
-
-struct xircom_private {
-	struct xircom_rx_desc rx_ring[RX_RING_SIZE];
-	struct xircom_tx_desc tx_ring[TX_RING_SIZE];
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
-	/* The X3201-3 requires 4-byte aligned tx bufs */
-	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
-	/* The addresses of receive-in-place skbuffs. */
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)];	/* Pseudo-Tx frame to init address table. */
-	int chip_id;
-	struct net_device_stats stats;
-	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int speed100:1;
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int autoneg:1;
-	unsigned int default_port:4;		/* Last dev->if_port value. */
-	unsigned int open:1;
-	unsigned int csr0;					/* CSR0 setting. */
-	unsigned int csr6;					/* Current CSR6 control settings. */
-	u16 to_advertise;					/* NWay capabilities advertised.  */
-	u16 advertising[4];
-	signed char phys[4], mii_cnt;		/* MII device addresses. */
-	int saved_if_port;
-	struct pci_dev *pdev;
-	spinlock_t lock;
-};
-
-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 void xircom_up(struct net_device *dev);
-static void xircom_down(struct net_device *dev);
-static int xircom_open(struct net_device *dev);
-static void xircom_tx_timeout(struct net_device *dev);
-static void xircom_init_ring(struct net_device *dev);
-static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int xircom_rx(struct net_device *dev);
-static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int xircom_close(struct net_device *dev);
-static struct net_device_stats *xircom_get_stats(struct net_device *dev);
-static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void set_rx_mode(struct net_device *dev);
-static void check_duplex(struct net_device *dev);
-
-
-/* The Xircom cards are picky about when certain bits in CSR6 can be
-   manipulated.  Keith Owens <kaos@ocs.com.au>. */
-static void outl_CSR6(u32 newcsr6, long ioaddr)
-{
-	const int strict_bits =
-		TxThresh10 | TxStoreForw | TxThreshMask | EnableTxRx | FullDuplexBit;
-    int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
-    long flags;
-    save_flags(flags);
-    cli();
-	/* mask out the reserved bits that always read 0 on the Xircom cards */
-	newcsr6 &= ~ReservedZeroMask;
-	/* or in the reserved bits that always read 1 */
-	newcsr6 |= ReservedOneMask;
-    currcsr6 = inl(ioaddr + CSR6);
-    if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
-	((currcsr6 & ~EnableTxRx) == 0)) {
-		outl(newcsr6, ioaddr + CSR6);	/* safe */
-		restore_flags(flags);
-		return;
-    }
-    /* make sure the transmitter and receiver are stopped first */
-    currcsr6 &= ~EnableTxRx;
-    while (1) {
-		csr5 = inl(ioaddr + CSR5);
-		if (csr5 == 0xffffffff)
-			break;  /* cannot read csr5, card removed? */
-		csr5_22_20 = csr5 & 0x700000;
-		csr5_19_17 = csr5 & 0x0e0000;
-		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
-			(csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
-			break;  /* both are stopped or suspended */
-		if (!--attempts) {
-			printk(KERN_INFO DRV_NAME ": outl_CSR6 too many attempts,"
-				   "csr5=0x%08x\n", csr5);
-			outl(newcsr6, ioaddr + CSR6);  /* unsafe but do it anyway */
-			restore_flags(flags);
-			return;
-		}
-		outl(currcsr6, ioaddr + CSR6);
-		udelay(1);
-    }
-    /* now it is safe to change csr6 */
-    outl(newcsr6, ioaddr + CSR6);
-    restore_flags(flags);
-}
-
-
-static void __devinit read_mac_address(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	int i, j;
-	unsigned char tuple, link, data_id, data_count;
-
-	/* Xircom has its address stored in the CIS;
-	 * we access it through the boot rom interface for now
-	 * this might not work, as the CIS is not parsed but I
-	 * (danilo) use the offset I found on my card's CIS !!!
-	 *
-	 * Doug Ledford: I changed this routine around so that it
-	 * walks the CIS memory space, parsing the config items, and
-	 * finds the proper lan_node_id tuple and uses the data
-	 * stored there.
-	 */
-	outl(1 << 12, ioaddr + CSR9); /* enable boot rom access */
-	for (i = 0x100; i < 0x1f7; i += link+2) {
-		outl(i, ioaddr + CSR10);
-		tuple = inl(ioaddr + CSR9) & 0xff;
-		outl(i + 1, ioaddr + CSR10);
-		link = inl(ioaddr + CSR9) & 0xff;
-		outl(i + 2, ioaddr + CSR10);
-		data_id = inl(ioaddr + CSR9) & 0xff;
-		outl(i + 3, ioaddr + CSR10);
-		data_count = inl(ioaddr + CSR9) & 0xff;
-		if ( (tuple == 0x22) &&
-			 (data_id == 0x04) && (data_count == 0x06) ) {
-			/*
-			 * This is it.  We have the data we want.
-			 */
-			for (j = 0; j < 6; j++) {
-				outl(i + j + 4, ioaddr + CSR10);
-				dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;
-			}
-			break;
-		} else if (link == 0) {
-			break;
-		}
-	}
-}
-
-
-/*
- * locate the MII interfaces and initialize them.
- * we disable full-duplex modes here,
- * because we don't know how to handle them.
- */
-static void find_mii_transceivers(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	int phy, phy_idx;
-
-	if (media_cap[tp->default_port] & MediaIsMII) {
-		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
-		tp->to_advertise = media2advert[tp->default_port - 9];
-	} else
-		tp->to_advertise =
-			/*ADVERTISE_100BASE4 | ADVERTISE_100FULL |*/ ADVERTISE_100HALF |
-			/*ADVERTISE_10FULL |*/ ADVERTISE_10HALF | ADVERTISE_CSMA;
-
-	/* Find the connected MII xcvrs.
-	   Doing this in open() would allow detecting external xcvrs later,
-	   but takes much time. */
-	for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
-		int mii_status = mdio_read(dev, phy, MII_BMSR);
-		if ((mii_status & (BMSR_100BASE4 | BMSR_100HALF | BMSR_10HALF)) == BMSR_100BASE4 ||
-			((mii_status & BMSR_100BASE4) == 0 &&
-			 (mii_status & (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF)) != 0)) {
-			int mii_reg0 = mdio_read(dev, phy, MII_BMCR);
-			int mii_advert = mdio_read(dev, phy, MII_ADVERTISE);
-			int reg4 = ((mii_status >> 6) & tp->to_advertise) | ADVERTISE_CSMA;
-			tp->phys[phy_idx] = phy;
-			tp->advertising[phy_idx++] = reg4;
-			printk(KERN_INFO "%s:  MII transceiver #%d "
-				   "config %4.4x status %4.4x advertising %4.4x.\n",
-				   dev->name, phy, mii_reg0, mii_status, mii_advert);
-		}
-	}
-	tp->mii_cnt = phy_idx;
-	if (phy_idx == 0) {
-		printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
-			   dev->name);
-		tp->phys[0] = 0;
-	}
-}
-
-
-/*
- * To quote Arjan van de Ven:
- *   tranceiver_voodoo() enables the external UTP plug thingy.
- *   it's called voodoo as I stole this code and cannot cross-reference
- *   it with the specification.
- * Actually it seems to go like this:
- * - GPIO2 enables the MII itself so we can talk to it. The MII gets reset
- *   so any prior MII settings are lost.
- * - GPIO0 enables the TP port so the MII can talk to the network.
- * - a software reset will reset both GPIO pins.
- * I also moved the software reset here, because doing it in xircom_up()
- * required enabling the GPIO pins each time, which reset the MII each time.
- * Thus we couldn't control the MII -- which sucks because we don't know
- * how to handle full-duplex modes so we *must* disable them.
- */
-static void transceiver_voodoo(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
-	outl(SoftwareReset, ioaddr + CSR0);
-	udelay(2);
-
-	/* Deassert reset. */
-	outl(tp->csr0, ioaddr + CSR0);
-
-	/* Reset the xcvr interface and turn on heartbeat. */
-	outl(0x0008, ioaddr + CSR15);
-	udelay(5);  /* The delays are Xircom-recommended to give the
-				 * chipset time to reset the actual hardware
-				 * on the PCMCIA card
-				 */
-	outl(0xa8050000, ioaddr + CSR15);
-	udelay(5);
-	outl(0xa00f0000, ioaddr + CSR15);
-	udelay(5);
-
-	outl_CSR6(0, ioaddr);
-	//outl_CSR6(FullDuplexBit, ioaddr);
-}
-
-
-static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct net_device *dev;
-	struct xircom_private *tp;
-	static int board_idx = -1;
-	int chip_idx = id->driver_data;
-	long ioaddr;
-	int i;
-	u8 chip_rev;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-	static int printed_version;
-	if (!printed_version++)
-		printk(version);
-#endif
-
-	//printk(KERN_INFO "xircom_init_one(%s)\n", pdev->slot_name);
-
-	board_idx++;
-
-	if (pci_enable_device(pdev))
-		return -ENODEV;
-
-	pci_set_master(pdev);
-
-	ioaddr = pci_resource_start(pdev, 0);
-	dev = alloc_etherdev(sizeof(*tp));
-	if (!dev) {
-		printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);
-		return -ENOMEM;
-	}
-	SET_MODULE_OWNER(dev);
-
-	dev->base_addr = ioaddr;
-	dev->irq = pdev->irq;
-
-	if (pci_request_regions(pdev, dev->name)) {
-		printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", board_idx);
-		goto err_out_free_netdev;
-	}
-
-	/* Bring the chip out of sleep mode.
-	   Caution: Snooze mode does not work with some boards! */
-	if (xircom_tbl[chip_idx].flags & HAS_ACPI)
-		pci_write_config_dword(pdev, PCI_POWERMGMT, 0);
-
-	/* Stop the chip's Tx and Rx processes. */
-	outl_CSR6(inl(ioaddr + CSR6) & ~EnableTxRx, ioaddr);
-	/* Clear the missed-packet counter. */
-	(volatile int)inl(ioaddr + CSR8);
-
-	tp = dev->priv;
-
-	tp->lock = SPIN_LOCK_UNLOCKED;
-	tp->pdev = pdev;
-	tp->chip_id = chip_idx;
-	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. */
-	/* XXX: is this necessary for Xircom? */
-	tp->csr0 = csr0 & ~EnableMWI;
-
-	pci_set_drvdata(pdev, dev);
-
-	/* The lower four bits are the media type. */
-	if (board_idx >= 0 && board_idx < MAX_UNITS) {
-		tp->default_port = options[board_idx] & 15;
-		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
-			tp->full_duplex = 1;
-		if (mtu[board_idx] > 0)
-			dev->mtu = mtu[board_idx];
-	}
-	if (dev->mem_start)
-		tp->default_port = dev->mem_start;
-	if (tp->default_port) {
-		if (media_cap[tp->default_port] & MediaAlwaysFD)
-			tp->full_duplex = 1;
-	}
-	if (tp->full_duplex)
-		tp->autoneg = 0;
-	else
-		tp->autoneg = 1;
-	tp->speed100 = 1;
-
-	/* The Xircom-specific entries in the device structure. */
-	dev->open = &xircom_open;
-	dev->hard_start_xmit = &xircom_start_xmit;
-	dev->stop = &xircom_close;
-	dev->get_stats = &xircom_get_stats;
-	dev->do_ioctl = &xircom_ioctl;
-#ifdef HAVE_MULTICAST
-	dev->set_multicast_list = &set_rx_mode;
-#endif
-	dev->tx_timeout = xircom_tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	transceiver_voodoo(dev);
-
-	read_mac_address(dev);
-
-	if (register_netdev(dev))
-		goto err_out_cleardev;
-
-	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
-	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
-	       dev->name, xircom_tbl[chip_idx].chip_name, chip_rev, ioaddr);
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
-	printk(", IRQ %d.\n", dev->irq);
-
-	if (xircom_tbl[chip_idx].flags & HAS_MII) {
-		find_mii_transceivers(dev);
-		check_duplex(dev);
-	}
-
-	return 0;
-
-err_out_cleardev:
-	pci_set_drvdata(pdev, NULL);
-	pci_release_regions(pdev);
-err_out_free_netdev:
-	unregister_netdev(dev);
-	kfree(dev);
-	return -ENODEV;
-}
-
-
-/* MII transceiver control section.
-   Read and write the MII registers using software-generated serial
-   MDIO protocol.  See the MII specifications or DP83840A data sheet
-   for details. */
-
-/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
-   "overclocking" issues or future 66Mhz PCI. */
-#define mdio_delay() inl(mdio_addr)
-
-/* Read and write the MII registers using software-generated serial
-   MDIO protocol.  It is just different enough from the EEPROM protocol
-   to not share code.  The maxium data clock rate is 2.5 Mhz. */
-#define MDIO_SHIFT_CLK	0x10000
-#define MDIO_DATA_WRITE0 0x00000
-#define MDIO_DATA_WRITE1 0x20000
-#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
-#define MDIO_ENB_IN		0x40000
-#define MDIO_DATA_READ	0x80000
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	int i;
-	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int retval = 0;
-	long ioaddr = dev->base_addr;
-	long mdio_addr = ioaddr + CSR9;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 19; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return (retval>>1) & 0xffff;
-}
-
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	int i;
-	int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
-	long ioaddr = dev->base_addr;
-	long mdio_addr = ioaddr + CSR9;
-
-	/* Establish sync by sending 32 logic ones. */
-	for (i = 32; i >= 0; i--) {
-		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
-		outl(MDIO_ENB | dataval, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		outl(MDIO_ENB_IN, mdio_addr);
-		mdio_delay();
-		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
-		mdio_delay();
-	}
-	return;
-}
-
-
-static void
-xircom_up(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-
-	/* Clear the tx ring */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		tp->tx_skbuff[i] = 0;
-		tp->tx_ring[i].status = 0;
-	}
-
-	if (xircom_debug > 1)
-		printk(KERN_DEBUG "%s: xircom_up() irq %d.\n", dev->name, dev->irq);
-
-	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
-	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
-
-	tp->saved_if_port = dev->if_port;
-	if (dev->if_port == 0)
-		dev->if_port = tp->default_port;
-
-	tp->csr6 = TxThresh10 /*| FullDuplexBit*/;						/* XXX: why 10 and not 100? */
-
-	set_rx_mode(dev);
-
-	/* Start the chip's Tx to process setup frame. */
-	outl_CSR6(tp->csr6, ioaddr);
-	outl_CSR6(tp->csr6 | EnableTx, ioaddr);
-
-	/* Acknowledge all outstanding interrupts sources */
-	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
-	/* Enable interrupts by setting the interrupt mask. */
-	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
-	/* Enable Rx */
-	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
-	/* Rx poll demand */
-	outl(0, ioaddr + CSR2);
-
-	/* Tell the net layer we're ready */
-	netif_start_queue (dev);
-
-	if (xircom_debug > 2) {
-		printk(KERN_DEBUG "%s: Done xircom_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
-			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
-			   inl(ioaddr + CSR6));
-	}
-}
-
-
-static int
-xircom_open(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-
-	if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))
-		return -EAGAIN;
-
-	xircom_init_ring(dev);
-
-	xircom_up(dev);
-	tp->open = 1;
-
-	return 0;
-}
-
-
-static void xircom_tx_timeout(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	if (media_cap[dev->if_port] & MediaIsMII) {
-		/* Do nothing -- the media monitor should handle this. */
-		if (xircom_debug > 1)
-			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
-				   dev->name);
-	}
-
-#if defined(way_too_many_messages)
-	if (xircom_debug > 3) {
-		int i;
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
-			int j;
-			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "
-				   "%2.2x %2.2x %2.2x.\n",
-				   i, (unsigned int)tp->rx_ring[i].status,
-				   (unsigned int)tp->rx_ring[i].length,
-				   (unsigned int)tp->rx_ring[i].buffer1,
-				   (unsigned int)tp->rx_ring[i].buffer2,
-				   buf[0], buf[1], buf[2]);
-			for (j = 0; buf[j] != 0xee && j < 1600; j++)
-				if (j < 100) printk(" %2.2x", buf[j]);
-			printk(" j=%d.\n", j);
-		}
-		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
-		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
-		printk("\n");
-	}
-#endif
-
-	/* Stop and restart the chip's Tx/Rx processes . */
-	outl_CSR6(tp->csr6 | EnableRx, ioaddr);
-	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
-	/* Trigger an immediate transmit demand. */
-	outl(0, ioaddr + CSR1);
-
-	dev->trans_start = jiffies;
-	netif_wake_queue (dev);
-	tp->stats.tx_errors++;
-}
-
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static void xircom_init_ring(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	int i;
-
-	tp->tx_full = 0;
-	tp->cur_rx = tp->cur_tx = 0;
-	tp->dirty_rx = tp->dirty_tx = 0;
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		tp->rx_ring[i].status = 0;
-		tp->rx_ring[i].length = PKT_BUF_SZ;
-		tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
-		tp->rx_skbuff[i] = NULL;
-	}
-	/* Mark the last entry as wrapping the ring. */
-	tp->rx_ring[i-1].length = PKT_BUF_SZ | Rx1RingWrap;
-	tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		/* Note the receive buffer must be longword aligned.
-		   dev_alloc_skb() provides 16 byte alignment.  But do *not*
-		   use skb_reserve() to align the IP header! */
-		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
-		tp->rx_skbuff[i] = skb;
-		if (skb == NULL)
-			break;
-		skb->dev = dev;			/* Mark as being used by this device. */
-		tp->rx_ring[i].status = Rx0DescOwned;	/* Owned by Xircom chip */
-		tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
-	}
-	tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
-	/* The Tx buffer descriptor is filled in as needed, but we
-	   do need to clear the ownership bit. */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		tp->tx_skbuff[i] = 0;
-		tp->tx_ring[i].status = 0;
-		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
-		if (tp->chip_id == X3201_3)
-			tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
-#endif /* CARDBUS */
-	}
-	tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
-}
-
-
-static int
-xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	int entry;
-	u32 flag;
-
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
-
-	/* Calculate the next Tx descriptor entry. */
-	entry = tp->cur_tx % TX_RING_SIZE;
-
-	tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
-	if (tp->chip_id == X3201_3) {
-		memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
-		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
-	} else
-#endif
-		tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
-
-	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
-		flag = Tx1WholePkt; /* No interrupt */
-	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
-		flag = Tx1WholePkt | Tx1ComplIntr; /* Tx-done intr. */
-	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
-		flag = Tx1WholePkt; /* No Tx-done intr. */
-	} else {
-		/* Leave room for set_rx_mode() to fill entries. */
-		flag = Tx1WholePkt | Tx1ComplIntr; /* Tx-done intr. */
-		tp->tx_full = 1;
-	}
-	if (entry == TX_RING_SIZE - 1)
-		flag |= Tx1WholePkt | Tx1ComplIntr | Tx1RingWrap;
-
-	tp->tx_ring[entry].length = skb->len | flag;
-	tp->tx_ring[entry].status = Tx0DescOwned;	/* Pass ownership to the chip. */
-	tp->cur_tx++;
-	if (tp->tx_full)
-		netif_stop_queue (dev);
-	else
-		netif_wake_queue (dev);
-
-	/* Trigger an immediate transmit demand. */
-	outl(0, dev->base_addr + CSR1);
-
-	dev->trans_start = jiffies;
-
-	return 0;
-}
-
-
-static void xircom_media_change(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-	u16 reg0, reg1, reg4, reg5;
-	u32 csr6 = inl(ioaddr + CSR6), newcsr6;
-
-	/* reset status first */
-	mdio_read(dev, tp->phys[0], MII_BMCR);
-	mdio_read(dev, tp->phys[0], MII_BMSR);
-
-	reg0 = mdio_read(dev, tp->phys[0], MII_BMCR);
-	reg1 = mdio_read(dev, tp->phys[0], MII_BMSR);
-
-	if (reg1 & BMSR_LSTATUS) {
-		/* link is up */
-		if (reg0 & BMCR_ANENABLE) {
-			/* autonegotiation is enabled */
-			reg4 = mdio_read(dev, tp->phys[0], MII_ADVERTISE);
-			reg5 = mdio_read(dev, tp->phys[0], MII_LPA);
-			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
-				tp->speed100 = 1;
-				tp->full_duplex = 1;
-			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
-				tp->speed100 = 1;
-				tp->full_duplex = 0;
-			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
-				tp->speed100 = 0;
-				tp->full_duplex = 1;
-			} else {
-				tp->speed100 = 0;
-				tp->full_duplex = 0;
-			}
-		} else {
-			/* autonegotiation is disabled */
-			if (reg0 & BMCR_SPEED100)
-				tp->speed100 = 1;
-			else
-				tp->speed100 = 0;
-			if (reg0 & BMCR_FULLDPLX)
-				tp->full_duplex = 1;
-			else
-				tp->full_duplex = 0;
-		}
-		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
-		       dev->name,
-		       tp->speed100 ? "100" : "10",
-		       tp->full_duplex ? "full" : "half");
-		newcsr6 = csr6 & ~FullDuplexBit;
-		if (tp->full_duplex)
-			newcsr6 |= FullDuplexBit;
-		if (newcsr6 != csr6)
-			outl_CSR6(newcsr6, ioaddr + CSR6);
-	} else {
-		printk(KERN_DEBUG "%s: Link is down\n", dev->name);
-	}
-}
-
-
-static void check_duplex(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	u16 reg0;
-
-	mdio_write(dev, tp->phys[0], MII_BMCR, BMCR_RESET);
-	udelay(500);
-	while (mdio_read(dev, tp->phys[0], MII_BMCR) & BMCR_RESET);
-
-	reg0 = mdio_read(dev, tp->phys[0], MII_BMCR);
-	mdio_write(dev, tp->phys[0], MII_ADVERTISE, tp->advertising[0]);
-
-	if (tp->autoneg) {
-		reg0 &= ~(BMCR_SPEED100 | BMCR_FULLDPLX);
-		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
-	} else {
-		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
-		if (tp->speed100)
-			reg0 |= BMCR_SPEED100;
-		if (tp->full_duplex)
-			reg0 |= BMCR_FULLDPLX;
-		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
-		       dev->name,
-		       tp->speed100 ? "100" : "10",
-		       tp->full_duplex ? "full" : "half");
-	}
-	mdio_write(dev, tp->phys[0], MII_BMCR, reg0);
-}
-
-
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
-static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-	struct net_device *dev = dev_instance;
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-	int csr5, work_budget = max_interrupt_work;
-
-	spin_lock (&tp->lock);
-
-	do {
-		csr5 = inl(ioaddr + CSR5);
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outl(csr5 & 0x0001ffff, ioaddr + CSR5);
-
-		if (xircom_debug > 4)
-			printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
-				   dev->name, csr5, inl(dev->base_addr + CSR5));
-
-		if (csr5 == 0xffffffff)
-			break;	/* all bits set, assume PCMCIA card removed */
-
-		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
-			break;
-
-		if (csr5 & (RxIntr | RxNoBuf))
-			work_budget -= xircom_rx(dev);
-
-		if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
-			unsigned int dirty_tx;
-
-			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
-				 dirty_tx++) {
-				int entry = dirty_tx % TX_RING_SIZE;
-				int status = tp->tx_ring[entry].status;
-
-				if (status < 0)
-					break;			/* It still hasn't been Txed */
-				/* Check for Rx filter setup frames. */
-				if (tp->tx_skbuff[entry] == NULL)
-				  continue;
-
-				if (status & Tx0DescError) {
-					/* There was an major error, log it. */
-#ifndef final_version
-					if (xircom_debug > 1)
-						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-							   dev->name, status);
-#endif
-					tp->stats.tx_errors++;
-					if (status & Tx0ManyColl) {
-						tp->stats.tx_aborted_errors++;
-#ifdef ETHER_STATS
-						tp->stats.collisions16++;
-#endif
-					}
-					if (status & Tx0NoCarrier) tp->stats.tx_carrier_errors++;
-					if (status & Tx0LateColl) tp->stats.tx_window_errors++;
-					if (status & Tx0Underflow) tp->stats.tx_fifo_errors++;
-				} else {
-					tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
-					tp->stats.collisions += (status >> 3) & 15;
-					tp->stats.tx_packets++;
-				}
-
-				/* Free the original skb. */
-				dev_kfree_skb_irq(tp->tx_skbuff[entry]);
-				tp->tx_skbuff[entry] = 0;
-			}
-
-#ifndef final_version
-			if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
-				printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
-#endif
-
-			if (tp->tx_full &&
-			    tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2)
-				/* The ring is no longer full */
-				tp->tx_full = 0;
-
-			if (tp->tx_full)
-				netif_stop_queue (dev);
-			else
-				netif_wake_queue (dev);
-
-			tp->dirty_tx = dirty_tx;
-			if (csr5 & TxDied) {
-				if (xircom_debug > 2)
-					printk(KERN_WARNING "%s: The transmitter stopped."
-						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
-						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
-				outl_CSR6(tp->csr6 | EnableRx, ioaddr);
-				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
-			}
-		}
-
-		/* Log errors. */
-		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
-			if (csr5 & LinkChange)
-				xircom_media_change(dev);
-			if (csr5 & TxFIFOUnderflow) {
-				if ((tp->csr6 & TxThreshMask) != TxThreshMask)
-					tp->csr6 += (1 << TxThreshShift);	/* Bump up the Tx threshold */
-				else
-					tp->csr6 |= TxStoreForw;  /* Store-n-forward. */
-				/* Restart the transmit process. */
-				outl_CSR6(tp->csr6 | EnableRx, ioaddr);
-				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
-			}
-			if (csr5 & RxDied) {		/* Missed a Rx frame. */
-				tp->stats.rx_errors++;
-				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
-			}
-			/* Clear all error sources, included undocumented ones! */
-			outl(0x0800f7ba, ioaddr + CSR5);
-		}
-		if (--work_budget < 0) {
-			if (xircom_debug > 1)
-				printk(KERN_WARNING "%s: Too much work during an interrupt, "
-					   "csr5=0x%8.8x.\n", dev->name, csr5);
-			/* Acknowledge all interrupt sources. */
-			outl(0x8001ffff, ioaddr + CSR5);
-			break;
-		}
-	} while (1);
-
-	if (xircom_debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
-			   dev->name, inl(ioaddr + CSR5));
-
-	spin_unlock (&tp->lock);
-}
-
-
-static int
-xircom_rx(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	int entry = tp->cur_rx % RX_RING_SIZE;
-	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
-	int work_done = 0;
-
-	if (xircom_debug > 4)
-		printk(KERN_DEBUG " In xircom_rx(), entry %d %8.8x.\n", entry,
-			   tp->rx_ring[entry].status);
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while (tp->rx_ring[entry].status >= 0) {
-		s32 status = tp->rx_ring[entry].status;
-
-		if (xircom_debug > 5)
-			printk(KERN_DEBUG " In xircom_rx(), entry %d %8.8x.\n", entry,
-				   tp->rx_ring[entry].status);
-		if (--rx_work_limit < 0)
-			break;
-		if ((status & 0x38008300) != 0x0300) {
-			if ((status & 0x38000300) != 0x0300) {
-				/* Ignore earlier buffers. */
-				if ((status & 0xffff) != 0x7fff) {
-					if (xircom_debug > 1)
-						printk(KERN_WARNING "%s: Oversized Ethernet frame "
-							   "spanned multiple buffers, status %8.8x!\n",
-							   dev->name, status);
-					tp->stats.rx_length_errors++;
-				}
-			} else if (status & Rx0DescError) {
-				/* There was a fatal error. */
-				if (xircom_debug > 2)
-					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-						   dev->name, status);
-				tp->stats.rx_errors++; /* end of a packet.*/
-				if (status & (Rx0Runt | Rx0HugeFrame)) tp->stats.rx_length_errors++;
-				if (status & Rx0CRCError) tp->stats.rx_crc_errors++;
-			}
-		} else {
-			/* Omit the four octet CRC from the length. */
-			short pkt_len = ((status >> 16) & 0x7ff) - 4;
-			struct sk_buff *skb;
-
-#ifndef final_version
-			if (pkt_len > 1518) {
-				printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
-					   dev->name, pkt_len, pkt_len);
-				pkt_len = 1518;
-				tp->stats.rx_length_errors++;
-			}
-#endif
-			/* Check if the packet is long enough to accept without copying
-			   to a minimally-sized skbuff. */
-			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if ! defined(__alpha__)
-				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
-								 pkt_len, 0);
-				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len),
-					   bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
-#endif
-				work_done++;
-			} else { 	/* Pass up the skb already on the Rx ring. */
-				skb_put(skb = tp->rx_skbuff[entry], pkt_len);
-				tp->rx_skbuff[entry] = NULL;
-			}
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			tp->stats.rx_packets++;
-			tp->stats.rx_bytes += pkt_len;
-		}
-		entry = (++tp->cur_rx) % RX_RING_SIZE;
-	}
-
-	/* Refill the Rx ring buffers. */
-	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
-		entry = tp->dirty_rx % RX_RING_SIZE;
-		if (tp->rx_skbuff[entry] == NULL) {
-			struct sk_buff *skb;
-			skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
-			if (skb == NULL)
-				break;
-			skb->dev = dev;			/* Mark as being used by this device. */
-			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
-			work_done++;
-		}
-		tp->rx_ring[entry].status = Rx0DescOwned;
-	}
-
-	return work_done;
-}
-
-
-static void
-xircom_down(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct xircom_private *tp = dev->priv;
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	outl(0, ioaddr + CSR7);
-	/* Stop the chip's Tx and Rx processes. */
-	outl_CSR6(inl(ioaddr + CSR6) & ~EnableTxRx, ioaddr);
-
-	if (inl(ioaddr + CSR6) != 0xffffffff)
-		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-
-	dev->if_port = tp->saved_if_port;
-}
-
-
-static int
-xircom_close(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct xircom_private *tp = dev->priv;
-	int i;
-
-	if (xircom_debug > 1)
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inl(ioaddr + CSR5));
-
-	netif_stop_queue(dev);
-
-	if (netif_device_present(dev))
-		xircom_down(dev);
-
-	free_irq(dev->irq, dev);
-
-	/* Free all the skbuffs in the Rx queue. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = tp->rx_skbuff[i];
-		tp->rx_skbuff[i] = 0;
-		tp->rx_ring[i].status = 0;		/* Not owned by Xircom chip. */
-		tp->rx_ring[i].length = 0;
-		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
-		if (skb) {
-			dev_kfree_skb(skb);
-		}
-	}
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (tp->tx_skbuff[i])
-			dev_kfree_skb(tp->tx_skbuff[i]);
-		tp->tx_skbuff[i] = 0;
-	}
-
-	tp->open = 0;
-	return 0;
-}
-
-
-static struct net_device_stats *xircom_get_stats(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	if (netif_device_present(dev))
-		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
-
-	return &tp->stats;
-}
-
-
-static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr)
-{
-	struct ethtool_cmd ecmd;
-	struct xircom_private *tp = dev->priv;
-
-	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-		return -EFAULT;
-
-	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported =
-			SUPPORTED_10baseT_Half |
-			SUPPORTED_10baseT_Full |
-			SUPPORTED_100baseT_Half |
-			SUPPORTED_100baseT_Full |
-			SUPPORTED_Autoneg |
-			SUPPORTED_MII;
-
-		ecmd.advertising = ADVERTISED_MII;
-		if (tp->advertising[0] & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (tp->advertising[0] & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (tp->advertising[0] & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (tp->advertising[0] & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-		if (tp->autoneg) {
-			ecmd.advertising |= ADVERTISED_Autoneg;
-			ecmd.autoneg = AUTONEG_ENABLE;
-		} else
-			ecmd.autoneg = AUTONEG_DISABLE;
-
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = tp->phys[0];
-		ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10;
-		ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		ecmd.maxtxpkt = TX_RING_SIZE / 2;
-		ecmd.maxrxpkt = 0;
-
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-
-	case ETHTOOL_SSET: {
-		u16 autoneg, speed100, full_duplex;
-
-		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
-		speed100 = (ecmd.speed == SPEED_100);
-		full_duplex = (ecmd.duplex == DUPLEX_FULL);
-
-		tp->autoneg = autoneg;
-		if (speed100 != tp->speed100 ||
-		    full_duplex != tp->full_duplex) {
-			tp->speed100 = speed100;
-			tp->full_duplex = full_duplex;
-			/* change advertising bits */
-			tp->advertising[0] &= ~(ADVERTISE_10HALF |
-					     ADVERTISE_10FULL |
-					     ADVERTISE_100HALF |
-					     ADVERTISE_100FULL |
-					     ADVERTISE_100BASE4);
-			if (speed100) {
-				if (full_duplex)
-					tp->advertising[0] |= ADVERTISE_100FULL;
-				else
-					tp->advertising[0] |= ADVERTISE_100HALF;
-			} else {
-				if (full_duplex)
-					tp->advertising[0] |= ADVERTISE_10FULL;
-				else
-					tp->advertising[0] |= ADVERTISE_10HALF;
-			}
-		}
-		check_duplex(dev);
-		return 0;
-	}
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info;
-		memset(&info, 0, sizeof(info));
-		info.cmd = ecmd.cmd;
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		*info.fw_version = 0;
-		strcpy(info.bus_info, tp->pdev->slot_name);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-		       return -EFAULT;
-		return 0;
-	}
-
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-
-/* Provide ioctl() calls to examine the MII xcvr state. */
-static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct xircom_private *tp = dev->priv;
-	u16 *data = (u16 *)&rq->ifr_data;
-	int phy = tp->phys[0] & 0x1f;
-	long flags;
-
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return xircom_ethtool_ioctl(dev, (void *) rq->ifr_data);
-
-	/* Legacy mii-diag interface */
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		if (tp->mii_cnt)
-			data[0] = phy;
-		else
-			return -ENODEV;
-		return 0;
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		save_flags(flags);
-		cli();
-		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
-		restore_flags(flags);
-		return 0;
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		save_flags(flags);
-		cli();
-		if (data[0] == tp->phys[0]) {
-			u16 value = data[2];
-			switch (data[1]) {
-			case 0:
-				if (value & (BMCR_RESET | BMCR_ANENABLE))
-					/* Autonegotiation. */
-					tp->autoneg = 1;
-				else {
-					tp->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
-					tp->autoneg = 0;
-				}
-				break;
-			case 4:
-				tp->advertising[0] = value;
-				break;
-			}
-			check_duplex(dev);
-		}
-		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		restore_flags(flags);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return -EOPNOTSUPP;
-}
-
-/* Set or clear the multicast filter for this adaptor.
-   Note that we only use exclusion around actually queueing the
-   new frame, not around filling tp->setup_frame.  This is non-deterministic
-   when re-entered but still correct. */
-static void set_rx_mode(struct net_device *dev)
-{
-	struct xircom_private *tp = dev->priv;
-	struct dev_mc_list *mclist;
-	long ioaddr = dev->base_addr;
-	int csr6 = inl(ioaddr + CSR6);
-	u16 *eaddrs, *setup_frm;
-	u32 tx_flags;
-	int i;
-
-	tp->csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);
-	csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		tp->csr6 |= PromiscBit;
-		csr6 |= PromiscBit;
-		goto out;
-	}
-
-	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to filter well -- accept all multicasts. */
-		tp->csr6 |= AllMultiBit;
-		csr6 |= AllMultiBit;
-		goto out;
-	}
-
-	tx_flags = Tx1WholePkt | Tx1SetupPkt | PKT_SETUP_SZ;
-
-	/* Note that only the low-address shortword of setup_frame is valid! */
-	setup_frm = tp->setup_frame;
-	mclist = dev->mc_list;
-
-	/* Fill the first entry with our physical address. */
-	eaddrs = (u16 *)dev->dev_addr;
-	*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;
-	*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;
-	*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;
-
-	if (dev->mc_count > 14) { /* Must use a multicast hash table. */
-		u32 *hash_table = (u32 *)(tp->setup_frame + 4 * 12);
-		u32 hash, hash2;
-
-		tx_flags |= Tx1HashSetup;
-		tp->csr6 |= HashFilterBit;
-		csr6 |= HashFilterBit;
-
-		/* Fill the unused 3 entries with the broadcast address.
-		   At least one entry *must* contain the broadcast address!!!*/
-		for (i = 0; i < 3; i++) {
-			*setup_frm = 0xffff; setup_frm += 2;
-			*setup_frm = 0xffff; setup_frm += 2;
-			*setup_frm = 0xffff; setup_frm += 2;
-		}
-
-		/* Truly brain-damaged hash filter layout */
-		/* XXX: not sure if I should take the last or the first 9 bits */
-		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {
-			u32 *hptr;
-			hash = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
-			if (hash < 384) {
-				hash2 = hash + ((hash >> 4) << 4) +
-					((hash >> 5) << 5);
-			} else {
-				hash -= 384;
-				hash2 = 64 + hash + (hash >> 4) * 80;
-			}
-			hptr = &hash_table[hash2 & ~0x1f];
-			*hptr |= cpu_to_le32(1 << (hash2 & 0x1f));
-		}
-	} else {
-		/* We have <= 14 mcast addresses so we can use Xircom's
-		   wonderful 16-address perfect filter. */
-		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {
-			eaddrs = (u16 *)mclist->dmi_addr;
-			*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;
-			*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;
-			*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;
-		}
-		/* Fill the unused entries with the broadcast address.
-		   At least one entry *must* contain the broadcast address!!!*/
-		for (; i < 15; i++) {
-			*setup_frm = 0xffff; setup_frm += 2;
-			*setup_frm = 0xffff; setup_frm += 2;
-			*setup_frm = 0xffff; setup_frm += 2;
-		}
-	}
-
-	/* Now add this frame to the Tx list. */
-	if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
-		/* Same setup recently queued, we need not add it. */
-		/* XXX: Huh? All it means is that the Tx list is full...*/
-	} else {
-		unsigned long flags;
-		unsigned int entry;
-		int dummy = -1;
-
-		save_flags(flags); cli();
-		entry = tp->cur_tx++ % TX_RING_SIZE;
-
-		if (entry != 0) {
-			/* Avoid a chip errata by prefixing a dummy entry. */
-			tp->tx_skbuff[entry] = 0;
-			tp->tx_ring[entry].length =
-				(entry == TX_RING_SIZE - 1) ? Tx1RingWrap : 0;
-			tp->tx_ring[entry].buffer1 = 0;
-			/* race with chip, set Tx0DescOwned later */
-			dummy = entry;
-			entry = tp->cur_tx++ % TX_RING_SIZE;
-		}
-
-		tp->tx_skbuff[entry] = 0;
-		/* Put the setup frame on the Tx list. */
-		if (entry == TX_RING_SIZE - 1)
-			tx_flags |= Tx1RingWrap;		/* Wrap ring. */
-		tp->tx_ring[entry].length = tx_flags;
-		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
-		tp->tx_ring[entry].status = Tx0DescOwned;
-		if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
-			tp->tx_full = 1;
-			netif_stop_queue (dev);
-		}
-		if (dummy >= 0)
-			tp->tx_ring[dummy].status = Tx0DescOwned;
-		restore_flags(flags);
-		/* Trigger an immediate transmit demand. */
-		outl(0, ioaddr + CSR1);
-	}
-
-out:
-	outl_CSR6(csr6, ioaddr);
-}
-
-
-static struct pci_device_id xircom_pci_table[] __devinitdata = {
-  { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
-  {0},
-};
-MODULE_DEVICE_TABLE(pci, xircom_pci_table);
-
-
-#ifdef CONFIG_PM
-static int xircom_suspend(struct pci_dev *pdev, u32 state)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *tp = dev->priv;
-	printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);
-	if (tp->open)
-		xircom_down(dev);
-	return 0;
-}
-
-
-static int xircom_resume(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *tp = dev->priv;
-	printk(KERN_INFO "xircom_resume(%s)\n", dev->name);
-
-	/* Bring the chip out of sleep mode.
-	   Caution: Snooze mode does not work with some boards! */
-	if (xircom_tbl[tp->chip_id].flags & HAS_ACPI)
-		pci_write_config_dword(tp->pdev, PCI_POWERMGMT, 0);
-
-	transceiver_voodoo(dev);
-	if (xircom_tbl[tp->chip_id].flags & HAS_MII)
-		check_duplex(dev);
-
-	if (tp->open)
-		xircom_up(dev);
-	return 0;
-}
-#endif /* CONFIG_PM */
-
-
-static void __devexit xircom_remove_one(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-
-	printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name);
-	unregister_netdev(dev);
-	pci_release_regions(pdev);
-	kfree(dev);
-	pci_set_drvdata(pdev, NULL);
-}
-
-
-static struct pci_driver xircom_driver = {
-	name:		DRV_NAME,
-	id_table:	xircom_pci_table,
-	probe:		xircom_init_one,
-	remove:		__devexit_p(xircom_remove_one),
-#ifdef CONFIG_PM
-	suspend:	xircom_suspend,
-	resume:		xircom_resume
-#endif /* CONFIG_PM */
-};
-
-
-static int __init xircom_init(void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-	printk(version);
-#endif
-	return pci_module_init(&xircom_driver);
-}
-
-
-static void __exit xircom_exit(void)
-{
-	pci_unregister_driver(&xircom_driver);
-}
-
-module_init(xircom_init)
-module_exit(xircom_exit)
-
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 4
- * End:
- */
diff -urN linux-2.5.6-pre3/drivers/net/pcnet32.c linux-2.5.6/drivers/net/pcnet32.c
--- linux-2.5.6-pre3/drivers/net/pcnet32.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/pcnet32.c	Thu Mar  7 18:24:47 2002
@@ -22,8 +22,9 @@
  *************************************************************************/
 
 #define DRV_NAME	"pcnet32"
-#define DRV_VERSION	"1.25kf"
-#define DRV_RELDATE	"17.11.2001"
+#define DRV_VERSION	"1.27a"
+#define DRV_RELDATE	"10.02.2002"
+#define PFX		DRV_NAME ": "
 
 static const char *version =
 DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n";
@@ -54,8 +55,6 @@
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 
-static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0};
-
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
@@ -65,13 +64,26 @@
     { 0, }
 };
 
+MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
+
+int cards_found __initdata;
+
+/* 
+ * VLB I/O addresses 
+ */
+static unsigned int pcnet32_portlist[] __initdata = 
+	{ 0x300, 0x320, 0x340, 0x360, 0 };
+
+
+
 static int pcnet32_debug = 1;
 static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */
+static int pcnet32vlb;	 /* check for VLB cards ? */
 
 static struct net_device *pcnet32_dev;
 
-static const int max_interrupt_work = 80;
-static const int rx_copybreak = 200;
+static int max_interrupt_work = 80;
+static int rx_copybreak = 200;
 
 #define PCNET32_PORT_AUI      0x00
 #define PCNET32_PORT_10BT     0x01
@@ -94,21 +106,21 @@
     PCNET32_PORT_AUI,			   /*  1 BNC/AUI	  */
     PCNET32_PORT_AUI,			   /*  2 AUI/BNC	  */ 
     PCNET32_PORT_ASEL,			   /*  3 not supported	  */
-    PCNET32_PORT_10BT | PCNET32_PORT_FD,	   /*  4 10baseT-FD	  */
+    PCNET32_PORT_10BT | PCNET32_PORT_FD,   /*  4 10baseT-FD	  */
     PCNET32_PORT_ASEL,			   /*  5 not supported	  */
     PCNET32_PORT_ASEL,			   /*  6 not supported	  */
     PCNET32_PORT_ASEL,			   /*  7 not supported	  */
     PCNET32_PORT_ASEL,			   /*  8 not supported	  */
     PCNET32_PORT_MII,			   /*  9 MII 10baseT	  */
-    PCNET32_PORT_MII | PCNET32_PORT_FD,		   /* 10 MII 10baseT-FD	  */
+    PCNET32_PORT_MII | PCNET32_PORT_FD,	   /* 10 MII 10baseT-FD	  */
     PCNET32_PORT_MII,			   /* 11 MII (autosel)	  */
     PCNET32_PORT_10BT,			   /* 12 10BaseT	  */
-    PCNET32_PORT_MII | PCNET32_PORT_100,	   /* 13 MII 100BaseTx	  */
+    PCNET32_PORT_MII | PCNET32_PORT_100,   /* 13 MII 100BaseTx	  */
     PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */
     PCNET32_PORT_ASEL			   /* 15 not supported	  */
 };
 
-#define MAX_UNITS 8
+#define MAX_UNITS 8	/* More are supported, limit only on options */
 static int options[MAX_UNITS];
 static int full_duplex[MAX_UNITS];
 
@@ -187,7 +199,19 @@
  * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com>
  * v1.26   Converted to pci_alloc_consistent, Jamey Hicks / George France
  *                                           <jamey@crl.dec.com>
- * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
+ * -	   Fixed a few bugs, related to running the controller in 32bit mode.
+ *	   23 Oct, 2000.  Carsten Langgaard, carstenl@mips.com
+ *	   Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+ * v1.26p  Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker
+ * v1.27   improved CSR/PROM address detection, lots of cleanups,
+ * 	   new pcnet32vlb module option, HP-PARISC support,
+ * 	   added module parameter descriptions, 
+ * 	   initial ethtool support - Helge Deller <deller@gmx.de>
+ * v1.27a  Sun Feb 10 2002 Go Taniguchi <go@turbolinux.co.jp>
+ *	   use alloc_etherdev and register_netdev
+ *	   fix pci probe not increment cards_found
+ *	   FD auto negotiate error workaround for xSeries250
+ *	   clean up and using new mii module
  */
 
 
@@ -201,13 +225,13 @@
 #define PCNET32_LOG_RX_BUFFERS 5
 #endif
 
-#define TX_RING_SIZE			(1 << (PCNET32_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS		((PCNET32_LOG_TX_BUFFERS) << 12)
-
-#define RX_RING_SIZE			(1 << (PCNET32_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS		((PCNET32_LOG_RX_BUFFERS) << 4)
+#define TX_RING_SIZE		(1 << (PCNET32_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK	(TX_RING_SIZE - 1)
+#define TX_RING_LEN_BITS	((PCNET32_LOG_TX_BUFFERS) << 12)
+
+#define RX_RING_SIZE		(1 << (PCNET32_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK	(RX_RING_SIZE - 1)
+#define RX_RING_LEN_BITS	((PCNET32_LOG_RX_BUFFERS) << 4)
 
 #define PKT_BUF_SZ		1544
 
@@ -222,7 +246,7 @@
 #define PCNET32_DWIO_RESET	0x18
 #define PCNET32_DWIO_BDP	0x1C
 
-#define PCNET32_TOTAL_SIZE 0x20
+#define PCNET32_TOTAL_SIZE	0x20
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
@@ -270,37 +294,36 @@
  */
 struct pcnet32_private {
     /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-    struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
-    struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
-    struct pcnet32_init_block	init_block;
-    dma_addr_t dma_addr;		/* DMA address of beginning of this object, returned by pci_alloc_consistent */
-    struct pci_dev *pci_dev;		/* Pointer to the associated pci device structure */
-    const char *name;
+    struct pcnet32_rx_head    rx_ring[RX_RING_SIZE];
+    struct pcnet32_tx_head    tx_ring[TX_RING_SIZE];
+    struct pcnet32_init_block init_block;
+    dma_addr_t 		dma_addr;	/* DMA address of beginning of this object, 
+					   returned by pci_alloc_consistent */
+    struct pci_dev	*pci_dev;	/* Pointer to the associated pci device structure */
+    const char		*name;
     /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-    struct sk_buff *tx_skbuff[TX_RING_SIZE];
-    struct sk_buff *rx_skbuff[RX_RING_SIZE];
-    dma_addr_t tx_dma_addr[TX_RING_SIZE];
-    dma_addr_t rx_dma_addr[RX_RING_SIZE];
+    struct sk_buff	*tx_skbuff[TX_RING_SIZE];
+    struct sk_buff	*rx_skbuff[RX_RING_SIZE];
+    dma_addr_t		tx_dma_addr[TX_RING_SIZE];
+    dma_addr_t		rx_dma_addr[RX_RING_SIZE];
     struct pcnet32_access a;
-    spinlock_t lock;					/* Guard lock */
-    unsigned int cur_rx, cur_tx;		/* The next free ring entry */
-    unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+    spinlock_t		lock;		/* Guard lock */
+    unsigned int	cur_rx, cur_tx;	/* The next free ring entry */
+    unsigned int	dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
     struct net_device_stats stats;
-    char tx_full;
-    int	 options;
-    int	 shared_irq:1,			/* shared irq possible */
-	ltint:1,
-#ifdef DO_DXSUFLO
-      dxsuflo:1,			    /* disable transmit stop on uflo */
-#endif
-	mii:1;					/* mii port available */
-    struct net_device *next;
+    char		tx_full;
+    int			options;
+    int	shared_irq:1,			/* shared irq possible */
+	ltint:1,			/* enable TxDone-intr inhibitor */
+	dxsuflo:1,			/* disable transmit stop on uflo */
+	mii:1;				/* mii port available */
+    struct net_device	*next;
     struct mii_if_info mii_if;
 };
 
-static int  pcnet32_probe_vlbus(int cards_found);
+static void pcnet32_probe_vlbus(void);
 static int  pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
-static int  pcnet32_probe1(unsigned long, unsigned char, int, int, struct pci_dev *);
+static int  pcnet32_probe1(unsigned long, unsigned char, int, struct pci_dev *);
 static int  pcnet32_open(struct net_device *);
 static int  pcnet32_init_ring(struct net_device *);
 static int  pcnet32_start_xmit(struct sk_buff *, struct net_device *);
@@ -319,15 +342,6 @@
     PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
 
-struct pcnet32_pci_id_info {
-    const char *name;
-    u16 vendor_id, device_id, svid, sdid, flags;
-    int io_size;
-    int (*probe1) (unsigned long, unsigned char, int, int, struct pci_dev *);
-};
-
-
-MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl);
 
 static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
 {
@@ -375,13 +389,13 @@
 }
 
 static struct pcnet32_access pcnet32_wio = {
-    pcnet32_wio_read_csr,
-    pcnet32_wio_write_csr,
-    pcnet32_wio_read_bcr,
-    pcnet32_wio_write_bcr,
-    pcnet32_wio_read_rap,
-    pcnet32_wio_write_rap,
-    pcnet32_wio_reset
+    read_csr:	pcnet32_wio_read_csr,
+    write_csr:	pcnet32_wio_write_csr,
+    read_bcr:	pcnet32_wio_read_bcr,
+    write_bcr:	pcnet32_wio_write_bcr,
+    read_rap:	pcnet32_wio_read_rap,
+    write_rap:	pcnet32_wio_write_rap,
+    reset:	pcnet32_wio_reset
 };
 
 static u16 pcnet32_dwio_read_csr (unsigned long addr, int index)
@@ -430,82 +444,61 @@
 }
 
 static struct pcnet32_access pcnet32_dwio = {
-    pcnet32_dwio_read_csr,
-    pcnet32_dwio_write_csr,
-    pcnet32_dwio_read_bcr,
-    pcnet32_dwio_write_bcr,
-    pcnet32_dwio_read_rap,
-    pcnet32_dwio_write_rap,
-    pcnet32_dwio_reset
-
+    read_csr:	pcnet32_dwio_read_csr,
+    write_csr:	pcnet32_dwio_write_csr,
+    read_bcr:	pcnet32_dwio_read_bcr,
+    write_bcr:	pcnet32_dwio_write_bcr,
+    read_rap:	pcnet32_dwio_read_rap,
+    write_rap:	pcnet32_dwio_write_rap,
+    reset:	pcnet32_dwio_reset
 };
 
-
 
-/* only probes for non-PCI devices, the rest are handled by pci_register_driver via pcnet32_probe_pci*/
-static int __init pcnet32_probe_vlbus(int cards_found)
+
+/* only probes for non-PCI devices, the rest are handled by 
+ * pci_register_driver via pcnet32_probe_pci */
+
+static void __devinit
+pcnet32_probe_vlbus(void)
 {
-    unsigned long ioaddr = 0; // FIXME dev ? dev->base_addr: 0;
-    unsigned int  irq_line = 0; // FIXME dev ? dev->irq : 0;
-    int *port;
+    unsigned int *port, ioaddr;
     
-    printk(KERN_INFO "pcnet32_probe_vlbus: cards_found=%d\n", cards_found);
-#ifndef __powerpc__
-    if (ioaddr > 0x1ff) {
-	if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
-	    return pcnet32_probe1(ioaddr, irq_line, 0, 0, NULL);
-	else
-	    return -ENODEV;
-    } else
-#endif
-	if (ioaddr != 0)
-	    return -ENXIO;
-    
-    /* now look for PCnet32 VLB cards */
-    for (port = pcnet32_portlist; *port; port++) {
-	unsigned long ioaddr = *port;
-	
-	if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
+    /* search for PCnet32 VLB cards at known addresses */
+    for (port = pcnet32_portlist; (ioaddr = *port); port++) {
+	if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) {
 	    /* check if there is really a pcnet chip on that ioaddr */
-	    if ((inb(ioaddr + 14) == 0x57) &&
-		(inb(ioaddr + 15) == 0x57) &&
-		(pcnet32_probe1(ioaddr, 0, 0, 0, NULL) == 0))
-		cards_found++;
+	    if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57))
+		pcnet32_probe1(ioaddr, 0, 0, NULL);
 	}
     }
-    return cards_found ? 0: -ENODEV;
 }
 
 
-
 static int __devinit
 pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-    static int card_idx;
-    long ioaddr;
-    int err = 0;
-
-    printk(KERN_INFO "pcnet32_probe_pci: found device %#08x.%#08x\n", ent->vendor, ent->device);
+    unsigned long ioaddr;
+    int err;
 
-    if ((err = pci_enable_device(pdev)) < 0) {
-	printk(KERN_ERR "pcnet32.c: failed to enable device -- err=%d\n", err);
+    err = pci_enable_device(pdev);
+    if (err < 0) {
+	printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err);
 	return err;
     }
     pci_set_master(pdev);
 
     ioaddr = pci_resource_start (pdev, 0);
-    printk(KERN_INFO "    ioaddr=%#08lx  resource_flags=%#08lx\n", ioaddr, pci_resource_flags (pdev, 0));
     if (!ioaddr) {
-        printk (KERN_ERR "no PCI IO resources, aborting\n");
+        printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n");
         return -ENODEV;
     }
-	
+    
     if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
-	printk(KERN_ERR "pcnet32.c: architecture does not support 32bit PCI busmaster DMA\n");
+	printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n");
 	return -ENODEV;
     }
 
-    return pcnet32_probe1(ioaddr, pdev->irq, 1, card_idx, pdev);
+    return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev);
 }
 
 
@@ -514,41 +507,44 @@
  *  pdev will be NULL when called from pcnet32_probe_vlbus.
  */
 static int __devinit
-pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx, struct pci_dev *pdev)
+pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared,
+		struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
     struct resource *res;
     dma_addr_t lp_dma_addr;
-    int i,media,fdx = 0, mii = 0, fset = 0;
-#ifdef DO_DXSUFLO
-    int dxsuflo = 0;
-#endif
-    int ltint = 0;
+    int i, media;
+    int fdx, mii, fset, dxsuflo, ltint;
     int chip_version;
     char *chipname;
     struct net_device *dev;
     struct pcnet32_access *a = NULL;
+    u8 promaddr[6];
 
     /* reset the chip */
     pcnet32_dwio_reset(ioaddr);
     pcnet32_wio_reset(ioaddr);
 
     /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */
-    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+    if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) {
 	a = &pcnet32_wio;
     } else {
-	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+	if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
 	    a = &pcnet32_dwio;
 	} else
 	    return -ENODEV;
     }
 
-    chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
+    chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16);
     if (pcnet32_debug > 2)
 	printk(KERN_INFO "  PCnet chip version is %#x.\n", chip_version);
     if ((chip_version & 0xfff) != 0x003)
 	return -ENODEV;
+    
+    /* initialize variables */
+    fdx = mii = fset = dxsuflo = ltint = 0;
     chip_version = (chip_version >> 12) & 0xffff;
+
     switch (chip_version) {
     case 0x2420:
 	chipname = "PCnet/PCI 79C970"; /* PCI */
@@ -587,23 +583,24 @@
 	 * mode by which the card should operate
 	 */
 	/* switch to home wiring mode */
-	media = a->read_bcr (ioaddr, 49);
+	media = a->read_bcr(ioaddr, 49);
 #if 0
 	if (pcnet32_debug > 2)
-	    printk(KERN_DEBUG "pcnet32: pcnet32 media value %#x.\n",  media);
+	    printk(KERN_DEBUG PFX "media value %#x.\n",  media);
 	media &= ~3;
 	media |= 1;
 #endif
 	if (pcnet32_debug > 2)
-	    printk(KERN_DEBUG "pcnet32: pcnet32 media reset to %#x.\n",  media);
-	a->write_bcr (ioaddr, 49, media);
+	    printk(KERN_DEBUG PFX "media reset to %#x.\n",  media);
+	a->write_bcr(ioaddr, 49, media);
 	break;
     case 0x2627:
 	chipname = "PCnet/FAST III 79C975"; /* PCI */
 	fdx = 1; mii = 1;
 	break;
     default:
-	printk(KERN_INFO "pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+	printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n",
+			chip_version);
 	return -ENODEV;
     }
 
@@ -618,17 +615,15 @@
     {
 	a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800));
 	a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00);
-#ifdef DO_DXSUFLO
 	dxsuflo = 1;
-#endif
 	ltint = 1;
     }
     
-    dev = init_etherdev(NULL, 0);
-    if(dev==NULL)
+    dev = alloc_etherdev(0);
+    if(!dev)
 	return -ENOMEM;
 
-    printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
+    printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
 
     /* In most chips, after a chip reset, the ethernet address is read from the
      * station address PROM at the base address and programmed into the
@@ -644,31 +639,28 @@
 	dev->dev_addr[2*i] = val & 0x0ff;
 	dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff;
     }
-    {
-	u8 promaddr[6];
-	for (i = 0; i < 6; i++) {
-	    promaddr[i] = inb(ioaddr + i);
-	}
-	if( memcmp( promaddr, dev->dev_addr, 6) )
-	{
-	    printk(" warning PROM address does not match CSR address\n");
-#if defined(__i386__)
-	    printk(KERN_WARNING "%s: Probably a Compaq, using the PROM address of", dev->name);
-	    memcpy(dev->dev_addr, promaddr, 6);
-#elif defined(__powerpc__)
-	    if (!is_valid_ether_addr(dev->dev_addr)
-		&& is_valid_ether_addr(promaddr)) {
-		    printk("\n" KERN_WARNING "%s: using PROM address:",
-			   dev->name);
-		    memcpy(dev->dev_addr, promaddr, 6);
-	    }
+
+    /* read PROM address and compare with CSR address */
+    for (i = 0; i < 6; i++)
+	promaddr[i] = inb(ioaddr + i);
+    
+    if( memcmp( promaddr, dev->dev_addr, 6)
+	|| !is_valid_ether_addr(dev->dev_addr) ) {
+#ifndef __powerpc__
+	if( is_valid_ether_addr(promaddr) ){
+#else
+	if( !is_valid_ether_addr(dev->dev_addr)
+	    && is_valid_ether_addr(promaddr)) {
 #endif
-	}	    	    
+	    printk(" warning: CSR address invalid,\n");
+	    printk(KERN_INFO "    using instead PROM address of");
+	    memcpy(dev->dev_addr, promaddr, 6);
+	}
     }
+
     /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */
     if( !is_valid_ether_addr(dev->dev_addr) )
-	for (i = 0; i < 6; i++)
-	    dev->dev_addr[i]=0;
+	memset(dev->dev_addr, 0, sizeof(dev->dev_addr));
 
     for (i = 0; i < 6; i++)
 	printk(" %2.2x", dev->dev_addr[i] );
@@ -698,7 +690,7 @@
 
     dev->base_addr = ioaddr;
     res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
-    if (res == NULL)
+    if (!res)
 	return -EBUSY;
     
     /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
@@ -710,7 +702,6 @@
     memset(lp, 0, sizeof(*lp));
     lp->dma_addr = lp_dma_addr;
     lp->pci_dev = pdev;
-    printk("\n" KERN_INFO "pcnet32: pcnet32_private lp=%p lp_dma_addr=%#08x", lp, lp_dma_addr);
 
     spin_lock_init(&lp->lock);
     
@@ -718,24 +709,23 @@
     lp->name = chipname;
     lp->shared_irq = shared;
     lp->mii_if.full_duplex = fdx;
-#ifdef DO_DXSUFLO
     lp->dxsuflo = dxsuflo;
-#endif
     lp->ltint = ltint;
     lp->mii = mii;
-    if (options[card_idx] > sizeof (options_mapping))
+    if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping)))
 	lp->options = PCNET32_PORT_ASEL;
     else
-	lp->options = options_mapping[options[card_idx]];
+	lp->options = options_mapping[options[cards_found]];
     lp->mii_if.dev = dev;
     lp->mii_if.mdio_read = mdio_read;
     lp->mii_if.mdio_write = mdio_write;
     
-    if (fdx && !(lp->options & PCNET32_PORT_ASEL) && full_duplex[card_idx])
+    if (fdx && !(lp->options & PCNET32_PORT_ASEL) && 
+		((cards_found>=MAX_UNITS) || full_duplex[cards_found]))
 	lp->options |= PCNET32_PORT_FD;
     
-    if (a == NULL) {
-      printk(KERN_ERR "pcnet32: No access methods\n");
+    if (!a) {
+      printk(KERN_ERR PFX "No access methods\n");
       pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
       release_resource(res);
       return -ENODEV;
@@ -790,8 +780,6 @@
 	}
     }
 
-    if (pcnet32_debug > 0)
-	printk(KERN_INFO "%s", version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -807,11 +795,13 @@
     pcnet32_dev = dev;
 
     /* Fill in the generic fields of the device structure. */
-    ether_setup(dev);
+    register_netdev(dev);
+    printk(KERN_INFO "%s: registered as %s\n",dev->name, lp->name);
+    cards_found++;
     return 0;
 }
 
-
+
 static int
 pcnet32_open(struct net_device *dev)
 {
@@ -856,6 +846,9 @@
 	    val |= 1;
 	    if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI))
 		val |= 2;
+	} else if (lp->options & PCNET32_PORT_ASEL) {
+	/* workaround for xSeries250 */
+	    val |= 3;
 	}
 	lp->a.write_bcr (ioaddr, 9, val);
     }
@@ -888,6 +881,7 @@
 	lp->a.write_csr (ioaddr, 3, val);
     }
 #endif
+
     if (lp->ltint) { /* Enable TxDone-intr inhibitor */
 	val = lp->a.read_csr (ioaddr, 5);
 	val |= (1<<14);
@@ -922,7 +916,7 @@
     if (pcnet32_debug > 2)
 	printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
 	       dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)),
-	       lp->a.read_csr (ioaddr, 0));
+	       lp->a.read_csr(ioaddr, 0));
 
 
     MOD_INC_USE_COUNT;
@@ -1032,7 +1026,7 @@
 
     /* Transmitter timeout, serious problems. */
 	printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n",
-	       dev->name, lp->a.read_csr (ioaddr, 0));
+	       dev->name, lp->a.read_csr(ioaddr, 0));
 	lp->a.write_csr (ioaddr, 0, 0x0004);
 	lp->stats.tx_errors++;
 	if (pcnet32_debug > 2) {
@@ -1068,7 +1062,7 @@
 
     if (pcnet32_debug > 3) {
 	printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
-	       dev->name, lp->a.read_csr (ioaddr, 0));
+	       dev->name, lp->a.read_csr(ioaddr, 0));
     }
 
     spin_lock_irqsave(&lp->lock, flags);
@@ -1135,8 +1129,9 @@
     int boguscnt =  max_interrupt_work;
     int must_restart;
 
-    if (dev == NULL) {
-	printk (KERN_DEBUG "pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+    if (!dev) {
+	printk (KERN_DEBUG "%s(): irq %d for unknown device\n",
+		__FUNCTION__, irq);
 	return;
     }
 
@@ -1207,7 +1202,8 @@
 
 		/* We must free the original skb */
 		if (lp->tx_skbuff[entry]) {
-                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
+                    pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry],
+			lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE);
 		    dev_kfree_skb_irq(lp->tx_skbuff[entry]);
 		    lp->tx_skbuff[entry] = 0;
                     lp->tx_dma_addr[entry] = 0;
@@ -1215,13 +1211,12 @@
 		dirty_tx++;
 	    }
 
-#ifndef final_version
 	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-		printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-		       dirty_tx, lp->cur_tx, lp->tx_full);
+		printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+			dev->name, dirty_tx, lp->cur_tx, lp->tx_full);
 		dirty_tx += TX_RING_SIZE;
 	    }
-#endif
+
 	    if (lp->tx_full &&
 		netif_queue_stopped(dev) &&
 		dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
@@ -1262,7 +1257,7 @@
 
     /* Clear any other interrupt, and set interrupt enable. */
     lp->a.write_csr (ioaddr, 0, 0x7940);
-    lp->a.write_rap(ioaddr,rap);
+    lp->a.write_rap (ioaddr,rap);
     
     if (pcnet32_debug > 4)
 	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
@@ -1315,7 +1310,9 @@
 			skb_put (skb, pkt_len);
 			lp->rx_skbuff[entry] = newskb;
 			newskb->dev = dev;
-                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);
+                        lp->rx_dma_addr[entry] = 
+				pci_map_single(lp->pci_dev, newskb->tail,
+					newskb->len, PCI_DMA_FROMDEVICE);
 			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		    } else
@@ -1349,6 +1346,7 @@
 		lp->stats.rx_bytes += skb->len;
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 		lp->stats.rx_packets++;
 	    }
 	}
@@ -1445,13 +1443,13 @@
 	
     /* set all multicast bits */
     if (dev->flags & IFF_ALLMULTI){ 
-	ib->filter [0] = 0xffffffff;
-	ib->filter [1] = 0xffffffff;
+	ib->filter[0] = 0xffffffff;
+	ib->filter[1] = 0xffffffff;
 	return;
     }
     /* clear the multicast filter */
-    ib->filter [0] = 0;
-    ib->filter [1] = 0;
+    ib->filter[0] = 0;
+    ib->filter[1] = 0;
 
     /* Add addresses */
     for (i = 0; i < dev->mc_count; i++){
@@ -1648,20 +1646,28 @@
     }
     return -EOPNOTSUPP;
 }
-					    
+
 static struct pci_driver pcnet32_driver = {
-	name:		DRV_NAME,
-	probe:		pcnet32_probe_pci,
-	remove:		NULL,
-	id_table:	pcnet32_pci_tbl,
+    name:	DRV_NAME,
+    probe:	pcnet32_probe_pci,
+    id_table:	pcnet32_pci_tbl,
 };
 
 MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, DRV_NAME " debug level (0-6)");
 MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt");  
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); 
 MODULE_PARM(tx_start_pt, "i");
+MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); 
+MODULE_PARM(pcnet32vlb, "i");
+MODULE_PARM_DESC(pcnet32vlb, DRV_NAME " Vesa local bus (VLB) support (0/1)"); 
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(options, DRV_NAME " initial option setting(s) (0-15)"); 
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)");
+
 MODULE_AUTHOR("Thomas Bogendoerfer");
 MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");
 MODULE_LICENSE("GPL");
@@ -1672,36 +1678,25 @@
 
 static int __init pcnet32_init_module(void)
 {
-    int cards_found = 0;
-    int err;
+    printk(KERN_INFO "%s", version);
 
     if (debug > 0)
 	pcnet32_debug = debug;
+
     if ((tx_start_pt >= 0) && (tx_start_pt <= 3))
 	tx_start = tx_start_pt;
-    
-    pcnet32_dev = NULL;
+
     /* find the PCI devices */
-#define USE_PCI_REGISTER_DRIVER
-#ifdef USE_PCI_REGISTER_DRIVER
-    if ((err = pci_module_init(&pcnet32_driver)) < 0 )
-       return err;
-#else
-    {
-        struct pci_device_id *devid = pcnet32_pci_tbl;
-        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {
-            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);
-            if (pdev != NULL) {
-                if (pcnet32_probe_pci(pdev, devid) >= 0) {
-                    cards_found++;
-                }
-            }
-        }
-    }
-#endif
-    return 0;
-    /* find any remaining VLbus devices */
-    return pcnet32_probe_vlbus(cards_found);
+    pci_module_init(&pcnet32_driver);
+
+    /* should we find any remaining VLbus devices ? */
+    if (pcnet32vlb)
+	pcnet32_probe_vlbus();
+
+    if (cards_found)
+	printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
+    
+    return cards_found ? 0 : -ENODEV;
 }
 
 static void __exit pcnet32_cleanup_module(void)
@@ -1710,13 +1705,13 @@
 
     /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
     while (pcnet32_dev) {
-        struct pcnet32_private *lp = pcnet32_dev->priv;
+	struct pcnet32_private *lp = pcnet32_dev->priv;
 	next_dev = lp->next;
 	unregister_netdev(pcnet32_dev);
 	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-	if (lp->pci_dev != NULL)
+	if (lp->pci_dev)
 	    pci_unregister_driver(&pcnet32_driver);
-        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+	pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
 	kfree(pcnet32_dev);
 	pcnet32_dev = next_dev;
     }
diff -urN linux-2.5.6-pre3/drivers/net/saa9730.c linux-2.5.6/drivers/net/saa9730.c
--- linux-2.5.6-pre3/drivers/net/saa9730.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/net/saa9730.c	Thu Mar  7 18:24:47 2002
@@ -685,6 +685,7 @@
 						 len, 0);
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
+				dev->last_rx = jiffies;
 			}
 		} else {
 			/* We got an error packet. */
diff -urN linux-2.5.6-pre3/drivers/net/sk98lin/skge.c linux-2.5.6/drivers/net/sk98lin/skge.c
--- linux-2.5.6-pre3/drivers/net/sk98lin/skge.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/drivers/net/sk98lin/skge.c	Thu Mar  7 18:24:47 2002
@@ -541,6 +541,48 @@
 
 		boards_found++;
 
+		/* More then one port found */
+		if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+			if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) {
+				printk(KERN_ERR "Unable to allocate etherdev "
+					"structure!\n");
+				break;
+			}
+
+			pAC->dev[1] = dev;
+			pNet = dev->priv;
+			pNet->PortNr = 1;
+			pNet->NetNr = 1;
+			pNet->pAC = pAC;
+			pNet->Mtu = 1500;
+			pNet->Up = 0;
+
+			dev->open =		&SkGeOpen;
+			dev->stop =		&SkGeClose;
+			dev->hard_start_xmit =	&SkGeXmit;
+			dev->get_stats =	&SkGeStats;
+			dev->set_multicast_list = &SkGeSetRxMode;
+			dev->set_mac_address =	&SkGeSetMacAddr;
+			dev->do_ioctl =		&SkGeIoctl;
+			dev->change_mtu =	&SkGeChangeMtu;
+
+			pProcFile = create_proc_entry(dev->name, 
+				S_IFREG | 0444, pSkRootDir);
+			pProcFile->read_proc = proc_read;
+			pProcFile->write_proc = NULL;
+			pProcFile->nlink = 1;
+			pProcFile->size = sizeof(dev->name+1);
+			pProcFile->data = (void*)pProcFile;
+
+			memcpy((caddr_t) &dev->dev_addr,
+			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
+	
+			printk("%s: %s\n", dev->name, pAC->DeviceStr);
+			printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+		
+		}
+
+
 		/*
 		 * This is bollocks, but we need to tell the net-init
 		 * code that it shall go for the next device.
diff -urN linux-2.5.6-pre3/drivers/net/smc-ultra.c linux-2.5.6/drivers/net/smc-ultra.c
--- linux-2.5.6-pre3/drivers/net/smc-ultra.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/drivers/net/smc-ultra.c	Thu Mar  7 18:24:47 2002
@@ -501,8 +501,10 @@
 
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ULTRA_CARDS) "i");
-MODULE_PARM_DESC(io, "SMC Ultra I/O base address(es)");
-MODULE_PARM_DESC(irq, "SMC Ultra IRQ number(s) (assigned)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)");
+MODULE_DESCRIPTION("SMC Ultra/EtherEZ ISA/PnP Ethernet driver");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
@@ -557,7 +559,6 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
 
 
diff -urN linux-2.5.6-pre3/drivers/net/smc-ultra32.c linux-2.5.6/drivers/net/smc-ultra32.c
--- linux-2.5.6-pre3/drivers/net/smc-ultra32.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/drivers/net/smc-ultra32.c	Thu Mar  7 18:24:47 2002
@@ -379,6 +379,9 @@
 #define MAX_ULTRA32_CARDS   4	/* Max number of Ultra cards per module */
 static struct net_device dev_ultra[MAX_ULTRA32_CARDS];
 
+MODULE_DESCRIPTION("SMC Ultra32 EISA ethernet driver");
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	int this_dev, found = 0;
@@ -415,5 +418,4 @@
 	}
 }
 #endif /* MODULE */
-MODULE_LICENSE("GPL");
 
diff -urN linux-2.5.6-pre3/drivers/net/starfire.c linux-2.5.6/drivers/net/starfire.c
--- linux-2.5.6-pre3/drivers/net/starfire.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/starfire.c	Thu Mar  7 18:24:47 2002
@@ -96,13 +96,19 @@
 	LK1.3.5 (jgarzik)
 	- ethtool NWAY_RST, GLINK, [GS]MSGLVL support
 
+	LK1.3.6:
+	- Sparc64 support and fixes (Ion Badulescu)
+	- Better stats and error handling (Ion Badulescu)
+	- Use new pci_set_mwi() PCI API function (jgarzik)
+
 TODO:
 	- implement tx_timeout() properly
+	- VLAN support
 */
 
 #define DRV_NAME	"starfire"
-#define DRV_VERSION	"1.03+LK1.3.5"
-#define DRV_RELDATE	"November 17, 2001"
+#define DRV_VERSION	"1.03+LK1.3.6"
+#define DRV_RELDATE	"March 7, 2002"
 
 #include <linux/version.h>
 #include <linux/module.h>
@@ -128,8 +134,11 @@
  * for this driver to really use the firmware. Note that Rx/Tx
  * hardware TCP checksumming is not possible without the firmware.
  *
- * I'm currently [Feb 2001] talking to Adaptec about this redistribution
- * issue. Stay tuned...
+ * If Adaptec could allow redistribution of the firmware (even in binary
+ * format), life would become a lot easier. Unfortunately, I've lost my
+ * Adaptec contacts, so progress on this front is rather unlikely to
+ * occur. If anybody from Adaptec reads this and can help with this matter,
+ * please let me know...
  */
 #undef HAS_FIRMWARE
 /*
@@ -609,7 +618,10 @@
 	long ioaddr;
 	int drv_flags, io_size;
 	int boguscnt;
+#ifndef HAVE_PCI_SET_MWI
+	u16 cmd;
 	u8 cache;
+#endif
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -644,14 +656,25 @@
 		goto err_out_free_netdev;
 	}
 
-	ioaddr = (long) ioremap (ioaddr, io_size);
+	/* ioremap is borken in Linux-2.2.x/sparc64 */
+#if !defined(CONFIG_SPARC64) || LINUX_VERSION_CODE > 0x20300
+	ioaddr = (long) ioremap(ioaddr, io_size);
 	if (!ioaddr) {
 		printk (KERN_ERR DRV_NAME " %d: cannot remap 0x%x @ 0x%lx, aborting\n",
 			card_idx, io_size, ioaddr);
 		goto err_out_free_res;
 	}
+#endif /* !CONFIG_SPARC64 || Linux 2.3.0+ */
 
-	pci_set_master (pdev);
+	pci_set_master(pdev);
+
+#ifdef HAVE_PCI_SET_MWI
+	pci_set_mwi(pdev);
+#else
+	/* enable MWI -- it vastly improves Rx performance on sparc64 */
+	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_INVALIDATE;
+	pci_write_config_word(pdev, PCI_COMMAND, cmd);
 
 	/* set PCI cache size */
 	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
@@ -662,6 +685,7 @@
 		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
 				      SMP_CACHE_BYTES >> 2);
 	}
+#endif
 
 #ifdef ZEROCOPY
 	/* Starfire can do SG and TCP/UDP checksumming */
@@ -670,7 +694,7 @@
 
 	/* Serial EEPROM reads are hidden by the hardware. */
 	for (i = 0; i < 6; i++)
-		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
+		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20 - i);
 
 #if ! defined(final_version) /* Dump the EEPROM contents during development. */
 	if (debug > 4)
@@ -932,7 +956,7 @@
 
 	/* Fill both the unused Tx SA register and the Rx perfect filter. */
 	for (i = 0; i < 6; i++)
-		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5 - i);
 	for (i = 0; i < 16; i++) {
 		u16 *eaddrs = (u16 *)dev->dev_addr;
 		long setup_frm = ioaddr + PerfFilterTable + i * 16;
@@ -979,9 +1003,9 @@
 #ifdef HAS_FIRMWARE
 	/* Load Rx/Tx firmware into the frame processors */
 	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
-		writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4);
+		writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
 	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
-		writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4);
+		writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
 	/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
 	writel(0x003F, ioaddr + GenCtrl);
 #else  /* not HAS_FIRMWARE */
@@ -1156,8 +1180,8 @@
 
 	np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping);
 #ifdef ZEROCOPY
-	np->tx_ring[entry].first_len = cpu_to_le32(skb_first_frag_len(skb));
-	np->tx_ring[entry].total_len = cpu_to_le32(skb->len);
+	np->tx_ring[entry].first_len = cpu_to_le16(skb_first_frag_len(skb));
+	np->tx_ring[entry].total_len = cpu_to_le16(skb->len);
 	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
 	np->tx_ring[entry].status = cpu_to_le32(TxDescID | TxCRCEn);
 	np->tx_ring[entry].nbufs = cpu_to_le32(skb_shinfo(skb)->nr_frags + 1);
@@ -1170,8 +1194,10 @@
 		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
 
 #ifdef ZEROCOPY
-	if (skb->ip_summed == CHECKSUM_HW)
+	if (skb->ip_summed == CHECKSUM_HW) {
 		np->tx_ring[entry].status |= cpu_to_le32(TxCalTCP);
+		np->stats.tx_compressed++;
+	}
 #endif /* ZEROCOPY */
 
 	if (debug > 5) {
@@ -1449,6 +1475,7 @@
 #if defined(full_rx_status) || defined(csum_rx_status)
 		if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) {
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
+			np->stats.rx_compressed++;
 		}
 		/*
 		 * This feature doesn't seem to be working, at least
@@ -1580,12 +1607,17 @@
 		printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
 		       dev->name, np->tx_threshold * 16);
 	}
-	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug)
+	if (intr_status & IntrRxGFPDead) {
+		np->stats.rx_fifo_errors++;
+		np->stats.rx_errors++;
+	}
+	if (intr_status & (IntrNoTxCsum | IntrDMAErr)) {
+		np->stats.tx_fifo_errors++;
+		np->stats.tx_errors++;
+	}
+	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrRxGFPDead | IntrNoTxCsum | IntrPCIPad)) && debug)
 		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 		       dev->name, intr_status);
-	/* Hmmmmm, it's not clear how to recover from DMA faults. */
-	if (intr_status & IntrDMAErr)
-		np->stats.tx_fifo_errors++;
 }
 
 
diff -urN linux-2.5.6-pre3/drivers/net/tg3.c linux-2.5.6/drivers/net/tg3.c
--- linux-2.5.6-pre3/drivers/net/tg3.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tg3.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,5925 @@
+/* $Id: tg3.c,v 1.43.2.74 2002/03/06 22:22:29 davem Exp $
+ * tg3.c: Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2002 Jeff Garzik (jgarzik@mandrakesoft.com)
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#ifndef PCI_DMA_BUS_IS_PHYS
+#define PCI_DMA_BUS_IS_PHYS 1
+#endif
+
+/* Either I can't figure out how they secretly implemented it (ie. RXD flags
+ * for mini ring, where it should go in NIC sram, and how many entries the NIC
+ * firmware expects) or it isn't really fully implemented.  Perhaps Broadcom
+ * wants people to pay for a "performance enhanced" version of their firmware +
+ * binary-only driver that has the mini ring actually implemented.
+ * These kids today... -DaveM
+ */
+#define TG3_MINI_RING_WORKS 0
+
+#define TG3_VLAN_TAG_USED 0
+
+#include "tg3.h"
+
+#define DRV_MODULE_NAME		"tg3"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"0.96"
+#define DRV_MODULE_RELDATE	"Mar 6, 2002"
+
+#define TG3_DEF_MAC_MODE	0
+#define TG3_DEF_RX_MODE		0
+#define TG3_DEF_TX_MODE		0
+#define TG3_DEF_MSG_ENABLE	  \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_PROBE	| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_TIMER	| \
+	 NETIF_MSG_IFDOWN	| \
+	 NETIF_MSG_IFUP		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
+
+/* length of time before we decide the hardware is borked,
+ * and dev->tx_timeout() should be called to fix the problem
+ */
+#define TG3_TX_TIMEOUT			(5 * HZ)
+
+/* hardware minimum and maximum for a single frame's data payload */
+#define TG3_MIN_MTU			60
+#define TG3_MAX_MTU			9000
+
+/* These numbers seem to be hard coded in the NIC firmware somehow.
+ * You can't change the ring sizes, but you can change where you place
+ * them in the NIC onboard memory.
+ */
+#define TG3_RX_RING_SIZE		512
+#define TG3_RX_RING_PENDING		200
+#if TG3_MINI_RING_WORKS
+#define TG3_RX_MINI_RING_SIZE		256 /* ??? */
+#define TG3_RX_MINI_RING_PENDING	100
+#endif
+#define TG3_RX_JUMBO_RING_SIZE		256
+#define TG3_RX_JUMBO_RING_PENDING	100
+#define TG3_RX_RCB_RING_SIZE		1024
+#define TG3_TX_RING_SIZE		512
+
+#define TG3_RX_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
+				 TG3_RX_RING_SIZE)
+#if TG3_MINI_RING_WORKS
+#define TG3_RX_MINI_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
+				 TG3_RX_MINI_RING_SIZE)
+#endif
+#define TG3_RX_JUMBO_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
+			         TG3_RX_JUMBO_RING_SIZE)
+#define TG3_RX_RCB_RING_BYTES	(sizeof(struct tg3_rx_buffer_desc) * \
+			         TG3_RX_RCB_RING_SIZE)
+#define TG3_TX_RING_BYTES	(sizeof(struct tg3_tx_buffer_desc) * \
+				 TG3_TX_RING_SIZE)
+#define TX_BUFFS_AVAIL(TP)						\
+	(((TP)->tx_cons <= (TP)->tx_prod) ?				\
+	  (TP)->tx_cons + (TG3_TX_RING_SIZE - 1) - (TP)->tx_prod :	\
+	  (TP)->tx_cons - (TP)->tx_prod - 1)
+#define NEXT_TX(N)		(((N) + 1) & (TG3_TX_RING_SIZE - 1))
+
+#define RX_PKT_BUF_SZ		(1536 + tp->rx_offset + 64)
+#if TG3_MINI_RING_WORKS
+#define RX_MINI_PKT_BUF_SZ	(256 + tp->rx_offset + 64)
+#endif
+#define RX_JUMBO_PKT_BUF_SZ	(9046 + tp->rx_offset + 64)
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define TG3_TX_WAKEUP_THRESH		(TG3_TX_RING_SIZE / 4)
+
+static char version[] __devinitdata =
+	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@mandrakesoft.com)");
+MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(tg3_debug, "i");
+MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
+
+static int tg3_debug = -1;	/* -1 == use TG3_DEF_MSG_ENABLE as value */
+
+static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_SYSKONNECT, 0x4400,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
+
+static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
+{
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&tp->indirect_lock, flags);
+		pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
+		pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
+		spin_unlock_irqrestore(&tp->indirect_lock, flags);
+	} else {
+		writel(val, tp->regs + off);
+	}
+}
+
+#define tw32(reg,val)		tg3_write_indirect_reg32(tp,(reg),(val))
+#define tw32_mailbox(reg, val)	writel(((val) & 0xffffffff), tp->regs + (reg))
+#define tw16(reg,val)		writew(((val) & 0xffff), tp->regs + (reg))
+#define tw8(reg,val)		writeb(((val) & 0xff), tp->regs + (reg))
+#define tr32(reg)		readl(tp->regs + (reg))
+#define tr16(reg)		readw(tp->regs + (reg))
+#define tr8(reg)		readb(tp->regs + (reg))
+
+static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->indirect_lock, flags);
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	spin_unlock_irqrestore(&tp->indirect_lock, flags);
+}
+
+static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->indirect_lock, flags);
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
+	pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+
+	/* Always leave this as zero. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+	spin_unlock_irqrestore(&tp->indirect_lock, flags);
+}
+
+static void tg3_disable_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+}
+
+static void tg3_enable_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+
+	if (tp->hw_status->status & SD_STATUS_UPDATED)
+		tw32(GRC_LOCAL_CTRL,
+		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+}
+
+#define PHY_BUSY_LOOPS	5000
+
+static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
+{
+	u32 frame_val;
+	int loops, ret;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32(MAC_MI_MODE,
+		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		udelay(40);
+	}
+
+	*val = 0xffffffff;
+
+	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (MI_COM_CMD_READ | MI_COM_START);
+	
+	tw32(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops-- > 0) {
+		frame_val = tr32(MAC_MI_COM);
+
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+		udelay(10);
+	}
+
+	ret = -EBUSY;
+	if (loops > 0) {
+		*val = frame_val & MI_COM_DATA_MASK;
+		ret = 0;
+	}
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32(MAC_MI_MODE, tp->mi_mode);
+		udelay(40);
+	}
+
+	return ret;
+}
+
+static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
+{
+	u32 frame_val;
+	int loops, ret;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32(MAC_MI_MODE,
+		     (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
+		udelay(40);
+	}
+
+	frame_val  = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
+		      MI_COM_PHY_ADDR_MASK);
+	frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
+		      MI_COM_REG_ADDR_MASK);
+	frame_val |= (val & MI_COM_DATA_MASK);
+	frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
+	
+	tw32(MAC_MI_COM, frame_val);
+
+	loops = PHY_BUSY_LOOPS;
+	while (loops-- > 0) {
+		frame_val = tr32(MAC_MI_COM);
+		if ((frame_val & MI_COM_BUSY) == 0) {
+			udelay(5);
+			frame_val = tr32(MAC_MI_COM);
+			break;
+		}
+		udelay(10);
+	}
+
+	ret = -EBUSY;
+	if (loops > 0)
+		ret = 0;
+
+	if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
+		tw32(MAC_MI_MODE, tp->mi_mode);
+		udelay(40);
+	}
+
+	return ret;
+}
+
+/* This will reset the tigon3 PHY if there is no valid
+ * link unless the FORCE argument is non-zero.
+ */
+static int tg3_phy_reset(struct tg3 *tp, int force)
+{
+	u32 phy_status, phy_control;
+	int err, limit;
+
+	err  = tg3_readphy(tp, MII_BMSR, &phy_status);
+	err |= tg3_readphy(tp, MII_BMSR, &phy_status);
+	if (err != 0)
+		return -EBUSY;
+
+	/* If we have link, and not forcing a reset, then nothing
+	 * to do.
+	 */
+	if ((phy_status & BMSR_LSTATUS) != 0 && (force == 0))
+		return 0;
+
+	/* OK, reset it, and poll the BMCR_RESET bit until it
+	 * clears or we time out.
+	 */
+	phy_control = BMCR_RESET;
+	err = tg3_writephy(tp, MII_BMCR, phy_control);
+	if (err != 0)
+		return -EBUSY;
+
+	limit = 5000;
+	while (limit--) {
+		err = tg3_readphy(tp, MII_BMCR, &phy_control);
+		if (err != 0)
+			return -EBUSY;
+
+		if ((phy_control & BMCR_RESET) == 0) {
+			udelay(40);
+			return 0;
+		}
+		udelay(10);
+	}
+
+	return -EBUSY;
+}
+
+static int tg3_setup_phy(struct tg3 *);
+static int tg3_halt(struct tg3 *);
+
+static int tg3_set_power_state(struct tg3 *tp, int state)
+{
+	u32 misc_host_ctrl;
+	u16 power_control, power_caps;
+	int pm = tp->pm_cap;
+
+	/* Make sure register accesses (indirect or otherwise)
+	 * will function correctly.
+	 */
+	pci_write_config_dword(tp->pdev,
+			       TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	pci_read_config_word(tp->pdev,
+			     pm + PCI_PM_CTRL,
+			     &power_control);
+	power_control |= PCI_PM_CTRL_PME_STATUS;
+	power_control &= ~(PCI_PM_CTRL_STATE_MASK);
+	switch (state) {
+	case 0:
+		power_control |= 0;
+		pci_write_config_word(tp->pdev,
+				      pm + PCI_PM_CTRL,
+				      power_control);
+		tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+		return 0;
+
+	case 1:
+		power_control |= 1;
+		break;
+
+	case 2:
+		power_control |= 2;
+		break;
+
+	case 3:
+		power_control |= 3;
+		break;
+
+	default:
+		printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n",
+		       tp->dev->name, state);
+		return -EINVAL;
+	};
+
+	power_control |= PCI_PM_CTRL_PME_ENABLE;
+
+	misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
+
+	if (tp->link_config.phy_is_low_power == 0) {
+		tp->link_config.phy_is_low_power = 1;
+		tp->link_config.orig_speed = tp->link_config.speed;
+		tp->link_config.orig_duplex = tp->link_config.duplex;
+		tp->link_config.orig_autoneg = tp->link_config.autoneg;
+	}
+
+	tp->link_config.speed = SPEED_10;
+	tp->link_config.autoneg = AUTONEG_ENABLE;
+	tg3_setup_phy(tp);
+
+	tg3_halt(tp);
+
+	pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
+
+	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
+		u32 mac_mode;
+
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+
+		mac_mode = MAC_MODE_PORT_MODE_MII |
+			MAC_MODE_LINK_POLARITY;
+
+		if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
+		     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)))
+			mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
+
+		tw32(MAC_MODE, mac_mode);
+		tw32(MAC_RX_MODE, RX_MODE_ENABLE);
+	}
+
+	if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) {
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_RXCLK_DISABLE |
+		      CLOCK_CTRL_TXCLK_DISABLE |
+		      CLOCK_CTRL_ALTCLK));
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_RXCLK_DISABLE |
+		      CLOCK_CTRL_TXCLK_DISABLE |
+		      CLOCK_CTRL_44MHZ_CORE));
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_RXCLK_DISABLE |
+		      CLOCK_CTRL_TXCLK_DISABLE |
+		      CLOCK_CTRL_ALTCLK |
+		      CLOCK_CTRL_44MHZ_CORE));
+	} else {
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_RXCLK_DISABLE |
+		      CLOCK_CTRL_TXCLK_DISABLE |
+		      CLOCK_CTRL_ALTCLK |
+		      CLOCK_CTRL_PWRDOWN_PLL133));
+	}
+
+	udelay(40);
+
+	if ((power_caps & PCI_PM_CAP_PME_D3cold) &&
+	    (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+		/* Move to auxilliary power. */
+		tw32(GRC_LOCAL_CTRL,
+		     (GRC_LCLCTRL_GPIO_OE0 |
+		      GRC_LCLCTRL_GPIO_OE1 |
+		      GRC_LCLCTRL_GPIO_OE2 |
+		      GRC_LCLCTRL_GPIO_OUTPUT0 |
+		      GRC_LCLCTRL_GPIO_OUTPUT1));
+	}
+
+	/* Finally, set the new power state. */
+	pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control);
+
+	return 0;
+}
+
+static void tg3_link_report(struct tg3 *tp)
+{
+	if (!netif_carrier_ok(tp->dev)) {
+		printk("%s: Link is down.\n", tp->dev->name);
+	} else {
+		printk("%s: Link is up at %d Mbps, %s duplex.\n",
+		       tp->dev->name,
+		       (tp->link_config.active_speed == SPEED_1000 ?
+			1000 :
+			(tp->link_config.active_speed == SPEED_100 ?
+			 100 : 10)),
+		       (tp->link_config.active_duplex == DUPLEX_FULL ?
+			"full" : "half"));
+
+		printk("%s: Flow control is %s for TX and %s for RX.\n",
+		       tp->dev->name,
+		       (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off",
+		       (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off");
+	}
+}
+
+static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv)
+{
+	u32 new_tg3_flags = 0;
+
+	if (local_adv & ADVERTISE_PAUSE_CAP) {
+		if (local_adv & ADVERTISE_PAUSE_ASYM) {
+			if (remote_adv & LPA_PAUSE_CAP)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE |
+					 TG3_FLAG_TX_PAUSE);
+			else if (remote_adv & LPA_PAUSE_ASYM)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE);
+		} else {
+			if (remote_adv & LPA_PAUSE_CAP)
+				new_tg3_flags |=
+					(TG3_FLAG_RX_PAUSE |
+					 TG3_FLAG_TX_PAUSE);
+		}
+	} else if (local_adv & ADVERTISE_PAUSE_ASYM) {
+		if ((remote_adv & LPA_PAUSE_CAP) &&
+		    (remote_adv & LPA_PAUSE_ASYM))
+			new_tg3_flags |= TG3_FLAG_TX_PAUSE;
+	}
+
+	tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE);
+	tp->tg3_flags |= new_tg3_flags;
+
+	if (new_tg3_flags & TG3_FLAG_RX_PAUSE)
+		tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE;
+
+	if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
+		tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
+	else
+		tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE;
+}
+
+static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex)
+{
+	switch (val & MII_TG3_AUX_STAT_SPDMASK) {
+	case MII_TG3_AUX_STAT_10HALF:
+		*speed = SPEED_10;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_10FULL:
+		*speed = SPEED_10;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	case MII_TG3_AUX_STAT_100HALF:
+		*speed = SPEED_100;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_100FULL:
+		*speed = SPEED_100;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	case MII_TG3_AUX_STAT_1000HALF:
+		*speed = SPEED_1000;
+		*duplex = DUPLEX_HALF;
+		break;
+
+	case MII_TG3_AUX_STAT_1000FULL:
+		*speed = SPEED_1000;
+		*duplex = DUPLEX_FULL;
+		break;
+
+	default:
+		*speed = SPEED_INVALID;
+		*duplex = DUPLEX_INVALID;
+		break;
+	};
+}
+
+static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link)
+{
+	u32 new_adv;
+	int i;
+
+	if (tp->link_config.phy_is_low_power) {
+		/* Entering low power mode.  Disable gigabit and
+		 * 100baseT advertisements.
+		 */
+		tg3_writephy(tp, MII_TG3_CTRL, 0);
+
+		new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL |
+			   ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+		if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
+			new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+
+		tg3_writephy(tp, MII_ADVERTISE, new_adv);
+	} else if (tp->link_config.speed == SPEED_INVALID) {
+		tp->link_config.advertising =
+			(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+			 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+			 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
+			 ADVERTISED_Autoneg | ADVERTISED_MII);
+
+		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+			tp->link_config.advertising &=
+				~(ADVERTISED_1000baseT_Half |
+				  ADVERTISED_1000baseT_Full);
+
+		new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+		if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
+			new_adv |= ADVERTISE_10HALF;
+		if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
+			new_adv |= ADVERTISE_10FULL;
+		if (tp->link_config.advertising & ADVERTISED_100baseT_Half)
+			new_adv |= ADVERTISE_100HALF;
+		if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
+			new_adv |= ADVERTISE_100FULL;
+		tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+		if (tp->link_config.advertising &
+		    (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
+			new_adv = 0;
+			if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
+				new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
+			if (tp->link_config.advertising & ADVERTISED_1000baseT_Full)
+				new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
+			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+				new_adv |= (MII_TG3_CTRL_AS_MASTER |
+					    MII_TG3_CTRL_ENABLE_AS_MASTER);
+			tg3_writephy(tp, MII_TG3_CTRL, new_adv);
+		} else {
+			tg3_writephy(tp, MII_TG3_CTRL, 0);
+		}
+	} else {
+		/* Asking for a specific link mode. */
+		if (tp->link_config.speed == SPEED_1000) {
+			new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+			tg3_writephy(tp, MII_ADVERTISE, new_adv);
+
+			if (tp->link_config.duplex == DUPLEX_FULL)
+				new_adv = MII_TG3_CTRL_ADV_1000_FULL;
+			else
+				new_adv = MII_TG3_CTRL_ADV_1000_HALF;
+			if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+			    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+				new_adv |= (MII_TG3_CTRL_AS_MASTER |
+					    MII_TG3_CTRL_ENABLE_AS_MASTER);
+			tg3_writephy(tp, MII_TG3_CTRL, new_adv);
+		} else {
+			tg3_writephy(tp, MII_TG3_CTRL, 0);
+
+			new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+			if (tp->link_config.speed == SPEED_100) {
+				if (tp->link_config.duplex == DUPLEX_FULL)
+					new_adv |= ADVERTISE_100FULL;
+				else
+					new_adv |= ADVERTISE_100HALF;
+			} else {
+				if (tp->link_config.duplex == DUPLEX_FULL)
+					new_adv |= ADVERTISE_10FULL;
+				else
+					new_adv |= ADVERTISE_10HALF;
+			}
+			tg3_writephy(tp, MII_ADVERTISE, new_adv);
+		}
+	}
+
+	if (tp->link_config.autoneg == AUTONEG_DISABLE &&
+	    tp->link_config.speed != SPEED_INVALID) {
+		u32 bmcr, orig_bmcr;
+
+		tp->link_config.active_speed = tp->link_config.speed;
+		tp->link_config.active_duplex = tp->link_config.duplex;
+
+		bmcr = 0;
+		switch (tp->link_config.speed) {
+		default:
+		case SPEED_10:
+			break;
+
+		case SPEED_100:
+			bmcr |= BMCR_SPEED100;
+			break;
+
+		case SPEED_1000:
+			bmcr |= TG3_BMCR_SPEED1000;
+			break;
+		};
+
+		if (tp->link_config.duplex == DUPLEX_FULL)
+			bmcr |= BMCR_FULLDPLX;
+
+		tg3_readphy(tp, MII_BMCR, &orig_bmcr);
+		if (bmcr != orig_bmcr) {
+			tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK);
+			for (i = 0; i < 15000; i++) {
+				u32 tmp;
+
+				udelay(10);
+				tg3_readphy(tp, MII_BMSR, &tmp);
+				tg3_readphy(tp, MII_BMSR, &tmp);
+				if (!(tmp & BMSR_LSTATUS)) {
+					udelay(40);
+					break;
+				}
+			}
+			tg3_writephy(tp, MII_BMCR, bmcr);
+			udelay(40);
+		}
+	} else {
+		tg3_writephy(tp, MII_BMCR,
+			     BMCR_ANENABLE | BMCR_ANRESTART);
+	}
+
+	if (wait_for_link) {
+		tp->link_config.active_speed = SPEED_INVALID;
+		tp->link_config.active_duplex = DUPLEX_INVALID;
+		for (i = 0; i < 300000; i++) {
+			u32 tmp;
+
+			udelay(10);
+			tg3_readphy(tp, MII_BMSR, &tmp);
+			tg3_readphy(tp, MII_BMSR, &tmp);
+			if (!(tmp & BMSR_LSTATUS))
+				continue;
+
+			tg3_readphy(tp, MII_TG3_AUX_STAT, &tmp);
+			tg3_aux_stat_to_speed_duplex(tp, tmp,
+						     &tp->link_config.active_speed,
+						     &tp->link_config.active_duplex);
+		}
+		if (tp->link_config.active_speed == SPEED_INVALID)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tg3_init_5401phy_dsp(struct tg3 *tp)
+{
+	int err;
+
+	/* Turn off tap power management. */
+	err  = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c20);
+
+	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0012);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1804);
+
+	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x0013);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x1204);
+
+	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0132);
+
+	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8006);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0232);
+
+	err |= tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+	err |= tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x0a20);
+
+	udelay(40);
+
+	return err;
+}
+
+static int tg3_setup_copper_phy(struct tg3 *tp)
+{
+	int current_link_up;
+	u32 bmsr, dummy;
+	u16 current_speed;
+	u8 current_duplex;
+	int i, err;
+
+	tw32(MAC_STATUS,
+	     (MAC_STATUS_SYNC_CHANGED |
+	      MAC_STATUS_CFG_CHANGED));
+
+	tp->mi_mode = MAC_MI_MODE_BASE;
+	tw32(MAC_MI_MODE, tp->mi_mode);
+	udelay(40);
+
+	if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+		tg3_readphy(tp, MII_BMSR, &bmsr);
+
+		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+			bmsr = 0;
+
+		if (!(bmsr & BMSR_LSTATUS)) {
+			err = tg3_init_5401phy_dsp(tp);
+			if (err)
+				return err;
+
+			tg3_readphy(tp, MII_BMSR, &bmsr);
+			for (i = 0; i < 1000; i++) {
+				udelay(10);
+				tg3_readphy(tp, MII_BMSR, &bmsr);
+				if (bmsr & BMSR_LSTATUS) {
+					udelay(40);
+					break;
+				}
+			}
+
+			if ((tp->phy_id & PHY_ID_REV_MASK) == PHY_REV_BCM5401_B0 &&
+			    !(bmsr & BMSR_LSTATUS) &&
+			    tp->link_config.active_speed == SPEED_1000) {
+				err = tg3_phy_reset(tp, 1);
+				if (!err)
+					err = tg3_init_5401phy_dsp(tp);
+				if (err)
+					return err;
+			}
+		}
+	} else if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+		   tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) {
+		/* 5701 {A0,B0} CRC bug workaround */
+		tg3_writephy(tp, 0x15, 0x0a75);
+		tg3_writephy(tp, 0x1c, 0x8c68);
+		tg3_writephy(tp, 0x1c, 0x8d68);
+		tg3_writephy(tp, 0x1c, 0x8c68);
+	}
+
+	/* Clear pending interrupts... */
+	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
+	tg3_readphy(tp, MII_TG3_ISTAT, &dummy);
+
+	if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
+		tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
+	else
+		tg3_writephy(tp, MII_TG3_IMASK, ~0);
+
+	if (tp->led_mode == led_mode_three_link)
+		tg3_writephy(tp, MII_TG3_EXT_CTRL,
+			     MII_TG3_EXT_CTRL_LNK3_LED_MODE);
+	else
+		tg3_writephy(tp, MII_TG3_EXT_CTRL, 0);
+
+	current_link_up = 0;
+	current_speed = SPEED_INVALID;
+	current_duplex = DUPLEX_INVALID;
+
+	tg3_readphy(tp, MII_BMSR, &bmsr);
+	tg3_readphy(tp, MII_BMSR, &bmsr);
+
+	if (bmsr & BMSR_LSTATUS) {
+		u32 aux_stat, bmcr;
+
+		tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+		for (i = 0; i < 2000; i++) {
+			udelay(10);
+			tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+			if (aux_stat)
+				break;
+		}
+
+		tg3_aux_stat_to_speed_duplex(tp, aux_stat,
+					     &current_speed,
+					     &current_duplex);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+			if (bmcr & BMCR_ANENABLE) {
+				u32 gig_ctrl;
+
+				current_link_up = 1;
+
+				/* Force autoneg restart if we are exiting
+				 * low power mode.
+				 */
+				tg3_readphy(tp, MII_TG3_CTRL, &gig_ctrl);
+				if (!(gig_ctrl & (MII_TG3_CTRL_ADV_1000_HALF |
+						  MII_TG3_CTRL_ADV_1000_FULL))) {
+					current_link_up = 0;
+				}
+			} else {
+				current_link_up = 0;
+			}
+		} else {
+			if (!(bmcr & BMCR_ANENABLE) &&
+			    tp->link_config.speed == current_speed &&
+			    tp->link_config.duplex == current_duplex) {
+				current_link_up = 1;
+			} else {
+				current_link_up = 0;
+			}
+		}
+
+		tp->link_config.active_speed = current_speed;
+		tp->link_config.active_duplex = current_duplex;
+	}
+
+	if (current_link_up == 1 &&
+	    (tp->link_config.active_duplex == DUPLEX_FULL) &&
+	    (tp->link_config.autoneg == AUTONEG_ENABLE)) {
+		u32 local_adv, remote_adv;
+
+		tg3_readphy(tp, MII_ADVERTISE, &local_adv);
+		local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+
+		tg3_readphy(tp, MII_LPA, &remote_adv);
+		remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
+
+		/* If we are not advertising full pause capability,
+		 * something is wrong.  Bring the link down and reconfigure.
+		 */
+		if (local_adv != ADVERTISE_PAUSE_CAP) {
+			current_link_up = 0;
+		} else {
+			tg3_setup_flow_control(tp, local_adv, remote_adv);
+		}
+	}
+
+	if (current_link_up == 0) {
+		u32 tmp;
+
+		tg3_phy_copper_begin(tp, 0);
+
+		tg3_readphy(tp, MII_BMSR, &tmp);
+		tg3_readphy(tp, MII_BMSR, &tmp);
+		if (tmp & BMSR_LSTATUS)
+			current_link_up = 1;
+	}
+
+	tp->mac_mode &= ~MAC_MODE_PORT_MODE_MASK;
+	if (current_link_up == 1) {
+		if (tp->link_config.active_speed == SPEED_100 ||
+		    tp->link_config.active_speed == SPEED_10)
+			tp->mac_mode |= MAC_MODE_PORT_MODE_MII;
+		else
+			tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+	} else
+		tp->mac_mode |= MAC_MODE_PORT_MODE_GMII;
+
+	tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
+	if (tp->link_config.active_duplex == DUPLEX_HALF)
+		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
+
+	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		if (current_link_up == 1)
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
+	} else {
+		if ((tp->led_mode == led_mode_link10) ||
+		    (current_link_up == 1 &&
+		     tp->link_config.active_speed == SPEED_10))
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+	}
+	tw32(MAC_MODE, tp->mac_mode);
+
+	if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
+		/* Polled via timer. */
+		tw32(MAC_EVENT, 0);
+	} else {
+		tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
+	    current_link_up == 1 &&
+	    tp->link_config.active_speed == SPEED_1000 &&
+	    ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
+	     (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
+		udelay(120);
+		tw32(MAC_STATUS,
+		     (MAC_STATUS_SYNC_CHANGED |
+		      MAC_STATUS_CFG_CHANGED));
+		tg3_write_mem(tp,
+			      NIC_SRAM_FIRMWARE_MBOX,
+			      NIC_SRAM_FIRMWARE_MBOX_MAGIC2);
+	}
+
+	if (current_link_up != netif_carrier_ok(tp->dev)) {
+		if (current_link_up)
+			netif_carrier_on(tp->dev);
+		else
+			netif_carrier_off(tp->dev);
+		tg3_link_report(tp);
+	}
+
+	return 0;
+}
+
+struct tg3_fiber_aneginfo {
+	int state;
+#define ANEG_STATE_UNKNOWN		0
+#define ANEG_STATE_AN_ENABLE		1
+#define ANEG_STATE_RESTART_INIT		2
+#define ANEG_STATE_RESTART		3
+#define ANEG_STATE_DISABLE_LINK_OK	4
+#define ANEG_STATE_ABILITY_DETECT_INIT	5
+#define ANEG_STATE_ABILITY_DETECT	6
+#define ANEG_STATE_ACK_DETECT_INIT	7
+#define ANEG_STATE_ACK_DETECT		8
+#define ANEG_STATE_COMPLETE_ACK_INIT	9
+#define ANEG_STATE_COMPLETE_ACK		10
+#define ANEG_STATE_IDLE_DETECT_INIT	11
+#define ANEG_STATE_IDLE_DETECT		12
+#define ANEG_STATE_LINK_OK		13
+#define ANEG_STATE_NEXT_PAGE_WAIT_INIT	14
+#define ANEG_STATE_NEXT_PAGE_WAIT	15
+
+	u32 flags;
+#define MR_AN_ENABLE		0x00000001
+#define MR_RESTART_AN		0x00000002
+#define MR_AN_COMPLETE		0x00000004
+#define MR_PAGE_RX		0x00000008
+#define MR_NP_LOADED		0x00000010
+#define MR_TOGGLE_TX		0x00000020
+#define MR_LP_ADV_FULL_DUPLEX	0x00000040
+#define MR_LP_ADV_HALF_DUPLEX	0x00000080
+#define MR_LP_ADV_SYM_PAUSE	0x00000100
+#define MR_LP_ADV_ASYM_PAUSE	0x00000200
+#define MR_LP_ADV_REMOTE_FAULT1	0x00000400
+#define MR_LP_ADV_REMOTE_FAULT2	0x00000800
+#define MR_LP_ADV_NEXT_PAGE	0x00001000
+#define MR_TOGGLE_RX		0x00002000
+#define MR_NP_RX		0x00004000
+
+#define MR_LINK_OK		0x80000000
+
+	unsigned long link_time, cur_time;
+
+	u32 ability_match_cfg;
+	int ability_match_count;
+
+	char ability_match, idle_match, ack_match;
+
+	u32 txconfig, rxconfig;
+#define ANEG_CFG_NP		0x00000080
+#define ANEG_CFG_ACK		0x00000040
+#define ANEG_CFG_RF2		0x00000020
+#define ANEG_CFG_RF1		0x00000010
+#define ANEG_CFG_PS2		0x00000001
+#define ANEG_CFG_PS1		0x00008000
+#define ANEG_CFG_HD		0x00004000
+#define ANEG_CFG_FD		0x00002000
+#define ANEG_CFG_INVAL		0x00001f06
+
+};
+#define ANEG_OK		0
+#define ANEG_DONE	1
+#define ANEG_TIMER_ENAB	2
+#define ANEG_FAILED	-1
+
+
+static int tg3_fiber_aneg_smachine(struct tg3 *tp,
+				   struct tg3_fiber_aneginfo *ap)
+{
+	unsigned long delta;
+	u32 rx_cfg_reg;
+	int ret;
+
+	if (ap->state == ANEG_STATE_UNKNOWN) {
+		ap->rxconfig = 0;
+		ap->link_time = 0;
+		ap->cur_time = 0;
+		ap->ability_match_cfg = 0;
+		ap->ability_match_count = 0;
+		ap->ability_match = 0;
+		ap->idle_match = 0;
+		ap->ack_match = 0;
+	}
+	ap->cur_time++;
+
+	if (tr32(MAC_STATUS) & MAC_STATUS_RCVD_CFG) {
+		rx_cfg_reg = tr32(MAC_RX_AUTO_NEG);
+
+		if (rx_cfg_reg != ap->ability_match_cfg) {
+			ap->ability_match_cfg = rx_cfg_reg;
+			ap->ability_match = 0;
+			ap->ability_match_count = 0;
+		} else {
+			if (++ap->ability_match_count > 1)
+				ap->ability_match = 1;
+		}
+		if (rx_cfg_reg & ANEG_CFG_ACK)
+			ap->ack_match = 1;
+		else
+			ap->ack_match = 0;
+
+		ap->idle_match = 0;
+	} else {
+		ap->idle_match = 1;
+		ap->ability_match_cfg = 0;
+		ap->ability_match_count = 0;
+		ap->ability_match = 0;
+		ap->ack_match = 0;
+
+		rx_cfg_reg = 0;
+	}
+
+	ap->rxconfig = rx_cfg_reg;
+	ret = ANEG_OK;
+
+	switch(ap->state) {
+	case ANEG_STATE_UNKNOWN:
+		if (ap->flags & (MR_AN_ENABLE | MR_RESTART_AN))
+			ap->state = ANEG_STATE_AN_ENABLE;
+
+		/* fallthru */
+	case ANEG_STATE_AN_ENABLE:
+		ap->flags &= ~(MR_AN_COMPLETE | MR_PAGE_RX);
+		if (ap->flags & MR_AN_ENABLE) {
+			ap->link_time = 0;
+			ap->cur_time = 0;
+			ap->ability_match_cfg = 0;
+			ap->ability_match_count = 0;
+			ap->ability_match = 0;
+			ap->idle_match = 0;
+			ap->ack_match = 0;
+
+			ap->state = ANEG_STATE_RESTART_INIT;
+		} else {
+			ap->state = ANEG_STATE_DISABLE_LINK_OK;
+		}
+		break;
+
+	case ANEG_STATE_RESTART_INIT:
+		ap->link_time = ap->cur_time;
+		ap->flags &= ~(MR_NP_LOADED);
+		ap->txconfig = 0;
+		tw32(MAC_TX_AUTO_NEG, 0);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32(MAC_MODE, tp->mac_mode);
+		ret = ANEG_TIMER_ENAB;
+		ap->state = ANEG_STATE_RESTART;
+
+		/* fallthru */
+	case ANEG_STATE_RESTART:
+		delta = ap->cur_time - ap->link_time;
+		if (delta > 100000)
+			ap->state = ANEG_STATE_ABILITY_DETECT_INIT;
+		else
+			ret = ANEG_TIMER_ENAB;
+		break;
+
+	case ANEG_STATE_DISABLE_LINK_OK:
+		ret = ANEG_DONE;
+		break;
+
+	case ANEG_STATE_ABILITY_DETECT_INIT:
+		ap->flags &= ~(MR_TOGGLE_TX);
+		ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1);
+		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32(MAC_MODE, tp->mac_mode);
+		ap->state = ANEG_STATE_ABILITY_DETECT;
+		break;
+
+	case ANEG_STATE_ABILITY_DETECT:
+		if (ap->ability_match != 0 && ap->rxconfig != 0)
+			ap->state = ANEG_STATE_ACK_DETECT_INIT;
+		break;
+
+	case ANEG_STATE_ACK_DETECT_INIT:
+		ap->txconfig |= ANEG_CFG_ACK;
+		tw32(MAC_TX_AUTO_NEG, ap->txconfig);
+		tp->mac_mode |= MAC_MODE_SEND_CONFIGS;
+		tw32(MAC_MODE, tp->mac_mode);
+		ap->state = ANEG_STATE_ACK_DETECT;
+
+		/* fallthru */
+	case ANEG_STATE_ACK_DETECT:
+		if (ap->ack_match != 0) {
+			if ((ap->rxconfig & ~ANEG_CFG_ACK) ==
+			    (ap->ability_match_cfg & ~ANEG_CFG_ACK))
+				ap->state = ANEG_STATE_COMPLETE_ACK_INIT;
+			else
+				ap->state = ANEG_STATE_AN_ENABLE;
+		} else if (ap->ability_match != 0 &&
+			   ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+		}
+		break;
+
+	case ANEG_STATE_COMPLETE_ACK_INIT:
+		if (ap->rxconfig & ANEG_CFG_INVAL) {
+			ret = ANEG_FAILED;
+			break;
+		}
+		ap->flags &= ~(MR_LP_ADV_FULL_DUPLEX |
+			       MR_LP_ADV_HALF_DUPLEX |
+			       MR_LP_ADV_SYM_PAUSE |
+			       MR_LP_ADV_ASYM_PAUSE |
+			       MR_LP_ADV_REMOTE_FAULT1 |
+			       MR_LP_ADV_REMOTE_FAULT2 |
+			       MR_LP_ADV_NEXT_PAGE |
+			       MR_TOGGLE_RX |
+			       MR_NP_RX);
+		if (ap->rxconfig & ANEG_CFG_FD)
+			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
+		if (ap->rxconfig & ANEG_CFG_HD)
+			ap->flags |= MR_LP_ADV_FULL_DUPLEX;
+		if (ap->rxconfig & ANEG_CFG_PS1)
+			ap->flags |= MR_LP_ADV_SYM_PAUSE;
+		if (ap->rxconfig & ANEG_CFG_PS2)
+			ap->flags |= MR_LP_ADV_ASYM_PAUSE;
+		if (ap->rxconfig & ANEG_CFG_RF1)
+			ap->flags |= MR_LP_ADV_REMOTE_FAULT1;
+		if (ap->rxconfig & ANEG_CFG_RF2)
+			ap->flags |= MR_LP_ADV_REMOTE_FAULT2;
+		if (ap->rxconfig & ANEG_CFG_NP)
+			ap->flags |= MR_LP_ADV_NEXT_PAGE;
+
+		ap->link_time = ap->cur_time;
+
+		ap->flags ^= (MR_TOGGLE_TX);
+		if (ap->rxconfig & 0x0008)
+			ap->flags |= MR_TOGGLE_RX;
+		if (ap->rxconfig & ANEG_CFG_NP)
+			ap->flags |= MR_NP_RX;
+		ap->flags |= MR_PAGE_RX;
+
+		ap->state = ANEG_STATE_COMPLETE_ACK;
+		ret = ANEG_TIMER_ENAB;
+		break;
+
+	case ANEG_STATE_COMPLETE_ACK:
+		if (ap->ability_match != 0 &&
+		    ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+			break;
+		}
+		delta = ap->cur_time - ap->link_time;
+		if (delta > 100000) {
+			if (!(ap->flags & (MR_LP_ADV_NEXT_PAGE))) {
+				ap->state = ANEG_STATE_IDLE_DETECT_INIT;
+			} else {
+				if ((ap->txconfig & 0x0080) == 0 &&
+				    !(ap->flags & MR_NP_RX))
+					ap->state = ANEG_STATE_IDLE_DETECT_INIT;
+				else
+					ret = ANEG_FAILED;
+			}
+		}
+		break;
+
+	case ANEG_STATE_IDLE_DETECT_INIT:
+		ap->link_time = ap->cur_time;
+		tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
+		tw32(MAC_MODE, tp->mac_mode);
+		ap->state = ANEG_STATE_IDLE_DETECT;
+		ret = ANEG_TIMER_ENAB;
+		break;
+
+	case ANEG_STATE_IDLE_DETECT:
+		if (ap->ability_match != 0 &&
+		    ap->rxconfig == 0) {
+			ap->state = ANEG_STATE_AN_ENABLE;
+			break;
+		}
+		delta = ap->cur_time - ap->link_time;
+		if (delta > 100000) {
+			/* XXX another gem from the Broadcom driver :( */
+			ap->state = ANEG_STATE_LINK_OK;
+		}
+		break;
+
+	case ANEG_STATE_LINK_OK:
+		ap->flags |= (MR_AN_COMPLETE | MR_LINK_OK);
+		ret = ANEG_DONE;
+		break;
+
+	case ANEG_STATE_NEXT_PAGE_WAIT_INIT:
+		/* ??? unimplemented */
+		break;
+
+	case ANEG_STATE_NEXT_PAGE_WAIT:
+		/* ??? unimplemented */
+		break;
+
+	default:
+		ret = ANEG_FAILED;
+		break;
+	};
+
+	return ret;
+}
+
+static int tg3_setup_fiber_phy(struct tg3 *tp)
+{
+	int current_link_up;
+	int i;
+
+	tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
+	tp->mac_mode |= MAC_MODE_PORT_MODE_TBI;
+	tw32(MAC_MODE, tp->mac_mode);
+	udelay(40);
+
+	/* Reset when initting first time or we have a link. */
+	if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+	    (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED)) {
+		/* Set PLL lock range. */
+		tg3_writephy(tp, 0x16, 0x8007);
+
+		/* SW reset */
+		tg3_writephy(tp, 0x00, 0x8000);
+
+		/* Wait for reset to complete. */
+		/* XXX schedule_timeout() ... */
+		for (i = 0; i < 500; i++)
+			udelay(10);
+
+		/* Config mode; select PMA/Ch 1 regs. */
+		tg3_writephy(tp, 0x10, 0x8411);
+
+		/* Enable auto-lock and comdet, select txclk for tx. */
+		tg3_writephy(tp, 0x11, 0x0a10);
+
+		tg3_writephy(tp, 0x18, 0x00a0);
+		tg3_writephy(tp, 0x16, 0x41ff);
+
+		/* Assert and deassert POR. */
+		tg3_writephy(tp, 0x13, 0x0400);
+		udelay(40);
+		tg3_writephy(tp, 0x13, 0x0000);
+
+		tg3_writephy(tp, 0x11, 0x0a50);
+		udelay(40);
+		tg3_writephy(tp, 0x11, 0x0a10);
+
+		/* Wait for signal to stabilize */
+		/* XXX schedule_timeout() ... */
+		for (i = 0; i < 15000; i++)
+			udelay(10);
+
+		/* Deselect the channel register so we can read the PHYID
+		 * later.
+		 */
+		tg3_writephy(tp, 0x10, 0x8011);
+	}
+
+	/* Enable link change interrupt. */
+	tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
+
+	current_link_up = 0;
+	if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) {
+		if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+			struct tg3_fiber_aneginfo aninfo;
+			int status = ANEG_FAILED;
+
+			memset(&aninfo, 0, sizeof(aninfo));
+			aninfo.flags |= (MR_AN_ENABLE);
+
+			for (i = 0; i < 6; i++) {
+				u32 tmp;
+
+				tw32(MAC_TX_AUTO_NEG, 0);
+
+				tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
+				tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII);
+				udelay(20);
+
+				tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS);
+
+				aninfo.state = ANEG_STATE_UNKNOWN;
+				aninfo.cur_time = 0;
+				while (aninfo.cur_time < 95000) {
+					status = tg3_fiber_aneg_smachine(tp, &aninfo);
+					if (status == ANEG_DONE ||
+					    status == ANEG_FAILED)
+						break;
+
+					udelay(1);
+				}
+				if (status == ANEG_DONE ||
+				    status == ANEG_FAILED)
+					break;
+			}
+
+			tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS;
+			tw32(MAC_MODE, tp->mac_mode);
+
+			if (status == ANEG_DONE &&
+			    (aninfo.flags & MR_AN_COMPLETE) &&
+			    (aninfo.flags & MR_LINK_OK) &&
+			    (aninfo.flags & MR_LP_ADV_FULL_DUPLEX)) {
+				u32 local_adv, remote_adv;
+
+				local_adv = ADVERTISE_PAUSE_CAP;
+				remote_adv = 0;
+				if (aninfo.flags & MR_LP_ADV_SYM_PAUSE)
+					remote_adv |= LPA_PAUSE_CAP;
+				if (aninfo.flags & MR_LP_ADV_ASYM_PAUSE)
+					remote_adv |= LPA_PAUSE_ASYM;
+
+				tg3_setup_flow_control(tp, local_adv, remote_adv);
+
+				current_link_up = 1;
+			}
+			for (i = 0; i < 60; i++) {
+				udelay(20);
+				tw32(MAC_STATUS,
+				     (MAC_STATUS_SYNC_CHANGED |
+				      MAC_STATUS_CFG_CHANGED));
+
+				udelay(20);
+				if ((tr32(MAC_STATUS) &
+				     (MAC_STATUS_SYNC_CHANGED |
+				      MAC_STATUS_CFG_CHANGED)) == 0)
+					break;
+			}
+		} else {
+			/* Forcing 1000FD link up. */
+			current_link_up = 1;
+		}
+	}
+
+	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
+	tw32(MAC_MODE, tp->mac_mode);
+
+	tp->hw_status->status =
+		(SD_STATUS_UPDATED |
+		 (tp->hw_status->status & ~SD_STATUS_LINK_CHG));
+
+	for (i = 0; i < 100; i++) {
+		tw32(MAC_STATUS,
+		     (MAC_STATUS_SYNC_CHANGED |
+		      MAC_STATUS_CFG_CHANGED));
+		udelay(5);
+
+		if ((tr32(MAC_STATUS) &
+		     (MAC_STATUS_SYNC_CHANGED |
+		      MAC_STATUS_CFG_CHANGED)) == 0)
+			break;
+	}
+
+	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0)
+		current_link_up = 0;
+
+	if (current_link_up == 1) {
+		tp->link_config.active_speed = SPEED_1000;
+		tp->link_config.active_duplex = DUPLEX_FULL;
+	} else {
+		tp->link_config.active_speed = SPEED_INVALID;
+		tp->link_config.active_duplex = DUPLEX_INVALID;
+	}
+
+	if (current_link_up != netif_carrier_ok(tp->dev)) {
+		if (current_link_up)
+			netif_carrier_on(tp->dev);
+		else
+			netif_carrier_off(tp->dev);
+		tg3_link_report(tp);
+	}
+
+	if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) {
+		tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY);
+		if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
+			udelay(1);
+			tw32(MAC_MODE, tp->mac_mode);
+		}
+	}
+
+	return 0;
+}
+
+static int tg3_setup_phy(struct tg3 *tp)
+{
+	int err;
+
+	if (tp->phy_id == PHY_ID_SERDES) {
+		err = tg3_setup_fiber_phy(tp);
+	} else {
+		err = tg3_setup_copper_phy(tp);
+	}
+
+	if (tp->link_config.active_speed == SPEED_1000 &&
+	    tp->link_config.active_duplex == DUPLEX_HALF)
+		tw32(MAC_TX_LENGTHS,
+		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+		      (6 << TX_LENGTHS_IPG_SHIFT) |
+		      (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+	else
+		tw32(MAC_TX_LENGTHS,
+		     ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+		      (6 << TX_LENGTHS_IPG_SHIFT) |
+		      (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+
+	return err;
+}
+
+/* Tigon3 never reports partial packet sends.  So we do not
+ * need special logic to handle SKBs that have not had all
+ * of their frags sent yet, like SunGEM does.
+ */
+static void tg3_tx(struct tg3 *tp)
+{
+	u32 hw_idx = tp->hw_status->idx[0].tx_consumer;
+	u32 sw_idx = tp->tx_cons;
+
+	while (sw_idx != hw_idx) {
+		struct ring_info *ri = &tp->tx_buffers[sw_idx];
+		struct sk_buff *skb = ri->skb;
+		int i;
+
+		if (unlikely(skb == NULL))
+			BUG();
+
+		pci_unmap_single(tp->pdev, ri->mapping,
+				 (skb->len - skb->data_len),
+				 PCI_DMA_TODEVICE);
+
+		ri->skb = NULL;
+
+		sw_idx = NEXT_TX(sw_idx);
+
+		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+			if (unlikely(sw_idx == hw_idx))
+				BUG();
+
+			ri = &tp->tx_buffers[sw_idx];
+			if (unlikely(ri->skb != NULL))
+				BUG();
+
+			pci_unmap_page(tp->pdev,
+				       ri->mapping,
+				       skb_shinfo(skb)->frags[i].size,
+				       PCI_DMA_TODEVICE);
+
+			sw_idx = NEXT_TX(sw_idx);
+		}
+
+		dev_kfree_skb_irq(skb);
+	}
+
+	tp->tx_cons = sw_idx;
+
+	if (netif_queue_stopped(tp->dev) &&
+	    (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
+		netif_wake_queue(tp->dev);
+}
+
+/* Returns size of skb allocated or < 0 on error.
+ *
+ * We only need to fill in the address because the other members
+ * of the RX descriptor are invariant, see tg3_init_rings.
+ *
+ * Note the purposeful assymetry of cpu vs. chip accesses.  For
+ * posting buffers we only dirty the first cache line of the RX
+ * descriptor (containing the address).  Whereas for the RX status
+ * buffers the cpu only reads the last cacheline of the RX descriptor
+ * (to fetch the error flags, vlan tag, checksum, and opaque cookie).
+ */
+static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
+			    int src_idx, u32 dest_idx_unmasked)
+{
+	struct tg3_rx_buffer_desc *desc;
+	struct ring_info *map, *src_map;
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int skb_size, dest_idx;
+
+	src_map = NULL;
+	switch (opaque_key) {
+	case RXD_OPAQUE_RING_STD:
+		dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE;
+		desc = &tp->rx_std[dest_idx];
+		map = &tp->rx_std_buffers[dest_idx];
+		if (src_idx >= 0)
+			src_map = &tp->rx_std_buffers[src_idx];
+		skb_size = RX_PKT_BUF_SZ;
+		break;
+
+	case RXD_OPAQUE_RING_JUMBO:
+		dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE;
+		desc = &tp->rx_jumbo[dest_idx];
+		map = &tp->rx_jumbo_buffers[dest_idx];
+		if (src_idx >= 0)
+			src_map = &tp->rx_jumbo_buffers[src_idx];
+		skb_size = RX_JUMBO_PKT_BUF_SZ;
+		break;
+#if TG3_MINI_RING_WORKS
+	case RXD_OPAQUE_RING_MINI:
+		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
+		desc = &tp->rx_mini[dest_idx];
+		map = &tp->rx_mini_buffers[dest_idx];
+		if (src_idx >= 0)
+			src_map = &tp->rx_mini_buffers[src_idx];
+		skb_size = RX_MINI_PKT_BUF_SZ;
+		break;
+#endif
+	default:
+		return -EINVAL;
+	};
+
+	/* Do not overwrite any of the map or rp information
+	 * until we are sure we can commit to a new buffer.
+	 *
+	 * Callers depend upon this behavior and assume that
+	 * we leave everything unchanged if we fail.
+	 */
+	skb = dev_alloc_skb(skb_size);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	skb->dev = tp->dev;
+	skb_reserve(skb, tp->rx_offset);
+
+	mapping = pci_map_single(tp->pdev, skb->data,
+				 skb_size - tp->rx_offset,
+				 PCI_DMA_FROMDEVICE);
+
+	map->skb = skb;
+	map->mapping = mapping;
+
+	if (src_map != NULL)
+		src_map->skb = NULL;
+
+	desc->addr_hi = ((u64)mapping >> 32);
+	desc->addr_lo = ((u64)mapping & 0xffffffff);
+
+	return skb_size;
+}
+
+/* We only need to move over in the address because the other
+ * members of the RX descriptor are invariant.  See notes above
+ * tg3_alloc_rx_skb for full details.
+ */
+static void tg3_recycle_rx(struct tg3 *tp, u32 opaque_key,
+			   int src_idx, int dest_idx_unmasked)
+{
+	struct tg3_rx_buffer_desc *src_desc, *dest_desc;
+	struct ring_info *src_map, *dest_map;
+	int dest_idx;
+
+	switch (opaque_key) {
+	case RXD_OPAQUE_RING_STD:
+		dest_idx = dest_idx_unmasked % TG3_RX_RING_SIZE;
+		dest_desc = &tp->rx_std[dest_idx];
+		dest_map = &tp->rx_std_buffers[dest_idx];
+		src_desc = &tp->rx_std[src_idx];
+		src_map = &tp->rx_std_buffers[src_idx];
+		break;
+
+	case RXD_OPAQUE_RING_JUMBO:
+		dest_idx = dest_idx_unmasked % TG3_RX_JUMBO_RING_SIZE;
+		dest_desc = &tp->rx_jumbo[dest_idx];
+		dest_map = &tp->rx_jumbo_buffers[dest_idx];
+		src_desc = &tp->rx_jumbo[src_idx];
+		src_map = &tp->rx_jumbo_buffers[src_idx];
+		break;
+#if TG3_MINI_RING_WORKS
+	case RXD_OPAQUE_RING_MINI:
+		dest_idx = dest_idx_unmasked % TG3_RX_MINI_RING_SIZE;
+		dest_desc = &tp->rx_mini[dest_idx];
+		dest_map = &tp->rx_mini_buffers[dest_idx];
+		src_desc = &tp->rx_mini[src_idx];
+		src_map = &tp->rx_mini_buffers[src_idx];
+		break;
+#endif
+	default:
+		return;
+	};
+
+	dest_map->skb = src_map->skb;
+	dest_map->mapping = src_map->mapping;
+	dest_desc->addr_hi = src_desc->addr_hi;
+	dest_desc->addr_lo = src_desc->addr_lo;
+
+	src_map->skb = NULL;
+}
+
+#if TG3_VLAN_TAG_USED
+static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag)
+{
+	return vlan_hwaccel_rx(skb, tp->vlgrp, vlan_tag);
+}
+#endif
+
+/* The RX ring scheme is composed of multiple rings which post fresh
+ * buffers to the chip, and one special ring the chip uses to report
+ * status back to the host.
+ *
+ * The special ring reports the status of received packets to the
+ * host.  The chip does not write into the original descriptor the
+ * RX buffer was obtained from.  The chip simply takes the original
+ * descriptor as provided by the host, updates the status and length
+ * field, then writes this into the next status ring entry.
+ *
+ * Each ring the host uses to post buffers to the chip is described
+ * by a TG3_BDINFO entry in the chips SRAM area.  When a packet arrives,
+ * it is first placed into the on-chip ram.  When the packet's length
+ * is known, it walks down the TG3_BDINFO entries to select the ring.
+ * Each TG3_BDINFO specifies a MAXLEN field and the first TG3_BDINFO
+ * which is within the range of the new packet's length is chosen.
+ *
+ * The "seperate ring for rx status" scheme may sound queer, but it makes
+ * sense from a cache coherency perspective.  If only the host writes
+ * to the buffer post rings, and only the chip writes to the rx status
+ * rings, then cache lines never move beyond shared-modified state.
+ * If both the host and chip were to write into the same ring, cache line
+ * eviction could occur since both entities want it in an exclusive state.
+ */
+static void tg3_rx(struct tg3 *tp)
+{
+	u32 work_mask;
+	u32 rx_rcb_ptr = tp->rx_rcb_ptr;
+	u16 hw_idx, sw_idx;
+
+	hw_idx = tp->hw_status->idx[0].rx_producer;
+	sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
+	work_mask = 0;
+	while (sw_idx != hw_idx) {
+		struct tg3_rx_buffer_desc *desc = &tp->rx_rcb[sw_idx];
+		unsigned int len;
+		struct sk_buff *skb;
+		dma_addr_t dma_addr;
+		u32 opaque_key, desc_idx, *post_ptr;
+
+		desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
+		opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
+		if (opaque_key == RXD_OPAQUE_RING_STD) {
+			dma_addr = tp->rx_std_buffers[desc_idx].mapping;
+			skb = tp->rx_std_buffers[desc_idx].skb;
+			post_ptr = &tp->rx_std_ptr;
+		} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
+			dma_addr = tp->rx_jumbo_buffers[desc_idx].mapping;
+			skb = tp->rx_jumbo_buffers[desc_idx].skb;
+			post_ptr = &tp->rx_jumbo_ptr;
+		}
+#if TG3_MINI_RING_WORKS
+		else if (opaque_key == RXD_OPAQUE_RING_MINI) {
+			dma_addr = tp->rx_mini_buffers[desc_idx].mapping;
+			skb = tp->rx_mini_buffers[desc_idx].skb;
+			post_ptr = &tp->rx_mini_ptr;
+		}
+#endif
+		else {
+			goto next_pkt_nopost;
+		}
+
+		work_mask |= opaque_key;
+
+		if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
+		    (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+		drop_it:
+			tg3_recycle_rx(tp, opaque_key,
+				       desc_idx, *post_ptr);
+		drop_it_no_recycle:
+			/* Other statistics kept track of by card. */
+			tp->net_stats.rx_dropped++;
+			goto next_pkt;
+		}
+
+		len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
+
+		/* Kill the copy case if we ever get the mini ring working. */
+		if (len > RX_COPY_THRESHOLD) {
+			int skb_size;
+
+			skb_size = tg3_alloc_rx_skb(tp, opaque_key,
+						    desc_idx, *post_ptr);
+			if (skb_size < 0)
+				goto drop_it;
+
+			pci_unmap_single(tp->pdev, dma_addr,
+					 skb_size - tp->rx_offset,
+					 PCI_DMA_FROMDEVICE);
+
+			skb_put(skb, len);
+		} else {
+			struct sk_buff *copy_skb;
+
+			tg3_recycle_rx(tp, opaque_key,
+				       desc_idx, *post_ptr);
+
+			copy_skb = dev_alloc_skb(len + 2);
+			if (copy_skb == NULL)
+				goto drop_it_no_recycle;
+
+			copy_skb->dev = tp->dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
+			memcpy(copy_skb->data, skb->data, len);
+
+			/* We'll reuse the original ring buffer. */
+			skb = copy_skb;
+		}
+
+		if (!(tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) &&
+		    (desc->type_flags & RXD_FLAG_TCPUDP_CSUM)) {
+			skb->csum = htons((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
+					  >> RXD_TCPCSUM_SHIFT);
+			skb->ip_summed = CHECKSUM_HW;
+		} else {
+			skb->ip_summed = CHECKSUM_NONE;
+		}
+
+		skb->protocol = eth_type_trans(skb, tp->dev);
+#if TG3_VLAN_TAG_USED
+		if (tp->vlgrp != NULL &&
+		    desc->type_flags & RXD_FLAG_VLAN) {
+			tg3_vlan_rx(tp, skb,
+				    desc->err_vlan & RXD_VLAN_MASK);
+		} else
+#endif
+			netif_rx(skb);
+
+		tp->dev->last_rx = jiffies;
+
+next_pkt:
+		(*post_ptr)++;
+next_pkt_nopost:
+		rx_rcb_ptr++;
+		sw_idx = rx_rcb_ptr % TG3_RX_RCB_RING_SIZE;
+	}
+
+	/* ACK the status ring. */
+	tp->rx_rcb_ptr = rx_rcb_ptr;
+	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
+		     (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE));
+
+	/* Refill RX ring(s). */
+	if (work_mask & RXD_OPAQUE_RING_STD) {
+		sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE;
+		tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
+			     sw_idx);
+	}
+	if (work_mask & RXD_OPAQUE_RING_JUMBO) {
+		sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE;
+		tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
+			     sw_idx);
+	}
+#if TG3_MINI_RING_WORKS
+	if (work_mask & RXD_OPAQUE_RING_MINI) {
+		sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
+		tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
+			     sw_idx);
+	}
+#endif
+}
+
+#define RATE_SAMPLE_INTERVAL	(1 * HZ)
+
+#define PKT_RATE_LOW		22000
+#define PKT_RATE_HIGH		61000
+
+static void tg3_rate_sample(struct tg3 *tp, unsigned long ticks)
+{
+	u32 delta, rx_now, tx_now;
+	int new_vals;
+
+	rx_now = tp->hw_stats->rx_ucast_packets.low;
+	tx_now = tp->hw_stats->COS_out_packets[0].low;
+
+	delta  = (rx_now - tp->last_rx_count);
+	delta += (tx_now - tp->last_tx_count);
+	delta /= (ticks / RATE_SAMPLE_INTERVAL);
+
+	tp->last_rx_count = rx_now;
+	tp->last_tx_count = tx_now;
+
+	new_vals = 0;
+	if (delta < PKT_RATE_LOW) {
+		if (tp->coalesce_config.rx_max_coalesced_frames !=
+		    LOW_RXMAX_FRAMES) {
+			tp->coalesce_config.rx_max_coalesced_frames =
+				LOW_RXMAX_FRAMES;
+			tp->coalesce_config.rx_coalesce_ticks =
+				LOW_RXCOL_TICKS;
+			new_vals = 1;
+		}
+	} else if (delta < PKT_RATE_HIGH) {
+		if (tp->coalesce_config.rx_max_coalesced_frames !=
+		    DEFAULT_RXMAX_FRAMES) {
+			tp->coalesce_config.rx_max_coalesced_frames =
+				DEFAULT_RXMAX_FRAMES;
+			tp->coalesce_config.rx_coalesce_ticks =
+				DEFAULT_RXCOL_TICKS;
+			new_vals = 1;
+		}
+	} else {
+		if (tp->coalesce_config.rx_max_coalesced_frames !=
+		    HIGH_RXMAX_FRAMES) {
+			tp->coalesce_config.rx_max_coalesced_frames =
+				HIGH_RXMAX_FRAMES;
+			tp->coalesce_config.rx_coalesce_ticks =
+				HIGH_RXCOL_TICKS;
+			new_vals = 1;
+		}
+	}
+
+	if (new_vals) {
+		tw32(HOSTCC_RXCOL_TICKS,
+		     tp->coalesce_config.rx_coalesce_ticks);
+		tw32(HOSTCC_RXMAX_FRAMES,
+		     tp->coalesce_config.rx_max_coalesced_frames);
+	}
+
+	tp->last_rate_sample = jiffies;
+}
+
+static void tg3_interrupt_main_work(struct tg3 *tp)
+{
+	struct tg3_hw_status *sblk = tp->hw_status;
+	int did_pkts;
+
+	if (!(tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG)) {
+		if (sblk->status & SD_STATUS_LINK_CHG) {
+			sblk->status = SD_STATUS_UPDATED |
+				(sblk->status & ~SD_STATUS_LINK_CHG);
+			tg3_setup_phy(tp);
+		}
+	}
+
+	did_pkts = 0;
+	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
+		tg3_rx(tp);
+		did_pkts = 1;
+	}
+
+	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
+		tg3_tx(tp);
+		did_pkts = 1;
+	}
+
+	if (did_pkts) {
+		unsigned long ticks = jiffies - tp->last_rate_sample;
+
+		if (ticks >= RATE_SAMPLE_INTERVAL)
+			tg3_rate_sample(tp, ticks);
+	}
+}
+
+static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = dev->priv;
+	struct tg3_hw_status *sblk = tp->hw_status;
+
+	spin_lock(&tp->lock);
+
+	while (sblk->status & SD_STATUS_UPDATED) {
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000001);
+		sblk->status &= ~SD_STATUS_UPDATED;
+
+		tg3_interrupt_main_work(tp);
+
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000000);
+		tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
+	}
+
+	spin_unlock(&tp->lock);
+}
+
+static void tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct tg3 *tp = dev->priv;
+	struct tg3_hw_status *sblk = tp->hw_status;
+
+	spin_lock(&tp->lock);
+
+	if (sblk->status & SD_STATUS_UPDATED) {
+		u32 oldtag;
+
+		tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
+			     0x00000001);
+		oldtag = sblk->status_tag;
+
+		while (1) {
+			u32 newtag;
+
+			sblk->status &= ~SD_STATUS_UPDATED;
+			barrier();
+
+			tg3_interrupt_main_work(tp);
+
+			newtag = sblk->status_tag;
+			if (newtag == oldtag) {
+				tw32_mailbox(MAILBOX_INTERRUPT_0 +
+					     TG3_64BIT_REG_LOW,
+					     newtag << 24);
+				break;
+			}
+			oldtag = newtag;
+		}
+	}
+
+	spin_unlock(&tp->lock);
+}
+
+static void tg3_init_rings(struct tg3 *);
+static int tg3_init_hw(struct tg3 *);
+
+static void tg3_tx_timeout(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+
+	printk(KERN_ERR "%s: transmit timed out, resetting\n",
+	       dev->name);
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_halt(tp);
+	tg3_init_rings(tp);
+	tg3_init_hw(tp);
+
+	spin_unlock_irq(&tp->lock);
+
+	netif_wake_queue(dev);
+}
+
+#if !PCI_DMA_BUS_IS_PHYS
+static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
+{
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
+
+		txd->addr_hi = ((u64) mapping >> 32);
+		txd->addr_lo = ((u64) mapping & 0xffffffff);
+	} else {
+		unsigned long txd;
+
+		txd = (tp->regs +
+		       NIC_SRAM_WIN_BASE +
+		       NIC_SRAM_TX_BUFFER_DESC);
+		txd += (entry * TXD_SIZE);
+
+		writel(((u64) mapping >> 32),
+		       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+
+		writel(((u64) mapping & 0xffffffff),
+		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
+	}
+}
+#endif
+
+static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int);
+
+static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
+				       u32 guilty_entry, int guilty_len,
+				       u32 last_plus_one, u32 *start)
+{
+	dma_addr_t new_addr;
+	u32 entry = *start;
+	int i;
+
+#if !PCI_DMA_BUS_IS_PHYS
+	/* IOMMU, just map the guilty area again which is guarenteed to
+	 * use different addresses.
+	 */
+
+	i = 0;
+	while (entry != guilty_entry) {
+		entry = NEXT_TX(entry);
+		i++;
+	}
+	if (i == 0) {
+		new_addr = pci_map_single(tp->pdev, skb->data, guilty_len,
+					  PCI_DMA_TODEVICE);
+	} else {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i - 1];
+
+		new_addr = pci_map_page(tp->pdev,
+					frag->page, frag->page_offset,
+					guilty_len, PCI_DMA_TODEVICE);
+	}
+	pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping,
+			 guilty_len, PCI_DMA_TODEVICE);
+	tg3_set_txd_addr(tp, guilty_entry, new_addr);
+	tp->tx_buffers[guilty_entry].mapping = new_addr;
+	*start = last_plus_one;
+#else
+	/* Oh well, no IOMMU, have to allocate a whole new SKB. */
+	struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC);
+
+	if (!new_skb) {
+		dev_kfree_skb(skb);
+		return -1;
+	}
+
+	/* NOTE: Broadcom's driver botches this case up really bad.
+	 *       This is especially true if any of the frag pages
+	 *       are in highmem.  It will instantly oops in that case.
+	 */
+
+	/* New SKB is guarenteed to be linear. */
+	entry = *start;
+	new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
+				  PCI_DMA_TODEVICE);
+	tg3_set_txd(tp, entry, new_addr, new_skb->len,
+		    (skb->ip_summed == CHECKSUM_HW) ?
+		    TXD_FLAG_TCPUDP_CSUM : 0, 1);
+	*start = NEXT_TX(entry);
+
+	/* Now clean up the sw ring entries. */
+	i = 0;
+	while (entry != last_plus_one) {
+		int len;
+
+		if (i == 0)
+			len = skb->len - skb->data_len;
+		else
+			len = skb_shinfo(skb)->frags[i-1].size;
+		pci_unmap_single(tp->pdev, tp->tx_buffers[entry].mapping,
+				 len, PCI_DMA_TODEVICE);
+		if (i == 0) {
+			tp->tx_buffers[entry].skb = new_skb;
+			tp->tx_buffers[entry].mapping = new_addr;
+		} else {
+			tp->tx_buffers[entry].skb = NULL;
+		}
+		entry = NEXT_TX(entry);
+	}
+
+	dev_kfree_skb(skb);
+#endif
+
+	return 0;
+}
+
+static void tg3_set_txd(struct tg3 *tp, int entry,
+			dma_addr_t mapping, int len, u32 flags,
+			int is_end)
+{
+#if TG3_VLAN_TAG_USED
+	u16 vlan_tag = 0;
+#endif
+
+	if (is_end)
+		flags |= TXD_FLAG_END;
+#if TG3_VLAN_TAG_USED
+	if (flags & TXD_FLAG_VLAN) {
+		vlan_tag = flags >> 16;
+		flags &= 0xffff;
+	}
+#endif
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry];
+
+		txd->addr_hi = ((u64) mapping >> 32);
+		txd->addr_lo = ((u64) mapping & 0xffffffff);
+		txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+#if TG3_VLAN_TAG_USED
+		txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
+#endif
+	} else {
+		unsigned long txd;
+
+		txd = (tp->regs +
+		       NIC_SRAM_WIN_BASE +
+		       NIC_SRAM_TX_BUFFER_DESC);
+		txd += (entry * TXD_SIZE);
+
+		/* Save some PIOs */
+		if (((u64) tp->tx_buffers[entry].mapping >> 32) !=
+		    ((u64) mapping >> 32))
+			writel(((u64) mapping >> 32),
+			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+
+		writel(((u64) mapping & 0xffffffff),
+		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
+		writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS);
+#if TG3_VLAN_TAG_USED
+		writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG);
+#endif
+	}
+}
+
+static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
+{
+	u32 base = (u32) mapping & 0xffffffff;
+
+	return ((base > 0xffffdcc0) &&
+		((u64) mapping >> 32) == 0 &&
+		(base + len + 8 < base));
+}
+
+static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	dma_addr_t mapping;
+	unsigned int i;
+	u32 len, entry, base_flags;
+	int would_hit_hwbug;
+
+	len = (skb->len - skb->data_len);
+
+	spin_lock_irq(&tp->lock);
+
+	/* This is a hard error, log it. */
+	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&tp->lock);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
+		return 1;
+	}
+
+	entry = tp->tx_prod;
+	base_flags = 0;
+	if (skb->ip_summed == CHECKSUM_HW)
+		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_VLAN_TAG_USED
+	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+		base_flags |= (TXD_FLAG_VLAN |
+			       (vlan_tx_tag_get(skb) << 16));
+#endif
+
+	/* Queue skb data, a.k.a. the main skb fragment. */
+	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+	tp->tx_buffers[entry].skb = skb;
+	tp->tx_buffers[entry].mapping = mapping;
+
+	would_hit_hwbug = tg3_4g_overflow_test(mapping, len);
+
+	tg3_set_txd(tp, entry, mapping, len, base_flags,
+		    (skb_shinfo(skb)->nr_frags == 0));
+
+	entry = NEXT_TX(entry);
+
+	/* Now loop through additional data fragments, and queue them. */
+	if (skb_shinfo(skb)->nr_frags > 0) {
+		unsigned int i, last;
+
+		last = skb_shinfo(skb)->nr_frags - 1;
+		for (i = 0; i <= last; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			len = frag->size;
+			mapping = pci_map_page(tp->pdev,
+					       frag->page,
+					       frag->page_offset,
+					       len, PCI_DMA_TODEVICE);
+
+			tp->tx_buffers[entry].skb = NULL;
+			tp->tx_buffers[entry].mapping = mapping;
+
+			would_hit_hwbug |=
+				tg3_4g_overflow_test(mapping, len);
+
+			tg3_set_txd(tp, entry, mapping, len,
+				    base_flags, (i == last));
+
+			entry = NEXT_TX(entry);
+		}
+	}
+
+	if (would_hit_hwbug) {
+		u32 last_plus_one = entry;
+		u32 start;
+		unsigned int len = 0;
+
+		entry = entry - 1 - skb_shinfo(skb)->nr_frags;
+		entry &= (TG3_TX_RING_SIZE - 1);
+		start = entry;
+		i = 0;
+		while (entry != last_plus_one) {
+			dma_addr_t mapping = tp->tx_buffers[entry].mapping;
+
+			if (i == 0)
+				len = skb->len - skb->data_len;
+			else
+				len = skb_shinfo(skb)->frags[i-1].size;
+
+			if (tg3_4g_overflow_test(mapping, len))
+				break;
+
+			i++;
+			entry = NEXT_TX(entry);
+
+		}
+
+		/* If the workaround fails due to memory/mapping
+		 * failure, silently drop this packet.
+		 */
+		if (tigon3_4gb_hwbug_workaround(tp, skb,
+						entry, len,
+						last_plus_one,
+						&start))
+			goto out_unlock;
+
+		entry = start;
+	}
+
+	/* Packets are ready, update Tx producer idx local and on card. */
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
+			      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
+			tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
+				      TG3_64BIT_REG_LOW), entry);
+	} else {
+		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
+			      TG3_64BIT_REG_LOW), entry);
+		if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
+			tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
+				      TG3_64BIT_REG_LOW), entry);
+	}
+
+	tp->tx_prod = entry;
+	if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
+		netif_stop_queue(dev);
+
+out_unlock:
+	spin_unlock_irq(&tp->lock);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	dma_addr_t mapping;
+	u32 len, entry, base_flags;
+
+	len = (skb->len - skb->data_len);
+
+	spin_lock_irq(&tp->lock);
+
+	/* This is a hard error, log it. */
+	if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&tp->lock);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
+		return 1;
+	}
+
+	entry = tp->tx_prod;
+	base_flags = 0;
+	if (skb->ip_summed == CHECKSUM_HW)
+		base_flags |= TXD_FLAG_TCPUDP_CSUM;
+#if TG3_VLAN_TAG_USED
+	if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
+		base_flags |= (TXD_FLAG_VLAN |
+			       (vlan_tx_tag_get(skb) << 16));
+#endif
+
+	/* Queue skb data, a.k.a. the main skb fragment. */
+	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+	tp->tx_buffers[entry].skb = skb;
+	tp->tx_buffers[entry].mapping = mapping;
+
+	tg3_set_txd(tp, entry, mapping, len, base_flags,
+		    (skb_shinfo(skb)->nr_frags == 0));
+
+	entry = NEXT_TX(entry);
+
+	/* Now loop through additional data fragments, and queue them. */
+	if (skb_shinfo(skb)->nr_frags > 0) {
+		unsigned int i, last;
+
+		last = skb_shinfo(skb)->nr_frags - 1;
+		for (i = 0; i <= last; i++) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+
+			len = frag->size;
+			mapping = pci_map_page(tp->pdev,
+					       frag->page,
+					       frag->page_offset,
+					       len, PCI_DMA_TODEVICE);
+
+			tp->tx_buffers[entry].skb = NULL;
+			tp->tx_buffers[entry].mapping = mapping;
+
+			tg3_set_txd(tp, entry, mapping, len,
+				    base_flags, (i == last));
+
+			entry = NEXT_TX(entry);
+		}
+	}
+
+	/* Packets are ready, update Tx producer idx local and on card.
+	 * We know this is not a 5700 (by virtue of not being a chip
+	 * requiring the 4GB overflow workaround) so we can safely omit
+	 * the double-write bug tests.
+	 */
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 +
+			      TG3_64BIT_REG_LOW), entry);
+	} else {
+		tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 +
+			      TG3_64BIT_REG_LOW), entry);
+	}
+
+	tp->tx_prod = entry;
+	if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&tp->lock);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+static int tg3_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct tg3 *tp = dev->priv;
+
+	if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU)
+		return -EINVAL;
+
+	if (!netif_running(dev)) {
+		/* We'll just catch it later when the
+		 * device is up'd.
+		 */
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_halt(tp);
+
+	dev->mtu = new_mtu;
+
+	if (new_mtu > ETH_DATA_LEN)
+		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_JUMBO_ENABLE;
+
+	tg3_init_rings(tp);
+	tg3_init_hw(tp);
+
+	spin_unlock_irq(&tp->lock);
+
+	return 0;
+}
+
+/* Free up pending packets in all rx/tx rings.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  tp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void tg3_free_rings(struct tg3 *tp)
+{
+	struct ring_info *rxp;
+	int i;
+
+	for (i = 0; i < TG3_RX_RING_SIZE; i++) {
+		rxp = &tp->rx_std_buffers[i];
+
+		if (rxp->skb == NULL)
+			continue;
+		pci_unmap_single(tp->pdev, rxp->mapping,
+				 RX_PKT_BUF_SZ - tp->rx_offset,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(rxp->skb);
+		rxp->skb = NULL;
+	}
+#if TG3_MINI_RING_WORKS
+	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
+		rxp = &tp->rx_mini_buffers[i];
+
+		if (rxp->skb == NULL)
+			continue;
+		pci_unmap_single(tp->pdev, rxp->mapping,
+				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(rxp->skb);
+		rxp->skb = NULL;
+	}
+#endif
+	for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
+		rxp = &tp->rx_jumbo_buffers[i];
+
+		if (rxp->skb == NULL)
+			continue;
+		pci_unmap_single(tp->pdev, rxp->mapping,
+				 RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb(rxp->skb);
+		rxp->skb = NULL;
+	}
+
+	for (i = 0; i < TG3_TX_RING_SIZE; ) {
+		struct ring_info *txp;
+		struct sk_buff *skb;
+		int j;
+
+		txp = &tp->tx_buffers[i];
+		skb = txp->skb;
+
+		if (skb == NULL) {
+			i++;
+			continue;
+		}
+
+		pci_unmap_single(tp->pdev, txp->mapping,
+				 (skb->len - skb->data_len),
+				 PCI_DMA_TODEVICE);
+		txp->skb = NULL;
+
+		i++;
+
+		for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
+			txp = &tp->tx_buffers[i & (TG3_TX_RING_SIZE - 1)];
+			pci_unmap_page(tp->pdev, txp->mapping,
+				       skb_shinfo(skb)->frags[j].size,
+				       PCI_DMA_TODEVICE);
+			i++;
+		}
+
+		dev_kfree_skb_any(skb);
+	}
+}
+
+/* Initialize tx/rx rings for packet processing.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  tp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void tg3_init_rings(struct tg3 *tp)
+{
+	unsigned long start, end;
+	u32 i;
+
+	/* Free up all the SKBs. */
+	tg3_free_rings(tp);
+
+	/* Zero out all descriptors. */
+	memset(tp->rx_std, 0, TG3_RX_RING_BYTES);
+#if TG3_MINI_RING_WORKS
+	memset(tp->rx_mini, 0, TG3_RX_MINI_RING_BYTES);
+#endif
+	memset(tp->rx_jumbo, 0, TG3_RX_JUMBO_RING_BYTES);
+	memset(tp->rx_rcb, 0, TG3_RX_RCB_RING_BYTES);
+
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		memset(tp->tx_ring, 0, TG3_TX_RING_BYTES);
+	} else {
+		start = (tp->regs +
+			 NIC_SRAM_WIN_BASE +
+			 NIC_SRAM_TX_BUFFER_DESC);
+		end = start + TG3_TX_RING_BYTES;
+		while (start < end) {
+			writel(0, start);
+			start += 4;
+		}
+	}
+
+	/* Initialize invariants of the rings, we only set this
+	 * stuff once.  This works because the card does not
+	 * write into the rx buffer posting rings.
+	 */
+	for (i = 0; i < TG3_RX_RING_SIZE; i++) {
+		struct tg3_rx_buffer_desc *rxd;
+
+		rxd = &tp->rx_std[i];
+		rxd->idx_len = (RX_PKT_BUF_SZ - tp->rx_offset - 64)
+			<< RXD_LEN_SHIFT;
+		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT);
+		rxd->opaque = (RXD_OPAQUE_RING_STD |
+			       (i << RXD_OPAQUE_INDEX_SHIFT));
+	}
+#if TG3_MINI_RING_WORKS
+	for (i = 0; i < TG3_RX_MINI_RING_SIZE; i++) {
+		struct tg3_rx_buffer_desc *rxd;
+
+		rxd = &tp->rx_mini[i];
+		rxd->idx_len = (RX_MINI_PKT_BUF_SZ - tp->rx_offset - 64)
+			<< RXD_LEN_SHIFT;
+		rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
+			RXD_FLAG_MINI;
+		rxd->opaque = (RXD_OPAQUE_RING_MINI |
+			       (i << RXD_OPAQUE_INDEX_SHIFT));
+	}
+#endif
+	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
+		for (i = 0; i < TG3_RX_JUMBO_RING_SIZE; i++) {
+			struct tg3_rx_buffer_desc *rxd;
+
+			rxd = &tp->rx_jumbo[i];
+			rxd->idx_len = (RX_JUMBO_PKT_BUF_SZ - tp->rx_offset - 64)
+				<< RXD_LEN_SHIFT;
+			rxd->type_flags = (RXD_FLAG_END << RXD_FLAGS_SHIFT) |
+				RXD_FLAG_JUMBO;
+			rxd->opaque = (RXD_OPAQUE_RING_JUMBO |
+			       (i << RXD_OPAQUE_INDEX_SHIFT));
+		}
+	}
+
+	/* Now allocate fresh SKBs for each rx ring. */
+	for (i = 0; i < TG3_RX_RING_PENDING; i++) {
+		if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD,
+				     -1, i) < 0)
+			break;
+	}
+
+#if TG3_MINI_RING_WORKS
+	for (i = 0; i < TG3_RX_MINI_RING_PENDING; i++) {
+		if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_MINI,
+				     -1, i) < 0)
+			break;
+	}
+#endif
+
+	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
+		for (i = 0; i < TG3_RX_JUMBO_RING_PENDING; i++) {
+			if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
+					     -1, i) < 0)
+				break;
+		}
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.
+ */
+static void tg3_free_consistent(struct tg3 *tp)
+{
+	if (tp->rx_std_buffers) {
+		kfree(tp->rx_std_buffers);
+		tp->rx_std_buffers = NULL;
+	}
+	if (tp->rx_std) {
+		pci_free_consistent(tp->pdev, TG3_RX_RING_BYTES,
+				    tp->rx_std, tp->rx_std_mapping);
+		tp->rx_std = NULL;
+	}
+#if TG3_MINI_RING_WORKS
+	if (tp->rx_mini) {
+		pci_free_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
+				    tp->rx_mini, tp->rx_mini_mapping);
+		tp->rx_mini = NULL;
+	}
+#endif
+	if (tp->rx_jumbo) {
+		pci_free_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
+				    tp->rx_jumbo, tp->rx_jumbo_mapping);
+		tp->rx_jumbo = NULL;
+	}
+	if (tp->rx_rcb) {
+		pci_free_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES,
+				    tp->rx_rcb, tp->rx_rcb_mapping);
+		tp->rx_rcb = NULL;
+	}
+	if (tp->tx_ring) {
+		pci_free_consistent(tp->pdev, TG3_TX_RING_BYTES,
+			tp->tx_ring, tp->tx_desc_mapping);
+		tp->tx_ring = NULL;
+	}
+	if (tp->hw_status) {
+		pci_free_consistent(tp->pdev, TG3_HW_STATUS_SIZE,
+				    tp->hw_status, tp->status_mapping);
+		tp->hw_status = NULL;
+	}
+	if (tp->hw_stats) {
+		pci_free_consistent(tp->pdev, sizeof(struct tg3_hw_stats),
+				    tp->hw_stats, tp->stats_mapping);
+		tp->hw_stats = NULL;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.  Can sleep.
+ */
+static int tg3_alloc_consistent(struct tg3 *tp)
+{
+	tp->rx_std_buffers = kmalloc(sizeof(struct ring_info) *
+				     (TG3_RX_RING_SIZE +
+#if TG3_MINI_RING_WORKS
+				      TG3_RX_MINI_RING_SIZE +
+#endif
+				      TG3_RX_JUMBO_RING_SIZE +
+				      TG3_TX_RING_SIZE),
+				     GFP_KERNEL);
+	if (!tp->rx_std_buffers)
+		return -ENOMEM;
+
+#if TG3_MINI_RING_WORKS
+	memset(tp->rx_std_buffers, 0,
+	       (sizeof(struct ring_info) *
+		(TG3_RX_RING_SIZE +
+		 TG3_RX_MINI_RING_SIZE +
+		 TG3_RX_JUMBO_RING_SIZE +
+		 TG3_TX_RING_SIZE)));
+#else
+	memset(tp->rx_std_buffers, 0,
+	       (sizeof(struct ring_info) *
+		(TG3_RX_RING_SIZE +
+		 TG3_RX_JUMBO_RING_SIZE +
+		 TG3_TX_RING_SIZE)));
+#endif
+
+#if TG3_MINI_RING_WORKS
+	tp->rx_mini_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
+	tp->rx_jumbo_buffers = &tp->rx_mini_buffers[TG3_RX_MINI_RING_SIZE];
+#else
+	tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE];
+#endif
+	tp->tx_buffers = &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE];
+
+	tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES,
+					  &tp->rx_std_mapping);
+	if (!tp->rx_std)
+		goto err_out;
+
+#if TG3_MINI_RING_WORKS
+	tp->rx_mini = pci_alloc_consistent(tp->pdev, TG3_RX_MINI_RING_BYTES,
+					   &tp->rx_mini_mapping);
+
+	if (!tp->rx_mini)
+		goto err_out;
+#endif
+
+	tp->rx_jumbo = pci_alloc_consistent(tp->pdev, TG3_RX_JUMBO_RING_BYTES,
+					    &tp->rx_jumbo_mapping);
+
+	if (!tp->rx_jumbo)
+		goto err_out;
+
+	tp->rx_rcb = pci_alloc_consistent(tp->pdev, TG3_RX_RCB_RING_BYTES,
+					  &tp->rx_rcb_mapping);
+	if (!tp->rx_rcb)
+		goto err_out;
+
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		tp->tx_ring = pci_alloc_consistent(tp->pdev, TG3_TX_RING_BYTES,
+						   &tp->tx_desc_mapping);
+		if (!tp->tx_ring)
+			goto err_out;
+	} else {
+		tp->tx_ring = NULL;
+		tp->tx_desc_mapping = 0;
+	}
+
+	tp->hw_status = pci_alloc_consistent(tp->pdev,
+					     TG3_HW_STATUS_SIZE,
+					     &tp->status_mapping);
+	if (!tp->hw_status)
+		goto err_out;
+
+	tp->hw_stats = pci_alloc_consistent(tp->pdev,
+					    sizeof(struct tg3_hw_stats),
+					    &tp->stats_mapping);
+	if (!tp->hw_stats)
+		goto err_out;
+
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+	memset(tp->hw_stats, 0, sizeof(struct tg3_hw_stats));
+
+	return 0;
+
+err_out:
+	tg3_free_consistent(tp);
+	return -ENOMEM;
+}
+
+#define MAX_WAIT_CNT 10000
+
+/* To stop a block, clear the enable bit and poll till it
+ * clears.  tp->lock is held.
+ */
+static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit)
+{
+	unsigned int i;
+	u32 val;
+
+	val = tr32(ofs);
+	val &= ~enable_bit;
+	tw32(ofs, val);
+
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		val = tr32(ofs);
+
+		if ((val & enable_bit) == 0)
+			break;
+		udelay(100);
+	}
+
+	if (i == MAX_WAIT_CNT) {
+		printk(KERN_ERR PFX "tg3_stop_block timed out, "
+		       "ofs=%lx enable_bit=%x\n",
+		       ofs, enable_bit);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* tp->lock is held. */
+static int tg3_abort_hw(struct tg3 *tp)
+{
+	int i, err;
+
+	tg3_disable_ints(tp);
+
+	tp->rx_mode &= ~RX_MODE_ENABLE;
+	tw32(MAC_RX_MODE, tp->rx_mode);
+
+	err  = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVLSC_MODE, RCVLSC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDBDI_MODE, RCVDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVDCC_MODE, RCVDCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RCVCC_MODE, RCVCC_MODE_ENABLE);
+
+	err |= tg3_stop_block(tp, SNDBDS_MODE, SNDBDS_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDI_MODE, SNDBDI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+	err |= tg3_stop_block(tp, RDMAC_MODE, RDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, SNDBDC_MODE, SNDBDC_MODE_ENABLE);
+	if (err)
+		goto out;
+
+	tp->mac_mode &= ~MAC_MODE_TDE_ENABLE;
+	tw32(MAC_MODE, tp->mac_mode);
+
+	tp->tx_mode &= ~TX_MODE_ENABLE;
+	tw32(MAC_TX_MODE, tp->tx_mode);
+	for (i = 0; i < MAX_WAIT_CNT; i++) {
+		udelay(100);
+		if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE))
+			break;
+	}
+	if (i >= MAX_WAIT_CNT) {
+		printk(KERN_ERR PFX "tg3_abort_hw timed out for %s, "
+		       "TX_MODE_ENABLE will not clear MAC_TX_MODE=%08x\n",
+		       tp->dev->name, tr32(MAC_TX_MODE));
+		return -ENODEV;
+	}
+
+	err  = tg3_stop_block(tp, HOSTCC_MODE, HOSTCC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, WDMAC_MODE, WDMAC_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MBFREE_MODE, MBFREE_MODE_ENABLE);
+
+	tw32(FTQ_RESET, 0xffffffff);
+	tw32(FTQ_RESET, 0x00000000);
+
+	err |= tg3_stop_block(tp, BUFMGR_MODE, BUFMGR_MODE_ENABLE);
+	err |= tg3_stop_block(tp, MEMARB_MODE, MEMARB_MODE_ENABLE);
+	if (err)
+		goto out;
+
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+out:
+	return err;
+}
+
+/* tp->lock is held. */
+static void tg3_chip_reset(struct tg3 *tp)
+{
+	u32 val;
+
+	/* Force NVRAM to settle.
+	 * This deals with a chip bug which can result in EEPROM
+	 * corruption.
+	 */
+	if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+		int i;
+
+		tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+		for (i = 0; i < 100000; i++) {
+			if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+				break;
+			udelay(10);
+		}
+	}
+
+	tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET);
+	udelay(40);
+	udelay(40);
+	udelay(40);
+
+	/* Re-enable indirect register accesses. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* Set MAX PCI retry to zero. */
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			       (PCISTATE_ROM_ENABLE |
+				PCISTATE_ROM_RETRY_ENABLE));
+
+	pci_restore_state(tp->pdev, tp->pci_cfg_state);
+
+	/* Make sure PCI-X relaxed ordering bit is clear. */
+	pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
+	val &= ~PCIX_CAPS_RELAXED_ORDERING;
+	pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+
+	tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+
+	tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
+}
+
+/* tp->lock is held. */
+static int tg3_halt(struct tg3 *tp)
+{
+	u32 val;
+	int i;
+
+	tg3_abort_hw(tp);
+	tg3_chip_reset(tp);
+	tg3_write_mem(tp,
+		      NIC_SRAM_FIRMWARE_MBOX,
+		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+	for (i = 0; i < 100000; i++) {
+		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+			break;
+		udelay(10);
+	}
+
+	if (i >= 100000) {
+		printk(KERN_ERR PFX "tg3_halt timed out for %s, "
+		       "firmware will not restart magic=%08x\n",
+		       tp->dev->name, val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+#define TG3_FW_RELEASE_MAJOR	0x0
+#define TG3_FW_RELASE_MINOR	0x0
+#define TG3_FW_RELEASE_FIX	0x0
+#define TG3_FW_START_ADDR	0x08000000
+#define TG3_FW_TEXT_ADDR	0x08000000
+#define TG3_FW_TEXT_LEN		0x9c0
+#define TG3_FW_RODATA_ADDR	0x080009c0
+#define TG3_FW_RODATA_LEN	0x60
+#define TG3_FW_DATA_ADDR	0x08000a40
+#define TG3_FW_DATA_LEN		0x20
+#define TG3_FW_SBSS_ADDR	0x08000a60
+#define TG3_FW_SBSS_LEN		0xc
+#define TG3_FW_BSS_ADDR		0x08000a70
+#define TG3_FW_BSS_LEN		0x10
+
+static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
+	0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
+	0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
+	0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
+	0x0e00021c, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, 0x00000000,
+	0x27bdffe0, 0x3c1cc000, 0xafbf0018, 0xaf80680c, 0x0e00004c, 0x241b2105,
+	0x97850000, 0x97870002, 0x9782002c, 0x9783002e, 0x3c040800, 0x248409c0,
+	0xafa00014, 0x00021400, 0x00621825, 0x00052c00, 0xafa30010, 0x8f860010,
+	0x00e52825, 0x0e000060, 0x24070102, 0x3c02ac00, 0x34420100, 0x3c03ac01,
+	0x34630100, 0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498, 0xaf82049c,
+	0x24020001, 0xaf825ce0, 0x0e00003f, 0xaf825d00, 0x0e000140, 0x00000000,
+	0x8fbf0018, 0x03e00008, 0x27bd0020, 0x2402ffff, 0xaf825404, 0x8f835400,
+	0x34630400, 0xaf835400, 0xaf825404, 0x3c020800, 0x24420034, 0xaf82541c,
+	0x03e00008, 0xaf805400, 0x00000000, 0x00000000, 0x3c020800, 0x34423000,
+	0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac220a64,
+	0x24020040, 0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60, 0xac600000,
+	0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
+	0x00804821, 0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800, 0x8c840a68,
+	0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac230a60, 0x14400003,
+	0x00004021, 0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60, 0x3c030800,
+	0x8c630a64, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
+	0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c420a60,
+	0x3c030800, 0x8c630a64, 0x8f84680c, 0x00021140, 0x00431021, 0xac440008,
+	0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0,
+	0x02000008, 0x00000000, 0x0a0001e3, 0x3c0a0001, 0x0a0001e3, 0x3c0a0002,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x3c0a0007, 0x0a0001e3, 0x3c0a0008, 0x0a0001e3, 0x3c0a0009,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000b,
+	0x0a0001e3, 0x3c0a000c, 0x0a0001e3, 0x3c0a000d, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000e, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
+	0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a0013, 0x0a0001e3, 0x3c0a0014,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0x27bdffe0, 0x00001821, 0x00001021, 0xafbf0018, 0xafb10014, 0xafb00010,
+	0x3c010800, 0x00220821, 0xac200a70, 0x3c010800, 0x00220821, 0xac200a74,
+	0x3c010800, 0x00220821, 0xac200a78, 0x24630001, 0x1860fff5, 0x2442000c,
+	0x24110001, 0x8f906810, 0x32020004, 0x14400005, 0x24040001, 0x3c020800,
+	0x8c420a78, 0x18400003, 0x00002021, 0x0e000182, 0x00000000, 0x32020001,
+	0x10400003, 0x00000000, 0x0e000169, 0x00000000, 0x0a000153, 0xaf915028,
+	0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c050800,
+	0x8ca50a70, 0x3c060800, 0x8cc60a80, 0x3c070800, 0x8ce70a78, 0x27bdffe0,
+	0x3c040800, 0x248409d0, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014,
+	0x0e00017b, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x24020001,
+	0x8f836810, 0x00821004, 0x00021027, 0x00621824, 0x03e00008, 0xaf836810,
+	0x27bdffd8, 0xafbf0024, 0x1080002e, 0xafb00020, 0x8f825cec, 0xafa20018,
+	0x8f825cec, 0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000, 0xaf825cec,
+	0x8e020000, 0x18400016, 0x00000000, 0x3c020800, 0x94420a74, 0x8fa3001c,
+	0x000221c0, 0xac830004, 0x8fa2001c, 0x3c010800, 0x0e000201, 0xac220a74,
+	0x10400005, 0x00000000, 0x8e020000, 0x24420001, 0x0a0001df, 0xae020000,
+	0x3c020800, 0x8c420a70, 0x00021c02, 0x000321c0, 0x0a0001c5, 0xafa2001c,
+	0x0e000201, 0x00000000, 0x1040001f, 0x00000000, 0x8e020000, 0x8fa3001c,
+	0x24420001, 0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74, 0x0a0001df,
+	0xae020000, 0x3c100800, 0x26100a78, 0x8e020000, 0x18400028, 0x00000000,
+	0x0e000201, 0x00000000, 0x14400024, 0x00000000, 0x8e020000, 0x3c030800,
+	0x8c630a70, 0x2442ffff, 0xafa3001c, 0x18400006, 0xae020000, 0x00031402,
+	0x000221c0, 0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e, 0x2442ff00,
+	0x2c420300, 0x1440000b, 0x24024000, 0x3c040800, 0x248409dc, 0xafa00010,
+	0xafa00014, 0x8fa6001c, 0x24050008, 0x0e000060, 0x00003821, 0x0a0001df,
+	0x00000000, 0xaf825cf8, 0x3c020800, 0x8c420a40, 0x8fa3001c, 0x24420001,
+	0xaf835cf8, 0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020, 0x03e00008,
+	0x27bd0028, 0x27bdffe0, 0x3c040800, 0x248409e8, 0x00002821, 0x00003021,
+	0x00003821, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x8fbf0018,
+	0x03e00008, 0x27bd0020, 0x8f82680c, 0x8f85680c, 0x00021827, 0x0003182b,
+	0x00031823, 0x00431024, 0x00441021, 0x00a2282b, 0x10a00006, 0x00000000,
+	0x00401821, 0x8f82680c, 0x0043102b, 0x1440fffd, 0x00000000, 0x03e00008,
+	0x00000000, 0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40, 0x0064102b,
+	0x54400002, 0x00831023, 0x00641023, 0x2c420008, 0x03e00008, 0x38420001,
+	0x27bdffe0, 0x00802821, 0x3c040800, 0x24840a00, 0x00003021, 0x00003821,
+	0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x0a000216, 0x00000000,
+	0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000, 0x27bdffe0, 0x3c1cc000,
+	0xafbf0018, 0x0e00004c, 0xaf80680c, 0x3c040800, 0x24840a10, 0x03802821,
+	0x00003021, 0x00003821, 0xafa00010, 0x0e000060, 0xafa00014, 0x2402ffff,
+	0xaf825404, 0x3c0200aa, 0x0e000234, 0xaf825434, 0x8fbf0018, 0x03e00008,
+	0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe8, 0xafb00010,
+	0x24100001, 0xafbf0014, 0x3c01c003, 0xac200000, 0x8f826810, 0x30422000,
+	0x10400003, 0x00000000, 0x0e000246, 0x00000000, 0x0a00023a, 0xaf905428,
+	0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdfff8, 0x8f845d0c,
+	0x3c0200ff, 0x3c030800, 0x8c630a50, 0x3442fff8, 0x00821024, 0x1043001e,
+	0x3c0500ff, 0x34a5fff8, 0x3c06c003, 0x3c074000, 0x00851824, 0x8c620010,
+	0x3c010800, 0xac230a50, 0x30420008, 0x10400005, 0x00871025, 0x8cc20000,
+	0x24420001, 0xacc20000, 0x00871025, 0xaf825d0c, 0x8fa20000, 0x24420001,
+	0xafa20000, 0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000, 0x8fa20000,
+	0x8f845d0c, 0x3c030800, 0x8c630a50, 0x00851024, 0x1443ffe8, 0x00851824,
+	0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
+};
+
+static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
+	0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
+	0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
+	0x00000000, 0x00000000, 0x4d61696e, 0x43707542, 0x00000000, 0x00000000,
+	0x00000000
+};
+
+#if 0 /* All zeros, dont eat up space with it. */
+u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+#endif
+
+#define RX_CPU_SCRATCH_BASE	0x30000
+#define RX_CPU_SCRATCH_SIZE	0x04000
+#define TX_CPU_SCRATCH_BASE	0x34000
+#define TX_CPU_SCRATCH_SIZE	0x04000
+
+/* tp->lock is held. */
+static int tg3_reset_cpu(struct tg3 *tp, u32 offset)
+{
+	int i;
+
+	tw32(offset + CPU_STATE, 0xffffffff);
+	tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+	if (offset == RX_CPU_BASE) {
+		for (i = 0; i < 10000; i++)
+			if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET))
+				break;
+		tw32(offset + CPU_STATE, 0xffffffff);
+		tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+		udelay(10);
+	} else {
+		for (i = 0; i < 10000; i++) {
+			if (!(tr32(offset + CPU_MODE) & CPU_MODE_RESET))
+				break;
+			tw32(offset + CPU_STATE, 0xffffffff);
+			tw32(offset + CPU_MODE,  CPU_MODE_RESET);
+			udelay(10);
+		}
+	}
+
+	if (i >= 10000) {
+		printk(KERN_ERR PFX "tg3_reset_cpu timed out for %s, "
+		       "and %s CPU\n",
+		       tp->dev->name,
+		       (offset == RX_CPU_BASE ? "RX" : "TX"));
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* tp->lock is held. */
+static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base,
+				 int cpu_scratch_size)
+{
+	int err, i;
+
+	err = tg3_reset_cpu(tp, cpu_base);
+	if (err)
+		return err;
+
+	for (i = 0; i < cpu_scratch_size; i += sizeof(u32))
+		tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0);
+	tw32(cpu_base + CPU_STATE, 0xffffffff);
+	tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
+	for (i = 0; i < (TG3_FW_TEXT_LEN / sizeof(u32)); i++)
+		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
+					      (TG3_FW_TEXT_ADDR & 0xffff) +
+					      (i * sizeof(u32))),
+					 t3FwText[i]);
+	for (i = 0; i < (TG3_FW_RODATA_LEN / sizeof(u32)); i++)
+		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
+					      (TG3_FW_RODATA_ADDR & 0xffff) +
+					      (i * sizeof(u32))),
+					 t3FwRodata[i]);
+	for (i = 0; i < (TG3_FW_DATA_LEN / sizeof(u32)); i++)
+		tg3_write_indirect_reg32(tp, (cpu_scratch_base +
+					      (TG3_FW_DATA_ADDR & 0xffff) +
+					      (i * sizeof(u32))),
+					 0);
+
+	return 0;
+}
+
+/* tp->lock is held. */
+static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
+{
+	int err, i;
+
+	err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
+				    RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE);
+	if (err)
+		return err;
+
+	err = tg3_load_firmware_cpu(tp, TX_CPU_BASE,
+				    TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE);
+	if (err)
+		return err;
+
+	/* Now startup only the RX cpu. */
+	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(RX_CPU_BASE + CPU_PC,    TG3_FW_TEXT_ADDR);
+	for (i = 0; i < 5; i++) {
+		if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR)
+			break;
+		tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+		tw32(RX_CPU_BASE + CPU_MODE,  CPU_MODE_HALT);
+		tw32(RX_CPU_BASE + CPU_PC,    TG3_FW_TEXT_ADDR);
+		udelay(1000);
+	}
+	if (i >= 5) {
+		printk(KERN_ERR PFX "tg3_load_firmware fails for %s "
+		       "to set RX CPU PC, is %08x should be %08x\n",
+		       tp->dev->name, tr32(RX_CPU_BASE + CPU_PC),
+		       TG3_FW_TEXT_ADDR);
+		return -ENODEV;
+	}
+	tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
+	tw32(RX_CPU_BASE + CPU_MODE,  0x00000000);
+
+	return 0;
+}
+
+/* tp->lock is held. */
+static void __tg3_set_mac_addr(struct tg3 *tp)
+{
+	u32 addr_high, addr_low;
+	int i;
+
+	addr_high = ((tp->dev->dev_addr[0] << 8) |
+		     tp->dev->dev_addr[1]);
+	addr_low = ((tp->dev->dev_addr[2] << 24) |
+		    (tp->dev->dev_addr[3] << 16) |
+		    (tp->dev->dev_addr[4] <<  8) |
+		    (tp->dev->dev_addr[5] <<  0));
+	for (i = 0; i < 4; i++) {
+		tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
+		tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
+	}
+
+	addr_high = (tp->dev->dev_addr[0] +
+		     tp->dev->dev_addr[1] +
+		     tp->dev->dev_addr[2] +
+		     tp->dev->dev_addr[3] +
+		     tp->dev->dev_addr[4] +
+		     tp->dev->dev_addr[5]) &
+		TX_BACKOFF_SEED_MASK;
+	tw32(MAC_TX_BACKOFF_SEED, addr_high);
+}
+
+static int tg3_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct tg3 *tp = dev->priv;
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	spin_lock_irq(&tp->lock);
+	__tg3_set_mac_addr(tp);
+	spin_unlock_irq(&tp->lock);
+
+	return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
+			   dma_addr_t mapping, u32 maxlen_flags,
+			   u32 nic_addr)
+{
+	tg3_write_mem(tp,
+		      (bdinfo_addr +
+		       TG3_BDINFO_HOST_ADDR +
+		       TG3_64BIT_REG_HIGH),
+		      ((u64) mapping >> 32));
+	tg3_write_mem(tp,
+		      (bdinfo_addr +
+		       TG3_BDINFO_HOST_ADDR +
+		       TG3_64BIT_REG_LOW),
+		      ((u64) mapping & 0xffffffff));
+	tg3_write_mem(tp,
+		      (bdinfo_addr +
+		       TG3_BDINFO_MAXLEN_FLAGS),
+		       maxlen_flags);
+	tg3_write_mem(tp,
+		      (bdinfo_addr +
+		       TG3_BDINFO_NIC_ADDR),
+		      nic_addr);
+}
+
+static void __tg3_set_rx_mode(struct net_device *);
+
+/* tp->lock is held. */
+static int tg3_reset_hw(struct tg3 *tp)
+{
+	u32 val;
+	int i, err;
+
+	tg3_disable_ints(tp);
+
+	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) {
+		err = tg3_abort_hw(tp);
+		if (err)
+			return err;
+	}
+
+	tg3_chip_reset(tp);
+
+	tw32(GRC_MODE, tp->grc_mode);
+	tg3_write_mem(tp,
+		      NIC_SRAM_FIRMWARE_MBOX,
+		      NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tp->mac_mode = MAC_MODE_PORT_MODE_TBI;
+		tw32(MAC_MODE, tp->mac_mode);
+	} else
+		tw32(MAC_MODE, 0);
+
+	/* Wait for firmware initialization to complete. */
+	for (i = 0; i < 100000; i++) {
+		tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+		if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+			break;
+		udelay(10);
+	}
+	if (i >= 100000) {
+		printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
+		       "firmware will not restart magic=%08x\n",
+		       tp->dev->name, val);
+		return -ENODEV;
+	}
+
+	/* This works around an issue with Athlon chipsets on
+	 * B3 tigon3 silicon.  This bit has no effect on any
+	 * other revision.
+	 */
+	val = tr32(TG3PCI_CLOCK_CTRL);
+	val |= CLOCK_CTRL_DELAY_PCI_GRANT;
+	tw32(TG3PCI_CLOCK_CTRL, val);
+
+	/* Clear statistics/status block in chip, and status block in ram. */
+	for (i = NIC_SRAM_STATS_BLK;
+	     i < NIC_SRAM_STATUS_BLK + TG3_HW_STATUS_SIZE;
+	     i += sizeof(u32))
+		tg3_write_mem(tp, i, 0);
+	memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE);
+
+	/* This value is determined during the probe time DMA
+	 * engine test, tg3_test_dma.
+	 */
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
+			  GRC_MODE_4X_NIC_SEND_RINGS |
+			  GRC_MODE_NO_TX_PHDR_CSUM |
+			  GRC_MODE_NO_RX_PHDR_CSUM);
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS)
+		tp->grc_mode |= GRC_MODE_HOST_SENDBDS;
+	else
+		tp->grc_mode |= GRC_MODE_4X_NIC_SEND_RINGS;
+	if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM)
+		tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM;
+	if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM)
+		tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM;
+
+	tw32(GRC_MODE,
+	     tp->grc_mode |
+	     (GRC_MODE_IRQ_ON_MAC_ATTN | GRC_MODE_HOST_STACKUP));
+
+	/* Setup the timer prescalar register.  Clock is always 66Mhz. */
+	tw32(GRC_MISC_CFG,
+	     (65 << GRC_MISC_CFG_PRESCALAR_SHIFT));
+
+	/* Initialize MBUF/DESC pool. */
+	tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
+	tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE);
+	tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
+	tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
+
+	if (!(tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)) {
+		tw32(BUFMGR_MB_RDMA_LOW_WATER,
+		     tp->bufmgr_config.mbuf_read_dma_low_water);
+		tw32(BUFMGR_MB_MACRX_LOW_WATER,
+		     tp->bufmgr_config.mbuf_mac_rx_low_water);
+		tw32(BUFMGR_MB_HIGH_WATER,
+		     tp->bufmgr_config.mbuf_high_water);
+	} else {
+		tw32(BUFMGR_MB_RDMA_LOW_WATER,
+		     tp->bufmgr_config.mbuf_read_dma_low_water_jumbo);
+		tw32(BUFMGR_MB_MACRX_LOW_WATER,
+		     tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo);
+		tw32(BUFMGR_MB_HIGH_WATER,
+		     tp->bufmgr_config.mbuf_high_water_jumbo);
+	}
+	tw32(BUFMGR_DMA_LOW_WATER,
+	     tp->bufmgr_config.dma_low_water);
+	tw32(BUFMGR_DMA_HIGH_WATER,
+	     tp->bufmgr_config.dma_high_water);
+
+	tw32(BUFMGR_MODE, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE);
+	for (i = 0; i < 2000; i++) {
+		if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
+			break;
+		udelay(10);
+	}
+	if (i >= 2000) {
+		printk(KERN_ERR PFX "tg3_reset_hw cannot enable BUFMGR for %s.\n",
+		       tp->dev->name);
+		return -ENODEV;
+	}
+
+	tw32(FTQ_RESET, 0xffffffff);
+	tw32(FTQ_RESET, 0x00000000);
+	for (i = 0; i < 2000; i++) {
+		if (tr32(FTQ_RESET) == 0x00000000)
+			break;
+		udelay(10);
+	}
+	if (i >= 2000) {
+		printk(KERN_ERR PFX "tg3_reset_hw cannot reset FTQ for %s.\n",
+		       tp->dev->name);
+		return -ENODEV;
+	}
+
+	/* Initialize TG3_BDINFO's at:
+	 *  RCVDBDI_STD_BD:	standard eth size rx ring
+	 *  RCVDBDI_JUMBO_BD:	jumbo frame rx ring
+	 *  RCVDBDI_MINI_BD:	small frame rx ring (??? does not work)
+	 *
+	 * like so:
+	 *  TG3_BDINFO_HOST_ADDR:	high/low parts of DMA address of ring
+	 *  TG3_BDINFO_MAXLEN_FLAGS:	(rx max buffer size << 16) |
+	 *                              ring attribute flags
+	 *  TG3_BDINFO_NIC_ADDR:	location of descriptors in nic SRAM
+	 *
+	 * Standard receive ring @ NIC_SRAM_RX_BUFFER_DESC, 512 entries.
+	 * Jumbo receive ring @ NIC_SRAM_RX_JUMBO_BUFFER_DESC, 256 entries.
+	 *
+	 * ??? No space allocated for mini receive ring? :(
+	 *
+	 * The size of each ring is fixed in the firmware, but the location is
+	 * configurable.
+	 */
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tp->rx_std_mapping >> 32));
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tp->rx_std_mapping & 0xffffffff));
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS,
+	     RX_STD_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
+	tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
+	     NIC_SRAM_RX_BUFFER_DESC);
+
+#if TG3_MINI_RING_WORKS
+	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tp->rx_mini_mapping >> 32));
+	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tp->rx_mini_mapping & 0xffffffff));
+	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
+	     RX_MINI_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
+	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_NIC_ADDR,
+	     NIC_SRAM_RX_MINI_BUFFER_DESC);
+#else
+	tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
+	     BDINFO_FLAGS_DISABLED);
+#endif
+
+	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) {
+		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
+		     ((u64) tp->rx_jumbo_mapping >> 32));
+		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
+		     ((u64) tp->rx_jumbo_mapping & 0xffffffff));
+		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		     RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT);
+		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
+		     NIC_SRAM_RX_JUMBO_BUFFER_DESC);
+	} else {
+		tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
+		     BDINFO_FLAGS_DISABLED);
+	}
+
+	/* Setup replenish thresholds. */
+	tw32(RCVBDI_STD_THRESH, TG3_RX_RING_PENDING / 8);
+#if TG3_MINI_RING_WORKS
+	tw32(RCVBDI_MINI_THRESH, TG3_RX_MINI_RING_PENDING / 8);
+#endif
+	tw32(RCVBDI_JUMBO_THRESH, TG3_RX_JUMBO_RING_PENDING / 8);
+
+	/* Clear out send RCB ring in SRAM. */
+	for (i = NIC_SRAM_SEND_RCB; i < NIC_SRAM_RCV_RET_RCB; i += TG3_BDINFO_SIZE)
+		tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS, BDINFO_FLAGS_DISABLED);
+
+	tp->tx_prod = 0;
+	tp->tx_cons = 0;
+	tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+	tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0);
+
+	if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) {
+		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
+			       tp->tx_desc_mapping,
+			       (TG3_TX_RING_SIZE <<
+				BDINFO_FLAGS_MAXLEN_SHIFT),
+			       NIC_SRAM_TX_BUFFER_DESC);
+	} else {
+		tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB,
+			       0,
+			       BDINFO_FLAGS_DISABLED,
+			       NIC_SRAM_TX_BUFFER_DESC);
+	}
+
+	for (i = NIC_SRAM_RCV_RET_RCB; i < NIC_SRAM_STATS_BLK; i += TG3_BDINFO_SIZE) {
+		tg3_write_mem(tp, i + TG3_BDINFO_MAXLEN_FLAGS,
+			      BDINFO_FLAGS_DISABLED);
+	}
+
+	tp->rx_rcb_ptr = 0;
+	tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0);
+
+	tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB,
+		       tp->rx_rcb_mapping,
+		       (TG3_RX_RCB_RING_SIZE <<
+			BDINFO_FLAGS_MAXLEN_SHIFT),
+		       0);
+
+	tp->rx_std_ptr = TG3_RX_RING_PENDING;
+	tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
+		     tp->rx_std_ptr);
+#if TG3_MINI_RING_WORKS
+	tp->rx_mini_ptr = TG3_RX_MINI_RING_PENDING;
+	tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
+		     tp->rx_mini_ptr);
+#endif
+
+	if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE)
+		tp->rx_jumbo_ptr = TG3_RX_JUMBO_RING_PENDING;
+	else
+		tp->rx_jumbo_ptr = 0;
+	tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
+		     tp->rx_jumbo_ptr);
+
+	/* Initialize MAC address and backoff seed. */
+	__tg3_set_mac_addr(tp);
+
+	/* MTU + ethernet header + FCS + optional VLAN tag */
+	tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8);
+
+	/* The slot time is changed by tg3_setup_phy if we
+	 * run at gigabit with half duplex.
+	 */
+	tw32(MAC_TX_LENGTHS,
+	     (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+	     (6 << TX_LENGTHS_IPG_SHIFT) |
+	     (32 << TX_LENGTHS_SLOT_TIME_SHIFT));
+
+	/* Receive rules. */
+	tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS);
+	tw32(RCVLPC_CONFIG, 0x0181);
+
+	/* Receive/send statistics. */
+	tw32(RCVLPC_STATS_ENABLE, 0xffffff);
+	tw32(RCVLPC_STATSCTRL, RCVLPC_STATSCTRL_ENABLE);
+	tw32(SNDDATAI_STATSENAB, 0xffffff);
+	tw32(SNDDATAI_STATSCTRL,
+	     (SNDDATAI_SCTRL_ENABLE |
+	      SNDDATAI_SCTRL_FASTUPD));
+
+	/* Setup host coalescing engine. */
+	tw32(HOSTCC_MODE, 0);
+	for (i = 0; i < 2000; i++) {
+		if (!(tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE))
+			break;
+		udelay(10);
+	}
+
+	tw32(HOSTCC_RXCOL_TICKS,
+	     tp->coalesce_config.rx_coalesce_ticks);
+	tw32(HOSTCC_RXMAX_FRAMES,
+	     tp->coalesce_config.rx_max_coalesced_frames);
+	tw32(HOSTCC_RXCOAL_TICK_INT,
+	     tp->coalesce_config.rx_coalesce_ticks_during_int);
+	tw32(HOSTCC_RXCOAL_MAXF_INT,
+	     tp->coalesce_config.rx_max_coalesced_frames_during_int);
+	tw32(HOSTCC_TXCOL_TICKS,
+	     tp->coalesce_config.tx_coalesce_ticks);
+	tw32(HOSTCC_TXMAX_FRAMES,
+	     tp->coalesce_config.tx_max_coalesced_frames);
+	tw32(HOSTCC_TXCOAL_TICK_INT,
+	     tp->coalesce_config.tx_coalesce_ticks_during_int);
+	tw32(HOSTCC_TXCOAL_MAXF_INT,
+	     tp->coalesce_config.tx_max_coalesced_frames_during_int);
+	tw32(HOSTCC_STAT_COAL_TICKS,
+	     tp->coalesce_config.stats_coalesce_ticks);
+
+	/* Status/statistics block address. */
+	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tp->stats_mapping >> 32));
+	tw32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tp->stats_mapping & 0xffffffff));
+	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
+	     ((u64) tp->status_mapping >> 32));
+	tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
+	     ((u64) tp->status_mapping & 0xffffffff));
+	tw32(HOSTCC_STATS_BLK_NIC_ADDR, NIC_SRAM_STATS_BLK);
+	tw32(HOSTCC_STATUS_BLK_NIC_ADDR, NIC_SRAM_STATUS_BLK);
+
+	tw32(HOSTCC_MODE, HOSTCC_MODE_ENABLE | tp->coalesce_mode);
+
+	tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE);
+	tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE);
+	tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
+
+	tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
+		MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+	tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
+
+	tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_GPIO_OE1 |
+		GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_AUTO_SEEPROM;
+	tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
+
+	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0);
+
+	tw32(DMAC_MODE, DMAC_MODE_ENABLE);
+
+	tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB |
+			  WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB |
+			  WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB |
+			  WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB |
+			  WDMAC_MODE_LNGREAD_ENAB));
+	tw32(RDMAC_MODE, (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB |
+			  RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB |
+			  RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
+			  RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
+			  RDMAC_MODE_LNGREAD_ENAB));
+
+	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
+	tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
+	tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+	tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
+	tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
+	tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
+	tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+	tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
+	tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0) {
+		err = tg3_load_5701_a0_firmware_fix(tp);
+		if (err)
+			return err;
+	}
+
+	tp->tx_mode = TX_MODE_ENABLE;
+	tw32(MAC_TX_MODE, tp->tx_mode);
+	tp->rx_mode = RX_MODE_ENABLE;
+	tw32(MAC_RX_MODE, tp->rx_mode);
+
+	if (tp->link_config.phy_is_low_power) {
+		tp->link_config.phy_is_low_power = 0;
+		tp->link_config.speed = tp->link_config.orig_speed;
+		tp->link_config.duplex = tp->link_config.orig_duplex;
+		tp->link_config.autoneg = tp->link_config.orig_autoneg;
+	}
+
+	tp->mi_mode = MAC_MI_MODE_BASE;
+	tw32(MAC_MI_MODE, tp->mi_mode);
+	tw32(MAC_LED_CTRL, 0);
+	tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB);
+	tw32(MAC_RX_MODE, RX_MODE_RESET);
+	udelay(10);
+	tw32(MAC_RX_MODE, tp->rx_mode);
+
+	err = tg3_setup_phy(tp);
+	if (err)
+		return err;
+
+	if (tp->phy_id != PHY_ID_SERDES) {
+		u32 tmp;
+
+		/* Clear CRC stats. */
+		tg3_readphy(tp, 0x1e, &tmp);
+		tg3_writephy(tp, 0x1e, tmp | 0x8000);
+		tg3_readphy(tp, 0x14, &tmp);
+	}
+
+	__tg3_set_rx_mode(tp->dev);
+
+	/* Initialize receive rules. */
+	tw32(MAC_RCV_RULE_0,  0xc2000000 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_0, 0xffffffff & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_RULE_1,  0x86000004 & RCV_RULE_DISABLE_MASK);
+	tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
+#if 0
+	tw32(MAC_RCV_RULE_2,  0); tw32(MAC_RCV_VALUE_2,  0);
+	tw32(MAC_RCV_RULE_3,  0); tw32(MAC_RCV_VALUE_3,  0);
+#endif
+	tw32(MAC_RCV_RULE_4,  0); tw32(MAC_RCV_VALUE_4,  0);
+	tw32(MAC_RCV_RULE_5,  0); tw32(MAC_RCV_VALUE_5,  0);
+	tw32(MAC_RCV_RULE_6,  0); tw32(MAC_RCV_VALUE_6,  0);
+	tw32(MAC_RCV_RULE_7,  0); tw32(MAC_RCV_VALUE_7,  0);
+	tw32(MAC_RCV_RULE_8,  0); tw32(MAC_RCV_VALUE_8,  0);
+	tw32(MAC_RCV_RULE_9,  0); tw32(MAC_RCV_VALUE_9,  0);
+	tw32(MAC_RCV_RULE_10,  0); tw32(MAC_RCV_VALUE_10,  0);
+	tw32(MAC_RCV_RULE_11,  0); tw32(MAC_RCV_VALUE_11,  0);
+	tw32(MAC_RCV_RULE_12,  0); tw32(MAC_RCV_VALUE_12,  0);
+	tw32(MAC_RCV_RULE_13,  0); tw32(MAC_RCV_VALUE_13,  0);
+	tw32(MAC_RCV_RULE_14,  0); tw32(MAC_RCV_VALUE_14,  0);
+	tw32(MAC_RCV_RULE_15,  0); tw32(MAC_RCV_VALUE_15,  0);
+
+	if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
+		tg3_enable_ints(tp);
+
+	return 0;
+}
+
+/* Called at device open time to get the chip ready for
+ * packet processing.  Invoked with tp->lock held.
+ */
+static int tg3_init_hw(struct tg3 *tp)
+{
+	int err;
+
+	/* Force the chip into D0. */
+	err = tg3_set_power_state(tp, 0);
+	if (err)
+		goto out;
+
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	err = tg3_reset_hw(tp);
+
+out:
+	return err;
+}
+
+static void tg3_timer(unsigned long __opaque)
+{
+	struct tg3 *tp = (struct tg3 *) __opaque;
+
+	spin_lock_irq(&tp->lock);
+
+	if (!(tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)) {
+		/* All of this garbage is because on the 5700 the
+		 * mailbox/status_block protocol the chip uses with
+		 * the cpu is race prone.
+		 */
+		if (tp->hw_status->status & SD_STATUS_UPDATED) {
+			tw32(GRC_LOCAL_CTRL,
+			     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+		} else {
+			tw32(HOSTCC_MODE,
+			     (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
+		}
+
+		if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+			tg3_halt(tp);
+			tg3_init_rings(tp);
+			tg3_init_hw(tp);
+		}
+	}
+
+	/* This part only runs once per second. */
+	if (!--tp->timer_counter) {
+		if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
+			u32 mac_stat;
+			int phy_event;
+
+			mac_stat = tr32(MAC_STATUS);
+
+			phy_event = 0;
+			if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) {
+				if (mac_stat & MAC_STATUS_MI_INTERRUPT)
+					phy_event = 1;
+			} else if (mac_stat & MAC_STATUS_LNKSTATE_CHANGED)
+				phy_event = 1;
+
+			if (phy_event)
+				tg3_setup_phy(tp);
+		}
+
+		tp->timer_counter = tp->timer_multiplier;
+	}
+
+	spin_unlock_irq(&tp->lock);
+
+	tp->timer.expires = jiffies + tp->timer_offset;
+	add_timer(&tp->timer);
+}
+
+static int tg3_open(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	int err;
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_disable_ints(tp);
+	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+
+	spin_unlock_irq(&tp->lock);
+
+	/* If you move this call, make sure TG3_FLAG_HOST_TXDS in
+	 * tp->tg3_flags is accurate at that new place.
+	 */
+	err = tg3_alloc_consistent(tp);
+	if (err)
+		return err;
+
+	if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS)
+		err = request_irq(dev->irq, tg3_interrupt_tagged,
+				  SA_SHIRQ, dev->name, dev);
+	else
+		err = request_irq(dev->irq, tg3_interrupt,
+				  SA_SHIRQ, dev->name, dev);
+
+	if (err) {
+		tg3_free_consistent(tp);
+		return err;
+	}
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_init_rings(tp);
+
+	err = tg3_init_hw(tp);
+	if (err) {
+		tg3_halt(tp);
+		tg3_free_rings(tp);
+	} else {
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_IRQ_STATUS) {
+			tp->timer_offset = HZ;
+			tp->timer_counter = tp->timer_multiplier = 1;
+		} else {
+			tp->timer_offset = HZ / 10;
+			tp->timer_counter = tp->timer_multiplier = 10;
+		}
+
+		init_timer(&tp->timer);
+		tp->timer.expires = jiffies + tp->timer_offset;
+		tp->timer.data = (unsigned long) tp;
+		tp->timer.function = tg3_timer;
+		add_timer(&tp->timer);
+
+		tp->last_rate_sample = jiffies;
+		tp->last_rx_count = 0;
+		tp->last_tx_count = 0;
+
+		tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+	}
+
+	spin_unlock_irq(&tp->lock);
+
+	if (err) {
+		free_irq(dev->irq, dev);
+		tg3_free_consistent(tp);
+		return err;
+	}
+
+	netif_start_queue(dev);
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_enable_ints(tp);
+
+	spin_unlock_irq(&tp->lock);
+
+	return 0;
+}
+
+#if 0
+/*static*/ void tg3_dump_state(struct tg3 *tp)
+{
+	u32 val32, val32_2, val32_3, val32_4, val32_5;
+	u16 val16;
+	int i;
+
+	pci_read_config_word(tp->pdev, PCI_STATUS, &val16);
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, &val32);
+	printk("DEBUG: PCI status [%04x] TG3PCI state[%08x]\n",
+	       val16, val32);
+
+	/* MAC block */
+	printk("DEBUG: MAC_MODE[%08x] MAC_STATUS[%08x]\n",
+	       tr32(MAC_MODE), tr32(MAC_STATUS));
+	printk("       MAC_EVENT[%08x] MAC_LED_CTRL[%08x]\n",
+	       tr32(MAC_EVENT), tr32(MAC_LED_CTRL));
+	printk("DEBUG: MAC_TX_MODE[%08x] MAC_TX_STATUS[%08x]\n",
+	       tr32(MAC_TX_MODE), tr32(MAC_TX_STATUS));
+	printk("       MAC_RX_MODE[%08x] MAC_RX_STATUS[%08x]\n",
+	       tr32(MAC_RX_MODE), tr32(MAC_RX_STATUS));
+
+	/* Send data initiator control block */
+	printk("DEBUG: SNDDATAI_MODE[%08x] SNDDATAI_STATUS[%08x]\n",
+	       tr32(SNDDATAI_MODE), tr32(SNDDATAI_STATUS));
+	printk("       SNDDATAI_STATSCTRL[%08x]\n",
+	       tr32(SNDDATAI_STATSCTRL));
+
+	/* Send data completion control block */
+	printk("DEBUG: SNDDATAC_MODE[%08x]\n", tr32(SNDDATAC_MODE));
+
+	/* Send BD ring selector block */
+	printk("DEBUG: SNDBDS_MODE[%08x] SNDBDS_STATUS[%08x]\n",
+	       tr32(SNDBDS_MODE), tr32(SNDBDS_STATUS));
+
+	/* Send BD initiator control block */
+	printk("DEBUG: SNDBDI_MODE[%08x] SNDBDI_STATUS[%08x]\n",
+	       tr32(SNDBDI_MODE), tr32(SNDBDI_STATUS));
+
+	/* Send BD completion control block */
+	printk("DEBUG: SNDBDC_MODE[%08x]\n", tr32(SNDBDC_MODE));
+
+	/* Receive list placement control block */
+	printk("DEBUG: RCVLPC_MODE[%08x] RCVLPC_STATUS[%08x]\n",
+	       tr32(RCVLPC_MODE), tr32(RCVLPC_STATUS));
+	printk("       RCVLPC_STATSCTRL[%08x]\n",
+	       tr32(RCVLPC_STATSCTRL));
+
+	/* Receive data and receive BD initiator control block */
+	printk("DEBUG: RCVDBDI_MODE[%08x] RCVDBDI_STATUS[%08x]\n",
+	       tr32(RCVDBDI_MODE), tr32(RCVDBDI_STATUS));
+
+	/* Receive data completion control block */
+	printk("DEBUG: RCVDCC_MODE[%08x]\n",
+	       tr32(RCVDCC_MODE));
+
+	/* Receive BD initiator control block */
+	printk("DEBUG: RCVBDI_MODE[%08x] RCVBDI_STATUS[%08x]\n",
+	       tr32(RCVBDI_MODE), tr32(RCVBDI_STATUS));
+
+	/* Receive BD completion control block */
+	printk("DEBUG: RCVCC_MODE[%08x] RCVCC_STATUS[%08x]\n",
+	       tr32(RCVCC_MODE), tr32(RCVCC_STATUS));
+
+	/* Receive list selector control block */
+	printk("DEBUG: RCVLSC_MODE[%08x] RCVLSC_STATUS[%08x]\n",
+	       tr32(RCVLSC_MODE), tr32(RCVLSC_STATUS));
+
+	/* Mbuf cluster free block */
+	printk("DEBUG: MBFREE_MODE[%08x] MBFREE_STATUS[%08x]\n",
+	       tr32(MBFREE_MODE), tr32(MBFREE_STATUS));
+
+	/* Host coalescing control block */
+	printk("DEBUG: HOSTCC_MODE[%08x] HOSTCC_STATUS[%08x]\n",
+	       tr32(HOSTCC_MODE), tr32(HOSTCC_STATUS));
+	printk("DEBUG: HOSTCC_STATS_BLK_HOST_ADDR[%08x%08x]\n",
+	       tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH),
+	       tr32(HOSTCC_STATS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW));
+	printk("DEBUG: HOSTCC_STATUS_BLK_HOST_ADDR[%08x%08x]\n",
+	       tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH),
+	       tr32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW));
+	printk("DEBUG: HOSTCC_STATS_BLK_NIC_ADDR[%08x]\n",
+	       tr32(HOSTCC_STATS_BLK_NIC_ADDR));
+	printk("DEBUG: HOSTCC_STATUS_BLK_NIC_ADDR[%08x]\n",
+	       tr32(HOSTCC_STATUS_BLK_NIC_ADDR));
+
+	/* Memory arbiter control block */
+	printk("DEBUG: MEMARB_MODE[%08x] MEMARB_STATUS[%08x]\n",
+	       tr32(MEMARB_MODE), tr32(MEMARB_STATUS));
+
+	/* Buffer manager control block */
+	printk("DEBUG: BUFMGR_MODE[%08x] BUFMGR_STATUS[%08x]\n",
+	       tr32(BUFMGR_MODE), tr32(BUFMGR_STATUS));
+	printk("DEBUG: BUFMGR_MB_POOL_ADDR[%08x] BUFMGR_MB_POOL_SIZE[%08x]\n",
+	       tr32(BUFMGR_MB_POOL_ADDR), tr32(BUFMGR_MB_POOL_SIZE));
+	printk("DEBUG: BUFMGR_DMA_DESC_POOL_ADDR[%08x] "
+	       "BUFMGR_DMA_DESC_POOL_SIZE[%08x]\n",
+	       tr32(BUFMGR_DMA_DESC_POOL_ADDR),
+	       tr32(BUFMGR_DMA_DESC_POOL_SIZE));
+
+	/* Read DMA control block */
+	printk("DEBUG: RDMAC_MODE[%08x] RDMAC_STATUS[%08x]\n",
+	       tr32(RDMAC_MODE), tr32(RDMAC_STATUS));
+
+	/* Write DMA control block */
+	printk("DEBUG: WDMAC_MODE[%08x] WDMAC_STATUS[%08x]\n",
+	       tr32(WDMAC_MODE), tr32(WDMAC_STATUS));
+
+	/* DMA completion block */
+	printk("DEBUG: DMAC_MODE[%08x]\n",
+	       tr32(DMAC_MODE));
+
+	/* GRC block */
+	printk("DEBUG: GRC_MODE[%08x] GRC_MISC_CFG[%08x]\n",
+	       tr32(GRC_MODE), tr32(GRC_MISC_CFG));
+	printk("DEBUG: GRC_LOCAL_CTRL[%08x]\n",
+	       tr32(GRC_LOCAL_CTRL));
+
+	/* TG3_BDINFOs */
+	printk("DEBUG: RCVDBDI_JUMBO_BD[%08x%08x:%08x:%08x]\n",
+	       tr32(RCVDBDI_JUMBO_BD + 0x0),
+	       tr32(RCVDBDI_JUMBO_BD + 0x4),
+	       tr32(RCVDBDI_JUMBO_BD + 0x8),
+	       tr32(RCVDBDI_JUMBO_BD + 0xc));
+	printk("DEBUG: RCVDBDI_STD_BD[%08x%08x:%08x:%08x]\n",
+	       tr32(RCVDBDI_STD_BD + 0x0),
+	       tr32(RCVDBDI_STD_BD + 0x4),
+	       tr32(RCVDBDI_STD_BD + 0x8),
+	       tr32(RCVDBDI_STD_BD + 0xc));
+	printk("DEBUG: RCVDBDI_MINI_BD[%08x%08x:%08x:%08x]\n",
+	       tr32(RCVDBDI_MINI_BD + 0x0),
+	       tr32(RCVDBDI_MINI_BD + 0x4),
+	       tr32(RCVDBDI_MINI_BD + 0x8),
+	       tr32(RCVDBDI_MINI_BD + 0xc));
+
+	tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x0, &val32);
+	tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x4, &val32_2);
+	tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0x8, &val32_3);
+	tg3_read_mem(tp, NIC_SRAM_SEND_RCB + 0xc, &val32_4);
+	printk("DEBUG: SRAM_SEND_RCB_0[%08x%08x:%08x:%08x]\n",
+	       val32, val32_2, val32_3, val32_4);
+
+	tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x0, &val32);
+	tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x4, &val32_2);
+	tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0x8, &val32_3);
+	tg3_read_mem(tp, NIC_SRAM_RCV_RET_RCB + 0xc, &val32_4);
+	printk("DEBUG: SRAM_RCV_RET_RCB_0[%08x%08x:%08x:%08x]\n",
+	       val32, val32_2, val32_3, val32_4);
+
+	tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x0, &val32);
+	tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x4, &val32_2);
+	tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x8, &val32_3);
+	tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0xc, &val32_4);
+	tg3_read_mem(tp, NIC_SRAM_STATUS_BLK + 0x10, &val32_5);
+	printk("DEBUG: SRAM_STATUS_BLK[%08x:%08x:%08x:%08x:%08x]\n",
+	       val32, val32_2, val32_3, val32_4, val32_5);
+
+	/* SW status block */
+	printk("DEBUG: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n",
+	       tp->hw_status->status,
+	       tp->hw_status->status_tag,
+	       tp->hw_status->rx_jumbo_consumer,
+	       tp->hw_status->rx_consumer,
+	       tp->hw_status->rx_mini_consumer,
+	       tp->hw_status->idx[0].rx_producer,
+	       tp->hw_status->idx[0].tx_consumer);
+
+	/* SW statistics block */
+	printk("DEBUG: Host statistics block [%08x:%08x:%08x:%08x]\n",
+	       ((u32 *)tp->hw_stats)[0],
+	       ((u32 *)tp->hw_stats)[1],
+	       ((u32 *)tp->hw_stats)[2],
+	       ((u32 *)tp->hw_stats)[3]);
+
+	/* Mailboxes */
+	printk("DEBUG: SNDHOST_PROD[%08x%08x] SNDNIC_PROD[%08x%08x]\n",
+	       tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x0),
+	       tr32(MAILBOX_SNDHOST_PROD_IDX_0 + 0x4),
+	       tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x0),
+	       tr32(MAILBOX_SNDNIC_PROD_IDX_0 + 0x4));
+
+	/* NIC side send descriptors. */
+	for (i = 0; i < 6; i++) {
+		unsigned long txd;
+
+		txd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_TX_BUFFER_DESC
+			+ (i * sizeof(struct tg3_tx_buffer_desc));
+		printk("DEBUG: NIC TXD(%d)[%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(txd + 0x0), readl(txd + 0x4),
+		       readl(txd + 0x8), readl(txd + 0xc));
+	}
+
+	/* NIC side RX descriptors. */
+	for (i = 0; i < 6; i++) {
+		unsigned long rxd;
+
+		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_BUFFER_DESC
+			+ (i * sizeof(struct tg3_rx_buffer_desc));
+		printk("DEBUG: NIC RXD_STD(%d)[0][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+		rxd += (4 * sizeof(u32));
+		printk("DEBUG: NIC RXD_STD(%d)[1][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+	}
+#if TG3_MINI_RING_WORKS
+	for (i = 0; i < 6; i++) {
+		unsigned long rxd;
+
+		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_MINI_BUFFER_DESC
+			+ (i * sizeof(struct tg3_rx_buffer_desc));
+		printk("DEBUG: NIC RXD_MINI(%d)[0][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+		rxd += (4 * sizeof(u32));
+		printk("DEBUG: NIC RXD_MINI(%d)[1][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+	}
+#endif
+
+	for (i = 0; i < 6; i++) {
+		unsigned long rxd;
+
+		rxd = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_RX_JUMBO_BUFFER_DESC
+			+ (i * sizeof(struct tg3_rx_buffer_desc));
+		printk("DEBUG: NIC RXD_JUMBO(%d)[0][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+		rxd += (4 * sizeof(u32));
+		printk("DEBUG: NIC RXD_JUMBO(%d)[1][%08x:%08x:%08x:%08x]\n",
+		       i,
+		       readl(rxd + 0x0), readl(rxd + 0x4),
+		       readl(rxd + 0x8), readl(rxd + 0xc));
+	}
+}
+#endif
+
+static int tg3_close(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+
+	netif_stop_queue(dev);
+
+	del_timer_sync(&tp->timer);
+
+	spin_lock_irq(&tp->lock);
+#if 0
+	tg3_dump_state(tp);
+#endif
+
+	tg3_disable_ints(tp);
+
+	tg3_halt(tp);
+	tg3_free_rings(tp);
+	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+
+	spin_unlock_irq(&tp->lock);
+
+	free_irq(dev->irq, dev);
+
+	tg3_free_consistent(tp);
+
+	return 0;
+}
+
+static inline unsigned long get_stat64(tg3_stat64_t *val)
+{
+	unsigned long ret;
+
+#if (BITS_PER_LONG == 32)
+	if (val->high != 0)
+		ret = ~0UL;
+	else
+		ret = val->low;
+#else
+	ret = ((u64)val->high << 32) | ((u64)val->low);
+#endif
+	return ret;
+}
+
+static unsigned long calc_crc_errors(struct tg3 *tp)
+{
+	struct tg3_hw_stats *hw_stats = tp->hw_stats;
+
+	if (tp->phy_id != PHY_ID_SERDES &&
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	     GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+		unsigned long flags;
+		u32 val;
+
+		spin_lock_irqsave(&tp->lock, flags);
+		tg3_readphy(tp, 0x1e, &val);
+		tg3_writephy(tp, 0x1e, val | 0x8000);
+		tg3_readphy(tp, 0x14, &val);
+		spin_unlock_irqrestore(&tp->lock, flags);
+
+		tp->phy_crc_errors += val;
+
+		return tp->phy_crc_errors;
+	}
+
+	return get_stat64(&hw_stats->rx_fcs_errors);
+}
+
+static struct net_device_stats *tg3_get_stats(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	struct net_device_stats *stats = &tp->net_stats;
+	struct tg3_hw_stats *hw_stats = tp->hw_stats;
+
+	/* XXX Fix this... this is wrong because
+	 * XXX it means every open/close we lose the stats.
+	 */
+	if (!hw_stats)
+		return stats;
+
+	stats->rx_packets =
+		get_stat64(&hw_stats->rx_ucast_packets) +
+		get_stat64(&hw_stats->rx_mcast_packets) +
+		get_stat64(&hw_stats->rx_bcast_packets);
+		
+	stats->tx_packets =
+		get_stat64(&hw_stats->COS_out_packets[0]);
+
+	stats->rx_bytes = get_stat64(&hw_stats->rx_octets);
+	stats->tx_bytes = get_stat64(&hw_stats->tx_octets);
+
+	stats->rx_errors = get_stat64(&hw_stats->rx_errors);
+	stats->tx_errors =
+		get_stat64(&hw_stats->tx_errors) +
+		get_stat64(&hw_stats->tx_mac_errors) +
+		get_stat64(&hw_stats->tx_carrier_sense_errors) +
+		get_stat64(&hw_stats->tx_discards);
+
+	stats->multicast = get_stat64(&hw_stats->rx_mcast_packets);
+	stats->collisions = get_stat64(&hw_stats->tx_collisions);
+
+	stats->rx_length_errors =
+		get_stat64(&hw_stats->rx_frame_too_long_errors) +
+		get_stat64(&hw_stats->rx_undersize_packets);
+
+	stats->rx_over_errors = get_stat64(&hw_stats->rxbds_empty);
+	stats->rx_frame_errors = get_stat64(&hw_stats->rx_align_errors);
+	stats->tx_aborted_errors = get_stat64(&hw_stats->tx_discards);
+	stats->tx_carrier_errors =
+		get_stat64(&hw_stats->tx_carrier_sense_errors);
+
+	stats->rx_crc_errors = calc_crc_errors(tp);
+
+	return stats;
+}
+
+static inline u32 calc_crc(unsigned char *buf, int len)
+{
+	u32 reg;
+	u32 tmp;
+	int j, k;
+
+	reg = 0xffffffff;
+
+	for (j = 0; j < len; j++) {
+		reg ^= buf[j];
+
+		for (k = 0; k < 8; k++) {
+			tmp = reg & 0x01;
+
+			reg >>= 1;
+
+			if (tmp) {
+				reg ^= 0xedb88320;
+			}
+		}
+	}
+
+	return ~reg;
+}
+
+static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all)
+{
+	/* accept or reject all multicast frames */
+	tw32 (MAC_HASH_REG_0, accept_all ? 0xffffffff : 0);
+	tw32 (MAC_HASH_REG_1, accept_all ? 0xffffffff : 0);
+	tw32 (MAC_HASH_REG_2, accept_all ? 0xffffffff : 0);
+	tw32 (MAC_HASH_REG_3, accept_all ? 0xffffffff : 0);
+}
+
+static void __tg3_set_rx_mode(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+	u32 rx_mode;
+
+	rx_mode = tp->rx_mode & ~RX_MODE_PROMISC;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Promiscuous mode. */
+		rx_mode |= RX_MODE_PROMISC;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		/* Accept all multicast. */
+		tg3_set_multi (tp, 1);
+	} else if (dev->mc_count < 1) {
+		/* Reject all multicast. */
+		tg3_set_multi (tp, 0);
+	} else {
+		/* Accept one or more multicast(s). */
+		struct dev_mc_list *mclist;
+		unsigned int i;
+		u32 mc_filter[4] = { 0, };
+		u32 regidx;
+		u32 bit;
+		u32 crc;
+
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+
+			crc = calc_crc (mclist->dmi_addr, ETH_ALEN);
+			bit = ~crc & 0x7f;
+			regidx = (bit & 0x60) >> 5;
+			bit &= 0x1f;
+			mc_filter[regidx] |= (1 << bit);
+		}
+
+		tw32 (MAC_HASH_REG_0, mc_filter[0]);
+		tw32 (MAC_HASH_REG_1, mc_filter[1]);
+		tw32 (MAC_HASH_REG_2, mc_filter[2]);
+		tw32 (MAC_HASH_REG_3, mc_filter[3]);
+	}
+
+	if (rx_mode != tp->rx_mode) {
+		tp->rx_mode = rx_mode;
+		tw32 (MAC_RX_MODE, rx_mode);
+	}
+}
+
+static void tg3_set_rx_mode(struct net_device *dev)
+{
+	struct tg3 *tp = dev->priv;
+
+	spin_lock_irq(&tp->lock);
+	__tg3_set_rx_mode(dev);
+	spin_unlock_irq(&tp->lock);
+}
+
+static u8 *tg3_get_regs(struct tg3 *tp)
+{
+	u8 *orig_p = kmalloc((32 * 1024), GFP_KERNEL);
+	u8 *p;
+	int i;
+
+	if (orig_p == NULL)
+		return NULL;
+
+	memset(orig_p, 0, (32 * 1024));
+
+	spin_lock_irq(&tp->lock);
+
+#define __GET_REG32(reg)	(*((u32 *)(p))++ = tr32(reg))
+#define GET_REG32_LOOP(base,len)		\
+do {	p = orig_p + (base);			\
+	for (i = 0; i < len; i += 4)		\
+		__GET_REG32((base) + i);	\
+} while (0)
+#define GET_REG32_1(reg)	\
+do {	p = orig_p + (reg);	\
+	__GET_REG32((reg));	\
+} while (0)
+
+	GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0);
+	GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200);
+	GET_REG32_LOOP(MAC_MODE, 0x4f0);
+	GET_REG32_LOOP(SNDDATAI_MODE, 0xe0);
+	GET_REG32_1(SNDDATAC_MODE);
+	GET_REG32_LOOP(SNDBDS_MODE, 0x80);
+	GET_REG32_LOOP(SNDBDI_MODE, 0x48);
+	GET_REG32_1(SNDBDC_MODE);
+	GET_REG32_LOOP(RCVLPC_MODE, 0x20);
+	GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c);
+	GET_REG32_LOOP(RCVDBDI_MODE, 0x0c);
+	GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c);
+	GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44);
+	GET_REG32_1(RCVDCC_MODE);
+	GET_REG32_LOOP(RCVBDI_MODE, 0x20);
+	GET_REG32_LOOP(RCVCC_MODE, 0x14);
+	GET_REG32_LOOP(RCVLSC_MODE, 0x08);
+	GET_REG32_1(MBFREE_MODE);
+	GET_REG32_LOOP(HOSTCC_MODE, 0x100);
+	GET_REG32_LOOP(MEMARB_MODE, 0x10);
+	GET_REG32_LOOP(BUFMGR_MODE, 0x58);
+	GET_REG32_LOOP(RDMAC_MODE, 0x08);
+	GET_REG32_LOOP(WDMAC_MODE, 0x08);
+	GET_REG32_LOOP(RX_CPU_BASE, 0x280);
+	GET_REG32_LOOP(TX_CPU_BASE, 0x280);
+	GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110);
+	GET_REG32_LOOP(FTQ_RESET, 0x120);
+	GET_REG32_LOOP(MSGINT_MODE, 0x0c);
+	GET_REG32_1(DMAC_MODE);
+	GET_REG32_LOOP(GRC_MODE, 0x4c);
+	GET_REG32_LOOP(NVRAM_CMD, 0x24);
+
+#undef __GET_REG32
+#undef GET_REG32_LOOP
+#undef GET_REG32_1
+
+	spin_unlock_irq(&tp->lock);
+
+	return orig_p;
+}
+
+static int tg3_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct tg3 *tp = dev->priv;
+	struct pci_dev *pci_dev = tp->pdev;
+	u32 ethcmd;
+
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:{
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_MODULE_NAME);
+		strcpy (info.version, DRV_MODULE_VERSION);
+		strcpy (info.bus_info, pci_dev->slot_name);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+		    tp->link_config.phy_is_low_power)
+			return -EAGAIN;
+		cmd.supported = (SUPPORTED_Autoneg);
+
+		if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+			cmd.supported |= (SUPPORTED_1000baseT_Half |
+					  SUPPORTED_1000baseT_Full);
+
+		if (tp->phy_id != PHY_ID_SERDES)
+			cmd.supported |= (SUPPORTED_100baseT_Half |
+					  SUPPORTED_100baseT_Full |
+					  SUPPORTED_10baseT_Half |
+					  SUPPORTED_10baseT_Full |
+					  SUPPORTED_MII);
+		else
+			cmd.supported |= SUPPORTED_FIBRE;
+
+		cmd.advertising = tp->link_config.advertising;
+		cmd.speed = tp->link_config.active_speed;
+		cmd.duplex = tp->link_config.active_duplex;
+		cmd.port = 0;
+		cmd.phy_address = PHY_ADDR;
+		cmd.transceiver = 0;
+		cmd.autoneg = tp->link_config.autoneg;
+		cmd.maxtxpkt = tp->coalesce_config.tx_max_coalesced_frames;
+		cmd.maxrxpkt = tp->coalesce_config.rx_max_coalesced_frames;
+		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd cmd;
+
+		if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) ||
+		    tp->link_config.phy_is_low_power)
+			return -EAGAIN;
+
+		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+			return -EFAULT;
+
+		/* Fiber PHY only supports 1000 full/half */
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			if (tp->phy_id == PHY_ID_SERDES &&
+			    (cmd.advertising &
+			     (ADVERTISED_10baseT_Half |
+			      ADVERTISED_10baseT_Full |
+			      ADVERTISED_100baseT_Half |
+			      ADVERTISED_100baseT_Full)))
+				return -EINVAL;
+			if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			    (cmd.advertising &
+			     (ADVERTISED_1000baseT_Half |
+			      ADVERTISED_1000baseT_Full)))
+				return -EINVAL;
+		} else {
+			if (tp->phy_id == PHY_ID_SERDES &&
+			    (cmd.speed == SPEED_10 ||
+			     cmd.speed == SPEED_100))
+				return -EINVAL;
+			if ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) &&
+			    (cmd.speed == SPEED_10 ||
+			     cmd.speed == SPEED_100))
+				return -EINVAL;
+		}
+
+		spin_lock_irq(&tp->lock);
+
+		tp->link_config.autoneg = cmd.autoneg;
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			tp->link_config.advertising = cmd.advertising;
+			tp->link_config.speed = SPEED_INVALID;
+			tp->link_config.duplex = DUPLEX_INVALID;
+		} else {
+			tp->link_config.speed = cmd.speed;
+			tp->link_config.duplex = cmd.duplex;
+		}
+
+		if (cmd.maxtxpkt || cmd.maxrxpkt) {
+			tp->coalesce_config.tx_max_coalesced_frames =
+				cmd.maxtxpkt;
+			tp->coalesce_config.rx_max_coalesced_frames =
+				cmd.maxrxpkt;
+
+			/* Coalescing config bits can be updated without
+			 * a full chip reset.
+			 */
+			tw32(HOSTCC_TXMAX_FRAMES,
+			     tp->coalesce_config.tx_max_coalesced_frames);
+			tw32(HOSTCC_RXMAX_FRAMES,
+			     tp->coalesce_config.rx_max_coalesced_frames);
+		}
+		tg3_setup_phy(tp);
+		spin_unlock_irq(&tp->lock);
+
+		return 0;
+	}
+
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs;
+		u8 *regbuf;
+		int ret;
+
+		if (copy_from_user(&regs, useraddr, sizeof(regs)))
+			return -EFAULT;
+		if (regs.len > (32 * 1024))
+			regs.len = (32 * 1024);
+		regs.version = 0;
+		if (copy_to_user(useraddr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		regbuf = tg3_get_regs(tp);
+		if (!regbuf)
+			return -ENOMEM;
+
+		useraddr += offsetof(struct ethtool_regs, data);
+		ret = 0;
+		if (copy_to_user(useraddr, regbuf, regs.len))
+			ret = -EFAULT;
+		kfree(regbuf);
+		return ret;
+	}
+	case ETHTOOL_GWOL: {
+		struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
+
+		wol.supported = WAKE_MAGIC;
+		wol.wolopts = 0;
+		if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
+			wol.wolopts = WAKE_MAGIC;
+		memset(&wol.sopass, 0, sizeof(wol.sopass));
+		if (copy_to_user(useraddr, &wol, sizeof(wol)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SWOL: {
+		struct ethtool_wolinfo wol;
+
+		if (copy_from_user(&wol, useraddr, sizeof(wol)))
+			return -EFAULT;
+		if (wol.wolopts & ~WAKE_MAGIC)
+			return -EINVAL;
+		spin_lock_irq(&tp->lock);
+		if (wol.wolopts & WAKE_MAGIC)
+			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+		else
+			tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+		spin_unlock_irq(&tp->lock);
+
+		return 0;
+	}
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+		edata.data = tp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		tp->msg_enable = edata.data;
+		return 0;
+	}
+	case ETHTOOL_NWAY_RST: {
+		u32 bmcr;
+		int r;
+
+		spin_lock_irq(&tp->lock);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		tg3_readphy(tp, MII_BMCR, &bmcr);
+		r = -EINVAL;
+		if (bmcr & BMCR_ANENABLE) {
+			tg3_writephy(tp, MII_BMCR,
+				     bmcr | BMCR_ANRESTART);
+			r = 0;
+		}
+		spin_unlock_irq(&tp->lock);
+
+		return r;
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+	}
+	};
+
+	return -EOPNOTSUPP;
+}
+
+static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct tg3 *tp = dev->priv;
+	int err;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return tg3_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+	case SIOCGMIIPHY:
+		data->phy_id = PHY_ADDR;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u32 mii_regval;
+
+		spin_lock_irq(&tp->lock);
+		err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
+		spin_unlock_irq(&tp->lock);
+
+		data->val_out = mii_regval;
+
+		return err;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_irq(&tp->lock);
+		err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
+		spin_unlock_irq(&tp->lock);
+
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	}
+	return -EOPNOTSUPP;
+}
+
+#if TG3_VLAN_TAG_USED
+static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+	struct tg3 *tp = dev->priv;
+
+	spin_lock_irq(&tp->lock);
+	tp->vlgrp = grp;
+	spin_unlock_irq(&tp->lock);
+}
+
+static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct tg3 *tp = dev->priv;
+
+	spin_lock_irq(&tp->lock);
+	if (tp->vlgrp)
+		tp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_irq(&tp->lock);
+}
+#endif
+
+/* Chips other than 5700/5701 use the NVRAM for fetching info. */
+static void __devinit tg3_nvram_init(struct tg3 *tp)
+{
+	int j;
+
+	tw32(GRC_EEPROM_ADDR,
+	     (EEPROM_ADDR_FSM_RESET |
+	      (EEPROM_DEFAULT_CLOCK_PERIOD <<
+	       EEPROM_ADDR_CLKPERD_SHIFT)));
+
+	/* XXX schedule_timeout() ... */
+	for (j = 0; j < 100; j++)
+		udelay(10);
+
+	/* Enable seeprom accesses. */
+	tw32(GRC_LOCAL_CTRL,
+	     tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM);
+	udelay(100);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+		u32 nvcfg1 = tr32(NVRAM_CFG1);
+
+		tp->tg3_flags |= TG3_FLAG_NVRAM;
+		if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
+			if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
+				tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+		} else {
+			nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+			tw32(NVRAM_CFG1, nvcfg1);
+		}
+
+	} else {
+		tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
+	}
+}
+
+static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
+						 u32 offset, u32 *val)
+{
+	u32 tmp;
+	int i;
+
+	if (offset > EEPROM_ADDR_ADDR_MASK ||
+	    (offset % 4) != 0)
+		return -EINVAL;
+
+	tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
+					EEPROM_ADDR_DEVID_MASK |
+					EEPROM_ADDR_READ);
+	tw32(GRC_EEPROM_ADDR,
+	     tmp |
+	     (0 << EEPROM_ADDR_DEVID_SHIFT) |
+	     ((offset << EEPROM_ADDR_ADDR_SHIFT) &
+	      EEPROM_ADDR_ADDR_MASK) |
+	     EEPROM_ADDR_READ | EEPROM_ADDR_START);
+
+	for (i = 0; i < 10000; i++) {
+		tmp = tr32(GRC_EEPROM_ADDR);
+
+		if (tmp & EEPROM_ADDR_COMPLETE)
+			break;
+		udelay(100);
+	}
+	if (!(tmp & EEPROM_ADDR_COMPLETE))
+		return -EBUSY;
+
+	*val = tr32(GRC_EEPROM_DATA);
+	return 0;
+}
+
+static int __devinit tg3_nvram_read(struct tg3 *tp,
+				    u32 offset, u32 *val)
+{
+	int i, saw_done_clear;
+
+	if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
+		return tg3_nvram_read_using_eeprom(tp, offset, val);
+
+	if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
+		offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
+			  NVRAM_BUFFERED_PAGE_POS) +
+			(offset % NVRAM_BUFFERED_PAGE_SIZE);
+
+	if (offset > NVRAM_ADDR_MSK)
+		return -EINVAL;
+
+	tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+	for (i = 0; i < 1000; i++) {
+		if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+			break;
+		udelay(20);
+	}
+
+	tw32(NVRAM_ADDR, offset);
+	tw32(NVRAM_CMD,
+	     NVRAM_CMD_RD | NVRAM_CMD_GO |
+	     NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+
+	/* Wait for done bit to clear then set again. */
+	saw_done_clear = 0;
+	for (i = 0; i < 1000; i++) {
+		udelay(10);
+		if (!saw_done_clear &&
+		    !(tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
+			saw_done_clear = 1;
+		else if (saw_done_clear &&
+			 (tr32(NVRAM_CMD) & NVRAM_CMD_DONE))
+			break;
+	}
+	if (i >= 1000) {
+		tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
+		return -EBUSY;
+	}
+
+	*val = swab32(tr32(NVRAM_RDDATA));
+	tw32(NVRAM_SWARB, 0x20);
+
+	return 0;
+}
+
+struct subsys_tbl_ent {
+	u16 subsys_vendor, subsys_devid;
+	u32 phy_id;
+};
+
+static struct subsys_tbl_ent subsys_id_to_phy_id[] = {
+	/* Broadcom boards. */
+	{ 0x14e4, 0x1644, PHY_ID_BCM5401 }, /* BCM95700A6 */
+	{ 0x14e4, 0x0001, PHY_ID_BCM5701 }, /* BCM95701A5 */
+	{ 0x14e4, 0x0002, PHY_ID_BCM8002 }, /* BCM95700T6 */
+	{ 0x14e4, 0x0003, PHY_ID_SERDES  }, /* BCM95700A9 */
+	{ 0x14e4, 0x0005, PHY_ID_BCM5701 }, /* BCM95701T1 */
+	{ 0x14e4, 0x0006, PHY_ID_BCM5701 }, /* BCM95701T8 */
+	{ 0x14e4, 0x0007, PHY_ID_SERDES  }, /* BCM95701A7 */
+	{ 0x14e4, 0x0008, PHY_ID_BCM5701 }, /* BCM95701A10 */
+	{ 0x14e4, 0x8008, PHY_ID_BCM5701 }, /* BCM95701A12 */
+	{ 0x14e4, 0x0009, PHY_ID_BCM5701 }, /* BCM95703Ax1 */
+	{ 0x14e4, 0x8009, PHY_ID_BCM5701 }, /* BCM95703Ax2 */
+
+	/* 3com boards. */
+	{ PCI_VENDOR_ID_3COM, 0x1000, PHY_ID_BCM5401 }, /* 3C996T */
+	{ PCI_VENDOR_ID_3COM, 0x1006, PHY_ID_BCM5701 }, /* 3C996BT */
+	/* { PCI_VENDOR_ID_3COM, 0x1002, PHY_ID_XXX },     3C996CT */
+	/* { PCI_VENDOR_ID_3COM, 0x1003, PHY_ID_XXX },     3C997T */
+	{ PCI_VENDOR_ID_3COM, 0x1004, PHY_ID_SERDES  }, /* 3C996SX */
+	/* { PCI_VENDOR_ID_3COM, 0x1005, PHY_ID_XXX },     3C997SZ */
+	{ PCI_VENDOR_ID_3COM, 0x1007, PHY_ID_BCM5701 }, /* 3C1000T */
+	{ PCI_VENDOR_ID_3COM, 0x1008, PHY_ID_BCM5701 }, /* 3C940BR01 */
+
+	/* DELL boards. */
+	{ PCI_VENDOR_ID_DELL, 0x00d1, PHY_ID_BCM5401 }, /* VIPER */
+	{ PCI_VENDOR_ID_DELL, 0x0106, PHY_ID_BCM5401 }, /* JAGUAR */
+	{ PCI_VENDOR_ID_DELL, 0x0109, PHY_ID_BCM5411 }, /* MERLOT */
+	{ PCI_VENDOR_ID_DELL, 0x010a, PHY_ID_BCM5411 }, /* SLIM_MERLOT */
+
+	/* Compaq boards. */
+	{ PCI_VENDOR_ID_COMPAQ, 0x007c, PHY_ID_BCM5701 }, /* BANSHEE */
+	{ PCI_VENDOR_ID_COMPAQ, 0x009a, PHY_ID_BCM5701 }, /* BANSHEE_2 */
+	{ PCI_VENDOR_ID_COMPAQ, 0x007d, PHY_ID_SERDES  }, /* CHANGELING */
+	{ PCI_VENDOR_ID_COMPAQ, 0x0085, PHY_ID_BCM5701 }, /* NC7780 */
+	{ PCI_VENDOR_ID_COMPAQ, 0x0099, PHY_ID_BCM5701 }  /* NC7780_2 */
+};
+
+static int __devinit tg3_phy_probe(struct tg3 *tp)
+{
+	u32 eeprom_phy_id, hw_phy_id_1, hw_phy_id_2;
+	u32 hw_phy_id, hw_phy_id_masked;
+	enum phy_led_mode eeprom_led_mode;
+	u32 val;
+	int i, eeprom_signature_found, err;
+
+	tp->phy_id = PHY_ID_INVALID;
+	for (i = 0; i < ARRAY_SIZE(subsys_id_to_phy_id); i++) {
+		if ((subsys_id_to_phy_id[i].subsys_vendor ==
+		     tp->pdev->subsystem_vendor) &&
+		    (subsys_id_to_phy_id[i].subsys_devid ==
+		     tp->pdev->subsystem_device)) {
+			tp->phy_id = subsys_id_to_phy_id[i].phy_id;
+			break;
+		}
+	}
+
+	eeprom_phy_id = PHY_ID_INVALID;
+	eeprom_led_mode = led_mode_auto;
+	eeprom_signature_found = 0;
+	tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
+	if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+		u32 nic_cfg;
+
+		tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
+
+		eeprom_signature_found = 1;
+
+		if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
+		    NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER) {
+			eeprom_phy_id = PHY_ID_SERDES;
+		} else {
+			u32 nic_phy_id;
+
+			tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &nic_phy_id);
+			if (nic_phy_id != 0) {
+				u32 id1 = nic_phy_id & NIC_SRAM_DATA_PHY_ID1_MASK;
+				u32 id2 = nic_phy_id & NIC_SRAM_DATA_PHY_ID2_MASK;
+
+				eeprom_phy_id  = (id1 >> 16) << 10;
+				eeprom_phy_id |= (id2 & 0xfc00) << 16;
+				eeprom_phy_id |= (id2 & 0x03ff) <<  0;
+			}
+		}
+
+		switch (nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK) {
+		case NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD:
+			eeprom_led_mode = led_mode_three_link;
+			break;
+
+		case NIC_SRAM_DATA_CFG_LED_LINK_SPD:
+			eeprom_led_mode = led_mode_link10;
+			break;
+
+		default:
+			eeprom_led_mode = led_mode_auto;
+			break;
+		};
+	}
+
+	err = tg3_phy_reset(tp, 0);
+	if (err)
+		return err;
+
+	/* Now read the physical PHY_ID from the chip and verify
+	 * that it is sane.  If it doesn't look good, we fall back
+	 * to either the hard-coded table based PHY_ID and failing
+	 * that the value found in the eeprom area.
+	 */
+	err  = tg3_readphy(tp, MII_PHYSID1, &hw_phy_id_1);
+	err |= tg3_readphy(tp, MII_PHYSID2, &hw_phy_id_2);
+
+	hw_phy_id  = (hw_phy_id_1 & 0xffff) << 10;
+	hw_phy_id |= (hw_phy_id_2 & 0xfc00) << 16;
+	hw_phy_id |= (hw_phy_id_2 & 0x03ff) <<  0;
+
+	hw_phy_id_masked = hw_phy_id & PHY_ID_MASK;
+
+	if (!err && KNOWN_PHY_ID(hw_phy_id_masked)) {
+		tp->phy_id = hw_phy_id;
+	} else {
+		/* phy_id currently holds the value found in the
+		 * subsys_id_to_phy_id[] table or PHY_ID_INVALID
+		 * if a match was not found there.
+		 */
+		if (tp->phy_id == PHY_ID_INVALID) {
+			if (!eeprom_signature_found ||
+			    !KNOWN_PHY_ID(eeprom_phy_id & PHY_ID_MASK))
+				return -ENODEV;
+			tp->phy_id = eeprom_phy_id;
+		}
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
+		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+		tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f);
+		tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa);
+	}
+
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
+		tp->tg3_flags |= TG3_FLAG_PHY_RESET_ON_INIT;
+
+	if (tp->tg3_flags & TG3_FLAG_PHY_RESET_ON_INIT) {
+		u32 mii_tg3_ctrl;
+
+		err = tg3_phy_reset(tp, 1);
+		if (err)
+			return err;
+
+		/* These chips, when reset, only advertise 10Mb capabilities.
+		 * Fix that.
+		 */
+		err  = tg3_writephy(tp, MII_ADVERTISE,
+				    (ADVERTISE_CSMA |
+				     ADVERTISE_10HALF | ADVERTISE_10FULL |
+				     ADVERTISE_100HALF | ADVERTISE_100FULL));
+		mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF |
+				MII_TG3_CTRL_ADV_1000_FULL |
+				MII_TG3_CTRL_AS_MASTER |
+				MII_TG3_CTRL_ENABLE_AS_MASTER);
+		if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+			mii_tg3_ctrl = 0;
+
+		err |= tg3_writephy(tp, MII_TG3_CTRL, mii_tg3_ctrl);
+		err |= tg3_writephy(tp, MII_BMCR,
+				    (BMCR_ANRESTART | BMCR_ANENABLE));
+	}
+
+	if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) {
+		err = tg3_init_5401phy_dsp(tp);
+	}
+
+	/* Determine the PHY led mode. */
+	if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) {
+		tp->led_mode = led_mode_link10;
+	} else {
+		tp->led_mode = led_mode_three_link;
+		if (eeprom_signature_found &&
+		    eeprom_led_mode != led_mode_auto)
+			tp->led_mode = eeprom_led_mode;
+	}
+
+	if (tp->phy_id == PHY_ID_SERDES)
+		tp->link_config.advertising =
+			(ADVERTISED_1000baseT_Half |
+			 ADVERTISED_1000baseT_Full |
+			 ADVERTISED_Autoneg |
+			 ADVERTISED_FIBRE);
+	if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+		tp->link_config.advertising &=
+			~(ADVERTISED_1000baseT_Half |
+			  ADVERTISED_1000baseT_Full);
+
+	return err;
+}
+
+static void __devinit tg3_read_partno(struct tg3 *tp)
+{
+	unsigned char vpd_data[256];
+	int i;
+
+	for (i = 0; i < 256; i += 4) {
+		u32 tmp;
+
+		if (tg3_nvram_read(tp, 0x100 + i, &tmp))
+			goto out_not_found;
+
+		vpd_data[i + 0] = ((tmp >>  0) & 0xff);
+		vpd_data[i + 1] = ((tmp >>  8) & 0xff);
+		vpd_data[i + 2] = ((tmp >> 16) & 0xff);
+		vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+	}
+
+	/* Now parse and find the part number. */
+	for (i = 0; i < 256; ) {
+		unsigned char val = vpd_data[i];
+		int block_end;
+
+		if (val == 0x82 || val == 0x91) {
+			i = (i + 3 +
+			     (vpd_data[i + 1] +
+			      (vpd_data[i + 2] << 8)));
+			continue;
+		}
+
+		if (val != 0x90)
+			goto out_not_found;
+
+		block_end = (i + 3 +
+			     (vpd_data[i + 1] +
+			      (vpd_data[i + 2] << 8)));
+		i += 3;
+		while (i < block_end) {
+			if (vpd_data[i + 0] == 'P' &&
+			    vpd_data[i + 1] == 'N') {
+				int partno_len = vpd_data[i + 2];
+
+				if (partno_len > 24)
+					goto out_not_found;
+
+				memcpy(tp->board_part_number,
+				       &vpd_data[i + 3],
+				       partno_len);
+
+				/* Success. */
+				return;
+			}
+		}
+
+		/* Part number not found. */
+		goto out_not_found;
+	}
+
+out_not_found:
+	strcpy(tp->board_part_number, "none");
+}
+
+static int __devinit tg3_get_invariants(struct tg3 *tp)
+{
+	u32 misc_ctrl_reg;
+	u32 cacheline_sz_reg;
+	u32 pci_state_reg, grc_misc_cfg;
+	u16 pci_cmd;
+	int err;
+
+	/* Force memory write invalidate off.  If we leave it on,
+	 * then on 5700_BX chips we have to enable a workaround.
+	 * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
+	 * to match the cacheline size.  The Broadcom driver have this
+	 * workaround but turns MWI off all the times so never uses
+	 * it.  This seems to suggest that the workaround is insufficient.
+	 */
+	pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+	pci_cmd &= ~PCI_COMMAND_INVALIDATE;
+	pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+
+	pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			      &misc_ctrl_reg);
+
+	tp->pci_chip_rev_id = (misc_ctrl_reg >>
+			       MISC_HOST_CTRL_CHIPREV_SHIFT);
+
+	pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
+			      &cacheline_sz_reg);
+
+	tp->pci_cacheline_sz = (cacheline_sz_reg >> 24) & 0xff;
+	tp->pci_lat_timer    = (cacheline_sz_reg >> 16) & 0xff;
+	tp->pci_hdr_type     = (cacheline_sz_reg >>  8) & 0xff;
+	tp->pci_bist         = (cacheline_sz_reg >>  0) & 0xff;
+
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			      &pci_state_reg);
+
+	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
+		tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
+
+		/* If this is a 5700 BX chipset, and we are in PCI-X
+		 * mode, enable register write workaround.
+		 *
+		 * The workaround is to use indirect register accesses
+		 * for all chip writes not to mailbox registers.
+		 */
+		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
+			u32 pm_reg;
+			u16 pci_cmd;
+
+			tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
+
+			/* The chip can have it's power management PCI config
+			 * space registers clobbered due to this bug.
+			 * So explicitly force the chip into D0 here.
+			 */
+			pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+					      &pm_reg);
+			pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
+			pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
+			pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+					       pm_reg);
+
+			/* Also, force SERR#/PERR# in PCI command. */
+			pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
+			pci_cmd |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+			pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
+		}
+	}
+	if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
+		tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
+	if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
+		tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
+
+	/* Force the chip into D0. */
+	err = tg3_set_power_state(tp, 0);
+	if (err)
+		return err;
+
+	/* 5700 B0 chips do not support checksumming correctly due
+	 * to hardware bugs.
+	 */
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0)
+		tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS;
+
+	/* Regardless of whether checksums work or not, we configure
+	 * the StrongARM chips to not compute the pseudo header checksums
+	 * in either direction.  Because of the way Linux checksum support
+	 * works we do not need the chips to do this, and taking the load
+	 * off of the TX/RX onboard StrongARM cpus means that they will not be
+	 * the bottleneck.  Whoever wrote Broadcom's driver did not
+	 * understand the situation at all.  He could have bothered
+	 * to read Jes's Acenic driver because the logic (and this part of
+	 * the Tigon2 hardware/firmware) is pretty much identical.
+	 */
+	tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM;
+	tp->tg3_flags |= TG3_FLAG_NO_RX_PSEUDO_CSUM;
+
+	/* Derive initial jumbo mode from MTU assigned in
+	 * ether_setup() via the alloc_etherdev() call
+	 */
+	if (tp->dev->mtu > ETH_DATA_LEN)
+		tp->tg3_flags |= TG3_FLAG_JUMBO_ENABLE;
+
+	/* Determine WakeOnLan speed to use. */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 ||
+	    tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) {
+		tp->tg3_flags &= ~(TG3_FLAG_WOL_SPEED_100MB);
+	} else {
+		tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB;
+	}
+
+	/* Only 5701 and later support tagged irq status mode. */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) {
+		tp->tg3_flags |= TG3_FLAG_TAGGED_IRQ_STATUS;
+		tp->misc_host_ctrl |= MISC_HOST_CTRL_TAGGED_STATUS;
+
+		/* ??? Due to a glitch Broadcom's driver ALWAYS sets
+		 * ??? these bits in coalesce_mode.  Because MM_GetConfig
+		 * ??? always sets pDevice->UseTaggedStatus correctly
+		 * ??? the following test at tigon3.c:LM_GetAdapterInfo()
+		 * ???
+		 * ???   pDevice->UseTaggedStatus &&
+		 * ???   (pDevice->ChipRevId == T3_CHIP_ID_5700_C0 ||
+		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_AX ||
+		 * ???    T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX)
+		 * ???
+		 * ??? will never pass and thus pDevice->CoalesceMode will never
+		 * ??? get set to zero.  For now I'll mirror what I believe is
+		 * ??? the intention of their driver.
+		 * ???
+		 * ??? Update: This is fixed in Broadcom's 2.2.3 and later
+		 * ???         drivers.  All the current 2.0.x drivers still
+		 * ???         have the bug.
+		 */
+		tp->coalesce_mode = (HOSTCC_MODE_CLRTICK_RXBD |
+				     HOSTCC_MODE_CLRTICK_TXBD);
+	} else {
+		tp->coalesce_mode = 0;
+
+		/* If not using tagged status, set the *_during_int
+		 * coalesce default config values to zero.
+		 */
+		tp->coalesce_config.rx_coalesce_ticks_during_int = 0;
+		tp->coalesce_config.rx_max_coalesced_frames_during_int = 0;
+		tp->coalesce_config.tx_coalesce_ticks_during_int = 0;
+		tp->coalesce_config.tx_max_coalesced_frames_during_int = 0;
+	}
+
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_AX &&
+	    GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
+		tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
+
+	/* Initialize misc host control in PCI block. */
+	tp->misc_host_ctrl |= (misc_ctrl_reg &
+			       MISC_HOST_CTRL_CHIPREV);
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* Initialize MAC MI mode, polling disabled. */
+	tw32(MAC_MI_MODE, tp->mi_mode);
+	udelay(40);
+
+	/* Initialize data/descriptor byte/word swapping. */
+	tw32(GRC_MODE, tp->grc_mode);
+
+	/* Clear these out for sanity. */
+	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
+			      &pci_state_reg);
+	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) == 0) {
+		u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl);
+
+		if (chiprevid == CHIPREV_ID_5701_A0 ||
+		    chiprevid == CHIPREV_ID_5701_B0 ||
+		    chiprevid == CHIPREV_ID_5701_B2 ||
+		    chiprevid == CHIPREV_ID_5701_B5) {
+			unsigned long sram_base;
+
+			/* Write some dummy words into the SRAM status block
+			 * area, see if it reads back correctly.  If the return
+			 * value is bad, force enable the PCIX workaround.
+			 */
+			sram_base = tp->regs + NIC_SRAM_WIN_BASE + NIC_SRAM_STATS_BLK;
+
+			writel(0x00000000, sram_base);
+			writel(0x00000000, sram_base + 4);
+			writel(0xffffffff, sram_base + 4);
+			if (readl(sram_base) != 0x00000000)
+				tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
+		}
+	}
+
+	udelay(50);
+	tg3_nvram_init(tp);
+
+	/* Determine if TX descriptors will reside in
+	 * main memory or in the chip SRAM.
+	 */
+	if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
+		tp->tg3_flags |= TG3_FLAG_HOST_TXDS;
+
+	/* Quick sanity check.  Make sure we see an expected
+	 * value here.
+	 */
+	grc_misc_cfg = tr32(GRC_MISC_CFG);
+	grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
+	if (grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5700 &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5701 &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 &&
+	    grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S)
+		return -ENODEV;
+
+	/* ROFL, you should see Broadcom's driver code implementing
+	 * this, stuff like "if (a || b)" where a and b are always
+	 * mutually exclusive.  DaveM finds like 6 bugs today, hello!
+	 */
+	if (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5702FE)
+		tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
+
+	err = tg3_phy_probe(tp);
+
+	tg3_read_partno(tp);
+
+	if (tp->phy_id == PHY_ID_SERDES) {
+		tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+
+		/* And override led_mode in case Dell ever makes
+		 * a fibre board.
+		 */
+		tp->led_mode = led_mode_three_link;
+	} else {
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+			tp->tg3_flags |= TG3_FLAG_USE_MI_INTERRUPT;
+		else
+			tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT;
+	}
+
+	/* 5700 {AX,BX} chips have a broken status block link
+	 * change bit implementation, so we must use the
+	 * status register in those cases.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
+		tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_USE_LINKCHG_REG;
+
+	/* The led_mode is set during tg3_phy_probe, here we might
+	 * have to force the link status polling mechanism based
+	 * upon subsystem IDs.
+	 */
+	if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+	    tp->phy_id != PHY_ID_SERDES) {
+		tp->tg3_flags |= (TG3_FLAG_USE_MI_INTERRUPT |
+				  TG3_FLAG_USE_LINKCHG_REG);
+	}
+
+	/* 5700 BX chips need to have their TX producer index mailboxes
+	 * written twice to workaround a bug.
+	 */
+	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
+		tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
+	else
+		tp->tg3_flags &= ~TG3_FLAG_TXD_MBOX_HWBUG;
+
+	/* 5700 chips can get confused if TX buffers straddle the
+	 * 4GB address boundary in some cases.
+	 */
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+		/* ROFL!  Latest Broadcom driver disables NETIF_F_HIGHDMA
+		 * in this case instead of fixing their workaround code.
+		 *
+		 * Like, hey, there is this skb_copy() thing guys,
+		 * use it.  Oh I can't stop laughing...
+		 */
+		tp->dev->hard_start_xmit = tg3_start_xmit_4gbug;
+	} else {
+		tp->dev->hard_start_xmit = tg3_start_xmit;
+	}
+
+	tp->rx_offset = 2;
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
+		tp->rx_offset = 0;
+
+	return err;
+}
+
+static int __devinit tg3_get_device_address(struct tg3 *tp)
+{
+	struct net_device *dev = tp->dev;
+	u32 hi, lo;
+
+	/* First try to get it from MAC address mailbox. */
+	tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
+	if ((hi >> 16) == 0x484b) {
+		dev->dev_addr[0] = (hi >>  8) & 0xff;
+		dev->dev_addr[1] = (hi >>  0) & 0xff;
+
+		tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_LOW_MBOX, &lo);
+		dev->dev_addr[2] = (lo >> 24) & 0xff;
+		dev->dev_addr[3] = (lo >> 16) & 0xff;
+		dev->dev_addr[4] = (lo >>  8) & 0xff;
+		dev->dev_addr[5] = (lo >>  0) & 0xff;
+	}
+	/* Next, try NVRAM. */
+	else if (!tg3_nvram_read(tp, 0x7c, &hi) &&
+		 !tg3_nvram_read(tp, 0x80, &lo)) {
+		dev->dev_addr[0] = ((hi >> 16) & 0xff);
+		dev->dev_addr[1] = ((hi >> 24) & 0xff);
+		dev->dev_addr[2] = ((lo >>  0) & 0xff);
+		dev->dev_addr[3] = ((lo >>  8) & 0xff);
+		dev->dev_addr[4] = ((lo >> 16) & 0xff);
+		dev->dev_addr[5] = ((lo >> 24) & 0xff);
+	}
+	/* Finally just fetch it out of the MAC control regs. */
+	else {
+		hi = tr32(MAC_ADDR_0_HIGH);
+		lo = tr32(MAC_ADDR_0_LOW);
+
+		dev->dev_addr[5] = lo & 0xff;
+		dev->dev_addr[4] = (lo >> 8) & 0xff;
+		dev->dev_addr[3] = (lo >> 16) & 0xff;
+		dev->dev_addr[2] = (lo >> 24) & 0xff;
+		dev->dev_addr[1] = hi & 0xff;
+		dev->dev_addr[0] = (hi >> 8) & 0xff;
+	}
+
+	if (!is_valid_ether_addr(&dev->dev_addr[0]))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dma, int size, int to_device)
+{
+	struct tg3_internal_buffer_desc test_desc;
+	u32 sram_dma_descs;
+	int i, ret;
+
+	sram_dma_descs = NIC_SRAM_DMA_DESC_POOL_BASE;
+
+	tw32(FTQ_RCVBD_COMP_FIFO_ENQDEQ, 0);
+	tw32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ, 0);
+	tw32(RDMAC_STATUS, 0);
+	tw32(WDMAC_STATUS, 0);
+
+	tw32(BUFMGR_MODE, 0);
+	tw32(FTQ_RESET, 0);
+
+	/* pci_alloc_consistent gives only non-DAC addresses */
+	test_desc.addr_hi = 0;
+	test_desc.addr_lo = buf_dma & 0xffffffff;
+	test_desc.nic_mbuf = 0x00002100;
+	test_desc.len = size;
+	if (to_device) {
+		test_desc.cqid_sqid = (13 << 8) | 2;
+		tw32(RDMAC_MODE, RDMAC_MODE_RESET);
+		tw32(RDMAC_MODE, RDMAC_MODE_ENABLE);
+	} else {
+		test_desc.cqid_sqid = (16 << 8) | 7;
+		tw32(WDMAC_MODE, WDMAC_MODE_RESET);
+		tw32(WDMAC_MODE, WDMAC_MODE_ENABLE);
+	}
+	test_desc.flags = 0x00000004;
+
+	for (i = 0; i < (sizeof(test_desc) / sizeof(u32)); i++) {
+		u32 val;
+
+		val = *(((u32 *)&test_desc) + i);
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR,
+				       sram_dma_descs + (i * sizeof(u32)));
+		pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
+	}
+	pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
+
+	if (to_device) {
+		tw32(FTQ_DMA_HIGH_READ_FIFO_ENQDEQ, sram_dma_descs);
+	} else {
+		tw32(FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ, sram_dma_descs);
+	}
+
+	ret = -ENODEV;
+	for (i = 0; i < 40; i++) {
+		u32 val;
+
+		if (to_device)
+			val = tr32(FTQ_RCVBD_COMP_FIFO_ENQDEQ);
+		else
+			val = tr32(FTQ_RCVDATA_COMP_FIFO_ENQDEQ);
+		if ((val & 0xffff) == sram_dma_descs) {
+			ret = 0;
+			break;
+		}
+
+		udelay(100);
+	}
+
+	return ret;
+}
+
+#define TEST_BUFFER_SIZE	0x400
+
+static int __devinit tg3_test_dma(struct tg3 *tp)
+{
+	dma_addr_t buf_dma;
+	u32 *buf;
+	int ret;
+
+	buf = pci_alloc_consistent(tp->pdev, TEST_BUFFER_SIZE, &buf_dma);
+	if (!buf) {
+		ret = -ENOMEM;
+		goto out_nofree;
+	}
+
+	tw32(TG3PCI_CLOCK_CTRL, 0);
+
+	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) == 0) {
+		tp->dma_rwctrl =
+			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+			(0x7 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+			(0x7 << DMA_RWCTRL_READ_WATER_SHIFT) |
+			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+	} else {
+		tp->dma_rwctrl =
+			(0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) |
+			(0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) |
+			(0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) |
+			(0x3 << DMA_RWCTRL_READ_WATER_SHIFT) |
+			(0x0f << DMA_RWCTRL_MIN_DMA_SHIFT);
+
+		/* Wheee, some more chip bugs... */
+		if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 ||
+		    tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)
+			tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA;
+	}
+
+	/* We don't do this on x86 because it seems to hurt performace.
+	 * It does help things on other platforms though.
+	 */
+#ifndef CONFIG_X86
+	{
+		u8 byte;
+		int cacheline_size;
+		pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, &byte);
+
+		if (byte == 0)
+			cacheline_size = 1024;
+		else
+			cacheline_size = (int) byte * 4;
+
+		tp->dma_rwctrl &= ~(DMA_RWCTRL_READ_BNDRY_MASK |
+				    DMA_RWCTRL_WRITE_BNDRY_MASK);
+
+		switch (cacheline_size) {
+		case 16:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_16 |
+				 DMA_RWCTRL_WRITE_BNDRY_16);
+			break;
+
+		case 32:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_32 |
+				 DMA_RWCTRL_WRITE_BNDRY_32);
+			break;
+
+		case 64:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_64 |
+				 DMA_RWCTRL_WRITE_BNDRY_64);
+			break;
+
+		case 128:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_128 |
+				 DMA_RWCTRL_WRITE_BNDRY_128);
+			break;
+
+		case 256:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_256 |
+				 DMA_RWCTRL_WRITE_BNDRY_256);
+			break;
+
+		case 512:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_512 |
+				 DMA_RWCTRL_WRITE_BNDRY_512);
+			break;
+
+		case 1024:
+			tp->dma_rwctrl |=
+				(DMA_RWCTRL_READ_BNDRY_1024 |
+				 DMA_RWCTRL_WRITE_BNDRY_1024);
+			break;
+		};
+	}
+#endif
+
+	/* Remove this if it causes problems for some boards. */
+	tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
+
+	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	ret = 0;
+	while (1) {
+		u32 *p, i;
+
+		p = buf;
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++)
+			p[i] = i;
+
+		/* Send the buffer to the chip. */
+		ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 1);
+		if (ret)
+			break;
+
+		p = buf;
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++)
+			p[i] = 0;
+
+		/* Now read it back. */
+		ret = tg3_do_test_dma(tp, buf, buf_dma, TEST_BUFFER_SIZE, 0);
+		if (ret)
+			break;
+
+		/* Verify it. */
+		p = buf;
+		for (i = 0; i < TEST_BUFFER_SIZE / sizeof(u32); i++) {
+			if (p[i] == i)
+				continue;
+
+			if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) ==
+			    DMA_RWCTRL_WRITE_BNDRY_DISAB) {
+				tp->dma_rwctrl |= DMA_RWCTRL_WRITE_BNDRY_16;
+				tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+				break;
+			} else {
+				ret = -ENODEV;
+				goto out;
+			}
+		}
+
+		if (i == (TEST_BUFFER_SIZE / sizeof(u32))) {
+			/* Success. */
+			ret = 0;
+			break;
+		}
+	}
+
+out:
+	pci_free_consistent(tp->pdev, TEST_BUFFER_SIZE, buf, buf_dma);
+out_nofree:
+	return ret;
+}
+
+static void __devinit tg3_init_link_config(struct tg3 *tp)
+{
+	tp->link_config.advertising =
+		(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+		 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+		 ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full |
+		 ADVERTISED_Autoneg | ADVERTISED_MII);
+	tp->link_config.speed = SPEED_INVALID;
+	tp->link_config.duplex = DUPLEX_INVALID;
+	tp->link_config.autoneg = AUTONEG_ENABLE;
+	netif_carrier_off(tp->dev);
+	tp->link_config.active_speed = SPEED_INVALID;
+	tp->link_config.active_duplex = DUPLEX_INVALID;
+	tp->link_config.phy_is_low_power = 0;
+	tp->link_config.orig_speed = SPEED_INVALID;
+	tp->link_config.orig_duplex = DUPLEX_INVALID;
+	tp->link_config.orig_autoneg = AUTONEG_INVALID;
+}
+
+static void __devinit tg3_init_coalesce_config(struct tg3 *tp)
+{
+	tp->coalesce_config.rx_coalesce_ticks = DEFAULT_RXCOL_TICKS;
+	tp->coalesce_config.rx_max_coalesced_frames = DEFAULT_RXMAX_FRAMES;
+	tp->coalesce_config.rx_coalesce_ticks_during_int =
+		DEFAULT_RXCOAL_TICK_INT;
+	tp->coalesce_config.rx_max_coalesced_frames_during_int =
+		DEFAULT_RXCOAL_MAXF_INT;
+	tp->coalesce_config.tx_coalesce_ticks = DEFAULT_TXCOL_TICKS;
+	tp->coalesce_config.tx_max_coalesced_frames = DEFAULT_TXMAX_FRAMES;
+	tp->coalesce_config.tx_coalesce_ticks_during_int =
+		DEFAULT_TXCOAL_TICK_INT;
+	tp->coalesce_config.tx_max_coalesced_frames_during_int =
+		DEFAULT_TXCOAL_MAXF_INT;
+	tp->coalesce_config.stats_coalesce_ticks =
+		DEFAULT_STAT_COAL_TICKS;
+}
+
+static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
+{
+	tp->bufmgr_config.mbuf_read_dma_low_water =
+		DEFAULT_MB_RDMA_LOW_WATER;
+	tp->bufmgr_config.mbuf_mac_rx_low_water =
+		DEFAULT_MB_MACRX_LOW_WATER;
+	tp->bufmgr_config.mbuf_high_water =
+		DEFAULT_MB_HIGH_WATER;
+
+	tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
+		DEFAULT_MB_RDMA_LOW_WATER_JUMBO;
+	tp->bufmgr_config.mbuf_mac_rx_low_water_jumbo =
+		DEFAULT_MB_MACRX_LOW_WATER_JUMBO;
+	tp->bufmgr_config.mbuf_high_water_jumbo =
+		DEFAULT_MB_HIGH_WATER_JUMBO;
+
+	tp->bufmgr_config.dma_low_water = DEFAULT_DMA_LOW_WATER;
+	tp->bufmgr_config.dma_high_water = DEFAULT_DMA_HIGH_WATER;
+}
+
+static char * __devinit tg3_phy_string(struct tg3 *tp)
+{
+	switch (tp->phy_id & PHY_ID_MASK) {
+	case PHY_ID_BCM5400:	return "5400";
+	case PHY_ID_BCM5401:	return "5401";
+	case PHY_ID_BCM5411:	return "5411";
+	case PHY_ID_BCM5701:	return "5701";
+	case PHY_ID_BCM5703:	return "5703";
+	case PHY_ID_BCM8002:	return "8002";
+	case PHY_ID_SERDES:	return "serdes";
+	default:		return "unknown";
+	};
+}
+
+static int __devinit tg3_init_one(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	static int tg3_version_printed = 0;
+	unsigned long tg3reg_base, tg3reg_len;
+	struct net_device *dev;
+	struct tg3 *tp;
+	int i, err, pci_using_dac, pm_cap;
+
+	if (tg3_version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device, "
+		       "aborting.\n");
+		return err;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find proper PCI device "
+		       "base address, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+		       "aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	/* Find power-management capability. */
+	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+	if (pm_cap == 0) {
+		printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
+		       "aborting.\n");
+		goto err_out_free_res;
+	}
+
+	/* Configure DMA attributes. */
+	if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) {
+		pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+		if (err) {
+			printk(KERN_ERR PFX "No usable DMA configuration, "
+			       "aborting.\n");
+			goto err_out_free_res;
+		}
+		pci_using_dac = 0;
+	}
+
+	tg3reg_base = pci_resource_start(pdev, 0);
+	tg3reg_len = pci_resource_len(pdev, 0);
+
+	dev = alloc_etherdev(sizeof(*tp));
+	if (!dev) {
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	if (pci_using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
+#if TG3_VLAN_TAG_USED
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register = tg3_vlan_rx_register;
+	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
+#endif
+
+	tp = dev->priv;
+	tp->pdev = pdev;
+	tp->dev = dev;
+	tp->pm_cap = pm_cap;
+	tp->mac_mode = TG3_DEF_MAC_MODE;
+	tp->rx_mode = TG3_DEF_RX_MODE;
+	tp->tx_mode = TG3_DEF_TX_MODE;
+	tp->mi_mode = MAC_MI_MODE_BASE;
+	if (tg3_debug > 0)
+		tp->msg_enable = tg3_debug;
+	else
+		tp->msg_enable = TG3_DEF_MSG_ENABLE;
+
+	/* The word/byte swap controls here control register access byte
+	 * swapping.  DMA data byte swapping is controlled in the GRC_MODE
+	 * setting below.
+	 */
+	tp->misc_host_ctrl =
+		MISC_HOST_CTRL_MASK_PCI_INT |
+		MISC_HOST_CTRL_WORD_SWAP |
+		MISC_HOST_CTRL_INDIR_ACCESS |
+		MISC_HOST_CTRL_PCISTATE_RW;
+
+	/* The NONFRM (non-frame) byte/word swap controls take effect
+	 * on descriptor entries, anything which isn't packet data.
+	 *
+	 * The StrongARM chips on the board (one for tx, one for rx)
+	 * are running in big-endian mode.
+	 */
+	tp->grc_mode = (GRC_MODE_WSWAP_DATA | GRC_MODE_BSWAP_DATA |
+			GRC_MODE_WSWAP_NONFRM_DATA);
+#ifdef __BIG_ENDIAN
+	tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
+#endif
+	spin_lock_init(&tp->lock);
+	spin_lock_init(&tp->indirect_lock);
+
+	tp->regs = (unsigned long) ioremap(tg3reg_base, tg3reg_len);
+	if (tp->regs == 0UL) {
+		printk(KERN_ERR PFX "Cannot map device registers, "
+		       "aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	tg3_init_link_config(tp);
+
+	tg3_init_coalesce_config(tp);
+
+	tg3_init_bufmgr_config(tp);
+
+	dev->open = tg3_open;
+	dev->stop = tg3_close;
+	dev->get_stats = tg3_get_stats;
+	dev->set_multicast_list = tg3_set_rx_mode;
+	dev->set_mac_address = tg3_set_mac_addr;
+	dev->do_ioctl = tg3_ioctl;
+	dev->tx_timeout = tg3_tx_timeout;
+	dev->watchdog_timeo = TG3_TX_TIMEOUT;
+	dev->change_mtu = tg3_change_mtu;
+	dev->irq = pdev->irq;
+
+	err = tg3_get_invariants(tp);
+	if (err) {
+		printk(KERN_ERR PFX "Problem fetching invariants of chip, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	err = tg3_get_device_address(tp);
+	if (err) {
+		printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	err = tg3_test_dma(tp);
+	if (err) {
+		printk(KERN_ERR PFX "DMA engine test failed, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	/* Tigon3 can do ipv4 only... and some chips have buggy
+	 * checksumming.
+	 */
+	if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0)
+		dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	/* Now that we have fully setup the chip, save away a snapshot
+	 * of the PCI config space.  We need to restore this after
+	 * GRC_MISC_CFG core clock resets and some resume events.
+	 */
+	pci_save_state(tp->pdev, tp->pci_cfg_state);
+
+	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ",
+	       dev->name,
+	       tp->board_part_number,
+	       tp->pci_chip_rev_id,
+	       tg3_phy_string(tp),
+	       ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "X" : ""),
+	       ((tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED) ?
+		((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "133MHz" : "66MHz") :
+		((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ? "100MHz" : "33MHz")),
+	       ((tp->tg3_flags & TG3_FLAG_PCI_32BIT) ? "32-bit" : "64-bit"),
+	       (tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100" : "10/100/1000");
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i],
+		       i == 5 ? '\n' : ':');
+
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *) tp->regs);
+
+err_out_free_dev:
+	kfree(dev);
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void __devexit tg3_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		unregister_netdev(dev);
+		iounmap((void *) ((struct tg3 *)(dev->priv))->regs);
+		kfree(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static int tg3_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tg3 *tp = dev->priv;
+	int err;
+
+	if (!netif_running(dev))
+		return 0;
+
+	spin_lock_irq(&tp->lock);
+	tg3_disable_ints(tp);
+	spin_unlock_irq(&tp->lock);
+
+	netif_device_detach(dev);
+
+	spin_lock_irq(&tp->lock);
+	tg3_halt(tp);
+	spin_unlock_irq(&tp->lock);
+
+	err = tg3_set_power_state(tp, state);
+	if (err) {
+		spin_lock_irq(&tp->lock);
+
+		tg3_init_rings(tp);
+		tg3_init_hw(tp);
+
+		spin_unlock_irq(&tp->lock);
+
+		netif_device_attach(dev);
+	}
+
+	return err;
+}
+
+static int tg3_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct tg3 *tp = dev->priv;
+	int err;
+
+	if (!netif_running(dev))
+		return 0;
+
+	err = tg3_set_power_state(tp, 0);
+	if (err)
+		return err;
+
+	netif_device_attach(dev);
+
+	spin_lock_irq(&tp->lock);
+
+	tg3_init_rings(tp);
+	tg3_init_hw(tp);
+	tg3_enable_ints(tp);
+
+	spin_unlock_irq(&tp->lock);
+
+	return 0;
+}
+
+static struct pci_driver tg3_driver = {
+	name:		DRV_MODULE_NAME,
+	id_table:	tg3_pci_tbl,
+	probe:		tg3_init_one,
+	remove:		__devexit_p(tg3_remove_one),
+	suspend:	tg3_suspend,
+	resume:		tg3_resume
+};
+
+static int __init tg3_init(void)
+{
+	return pci_module_init(&tg3_driver);
+}
+
+static void __exit tg3_cleanup(void)
+{
+	pci_unregister_driver(&tg3_driver);
+}
+
+module_init(tg3_init);
+module_exit(tg3_cleanup);
diff -urN linux-2.5.6-pre3/drivers/net/tg3.h linux-2.5.6/drivers/net/tg3.h
--- linux-2.5.6-pre3/drivers/net/tg3.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tg3.h	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,1851 @@
+/* $Id: tg3.h,v 1.37.2.30 2002/03/05 10:08:39 davem Exp $
+ * tg3.h: Definitions for Broadcom Tigon3 ethernet driver.
+ *
+ * Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001 Jeff Garzik (jgarzik@mandrakesoft.com)
+ */
+
+#ifndef _T3_H
+#define _T3_H
+
+#define TG3_64BIT_REG_HIGH		0x00UL
+#define TG3_64BIT_REG_LOW		0x04UL
+
+/* Descriptor block info. */
+#define TG3_BDINFO_HOST_ADDR		0x0UL /* 64-bit */
+#define TG3_BDINFO_MAXLEN_FLAGS		0x8UL /* 32-bit */
+#define  BDINFO_FLAGS_USE_EXT_RECV	 0x00000001 /* ext rx_buffer_desc */
+#define  BDINFO_FLAGS_DISABLED		 0x00000002
+#define  BDINFO_FLAGS_MAXLEN_MASK	 0xffff0000
+#define  BDINFO_FLAGS_MAXLEN_SHIFT	 16
+#define TG3_BDINFO_NIC_ADDR		0xcUL /* 32-bit */
+#define TG3_BDINFO_SIZE			0x10UL
+
+#define RX_COPY_THRESHOLD  		256
+
+#define RX_STD_MAX_SIZE			1536
+#define RX_JUMBO_MAX_SIZE		0xdeadbeef /* XXX */
+#if TG3_MINI_RING_WORKS
+#define RX_MINI_MAX_SIZE		256
+#endif
+
+/* First 256 bytes are a mirror of PCI config space. */
+#define TG3PCI_VENDOR			0x00000000
+#define  TG3PCI_VENDOR_BROADCOM		 0x14e4
+#define TG3PCI_DEVICE			0x00000002
+#define  TG3PCI_DEVICE_TIGON3_1		 0x1644 /* BCM5700 */
+#define  TG3PCI_DEVICE_TIGON3_2		 0x1645 /* BCM5701 */
+#define  TG3PCI_DEVICE_TIGON3_3		 0x1646 /* BCM5702 */
+#define  TG3PCI_DEVICE_TIGON3_4		 0x1647 /* BCM5703 */
+#define TG3PCI_COMMAND			0x00000004
+#define TG3PCI_STATUS			0x00000006
+#define TG3PCI_CCREVID			0x00000008
+#define TG3PCI_CACHELINESZ		0x0000000c
+#define TG3PCI_LATTIMER			0x0000000d
+#define TG3PCI_HEADERTYPE		0x0000000e
+#define TG3PCI_BIST			0x0000000f
+#define TG3PCI_BASE0_LOW		0x00000010
+#define TG3PCI_BASE0_HIGH		0x00000014
+/* 0x18 --> 0x2c unused */
+#define TG3PCI_SUBSYSVENID		0x0000002c
+#define TG3PCI_SUBSYSID			0x0000002e
+#define TG3PCI_ROMADDR			0x00000030
+#define TG3PCI_CAPLIST			0x00000034
+/* 0x35 --> 0x3c unused */
+#define TG3PCI_IRQ_LINE			0x0000003c
+#define TG3PCI_IRQ_PIN			0x0000003d
+#define TG3PCI_MIN_GNT			0x0000003e
+#define TG3PCI_MAX_LAT			0x0000003f
+#define TG3PCI_X_CAPS			0x00000040
+#define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
+#define TG3PCI_PM_CAP_PTR		0x00000041
+#define TG3PCI_X_COMMAND		0x00000042
+#define TG3PCI_X_STATUS			0x00000044
+#define TG3PCI_PM_CAP_ID		0x00000048
+#define TG3PCI_VPD_CAP_PTR		0x00000049
+#define TG3PCI_PM_CAPS			0x0000004a
+#define TG3PCI_PM_CTRL_STAT		0x0000004c
+#define TG3PCI_BR_SUPP_EXT		0x0000004e
+#define TG3PCI_PM_DATA			0x0000004f
+#define TG3PCI_VPD_CAP_ID		0x00000050
+#define TG3PCI_MSI_CAP_PTR		0x00000051
+#define TG3PCI_VPD_ADDR_FLAG		0x00000052
+#define  VPD_ADDR_FLAG_WRITE		0x00008000
+#define TG3PCI_VPD_DATA			0x00000054
+#define TG3PCI_MSI_CAP_ID		0x00000058
+#define TG3PCI_NXT_CAP_PTR		0x00000059
+#define TG3PCI_MSI_CTRL			0x0000005a
+#define TG3PCI_MSI_ADDR_LOW		0x0000005c
+#define TG3PCI_MSI_ADDR_HIGH		0x00000060
+#define TG3PCI_MSI_DATA			0x00000064
+/* 0x66 --> 0x68 unused */
+#define TG3PCI_MISC_HOST_CTRL		0x00000068
+#define  MISC_HOST_CTRL_CLEAR_INT	 0x00000001
+#define  MISC_HOST_CTRL_MASK_PCI_INT	 0x00000002
+#define  MISC_HOST_CTRL_BYTE_SWAP	 0x00000004
+#define  MISC_HOST_CTRL_WORD_SWAP	 0x00000008
+#define  MISC_HOST_CTRL_PCISTATE_RW	 0x00000010
+#define  MISC_HOST_CTRL_CLKREG_RW	 0x00000020
+#define  MISC_HOST_CTRL_REGWORD_SWAP	 0x00000040
+#define  MISC_HOST_CTRL_INDIR_ACCESS	 0x00000080
+#define  MISC_HOST_CTRL_IRQ_MASK_MODE	 0x00000100
+#define  MISC_HOST_CTRL_TAGGED_STATUS	 0x00000200
+#define  MISC_HOST_CTRL_CHIPREV		 0xffff0000
+#define  MISC_HOST_CTRL_CHIPREV_SHIFT	 16
+#define  GET_CHIP_REV_ID(MISC_HOST_CTRL) \
+	 (((MISC_HOST_CTRL) & MISC_HOST_CTRL_CHIPREV) >> \
+	  MISC_HOST_CTRL_CHIPREV_SHIFT)
+#define  CHIPREV_ID_5700_A0		 0x7000
+#define  CHIPREV_ID_5700_A1		 0x7001
+#define  CHIPREV_ID_5700_B0		 0x7100
+#define  CHIPREV_ID_5700_B1		 0x7101
+#define  CHIPREV_ID_5700_C0		 0x7200
+#define  CHIPREV_ID_5701_A0		 0x0000
+#define  CHIPREV_ID_5701_B0		 0x0100
+#define  CHIPREV_ID_5701_B2		 0x0102
+#define  CHIPREV_ID_5701_B5		 0x0105
+#define  CHIPREV_ID_5703_A0		 0x1000
+#define  CHIPREV_ID_5703_A1		 0x1001
+#define  CHIPREV_ID_5703_A2		 0x1002
+#define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
+#define   ASIC_REV_5700			 0x07
+#define   ASIC_REV_5701			 0x00
+#define   ASIC_REV_5703			 0x01
+#define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
+#define   CHIPREV_5700_AX		 0x70
+#define   CHIPREV_5700_BX		 0x71
+#define   CHIPREV_5700_CX		 0x72
+#define   CHIPREV_5701_AX		 0x00
+#define  GET_METAL_REV(CHIP_REV_ID)	((CHIP_REV_ID) & 0xff)
+#define   METAL_REV_A0			 0x00
+#define   METAL_REV_A1			 0x01
+#define   METAL_REV_B0			 0x00
+#define   METAL_REV_B1			 0x01
+#define   METAL_REV_B2			 0x02
+#define TG3PCI_DMA_RW_CTRL		0x0000006c
+#define  DMA_RWCTRL_MIN_DMA		 0x000000ff
+#define  DMA_RWCTRL_MIN_DMA_SHIFT	 0
+#define  DMA_RWCTRL_READ_BNDRY_MASK	 0x00000700
+#define  DMA_RWCTRL_READ_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_READ_BNDRY_16	 0x00000100
+#define  DMA_RWCTRL_READ_BNDRY_32	 0x00000200
+#define  DMA_RWCTRL_READ_BNDRY_64	 0x00000300
+#define  DMA_RWCTRL_READ_BNDRY_128	 0x00000400
+#define  DMA_RWCTRL_READ_BNDRY_256	 0x00000500
+#define  DMA_RWCTRL_READ_BNDRY_512	 0x00000600
+#define  DMA_RWCTRL_READ_BNDRY_1024	 0x00000700
+#define  DMA_RWCTRL_WRITE_BNDRY_MASK	 0x00003800
+#define  DMA_RWCTRL_WRITE_BNDRY_DISAB	 0x00000000
+#define  DMA_RWCTRL_WRITE_BNDRY_16	 0x00000800
+#define  DMA_RWCTRL_WRITE_BNDRY_32	 0x00001000
+#define  DMA_RWCTRL_WRITE_BNDRY_64	 0x00001800
+#define  DMA_RWCTRL_WRITE_BNDRY_128	 0x00002000
+#define  DMA_RWCTRL_WRITE_BNDRY_256	 0x00002800
+#define  DMA_RWCTRL_WRITE_BNDRY_512	 0x00003000
+#define  DMA_RWCTRL_WRITE_BNDRY_1024	 0x00003800
+#define  DMA_RWCTRL_ONE_DMA		 0x00004000
+#define  DMA_RWCTRL_READ_WATER		 0x00070000
+#define  DMA_RWCTRL_READ_WATER_SHIFT	 16
+#define  DMA_RWCTRL_WRITE_WATER		 0x00380000
+#define  DMA_RWCTRL_WRITE_WATER_SHIFT	 19
+#define  DMA_RWCTRL_USE_MEM_READ_MULT	 0x00400000
+#define  DMA_RWCTRL_ASSERT_ALL_BE	 0x00800000
+#define  DMA_RWCTRL_PCI_READ_CMD	 0x0f000000
+#define  DMA_RWCTRL_PCI_READ_CMD_SHIFT	 24
+#define  DMA_RWCTRL_PCI_WRITE_CMD	 0xf0000000
+#define  DMA_RWCTRL_PCI_WRITE_CMD_SHIFT	 28
+#define TG3PCI_PCISTATE			0x00000070
+#define  PCISTATE_FORCE_RESET		 0x00000001
+#define  PCISTATE_INT_NOT_ACTIVE	 0x00000002
+#define  PCISTATE_CONV_PCI_MODE		 0x00000004
+#define  PCISTATE_BUS_SPEED_HIGH	 0x00000008
+#define  PCISTATE_BUS_32BIT		 0x00000010
+#define  PCISTATE_ROM_ENABLE		 0x00000020
+#define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
+#define  PCISTATE_FLAT_VIEW		 0x00000100
+#define TG3PCI_CLOCK_CTRL		0x00000074
+#define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
+#define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
+#define  CLOCK_CTRL_TXCLK_DISABLE	 0x00000800
+#define  CLOCK_CTRL_ALTCLK		 0x00001000
+#define  CLOCK_CTRL_PWRDOWN_PLL133	 0x00008000
+#define  CLOCK_CTRL_44MHZ_CORE		 0x00040000
+#define  CLOCK_CTRL_DELAY_PCI_GRANT	 0x80000000
+#define TG3PCI_REG_BASE_ADDR		0x00000078
+#define TG3PCI_MEM_WIN_BASE_ADDR	0x0000007c
+#define TG3PCI_REG_DATA			0x00000080
+#define TG3PCI_MEM_WIN_DATA		0x00000084
+#define TG3PCI_MODE_CTRL		0x00000088
+#define TG3PCI_MISC_CFG			0x0000008c
+#define TG3PCI_MISC_LOCAL_CTRL		0x00000090
+/* 0x94 --> 0x98 unused */
+#define TG3PCI_STD_RING_PROD_IDX	0x00000098 /* 64-bit */
+#define TG3PCI_RCV_RET_RING_CON_IDX	0x000000a0 /* 64-bit */
+#define TG3PCI_SND_PROD_IDX		0x000000a8 /* 64-bit */
+/* 0xb0 --> 0x100 unused */
+
+/* 0x100 --> 0x200 unused */
+
+/* Mailbox registers */
+#define MAILBOX_INTERRUPT_0		0x00000200 /* 64-bit */
+#define MAILBOX_INTERRUPT_1		0x00000208 /* 64-bit */
+#define MAILBOX_INTERRUPT_2		0x00000210 /* 64-bit */
+#define MAILBOX_INTERRUPT_3		0x00000218 /* 64-bit */
+#define MAILBOX_GENERAL_0		0x00000220 /* 64-bit */
+#define MAILBOX_GENERAL_1		0x00000228 /* 64-bit */
+#define MAILBOX_GENERAL_2		0x00000230 /* 64-bit */
+#define MAILBOX_GENERAL_3		0x00000238 /* 64-bit */
+#define MAILBOX_GENERAL_4		0x00000240 /* 64-bit */
+#define MAILBOX_GENERAL_5		0x00000248 /* 64-bit */
+#define MAILBOX_GENERAL_6		0x00000250 /* 64-bit */
+#define MAILBOX_GENERAL_7		0x00000258 /* 64-bit */
+#define MAILBOX_RELOAD_STAT		0x00000260 /* 64-bit */
+#define MAILBOX_RCV_STD_PROD_IDX	0x00000268 /* 64-bit */
+#define MAILBOX_RCV_JUMBO_PROD_IDX	0x00000270 /* 64-bit */
+#define MAILBOX_RCV_MINI_PROD_IDX	0x00000278 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_0	0x00000280 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_1	0x00000288 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_2	0x00000290 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_3	0x00000298 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_4	0x000002a0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_5	0x000002a8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_6	0x000002b0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_7	0x000002b8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_8	0x000002c0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_9	0x000002c8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_10	0x000002d0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_11	0x000002d8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_12	0x000002e0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_13	0x000002e8 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_14	0x000002f0 /* 64-bit */
+#define MAILBOX_RCVRET_CON_IDX_15	0x000002f8 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_0	0x00000300 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_1	0x00000308 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_2	0x00000310 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_3	0x00000318 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_4	0x00000320 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_5	0x00000328 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_6	0x00000330 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_7	0x00000338 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_8	0x00000340 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_9	0x00000348 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_10	0x00000350 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_11	0x00000358 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_12	0x00000360 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_13	0x00000368 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_14	0x00000370 /* 64-bit */
+#define MAILBOX_SNDHOST_PROD_IDX_15	0x00000378 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_0	0x00000380 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_1	0x00000388 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_2	0x00000390 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_3	0x00000398 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_4	0x000003a0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_5	0x000003a8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_6	0x000003b0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_7	0x000003b8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_8	0x000003c0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_9	0x000003c8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_10	0x000003d0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_11	0x000003d8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_12	0x000003e0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_13	0x000003e8 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_14	0x000003f0 /* 64-bit */
+#define MAILBOX_SNDNIC_PROD_IDX_15	0x000003f8 /* 64-bit */
+
+/* MAC control registers */
+#define MAC_MODE			0x00000400
+#define  MAC_MODE_RESET			 0x00000001
+#define  MAC_MODE_HALF_DUPLEX		 0x00000002
+#define  MAC_MODE_PORT_MODE_MASK	 0x0000000c
+#define  MAC_MODE_PORT_MODE_TBI		 0x0000000c
+#define  MAC_MODE_PORT_MODE_GMII	 0x00000008
+#define  MAC_MODE_PORT_MODE_MII		 0x00000004
+#define  MAC_MODE_PORT_MODE_NONE	 0x00000000
+#define  MAC_MODE_PORT_INT_LPBACK	 0x00000010
+#define  MAC_MODE_TAGGED_MAC_CTRL	 0x00000080
+#define  MAC_MODE_TX_BURSTING		 0x00000100
+#define  MAC_MODE_MAX_DEFER		 0x00000200
+#define  MAC_MODE_LINK_POLARITY		 0x00000400
+#define  MAC_MODE_RXSTAT_ENABLE		 0x00000800
+#define  MAC_MODE_RXSTAT_CLEAR		 0x00001000
+#define  MAC_MODE_RXSTAT_FLUSH		 0x00002000
+#define  MAC_MODE_TXSTAT_ENABLE		 0x00004000
+#define  MAC_MODE_TXSTAT_CLEAR		 0x00008000
+#define  MAC_MODE_TXSTAT_FLUSH		 0x00010000
+#define  MAC_MODE_SEND_CONFIGS		 0x00020000
+#define  MAC_MODE_MAGIC_PKT_ENABLE	 0x00040000
+#define  MAC_MODE_ACPI_ENABLE		 0x00080000
+#define  MAC_MODE_MIP_ENABLE		 0x00100000
+#define  MAC_MODE_TDE_ENABLE		 0x00200000
+#define  MAC_MODE_RDE_ENABLE		 0x00400000
+#define  MAC_MODE_FHDE_ENABLE		 0x00800000
+#define MAC_STATUS			0x00000404
+#define  MAC_STATUS_PCS_SYNCED		 0x00000001
+#define  MAC_STATUS_SIGNAL_DET		 0x00000002
+#define  MAC_STATUS_RCVD_CFG		 0x00000004
+#define  MAC_STATUS_CFG_CHANGED		 0x00000008
+#define  MAC_STATUS_SYNC_CHANGED	 0x00000010
+#define  MAC_STATUS_PORT_DEC_ERR	 0x00000400
+#define  MAC_STATUS_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_STATUS_MI_COMPLETION	 0x00400000
+#define  MAC_STATUS_MI_INTERRUPT	 0x00800000
+#define  MAC_STATUS_AP_ERROR		 0x01000000
+#define  MAC_STATUS_ODI_ERROR		 0x02000000
+#define  MAC_STATUS_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_STATUS_TXSTAT_OVERRUN	 0x08000000
+#define MAC_EVENT			0x00000408
+#define  MAC_EVENT_PORT_DECODE_ERR	 0x00000400
+#define  MAC_EVENT_LNKSTATE_CHANGED	 0x00001000
+#define  MAC_EVENT_MI_COMPLETION	 0x00400000
+#define  MAC_EVENT_MI_INTERRUPT		 0x00800000
+#define  MAC_EVENT_AP_ERROR		 0x01000000
+#define  MAC_EVENT_ODI_ERROR		 0x02000000
+#define  MAC_EVENT_RXSTAT_OVERRUN	 0x04000000
+#define  MAC_EVENT_TXSTAT_OVERRUN	 0x08000000
+#define MAC_LED_CTRL			0x0000040c
+#define  LED_CTRL_LNKLED_OVERRIDE	 0x00000001
+#define  LED_CTRL_1000MBPS_ON		 0x00000002
+#define  LED_CTRL_100MBPS_ON		 0x00000004
+#define  LED_CTRL_10MBPS_ON		 0x00000008
+#define  LED_CTRL_TRAFFIC_OVERRIDE	 0x00000010
+#define  LED_CTRL_TRAFFIC_BLINK		 0x00000020
+#define  LED_CTRL_TRAFFIC_LED		 0x00000040
+#define  LED_CTRL_1000MBPS_STATUS	 0x00000080
+#define  LED_CTRL_100MBPS_STATUS	 0x00000100
+#define  LED_CTRL_10MBPS_STATUS		 0x00000200
+#define  LED_CTRL_TRAFFIC_STATUS	 0x00000400
+#define  LED_CTRL_MAC_MODE		 0x00000000
+#define  LED_CTRL_PHY_MODE_1		 0x00000800
+#define  LED_CTRL_PHY_MODE_2		 0x00001000
+#define  LED_CTRL_BLINK_RATE_MASK	 0x7ff80000
+#define  LED_CTRL_BLINK_RATE_SHIFT	 19
+#define  LED_CTRL_BLINK_PER_OVERRIDE	 0x00080000
+#define  LED_CTRL_BLINK_RATE_OVERRIDE	 0x80000000
+#define MAC_ADDR_0_HIGH			0x00000410 /* upper 2 bytes */
+#define MAC_ADDR_0_LOW			0x00000414 /* lower 4 bytes */
+#define MAC_ADDR_1_HIGH			0x00000418 /* upper 2 bytes */
+#define MAC_ADDR_1_LOW			0x0000041c /* lower 4 bytes */
+#define MAC_ADDR_2_HIGH			0x00000420 /* upper 2 bytes */
+#define MAC_ADDR_2_LOW			0x00000424 /* lower 4 bytes */
+#define MAC_ADDR_3_HIGH			0x00000428 /* upper 2 bytes */
+#define MAC_ADDR_3_LOW			0x0000042c /* lower 4 bytes */
+#define MAC_ACPI_MBUF_PTR		0x00000430
+#define MAC_ACPI_LEN_OFFSET		0x00000434
+#define  ACPI_LENOFF_LEN_MASK		 0x0000ffff
+#define  ACPI_LENOFF_LEN_SHIFT		 0
+#define  ACPI_LENOFF_OFF_MASK		 0x0fff0000
+#define  ACPI_LENOFF_OFF_SHIFT		 16
+#define MAC_TX_BACKOFF_SEED		0x00000438
+#define  TX_BACKOFF_SEED_MASK		 0x000003ff
+#define MAC_RX_MTU_SIZE			0x0000043c
+#define  RX_MTU_SIZE_MASK		 0x0000ffff
+#define MAC_PCS_TEST			0x00000440
+#define  PCS_TEST_PATTERN_MASK		 0x000fffff
+#define  PCS_TEST_PATTERN_SHIFT		 0
+#define  PCS_TEST_ENABLE		 0x00100000
+#define MAC_TX_AUTO_NEG			0x00000444
+#define  TX_AUTO_NEG_MASK		 0x0000ffff
+#define  TX_AUTO_NEG_SHIFT		 0
+#define MAC_RX_AUTO_NEG			0x00000448
+#define  RX_AUTO_NEG_MASK		 0x0000ffff
+#define  RX_AUTO_NEG_SHIFT		 0
+#define MAC_MI_COM			0x0000044c
+#define  MI_COM_CMD_MASK		 0x0c000000
+#define  MI_COM_CMD_WRITE		 0x04000000
+#define  MI_COM_CMD_READ		 0x08000000
+#define  MI_COM_READ_FAILED		 0x10000000
+#define  MI_COM_START			 0x20000000
+#define  MI_COM_BUSY			 0x20000000
+#define  MI_COM_PHY_ADDR_MASK		 0x03e00000
+#define  MI_COM_PHY_ADDR_SHIFT		 21
+#define  MI_COM_REG_ADDR_MASK		 0x001f0000
+#define  MI_COM_REG_ADDR_SHIFT		 16
+#define  MI_COM_DATA_MASK		 0x0000ffff
+#define MAC_MI_STAT			0x00000450
+#define  MAC_MI_STAT_LNKSTAT_ATTN_ENAB	 0x00000001
+#define MAC_MI_MODE			0x00000454
+#define  MAC_MI_MODE_CLK_10MHZ		 0x00000001
+#define  MAC_MI_MODE_SHORT_PREAMBLE	 0x00000002
+#define  MAC_MI_MODE_AUTO_POLL		 0x00000010
+#define  MAC_MI_MODE_CORE_CLK_62MHZ	 0x00008000
+#define  MAC_MI_MODE_BASE		 0x000c0000 /* XXX magic values XXX */
+#define MAC_AUTO_POLL_STATUS		0x00000458
+#define  MAC_AUTO_POLL_ERROR		 0x00000001
+#define MAC_TX_MODE			0x0000045c
+#define  TX_MODE_RESET			 0x00000001
+#define  TX_MODE_ENABLE			 0x00000002
+#define  TX_MODE_FLOW_CTRL_ENABLE	 0x00000010
+#define  TX_MODE_BIG_BCKOFF_ENABLE	 0x00000020
+#define  TX_MODE_LONG_PAUSE_ENABLE	 0x00000040
+#define MAC_TX_STATUS			0x00000460
+#define  TX_STATUS_XOFFED		 0x00000001
+#define  TX_STATUS_SENT_XOFF		 0x00000002
+#define  TX_STATUS_SENT_XON		 0x00000004
+#define  TX_STATUS_LINK_UP		 0x00000008
+#define  TX_STATUS_ODI_UNDERRUN		 0x00000010
+#define  TX_STATUS_ODI_OVERRUN		 0x00000020
+#define MAC_TX_LENGTHS			0x00000464
+#define  TX_LENGTHS_SLOT_TIME_MASK	 0x000000ff
+#define  TX_LENGTHS_SLOT_TIME_SHIFT	 0
+#define  TX_LENGTHS_IPG_MASK		 0x00000f00
+#define  TX_LENGTHS_IPG_SHIFT		 8
+#define  TX_LENGTHS_IPG_CRS_MASK	 0x00003000
+#define  TX_LENGTHS_IPG_CRS_SHIFT	 12
+#define MAC_RX_MODE			0x00000468
+#define  RX_MODE_RESET			 0x00000001
+#define  RX_MODE_ENABLE			 0x00000002
+#define  RX_MODE_FLOW_CTRL_ENABLE	 0x00000004
+#define  RX_MODE_KEEP_MAC_CTRL		 0x00000008
+#define  RX_MODE_KEEP_PAUSE		 0x00000010
+#define  RX_MODE_ACCEPT_OVERSIZED	 0x00000020
+#define  RX_MODE_ACCEPT_RUNTS		 0x00000040
+#define  RX_MODE_LEN_CHECK		 0x00000080
+#define  RX_MODE_PROMISC		 0x00000100
+#define  RX_MODE_NO_CRC_CHECK		 0x00000200
+#define  RX_MODE_KEEP_VLAN_TAG		 0x00000400
+#define MAC_RX_STATUS			0x0000046c
+#define  RX_STATUS_REMOTE_TX_XOFFED	 0x00000001
+#define  RX_STATUS_XOFF_RCVD		 0x00000002
+#define  RX_STATUS_XON_RCVD		 0x00000004
+#define MAC_HASH_REG_0			0x00000470
+#define MAC_HASH_REG_1			0x00000474
+#define MAC_HASH_REG_2			0x00000478
+#define MAC_HASH_REG_3			0x0000047c
+#define MAC_RCV_RULE_0			0x00000480
+#define MAC_RCV_VALUE_0			0x00000484
+#define MAC_RCV_RULE_1			0x00000488
+#define MAC_RCV_VALUE_1			0x0000048c
+#define MAC_RCV_RULE_2			0x00000490
+#define MAC_RCV_VALUE_2			0x00000494
+#define MAC_RCV_RULE_3			0x00000498
+#define MAC_RCV_VALUE_3			0x0000049c
+#define MAC_RCV_RULE_4			0x000004a0
+#define MAC_RCV_VALUE_4			0x000004a4
+#define MAC_RCV_RULE_5			0x000004a8
+#define MAC_RCV_VALUE_5			0x000004ac
+#define MAC_RCV_RULE_6			0x000004b0
+#define MAC_RCV_VALUE_6			0x000004b4
+#define MAC_RCV_RULE_7			0x000004b8
+#define MAC_RCV_VALUE_7			0x000004bc
+#define MAC_RCV_RULE_8			0x000004c0
+#define MAC_RCV_VALUE_8			0x000004c4
+#define MAC_RCV_RULE_9			0x000004c8
+#define MAC_RCV_VALUE_9			0x000004cc
+#define MAC_RCV_RULE_10			0x000004d0
+#define MAC_RCV_VALUE_10		0x000004d4
+#define MAC_RCV_RULE_11			0x000004d8
+#define MAC_RCV_VALUE_11		0x000004dc
+#define MAC_RCV_RULE_12			0x000004e0
+#define MAC_RCV_VALUE_12		0x000004e4
+#define MAC_RCV_RULE_13			0x000004e8
+#define MAC_RCV_VALUE_13		0x000004ec
+#define MAC_RCV_RULE_14			0x000004f0
+#define MAC_RCV_VALUE_14		0x000004f4
+#define MAC_RCV_RULE_15			0x000004f8
+#define MAC_RCV_VALUE_15		0x000004fc
+#define  RCV_RULE_DISABLE_MASK		 0x7fffffff
+#define MAC_RCV_RULE_CFG		0x00000500
+#define  RCV_RULE_CFG_DEFAULT_CLASS	0x00000008
+/* 0x504 --> 0x590 unused */
+#define MAC_SERDES_CFG			0x00000590
+#define MAC_SERDES_STAT			0x00000594
+/* 0x598 --> 0x600 unused */
+#define MAC_TX_MAC_STATE_BASE		0x00000600 /* 16 bytes */
+#define MAC_RX_MAC_STATE_BASE		0x00000610 /* 20 bytes */
+/* 0x624 --> 0x800 unused */
+#define MAC_RX_STATS_BASE		0x00000800 /* 26 32-bit words */
+/* 0x868 --> 0x880 unused */
+#define MAC_TX_STATS_BASE		0x00000880 /* 28 32-bit words */
+/* 0x8f0 --> 0xc00 unused */
+
+/* Send data initiator control registers */
+#define SNDDATAI_MODE			0x00000c00
+#define  SNDDATAI_MODE_RESET		 0x00000001
+#define  SNDDATAI_MODE_ENABLE		 0x00000002
+#define  SNDDATAI_MODE_STAT_OFLOW_ENAB	 0x00000004
+#define SNDDATAI_STATUS			0x00000c04
+#define  SNDDATAI_STATUS_STAT_OFLOW	 0x00000004
+#define SNDDATAI_STATSCTRL		0x00000c08
+#define  SNDDATAI_SCTRL_ENABLE		 0x00000001
+#define  SNDDATAI_SCTRL_FASTUPD		 0x00000002
+#define  SNDDATAI_SCTRL_CLEAR		 0x00000004
+#define  SNDDATAI_SCTRL_FLUSH		 0x00000008
+#define  SNDDATAI_SCTRL_FORCE_ZERO	 0x00000010
+#define SNDDATAI_STATSENAB		0x00000c0c
+#define SNDDATAI_STATSINCMASK		0x00000c10
+/* 0xc14 --> 0xc80 unused */
+#define SNDDATAI_COS_CNT_0		0x00000c80
+#define SNDDATAI_COS_CNT_1		0x00000c84
+#define SNDDATAI_COS_CNT_2		0x00000c88
+#define SNDDATAI_COS_CNT_3		0x00000c8c
+#define SNDDATAI_COS_CNT_4		0x00000c90
+#define SNDDATAI_COS_CNT_5		0x00000c94
+#define SNDDATAI_COS_CNT_6		0x00000c98
+#define SNDDATAI_COS_CNT_7		0x00000c9c
+#define SNDDATAI_COS_CNT_8		0x00000ca0
+#define SNDDATAI_COS_CNT_9		0x00000ca4
+#define SNDDATAI_COS_CNT_10		0x00000ca8
+#define SNDDATAI_COS_CNT_11		0x00000cac
+#define SNDDATAI_COS_CNT_12		0x00000cb0
+#define SNDDATAI_COS_CNT_13		0x00000cb4
+#define SNDDATAI_COS_CNT_14		0x00000cb8
+#define SNDDATAI_COS_CNT_15		0x00000cbc
+#define SNDDATAI_DMA_RDQ_FULL_CNT	0x00000cc0
+#define SNDDATAI_DMA_PRIO_RDQ_FULL_CNT	0x00000cc4
+#define SNDDATAI_SDCQ_FULL_CNT		0x00000cc8
+#define SNDDATAI_NICRNG_SSND_PIDX_CNT	0x00000ccc
+#define SNDDATAI_STATS_UPDATED_CNT	0x00000cd0
+#define SNDDATAI_INTERRUPTS_CNT		0x00000cd4
+#define SNDDATAI_AVOID_INTERRUPTS_CNT	0x00000cd8
+#define SNDDATAI_SND_THRESH_HIT_CNT	0x00000cdc
+/* 0xce0 --> 0x1000 unused */
+
+/* Send data completion control registers */
+#define SNDDATAC_MODE			0x00001000
+#define  SNDDATAC_MODE_RESET		 0x00000001
+#define  SNDDATAC_MODE_ENABLE		 0x00000002
+/* 0x1004 --> 0x1400 unused */
+
+/* Send BD ring selector */
+#define SNDBDS_MODE			0x00001400
+#define  SNDBDS_MODE_RESET		 0x00000001
+#define  SNDBDS_MODE_ENABLE		 0x00000002
+#define  SNDBDS_MODE_ATTN_ENABLE	 0x00000004
+#define SNDBDS_STATUS			0x00001404
+#define  SNDBDS_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDS_HWDIAG			0x00001408
+/* 0x140c --> 0x1440 */
+#define SNDBDS_SEL_CON_IDX_0		0x00001440
+#define SNDBDS_SEL_CON_IDX_1		0x00001444
+#define SNDBDS_SEL_CON_IDX_2		0x00001448
+#define SNDBDS_SEL_CON_IDX_3		0x0000144c
+#define SNDBDS_SEL_CON_IDX_4		0x00001450
+#define SNDBDS_SEL_CON_IDX_5		0x00001454
+#define SNDBDS_SEL_CON_IDX_6		0x00001458
+#define SNDBDS_SEL_CON_IDX_7		0x0000145c
+#define SNDBDS_SEL_CON_IDX_8		0x00001460
+#define SNDBDS_SEL_CON_IDX_9		0x00001464
+#define SNDBDS_SEL_CON_IDX_10		0x00001468
+#define SNDBDS_SEL_CON_IDX_11		0x0000146c
+#define SNDBDS_SEL_CON_IDX_12		0x00001470
+#define SNDBDS_SEL_CON_IDX_13		0x00001474
+#define SNDBDS_SEL_CON_IDX_14		0x00001478
+#define SNDBDS_SEL_CON_IDX_15		0x0000147c
+/* 0x1480 --> 0x1800 unused */
+
+/* Send BD initiator control registers */
+#define SNDBDI_MODE			0x00001800
+#define  SNDBDI_MODE_RESET		 0x00000001
+#define  SNDBDI_MODE_ENABLE		 0x00000002
+#define  SNDBDI_MODE_ATTN_ENABLE	 0x00000004
+#define SNDBDI_STATUS			0x00001804
+#define  SNDBDI_STATUS_ERROR_ATTN	 0x00000004
+#define SNDBDI_IN_PROD_IDX_0		0x00001808
+#define SNDBDI_IN_PROD_IDX_1		0x0000180c
+#define SNDBDI_IN_PROD_IDX_2		0x00001810
+#define SNDBDI_IN_PROD_IDX_3		0x00001814
+#define SNDBDI_IN_PROD_IDX_4		0x00001818
+#define SNDBDI_IN_PROD_IDX_5		0x0000181c
+#define SNDBDI_IN_PROD_IDX_6		0x00001820
+#define SNDBDI_IN_PROD_IDX_7		0x00001824
+#define SNDBDI_IN_PROD_IDX_8		0x00001828
+#define SNDBDI_IN_PROD_IDX_9		0x0000182c
+#define SNDBDI_IN_PROD_IDX_10		0x00001830
+#define SNDBDI_IN_PROD_IDX_11		0x00001834
+#define SNDBDI_IN_PROD_IDX_12		0x00001838
+#define SNDBDI_IN_PROD_IDX_13		0x0000183c
+#define SNDBDI_IN_PROD_IDX_14		0x00001840
+#define SNDBDI_IN_PROD_IDX_15		0x00001844
+/* 0x1848 --> 0x1c00 unused */
+
+/* Send BD completion control registers */
+#define SNDBDC_MODE			0x00001c00
+#define SNDBDC_MODE_RESET		 0x00000001
+#define SNDBDC_MODE_ENABLE		 0x00000002
+#define SNDBDC_MODE_ATTN_ENABLE		 0x00000004
+/* 0x1c04 --> 0x2000 unused */
+
+/* Receive list placement control registers */
+#define RCVLPC_MODE			0x00002000
+#define  RCVLPC_MODE_RESET		 0x00000001
+#define  RCVLPC_MODE_ENABLE		 0x00000002
+#define  RCVLPC_MODE_CLASS0_ATTN_ENAB	 0x00000004
+#define  RCVLPC_MODE_MAPOOR_AATTN_ENAB	 0x00000008
+#define  RCVLPC_MODE_STAT_OFLOW_ENAB	 0x00000010
+#define RCVLPC_STATUS			0x00002004
+#define  RCVLPC_STATUS_CLASS0		 0x00000004
+#define  RCVLPC_STATUS_MAPOOR		 0x00000008
+#define  RCVLPC_STATUS_STAT_OFLOW	 0x00000010
+#define RCVLPC_LOCK			0x00002008
+#define  RCVLPC_LOCK_REQ_MASK		 0x0000ffff
+#define  RCVLPC_LOCK_REQ_SHIFT		 0
+#define  RCVLPC_LOCK_GRANT_MASK		 0xffff0000
+#define  RCVLPC_LOCK_GRANT_SHIFT	 16
+#define RCVLPC_NON_EMPTY_BITS		0x0000200c
+#define  RCVLPC_NON_EMPTY_BITS_MASK	 0x0000ffff
+#define RCVLPC_CONFIG			0x00002010
+#define RCVLPC_STATSCTRL		0x00002014
+#define  RCVLPC_STATSCTRL_ENABLE	 0x00000001
+#define  RCVLPC_STATSCTRL_FASTUPD	 0x00000002
+#define RCVLPC_STATS_ENABLE		0x00002018
+#define RCVLPC_STATS_INCMASK		0x0000201c
+/* 0x2020 --> 0x2100 unused */
+#define RCVLPC_SELLST_BASE		0x00002100 /* 16 16-byte entries */
+#define  SELLST_TAIL			0x00000004
+#define  SELLST_CONT			0x00000008
+#define  SELLST_UNUSED			0x0000000c
+#define RCVLPC_COS_CNTL_BASE		0x00002200 /* 16 4-byte entries */
+#define RCVLPC_DROP_FILTER_CNT		0x00002240
+#define RCVLPC_DMA_WQ_FULL_CNT		0x00002244
+#define RCVLPC_DMA_HIPRIO_WQ_FULL_CNT	0x00002248
+#define RCVLPC_NO_RCV_BD_CNT		0x0000224c
+#define RCVLPC_IN_DISCARDS_CNT		0x00002250
+#define RCVLPC_IN_ERRORS_CNT		0x00002254
+#define RCVLPC_RCV_THRESH_HIT_CNT	0x00002258
+/* 0x225c --> 0x2400 unused */
+
+/* Receive Data and Receive BD Initiator Control */
+#define RCVDBDI_MODE			0x00002400
+#define  RCVDBDI_MODE_RESET		 0x00000001
+#define  RCVDBDI_MODE_ENABLE		 0x00000002
+#define  RCVDBDI_MODE_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_MODE_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_MODE_INV_RING_SZ	 0x00000010
+#define RCVDBDI_STATUS			0x00002404
+#define  RCVDBDI_STATUS_JUMBOBD_NEEDED	 0x00000004
+#define  RCVDBDI_STATUS_FRM_TOO_BIG	 0x00000008
+#define  RCVDBDI_STATUS_INV_RING_SZ	 0x00000010
+#define RCVDBDI_SPLIT_FRAME_MINSZ	0x00002408
+/* 0x240c --> 0x2440 unused */
+#define RCVDBDI_JUMBO_BD		0x00002440 /* TG3_BDINFO_... */
+#define RCVDBDI_STD_BD			0x00002450 /* TG3_BDINFO_... */
+#define RCVDBDI_MINI_BD			0x00002460 /* TG3_BDINFO_... */
+#define RCVDBDI_JUMBO_CON_IDX		0x00002470
+#define RCVDBDI_STD_CON_IDX		0x00002474
+#define RCVDBDI_MINI_CON_IDX		0x00002478
+/* 0x247c --> 0x2480 unused */
+#define RCVDBDI_BD_PROD_IDX_0		0x00002480
+#define RCVDBDI_BD_PROD_IDX_1		0x00002484
+#define RCVDBDI_BD_PROD_IDX_2		0x00002488
+#define RCVDBDI_BD_PROD_IDX_3		0x0000248c
+#define RCVDBDI_BD_PROD_IDX_4		0x00002490
+#define RCVDBDI_BD_PROD_IDX_5		0x00002494
+#define RCVDBDI_BD_PROD_IDX_6		0x00002498
+#define RCVDBDI_BD_PROD_IDX_7		0x0000249c
+#define RCVDBDI_BD_PROD_IDX_8		0x000024a0
+#define RCVDBDI_BD_PROD_IDX_9		0x000024a4
+#define RCVDBDI_BD_PROD_IDX_10		0x000024a8
+#define RCVDBDI_BD_PROD_IDX_11		0x000024ac
+#define RCVDBDI_BD_PROD_IDX_12		0x000024b0
+#define RCVDBDI_BD_PROD_IDX_13		0x000024b4
+#define RCVDBDI_BD_PROD_IDX_14		0x000024b8
+#define RCVDBDI_BD_PROD_IDX_15		0x000024bc
+#define RCVDBDI_HWDIAG			0x000024c0
+/* 0x24c4 --> 0x2800 unused */
+
+/* Receive Data Completion Control */
+#define RCVDCC_MODE			0x00002800
+#define  RCVDCC_MODE_RESET		 0x00000001
+#define  RCVDCC_MODE_ENABLE		 0x00000002
+#define  RCVDCC_MODE_ATTN_ENABLE	 0x00000004
+/* 0x2804 --> 0x2c00 unused */
+
+/* Receive BD Initiator Control Registers */
+#define RCVBDI_MODE			0x00002c00
+#define  RCVBDI_MODE_RESET		 0x00000001
+#define  RCVBDI_MODE_ENABLE		 0x00000002
+#define  RCVBDI_MODE_RCB_ATTN_ENAB	 0x00000004
+#define RCVBDI_STATUS			0x00002c04
+#define  RCVBDI_STATUS_RCB_ATTN		 0x00000004
+#define RCVBDI_JUMBO_PROD_IDX		0x00002c08
+#define RCVBDI_STD_PROD_IDX		0x00002c0c
+#define RCVBDI_MINI_PROD_IDX		0x00002c10
+#define RCVBDI_MINI_THRESH		0x00002c14
+#define RCVBDI_STD_THRESH		0x00002c18
+#define RCVBDI_JUMBO_THRESH		0x00002c1c
+/* 0x2c20 --> 0x3000 unused */
+
+/* Receive BD Completion Control Registers */
+#define RCVCC_MODE			0x00003000
+#define  RCVCC_MODE_RESET		 0x00000001
+#define  RCVCC_MODE_ENABLE		 0x00000002
+#define  RCVCC_MODE_ATTN_ENABLE		 0x00000004
+#define RCVCC_STATUS			0x00003004
+#define  RCVCC_STATUS_ERROR_ATTN	 0x00000004
+#define RCVCC_JUMP_PROD_IDX		0x00003008
+#define RCVCC_STD_PROD_IDX		0x0000300c
+#define RCVCC_MINI_PROD_IDX		0x00003010
+/* 0x3014 --> 0x3400 unused */
+
+/* Receive list selector control registers */
+#define RCVLSC_MODE			0x00003400
+#define  RCVLSC_MODE_RESET		 0x00000001
+#define  RCVLSC_MODE_ENABLE		 0x00000002
+#define  RCVLSC_MODE_ATTN_ENABLE	 0x00000004
+#define RCVLSC_STATUS			0x00003404
+#define  RCVLSC_STATUS_ERROR_ATTN	 0x00000004
+/* 0x3408 --> 0x3800 unused */
+
+/* Mbuf cluster free registers */
+#define MBFREE_MODE			0x00003800
+#define  MBFREE_MODE_RESET		 0x00000001
+#define  MBFREE_MODE_ENABLE		 0x00000002
+#define MBFREE_STATUS			0x00003804
+/* 0x3808 --> 0x3c00 unused */
+
+/* Host coalescing control registers */
+#define HOSTCC_MODE			0x00003c00
+#define  HOSTCC_MODE_RESET		 0x00000001
+#define  HOSTCC_MODE_ENABLE		 0x00000002
+#define  HOSTCC_MODE_ATTN		 0x00000004
+#define  HOSTCC_MODE_NOW		 0x00000008
+#define  HOSTCC_MODE_FULL_STATUS	 0x00000000
+#define  HOSTCC_MODE_64BYTE		 0x00000080
+#define  HOSTCC_MODE_32BYTE		 0x00000100
+#define  HOSTCC_MODE_CLRTICK_RXBD	 0x00000200
+#define  HOSTCC_MODE_CLRTICK_TXBD	 0x00000400
+#define  HOSTCC_MODE_NOINT_ON_NOW	 0x00000800
+#define  HOSTCC_MODE_NOINT_ON_FORCE	 0x00001000
+#define HOSTCC_STATUS			0x00003c04
+#define  HOSTCC_STATUS_ERROR_ATTN	 0x00000004
+#define HOSTCC_RXCOL_TICKS		0x00003c08
+#define  LOW_RXCOL_TICKS		 0x00000032
+#define  DEFAULT_RXCOL_TICKS		 0x00000048
+#define  HIGH_RXCOL_TICKS		 0x00000096
+#define HOSTCC_TXCOL_TICKS		0x00003c0c
+#define  DEFAULT_TXCOL_TICKS		 0x0000012c
+#define HOSTCC_RXMAX_FRAMES		0x00003c10
+#define  LOW_RXMAX_FRAMES		 0x00000005
+#define  DEFAULT_RXMAX_FRAMES		 0x00000008
+#define  HIGH_RXMAX_FRAMES		 0x00000012
+#define HOSTCC_TXMAX_FRAMES		0x00003c14
+#define  DEFAULT_TXMAX_FRAMES		 0x0000004b
+#define HOSTCC_RXCOAL_TICK_INT		0x00003c18
+#define  DEFAULT_RXCOAL_TICK_INT	 0x00000019
+#define HOSTCC_TXCOAL_TICK_INT		0x00003c1c
+#define  DEFAULT_TXCOAL_TICK_INT	 0x00000019
+#define HOSTCC_RXCOAL_MAXF_INT		0x00003c20
+#define  DEFAULT_RXCOAL_MAXF_INT	 0x00000005
+#define HOSTCC_TXCOAL_MAXF_INT		0x00003c24
+#define  DEFAULT_TXCOAL_MAXF_INT	 0x00000005
+#define HOSTCC_STAT_COAL_TICKS		0x00003c28
+#define  DEFAULT_STAT_COAL_TICKS	 0x000f4240
+/* 0x3c2c --> 0x3c30 unused */
+#define HOSTCC_STATS_BLK_HOST_ADDR	0x00003c30 /* 64-bit */
+#define HOSTCC_STATUS_BLK_HOST_ADDR	0x00003c38 /* 64-bit */
+#define HOSTCC_STATS_BLK_NIC_ADDR	0x00003c40
+#define HOSTCC_STATUS_BLK_NIC_ADDR	0x00003c44
+#define HOSTCC_FLOW_ATTN		0x00003c48
+/* 0x3c4c --> 0x3c50 unused */
+#define HOSTCC_JUMBO_CON_IDX		0x00003c50
+#define HOSTCC_STD_CON_IDX		0x00003c54
+#define HOSTCC_MINI_CON_IDX		0x00003c58
+/* 0x3c5c --> 0x3c80 unused */
+#define HOSTCC_RET_PROD_IDX_0		0x00003c80
+#define HOSTCC_RET_PROD_IDX_1		0x00003c84
+#define HOSTCC_RET_PROD_IDX_2		0x00003c88
+#define HOSTCC_RET_PROD_IDX_3		0x00003c8c
+#define HOSTCC_RET_PROD_IDX_4		0x00003c90
+#define HOSTCC_RET_PROD_IDX_5		0x00003c94
+#define HOSTCC_RET_PROD_IDX_6		0x00003c98
+#define HOSTCC_RET_PROD_IDX_7		0x00003c9c
+#define HOSTCC_RET_PROD_IDX_8		0x00003ca0
+#define HOSTCC_RET_PROD_IDX_9		0x00003ca4
+#define HOSTCC_RET_PROD_IDX_10		0x00003ca8
+#define HOSTCC_RET_PROD_IDX_11		0x00003cac
+#define HOSTCC_RET_PROD_IDX_12		0x00003cb0
+#define HOSTCC_RET_PROD_IDX_13		0x00003cb4
+#define HOSTCC_RET_PROD_IDX_14		0x00003cb8
+#define HOSTCC_RET_PROD_IDX_15		0x00003cbc
+#define HOSTCC_SND_CON_IDX_0		0x00003cc0
+#define HOSTCC_SND_CON_IDX_1		0x00003cc4
+#define HOSTCC_SND_CON_IDX_2		0x00003cc8
+#define HOSTCC_SND_CON_IDX_3		0x00003ccc
+#define HOSTCC_SND_CON_IDX_4		0x00003cd0
+#define HOSTCC_SND_CON_IDX_5		0x00003cd4
+#define HOSTCC_SND_CON_IDX_6		0x00003cd8
+#define HOSTCC_SND_CON_IDX_7		0x00003cdc
+#define HOSTCC_SND_CON_IDX_8		0x00003ce0
+#define HOSTCC_SND_CON_IDX_9		0x00003ce4
+#define HOSTCC_SND_CON_IDX_10		0x00003ce8
+#define HOSTCC_SND_CON_IDX_11		0x00003cec
+#define HOSTCC_SND_CON_IDX_12		0x00003cf0
+#define HOSTCC_SND_CON_IDX_13		0x00003cf4
+#define HOSTCC_SND_CON_IDX_14		0x00003cf8
+#define HOSTCC_SND_CON_IDX_15		0x00003cfc
+/* 0x3d00 --> 0x4000 unused */
+
+/* Memory arbiter control registers */
+#define MEMARB_MODE			0x00004000
+#define  MEMARB_MODE_RESET		 0x00000001
+#define  MEMARB_MODE_ENABLE		 0x00000002
+#define MEMARB_STATUS			0x00004004
+#define MEMARB_TRAP_ADDR_LOW		0x00004008
+#define MEMARB_TRAP_ADDR_HIGH		0x0000400c
+/* 0x4010 --> 0x4400 unused */
+
+/* Buffer manager control registers */
+#define BUFMGR_MODE			0x00004400
+#define  BUFMGR_MODE_RESET		 0x00000001
+#define  BUFMGR_MODE_ENABLE		 0x00000002
+#define  BUFMGR_MODE_ATTN_ENABLE	 0x00000004
+#define  BUFMGR_MODE_BM_TEST		 0x00000008
+#define  BUFMGR_MODE_MBLOW_ATTN_ENAB	 0x00000010
+#define BUFMGR_STATUS			0x00004404
+#define  BUFMGR_STATUS_ERROR		 0x00000004
+#define  BUFMGR_STATUS_MBLOW		 0x00000010
+#define BUFMGR_MB_POOL_ADDR		0x00004408
+#define BUFMGR_MB_POOL_SIZE		0x0000440c
+#define BUFMGR_MB_RDMA_LOW_WATER	0x00004410
+#define  DEFAULT_MB_RDMA_LOW_WATER	 0x00000040
+#define  DEFAULT_MB_RDMA_LOW_WATER_JUMBO 0x00000130
+#define BUFMGR_MB_MACRX_LOW_WATER	0x00004414
+#define  DEFAULT_MB_MACRX_LOW_WATER	  0x00000020
+#define  DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
+#define BUFMGR_MB_HIGH_WATER		0x00004418
+#define  DEFAULT_MB_HIGH_WATER		 0x00000060
+#define  DEFAULT_MB_HIGH_WATER_JUMBO	 0x0000017c
+#define BUFMGR_RX_MB_ALLOC_REQ		0x0000441c
+#define  BUFMGR_MB_ALLOC_BIT		 0x10000000
+#define BUFMGR_RX_MB_ALLOC_RESP		0x00004420
+#define BUFMGR_TX_MB_ALLOC_REQ		0x00004424
+#define BUFMGR_TX_MB_ALLOC_RESP		0x00004428
+#define BUFMGR_DMA_DESC_POOL_ADDR	0x0000442c
+#define BUFMGR_DMA_DESC_POOL_SIZE	0x00004430
+#define BUFMGR_DMA_LOW_WATER		0x00004434
+#define  DEFAULT_DMA_LOW_WATER		 0x00000005
+#define BUFMGR_DMA_HIGH_WATER		0x00004438
+#define  DEFAULT_DMA_HIGH_WATER		 0x0000000a
+#define BUFMGR_RX_DMA_ALLOC_REQ		0x0000443c
+#define BUFMGR_RX_DMA_ALLOC_RESP	0x00004440
+#define BUFMGR_TX_DMA_ALLOC_REQ		0x00004444
+#define BUFMGR_TX_DMA_ALLOC_RESP	0x00004448
+#define BUFMGR_HWDIAG_0			0x0000444c
+#define BUFMGR_HWDIAG_1			0x00004450
+#define BUFMGR_HWDIAG_2			0x00004454
+/* 0x4458 --> 0x4800 unused */
+
+/* Read DMA control registers */
+#define RDMAC_MODE			0x00004800
+#define  RDMAC_MODE_RESET		 0x00000001
+#define  RDMAC_MODE_ENABLE		 0x00000002
+#define  RDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  RDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  RDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  RDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  RDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  RDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define RDMAC_STATUS			0x00004804
+#define  RDMAC_STATUS_TGTABORT		 0x00000004
+#define  RDMAC_STATUS_MSTABORT		 0x00000008
+#define  RDMAC_STATUS_PARITYERR		 0x00000010
+#define  RDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  RDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  RDMAC_STATUS_FIFOURUN		 0x00000080
+#define  RDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  RDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4808 --> 0x4c00 unused */
+
+/* Write DMA control registers */
+#define WDMAC_MODE			0x00004c00
+#define  WDMAC_MODE_RESET		 0x00000001
+#define  WDMAC_MODE_ENABLE		 0x00000002
+#define  WDMAC_MODE_TGTABORT_ENAB	 0x00000004
+#define  WDMAC_MODE_MSTABORT_ENAB	 0x00000008
+#define  WDMAC_MODE_PARITYERR_ENAB	 0x00000010
+#define  WDMAC_MODE_ADDROFLOW_ENAB	 0x00000020
+#define  WDMAC_MODE_FIFOOFLOW_ENAB	 0x00000040
+#define  WDMAC_MODE_FIFOURUN_ENAB	 0x00000080
+#define  WDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
+#define  WDMAC_MODE_LNGREAD_ENAB	 0x00000200
+#define WDMAC_STATUS			0x00004c04
+#define  WDMAC_STATUS_TGTABORT		 0x00000004
+#define  WDMAC_STATUS_MSTABORT		 0x00000008
+#define  WDMAC_STATUS_PARITYERR		 0x00000010
+#define  WDMAC_STATUS_ADDROFLOW		 0x00000020
+#define  WDMAC_STATUS_FIFOOFLOW		 0x00000040
+#define  WDMAC_STATUS_FIFOURUN		 0x00000080
+#define  WDMAC_STATUS_FIFOOREAD		 0x00000100
+#define  WDMAC_STATUS_LNGREAD		 0x00000200
+/* 0x4c08 --> 0x5000 unused */
+
+/* Per-cpu register offsets (arm9) */
+#define CPU_MODE			0x00000000
+#define  CPU_MODE_RESET			 0x00000001
+#define  CPU_MODE_HALT			 0x00000400
+#define CPU_STATE			0x00000004
+#define CPU_EVTMASK			0x00000008
+/* 0xc --> 0x1c reserved */
+#define CPU_PC				0x0000001c
+#define CPU_INSN			0x00000020
+#define CPU_SPAD_UFLOW			0x00000024
+#define CPU_WDOG_CLEAR			0x00000028
+#define CPU_WDOG_VECTOR			0x0000002c
+#define CPU_WDOG_PC			0x00000030
+#define CPU_HW_BP			0x00000034
+/* 0x38 --> 0x44 unused */
+#define CPU_WDOG_SAVED_STATE		0x00000044
+#define CPU_LAST_BRANCH_ADDR		0x00000048
+#define CPU_SPAD_UFLOW_SET		0x0000004c
+/* 0x50 --> 0x200 unused */
+#define CPU_R0				0x00000200
+#define CPU_R1				0x00000204
+#define CPU_R2				0x00000208
+#define CPU_R3				0x0000020c
+#define CPU_R4				0x00000210
+#define CPU_R5				0x00000214
+#define CPU_R6				0x00000218
+#define CPU_R7				0x0000021c
+#define CPU_R8				0x00000220
+#define CPU_R9				0x00000224
+#define CPU_R10				0x00000228
+#define CPU_R11				0x0000022c
+#define CPU_R12				0x00000230
+#define CPU_R13				0x00000234
+#define CPU_R14				0x00000238
+#define CPU_R15				0x0000023c
+#define CPU_R16				0x00000240
+#define CPU_R17				0x00000244
+#define CPU_R18				0x00000248
+#define CPU_R19				0x0000024c
+#define CPU_R20				0x00000250
+#define CPU_R21				0x00000254
+#define CPU_R22				0x00000258
+#define CPU_R23				0x0000025c
+#define CPU_R24				0x00000260
+#define CPU_R25				0x00000264
+#define CPU_R26				0x00000268
+#define CPU_R27				0x0000026c
+#define CPU_R28				0x00000270
+#define CPU_R29				0x00000274
+#define CPU_R30				0x00000278
+#define CPU_R31				0x0000027c
+/* 0x280 --> 0x400 unused */
+
+#define RX_CPU_BASE			0x00005000
+#define TX_CPU_BASE			0x00005400
+
+/* Mailboxes */
+#define GRCMBOX_INTERRUPT_0		0x00005800 /* 64-bit */
+#define GRCMBOX_INTERRUPT_1		0x00005808 /* 64-bit */
+#define GRCMBOX_INTERRUPT_2		0x00005810 /* 64-bit */
+#define GRCMBOX_INTERRUPT_3		0x00005818 /* 64-bit */
+#define GRCMBOX_GENERAL_0		0x00005820 /* 64-bit */
+#define GRCMBOX_GENERAL_1		0x00005828 /* 64-bit */
+#define GRCMBOX_GENERAL_2		0x00005830 /* 64-bit */
+#define GRCMBOX_GENERAL_3		0x00005838 /* 64-bit */
+#define GRCMBOX_GENERAL_4		0x00005840 /* 64-bit */
+#define GRCMBOX_GENERAL_5		0x00005848 /* 64-bit */
+#define GRCMBOX_GENERAL_6		0x00005850 /* 64-bit */
+#define GRCMBOX_GENERAL_7		0x00005858 /* 64-bit */
+#define GRCMBOX_RELOAD_STAT		0x00005860 /* 64-bit */
+#define GRCMBOX_RCVSTD_PROD_IDX		0x00005868 /* 64-bit */
+#define GRCMBOX_RCVJUMBO_PROD_IDX	0x00005870 /* 64-bit */
+#define GRCMBOX_RCVMINI_PROD_IDX	0x00005878 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_0	0x00005880 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_1	0x00005888 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_2	0x00005890 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_3	0x00005898 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_4	0x000058a0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_5	0x000058a8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_6	0x000058b0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_7	0x000058b8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_8	0x000058c0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_9	0x000058c8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_10	0x000058d0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_11	0x000058d8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_12	0x000058e0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_13	0x000058e8 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_14	0x000058f0 /* 64-bit */
+#define GRCMBOX_RCVRET_CON_IDX_15	0x000058f8 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_0	0x00005900 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_1	0x00005908 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_2	0x00005910 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_3	0x00005918 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_4	0x00005920 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_5	0x00005928 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_6	0x00005930 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_7	0x00005938 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_8	0x00005940 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_9	0x00005948 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_10	0x00005950 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_11	0x00005958 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_12	0x00005960 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_13	0x00005968 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_14	0x00005970 /* 64-bit */
+#define GRCMBOX_SNDHOST_PROD_IDX_15	0x00005978 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_0	0x00005980 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_1	0x00005988 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_2	0x00005990 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_3	0x00005998 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_4	0x000059a0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_5	0x000059a8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_6	0x000059b0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_7	0x000059b8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_8	0x000059c0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_9	0x000059c8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_10	0x000059d0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_11	0x000059d8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_12	0x000059e0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_13	0x000059e8 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_14	0x000059f0 /* 64-bit */
+#define GRCMBOX_SNDNIC_PROD_IDX_15	0x000059f8 /* 64-bit */
+#define GRCMBOX_HIGH_PRIO_EV_VECTOR	0x00005a00
+#define GRCMBOX_HIGH_PRIO_EV_MASK	0x00005a04
+#define GRCMBOX_LOW_PRIO_EV_VEC		0x00005a08
+#define GRCMBOX_LOW_PRIO_EV_MASK	0x00005a0c
+/* 0x5a10 --> 0x5c00 */
+
+/* Flow Through queues */
+#define FTQ_RESET			0x00005c00
+/* 0x5c04 --> 0x5c10 unused */
+#define FTQ_DMA_NORM_READ_CTL		0x00005c10
+#define FTQ_DMA_NORM_READ_FULL_CNT	0x00005c14
+#define FTQ_DMA_NORM_READ_FIFO_ENQDEQ	0x00005c18
+#define FTQ_DMA_NORM_READ_WRITE_PEEK	0x00005c1c
+#define FTQ_DMA_HIGH_READ_CTL		0x00005c20
+#define FTQ_DMA_HIGH_READ_FULL_CNT	0x00005c24
+#define FTQ_DMA_HIGH_READ_FIFO_ENQDEQ	0x00005c28
+#define FTQ_DMA_HIGH_READ_WRITE_PEEK	0x00005c2c
+#define FTQ_DMA_COMP_DISC_CTL		0x00005c30
+#define FTQ_DMA_COMP_DISC_FULL_CNT	0x00005c34
+#define FTQ_DMA_COMP_DISC_FIFO_ENQDEQ	0x00005c38
+#define FTQ_DMA_COMP_DISC_WRITE_PEEK	0x00005c3c
+#define FTQ_SEND_BD_COMP_CTL		0x00005c40
+#define FTQ_SEND_BD_COMP_FULL_CNT	0x00005c44
+#define FTQ_SEND_BD_COMP_FIFO_ENQDEQ	0x00005c48
+#define FTQ_SEND_BD_COMP_WRITE_PEEK	0x00005c4c
+#define FTQ_SEND_DATA_INIT_CTL		0x00005c50
+#define FTQ_SEND_DATA_INIT_FULL_CNT	0x00005c54
+#define FTQ_SEND_DATA_INIT_FIFO_ENQDEQ	0x00005c58
+#define FTQ_SEND_DATA_INIT_WRITE_PEEK	0x00005c5c
+#define FTQ_DMA_NORM_WRITE_CTL		0x00005c60
+#define FTQ_DMA_NORM_WRITE_FULL_CNT	0x00005c64
+#define FTQ_DMA_NORM_WRITE_FIFO_ENQDEQ	0x00005c68
+#define FTQ_DMA_NORM_WRITE_WRITE_PEEK	0x00005c6c
+#define FTQ_DMA_HIGH_WRITE_CTL		0x00005c70
+#define FTQ_DMA_HIGH_WRITE_FULL_CNT	0x00005c74
+#define FTQ_DMA_HIGH_WRITE_FIFO_ENQDEQ	0x00005c78
+#define FTQ_DMA_HIGH_WRITE_WRITE_PEEK	0x00005c7c
+#define FTQ_SWTYPE1_CTL			0x00005c80
+#define FTQ_SWTYPE1_FULL_CNT		0x00005c84
+#define FTQ_SWTYPE1_FIFO_ENQDEQ		0x00005c88
+#define FTQ_SWTYPE1_WRITE_PEEK		0x00005c8c
+#define FTQ_SEND_DATA_COMP_CTL		0x00005c90
+#define FTQ_SEND_DATA_COMP_FULL_CNT	0x00005c94
+#define FTQ_SEND_DATA_COMP_FIFO_ENQDEQ	0x00005c98
+#define FTQ_SEND_DATA_COMP_WRITE_PEEK	0x00005c9c
+#define FTQ_HOST_COAL_CTL		0x00005ca0
+#define FTQ_HOST_COAL_FULL_CNT		0x00005ca4
+#define FTQ_HOST_COAL_FIFO_ENQDEQ	0x00005ca8
+#define FTQ_HOST_COAL_WRITE_PEEK	0x00005cac
+#define FTQ_MAC_TX_CTL			0x00005cb0
+#define FTQ_MAC_TX_FULL_CNT		0x00005cb4
+#define FTQ_MAC_TX_FIFO_ENQDEQ		0x00005cb8
+#define FTQ_MAC_TX_WRITE_PEEK		0x00005cbc
+#define FTQ_MB_FREE_CTL			0x00005cc0
+#define FTQ_MB_FREE_FULL_CNT		0x00005cc4
+#define FTQ_MB_FREE_FIFO_ENQDEQ		0x00005cc8
+#define FTQ_MB_FREE_WRITE_PEEK		0x00005ccc
+#define FTQ_RCVBD_COMP_CTL		0x00005cd0
+#define FTQ_RCVBD_COMP_FULL_CNT		0x00005cd4
+#define FTQ_RCVBD_COMP_FIFO_ENQDEQ	0x00005cd8
+#define FTQ_RCVBD_COMP_WRITE_PEEK	0x00005cdc
+#define FTQ_RCVLST_PLMT_CTL		0x00005ce0
+#define FTQ_RCVLST_PLMT_FULL_CNT	0x00005ce4
+#define FTQ_RCVLST_PLMT_FIFO_ENQDEQ	0x00005ce8
+#define FTQ_RCVLST_PLMT_WRITE_PEEK	0x00005cec
+#define FTQ_RCVDATA_INI_CTL		0x00005cf0
+#define FTQ_RCVDATA_INI_FULL_CNT	0x00005cf4
+#define FTQ_RCVDATA_INI_FIFO_ENQDEQ	0x00005cf8
+#define FTQ_RCVDATA_INI_WRITE_PEEK	0x00005cfc
+#define FTQ_RCVDATA_COMP_CTL		0x00005d00
+#define FTQ_RCVDATA_COMP_FULL_CNT	0x00005d04
+#define FTQ_RCVDATA_COMP_FIFO_ENQDEQ	0x00005d08
+#define FTQ_RCVDATA_COMP_WRITE_PEEK	0x00005d0c
+#define FTQ_SWTYPE2_CTL			0x00005d10
+#define FTQ_SWTYPE2_FULL_CNT		0x00005d14
+#define FTQ_SWTYPE2_FIFO_ENQDEQ		0x00005d18
+#define FTQ_SWTYPE2_WRITE_PEEK		0x00005d1c
+/* 0x5d20 --> 0x6000 unused */
+
+/* Message signaled interrupt registers */
+#define MSGINT_MODE			0x00006000
+#define  MSGINT_MODE_RESET		 0x00000001
+#define  MSGINT_MODE_ENABLE		 0x00000002
+#define MSGINT_STATUS			0x00006004
+#define MSGINT_FIFO			0x00006008
+/* 0x600c --> 0x6400 unused */
+
+/* DMA completion registers */
+#define DMAC_MODE			0x00006400
+#define  DMAC_MODE_RESET		 0x00000001
+#define  DMAC_MODE_ENABLE		 0x00000002
+/* 0x6404 --> 0x6800 unused */
+
+/* GRC registers */
+#define GRC_MODE			0x00006800
+#define  GRC_MODE_UPD_ON_COAL		0x00000001
+#define  GRC_MODE_BSWAP_NONFRM_DATA	0x00000002
+#define  GRC_MODE_WSWAP_NONFRM_DATA	0x00000004
+#define  GRC_MODE_BSWAP_DATA		0x00000010
+#define  GRC_MODE_WSWAP_DATA		0x00000020
+#define  GRC_MODE_SPLITHDR		0x00000100
+#define  GRC_MODE_NOFRM_CRACKING	0x00000200
+#define  GRC_MODE_INCL_CRC		0x00000400
+#define  GRC_MODE_ALLOW_BAD_FRMS	0x00000800
+#define  GRC_MODE_NOIRQ_ON_SENDS	0x00002000
+#define  GRC_MODE_NOIRQ_ON_RCV		0x00004000
+#define  GRC_MODE_FORCE_PCI32BIT	0x00008000
+#define  GRC_MODE_HOST_STACKUP		0x00010000
+#define  GRC_MODE_HOST_SENDBDS		0x00020000
+#define  GRC_MODE_NO_TX_PHDR_CSUM	0x00100000
+#define  GRC_MODE_NO_RX_PHDR_CSUM	0x00800000
+#define  GRC_MODE_IRQ_ON_TX_CPU_ATTN	0x01000000
+#define  GRC_MODE_IRQ_ON_RX_CPU_ATTN	0x02000000
+#define  GRC_MODE_IRQ_ON_MAC_ATTN	0x04000000
+#define  GRC_MODE_IRQ_ON_DMA_ATTN	0x08000000
+#define  GRC_MODE_IRQ_ON_FLOW_ATTN	0x10000000
+#define  GRC_MODE_4X_NIC_SEND_RINGS	0x20000000
+#define  GRC_MODE_MCAST_FRM_ENABLE	0x40000000
+#define GRC_MISC_CFG			0x00006804
+#define  GRC_MISC_CFG_CORECLK_RESET	0x00000001
+#define  GRC_MISC_CFG_PRESCALAR_MASK	0x000000fe
+#define  GRC_MISC_CFG_PRESCALAR_SHIFT	1
+#define  GRC_MISC_CFG_BOARD_ID_MASK	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5700	0x0001e000
+#define  GRC_MISC_CFG_BOARD_ID_5701	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5702FE	0x00004000
+#define  GRC_MISC_CFG_BOARD_ID_5703	0x00000000
+#define  GRC_MISC_CFG_BOARD_ID_5703S	0x00002000
+#define GRC_LOCAL_CTRL			0x00006808
+#define  GRC_LCLCTRL_INT_ACTIVE		0x00000001
+#define  GRC_LCLCTRL_CLEARINT		0x00000002
+#define  GRC_LCLCTRL_SETINT		0x00000004
+#define  GRC_LCLCTRL_INT_ON_ATTN	0x00000008
+#define  GRC_LCLCTRL_GPIO_INPUT0	0x00000100
+#define  GRC_LCLCTRL_GPIO_INPUT1	0x00000200
+#define  GRC_LCLCTRL_GPIO_INPUT2	0x00000400
+#define  GRC_LCLCTRL_GPIO_OE0		0x00000800
+#define  GRC_LCLCTRL_GPIO_OE1		0x00001000
+#define  GRC_LCLCTRL_GPIO_OE2		0x00002000
+#define  GRC_LCLCTRL_GPIO_OUTPUT0	0x00004000
+#define  GRC_LCLCTRL_GPIO_OUTPUT1	0x00008000
+#define  GRC_LCLCTRL_GPIO_OUTPUT2	0x00010000
+#define  GRC_LCLCTRL_EXTMEM_ENABLE	0x00020000
+#define  GRC_LCLCTRL_MEMSZ_MASK		0x001c0000
+#define  GRC_LCLCTRL_MEMSZ_256K		0x00000000
+#define  GRC_LCLCTRL_MEMSZ_512K		0x00040000
+#define  GRC_LCLCTRL_MEMSZ_1M		0x00080000
+#define  GRC_LCLCTRL_MEMSZ_2M		0x000c0000
+#define  GRC_LCLCTRL_MEMSZ_4M		0x00100000
+#define  GRC_LCLCTRL_MEMSZ_8M		0x00140000
+#define  GRC_LCLCTRL_MEMSZ_16M		0x00180000
+#define  GRC_LCLCTRL_BANK_SELECT	0x00200000
+#define  GRC_LCLCTRL_SSRAM_TYPE		0x00400000
+#define  GRC_LCLCTRL_AUTO_SEEPROM	0x01000000
+#define GRC_TIMER			0x0000680c
+#define GRC_RX_CPU_EVENT		0x00006810
+#define GRC_RX_TIMER_REF		0x00006814
+#define GRC_RX_CPU_SEM			0x00006818
+#define GRC_REMOTE_RX_CPU_ATTN		0x0000681c
+#define GRC_TX_CPU_EVENT		0x00006820
+#define GRC_TX_TIMER_REF		0x00006824
+#define GRC_TX_CPU_SEM			0x00006828
+#define GRC_REMOTE_TX_CPU_ATTN		0x0000682c
+#define GRC_MEM_POWER_UP		0x00006830 /* 64-bit */
+#define GRC_EEPROM_ADDR			0x00006838
+#define  EEPROM_ADDR_WRITE		0x00000000
+#define  EEPROM_ADDR_READ		0x80000000
+#define  EEPROM_ADDR_COMPLETE		0x40000000
+#define  EEPROM_ADDR_FSM_RESET		0x20000000
+#define  EEPROM_ADDR_DEVID_MASK		0x1c000000
+#define  EEPROM_ADDR_DEVID_SHIFT	26
+#define  EEPROM_ADDR_START		0x02000000
+#define  EEPROM_ADDR_CLKPERD_SHIFT	16
+#define  EEPROM_ADDR_ADDR_MASK		0x0000ffff
+#define  EEPROM_ADDR_ADDR_SHIFT		0
+#define  EEPROM_DEFAULT_CLOCK_PERIOD	0x60
+#define  EEPROM_CHIP_SIZE		(64 * 1024)
+#define GRC_EEPROM_DATA			0x0000683c
+#define GRC_EEPROM_CTRL			0x00006840
+#define GRC_MDI_CTRL			0x00006844
+#define GRC_SEEPROM_DELAY		0x00006848
+/* 0x684c --> 0x6c00 unused */
+
+/* 0x6c00 --> 0x7000 unused */
+
+/* NVRAM Control registers */
+#define NVRAM_CMD			0x00007000
+#define  NVRAM_CMD_RESET		 0x00000001
+#define  NVRAM_CMD_DONE			 0x00000008
+#define  NVRAM_CMD_GO			 0x00000010
+#define  NVRAM_CMD_WR			 0x00000020
+#define  NVRAM_CMD_RD			 0x00000000
+#define  NVRAM_CMD_ERASE		 0x00000040
+#define  NVRAM_CMD_FIRST		 0x00000080
+#define  NVRAM_CMD_LAST			 0x00000100
+#define NVRAM_STAT			0x00007004
+#define NVRAM_WRDATA			0x00007008
+#define NVRAM_ADDR			0x0000700c
+#define  NVRAM_ADDR_MSK			0x00ffffff
+#define NVRAM_RDDATA			0x00007010
+#define NVRAM_CFG1			0x00007014
+#define  NVRAM_CFG1_FLASHIF_ENAB	 0x00000001
+#define  NVRAM_CFG1_BUFFERED_MODE	 0x00000002
+#define  NVRAM_CFG1_PASS_THRU		 0x00000004
+#define  NVRAM_CFG1_BIT_BANG		 0x00000008
+#define  NVRAM_CFG1_COMPAT_BYPASS	 0x80000000
+#define NVRAM_CFG2			0x00007018
+#define NVRAM_CFG3			0x0000701c
+#define NVRAM_SWARB			0x00007020
+#define  SWARB_REQ_SET0			 0x00000001
+#define  SWARB_REQ_SET1			 0x00000002
+#define  SWARB_REQ_SET2			 0x00000004
+#define  SWARB_REQ_SET3			 0x00000008
+#define  SWARB_REQ_CLR0			 0x00000010
+#define  SWARB_REQ_CLR1			 0x00000020
+#define  SWARB_REQ_CLR2			 0x00000040
+#define  SWARB_REQ_CLR3			 0x00000080
+#define  SWARB_GNT0			 0x00000100
+#define  SWARB_GNT1			 0x00000200
+#define  SWARB_GNT2			 0x00000400
+#define  SWARB_GNT3			 0x00000800
+#define  SWARB_REQ0			 0x00001000
+#define  SWARB_REQ1			 0x00002000
+#define  SWARB_REQ2			 0x00004000
+#define  SWARB_REQ3			 0x00008000
+#define    NVRAM_BUFFERED_PAGE_SIZE	   264
+#define    NVRAM_BUFFERED_PAGE_POS	   9
+/* 0x7024 --> 0x7400 unused */
+
+/* 0x7400 --> 0x8000 unused */
+
+/* 32K Window into NIC internal memory */
+#define NIC_SRAM_WIN_BASE		0x00008000
+
+/* Offsets into first 32k of NIC internal memory. */
+#define NIC_SRAM_PAGE_ZERO		0x00000000
+#define NIC_SRAM_SEND_RCB		0x00000100 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_RCV_RET_RCB		0x00000200 /* 16 * TG3_BDINFO_... */
+#define NIC_SRAM_STATS_BLK		0x00000300
+#define NIC_SRAM_STATUS_BLK		0x00000b00
+
+#define NIC_SRAM_FIRMWARE_MBOX		0x00000b50
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC1	 0x4B657654
+#define  NIC_SRAM_FIRMWARE_MBOX_MAGIC2	 0x4861764b /* !dma on linkchg */
+
+#define NIC_SRAM_DATA_SIG		0x00000b54
+#define  NIC_SRAM_DATA_SIG_MAGIC	 0x4b657654 /* ascii for 'KevT' */
+
+#define NIC_SRAM_DATA_CFG			0x00000b58
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_MASK	 0x0000000c
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER	 0x00000004
+#define  NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER	 0x00000008
+#define  NIC_SRAM_DATA_CFG_LED_MODE_MASK	 0x00000030
+#define  NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN	 0x00000000
+#define  NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD	 0x00000010
+#define  NIC_SRAM_DATA_CFG_LED_LINK_SPD		 0x00000020
+
+#define NIC_SRAM_DATA_PHY_ID		0x00000b74
+#define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
+#define  NIC_SRAM_DATA_PHY_ID2_MASK	 0x0000ffff
+
+#define NIC_SRAM_FW_CMD_MBOX		0x00000b78
+#define  FWCMD_NICDRV_ALIVE		 0x00000001
+#define  FWCMD_NICDRV_PAUSE_FW		 0x00000002
+#define  FWCMD_NICDRV_IPV4ADDR_CHG	 0x00000003
+#define  FWCMD_NICDRV_IPV6ADDR_CHG	 0x00000004
+#define  FWCMD_NICDRV_FIX_DMAR		 0x00000005
+#define  FWCMD_NICDRV_FIX_DMAW		 0x00000006
+#define NIC_SRAM_FW_CMD_LEN_MBOX	0x00000b7c
+#define NIC_SRAM_FW_CMD_DATA_MBOX	0x00000b80
+#define NIC_SRAM_FW_ASF_STATUS_MBOX	0x00000c00
+#define NIC_SRAM_FW_DRV_STATE_MBOX	0x00000c04
+#define  DRV_STATE_START		 0x00000001
+#define  DRV_STATE_UNLOAD		 0x00000002
+#define  DRV_STATE_WOL			 0x00000003
+#define  DRV_STATE_SUSPEND		 0x00000004
+
+#define NIC_SRAM_FW_RESET_TYPE_MBOX	0x00000c08
+
+#define NIC_SRAM_MAC_ADDR_HIGH_MBOX	0x00000c14
+#define NIC_SRAM_MAC_ADDR_LOW_MBOX	0x00000c18
+
+#if TG3_MINI_RING_WORKS
+#define NIC_SRAM_RX_MINI_BUFFER_DESC	0x00001000
+#endif
+
+#define NIC_SRAM_DMA_DESC_POOL_BASE	0x00002000
+#define  NIC_SRAM_DMA_DESC_POOL_SIZE	 0x00002000
+#define NIC_SRAM_TX_BUFFER_DESC		0x00004000 /* 512 entries */
+#define NIC_SRAM_RX_BUFFER_DESC		0x00006000 /* 256 entries */
+#define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
+#define NIC_SRAM_MBUF_POOL_BASE		0x00008000
+#define  NIC_SRAM_MBUF_POOL_SIZE	 0x00018000
+
+/* Currently this is fixed. */
+#define PHY_ADDR		0x01
+
+/* Tigon3 specific PHY MII registers. */
+#define  TG3_BMCR_SPEED1000		0x0040
+
+#define MII_TG3_CTRL			0x09 /* 1000-baseT control register */
+#define  MII_TG3_CTRL_ADV_1000_HALF	0x0100
+#define  MII_TG3_CTRL_ADV_1000_FULL	0x0200
+#define  MII_TG3_CTRL_AS_MASTER		0x0800
+#define  MII_TG3_CTRL_ENABLE_AS_MASTER	0x1000
+
+#define MII_TG3_EXT_CTRL		0x10 /* Extended control register */
+#define  MII_TG3_EXT_CTRL_LNK3_LED_MODE	0x0002
+#define  MII_TG3_EXT_CTRL_TBI		0x8000
+
+#define MII_TG3_EXT_STAT		0x11 /* Extended status register */
+#define  MII_TG3_EXT_STAT_LPASS		0x0100
+
+#define MII_TG3_DSP_RW_PORT		0x15 /* DSP coefficient read/write port */
+
+#define MII_TG3_DSP_ADDRESS		0x17 /* DSP address register */
+
+#define MII_TG3_AUX_CTRL		0x18 /* auxilliary control register */
+
+#define MII_TG3_AUX_STAT		0x19 /* auxilliary status register */
+#define MII_TG3_AUX_STAT_LPASS		0x0004
+#define MII_TG3_AUX_STAT_SPDMASK	0x0700
+#define MII_TG3_AUX_STAT_10HALF		0x0100
+#define MII_TG3_AUX_STAT_10FULL		0x0200
+#define MII_TG3_AUX_STAT_100HALF	0x0300
+#define MII_TG3_AUX_STAT_100_4		0x0400
+#define MII_TG3_AUX_STAT_100FULL	0x0500
+#define MII_TG3_AUX_STAT_1000HALF	0x0600
+#define MII_TG3_AUX_STAT_1000FULL	0x0700
+
+#define MII_TG3_ISTAT			0x1a /* IRQ status register */
+#define MII_TG3_IMASK			0x1b /* IRQ mask register */
+
+/* ISTAT/IMASK event bits */
+#define MII_TG3_INT_LINKCHG		0x0002
+#define MII_TG3_INT_SPEEDCHG		0x0004
+#define MII_TG3_INT_DUPLEXCHG		0x0008
+#define MII_TG3_INT_ANEG_PAGE_RX	0x0400
+
+/* XXX Add this to mii.h */
+#ifndef ADVERTISE_PAUSE
+#define ADVERTISE_PAUSE_CAP		0x0400
+#endif
+#ifndef ADVERTISE_PAUSE_ASYM
+#define ADVERTISE_PAUSE_ASYM		0x0800
+#endif
+#ifndef LPA_PAUSE
+#define LPA_PAUSE_CAP			0x0400
+#endif
+#ifndef LPA_PAUSE_ASYM
+#define LPA_PAUSE_ASYM			0x0800
+#endif
+
+/* There are two ways to manage the TX descriptors on the tigon3.
+ * Either the descriptors are in host DMA'able memory, or they
+ * exist only in the cards on-chip SRAM.  All 16 send bds are under
+ * the same mode, they may not be configured individually.
+ *
+ * The mode we use is controlled by TG3_FLAG_HOST_TXDS in tp->tg3_flags.
+ *
+ * To use host memory TX descriptors:
+ *	1) Set GRC_MODE_HOST_SENDBDS in GRC_MODE register.
+ *	   Make sure GRC_MODE_4X_NIC_SEND_RINGS is clear.
+ *	2) Allocate DMA'able memory.
+ *	3) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to DMA address of memory
+ *	      obtained in step 2
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC.
+ *	   c) Set len field of TG3_BDINFO_MAXLEN_FLAGS to number
+ *            of TX descriptors.  Leave flags field clear.
+ *	4) Access TX descriptors via host memory.  The chip
+ *	   will refetch into local SRAM as needed when producer
+ *	   index mailboxes are updated.
+ *
+ * To use on-chip TX descriptors:
+ *	1) Set GRC_MODE_4X_NIC_SEND_RINGS in GRC_MODE register.
+ *	   Make sure GRC_MODE_HOST_SENDBDS is clear.
+ *	2) In NIC_SRAM_SEND_RCB (of desired index) of on-chip SRAM:
+ *	   a) Set TG3_BDINFO_HOST_ADDR to zero.
+ *	   b) Set TG3_BDINFO_NIC_ADDR to NIC_SRAM_TX_BUFFER_DESC
+ *	   c) TG3_BDINFO_MAXLEN_FLAGS is don't care.
+ *	3) Access TX descriptors directly in on-chip SRAM
+ *	   using normal {read,write}l().  (and not using
+ *         pointer dereferencing of ioremap()'d memory like
+ *	   the broken Broadcom driver does)
+ *
+ * Note that BDINFO_FLAGS_DISABLED should be set in the flags field of
+ * TG3_BDINFO_MAXLEN_FLAGS of all unused SEND_RCB indices.
+ */
+struct tg3_tx_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+
+	u32				len_flags;
+#define TXD_FLAG_TCPUDP_CSUM		0x0001
+#define TXD_FLAG_IP_CSUM		0x0002
+#define TXD_FLAG_END			0x0004
+#define TXD_FLAG_IP_FRAG		0x0008
+#define TXD_FLAG_IP_FRAG_END		0x0010
+#define TXD_FLAG_VLAN			0x0040
+#define TXD_FLAG_COAL_NOW		0x0080
+#define TXD_FLAG_CPU_PRE_DMA		0x0100
+#define TXD_FLAG_CPU_POST_DMA		0x0200
+#define TXD_FLAG_ADD_SRC_ADDR		0x1000
+#define TXD_FLAG_CHOOSE_SRC_ADDR	0x6000
+#define TXD_FLAG_NO_CRC			0x8000
+#define TXD_LEN_SHIFT			16
+
+	u32				vlan_tag;
+#define TXD_VLAN_TAG_SHIFT		0
+};
+
+#define TXD_ADDR			0x00UL /* 64-bit */
+#define TXD_LEN_FLAGS			0x08UL /* 32-bit (upper 16-bits are len) */
+#define TXD_VLAN_TAG			0x0cUL /* 32-bit (upper 16-bits are tag) */
+#define TXD_SIZE			0x10UL
+
+struct tg3_rx_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+
+	u32				idx_len;
+#define RXD_IDX_MASK	0xffff0000
+#define RXD_IDX_SHIFT	16
+#define RXD_LEN_MASK	0x0000ffff
+#define RXD_LEN_SHIFT	0
+
+	u32				type_flags;
+#define RXD_TYPE_SHIFT	16
+#define RXD_FLAGS_SHIFT	0
+
+#define RXD_FLAG_END			0x0004
+#if TG3_MINI_RING_WORKS
+#define RXD_FLAG_MINI			0x0800
+#endif
+#define RXD_FLAG_JUMBO			0x0020
+#define RXD_FLAG_VLAN			0x0040
+#define RXD_FLAG_ERROR			0x0400
+#define RXD_FLAG_IP_CSUM		0x1000
+#define RXD_FLAG_TCPUDP_CSUM		0x2000
+#define RXD_FLAG_IS_TCP			0x4000
+
+	u32				ip_tcp_csum;
+#define RXD_IPCSUM_MASK		0xffff0000
+#define RXD_IPCSUM_SHIFT	16
+#define RXD_TCPCSUM_MASK	0x0000ffff
+#define RXD_TCPCSUM_SHIFT	0
+
+	u32				err_vlan;
+
+#define RXD_VLAN_MASK			0x0000ffff
+
+#define RXD_ERR_BAD_CRC			0x00010000
+#define RXD_ERR_COLLISION		0x00020000
+#define RXD_ERR_LINK_LOST		0x00040000
+#define RXD_ERR_PHY_DECODE		0x00080000
+#define RXD_ERR_ODD_NIBBLE_RCVD_MII	0x00100000
+#define RXD_ERR_MAC_ABRT		0x00200000
+#define RXD_ERR_TOO_SMALL		0x00400000
+#define RXD_ERR_NO_RESOURCES		0x00800000
+#define RXD_ERR_HUGE_FRAME		0x01000000
+#define RXD_ERR_MASK			0xffff0000
+
+	u32				reserved;
+	u32				opaque;
+#define RXD_OPAQUE_INDEX_MASK		0x0000ffff
+#define RXD_OPAQUE_INDEX_SHIFT		0
+#define RXD_OPAQUE_RING_STD		0x00010000
+#define RXD_OPAQUE_RING_JUMBO		0x00020000
+#if TG3_MINI_RING_WORKS
+#define RXD_OPAQUE_RING_MINI		0x00040000
+#endif
+#define RXD_OPAQUE_RING_MASK		0x00070000
+};
+
+struct tg3_ext_rx_buffer_desc {
+	struct {
+		u32			addr_hi;
+		u32			addr_lo;
+	}				addrlist[3];
+	u32				len2_len1;
+	u32				resv_len3;
+	struct tg3_rx_buffer_desc	std;
+};
+
+/* We only use this when testing out the DMA engine
+ * at probe time.  This is the internal format of buffer
+ * descriptors used by the chip at NIC_SRAM_DMA_DESCS.
+ */
+struct tg3_internal_buffer_desc {
+	u32				addr_hi;
+	u32				addr_lo;
+	u32				nic_mbuf;
+	/* XXX FIX THIS */
+#ifdef __BIG_ENDIAN
+	u16				cqid_sqid;
+	u16				len;
+#else
+	u16				len;
+	u16				cqid_sqid;
+#endif
+	u32				flags;
+	u32				__cookie1;
+	u32				__cookie2;
+	u32				__cookie3;
+};
+
+#define TG3_HW_STATUS_SIZE		0x80
+struct tg3_hw_status {
+	u32				status;
+#define SD_STATUS_UPDATED		0x00000001
+#define SD_STATUS_LINK_CHG		0x00000002
+#define SD_STATUS_ERROR			0x00000004
+
+	u32				status_tag;
+
+#ifdef __BIG_ENDIAN
+	u16				rx_consumer;
+	u16				rx_jumbo_consumer;
+#else
+	u16				rx_jumbo_consumer;
+	u16				rx_consumer;
+#endif
+
+#ifdef __BIG_ENDIAN
+	u16				reserved;
+	u16				rx_mini_consumer;
+#else
+	u16				rx_mini_consumer;
+	u16				reserved;
+#endif
+	struct {
+#ifdef __BIG_ENDIAN
+		u16			tx_consumer;
+		u16			rx_producer;
+#else
+		u16			rx_producer;
+		u16			tx_consumer;
+#endif
+	}				idx[16];
+};
+
+typedef struct {
+	u32 high, low;
+} tg3_stat64_t;
+
+struct tg3_hw_stats {
+	u8				__reserved0[0x400-0x300];
+
+	/* Statistics maintained by Receive MAC. */
+	tg3_stat64_t			rx_octets;
+	u64				__reserved1;
+	tg3_stat64_t			rx_fragments;
+	tg3_stat64_t			rx_ucast_packets;
+	tg3_stat64_t			rx_mcast_packets;
+	tg3_stat64_t			rx_bcast_packets;
+	tg3_stat64_t			rx_fcs_errors;
+	tg3_stat64_t			rx_align_errors;
+	tg3_stat64_t			rx_xon_pause_rcvd;
+	tg3_stat64_t			rx_xoff_pause_rcvd;
+	tg3_stat64_t			rx_mac_ctrl_rcvd;
+	tg3_stat64_t			rx_xoff_entered;
+	tg3_stat64_t			rx_frame_too_long_errors;
+	tg3_stat64_t			rx_jabbers;
+	tg3_stat64_t			rx_undersize_packets;
+	tg3_stat64_t			rx_in_length_errors;
+	tg3_stat64_t			rx_out_length_errors;
+	tg3_stat64_t			rx_64_or_less_octet_packets;
+	tg3_stat64_t			rx_65_to_127_octet_packets;
+	tg3_stat64_t			rx_128_to_255_octet_packets;
+	tg3_stat64_t			rx_256_to_511_octet_packets;
+	tg3_stat64_t			rx_512_to_1023_octet_packets;
+	tg3_stat64_t			rx_1024_to_1522_octet_packets;
+	tg3_stat64_t			rx_1523_to_2047_octet_packets;
+	tg3_stat64_t			rx_2048_to_4095_octet_packets;
+	tg3_stat64_t			rx_4096_to_8191_octet_packets;
+	tg3_stat64_t			rx_8192_to_9022_octet_packets;
+
+	u64				__unused0[37];
+
+	/* Statistics maintained by Transmit MAC. */
+	tg3_stat64_t			tx_octets;
+	u64				__reserved2;
+	tg3_stat64_t			tx_collisions;
+	tg3_stat64_t			tx_xon_sent;
+	tg3_stat64_t			tx_xoff_sent;
+	tg3_stat64_t			tx_flow_control;
+	tg3_stat64_t			tx_mac_errors;
+	tg3_stat64_t			tx_single_collisions;
+	tg3_stat64_t			tx_mult_collisions;
+	tg3_stat64_t			tx_deferred;
+	u64				__reserved3;
+	tg3_stat64_t			tx_excessive_collisions;
+	tg3_stat64_t			tx_late_collisions;
+	tg3_stat64_t			tx_collide_2times;
+	tg3_stat64_t			tx_collide_3times;
+	tg3_stat64_t			tx_collide_4times;
+	tg3_stat64_t			tx_collide_5times;
+	tg3_stat64_t			tx_collide_6times;
+	tg3_stat64_t			tx_collide_7times;
+	tg3_stat64_t			tx_collide_8times;
+	tg3_stat64_t			tx_collide_9times;
+	tg3_stat64_t			tx_collide_10times;
+	tg3_stat64_t			tx_collide_11times;
+	tg3_stat64_t			tx_collide_12times;
+	tg3_stat64_t			tx_collide_13times;
+	tg3_stat64_t			tx_collide_14times;
+	tg3_stat64_t			tx_collide_15times;
+	tg3_stat64_t			tx_ucast_packets;
+	tg3_stat64_t			tx_mcast_packets;
+	tg3_stat64_t			tx_bcast_packets;
+	tg3_stat64_t			tx_carrier_sense_errors;
+	tg3_stat64_t			tx_discards;
+	tg3_stat64_t			tx_errors;
+
+	u64				__unused1[31];
+
+	/* Statistics maintained by Receive List Placement. */
+	tg3_stat64_t			COS_rx_packets[16];
+	tg3_stat64_t			COS_rx_filter_dropped;
+	tg3_stat64_t			dma_writeq_full;
+	tg3_stat64_t			dma_write_prioq_full;
+	tg3_stat64_t			rxbds_empty;
+	tg3_stat64_t			rx_discards;
+	tg3_stat64_t			rx_errors;
+	tg3_stat64_t			rx_threshold_hit;
+
+	u64				__unused2[9];
+
+	/* Statistics maintained by Send Data Initiator. */
+	tg3_stat64_t			COS_out_packets[16];
+	tg3_stat64_t			dma_readq_full;
+	tg3_stat64_t			dma_read_prioq_full;
+	tg3_stat64_t			tx_comp_queue_full;
+
+	/* Statistics maintained by Host Coalescing. */
+	tg3_stat64_t			ring_set_send_prod_index;
+	tg3_stat64_t			ring_status_update;
+	tg3_stat64_t			nic_irqs;
+	tg3_stat64_t			nic_avoided_irqs;
+	tg3_stat64_t			nic_tx_threshold_hit;
+
+	u8				__reserved4[0xb00-0x9c0];
+};
+
+enum phy_led_mode {
+	led_mode_auto,
+	led_mode_three_link,
+	led_mode_link10
+};
+
+/* 'mapping' is superfluous as the chip does not write into
+ * the tx/rx post rings so we could just fetch it from there.
+ * But the cache behavior is better how we are doing it now.
+ */
+struct ring_info {
+	struct sk_buff			*skb;
+	dma_addr_t			mapping;
+};
+
+struct tg3_config_info {
+	u32				flags;
+};
+
+struct tg3_link_config {
+	/* Describes what we're trying to get. */
+	u32				advertising;
+	u16				speed;
+	u8				duplex;
+	u8				autoneg;
+
+	/* Describes what we actually have. */
+	u16				active_speed;
+	u8				active_duplex;
+#define SPEED_INVALID		0xffff
+#define DUPLEX_INVALID		0xff
+#define AUTONEG_INVALID		0xff
+
+	/* When we go in and out of low power mode we need
+	 * to swap with this state.
+	 */
+	int				phy_is_low_power;
+	u16				orig_speed;
+	u8				orig_duplex;
+	u8				orig_autoneg;
+};
+
+struct tg3_coalesce_config {
+	u32		rx_coalesce_ticks;
+	u32		rx_max_coalesced_frames;
+	u32		rx_coalesce_ticks_during_int;
+	u32		rx_max_coalesced_frames_during_int;
+
+	u32		tx_coalesce_ticks;
+	u32		tx_max_coalesced_frames;
+	u32		tx_coalesce_ticks_during_int;
+	u32		tx_max_coalesced_frames_during_int;
+
+	u32		stats_coalesce_ticks;
+};
+
+struct tg3_bufmgr_config {
+	u32		mbuf_read_dma_low_water;
+	u32		mbuf_mac_rx_low_water;
+	u32		mbuf_high_water;
+
+	u32		mbuf_read_dma_low_water_jumbo;
+	u32		mbuf_mac_rx_low_water_jumbo;
+	u32		mbuf_high_water_jumbo;
+
+	u32		dma_low_water;
+	u32		dma_high_water;
+};
+
+struct tg3 {
+	spinlock_t			lock;
+	u32				tx_prod;
+	u32				tx_cons;
+	u32				rx_rcb_ptr;
+	u32				rx_std_ptr;
+	u32				rx_jumbo_ptr;
+#if TG3_MINI_RING_WORKS
+	u32				rx_mini_ptr;
+#endif
+	spinlock_t			indirect_lock;
+
+	struct net_device_stats		net_stats;
+	unsigned long			phy_crc_errors;
+
+	/* Adaptive coalescing engine. */
+	unsigned long			last_rate_sample;
+	u32				last_rx_count;
+	u32				last_tx_count;
+
+	u32				rx_offset;
+	u32				tg3_flags;
+#define TG3_FLAG_HOST_TXDS		0x00000001
+#define TG3_FLAG_TXD_MBOX_HWBUG		0x00000002
+#define TG3_FLAG_BROKEN_CHECKSUMS	0x00000004
+#define TG3_FLAG_USE_LINKCHG_REG	0x00000008
+#define TG3_FLAG_USE_MI_INTERRUPT	0x00000010
+#define TG3_FLAG_PHY_RESET_ON_INIT	0x00000100
+#define TG3_FLAG_PCIX_TARGET_HWBUG	0x00000200
+#define TG3_FLAG_TAGGED_IRQ_STATUS	0x00000400
+#define TG3_FLAG_WOL_SPEED_100MB	0x00000800
+#define TG3_FLAG_WOL_ENABLE		0x00001000
+#define TG3_FLAG_NVRAM			0x00002000
+#define TG3_FLAG_NVRAM_BUFFERED		0x00004000
+#define TG3_FLAG_RX_PAUSE		0x00008000
+#define TG3_FLAG_TX_PAUSE		0x00010000
+#define TG3_FLAG_PCIX_MODE		0x00020000
+#define TG3_FLAG_PCI_HIGH_SPEED		0x00040000
+#define TG3_FLAG_PCI_32BIT		0x00080000
+#define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
+#define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
+#define TG3_FLAG_AUTONEG_DISABLE	0x00400000
+#define TG3_FLAG_JUMBO_ENABLE		0x00800000
+#define TG3_FLAG_10_100_ONLY		0x01000000
+#define TG3_FLAG_INIT_COMPLETE		0x80000000
+
+	u32				msg_enable;
+
+	struct timer_list		timer;
+	u16				timer_counter;
+	u16				timer_multiplier;
+	u32				timer_offset;
+
+	struct tg3_link_config		link_config;
+	struct tg3_coalesce_config	coalesce_config;
+	struct tg3_bufmgr_config	bufmgr_config;
+
+	/* cache h/w values, often passed straight to h/w */
+	u32				rx_mode;
+	u32				tx_mode;
+	u32				mac_mode;
+	u32				mi_mode;
+	u32				misc_host_ctrl;
+	u32				grc_mode;
+	u32				grc_local_ctrl;
+	u32				dma_rwctrl;
+	u32				coalesce_mode;
+
+	/* PCI block */
+	u16				pci_chip_rev_id;
+	u8				pci_cacheline_sz;
+	u8				pci_lat_timer;
+	u8				pci_hdr_type;
+	u8				pci_bist;
+	u32				pci_cfg_state[64 / sizeof(u32)];
+
+	int				pm_cap;
+
+	/* PHY info */
+	u32				phy_id;
+#define PHY_ID_MASK			0xfffffff0
+#define PHY_ID_BCM5400			0x60008040
+#define PHY_ID_BCM5401			0x60008050
+#define PHY_ID_BCM5411			0x60008070
+#define PHY_ID_BCM5701			0x60008110
+#define PHY_ID_BCM5703			0x60008160
+#define PHY_ID_BCM8002			0x60010140
+#define PHY_ID_SERDES			0xfeedbee0
+#define PHY_ID_INVALID			0xffffffff
+#define PHY_ID_REV_MASK			0x0000000f
+#define PHY_REV_BCM5401_B0		0x1
+#define PHY_REV_BCM5401_B2		0x3
+#define PHY_REV_BCM5401_C0		0x6
+
+	enum phy_led_mode		led_mode;
+
+	char				board_part_number[24];
+
+	/* This macro assumes the passed PHY ID is already masked
+	 * with PHY_ID_MASK.
+	 */
+#define KNOWN_PHY_ID(X)		\
+	((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
+	 (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
+	 (X) == PHY_ID_BCM5703 ||			   \
+	 (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
+
+	unsigned long			regs;
+	struct pci_dev			*pdev;
+	struct net_device		*dev;
+#if TG3_VLAN_TAG_USED
+	struct vlan_group		*vlgrp;
+#endif
+
+	struct tg3_rx_buffer_desc	*rx_std;
+	struct ring_info		*rx_std_buffers;
+	dma_addr_t			rx_std_mapping;
+#if TG3_MINI_RING_WORKS
+	struct tg3_rx_buffer_desc	*rx_mini;
+	struct ring_info		*rx_mini_buffers;
+	dma_addr_t			rx_mini_mapping;
+#endif
+	struct tg3_rx_buffer_desc	*rx_jumbo;
+	struct ring_info		*rx_jumbo_buffers;
+	dma_addr_t			rx_jumbo_mapping;
+
+	struct tg3_rx_buffer_desc	*rx_rcb;
+	dma_addr_t			rx_rcb_mapping;
+
+	/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
+	struct tg3_tx_buffer_desc	*tx_ring;
+	struct ring_info		*tx_buffers;
+	dma_addr_t			tx_desc_mapping;
+
+	struct tg3_hw_status		*hw_status;
+	dma_addr_t			status_mapping;
+
+	struct tg3_hw_stats		*hw_stats;
+	dma_addr_t			stats_mapping;
+};
+
+#endif /* !(_T3_H) */
diff -urN linux-2.5.6-pre3/drivers/net/tokenring/lanstreamer.c linux-2.5.6/drivers/net/tokenring/lanstreamer.c
--- linux-2.5.6-pre3/drivers/net/tokenring/lanstreamer.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/tokenring/lanstreamer.c	Thu Mar  7 18:24:48 2002
@@ -60,6 +60,11 @@
  *		malloc free checks, reviewed code. <alan@redhat.com>
  *  03/13/00 - Added spinlocks for smp
  *  03/08/01 - Added support for module_init() and module_exit()
+ *  08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue
+ *             calls and other incorrectness - Kent Yoder <yoder1@us.ibm.com>
+ *  11/05/01 - Restructured the interrupt function, added delays, reduced the 
+ *             the number of TX descriptors to 1, which together can prevent 
+ *             the card from locking up the box - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -84,6 +89,14 @@
 
 #define STREAMER_NETWORK_MONITOR 0
 
+/* #define CONFIG_PROC_FS */
+
+/*
+ *  Allow or disallow ioctl's for debugging
+ */
+
+#define STREAMER_IOCTL 0
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -105,6 +118,7 @@
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/version.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
@@ -121,7 +135,8 @@
  * Official releases will only have an a.b.c version number format.
  */
 
-static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan";
+static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
+                        "              v0.5.1 03/04/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -175,6 +190,10 @@
 MODULE_PARM(message_level,
 	    "1-" __MODULE_STRING(STREAMER_MAX_ADAPTERS) "i");
 
+#if STREAMER_IOCTL
+static int streamer_ioctl(struct net_device *, struct ifreq *, int);
+#endif
+
 static int streamer_reset(struct net_device *dev);
 static int streamer_open(struct net_device *dev);
 static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -206,6 +225,8 @@
   __u32 mmio_start, mmio_end, mmio_flags, mmio_len;
   int rc=0;
   static int card_no=-1;
+  u16 pcr;
+  u8 cls = 0;
 
 #if STREAMER_DEBUG
   printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);
@@ -281,7 +302,11 @@
 			dev->hard_start_xmit = &streamer_xmit;
 			dev->change_mtu = &streamer_change_mtu;
 			dev->stop = &streamer_close;
+#if STREAMER_IOCTL
+			dev->do_ioctl = &streamer_ioctl;
+#else
 			dev->do_ioctl = NULL;
+#endif
 			dev->set_multicast_list = &streamer_set_rx_mode;
 			dev->get_stats = &streamer_get_stats;
 			dev->set_mac_address = &streamer_set_mac_address;
@@ -303,6 +328,27 @@
 
   spin_lock_init(&streamer_priv->streamer_lock);
   
+  pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls);
+  cls <<= 2;
+  if (cls != SMP_CACHE_BYTES) {
+         printk(KERN_INFO "  PCI cache line size set incorrectly "
+                "(%i bytes) by BIOS/FW, ", cls);
+         if (cls > SMP_CACHE_BYTES)
+                printk("expecting %i\n", SMP_CACHE_BYTES);
+         else {
+                printk("correcting to %i\n", SMP_CACHE_BYTES);
+                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+                                      SMP_CACHE_BYTES >> 2);
+         }
+  }
+
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
+  pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR);
+
+  pci_write_config_word (pdev, PCI_COMMAND, pcr);
+  pci_read_config_word (pdev, PCI_COMMAND, &pcr);
+
   printk("%s \n", version);
   printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name,
 	 streamer_priv->streamer_card_name,
@@ -403,6 +449,7 @@
 	printk("GPR: %x\n", readw(streamer_mmio + GPR));
 	printk("SISRMASK: %x\n", readw(streamer_mmio + SISR_MASK));
 #endif
+	writew(readw(streamer_mmio + BCTL) | (BCTL_RX_FIFO_8 | BCTL_TX_FIFO_8), streamer_mmio + BCTL );
 
 	if (streamer_priv->streamer_ring_speed == 0) {	/* Autosense */
 		writew(readw(streamer_mmio + GPR) | GPR_AUTOSENSE,
@@ -558,8 +605,6 @@
 	do {
 		int i;
 
-		save_flags(flags);
-		cli();
 		for (i = 0; i < SRB_COMMAND_SIZE; i += 2) {
 			writew(0, streamer_mmio + LAPDINC);
 		}
@@ -599,11 +644,12 @@
 		}
 		printk("\n");
 #endif
-
+		spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 		streamer_priv->srb_queued = 1;
 
 		/* signal solo that SRB command has been issued */
 		writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
+		spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
 
 		while (streamer_priv->srb_queued) {
 			interruptible_sleep_on_timeout(&streamer_priv->srb_wait, 5 * HZ);
@@ -617,7 +663,6 @@
 				break;
 			}
 		}
-		restore_flags(flags);
 
 #if STREAMER_DEBUG
 		printk("SISR_MASK: %x\n", readw(streamer_mmio + SISR_MASK));
@@ -767,9 +812,12 @@
 		streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
 		streamer_priv->streamer_tx_ring[i].buffer = 0;
 		streamer_priv->streamer_tx_ring[i].buflen = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd1 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
 	}
 	streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
-					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);;
+					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
 
 	streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
 	streamer_priv->tx_ring_free = 0;	/* next entry in tx ring to use */
@@ -941,37 +989,30 @@
 	__u8 *streamer_mmio = streamer_priv->streamer_mmio;
 	__u16 sisr;
 	__u16 misr;
-	__u16 sisrmask;
+	u8 max_intr = MAX_INTR;
 
-	sisrmask = SISR_MI;
-	writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
+	spin_lock(&streamer_priv->streamer_lock);
 	sisr = readw(streamer_mmio + SISR);
-	writew(~sisr, streamer_mmio + SISR_RUM);
-	misr = readw(streamer_mmio + MISR_RUM);
-	writew(~misr, streamer_mmio + MISR_RUM);
 
-	if (!sisr) 
-	{		/* Interrupt isn't for us */
-  	        writew(~misr,streamer_mmio+MISR_RUM);
-		return;
-	}
+	while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | 
+		       SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR))
+               && (max_intr > 0)) {
 
-	spin_lock(&streamer_priv->streamer_lock);
+		if(sisr & SISR_PAR_ERR) {
+			writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
 
-	if ((sisr & (SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | SISR_ARB_CMD | SISR_TRB_REPLY))
-	    || (misr & (MISR_TX2_EOF | MISR_RX_NOBUF | MISR_RX_EOF))) {
-		if (sisr & SISR_SRB_REPLY) {
-			if (streamer_priv->srb_queued == 1) {
-				wake_up_interruptible(&streamer_priv->srb_wait);
-			} else if (streamer_priv->srb_queued == 2) {
-				streamer_srb_bh(dev);
-			}
-			streamer_priv->srb_queued = 0;
+		else if(sisr & SISR_SERR_ERR) {
+			writew(~SISR_SERR_ERR, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
-		/* SISR_SRB_REPLY */
+
+		else if(sisr & SISR_MI) {
+			misr = readw(streamer_mmio + MISR_RUM);
+
 		if (misr & MISR_TX2_EOF) {
-			while (streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) 
-			{
+				while(streamer_priv->streamer_tx_ring[(streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1)].status) {
 				streamer_priv->tx_ring_last_status = (streamer_priv->tx_ring_last_status + 1) & (STREAMER_TX_RING_SIZE - 1);
 				streamer_priv->free_tx_ring_entries++;
 				streamer_priv->streamer_stats.tx_bytes += streamer_priv->tx_ring_skb[streamer_priv->tx_ring_last_status]->len;
@@ -981,6 +1022,9 @@
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].status = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].bufcnt_framelen = 0;
 				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].buflen = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd1 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd2 = 0;
+				streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_last_status].rsvd3 = 0;
 			}
 			netif_wake_queue(dev);
 		}
@@ -989,7 +1033,30 @@
 			streamer_rx(dev);
 		}
 		/* MISR_RX_EOF */
-		if (sisr & SISR_ADAPTER_CHECK) {
+
+			if (misr & MISR_RX_NOBUF) {
+				/* According to the documentation, we don't have to do anything,  
+                                 * but trapping it keeps it out of /var/log/messages.  
+                                 */
+			}		/* SISR_RX_NOBUF */
+
+			writew(~misr, streamer_mmio + MISR_RUM);
+			(void)readw(streamer_mmio + MISR_RUM);
+		}
+
+		else if (sisr & SISR_SRB_REPLY) {
+			if (streamer_priv->srb_queued == 1) {
+				wake_up_interruptible(&streamer_priv->srb_wait);
+			} else if (streamer_priv->srb_queued == 2) {
+				streamer_srb_bh(dev);
+			}
+			streamer_priv->srb_queued = 0;
+
+			writew(~SISR_SRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
+		}
+
+		else if (sisr & SISR_ADAPTER_CHECK) {
 			printk(KERN_WARNING "%s: Adapter Check Interrupt Raised, 8 bytes of information follow:\n", dev->name);
 			writel(readl(streamer_mmio + LAPWWO), streamer_mmio + LAPA);
 			printk(KERN_WARNING "%s: Words %x:%x:%x:%x:\n",
@@ -1001,38 +1068,37 @@
 		}
 
 		/* SISR_ADAPTER_CHECK */
-		if (sisr & SISR_ASB_FREE) {
+		else if (sisr & SISR_ASB_FREE) {
 			/* Wake up anything that is waiting for the asb response */
 			if (streamer_priv->asb_queued) {
 				streamer_asb_bh(dev);
 			}
+			writew(~SISR_ASB_FREE, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ASB_FREE */
-		if (sisr & SISR_ARB_CMD) {
+		else if (sisr & SISR_ARB_CMD) {
 			streamer_arb_cmd(dev);
+			writew(~SISR_ARB_CMD, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_ARB_CMD */
-		if (sisr & SISR_TRB_REPLY) {
+		else if (sisr & SISR_TRB_REPLY) {
 			/* Wake up anything that is waiting for the trb response */
 			if (streamer_priv->trb_queued) {
 				wake_up_interruptible(&streamer_priv->
 						      trb_wait);
 			}
 			streamer_priv->trb_queued = 0;
+			writew(~SISR_TRB_REPLY, streamer_mmio + SISR_RUM);
+			(void)readw(streamer_mmio + SISR_RUM);
 		}
 		/* SISR_TRB_REPLY */
-		if (misr & MISR_RX_NOBUF) {
-			/* According to the documentation, we don't have to do anything, but trapping it keeps it out of
-			   /var/log/messages.  */
-		}		/* SISR_RX_NOBUF */
-	} else {
-		printk(KERN_WARNING "%s: Unexpected interrupt: %x\n",
-		       dev->name, sisr);
-		printk(KERN_WARNING "%s: SISR_MASK: %x\n", dev->name,
-		       readw(streamer_mmio + SISR_MASK));
-	}			/* One if the interrupts we want */
 
-	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		sisr = readw(streamer_mmio + SISR);
+		max_intr--;
+	} /* while() */		
+
 	spin_unlock(&streamer_priv->streamer_lock) ; 
 }
 
@@ -1044,13 +1110,16 @@
 	unsigned long flags ;
 
 	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
-	netif_stop_queue(dev);
 
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
-		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buflen = skb->len;
+
 		streamer_priv->tx_ring_skb[streamer_priv->tx_ring_free] = skb;
 		streamer_priv->free_tx_ring_entries--;
 #if STREAMER_DEBUG_PACKETS
@@ -1067,12 +1136,13 @@
 #endif
 
 		writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+		(void)readl(streamer_mmio + TX2LFDA);
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
-		netif_wake_queue(dev);
 		spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 0;
 	} else {
+	        netif_stop_queue(dev);
 	        spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
 		return 1;
 	}
@@ -1092,12 +1162,13 @@
 	writew(htons(SRB_CLOSE_ADAPTER << 8),streamer_mmio+LAPDINC);
 	writew(htons(STREAMER_CLEAR_RET_CODE << 8), streamer_mmio+LAPDINC);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&streamer_priv->streamer_lock, flags);
 
 	streamer_priv->srb_queued = 1;
 	writew(LISR_SRB_CMD, streamer_mmio + LISR_SUM);
 
+	spin_unlock_irqrestore(&streamer_priv->streamer_lock, flags);
+
 	while (streamer_priv->srb_queued) 
 	{
 		interruptible_sleep_on_timeout(&streamer_priv->srb_wait,
@@ -1114,7 +1185,6 @@
 		}
 	}
 
-	restore_flags(flags);
 	streamer_priv->rx_ring_last_received = (streamer_priv->rx_ring_last_received + 1) & (STREAMER_RX_RING_SIZE - 1);
 
 	for (i = 0; i < STREAMER_RX_RING_SIZE; i++) {
@@ -1808,6 +1878,64 @@
 #endif
 #endif
 
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+        int i;
+	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	u8 *streamer_mmio = streamer_priv->streamer_mmio;
+
+	switch(cmd) {
+	case IOCTL_SISR_MASK:
+		writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+		break;
+	case IOCTL_SPIN_LOCK_TEST:
+	        printk(KERN_INFO "spin_lock() called.\n");
+		spin_lock(&streamer_priv->streamer_lock);
+		spin_unlock(&streamer_priv->streamer_lock);
+		printk(KERN_INFO "spin_unlock() finished.\n");
+		break;
+	case IOCTL_PRINT_BDAS:
+	        printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
+		       readw(streamer_mmio + RXBDA),
+		       readw(streamer_mmio + RXLBDA),
+		       readw(streamer_mmio + TX2FDA),
+		       readw(streamer_mmio + TX2LFDA));
+		break;
+	case IOCTL_PRINT_REGISTERS:
+	        printk(KERN_INFO "registers:\n");
+		printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask  %04x mask  %04x\n", 
+		       readw(streamer_mmio + SISR),
+		       readw(streamer_mmio + MISR_RUM),
+		       readw(streamer_mmio + LISR),
+		       readw(streamer_mmio + BCTL),
+		       readw(streamer_mmio + BMCTL_SUM),
+		       readw(streamer_mmio + SISR_MASK),
+		       readw(streamer_mmio + MISR_MASK));
+		break;
+	case IOCTL_PRINT_RX_BUFS:
+	        printk(KERN_INFO "Print rx bufs:\n");
+		for(i=0; i<STREAMER_RX_RING_SIZE; i++)
+		        printk(KERN_INFO "rx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_rx_ring[i].status);
+		break;
+	case IOCTL_PRINT_TX_BUFS:
+	        printk(KERN_INFO "Print tx bufs:\n");
+		for(i=0; i<STREAMER_TX_RING_SIZE; i++)
+		        printk(KERN_INFO "tx_ring %d status: 0x%x\n", i, 
+			       streamer_priv->streamer_tx_ring[i].status);
+		break;
+	case IOCTL_RX_CMD:
+	        streamer_rx(dev);
+		printk(KERN_INFO "Sent rx command.\n");
+		break;
+	default:
+	        printk(KERN_INFO "Bad ioctl!\n");
+	}
+	return 0;
+}
+#endif
+
 static struct pci_driver streamer_pci_driver = {
   name:       "lanstreamer",
   id_table:   streamer_pci_tbl,
diff -urN linux-2.5.6-pre3/drivers/net/tokenring/lanstreamer.h linux-2.5.6/drivers/net/tokenring/lanstreamer.h
--- linux-2.5.6-pre3/drivers/net/tokenring/lanstreamer.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/tokenring/lanstreamer.h	Thu Mar  7 18:24:48 2002
@@ -56,11 +56,36 @@
  * 
  *  12/10/99 - Alpha Release 0.1.0
  *            First release to the public
+ *  08/15/01 - Added ioctl() definitions and others - Kent Yoder <yoder1@us.ibm.com>
  *
  */
 
+#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+#include <asm/ioctl.h>
+#define IOCTL_PRINT_RX_BUFS   SIOCDEVPRIVATE
+#define IOCTL_PRINT_TX_BUFS   SIOCDEVPRIVATE+1
+#define IOCTL_RX_CMD          SIOCDEVPRIVATE+2
+#define IOCTL_TX_CMD          SIOCDEVPRIVATE+3
+#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
+#define IOCTL_PRINT_BDAS      SIOCDEVPRIVATE+5
+#define IOCTL_SPIN_LOCK_TEST  SIOCDEVPRIVATE+6
+#define IOCTL_SISR_MASK       SIOCDEVPRIVATE+7
+#endif
+
+/* MAX_INTR - the maximum number of times we can loop
+ * inside the interrupt function before returning
+ * control to the OS (maximum value is 256)
+ */
+#define MAX_INTR 5
+
+#define CLS 0x0C
+#define MLR 0x86
+#define LTR 0x0D
+
 #define BCTL 0x60
 #define BCTL_SOFTRESET (1<<15)
+#define BCTL_RX_FIFO_8 (1<<1)
+#define BCTL_TX_FIFO_8 (1<<3)
 
 #define GPR 0x4a
 #define GPR_AUTOSENSE (1<<2)
@@ -89,6 +114,7 @@
 #define SISR_MASK_RUM 0x58
 
 #define SISR_MI (1<<15)
+#define SISR_SERR_ERR (1<<14)
 #define SISR_TIMER (1<<11)
 #define SISR_LAP_PAR_ERR (1<<10)
 #define SISR_LAP_ACC_ERR (1<<9)
@@ -218,7 +244,13 @@
 /* Streamer defaults for buffers */
 
 #define STREAMER_RX_RING_SIZE 16	/* should be a power of 2 */
-#define STREAMER_TX_RING_SIZE 8	/* should be a power of 2 */
+/* Setting the number of TX descriptors to 1 is a workaround for an
+ * undocumented hardware problem with the lanstreamer board. Setting
+ * this to something higher may slightly increase the throughput you
+ * can get from the card, but at the risk of locking up the box. - 
+ * <yoder1@us.ibm.com>
+ */
+#define STREAMER_TX_RING_SIZE 1	/* should be a power of 2 */
 
 #define PKT_BUF_SZ 4096		/* Default packet size */
 
diff -urN linux-2.5.6-pre3/drivers/net/tulip/ChangeLog linux-2.5.6/drivers/net/tulip/ChangeLog
--- linux-2.5.6-pre3/drivers/net/tulip/ChangeLog	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/tulip/ChangeLog	Thu Mar  7 18:24:48 2002
@@ -1,3 +1,10 @@
+2002-03-07  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* tulip_core (tulip_mwi_config): Use new PCI API functions
+	for enabling and disabled Memory-Write-Invalidate
+	PCI transaction.
+	Fix bugs in tulip MWI config also.
+
 2002-01-28  Stefan Rompf  <srompf@isg.de>,
             Jeff Garzik  <jgarzik@mandrakesoft.com>
 
diff -urN linux-2.5.6-pre3/drivers/net/tulip/Config.help linux-2.5.6/drivers/net/tulip/Config.help
--- linux-2.5.6-pre3/drivers/net/tulip/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/Config.help	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,110 @@
+CONFIG_PCMCIA_XIRCOM
+  This driver is for the Digital "Tulip" Ethernet CardBus adapters.
+  It should work with most DEC 21*4*-based chips/ethercards, as well
+  as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
+  ASIX.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called xircom_cb.o.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>. If unsure, say N.
+
+CONFIG_PCMCIA_XIRTULIP
+  This driver is for the Digital "Tulip" Ethernet CardBus adapters.
+  It should work with most DEC 21*4*-based chips/ethercards, as well
+  as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and
+  ASIX.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called xircom_tulip_cb.o.  If you want to compile
+  it as a module, say M here and read
+  <file:Documentation/modules.txt>. If unsure, say N.
+
+CONFIG_DE2104X
+  This driver is developed for the SMC EtherPower series Ethernet
+  cards and also works with cards based on the DECchip
+  21040 (Tulip series) chips.  Some LinkSys PCI cards are
+  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
+  (smc9332dst), you can also try the driver for "Generic DECchip"
+  cards, above.  However, most people with a network card of this type
+  will say Y here.) Do read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  More specific
+  information is contained in
+  <file:Documentation/DocBook/tulip-user.tmpl>.
+  
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tulip.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_TULIP
+  This driver is developed for the SMC EtherPower series Ethernet
+  cards and also works with cards based on the DECchip 
+  21040/21041/21140 (Tulip series) chips.  Some LinkSys PCI cards are
+  of this type.  (If your card is NOT SMC EtherPower 10/100 PCI
+  (smc9332dst), you can also try the driver for "Generic DECchip"
+  cards, above.  However, most people with a network card of this type
+  will say Y here.) Do read the Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.  More specific
+  information is contained in 
+  <file:Documentation/networking/tulip.txt>.
+  
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tulip.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_TULIP_MWI
+  This configures your Tulip card specifically for the card and
+  system cache line size type you are using.
+  
+  This is experimental code, not yet tested on many boards.
+
+  If unsure, say N.
+
+CONFIG_TULIP_MMIO
+  Use PCI shared memory for the NIC registers, rather than going through
+  the Tulip's PIO (programmed I/O ports).  Faster, but could produce
+  obscure bugs if your mainboard has memory controller timing issues.
+  If in doubt, say N.
+
+CONFIG_NET_TULIP
+  This selects the "Tulip" family of EISA/PCI network cards.
+
+CONFIG_DE4X5
+  This is support for the DIGITAL series of PCI/EISA Ethernet cards.
+  These include the DE425, DE434, DE435, DE450 and DE500 models.  If
+  you have a network card of this type, say Y and read the
+  Ethernet-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>. More specific
+  information is contained in
+  <file:Documentation/networking/de4x5.txt>.
+  
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called de4x5.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
+CONFIG_WINBOND_840
+  This driver is for the Winbond W89c840 chip.  It also works with 
+  the TX9882 chip on the Compex RL100-ATX board.
+  More specific information and updates are available from
+  <http://www.scyld.com/network/drivers.html>.
+
+CONFIG_DM9102
+  This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
+  Davicom (<http://www.davicom.com.tw/>).  If you have such a network
+  (Ethernet) card, say Y.  Some information is contained in the file
+  <file:Documentation/networking/dmfe.txt>.
+  
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called dmfe.o.  If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt> as well
+  as <file:Documentation/networking/net-modules.txt>.
+
diff -urN linux-2.5.6-pre3/drivers/net/tulip/Config.in linux-2.5.6/drivers/net/tulip/Config.in
--- linux-2.5.6-pre3/drivers/net/tulip/Config.in	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/Config.in	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,27 @@
+#
+# Tulip family network device configuration
+#
+
+mainmenu_option next_comment
+comment '"Tulip" family network device support'
+
+bool '"Tulip" family network device support' CONFIG_NET_TULIP
+if [ "$CONFIG_NET_TULIP" = "y" ]; then
+   dep_tristate '    Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)' CONFIG_DE2104X $CONFIG_PCI $CONFIG_EXPERIMENTAL
+   dep_tristate '    DECchip Tulip (dc2114x) PCI support' CONFIG_TULIP $CONFIG_PCI
+   if [ "$CONFIG_TULIP" = "y" -o "$CONFIG_TULIP" = "m" ]; then
+      dep_bool '      New bus configuration (EXPERIMENTAL)' CONFIG_TULIP_MWI $CONFIG_EXPERIMENTAL
+      bool '      Use PCI shared mem for NIC registers' CONFIG_TULIP_MMIO
+   fi
+   if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
+      tristate '    Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
+   fi
+   dep_tristate '    Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI
+   dep_tristate '    Davicom DM910x/DM980x support' CONFIG_DM9102 $CONFIG_PCI
+   if [ "$CONFIG_CARDBUS" = "y" ]; then
+      tristate '  Xircom CardBus support (new driver)' CONFIG_PCMCIA_XIRCOM
+      tristate '  Xircom Tulip-like CardBus support (old driver)' CONFIG_PCMCIA_XIRTULIP
+   fi
+fi
+
+endmenu
diff -urN linux-2.5.6-pre3/drivers/net/tulip/Makefile linux-2.5.6/drivers/net/tulip/Makefile
--- linux-2.5.6-pre3/drivers/net/tulip/Makefile	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/drivers/net/tulip/Makefile	Thu Mar  7 18:24:48 2002
@@ -1,17 +1,36 @@
 #
-# Makefile for the Tulip ethernet driver
+# drivers/net/tulip/Makefile
 #
-# 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).
+# Makefile for the Linux "Tulip" family network device drivers.
 #
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-O_TARGET := tulip.o
+O_TARGET := tulip_net.o
 
-obj-y   := eeprom.o interrupt.o media.o \
-	   timer.o tulip_core.o		\
-	   21142.o pnic.o pnic2.o
-obj-m   := $(O_TARGET)
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Things that need to export symbols
+export-objs	:=
+
+obj-$(CONFIG_PCMCIA_XIRTULIP)	+= xircom_tulip_cb.o
+obj-$(CONFIG_PCMCIA_XIRCOM)	+= xircom_cb.o
+obj-$(CONFIG_DM9102)		+= dmfe.o
+obj-$(CONFIG_WINBOND_840)	+= winbond-840.o
+obj-$(CONFIG_DE2104X)		+= de2104x.o
+obj-$(CONFIG_TULIP)		+= tulip.o
+obj-$(CONFIG_DE4X5)		+= de4x5.o
+
+# Declare multi-part drivers.
+list-multi			:= tulip.o
+
+tulip-objs			:= eeprom.o interrupt.o media.o \
+				   timer.o tulip_core.o		\
+				   21142.o pnic.o pnic2.o
 
 include $(TOPDIR)/Rules.make
+
+# Link rules for multi-part drivers.
+tulip.o: $(tulip-objs)
+	$(LD) -r -o $@ $(tulip-objs)
diff -urN linux-2.5.6-pre3/drivers/net/tulip/de2104x.c linux-2.5.6/drivers/net/tulip/de2104x.c
--- linux-2.5.6-pre3/drivers/net/tulip/de2104x.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/de2104x.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,2240 @@
+/* de2104x.c: A Linux PCI Ethernet driver for Intel/Digital 21040/1 chips. */
+/*
+	Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+	Copyright 1994, 1995 Digital Equipment Corporation.	    [de4x5.c]
+	Written/copyright 1994-2001 by Donald Becker.		    [tulip.c]
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	See the file COPYING in this distribution for more information.
+
+	TODO, in rough priority order:
+	* Support forcing media type with a module parameter,
+	  like dl2k.c/sundance.c
+	* Constants (module parms?) for Rx work limit
+	* Complete reset on PciErr
+	* Jumbo frames / dev->change_mtu
+	* Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
+	* Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
+	* Implement Tx software interrupt mitigation via
+	  Tx descriptor bit
+
+ */
+
+#define DRV_NAME		"de2104x"
+#define DRV_VERSION		"0.5.4"
+#define DRV_RELDATE		"Jan 1, 2002"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/compiler.h>
+#include <linux/sched.h>
+#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __initdata =
+KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static int debug = -1;
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number");
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
+        || defined(__sparc_) || defined(__ia64__) \
+        || defined(__sh__) || defined(__mips__)
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+MODULE_PARM (rx_copybreak, "i");
+MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");
+
+#define PFX			DRV_NAME ": "
+
+#define DE_DEF_MSG_ENABLE	(NETIF_MSG_DRV		| \
+				 NETIF_MSG_PROBE 	| \
+				 NETIF_MSG_LINK		| \
+				 NETIF_MSG_TIMER	| \
+				 NETIF_MSG_IFDOWN	| \
+				 NETIF_MSG_IFUP		| \
+				 NETIF_MSG_RX_ERR	| \
+				 NETIF_MSG_TX_ERR)
+
+#define DE_RX_RING_SIZE		64
+#define DE_TX_RING_SIZE		64
+#define DE_RING_BYTES		\
+		((sizeof(struct de_desc) * DE_RX_RING_SIZE) +	\
+		(sizeof(struct de_desc) * DE_TX_RING_SIZE))
+#define NEXT_TX(N)		(((N) + 1) & (DE_TX_RING_SIZE - 1))
+#define NEXT_RX(N)		(((N) + 1) & (DE_RX_RING_SIZE - 1))
+#define TX_BUFFS_AVAIL(CP)					\
+	(((CP)->tx_tail <= (CP)->tx_head) ?			\
+	  (CP)->tx_tail + (DE_TX_RING_SIZE - 1) - (CP)->tx_head :	\
+	  (CP)->tx_tail - (CP)->tx_head - 1)
+
+#define PKT_BUF_SZ		1536	/* Size of each temporary Rx buffer.*/
+#define RX_OFFSET		2
+
+#define DE_SETUP_SKB		((struct sk_buff *) 1)
+#define DE_DUMMY_SKB		((struct sk_buff *) 2)
+#define DE_SETUP_FRAME_WORDS	96
+#define DE_EEPROM_WORDS		256
+#define DE_EEPROM_SIZE		(DE_EEPROM_WORDS * sizeof(u16))
+#define DE_MAX_MEDIA		5
+
+#define DE_MEDIA_TP_AUTO	0
+#define DE_MEDIA_BNC		1
+#define DE_MEDIA_AUI		2
+#define DE_MEDIA_TP		3
+#define DE_MEDIA_TP_FD		4
+#define DE_MEDIA_INVALID	DE_MAX_MEDIA
+#define DE_MEDIA_FIRST		0
+#define DE_MEDIA_LAST		(DE_MAX_MEDIA - 1)
+#define DE_AUI_BNC		(SUPPORTED_AUI | SUPPORTED_BNC)
+
+#define DE_TIMER_LINK		(60 * HZ)
+#define DE_TIMER_NO_LINK	(5 * HZ)
+
+#define DE_NUM_REGS		16
+#define DE_REGS_SIZE		(DE_NUM_REGS * sizeof(u32))
+#define DE_REGS_VER		1
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT		(6*HZ)
+
+#define DE_UNALIGNED_16(a)	(u16)(get_unaligned((u16 *)(a)))
+
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+   to support a pre-NWay full-duplex signaling mechanism using short frames.
+   No one knows what it should be, but if left at its default value some
+   10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC	0x6969
+
+enum {
+	/* NIC registers */
+	BusMode			= 0x00,
+	TxPoll			= 0x08,
+	RxPoll			= 0x10,
+	RxRingAddr		= 0x18,
+	TxRingAddr		= 0x20,
+	MacStatus		= 0x28,
+	MacMode			= 0x30,
+	IntrMask		= 0x38,
+	RxMissed		= 0x40,
+	ROMCmd			= 0x48,
+	CSR11			= 0x58,
+	SIAStatus		= 0x60,
+	CSR13			= 0x68,
+	CSR14			= 0x70,
+	CSR15			= 0x78,
+	PCIPM			= 0x40,
+
+	/* BusMode bits */
+	CmdReset		= (1 << 0),
+	CacheAlign16		= 0x00008000,
+	BurstLen4		= 0x00000400,
+
+	/* Rx/TxPoll bits */
+	NormalTxPoll		= (1 << 0),
+	NormalRxPoll		= (1 << 0),
+
+	/* Tx/Rx descriptor status bits */
+	DescOwn			= (1 << 31),
+	RxError			= (1 << 15),
+	RxErrLong		= (1 << 7),
+	RxErrCRC		= (1 << 1),
+	RxErrFIFO		= (1 << 0),
+	RxErrRunt		= (1 << 11),
+	RxErrFrame		= (1 << 14),
+	RingEnd			= (1 << 25),
+	FirstFrag		= (1 << 29),
+	LastFrag		= (1 << 30),
+	TxError			= (1 << 15),
+	TxFIFOUnder		= (1 << 1),
+	TxLinkFail		= (1 << 2) | (1 << 10) | (1 << 11),
+	TxMaxCol		= (1 << 8),
+	TxOWC			= (1 << 9),
+	TxJabber		= (1 << 14),
+	SetupFrame		= (1 << 27),
+	TxSwInt			= (1 << 31),
+
+	/* MacStatus bits */
+	IntrOK			= (1 << 16),
+	IntrErr			= (1 << 15),
+	RxIntr			= (1 << 6),
+	RxEmpty			= (1 << 7),
+	TxIntr			= (1 << 0),
+	TxEmpty			= (1 << 2),
+	PciErr			= (1 << 13),
+	TxState			= (1 << 22) | (1 << 21) | (1 << 20),
+	RxState			= (1 << 19) | (1 << 18) | (1 << 17),
+	LinkFail		= (1 << 12),
+	LinkPass		= (1 << 4),
+	RxStopped		= (1 << 8),
+	TxStopped		= (1 << 1),
+
+	/* MacMode bits */
+	TxEnable		= (1 << 13),
+	RxEnable		= (1 << 1),
+	RxTx			= TxEnable | RxEnable,
+	FullDuplex		= (1 << 9),
+	AcceptAllMulticast	= (1 << 7),
+	AcceptAllPhys		= (1 << 6),
+	BOCnt			= (1 << 5),
+	MacModeClear		= (1<<12) | (1<<11) | (1<<10) | (1<<8) | (1<<3) |
+				  RxTx | BOCnt | AcceptAllPhys | AcceptAllMulticast,
+
+	/* ROMCmd bits */
+	EE_SHIFT_CLK		= 0x02,	/* EEPROM shift clock. */
+	EE_CS			= 0x01,	/* EEPROM chip select. */
+	EE_DATA_WRITE		= 0x04,	/* Data from the Tulip to EEPROM. */
+	EE_WRITE_0		= 0x01,
+	EE_WRITE_1		= 0x05,
+	EE_DATA_READ		= 0x08,	/* Data from the EEPROM chip. */
+	EE_ENB			= (0x4800 | EE_CS),
+
+	/* The EEPROM commands include the alway-set leading bit. */
+	EE_READ_CMD		= 6,
+
+	/* RxMissed bits */
+	RxMissedOver		= (1 << 16),
+	RxMissedMask		= 0xffff,
+
+	/* SROM-related bits */
+	SROMC0InfoLeaf		= 27,
+	MediaBlockMask		= 0x3f,
+	MediaCustomCSRs		= (1 << 6),
+	
+	/* PCIPM bits */
+	PM_Sleep		= (1 << 31),
+	PM_Snooze		= (1 << 30),
+	PM_Mask			= PM_Sleep | PM_Snooze,
+	
+	/* SIAStatus bits */
+	NWayState		= (1 << 14) | (1 << 13) | (1 << 12),
+	NWayRestart		= (1 << 12),
+	NonselPortActive	= (1 << 9),
+	LinkFailStatus		= (1 << 2),
+	NetCxnErr		= (1 << 1),
+};
+
+static const u32 de_intr_mask =
+	IntrOK | IntrErr | RxIntr | RxEmpty | TxIntr | TxEmpty |
+	LinkPass | LinkFail | PciErr;
+
+/*
+ * Set the programmable burst length to 4 longwords for all:
+ * DMA errors result without these values. Cache align 16 long.
+ */
+static const u32 de_bus_mode = CacheAlign16 | BurstLen4;
+
+struct de_srom_media_block {
+	u8			opts;
+	u16			csr13;
+	u16			csr14;
+	u16			csr15;
+} __attribute__((packed));
+
+struct de_srom_info_leaf {
+	u16			default_media;
+	u8			n_blocks;
+	u8			unused;
+} __attribute__((packed));
+
+struct de_desc {
+	u32			opts1;
+	u32			opts2;
+	u32			addr1;
+	u32			addr2;
+};
+
+struct media_info {
+	u16			type;	/* DE_MEDIA_xxx */
+	u16			csr13;
+	u16			csr14;
+	u16			csr15;
+};
+
+struct ring_info {
+	struct sk_buff		*skb;
+	dma_addr_t		mapping;
+};
+
+struct de_private {
+	unsigned		tx_head;
+	unsigned		tx_tail;
+	unsigned		rx_tail;
+
+	void			*regs;
+	struct net_device	*dev;
+	spinlock_t		lock;
+
+	struct de_desc		*rx_ring;
+	struct de_desc		*tx_ring;
+	struct ring_info	tx_skb[DE_TX_RING_SIZE];
+	struct ring_info	rx_skb[DE_RX_RING_SIZE];
+	unsigned		rx_buf_sz;
+	dma_addr_t		ring_dma;
+
+	u32			msg_enable;
+
+	struct net_device_stats net_stats;
+
+	struct pci_dev		*pdev;
+	u32			macmode;
+
+	u16			setup_frame[DE_SETUP_FRAME_WORDS];
+
+	u32			media_type;
+	u32			media_supported;
+	u32			media_advertise;
+	struct media_info	media[DE_MAX_MEDIA];
+	struct timer_list	media_timer;
+
+	u8			*ee_data;
+	unsigned		board_idx;
+	unsigned		de21040 : 1;
+	unsigned		media_lock : 1;
+};
+
+
+static void de_set_rx_mode (struct net_device *dev);
+static void de_tx (struct de_private *de);
+static void de_clean_rings (struct de_private *de);
+static void de_media_interrupt (struct de_private *de, u32 status);
+static void de21040_media_timer (unsigned long data);
+static void de21041_media_timer (unsigned long data);
+static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media);
+
+
+static struct pci_device_id de_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_PLUS,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ },
+};
+MODULE_DEVICE_TABLE(pci, de_pci_tbl);
+
+static const char * const media_name[DE_MAX_MEDIA] = {
+	"10baseT auto",
+	"BNC",
+	"AUI",
+	"10baseT-HD",
+	"10baseT-FD"
+};
+
+/* 21040 transceiver register settings:
+ * TP AUTO(unused), BNC(unused), AUI, TP, TP FD*/
+static u16 t21040_csr13[] = { 0, 0, 0x8F09, 0x8F01, 0x8F01, };
+static u16 t21040_csr14[] = { 0, 0, 0x0705, 0xFFFF, 0xFFFD, };
+static u16 t21040_csr15[] = { 0, 0, 0x0006, 0x0000, 0x0000, };
+
+/* 21041 transceiver register settings: TP AUTO, BNC, AUI, TP, TP FD*/
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x6F3F, 0x6F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+
+static inline unsigned long
+msec_to_jiffies(unsigned long ms)
+{
+	return (((ms)*HZ+999)/1000);
+}
+
+
+#define dr32(reg)		readl(de->regs + (reg))
+#define dw32(reg,val)		writel((val), de->regs + (reg))
+
+
+static void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
+			    u32 status, u32 len)
+{
+	if (netif_msg_rx_err (de))
+		printk (KERN_DEBUG
+			"%s: rx err, slot %d status 0x%x len %d\n",
+			de->dev->name, rx_tail, status, len);
+
+	if ((status & 0x38000300) != 0x0300) {
+		/* Ingore earlier buffers. */
+		if ((status & 0xffff) != 0x7fff) {
+			if (netif_msg_rx_err(de))
+				printk(KERN_WARNING "%s: Oversized Ethernet frame "
+					   "spanned multiple buffers, status %8.8x!\n",
+					   de->dev->name, status);
+			de->net_stats.rx_length_errors++;
+		}
+	} else if (status & RxError) {
+		/* There was a fatal error. */
+		de->net_stats.rx_errors++; /* end of a packet.*/
+		if (status & 0x0890) de->net_stats.rx_length_errors++;
+		if (status & RxErrCRC) de->net_stats.rx_crc_errors++;
+		if (status & RxErrFIFO) de->net_stats.rx_fifo_errors++;
+	}
+}
+
+static void de_rx (struct de_private *de)
+{
+	unsigned rx_tail = de->rx_tail;
+	unsigned rx_work = DE_RX_RING_SIZE;
+	unsigned drop = 0;
+	int rc;
+
+	while (rx_work--) {
+		u32 status, len;
+		dma_addr_t mapping;
+		struct sk_buff *skb, *copy_skb;
+		unsigned copying_skb, buflen;
+
+		skb = de->rx_skb[rx_tail].skb;
+		if (!skb)
+			BUG();
+		rmb();
+		status = le32_to_cpu(de->rx_ring[rx_tail].opts1);
+		if (status & DescOwn)
+			break;
+
+		len = ((status >> 16) & 0x7ff) - 4;
+		mapping = de->rx_skb[rx_tail].mapping;
+
+		if (unlikely(drop)) {
+			de->net_stats.rx_dropped++;
+			goto rx_next;
+		}
+
+		if (unlikely((status & 0x38008300) != 0x0300)) {
+			de_rx_err_acct(de, rx_tail, status, len);
+			goto rx_next;
+		}
+
+		copying_skb = (len <= rx_copybreak);
+
+		if (unlikely(netif_msg_rx_status(de)))
+			printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
+			       de->dev->name, rx_tail, status, len,
+			       copying_skb);
+
+		buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz;
+		copy_skb = dev_alloc_skb (buflen);
+		if (unlikely(!copy_skb)) {
+			de->net_stats.rx_dropped++;
+			drop = 1;
+			rx_work = 100;
+			goto rx_next;
+		}
+		copy_skb->dev = de->dev;
+
+		if (!copying_skb) {
+			pci_unmap_single(de->pdev, mapping,
+					 buflen, PCI_DMA_FROMDEVICE);
+			skb_put(skb, len);
+
+			mapping =
+			de->rx_skb[rx_tail].mapping =
+				pci_map_single(de->pdev, copy_skb->tail,
+					       buflen, PCI_DMA_FROMDEVICE);
+			de->rx_skb[rx_tail].skb = copy_skb;
+		} else {
+			pci_dma_sync_single(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
+			skb_reserve(copy_skb, RX_OFFSET);
+			memcpy(skb_put(copy_skb, len), skb->tail, len);
+
+			/* We'll reuse the original ring buffer. */
+			skb = copy_skb;
+		}
+
+		skb->protocol = eth_type_trans (skb, de->dev);
+
+		de->net_stats.rx_packets++;
+		de->net_stats.rx_bytes += skb->len;
+		de->dev->last_rx = jiffies;
+		rc = netif_rx (skb);
+		if (rc == NET_RX_DROP)
+			drop = 1;
+
+rx_next:
+		de->rx_ring[rx_tail].opts1 = cpu_to_le32(DescOwn);
+		if (rx_tail == (DE_RX_RING_SIZE - 1))
+			de->rx_ring[rx_tail].opts2 =
+				cpu_to_le32(RingEnd | de->rx_buf_sz);
+		else
+			de->rx_ring[rx_tail].opts2 = cpu_to_le32(de->rx_buf_sz);
+		de->rx_ring[rx_tail].addr1 = cpu_to_le32(mapping);
+		rx_tail = NEXT_RX(rx_tail);
+	}
+
+	if (!rx_work)
+		printk(KERN_WARNING "%s: rx work limit reached\n", de->dev->name);
+
+	de->rx_tail = rx_tail;
+}
+
+static void de_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct de_private *de = dev->priv;
+	u32 status;
+
+	status = dr32(MacStatus);
+	if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF))
+		return;
+
+	if (netif_msg_intr(de))
+		printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n",
+		        dev->name, status, dr32(MacMode), de->rx_tail, de->tx_head, de->tx_tail);
+
+	dw32(MacStatus, status);
+
+	if (status & (RxIntr | RxEmpty)) {
+		de_rx(de);
+		if (status & RxEmpty)
+			dw32(RxPoll, NormalRxPoll);
+	}
+
+	spin_lock(&de->lock);
+
+	if (status & (TxIntr | TxEmpty))
+		de_tx(de);
+
+	if (status & (LinkPass | LinkFail))
+		de_media_interrupt(de, status);
+
+	spin_unlock(&de->lock);
+
+	if (status & PciErr) {
+		u16 pci_status;
+
+		pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
+		pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
+		printk(KERN_ERR "%s: PCI bus error, status=%08x, PCI status=%04x\n",
+		       dev->name, status, pci_status);
+	}
+}
+
+static void de_tx (struct de_private *de)
+{
+	unsigned tx_head = de->tx_head;
+	unsigned tx_tail = de->tx_tail;
+
+	while (tx_tail != tx_head) {
+		struct sk_buff *skb;
+		u32 status;
+
+		rmb();
+		status = le32_to_cpu(de->tx_ring[tx_tail].opts1);
+		if (status & DescOwn)
+			break;
+
+		skb = de->tx_skb[tx_tail].skb;
+		if (!skb)
+			BUG();
+		if (unlikely(skb == DE_DUMMY_SKB))
+			goto next;
+
+		if (unlikely(skb == DE_SETUP_SKB)) {
+			pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
+					 sizeof(de->setup_frame), PCI_DMA_TODEVICE);
+			goto next;
+		}
+
+		pci_unmap_single(de->pdev, de->tx_skb[tx_tail].mapping,
+				 skb->len, PCI_DMA_TODEVICE);
+
+		if (status & LastFrag) {
+			if (status & TxError) {
+				if (netif_msg_tx_err(de))
+					printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
+					       de->dev->name, status);
+				de->net_stats.tx_errors++;
+				if (status & TxOWC)
+					de->net_stats.tx_window_errors++;
+				if (status & TxMaxCol)
+					de->net_stats.tx_aborted_errors++;
+				if (status & TxLinkFail)
+					de->net_stats.tx_carrier_errors++;
+				if (status & TxFIFOUnder)
+					de->net_stats.tx_fifo_errors++;
+			} else {
+				de->net_stats.tx_packets++;
+				de->net_stats.tx_bytes += skb->len;
+				if (netif_msg_tx_done(de))
+					printk(KERN_DEBUG "%s: tx done, slot %d\n", de->dev->name, tx_tail);
+			}
+			dev_kfree_skb_irq(skb);
+		}
+
+next:
+		de->tx_skb[tx_tail].skb = NULL;
+
+		tx_tail = NEXT_TX(tx_tail);
+	}
+
+	de->tx_tail = tx_tail;
+
+	if (netif_queue_stopped(de->dev) && (TX_BUFFS_AVAIL(de) > (DE_TX_RING_SIZE / 4)))
+		netif_wake_queue(de->dev);
+}
+
+static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	unsigned int entry, tx_free;
+	u32 mapping, len, flags = FirstFrag | LastFrag;
+	struct de_desc *txd;
+
+	spin_lock_irq(&de->lock);
+
+	tx_free = TX_BUFFS_AVAIL(de);
+	if (tx_free == 0) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&de->lock);
+		return 1;
+	}
+	tx_free--;
+
+	entry = de->tx_head;
+
+	txd = &de->tx_ring[entry];
+
+	len = skb->len;
+	mapping = pci_map_single(de->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	if (entry == (DE_TX_RING_SIZE - 1))
+		flags |= RingEnd;
+	if (!tx_free || (tx_free == (DE_TX_RING_SIZE / 2)))
+		flags |= TxSwInt;
+	flags |= len;
+	txd->opts2 = cpu_to_le32(flags);
+	txd->addr1 = cpu_to_le32(mapping);
+
+	de->tx_skb[entry].skb = skb;
+	de->tx_skb[entry].mapping = mapping;
+	wmb();
+
+	txd->opts1 = cpu_to_le32(DescOwn);
+	wmb();
+
+	de->tx_head = NEXT_TX(entry);
+	if (netif_msg_tx_queued(de))
+		printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+		       dev->name, entry, skb->len);
+
+	if (tx_free == 0)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&de->lock);
+
+	/* Trigger an immediate transmit demand. */
+	dw32(TxPoll, NormalTxPoll);
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling de->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+#undef set_bit_le
+#define set_bit_le(i,p) do { ((char *)(p))[(i)/8] |= (1<<((i)%8)); } while(0)
+
+static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	u16 hash_table[32];
+	struct dev_mc_list *mclist;
+	int i;
+	u16 *eaddrs;
+
+	memset(hash_table, 0, sizeof(hash_table));
+	set_bit_le(255, hash_table); 			/* Broadcast entry */
+	/* This should work on big-endian machines as well. */
+	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+	     i++, mclist = mclist->next) {
+		int index = ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
+
+		set_bit_le(index, hash_table);
+
+		for (i = 0; i < 32; i++) {
+			*setup_frm++ = hash_table[i];
+			*setup_frm++ = hash_table[i];
+		}
+		setup_frm = &de->setup_frame[13*6];
+	}
+
+	/* Fill the final entry with our physical address. */
+	eaddrs = (u16 *)dev->dev_addr;
+	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+}
+
+static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	struct dev_mc_list *mclist;
+	int i;
+	u16 *eaddrs;
+
+	/* We have <= 14 addresses so we can use the wonderful
+	   16 address perfect filtering of the Tulip. */
+	for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+	     i++, mclist = mclist->next) {
+		eaddrs = (u16 *)mclist->dmi_addr;
+		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+		*setup_frm++ = *eaddrs; *setup_frm++ = *eaddrs++;
+	}
+	/* Fill the unused entries with the broadcast address. */
+	memset(setup_frm, 0xff, (15-i)*12);
+	setup_frm = &de->setup_frame[15*6];
+
+	/* Fill the final entry with our physical address. */
+	eaddrs = (u16 *)dev->dev_addr;
+	*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+	*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+	*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+}
+
+
+static void __de_set_rx_mode (struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	u32 macmode;
+	unsigned int entry;
+	u32 mapping;
+	struct de_desc *txd;
+	struct de_desc *dummy_txd = NULL;
+
+	macmode = de->macmode & ~(AcceptAllMulticast | AcceptAllPhys);
+
+	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
+		macmode |= AcceptAllMulticast | AcceptAllPhys;
+		goto out;
+	}
+
+	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter well -- accept all multicasts. */
+		macmode |= AcceptAllMulticast;
+		goto out;
+	}
+
+	/* Note that only the low-address shortword of setup_frame is valid!
+	   The values are doubled for big-endian architectures. */
+	if (dev->mc_count > 14)	/* Must use a multicast hash table. */
+		build_setup_frame_hash (de->setup_frame, dev);
+	else
+		build_setup_frame_perfect (de->setup_frame, dev);
+
+	/*
+	 * Now add this frame to the Tx list.
+	 */
+
+	entry = de->tx_head;
+
+	/* Avoid a chip errata by prefixing a dummy entry. */
+	if (entry != 0) {
+		de->tx_skb[entry].skb = DE_DUMMY_SKB;
+
+		dummy_txd = &de->tx_ring[entry];
+		dummy_txd->opts2 = (entry == (DE_TX_RING_SIZE - 1)) ?
+				   cpu_to_le32(RingEnd) : 0;
+		dummy_txd->addr1 = 0;
+
+		/* Must set DescOwned later to avoid race with chip */
+
+		entry = NEXT_TX(entry);
+	}
+
+	de->tx_skb[entry].skb = DE_SETUP_SKB;
+	de->tx_skb[entry].mapping = mapping =
+	    pci_map_single (de->pdev, de->setup_frame,
+			    sizeof (de->setup_frame), PCI_DMA_TODEVICE);
+
+	/* Put the setup frame on the Tx list. */
+	txd = &de->tx_ring[entry];
+	if (entry == (DE_TX_RING_SIZE - 1))
+		txd->opts2 = cpu_to_le32(SetupFrame | RingEnd | sizeof (de->setup_frame));
+	else
+		txd->opts2 = cpu_to_le32(SetupFrame | sizeof (de->setup_frame));
+	txd->addr1 = cpu_to_le32(mapping);
+	wmb();
+
+	txd->opts1 = cpu_to_le32(DescOwn);
+	wmb();
+
+	if (dummy_txd) {
+		dummy_txd->opts1 = cpu_to_le32(DescOwn);
+		wmb();
+	}
+
+	de->tx_head = NEXT_TX(entry);
+
+	if (TX_BUFFS_AVAIL(de) < 0)
+		BUG();
+	if (TX_BUFFS_AVAIL(de) == 0)
+		netif_stop_queue(dev);
+
+	/* Trigger an immediate transmit demand. */
+	dw32(TxPoll, NormalTxPoll);
+
+out:
+	if (macmode != de->macmode) {
+		dw32 (MacMode, macmode);
+		de->macmode = macmode;
+	}
+}
+
+static void de_set_rx_mode (struct net_device *dev)
+{
+	unsigned long flags;
+	struct de_private *de = dev->priv;
+
+	spin_lock_irqsave (&de->lock, flags);
+	__de_set_rx_mode(dev);
+	spin_unlock_irqrestore (&de->lock, flags);
+}
+
+static inline void de_rx_missed(struct de_private *de, u32 rx_missed)
+{
+	if (unlikely(rx_missed & RxMissedOver))
+		de->net_stats.rx_missed_errors += RxMissedMask;
+	else
+		de->net_stats.rx_missed_errors += (rx_missed & RxMissedMask);
+}
+
+static void __de_get_stats(struct de_private *de)
+{
+	u32 tmp = dr32(RxMissed); /* self-clearing */
+
+	de_rx_missed(de, tmp);
+}
+
+static struct net_device_stats *de_get_stats(struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+
+	/* The chip only need report frame silently dropped. */
+	spin_lock_irq(&de->lock);
+ 	if (netif_running(dev) && netif_device_present(dev))
+ 		__de_get_stats(de);
+	spin_unlock_irq(&de->lock);
+
+	return &de->net_stats;
+}
+
+static inline int de_is_running (struct de_private *de)
+{
+	return (dr32(MacStatus) & (RxState | TxState)) ? 1 : 0;
+}
+
+static void de_stop_rxtx (struct de_private *de)
+{
+	u32 macmode;
+	unsigned int work = 1000;
+
+	macmode = dr32(MacMode);
+	if (macmode & RxTx) {
+		dw32(MacMode, macmode & ~RxTx);
+		dr32(MacMode);
+	}
+
+	while (--work > 0) {
+		if (!de_is_running(de))
+			return;
+		cpu_relax();
+	}
+	
+	printk(KERN_WARNING "%s: timeout expired stopping DMA\n", de->dev->name);
+}
+
+static inline void de_start_rxtx (struct de_private *de)
+{
+	u32 macmode;
+
+	macmode = dr32(MacMode);
+	if ((macmode & RxTx) != RxTx) {
+		dw32(MacMode, macmode | RxTx);
+		dr32(MacMode);
+	}
+}
+
+static void de_stop_hw (struct de_private *de)
+{
+
+	udelay(5);
+	dw32(IntrMask, 0);
+
+	de_stop_rxtx(de);
+
+	dw32(MacStatus, dr32(MacStatus));
+
+	udelay(10);
+
+	de->rx_tail = 0;
+	de->tx_head = de->tx_tail = 0;
+}
+
+static void de_link_up(struct de_private *de)
+{
+	if (!netif_carrier_ok(de->dev)) {
+		netif_carrier_on(de->dev);
+		if (netif_msg_link(de))
+			printk(KERN_INFO "%s: link up, media %s\n",
+			       de->dev->name, media_name[de->media_type]);
+	}
+}
+
+static void de_link_down(struct de_private *de)
+{
+	if (netif_carrier_ok(de->dev)) {
+		netif_carrier_off(de->dev);
+		if (netif_msg_link(de))
+			printk(KERN_INFO "%s: link down\n", de->dev->name);
+	}
+}
+
+static void de_set_media (struct de_private *de)
+{
+	unsigned media = de->media_type;
+
+	if (de_is_running(de))
+		BUG();
+
+	if (de->de21040)
+		dw32(CSR11, FULL_DUPLEX_MAGIC);
+	dw32(CSR13, 0); /* Reset phy */
+	dw32(CSR14, de->media[media].csr14);
+	dw32(CSR15, de->media[media].csr15);
+	dw32(CSR13, de->media[media].csr13);
+
+	/* must delay 10ms before writing to other registers,
+	 * especially CSR6
+	 */
+	mdelay(10);
+
+	if (media == DE_MEDIA_TP_FD)
+		de->macmode |= FullDuplex;
+	else
+		de->macmode &= ~FullDuplex;
+	
+	if (netif_msg_link(de)) {
+		printk(KERN_INFO "%s: set link %s\n"
+		       KERN_INFO "%s:    mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n"
+		       KERN_INFO "%s:    set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
+		       de->dev->name, media_name[media],
+		       de->dev->name, dr32(MacMode), dr32(SIAStatus),
+		       dr32(CSR13), dr32(CSR14), dr32(CSR15),
+		       de->dev->name, de->macmode, de->media[media].csr13,
+		       de->media[media].csr14, de->media[media].csr15);
+	}
+}
+
+static void de_next_media (struct de_private *de, u32 *media,
+			   unsigned int n_media)
+{
+	unsigned int i;
+
+	for (i = 0; i < n_media; i++) {
+		if (de_ok_to_advertise(de, media[i])) {
+			de->media_type = media[i];
+			return;
+		}
+	}
+}
+
+static void de21040_media_timer (unsigned long data)
+{
+	struct de_private *de = (struct de_private *) data;
+	struct net_device *dev = de->dev;
+	u32 status = dr32(SIAStatus);
+	unsigned int carrier;
+	unsigned long flags;
+	
+	carrier = (status & NetCxnErr) ? 0 : 1;
+		
+	if (carrier) {
+		if (de->media_type != DE_MEDIA_AUI && (status & LinkFailStatus))
+			goto no_link_yet;
+
+		de->media_timer.expires = jiffies + DE_TIMER_LINK;
+		add_timer(&de->media_timer);
+		if (!netif_carrier_ok(dev))
+			de_link_up(de);
+		else
+			if (netif_msg_timer(de))
+				printk(KERN_INFO "%s: %s link ok, status %x\n",
+				       dev->name, media_name[de->media_type],
+				       status);
+		return;
+	}
+
+	de_link_down(de);	
+
+	if (de->media_lock)
+		return;
+
+	if (de->media_type == DE_MEDIA_AUI) {
+		u32 next_state = DE_MEDIA_TP;
+		de_next_media(de, &next_state, 1);
+	} else {
+		u32 next_state = DE_MEDIA_AUI;
+		de_next_media(de, &next_state, 1);
+	}
+
+	spin_lock_irqsave(&de->lock, flags);
+	de_stop_rxtx(de);
+	spin_unlock_irqrestore(&de->lock, flags);
+	de_set_media(de);
+	de_start_rxtx(de);
+
+no_link_yet:
+	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
+	add_timer(&de->media_timer);
+
+	if (netif_msg_timer(de))
+		printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
+		       dev->name, media_name[de->media_type], status);
+}
+
+static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
+{
+	switch (new_media) {
+	case DE_MEDIA_TP_AUTO:
+		if (!(de->media_advertise & ADVERTISED_Autoneg))
+			return 0;
+		if (!(de->media_advertise & (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full)))
+			return 0;
+		break;
+	case DE_MEDIA_BNC:
+		if (!(de->media_advertise & ADVERTISED_BNC))
+			return 0;
+		break;
+	case DE_MEDIA_AUI:
+		if (!(de->media_advertise & ADVERTISED_AUI))
+			return 0;
+		break;
+	case DE_MEDIA_TP:
+		if (!(de->media_advertise & ADVERTISED_10baseT_Half))
+			return 0;
+		break;
+	case DE_MEDIA_TP_FD:
+		if (!(de->media_advertise & ADVERTISED_10baseT_Full))
+			return 0;
+		break;
+	}
+	
+	return 1;
+}
+
+static void de21041_media_timer (unsigned long data)
+{
+	struct de_private *de = (struct de_private *) data;
+	struct net_device *dev = de->dev;
+	u32 status = dr32(SIAStatus);
+	unsigned int carrier;
+	unsigned long flags;
+	
+	carrier = (status & NetCxnErr) ? 0 : 1;
+		
+	if (carrier) {
+		if ((de->media_type == DE_MEDIA_TP_AUTO ||
+		     de->media_type == DE_MEDIA_TP ||
+		     de->media_type == DE_MEDIA_TP_FD) &&
+		    (status & LinkFailStatus))
+			goto no_link_yet;
+
+		de->media_timer.expires = jiffies + DE_TIMER_LINK;
+		add_timer(&de->media_timer);
+		if (!netif_carrier_ok(dev))
+			de_link_up(de);
+		else
+			if (netif_msg_timer(de))
+				printk(KERN_INFO "%s: %s link ok, mode %x status %x\n",
+				       dev->name, media_name[de->media_type],
+				       dr32(MacMode), status);
+		return;
+	}
+
+	de_link_down(de);	
+
+	/* if media type locked, don't switch media */
+	if (de->media_lock)
+		goto set_media;
+
+	/* if activity detected, use that as hint for new media type */
+	if (status & NonselPortActive) {
+		unsigned int have_media = 1;
+
+		/* if AUI/BNC selected, then activity is on TP port */
+		if (de->media_type == DE_MEDIA_AUI ||
+		    de->media_type == DE_MEDIA_BNC) {
+			if (de_ok_to_advertise(de, DE_MEDIA_TP_AUTO))
+				de->media_type = DE_MEDIA_TP_AUTO;
+			else
+				have_media = 0;
+		}
+
+		/* TP selected.  If there is only TP and BNC, then it's BNC */
+		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_BNC) &&
+			 de_ok_to_advertise(de, DE_MEDIA_BNC))
+			de->media_type = DE_MEDIA_BNC;
+
+		/* TP selected.  If there is only TP and AUI, then it's AUI */
+		else if (((de->media_supported & DE_AUI_BNC) == SUPPORTED_AUI) &&
+			 de_ok_to_advertise(de, DE_MEDIA_AUI))
+			de->media_type = DE_MEDIA_AUI;
+
+		/* otherwise, ignore the hint */
+		else
+			have_media = 0;
+
+		if (have_media)
+			goto set_media;
+	}
+
+	/*
+	 * Absent or ambiguous activity hint, move to next advertised
+	 * media state.  If de->media_type is left unchanged, this
+	 * simply resets the PHY and reloads the current media settings.
+	 */
+	if (de->media_type == DE_MEDIA_AUI) {
+		u32 next_states[] = { DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	} else if (de->media_type == DE_MEDIA_BNC) {
+		u32 next_states[] = { DE_MEDIA_TP_AUTO, DE_MEDIA_AUI };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	} else {
+		u32 next_states[] = { DE_MEDIA_AUI, DE_MEDIA_BNC, DE_MEDIA_TP_AUTO };
+		de_next_media(de, next_states, ARRAY_SIZE(next_states));
+	}
+	
+set_media:
+	spin_lock_irqsave(&de->lock, flags);
+	de_stop_rxtx(de);
+	spin_unlock_irqrestore(&de->lock, flags);
+	de_set_media(de);
+	de_start_rxtx(de);
+
+no_link_yet:
+	de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
+	add_timer(&de->media_timer);
+
+	if (netif_msg_timer(de))
+		printk(KERN_INFO "%s: no link, trying media %s, status %x\n",
+		       dev->name, media_name[de->media_type], status);
+}
+
+static void de_media_interrupt (struct de_private *de, u32 status)
+{
+	if (status & LinkPass) {
+		de_link_up(de);
+		mod_timer(&de->media_timer, jiffies + DE_TIMER_LINK);
+		return;
+	}
+	
+	if (!(status & LinkFail))
+		BUG();
+
+	if (netif_carrier_ok(de->dev)) {
+		de_link_down(de);
+		mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
+	}
+}
+
+static int de_reset_mac (struct de_private *de)
+{
+	u32 status, tmp;
+
+	/*
+	 * Reset MAC.  Copied from de4x5.c.
+	 */
+
+	tmp = dr32 (BusMode);
+	if (tmp == 0xffffffff)
+		return -ENODEV;
+	mdelay (1);
+
+	dw32 (BusMode, tmp | CmdReset);
+	mdelay (1);
+
+	dw32 (BusMode, tmp);
+	mdelay (1);
+
+	for (tmp = 0; tmp < 5; tmp++) {
+		dr32 (BusMode);
+		mdelay (1);
+	}
+
+	mdelay (1);
+
+	status = dr32(MacStatus);
+	if (status & (RxState | TxState))
+		return -EBUSY;
+	if (status == 0xffffffff)
+		return -ENODEV;
+	return 0;
+}
+
+static void de_adapter_wake (struct de_private *de)
+{
+	u32 pmctl;
+
+	if (de->de21040)
+		return;
+
+	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
+	if (pmctl & PM_Mask) {
+		pmctl &= ~PM_Mask;
+		pci_write_config_dword(de->pdev, PCIPM, pmctl);
+
+		/* de4x5.c delays, so we do too */
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(msec_to_jiffies(10));
+	}
+}
+
+static void de_adapter_sleep (struct de_private *de)
+{
+	u32 pmctl;
+
+	if (de->de21040)
+		return;
+
+	pci_read_config_dword(de->pdev, PCIPM, &pmctl);
+	pmctl |= PM_Sleep;
+	pci_write_config_dword(de->pdev, PCIPM, pmctl);
+}
+
+static int de_init_hw (struct de_private *de)
+{
+	struct net_device *dev = de->dev;
+	int rc;
+
+	de_adapter_wake(de);
+	
+	de->macmode = dr32(MacMode) & ~MacModeClear;
+
+	rc = de_reset_mac(de);
+	if (rc)
+		return rc;
+
+	de_set_media(de); /* reset phy */
+
+	dw32(RxRingAddr, de->ring_dma);
+	dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
+
+	dw32(MacMode, RxTx | de->macmode);
+
+	dr32(RxMissed); /* self-clearing */
+
+	dw32(IntrMask, de_intr_mask);
+
+	de_set_rx_mode(dev);
+
+	return 0;
+}
+
+static int de_refill_rx (struct de_private *de)
+{
+	unsigned i;
+
+	for (i = 0; i < DE_RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+
+		skb = dev_alloc_skb(de->rx_buf_sz);
+		if (!skb)
+			goto err_out;
+
+		skb->dev = de->dev;
+
+		de->rx_skb[i].mapping = pci_map_single(de->pdev,
+			skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		de->rx_skb[i].skb = skb;
+
+		de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
+		if (i == (DE_RX_RING_SIZE - 1))
+			de->rx_ring[i].opts2 =
+				cpu_to_le32(RingEnd | de->rx_buf_sz);
+		else
+			de->rx_ring[i].opts2 = cpu_to_le32(de->rx_buf_sz);
+		de->rx_ring[i].addr1 = cpu_to_le32(de->rx_skb[i].mapping);
+		de->rx_ring[i].addr2 = 0;
+	}
+
+	return 0;
+
+err_out:
+	de_clean_rings(de);
+	return -ENOMEM;
+}
+
+static int de_init_rings (struct de_private *de)
+{
+	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
+	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
+
+	de->rx_tail = 0;
+	de->tx_head = de->tx_tail = 0;
+
+	return de_refill_rx (de);
+}
+
+static int de_alloc_rings (struct de_private *de)
+{
+	de->rx_ring = pci_alloc_consistent(de->pdev, DE_RING_BYTES, &de->ring_dma);
+	if (!de->rx_ring)
+		return -ENOMEM;
+	de->tx_ring = &de->rx_ring[DE_RX_RING_SIZE];
+	return de_init_rings(de);
+}
+
+static void de_clean_rings (struct de_private *de)
+{
+	unsigned i;
+
+	memset(de->rx_ring, 0, sizeof(struct de_desc) * DE_RX_RING_SIZE);
+	de->rx_ring[DE_RX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
+	wmb();
+	memset(de->tx_ring, 0, sizeof(struct de_desc) * DE_TX_RING_SIZE);
+	de->tx_ring[DE_TX_RING_SIZE - 1].opts2 = cpu_to_le32(RingEnd);
+	wmb();
+
+	for (i = 0; i < DE_RX_RING_SIZE; i++) {
+		if (de->rx_skb[i].skb) {
+			pci_unmap_single(de->pdev, de->rx_skb[i].mapping,
+					 de->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(de->rx_skb[i].skb);
+		}
+	}
+
+	for (i = 0; i < DE_TX_RING_SIZE; i++) {
+		struct sk_buff *skb = de->tx_skb[i].skb;
+		if ((skb) && (skb != DE_DUMMY_SKB)) {
+			if (skb != DE_SETUP_SKB) {
+				dev_kfree_skb(skb);
+				de->net_stats.tx_dropped++;
+				pci_unmap_single(de->pdev,
+					de->tx_skb[i].mapping,
+					skb->len, PCI_DMA_TODEVICE);
+			} else {
+				pci_unmap_single(de->pdev,
+					de->tx_skb[i].mapping,
+					sizeof(de->setup_frame),
+					PCI_DMA_TODEVICE);
+			}
+		}
+	}
+
+	memset(&de->rx_skb, 0, sizeof(struct ring_info) * DE_RX_RING_SIZE);
+	memset(&de->tx_skb, 0, sizeof(struct ring_info) * DE_TX_RING_SIZE);
+}
+
+static void de_free_rings (struct de_private *de)
+{
+	de_clean_rings(de);
+	pci_free_consistent(de->pdev, DE_RING_BYTES, de->rx_ring, de->ring_dma);
+	de->rx_ring = NULL;
+	de->tx_ring = NULL;
+}
+
+static int de_open (struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	int rc;
+	unsigned long flags;
+
+	if (netif_msg_ifup(de))
+		printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
+
+	de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	rc = de_alloc_rings(de);
+	if (rc) {
+		printk(KERN_ERR "%s: ring allocation failure, err=%d\n",
+		       dev->name, rc);
+		return rc;
+	}
+
+	rc = de_init_hw(de);
+	if (rc) {
+		printk(KERN_ERR "%s: h/w init failure, err=%d\n",
+		       dev->name, rc);
+		goto err_out_free;
+	}
+
+	rc = request_irq(dev->irq, de_interrupt, SA_SHIRQ, dev->name, dev);
+	if (rc) {
+		printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n",
+		       dev->name, dev->irq, rc);
+		goto err_out_hw;
+	}
+
+	netif_start_queue(dev);
+	mod_timer(&de->media_timer, jiffies + DE_TIMER_NO_LINK);
+
+	return 0;
+
+err_out_hw:
+	spin_lock_irqsave(&de->lock, flags);
+	de_stop_hw(de);
+	spin_unlock_irqrestore(&de->lock, flags);
+
+err_out_free:
+	de_free_rings(de);
+	return rc;
+}
+
+static int de_close (struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+	unsigned long flags;
+
+	if (netif_msg_ifdown(de))
+		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
+
+	del_timer_sync(&de->media_timer);
+
+	spin_lock_irqsave(&de->lock, flags);
+	de_stop_hw(de);
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+	spin_unlock_irqrestore(&de->lock, flags);
+	
+	free_irq(dev->irq, dev);
+
+	de_free_rings(de);
+	de_adapter_sleep(de);
+	pci_disable_device(de->pdev);
+	return 0;
+}
+
+static void de_tx_timeout (struct net_device *dev)
+{
+	struct de_private *de = dev->priv;
+
+	printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
+	       dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
+	       de->rx_tail, de->tx_head, de->tx_tail);
+
+	del_timer_sync(&de->media_timer);
+
+	disable_irq(dev->irq);
+	spin_lock_irq(&de->lock);
+
+	de_stop_hw(de);
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+
+	spin_unlock_irq(&de->lock);
+	enable_irq(dev->irq);
+		
+	/* Update the error counts. */
+	__de_get_stats(de);
+
+	synchronize_irq();
+	de_clean_rings(de);
+
+	de_init_hw(de);
+	
+	netif_wake_queue(dev);
+}
+
+static int de_get_regs(struct de_private *de, u8 *buf)
+{
+	int i;
+	u32 *rbuf = (u32 *)buf;
+	
+	/* read all CSRs */
+	for (i = 0; i < DE_NUM_REGS; i++)
+		rbuf[i] = dr32(i * 8);
+
+	/* handle self-clearing RxMissed counter, CSR8 */
+	de_rx_missed(de, rbuf[8]);
+
+	return 0;
+}
+
+static int de_ethtool_gset(struct de_private *de, struct ethtool_cmd *ecmd)
+{
+	ecmd->supported = de->media_supported;
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = 0;
+	ecmd->advertising = de->media_advertise;
+	
+	switch (de->media_type) {
+	case DE_MEDIA_AUI:
+		ecmd->port = PORT_AUI;
+		ecmd->speed = 5;
+		break;
+	case DE_MEDIA_BNC:
+		ecmd->port = PORT_BNC;
+		ecmd->speed = 2;
+		break;
+	default:
+		ecmd->port = PORT_TP;
+		ecmd->speed = SPEED_10;
+		break;
+	}
+	
+	if (de->macmode & FullDuplex)
+		ecmd->duplex = DUPLEX_FULL;
+	else
+		ecmd->duplex = DUPLEX_HALF;
+
+	if (de->media_lock)
+		ecmd->autoneg = AUTONEG_DISABLE;
+	else
+		ecmd->autoneg = AUTONEG_ENABLE;
+
+	/* ignore maxtxpkt, maxrxpkt for now */
+
+	return 0;
+}
+
+static int de_ethtool_sset(struct de_private *de, struct ethtool_cmd *ecmd)
+{
+	u32 new_media;
+	unsigned int media_lock;
+
+	if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2)
+		return -EINVAL;
+	if (de->de21040 && ecmd->speed == 2)
+		return -EINVAL;
+	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+	if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI && ecmd->port != PORT_BNC)
+		return -EINVAL;
+	if (de->de21040 && ecmd->port == PORT_BNC)
+		return -EINVAL;
+	if (ecmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+	if (ecmd->advertising & ~de->media_supported)
+		return -EINVAL;
+	if (ecmd->autoneg == AUTONEG_ENABLE &&
+	    (!(ecmd->advertising & ADVERTISED_Autoneg)))
+		return -EINVAL;
+	
+	switch (ecmd->port) {
+	case PORT_AUI:
+		new_media = DE_MEDIA_AUI;
+		if (!(ecmd->advertising & ADVERTISED_AUI))
+			return -EINVAL;
+		break;
+	case PORT_BNC:
+		new_media = DE_MEDIA_BNC;
+		if (!(ecmd->advertising & ADVERTISED_BNC))
+			return -EINVAL;
+		break;
+	default:
+		if (ecmd->autoneg == AUTONEG_ENABLE)
+			new_media = DE_MEDIA_TP_AUTO;
+		else if (ecmd->duplex == DUPLEX_FULL)
+			new_media = DE_MEDIA_TP_FD;
+		else
+			new_media = DE_MEDIA_TP;
+		if (!(ecmd->advertising & ADVERTISED_TP))
+			return -EINVAL;
+		if (!(ecmd->advertising & (ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half)))
+			return -EINVAL;
+		break;
+	}
+	
+	media_lock = (ecmd->autoneg == AUTONEG_ENABLE) ? 0 : 1;
+	
+	if ((new_media == de->media_type) &&
+	    (media_lock == de->media_lock) &&
+	    (ecmd->advertising == de->media_advertise))
+		return 0; /* nothing to change */
+	    
+	de_link_down(de);
+	de_stop_rxtx(de);
+	
+	de->media_type = new_media;
+	de->media_lock = media_lock;
+	de->media_advertise = ecmd->advertising;
+	de_set_media(de);
+	
+	return 0;
+}
+
+static int de_ethtool_ioctl (struct de_private *de, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		strcpy (info.bus_info, de->pdev->slot_name);
+		info.eedump_len = DE_EEPROM_SIZE;
+		info.regdump_len = DE_REGS_SIZE;
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&de->lock);
+		de_ethtool_gset(de, &ecmd);
+		spin_unlock_irq(&de->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd ecmd;
+		int r;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&de->lock);
+		r = de_ethtool_sset(de, &ecmd);
+		spin_unlock_irq(&de->lock);
+		return r;
+	}
+
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		u32 status;
+
+		if (de->media_type != DE_MEDIA_TP_AUTO)
+			return -EINVAL;
+		if (netif_carrier_ok(de->dev))
+			de_link_down(de);
+
+		status = dr32(SIAStatus);
+		dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
+		if (netif_msg_link(de))
+			printk(KERN_INFO "%s: link nway restart, status %x,%x\n",
+			       de->dev->name, status, dr32(SIAStatus));
+		return 0;
+	}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = (netif_carrier_ok(de->dev)) ? 1 : 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = de->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		de->msg_enable = edata.data;
+		return 0;
+	}
+
+	/* get registers */
+	case ETHTOOL_GREGS: {
+		struct ethtool_regs regs;
+		u8 regbuf[DE_REGS_SIZE];
+		int r;
+
+		if (copy_from_user(&regs, useraddr, sizeof(regs)))
+			return -EFAULT;
+		
+		if (regs.len > DE_REGS_SIZE) {
+			regs.len = DE_REGS_SIZE;
+		}
+		regs.version = (DE_REGS_VER << 2) | de->de21040;
+		if (copy_to_user(useraddr, &regs, sizeof(regs)))
+			return -EFAULT;
+
+		useraddr += offsetof(struct ethtool_regs, data);
+
+		spin_lock_irq(&de->lock);
+		r = de_get_regs(de, regbuf);
+		spin_unlock_irq(&de->lock);
+
+		if (r)
+			return r;
+		if (copy_to_user(useraddr, regbuf, regs.len))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get SROM dump */
+	case ETHTOOL_GEEPROM: {
+		struct ethtool_eeprom eeprom;
+
+		if (!de->ee_data)
+			break;
+		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
+			return -EFAULT;
+		if ((eeprom.offset != 0) || (eeprom.magic != 0) ||
+		    (eeprom.len != DE_EEPROM_SIZE))
+			return -EINVAL;
+
+		useraddr += offsetof(struct ethtool_regs, data);
+		if (copy_to_user(useraddr, de->ee_data, DE_EEPROM_SIZE))
+			return -EFAULT;
+	}
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+
+static int de_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct de_private *de = dev->priv;
+	int rc = 0;
+
+	if (!netif_running(dev))
+		return -EINVAL;
+		
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return de_ethtool_ioctl(de, (void *) rq->ifr_data);
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	return rc;
+}
+
+static void __init de21040_get_mac_address (struct de_private *de)
+{
+	unsigned i;
+
+	dw32 (ROMCmd, 0);	/* Reset the pointer with a dummy write. */
+
+	for (i = 0; i < 6; i++) {
+		int value, boguscnt = 100000;
+		do
+			value = dr32(ROMCmd);
+		while (value < 0 && --boguscnt > 0);
+		de->dev->dev_addr[i] = value;
+		if (boguscnt <= 0)
+			printk(KERN_WARNING PFX "timeout reading 21040 MAC address byte %u\n", i);
+	}
+}
+
+static void __init de21040_get_media_info(struct de_private *de)
+{
+	unsigned int i;
+
+	de->media_type = DE_MEDIA_TP;
+	de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full |
+			       SUPPORTED_10baseT_Half | SUPPORTED_AUI;
+	de->media_advertise = de->media_supported;
+
+	for (i = 0; i < DE_MAX_MEDIA; i++) {
+		switch (i) {
+		case DE_MEDIA_AUI:
+		case DE_MEDIA_TP:
+		case DE_MEDIA_TP_FD:
+			de->media[i].type = i;
+			de->media[i].csr13 = t21040_csr13[i];
+			de->media[i].csr14 = t21040_csr14[i];
+			de->media[i].csr15 = t21040_csr15[i];
+			break;
+		default:
+			de->media[i].type = DE_MEDIA_INVALID;
+			break;
+		}
+	}
+}
+
+/* Note: this routine returns extra data bits for size detection. */
+static unsigned __init tulip_read_eeprom(void *regs, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	void *ee_addr = regs + ROMCmd;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	writel(EE_ENB & ~EE_CS, ee_addr);
+	writel(EE_ENB, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		writel(EE_ENB | dataval, ee_addr);
+		readl(ee_addr);
+		writel(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		readl(ee_addr);
+		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+	}
+	writel(EE_ENB, ee_addr);
+	readl(ee_addr);
+
+	for (i = 16; i > 0; i--) {
+		writel(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		readl(ee_addr);
+		retval = (retval << 1) | ((readl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		writel(EE_ENB, ee_addr);
+		readl(ee_addr);
+	}
+
+	/* Terminate the EEPROM access. */
+	writel(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+static void __init de21041_get_srom_info (struct de_private *de)
+{
+	unsigned i, sa_offset = 0, ofs;
+	u8 ee_data[DE_EEPROM_SIZE + 6] = {};
+	unsigned ee_addr_size = tulip_read_eeprom(de->regs, 0xff, 8) & 0x40000 ? 8 : 6;
+	struct de_srom_info_leaf *il;
+	void *bufp;
+
+	/* download entire eeprom */
+	for (i = 0; i < DE_EEPROM_WORDS; i++)
+		((u16 *)ee_data)[i] =
+			le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
+
+	/* DEC now has a specification but early board makers
+	   just put the address in the first EEPROM locations. */
+	/* This does  memcmp(eedata, eedata+16, 8) */
+	for (i = 0; i < 8; i ++)
+		if (ee_data[i] != ee_data[16+i])
+			sa_offset = 20;
+
+	/* store MAC address */
+	for (i = 0; i < 6; i ++)
+		de->dev->dev_addr[i] = ee_data[i + sa_offset];
+
+	/* get offset of controller 0 info leaf.  ignore 2nd byte. */
+	ofs = ee_data[SROMC0InfoLeaf];
+	if (ofs >= (sizeof(ee_data) - sizeof(struct de_srom_info_leaf) - sizeof(struct de_srom_media_block)))
+		goto bad_srom;
+
+	/* get pointer to info leaf */
+	il = (struct de_srom_info_leaf *) &ee_data[ofs];
+
+	/* paranoia checks */
+	if (il->n_blocks == 0)
+		goto bad_srom;
+	if ((sizeof(ee_data) - ofs) <
+	    (sizeof(struct de_srom_info_leaf) + (sizeof(struct de_srom_media_block) * il->n_blocks)))
+		goto bad_srom;
+
+	/* get default media type */
+	switch (DE_UNALIGNED_16(&il->default_media)) {
+	case 0x0001:  de->media_type = DE_MEDIA_BNC; break;
+	case 0x0002:  de->media_type = DE_MEDIA_AUI; break;
+	case 0x0204:  de->media_type = DE_MEDIA_TP_FD; break;
+	default: de->media_type = DE_MEDIA_TP_AUTO; break;
+	}
+	
+	if (netif_msg_probe(de))
+		printk(KERN_INFO "de%d: SROM leaf offset %u, default media %s\n",
+		       de->board_idx, ofs,
+		       media_name[de->media_type]);
+
+	/* init SIA register values to defaults */
+	for (i = 0; i < DE_MAX_MEDIA; i++) {
+		de->media[i].type = DE_MEDIA_INVALID;
+		de->media[i].csr13 = 0xffff;
+		de->media[i].csr14 = 0xffff;
+		de->media[i].csr15 = 0xffff;
+	}
+
+	/* parse media blocks to see what medias are supported,
+	 * and if any custom CSR values are provided
+	 */
+	bufp = ((void *)il) + sizeof(*il);
+	for (i = 0; i < il->n_blocks; i++) {
+		struct de_srom_media_block *ib = bufp;
+		unsigned idx;
+
+		/* index based on media type in media block */
+		switch(ib->opts & MediaBlockMask) {
+		case 0: /* 10baseT */
+			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half
+					  | SUPPORTED_Autoneg;
+			idx = DE_MEDIA_TP;
+			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
+			break;
+		case 1: /* BNC */
+			de->media_supported |= SUPPORTED_BNC;
+			idx = DE_MEDIA_BNC;
+			break;
+		case 2: /* AUI */
+			de->media_supported |= SUPPORTED_AUI;
+			idx = DE_MEDIA_AUI;
+			break;
+		case 4: /* 10baseT-FD */
+			de->media_supported |= SUPPORTED_TP | SUPPORTED_10baseT_Full
+					  | SUPPORTED_Autoneg;
+			idx = DE_MEDIA_TP_FD;
+			de->media[DE_MEDIA_TP_AUTO].type = DE_MEDIA_TP_AUTO;
+			break;
+		default:
+			goto bad_srom;
+		}
+
+		de->media[idx].type = idx;
+
+		if (netif_msg_probe(de))
+			printk(KERN_INFO "de%d:   media block #%u: %s",
+			       de->board_idx, i,
+			       media_name[de->media[idx].type]);
+
+		bufp += sizeof (ib->opts);
+
+		if (ib->opts & MediaCustomCSRs) {
+			de->media[idx].csr13 = DE_UNALIGNED_16(&ib->csr13);
+			de->media[idx].csr14 = DE_UNALIGNED_16(&ib->csr14);
+			de->media[idx].csr15 = DE_UNALIGNED_16(&ib->csr15);
+			bufp += sizeof(ib->csr13) + sizeof(ib->csr14) +
+				sizeof(ib->csr15);
+
+			if (netif_msg_probe(de))
+				printk(" (%x,%x,%x)\n",
+				       de->media[idx].csr13,
+				       de->media[idx].csr14,
+				       de->media[idx].csr15);
+				       
+		} else if (netif_msg_probe(de))
+			printk("\n");
+
+		if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
+			break;
+	}
+
+	de->media_advertise = de->media_supported;
+
+fill_defaults:
+	/* fill in defaults, for cases where custom CSRs not used */
+	for (i = 0; i < DE_MAX_MEDIA; i++) {
+		if (de->media[i].csr13 == 0xffff)
+			de->media[i].csr13 = t21041_csr13[i];
+		if (de->media[i].csr14 == 0xffff)
+			de->media[i].csr14 = t21041_csr14[i];
+		if (de->media[i].csr15 == 0xffff)
+			de->media[i].csr15 = t21041_csr15[i];
+	}
+
+	de->ee_data = kmalloc(DE_EEPROM_SIZE, GFP_KERNEL);
+	if (de->ee_data)
+		memcpy(de->ee_data, &ee_data[0], DE_EEPROM_SIZE);
+
+	return;
+
+bad_srom:
+	/* for error cases, it's ok to assume we support all these */
+	for (i = 0; i < DE_MAX_MEDIA; i++)
+		de->media[i].type = i;
+	de->media_supported =
+		SUPPORTED_10baseT_Half |
+		SUPPORTED_10baseT_Full |
+		SUPPORTED_Autoneg |
+		SUPPORTED_TP |
+		SUPPORTED_AUI |
+		SUPPORTED_BNC;
+	goto fill_defaults;
+}
+
+static int __init de_init_one (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct de_private *de;
+	int rc;
+	void *regs;
+	long pciaddr;
+	static int board_idx = -1;
+
+	board_idx++;
+
+#ifndef MODULE
+	if (board_idx == 0)
+		printk("%s", version);
+#endif
+
+	/* allocate a new ethernet device structure, and fill in defaults */
+	dev = alloc_etherdev(sizeof(struct de_private));
+	if (!dev)
+		return -ENOMEM;
+
+	SET_MODULE_OWNER(dev);
+	dev->open = de_open;
+	dev->stop = de_close;
+	dev->set_multicast_list = de_set_rx_mode;
+	dev->hard_start_xmit = de_start_xmit;
+	dev->get_stats = de_get_stats;
+	dev->do_ioctl = de_ioctl;
+	dev->tx_timeout = de_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	dev->irq = pdev->irq;
+
+	de = dev->priv;
+	de->de21040 = ent->driver_data == 0 ? 1 : 0;
+	de->pdev = pdev;
+	de->dev = dev;
+	de->msg_enable = (debug < 0 ? DE_DEF_MSG_ENABLE : debug);
+	de->board_idx = board_idx;
+	spin_lock_init (&de->lock);
+	init_timer(&de->media_timer);
+	if (de->de21040)
+		de->media_timer.function = de21040_media_timer;
+	else
+		de->media_timer.function = de21041_media_timer;
+	de->media_timer.data = (unsigned long) de;
+
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+
+	/* wake up device, assign resources */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out_free;
+
+	/* reserve PCI resources to ensure driver atomicity */
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out_disable;
+
+	/* check for invalid IRQ value */
+	if (pdev->irq < 2) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
+		       pdev->irq, pdev->slot_name);
+		goto err_out_res;
+	}
+
+	/* obtain and check validity of PCI I/O address */
+	pciaddr = pci_resource_start(pdev, 1);
+	if (!pciaddr) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
+		       pdev->slot_name);
+		goto err_out_res;
+	}
+	if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
+		       pci_resource_len(pdev, 1), pdev->slot_name);
+		goto err_out_res;
+	}
+
+	/* remap CSR registers */
+	regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
+	if (!regs) {
+		rc = -EIO;
+		printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
+		       pci_resource_len(pdev, 1), pciaddr, pdev->slot_name);
+		goto err_out_res;
+	}
+	dev->base_addr = (unsigned long) regs;
+	de->regs = regs;
+
+	de_adapter_wake(de);
+
+	/* make sure hardware is not running */
+	rc = de_reset_mac(de);
+	if (rc) {
+		printk(KERN_ERR PFX "Cannot reset MAC, pci dev %s\n",
+		       pdev->slot_name);
+		goto err_out_iomap;
+	}
+
+	/* get MAC address, initialize default media type and
+	 * get list of supported media
+	 */
+	if (de->de21040) {
+		de21040_get_mac_address(de);
+		de21040_get_media_info(de);
+	} else {
+		de21041_get_srom_info(de);
+	}
+
+	/* register new network interface with kernel */
+	rc = register_netdev(dev);
+	if (rc)
+		goto err_out_iomap;
+
+	/* print info about board and interface just registered */
+	printk (KERN_INFO "%s: %s at 0x%lx, "
+		"%02x:%02x:%02x:%02x:%02x:%02x, "
+		"IRQ %d\n",
+		dev->name,
+		de->de21040 ? "21040" : "21041",
+		dev->base_addr,
+		dev->dev_addr[0], dev->dev_addr[1],
+		dev->dev_addr[2], dev->dev_addr[3],
+		dev->dev_addr[4], dev->dev_addr[5],
+		dev->irq);
+
+	pci_set_drvdata(pdev, dev);
+
+	/* enable busmastering */
+	pci_set_master(pdev);
+
+	/* put adapter to sleep */
+	de_adapter_sleep(de);
+
+	return 0;
+
+err_out_iomap:
+	if (de->ee_data)
+		kfree(de->ee_data);
+	iounmap(regs);
+err_out_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+err_out_free:
+	kfree(dev);
+	return rc;
+}
+
+static void __exit de_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct de_private *de = dev->priv;
+
+	if (!dev)
+		BUG();
+	unregister_netdev(dev);
+	if (de->ee_data)
+		kfree(de->ee_data);
+	iounmap(de->regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int de_suspend (struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct de_private *de = dev->priv;
+
+	rtnl_lock();
+	if (netif_running (dev)) {
+		del_timer_sync(&de->media_timer);
+
+		disable_irq(dev->irq);
+		spin_lock_irq(&de->lock);
+
+		de_stop_hw(de);
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
+		netif_carrier_off(dev);
+
+		spin_unlock_irq(&de->lock);
+		enable_irq(dev->irq);
+		
+		/* Update the error counts. */
+		__de_get_stats(de);
+
+		synchronize_irq();
+		de_clean_rings(de);
+
+		de_adapter_sleep(de);
+		pci_disable_device(pdev);
+	} else {
+		netif_device_detach(dev);
+	}
+	rtnl_unlock();
+	return 0;
+}
+
+static int de_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct de_private *de = dev->priv;
+
+	rtnl_lock();
+	if (netif_device_present(dev))
+		goto out;
+	if (netif_running(dev)) {
+		pci_enable_device(pdev);
+		de_init_hw(de);
+		netif_device_attach(dev);
+	} else {
+		netif_device_attach(dev);
+	}
+out:
+	rtnl_unlock();
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct pci_driver de_driver = {
+	name:		DRV_NAME,
+	id_table:	de_pci_tbl,
+	probe:		de_init_one,
+	remove:		de_remove_one,
+#ifdef CONFIG_PM
+	suspend:	de_suspend,
+	resume:		de_resume,
+#endif
+};
+
+static int __init de_init (void)
+{
+#ifdef MODULE
+	printk("%s", version);
+#endif
+	return pci_module_init (&de_driver);
+}
+
+static void __exit de_exit (void)
+{
+	pci_unregister_driver (&de_driver);
+}
+
+module_init(de_init);
+module_exit(de_exit);
diff -urN linux-2.5.6-pre3/drivers/net/tulip/de4x5.c linux-2.5.6/drivers/net/tulip/de4x5.c
--- linux-2.5.6-pre3/drivers/net/tulip/de4x5.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/de4x5.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,5918 @@
+/*  de4x5.c: A DIGITAL DC21x4x DECchip and DE425/DE434/DE435/DE450/DE500
+             ethernet driver for Linux.
+
+    Copyright 1994, 1995 Digital Equipment Corporation.
+
+    Testing resources for this driver have been made available
+    in part by NASA Ames Research Center (mjacob@nas.nasa.gov).
+
+    The author may be reached at davies@maniac.ultranet.com.
+
+    This program is free software; you can redistribute  it and/or modify it
+    under  the terms of  the GNU General  Public License as published by the
+    Free Software Foundation;  either version 2 of the  License, or (at your
+    option) any later version.
+
+    THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
+    WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+    NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
+    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+    NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+    USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+    ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+    You should have received a copy of the  GNU General Public License along
+    with this program; if not, write  to the Free Software Foundation, Inc.,
+    675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Originally,   this  driver  was    written  for the  Digital   Equipment
+    Corporation series of EtherWORKS ethernet cards:
+
+        DE425 TP/COAX EISA
+	DE434 TP PCI
+	DE435 TP/COAX/AUI PCI
+	DE450 TP/COAX/AUI PCI
+	DE500 10/100 PCI Fasternet
+
+    but it  will  now attempt  to  support all  cards which   conform to the
+    Digital Semiconductor   SROM   Specification.    The  driver   currently
+    recognises the following chips:
+
+        DC21040  (no SROM) 
+	DC21041[A]  
+	DC21140[A] 
+	DC21142 
+	DC21143 
+
+    So far the driver is known to work with the following cards:
+
+        KINGSTON
+	Linksys
+	ZNYX342
+	SMC8432
+	SMC9332 (w/new SROM)
+	ZNYX31[45]
+	ZNYX346 10/100 4 port (can act as a 10/100 bridge!) 
+
+    The driver has been tested on a relatively busy network using the DE425,
+    DE434, DE435 and DE500 cards and benchmarked with 'ttcp': it transferred
+    16M of data to a DECstation 5000/200 as follows:
+
+                TCP           UDP
+             TX     RX     TX     RX
+    DE425   1030k  997k   1170k  1128k
+    DE434   1063k  995k   1170k  1125k
+    DE435   1063k  995k   1170k  1125k
+    DE500   1063k  998k   1170k  1125k  in 10Mb/s mode
+
+    All  values are typical (in   kBytes/sec) from a  sample  of 4 for  each
+    measurement. Their error is +/-20k on a quiet (private) network and also
+    depend on what load the CPU has.
+
+    =========================================================================
+    This driver  has been written substantially  from  scratch, although its
+    inheritance of style and stack interface from 'ewrk3.c' and in turn from
+    Donald Becker's 'lance.c' should be obvious. With the module autoload of
+    every  usable DECchip board,  I  pinched Donald's 'next_module' field to
+    link my modules together.
+
+    Upto 15 EISA cards can be supported under this driver, limited primarily
+    by the available IRQ lines.  I have  checked different configurations of
+    multiple depca, EtherWORKS 3 cards and de4x5 cards and  have not found a
+    problem yet (provided you have at least depca.c v0.38) ...
+
+    PCI support has been added  to allow the driver  to work with the DE434,
+    DE435, DE450 and DE500 cards. The I/O accesses are a bit of a kludge due
+    to the differences in the EISA and PCI CSR address offsets from the base
+    address.
+
+    The ability to load this  driver as a loadable  module has been included
+    and used extensively  during the driver development  (to save those long
+    reboot sequences).  Loadable module support  under PCI and EISA has been
+    achieved by letting the driver autoprobe as if it were compiled into the
+    kernel. Do make sure  you're not sharing  interrupts with anything  that
+    cannot accommodate  interrupt  sharing!
+
+    To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy de4x5.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) for fixed  autoprobes (not  recommended),  edit the source code  near
+    line 5594 to reflect the I/O address  you're using, or assign these when
+    loading by:
+
+                   insmod de4x5 io=0xghh           where g = bus number
+		                                        hh = device number   
+
+       NB: autoprobing for modules is now supported by default. You may just
+           use:
+
+                   insmod de4x5
+
+           to load all available boards. For a specific board, still use
+	   the 'io=?' above.
+    3) compile  de4x5.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the de4x5 configuration turned off and reboot.
+    5) insmod de4x5 [io=0xghh]
+    6) run the net startup bits for your new eth?? interface(s) manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    To unload a module, turn off the associated interface(s) 
+    'ifconfig eth?? down' then 'rmmod de4x5'.
+
+    Automedia detection is included so that in  principal you can disconnect
+    from, e.g.  TP, reconnect  to BNC  and  things will still work  (after a
+    pause whilst the   driver figures out   where its media went).  My tests
+    using ping showed that it appears to work....
+
+    By  default,  the driver will  now   autodetect any  DECchip based card.
+    Should you have a need to restrict the driver to DIGITAL only cards, you
+    can compile with a  DEC_ONLY define, or if  loading as a module, use the
+    'dec_only=1'  parameter. 
+
+    I've changed the timing routines to  use the kernel timer and scheduling
+    functions  so that the  hangs  and other assorted problems that occurred
+    while autosensing the  media  should be gone.  A  bonus  for the DC21040
+    auto  media sense algorithm is  that it can now  use one that is more in
+    line with the  rest (the DC21040  chip doesn't  have a hardware  timer).
+    The downside is the 1 'jiffies' (10ms) resolution.
+
+    IEEE 802.3u MII interface code has  been added in anticipation that some
+    products may use it in the future.
+
+    The SMC9332 card  has a non-compliant SROM  which needs fixing -  I have
+    patched this  driver to detect it  because the SROM format used complies
+    to a previous DEC-STD format.
+
+    I have removed the buffer copies needed for receive on Intels.  I cannot
+    remove them for   Alphas since  the  Tulip hardware   only does longword
+    aligned  DMA transfers  and  the  Alphas get   alignment traps with  non
+    longword aligned data copies (which makes them really slow). No comment.
+
+    I  have added SROM decoding  routines to make this  driver work with any
+    card that  supports the Digital  Semiconductor SROM spec. This will help
+    all  cards running the dc2114x  series chips in particular.  Cards using
+    the dc2104x  chips should run correctly with  the basic  driver.  I'm in
+    debt to <mjacob@feral.com> for the  testing and feedback that helped get
+    this feature working.  So far we have  tested KINGSTON, SMC8432, SMC9332
+    (with the latest SROM complying  with the SROM spec  V3: their first was
+    broken), ZNYX342  and  LinkSys. ZYNX314 (dual  21041  MAC) and  ZNYX 315
+    (quad 21041 MAC)  cards also  appear  to work despite their  incorrectly
+    wired IRQs.
+
+    I have added a temporary fix for interrupt problems when some SCSI cards
+    share the same interrupt as the DECchip based  cards. The problem occurs
+    because  the SCSI card wants to  grab the interrupt  as a fast interrupt
+    (runs the   service routine with interrupts turned   off) vs.  this card
+    which really needs to run the service routine with interrupts turned on.
+    This driver will  now   add the interrupt service   routine  as  a  fast
+    interrupt if it   is bounced from the   slow interrupt.  THIS IS NOT   A
+    RECOMMENDED WAY TO RUN THE DRIVER  and has been done  for a limited time
+    until  people   sort  out their  compatibility    issues and the  kernel
+    interrupt  service code  is  fixed.   YOU  SHOULD SEPARATE OUT  THE FAST
+    INTERRUPT CARDS FROM THE SLOW INTERRUPT CARDS to ensure that they do not
+    run on the same interrupt. PCMCIA/CardBus is another can of worms...
+
+    Finally, I think  I have really  fixed  the module  loading problem with
+    more than one DECchip based  card.  As a  side effect, I don't mess with
+    the  device structure any  more which means that  if more than 1 card in
+    2.0.x is    installed (4  in   2.1.x),  the  user   will have   to  edit
+    linux/drivers/net/Space.c  to make room for  them. Hence, module loading
+    is  the preferred way to use   this driver, since  it  doesn't have this
+    limitation.
+
+    Where SROM media  detection is used and  full duplex is specified in the
+    SROM,  the feature is  ignored unless  lp->params.fdx  is set at compile
+    time  OR during  a   module load  (insmod  de4x5   args='eth??:fdx' [see
+    below]).  This is because there  is no way  to automatically detect full
+    duplex   links  except through   autonegotiation.    When I  include the
+    autonegotiation feature in  the SROM autoconf  code, this detection will
+    occur automatically for that case.
+
+    Command  line arguments are  now  allowed, similar  to passing arguments
+    through LILO. This will allow a per adapter board  set up of full duplex
+    and media. The only lexical constraints  are: the board name (dev->name)
+    appears in the list before its  parameters.  The list of parameters ends
+    either at the end of the parameter list or with another board name.  The
+    following parameters are allowed:
+
+            fdx        for full duplex
+	    autosense  to set the media/speed; with the following 
+	               sub-parameters:
+		       TP, TP_NW, BNC, AUI, BNC_AUI, 100Mb, 10Mb, AUTO
+
+    Case sensitivity is important  for  the sub-parameters. They *must*   be
+    upper case. Examples:
+
+        insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+
+    For a compiled in driver, at or above line 548, place e.g.
+	#define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
+
+    Yes,  I know full duplex isn't  permissible on BNC  or AUI; they're just
+    examples. By default, full duplex is turned off and  AUTO is the default
+    autosense setting.  In reality, I expect only  the full duplex option to
+    be used. Note the use of single quotes in the two examples above and the
+    lack of commas to separate items. ALSO, you must get the requested media
+    correct in relation to what the adapter SROM says it has. There's no way
+    to  determine this in  advance other than by  trial and error and common
+    sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
+
+    Changed the bus probing.  EISA used to be  done first,  followed by PCI.
+    Most people probably don't even know  what a de425 is today and the EISA
+    probe has messed  up some SCSI cards  in the past,  so now PCI is always
+    probed  first  followed by  EISA if  a) the architecture allows EISA and
+    either  b) there have been no PCI cards detected or  c) an EISA probe is
+    forced by  the user.  To force  a probe  include  "force_eisa"  in  your
+    insmod "args" line;  for built-in kernels either change the driver to do
+    this  automatically  or include  #define DE4X5_FORCE_EISA  on or  before
+    line 1040 in the driver.
+
+    TO DO: 
+    ------
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1     17-Nov-94   Initial writing. ALPHA code release.
+      0.2     13-Jan-95   Added PCI support for DE435's.
+      0.21    19-Jan-95   Added auto media detection.
+      0.22    10-Feb-95   Fix interrupt handler call <chris@cosy.sbg.ac.at>.
+                          Fix recognition bug reported by <bkm@star.rl.ac.uk>.
+			  Add request/release_region code.
+			  Add loadable modules support for PCI.
+			  Clean up loadable modules support.
+      0.23    28-Feb-95   Added DC21041 and DC21140 support. 
+                          Fix missed frame counter value and initialisation.
+			  Fixed EISA probe.
+      0.24    11-Apr-95   Change delay routine to use <linux/udelay>.
+                          Change TX_BUFFS_AVAIL macro.
+			  Change media autodetection to allow manual setting.
+			  Completed DE500 (DC21140) support.
+      0.241   18-Apr-95   Interim release without DE500 Autosense Algorithm.
+      0.242   10-May-95   Minor changes.
+      0.30    12-Jun-95   Timer fix for DC21140.
+                          Portability changes.
+			  Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
+			  Add DE500 semi automatic autosense.
+			  Add Link Fail interrupt TP failure detection.
+			  Add timer based link change detection.
+			  Plugged a memory leak in de4x5_queue_pkt().
+      0.31    13-Jun-95   Fixed PCI stuff for 1.3.1.
+      0.32    26-Jun-95   Added verify_area() calls in de4x5_ioctl() from a
+                          suggestion by <heiko@colossus.escape.de>.
+      0.33     8-Aug-95   Add shared interrupt support (not released yet).
+      0.331   21-Aug-95   Fix de4x5_open() with fast CPUs.
+                          Fix de4x5_interrupt().
+                          Fix dc21140_autoconf() mess.
+			  No shared interrupt support.
+      0.332   11-Sep-95   Added MII management interface routines.
+      0.40     5-Mar-96   Fix setup frame timeout <maartenb@hpkuipc.cern.ch>.
+                          Add kernel timer code (h/w is too flaky).
+			  Add MII based PHY autosense.
+			  Add new multicasting code.
+			  Add new autosense algorithms for media/mode 
+			  selection using kernel scheduling/timing.
+			  Re-formatted.
+			  Made changes suggested by <jeff@router.patch.net>:
+			    Change driver to detect all DECchip based cards
+			    with DEC_ONLY restriction a special case.
+			    Changed driver to autoprobe as a module. No irq
+			    checking is done now - assume BIOS is good!
+			  Added SMC9332 detection <manabe@Roy.dsl.tutics.ac.jp>
+      0.41    21-Mar-96   Don't check for get_hw_addr checksum unless DEC card
+                          only <niles@axp745gsfc.nasa.gov>
+			  Fix for multiple PCI cards reported by <jos@xos.nl>
+			  Duh, put the SA_SHIRQ flag into request_interrupt().
+			  Fix SMC ethernet address in enet_det[].
+			  Print chip name instead of "UNKNOWN" during boot.
+      0.42    26-Apr-96   Fix MII write TA bit error.
+                          Fix bug in dc21040 and dc21041 autosense code.
+			  Remove buffer copies on receive for Intels.
+			  Change sk_buff handling during media disconnects to
+			   eliminate DUP packets.
+			  Add dynamic TX thresholding.
+			  Change all chips to use perfect multicast filtering.
+			  Fix alloc_device() bug <jari@markkus2.fimr.fi>
+      0.43   21-Jun-96    Fix unconnected media TX retry bug.
+                          Add Accton to the list of broken cards.
+			  Fix TX under-run bug for non DC21140 chips.
+			  Fix boot command probe bug in alloc_device() as
+			   reported by <koen.gadeyne@barco.com> and 
+			   <orava@nether.tky.hut.fi>.
+			  Add cache locks to prevent a race condition as
+			   reported by <csd@microplex.com> and 
+			   <baba@beckman.uiuc.edu>.
+			  Upgraded alloc_device() code.
+      0.431  28-Jun-96    Fix potential bug in queue_pkt() from discussion
+                          with <csd@microplex.com>
+      0.44   13-Aug-96    Fix RX overflow bug in 2114[023] chips.
+                          Fix EISA probe bugs reported by <os2@kpi.kharkov.ua>
+			  and <michael@compurex.com>.
+      0.441   9-Sep-96    Change dc21041_autoconf() to probe quiet BNC media
+                           with a loopback packet.
+      0.442   9-Sep-96    Include AUI in dc21041 media printout. Bug reported
+                           by <bhat@mundook.cs.mu.OZ.AU>
+      0.45    8-Dec-96    Include endian functions for PPC use, from work 
+                           by <cort@cs.nmt.edu> and <g.thomas@opengroup.org>.
+      0.451  28-Dec-96    Added fix to allow autoprobe for modules after
+                           suggestion from <mjacob@feral.com>.
+      0.5    30-Jan-97    Added SROM decoding functions.
+                          Updated debug flags.
+			  Fix sleep/wakeup calls for PCI cards, bug reported
+			   by <cross@gweep.lkg.dec.com>.
+			  Added multi-MAC, one SROM feature from discussion
+			   with <mjacob@feral.com>.
+			  Added full module autoprobe capability.
+			  Added attempt to use an SMC9332 with broken SROM.
+			  Added fix for ZYNX multi-mac cards that didn't
+			   get their IRQs wired correctly.
+      0.51   13-Feb-97    Added endian fixes for the SROM accesses from
+			   <paubert@iram.es>
+			  Fix init_connection() to remove extra device reset.
+			  Fix MAC/PHY reset ordering in dc21140m_autoconf().
+			  Fix initialisation problem with lp->timeout in
+			   typeX_infoblock() from <paubert@iram.es>.
+			  Fix MII PHY reset problem from work done by
+			   <paubert@iram.es>.
+      0.52   26-Apr-97    Some changes may not credit the right people -
+                           a disk crash meant I lost some mail.
+			  Change RX interrupt routine to drop rather than 
+			   defer packets to avoid hang reported by 
+			   <g.thomas@opengroup.org>.
+			  Fix srom_exec() to return for COMPACT and type 1
+			   infoblocks.
+			  Added DC21142 and DC21143 functions.
+			  Added byte counters from <phil@tazenda.demon.co.uk>
+			  Added SA_INTERRUPT temporary fix from 
+			   <mjacob@feral.com>.
+      0.53   12-Nov-97    Fix the *_probe() to include 'eth??' name during
+                           module load: bug reported by
+			   <Piete.Brooks@cl.cam.ac.uk>
+			  Fix multi-MAC, one SROM, to work with 2114x chips:
+			   bug reported by <cmetz@inner.net>.
+			  Make above search independent of BIOS device scan
+			   direction.
+			  Completed DC2114[23] autosense functions.
+      0.531  21-Dec-97    Fix DE500-XA 100Mb/s bug reported by 
+                           <robin@intercore.com
+			  Fix type1_infoblock() bug introduced in 0.53, from
+			   problem reports by 
+			   <parmee@postecss.ncrfran.france.ncr.com> and
+			   <jo@ice.dillingen.baynet.de>.
+			  Added argument list to set up each board from either
+			   a module's command line or a compiled in #define.
+			  Added generic MII PHY functionality to deal with
+			   newer PHY chips.
+			  Fix the mess in 2.1.67.
+      0.532   5-Jan-98    Fix bug in mii_get_phy() reported by 
+                           <redhat@cococo.net>.
+                          Fix bug in pci_probe() for 64 bit systems reported
+			   by <belliott@accessone.com>.
+      0.533   9-Jan-98    Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
+      0.534  24-Jan-98    Fix last (?) endian bug from <geert@linux-m68k.org>
+      0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
+      0.536  21-Mar-98    Change pci_probe() to use the pci_dev structure.
+			  **Incompatible with 2.0.x from here.**
+      0.540   5-Jul-98    Atomicize assertion of dev->interrupt for SMP
+                           from <lma@varesearch.com>
+			  Add TP, AUI and BNC cases to 21140m_autoconf() for
+			   case where a 21140 under SROM control uses, e.g. AUI
+			   from problem report by <delchini@lpnp09.in2p3.fr>
+			  Add MII parallel detection to 2114x_autoconf() for
+			   case where no autonegotiation partner exists from
+			   problem report by <mlapsley@ndirect.co.uk>.
+			  Add ability to force connection type directly even
+			   when using SROM control from problem report by
+			   <earl@exis.net>.
+			  Updated the PCI interface to conform with the latest
+			   version. I hope nothing is broken...
+          		  Add TX done interrupt modification from suggestion
+			   by <Austin.Donnelly@cl.cam.ac.uk>.
+			  Fix is_anc_capable() bug reported by 
+			   <Austin.Donnelly@cl.cam.ac.uk>.
+			  Fix type[13]_infoblock() bug: during MII search, PHY
+			   lp->rst not run because lp->ibn not initialised -
+			   from report & fix by <paubert@iram.es>.
+			  Fix probe bug with EISA & PCI cards present from
+                           report by <eirik@netcom.com>.
+      0.541  24-Aug-98    Fix compiler problems associated with i386-string
+                           ops from multiple bug reports and temporary fix
+			   from <paubert@iram.es>.
+			  Fix pci_probe() to correctly emulate the old
+			   pcibios_find_class() function.
+			  Add an_exception() for old ZYNX346 and fix compile
+			   warning on PPC & SPARC, from <ecd@skynet.be>.
+			  Fix lastPCI to correctly work with compiled in
+			   kernels and modules from bug report by 
+			   <Zlatko.Calusic@CARNet.hr> et al.
+      0.542  15-Sep-98    Fix dc2114x_autoconf() to stop multiple messages
+                           when media is unconnected.
+			  Change dev->interrupt to lp->interrupt to ensure
+			   alignment for Alpha's and avoid their unaligned
+			   access traps. This flag is merely for log messages:
+			   should do something more definitive though...
+      0.543  30-Dec-98    Add SMP spin locking.
+      0.544   8-May-99    Fix for buggy SROM in Motorola embedded boards using
+                           a 21143 by <mmporter@home.com>.
+			  Change PCI/EISA bus probing order.
+      0.545  28-Nov-99    Further Moto SROM bug fix from 
+                           <mporter@eng.mcd.mot.com>
+                          Remove double checking for DEBUG_RX in de4x5_dbg_rx()
+			   from report by <geert@linux-m68k.org>
+      0.546  22-Feb-01    Fixes Alpha XP1000 oops.  The srom_search function
+                           was causing a page fault when initializing the
+                           variable 'pb', on a non de4x5 PCI device, in this
+                           case a PCI bridge (DEC chip 21152). The value of
+                           'pb' is now only initialized if a de4x5 chip is
+                           present. 
+                           <france@handhelds.org>  
+      0.547  08-Nov-01    Use library crc32 functions by <Matt_Domsch@dell.com>
+    =========================================================================
+*/
+
+static const char *version = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <asm/uaccess.h>
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif /* CONFIG_PPC */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+#include <linux/ctype.h>
+
+#include "de4x5.h"
+
+#define c_char const char
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+
+/*
+** MII Information
+*/
+struct phy_table {
+    int reset;              /* Hard reset required?                         */
+    int id;                 /* IEEE OUI                                     */
+    int ta;                 /* One cycle TA time - 802.3u is confusing here */
+    struct {                /* Non autonegotiation (parallel) speed det.    */
+	int reg;
+	int mask;
+	int value;
+    } spd;
+};
+
+struct mii_phy {
+    int reset;              /* Hard reset required?                      */
+    int id;                 /* IEEE OUI                                  */
+    int ta;                 /* One cycle TA time                         */
+    struct {                /* Non autonegotiation (parallel) speed det. */
+	int reg;
+	int mask;
+	int value;
+    } spd;
+    int addr;               /* MII address for the PHY                   */
+    u_char  *gep;           /* Start of GEP sequence block in SROM       */
+    u_char  *rst;           /* Start of reset sequence in SROM           */
+    u_int mc;               /* Media Capabilities                        */
+    u_int ana;              /* NWay Advertisement                        */
+    u_int fdx;              /* Full DupleX capabilites for each media    */
+    u_int ttm;              /* Transmit Threshold Mode for each media    */
+    u_int mci;              /* 21142 MII Connector Interrupt info        */
+};
+
+#define DE4X5_MAX_PHY 8     /* Allow upto 8 attached PHY devices per board */
+
+struct sia_phy {
+    u_char mc;              /* Media Code                                */
+    u_char ext;             /* csr13-15 valid when set                   */
+    int csr13;              /* SIA Connectivity Register                 */
+    int csr14;              /* SIA TX/RX Register                        */
+    int csr15;              /* SIA General Register                      */
+    int gepc;               /* SIA GEP Control Information               */
+    int gep;                /* SIA GEP Data                              */
+};
+
+/*
+** Define the know universe of PHY devices that can be
+** recognised by this driver.
+*/
+static struct phy_table phy_info[] = {
+    {0, NATIONAL_TX, 1, {0x19, 0x40, 0x00}},       /* National TX      */
+    {1, BROADCOM_T4, 1, {0x10, 0x02, 0x02}},       /* Broadcom T4      */
+    {0, SEEQ_T4    , 1, {0x12, 0x10, 0x10}},       /* SEEQ T4          */
+    {0, CYPRESS_T4 , 1, {0x05, 0x20, 0x20}},       /* Cypress T4       */
+    {0, 0x7810     , 1, {0x14, 0x0800, 0x0800}}    /* Level One LTX970 */
+};
+
+/*
+** These GENERIC values assumes that the PHY devices follow 802.3u and
+** allow parallel detection to set the link partner ability register.
+** Detection of 100Base-TX [H/F Duplex] and 100Base-T4 is supported.
+*/
+#define GENERIC_REG   0x05      /* Autoneg. Link Partner Advertisement Reg. */
+#define GENERIC_MASK  MII_ANLPA_100M /* All 100Mb/s Technologies            */
+#define GENERIC_VALUE MII_ANLPA_100M /* 100B-TX, 100B-TX FDX, 100B-T4       */
+
+/*
+** Define special SROM detection cases
+*/
+static c_char enet_det[][ETH_ALEN] = {
+    {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00},
+    {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00}
+};
+
+#define SMC    1
+#define ACCTON 2
+
+/*
+** SROM Repair definitions. If a broken SROM is detected a card may
+** use this information to help figure out what to do. This is a
+** "stab in the dark" and so far for SMC9332's only.
+*/
+static c_char srom_repair_info[][100] = {
+    {0x00,0x1e,0x00,0x00,0x00,0x08,             /* SMC9332 */
+     0x1f,0x01,0x8f,0x01,0x00,0x01,0x00,0x02,
+     0x01,0x00,0x00,0x78,0xe0,0x01,0x00,0x50,
+     0x00,0x18,}
+};
+
+
+#ifdef DE4X5_DEBUG
+static int de4x5_debug = DE4X5_DEBUG;
+#else
+/*static int de4x5_debug = (DEBUG_MII | DEBUG_SROM | DEBUG_PCICFG | DEBUG_MEDIA | DEBUG_VERSION);*/
+static int de4x5_debug = (DEBUG_MEDIA | DEBUG_VERSION);
+#endif
+
+/*
+** Allow per adapter set up. For modules this is simply a command line
+** parameter, e.g.: 
+** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'.
+**
+** For a compiled in driver, place e.g.
+**     #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP"
+** here
+*/
+#ifdef DE4X5_PARM
+static char *args = DE4X5_PARM;
+#else
+static char *args;
+#endif
+
+struct parameters {
+    int fdx;
+    int autosense;
+};
+
+#define DE4X5_AUTOSENSE_MS 250      /* msec autosense tick (DE500) */
+
+#define DE4X5_NDA 0xffe0            /* No Device (I/O) Address */
+
+/*
+** Ethernet PROM defines
+*/
+#define PROBE_LENGTH    32
+#define ETH_PROM_SIG    0xAA5500FFUL
+
+/*
+** Ethernet Info
+*/
+#define PKT_BUF_SZ	1536            /* Buffer size for each Tx/Rx buffer */
+#define IEEE802_3_SZ    1518            /* Packet + CRC */
+#define MAX_PKT_SZ   	1514            /* Maximum ethernet packet length */
+#define MAX_DAT_SZ   	1500            /* Maximum ethernet data length */
+#define MIN_DAT_SZ   	1               /* Minimum ethernet data length */
+#define PKT_HDR_LEN     14              /* Addresses and data length info */
+#define FAKE_FRAME_LEN  (MAX_PKT_SZ + 1)
+#define QUEUE_PKT_TIMEOUT (3*HZ)        /* 3 second timeout */
+
+
+/*
+** EISA bus defines
+*/
+#define DE4X5_EISA_IO_PORTS   0x0c00    /* I/O port base address, slot 0 */
+#define DE4X5_EISA_TOTAL_SIZE 0x100     /* I/O address extent */
+
+#define MAX_EISA_SLOTS 16
+#define EISA_SLOT_INC 0x1000
+#define EISA_ALLOWED_IRQ_LIST  {5, 9, 10, 11}
+
+#define DE4X5_SIGNATURE {"DE425","DE434","DE435","DE450","DE500"}
+#define DE4X5_NAME_LENGTH 8
+
+/*
+** Ethernet PROM defines for DC21040
+*/
+#define PROBE_LENGTH    32
+#define ETH_PROM_SIG    0xAA5500FFUL
+
+/*
+** PCI Bus defines
+*/
+#define PCI_MAX_BUS_NUM      8
+#define DE4X5_PCI_TOTAL_SIZE 0x80       /* I/O address extent */
+#define DE4X5_CLASS_CODE     0x00020000 /* Network controller, Ethernet */
+#define NO_MORE_PCI          -2         /* PCI bus search all done */
+
+/*
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry. 
+*/
+#define DE4X5_ALIGN4      ((u_long)4 - 1)     /* 1 longword align */
+#define DE4X5_ALIGN8      ((u_long)8 - 1)     /* 2 longword align */
+#define DE4X5_ALIGN16     ((u_long)16 - 1)    /* 4 longword align */
+#define DE4X5_ALIGN32     ((u_long)32 - 1)    /* 8 longword align */
+#define DE4X5_ALIGN64     ((u_long)64 - 1)    /* 16 longword align */
+#define DE4X5_ALIGN128    ((u_long)128 - 1)   /* 32 longword align */
+
+#define DE4X5_ALIGN         DE4X5_ALIGN32           /* Keep the DC21040 happy... */
+#define DE4X5_CACHE_ALIGN   CAL_16LONG
+#define DESC_SKIP_LEN DSL_0             /* Must agree with DESC_ALIGN */
+/*#define DESC_ALIGN    u32 dummy[4];  / * Must agree with DESC_SKIP_LEN */
+#define DESC_ALIGN
+
+#ifndef DEC_ONLY                        /* See README.de4x5 for using this */
+static int dec_only;
+#else
+static int dec_only = 1;
+#endif
+
+/*
+** DE4X5 IRQ ENABLE/DISABLE
+*/
+#define ENABLE_IRQs { \
+    imr |= lp->irq_en;\
+    outl(imr, DE4X5_IMR);               /* Enable the IRQs */\
+}
+
+#define DISABLE_IRQs {\
+    imr = inl(DE4X5_IMR);\
+    imr &= ~lp->irq_en;\
+    outl(imr, DE4X5_IMR);               /* Disable the IRQs */\
+}
+
+#define UNMASK_IRQs {\
+    imr |= lp->irq_mask;\
+    outl(imr, DE4X5_IMR);               /* Unmask the IRQs */\
+}
+
+#define MASK_IRQs {\
+    imr = inl(DE4X5_IMR);\
+    imr &= ~lp->irq_mask;\
+    outl(imr, DE4X5_IMR);               /* Mask the IRQs */\
+}
+
+/*
+** DE4X5 START/STOP
+*/
+#define START_DE4X5 {\
+    omr = inl(DE4X5_OMR);\
+    omr |= OMR_ST | OMR_SR;\
+    outl(omr, DE4X5_OMR);               /* Enable the TX and/or RX */\
+}
+
+#define STOP_DE4X5 {\
+    omr = inl(DE4X5_OMR);\
+    omr &= ~(OMR_ST|OMR_SR);\
+    outl(omr, DE4X5_OMR);               /* Disable the TX and/or RX */ \
+}
+
+/*
+** DE4X5 SIA RESET
+*/
+#define RESET_SIA outl(0, DE4X5_SICR);  /* Reset SIA connectivity regs */
+
+/*
+** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
+*/
+#define DE4X5_AUTOSENSE_MS  250
+
+/*
+** SROM Structure
+*/
+struct de4x5_srom {
+    char sub_vendor_id[2];
+    char sub_system_id[2];
+    char reserved[12];
+    char id_block_crc;
+    char reserved2;
+    char version;
+    char num_controllers;
+    char ieee_addr[6];
+    char info[100];
+    short chksum;
+};
+#define SUB_VENDOR_ID 0x500a
+
+/*
+** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
+** and have sizes of both a power of 2 and a multiple of 4.
+** A size of 256 bytes for each buffer could be chosen because over 90% of
+** all packets in our network are <256 bytes long and 64 longword alignment
+** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
+** descriptors are needed for machines with an ALPHA CPU.
+*/
+#define NUM_RX_DESC 8                   /* Number of RX descriptors   */
+#define NUM_TX_DESC 32                  /* Number of TX descriptors   */
+#define RX_BUFF_SZ  1536                /* Power of 2 for kmalloc and */
+                                        /* Multiple of 4 for DC21040  */
+                                        /* Allows 512 byte alignment  */
+struct de4x5_desc {
+    volatile s32 status;
+    u32 des1;
+    u32 buf;
+    u32 next;
+    DESC_ALIGN
+};
+
+/*
+** The DE4X5 private structure
+*/
+#define DE4X5_PKT_STAT_SZ 16
+#define DE4X5_PKT_BIN_SZ  128            /* Should be >=100 unless you
+                                            increase DE4X5_PKT_STAT_SZ */
+
+struct pkt_stats {
+	u_int bins[DE4X5_PKT_STAT_SZ];      /* Private stats counters       */
+	u_int unicast;
+	u_int multicast;
+	u_int broadcast;
+	u_int excessive_collisions;
+	u_int tx_underruns;
+	u_int excessive_underruns;
+	u_int rx_runt_frames;
+	u_int rx_collision;
+	u_int rx_dribble;
+	u_int rx_overflow;
+};
+
+struct de4x5_private {
+    char adapter_name[80];                  /* Adapter name                 */
+    u_long interrupt;                       /* Aligned ISR flag             */
+    struct de4x5_desc *rx_ring;		    /* RX descriptor ring           */
+    struct de4x5_desc *tx_ring;		    /* TX descriptor ring           */
+    struct sk_buff *tx_skb[NUM_TX_DESC];    /* TX skb for freeing when sent */
+    struct sk_buff *rx_skb[NUM_RX_DESC];    /* RX skb's                     */
+    int rx_new, rx_old;                     /* RX descriptor ring pointers  */
+    int tx_new, tx_old;                     /* TX descriptor ring pointers  */
+    char setup_frame[SETUP_FRAME_LEN];      /* Holds MCA and PA info.       */
+    char frame[64];                         /* Min sized packet for loopback*/
+    spinlock_t lock;                        /* Adapter specific spinlock    */
+    struct net_device_stats stats;          /* Public stats                 */
+    struct pkt_stats pktStats;	            /* Private stats counters	    */
+    char rxRingSize;
+    char txRingSize;
+    int  bus;                               /* EISA or PCI                  */
+    int  bus_num;                           /* PCI Bus number               */
+    int  device;                            /* Device number on PCI bus     */
+    int  state;                             /* Adapter OPENED or CLOSED     */
+    int  chipset;                           /* DC21040, DC21041 or DC21140  */
+    s32  irq_mask;                          /* Interrupt Mask (Enable) bits */
+    s32  irq_en;                            /* Summary interrupt bits       */
+    int  media;                             /* Media (eg TP), mode (eg 100B)*/
+    int  c_media;                           /* Remember the last media conn */
+    int  fdx;                               /* media full duplex flag       */
+    int  linkOK;                            /* Link is OK                   */
+    int  autosense;                         /* Allow/disallow autosensing   */
+    int  tx_enable;                         /* Enable descriptor polling    */
+    int  setup_f;                           /* Setup frame filtering type   */
+    int  local_state;                       /* State within a 'media' state */
+    struct mii_phy phy[DE4X5_MAX_PHY];      /* List of attached PHY devices */
+    struct sia_phy sia;                     /* SIA PHY Information          */
+    int  active;                            /* Index to active PHY device   */
+    int  mii_cnt;                           /* Number of attached PHY's     */
+    int  timeout;                           /* Scheduling counter           */
+    struct timer_list timer;                /* Timer info for kernel        */
+    int tmp;                                /* Temporary global per card    */
+    struct {
+	void *priv;                         /* Original kmalloc'd mem addr  */
+	u_long lock;                        /* Lock the cache accesses      */
+	s32 csr0;                           /* Saved Bus Mode Register      */
+	s32 csr6;                           /* Saved Operating Mode Reg.    */
+	s32 csr7;                           /* Saved IRQ Mask Register      */
+	s32 gep;                            /* Saved General Purpose Reg.   */
+	s32 gepc;                           /* Control info for GEP         */
+	s32 csr13;                          /* Saved SIA Connectivity Reg.  */
+	s32 csr14;                          /* Saved SIA TX/RX Register     */
+	s32 csr15;                          /* Saved SIA General Register   */
+	int save_cnt;                       /* Flag if state already saved  */
+	struct sk_buff *skb;                /* Save the (re-ordered) skb's  */
+    } cache;
+    struct de4x5_srom srom;                 /* A copy of the SROM           */
+    struct net_device *next_module;             /* Link to the next module      */
+    int rx_ovf;                             /* Check for 'RX overflow' tag  */
+    int useSROM;                            /* For non-DEC card use SROM    */
+    int useMII;                             /* Infoblock using the MII      */
+    int asBitValid;                         /* Autosense bits in GEP?       */
+    int asPolarity;                         /* 0 => asserted high           */
+    int asBit;                              /* Autosense bit number in GEP  */
+    int defMedium;                          /* SROM default medium          */
+    int tcount;                             /* Last infoblock number        */
+    int infoblock_init;                     /* Initialised this infoblock?  */
+    int infoleaf_offset;                    /* SROM infoleaf for controller */
+    s32 infoblock_csr6;                     /* csr6 value in SROM infoblock */
+    int infoblock_media;                    /* infoblock media              */
+    int (*infoleaf_fn)(struct net_device *);    /* Pointer to infoleaf function */
+    u_char *rst;                            /* Pointer to Type 5 reset info */
+    u_char  ibn;                            /* Infoblock number             */
+    struct parameters params;               /* Command line/ #defined params */
+    struct pci_dev *pdev;		    /* Device cookie for DMA alloc  */
+    dma_addr_t dma_rings;		    /* DMA handle for rings	    */
+    int dma_size;			    /* Size of the DMA area	    */
+    char *rx_bufs;			    /* rx bufs on alpha, sparc, ... */
+};
+
+/*
+** Kludge to get around the fact that the CSR addresses have different
+** offsets in the PCI and EISA boards. Also note that the ethernet address
+** PROM is accessed differently.
+*/
+static struct bus_type {
+    int bus;
+    int bus_num;
+    int device;
+    int chipset;
+    struct de4x5_srom srom;
+    int autosense;
+    int useSROM;
+} bus;
+
+/*
+** To get around certain poxy cards that don't provide an SROM
+** for the second and more DECchip, I have to key off the first
+** chip's address. I'll assume there's not a bad SROM iff:
+**
+**      o the chipset is the same
+**      o the bus number is the same and > 0
+**      o the sum of all the returned hw address bytes is 0 or 0x5fa
+**
+** Also have to save the irq for those cards whose hardware designers
+** can't follow the PCI to PCI Bridge Architecture spec.
+*/
+static struct {
+    int chipset;
+    int bus;
+    int irq;
+    u_char addr[ETH_ALEN];
+} last = {0,};
+
+/*
+** The transmit ring full condition is described by the tx_old and tx_new
+** pointers by:
+**    tx_old            = tx_new    Empty ring
+**    tx_old            = tx_new+1  Full ring
+**    tx_old+txRingSize = tx_new+1  Full ring  (wrapped condition)
+*/
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+			lp->tx_old+lp->txRingSize-lp->tx_new-1:\
+			lp->tx_old               -lp->tx_new-1)
+
+#define TX_PKT_PENDING (lp->tx_old != lp->tx_new)
+
+/*
+** Public Functions
+*/
+static int     de4x5_open(struct net_device *dev);
+static int     de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev);
+static void    de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int     de4x5_close(struct net_device *dev);
+static struct  net_device_stats *de4x5_get_stats(struct net_device *dev);
+static void    de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len);
+static void    set_multicast_list(struct net_device *dev);
+static int     de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+
+/*
+** Private functions
+*/
+static int     de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev);
+static int     de4x5_init(struct net_device *dev);
+static int     de4x5_sw_reset(struct net_device *dev);
+static int     de4x5_rx(struct net_device *dev);
+static int     de4x5_tx(struct net_device *dev);
+static int     de4x5_ast(struct net_device *dev);
+static int     de4x5_txur(struct net_device *dev);
+static int     de4x5_rx_ovfc(struct net_device *dev);
+
+static int     autoconf_media(struct net_device *dev);
+static void    create_packet(struct net_device *dev, char *frame, int len);
+static void    load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb);
+static int     dc21040_autoconf(struct net_device *dev);
+static int     dc21041_autoconf(struct net_device *dev);
+static int     dc21140m_autoconf(struct net_device *dev);
+static int     dc2114x_autoconf(struct net_device *dev);
+static int     srom_autoconf(struct net_device *dev);
+static int     de4x5_suspect_state(struct net_device *dev, int timeout, int prev_state, int (*fn)(struct net_device *, int), int (*asfn)(struct net_device *));
+static int     dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct net_device *, int));
+static int     test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
+static int     test_for_100Mb(struct net_device *dev, int msec);
+static int     wait_for_link(struct net_device *dev);
+static int     test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec);
+static int     is_spd_100(struct net_device *dev);
+static int     is_100_up(struct net_device *dev);
+static int     is_10_up(struct net_device *dev);
+static int     is_anc_capable(struct net_device *dev);
+static int     ping_media(struct net_device *dev, int msec);
+static struct sk_buff *de4x5_alloc_rx_buff(struct net_device *dev, int index, int len);
+static void    de4x5_free_rx_buffs(struct net_device *dev);
+static void    de4x5_free_tx_buffs(struct net_device *dev);
+static void    de4x5_save_skbs(struct net_device *dev);
+static void    de4x5_rst_desc_ring(struct net_device *dev);
+static void    de4x5_cache_state(struct net_device *dev, int flag);
+static void    de4x5_put_cache(struct net_device *dev, struct sk_buff *skb);
+static void    de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb);
+static struct  sk_buff *de4x5_get_cache(struct net_device *dev);
+static void    de4x5_setup_intr(struct net_device *dev);
+static void    de4x5_init_connection(struct net_device *dev);
+static int     de4x5_reset_phy(struct net_device *dev);
+static void    reset_init_sia(struct net_device *dev, s32 sicr, s32 strr, s32 sigr);
+static int     test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec);
+static int     test_tp(struct net_device *dev, s32 msec);
+static int     EISA_signature(char *name, s32 eisa_id);
+static int     PCI_signature(char *name, struct bus_type *lp);
+static void    DevicePresent(u_long iobase);
+static void    enet_addr_rst(u_long aprom_addr);
+static int     de4x5_bad_srom(struct bus_type *lp);
+static short   srom_rd(u_long address, u_char offset);
+static void    srom_latch(u_int command, u_long address);
+static void    srom_command(u_int command, u_long address);
+static void    srom_address(u_int command, u_long address, u_char offset);
+static short   srom_data(u_int command, u_long address);
+/*static void    srom_busy(u_int command, u_long address);*/
+static void    sendto_srom(u_int command, u_long addr);
+static int     getfrom_srom(u_long addr);
+static int     srom_map_media(struct net_device *dev);
+static int     srom_infoleaf_info(struct net_device *dev);
+static void    srom_init(struct net_device *dev);
+static void    srom_exec(struct net_device *dev, u_char *p);
+static int     mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr);
+static void    mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr);
+static int     mii_rdata(u_long ioaddr);
+static void    mii_wdata(int data, int len, u_long ioaddr);
+static void    mii_ta(u_long rw, u_long ioaddr);
+static int     mii_swap(int data, int len);
+static void    mii_address(u_char addr, u_long ioaddr);
+static void    sendto_mii(u32 command, int data, u_long ioaddr);
+static int     getfrom_mii(u32 command, u_long ioaddr);
+static int     mii_get_oui(u_char phyaddr, u_long ioaddr);
+static int     mii_get_phy(struct net_device *dev);
+static void    SetMulticastFilter(struct net_device *dev);
+static int     get_hw_addr(struct net_device *dev);
+static void    srom_repair(struct net_device *dev, int card);
+static int     test_bad_enet(struct net_device *dev, int status);
+static int     an_exception(struct bus_type *lp);
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+static void    eisa_probe(struct net_device *dev, u_long iobase);
+#endif
+static void    pci_probe(struct net_device *dev, u_long iobase);
+static void    srom_search(struct pci_dev *pdev);
+static char    *build_setup_frame(struct net_device *dev, int mode);
+static void    disable_ast(struct net_device *dev);
+static void    enable_ast(struct net_device *dev, u32 time_out);
+static long    de4x5_switch_mac_port(struct net_device *dev);
+static int     gep_rd(struct net_device *dev);
+static void    gep_wr(s32 data, struct net_device *dev);
+static void    timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec);
+static void    yawn(struct net_device *dev, int state);
+static void    link_modules(struct net_device *dev, struct net_device *tmp);
+static void    de4x5_parse_params(struct net_device *dev);
+static void    de4x5_dbg_open(struct net_device *dev);
+static void    de4x5_dbg_mii(struct net_device *dev, int k);
+static void    de4x5_dbg_media(struct net_device *dev);
+static void    de4x5_dbg_srom(struct de4x5_srom *p);
+static void    de4x5_dbg_rx(struct sk_buff *skb, int len);
+static int     de4x5_strncmp(char *a, char *b, int n);
+static int     dc21041_infoleaf(struct net_device *dev);
+static int     dc21140_infoleaf(struct net_device *dev);
+static int     dc21142_infoleaf(struct net_device *dev);
+static int     dc21143_infoleaf(struct net_device *dev);
+static int     type0_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     type1_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     type2_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     type3_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     type4_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     type5_infoblock(struct net_device *dev, u_char count, u_char *p);
+static int     compact_infoblock(struct net_device *dev, u_char count, u_char *p);
+
+#ifdef MODULE
+int  init_module(void);
+void cleanup_module(void);
+static struct net_device *unlink_modules(struct net_device *p);
+static struct net_device *insert_device(struct net_device *dev, u_long iobase,
+				     int (*init)(struct net_device *));
+static int count_adapters(void);
+static int loading_module = 1;
+MODULE_PARM(de4x5_debug, "i");
+MODULE_PARM(dec_only, "i");
+MODULE_PARM(args, "s");
+MODULE_PARM_DESC(de4x5_debug, "de4x5 debug mask");
+MODULE_PARM_DESC(dec_only, "de4x5 probe only for Digital boards (0-1)");
+MODULE_PARM_DESC(args, "de4x5 full duplex and media type settings; see de4x5.c for details");
+MODULE_LICENSE("GPL");
+
+# else
+static int loading_module;
+#endif /* MODULE */
+
+static char name[DE4X5_NAME_LENGTH + 1];
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
+static int lastEISA;
+#  ifdef DE4X5_FORCE_EISA                 /* Force an EISA bus probe or not */
+static int forceEISA = 1;
+#  else
+static int forceEISA;
+#  endif
+#endif
+static int num_de4x5s;
+static int cfrv, useSROM;
+static int lastPCI = -1;
+static struct net_device *lastModule;
+static struct pci_dev *pdev;
+
+/*
+** List the SROM infoleaf functions and chipsets
+*/
+struct InfoLeaf {
+    int chipset;
+    int (*fn)(struct net_device *);
+};
+static struct InfoLeaf infoleaf_array[] = {
+    {DC21041, dc21041_infoleaf},
+    {DC21140, dc21140_infoleaf},
+    {DC21142, dc21142_infoleaf},
+    {DC21143, dc21143_infoleaf}
+};
+#define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *)))
+
+/*
+** List the SROM info block functions
+*/
+static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = {
+    type0_infoblock,
+    type1_infoblock,
+    type2_infoblock,
+    type3_infoblock,
+    type4_infoblock,
+    type5_infoblock,
+    compact_infoblock
+};
+
+#define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1)
+
+/*
+** Miscellaneous defines...
+*/
+#define RESET_DE4X5 {\
+    int i;\
+    i=inl(DE4X5_BMR);\
+    mdelay(1);\
+    outl(i | BMR_SWR, DE4X5_BMR);\
+    mdelay(1);\
+    outl(i, DE4X5_BMR);\
+    mdelay(1);\
+    for (i=0;i<5;i++) {inl(DE4X5_BMR); mdelay(1);}\
+    mdelay(1);\
+}
+
+#define PHY_HARD_RESET {\
+    outl(GEP_HRST, DE4X5_GEP);           /* Hard RESET the PHY dev. */\
+    mdelay(1);                           /* Assert for 1ms */\
+    outl(0x00, DE4X5_GEP);\
+    mdelay(2);                           /* Wait for 2ms */\
+}
+
+
+/*
+** Autoprobing in modules is allowed here. See the top of the file for
+** more info.
+*/
+int __init 
+de4x5_probe(struct net_device *dev)
+{
+    u_long iobase = dev->base_addr;
+
+    pci_probe(dev, iobase);
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+    if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) {
+        eisa_probe(dev, iobase);
+    }
+#endif
+    
+    return (dev->priv ? 0 : -ENODEV);
+}
+
+static int __init 
+de4x5_hw_init(struct net_device *dev, u_long iobase, struct pci_dev *pdev)
+{
+    struct bus_type *lp = &bus;
+    int i, status=0;
+    char *tmp;
+    
+    /* Ensure we're not sleeping */
+    if (lp->bus == EISA) {
+	outb(WAKEUP, PCI_CFPM);
+    } else {
+	pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				  PCI_CFDA_PSM, WAKEUP);
+    }
+    mdelay(10);
+
+    RESET_DE4X5;
+    
+    if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) != 0) {
+	return -ENXIO;                       /* Hardware could not reset */
+    }
+    
+    /* 
+    ** Now find out what kind of DC21040/DC21041/DC21140 board we have.
+    */
+    useSROM = FALSE;
+    if (lp->bus == PCI) {
+	PCI_signature(name, lp);
+    } else {
+	EISA_signature(name, EISA_ID0);
+    }
+    
+    if (*name == '\0') {                     /* Not found a board signature */
+	return -ENXIO;
+    }
+    
+    dev->base_addr = iobase;
+    if (lp->bus == EISA) {
+	printk("%s: %s at 0x%04lx (EISA slot %ld)", 
+	       dev->name, name, iobase, ((iobase>>12)&0x0f));
+    } else {                                 /* PCI port address */
+	printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name,
+	       iobase, lp->bus_num, lp->device);
+    }
+    
+    printk(", h/w address ");
+    status = get_hw_addr(dev);
+    for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
+	printk("%2.2x:", dev->dev_addr[i]);
+    }
+    printk("%2.2x,\n", dev->dev_addr[i]);
+    
+    if (status != 0) {
+	printk("      which has an Ethernet PROM CRC error.\n");
+	return -ENXIO;
+    } else {
+	struct de4x5_private *lp;
+	
+	/* 
+	** Reserve a section of kernel memory for the adapter
+	** private area and the TX/RX descriptor rings.
+	*/
+	dev->priv = (void *) kmalloc(sizeof(struct de4x5_private) + DE4X5_ALIGN, 
+				     GFP_KERNEL);
+	if (dev->priv == NULL) {
+	    return -ENOMEM;
+	}
+	
+	/*
+	** Align to a longword boundary
+	*/
+	tmp = dev->priv;
+	dev->priv = (void *)(((u_long)dev->priv + DE4X5_ALIGN) & ~DE4X5_ALIGN);
+	lp = (struct de4x5_private *)dev->priv;
+	memset(dev->priv, 0, sizeof(struct de4x5_private));
+	lp->bus = bus.bus;
+	lp->bus_num = bus.bus_num;
+	lp->device = bus.device;
+	lp->chipset = bus.chipset;
+	lp->cache.priv = tmp;
+	lp->cache.gepc = GEP_INIT;
+	lp->asBit = GEP_SLNK;
+	lp->asPolarity = GEP_SLNK;
+	lp->asBitValid = TRUE;
+	lp->timeout = -1;
+	lp->useSROM = useSROM;
+	lp->pdev = pdev;
+	memcpy((char *)&lp->srom,(char *)&bus.srom,sizeof(struct de4x5_srom));
+	lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+	de4x5_parse_params(dev);
+
+	/*
+	** Choose correct autosensing in case someone messed up
+	*/
+        lp->autosense = lp->params.autosense;
+        if (lp->chipset != DC21140) {
+            if ((lp->chipset==DC21040) && (lp->params.autosense&TP_NW)) {
+                lp->params.autosense = TP;
+            }
+            if ((lp->chipset==DC21041) && (lp->params.autosense&BNC_AUI)) {
+                lp->params.autosense = BNC;
+            }
+        }
+	lp->fdx = lp->params.fdx;
+	sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+
+	lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc);
+#if defined(__alpha__) || defined(__powerpc__) || defined(__sparc_v9__) || defined(DE4X5_DO_MEMCPY)
+	lp->dma_size += RX_BUFF_SZ * NUM_RX_DESC + DE4X5_ALIGN;
+#endif
+	lp->rx_ring = pci_alloc_consistent(pdev, lp->dma_size, &lp->dma_rings);
+	if (lp->rx_ring == NULL) {
+	    kfree(lp->cache.priv);
+	    lp->cache.priv = NULL;
+	    return -ENOMEM;
+	}
+
+	lp->tx_ring = lp->rx_ring + NUM_RX_DESC;
+	    
+	/*
+	** Set up the RX descriptor ring (Intels)
+	** Allocate contiguous receive buffers, long word aligned (Alphas) 
+	*/
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+	for (i=0; i<NUM_RX_DESC; i++) {
+	    lp->rx_ring[i].status = 0;
+	    lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+	    lp->rx_ring[i].buf = 0;
+	    lp->rx_ring[i].next = 0;
+	    lp->rx_skb[i] = (struct sk_buff *) 1;     /* Dummy entry */
+	}
+
+#else
+	{
+		dma_addr_t dma_rx_bufs;
+
+		dma_rx_bufs = lp->dma_rings + (NUM_RX_DESC + NUM_TX_DESC)
+		      	* sizeof(struct de4x5_desc);
+		dma_rx_bufs = (dma_rx_bufs + DE4X5_ALIGN) & ~DE4X5_ALIGN;
+		lp->rx_bufs = (char *)(((long)(lp->rx_ring + NUM_RX_DESC
+		      	+ NUM_TX_DESC) + DE4X5_ALIGN) & ~DE4X5_ALIGN);
+		for (i=0; i<NUM_RX_DESC; i++) {
+	    		lp->rx_ring[i].status = 0;
+	    		lp->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
+	    		lp->rx_ring[i].buf =
+				cpu_to_le32(dma_rx_bufs+i*RX_BUFF_SZ);
+	    		lp->rx_ring[i].next = 0;
+	    		lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */
+		}
+
+	}
+#endif
+
+	barrier();
+	    
+	request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE :
+				DE4X5_EISA_TOTAL_SIZE), 
+		       lp->adapter_name);
+	    
+	lp->rxRingSize = NUM_RX_DESC;
+	lp->txRingSize = NUM_TX_DESC;
+	    
+	/* Write the end of list marker to the descriptor lists */
+	lp->rx_ring[lp->rxRingSize - 1].des1 |= cpu_to_le32(RD_RER);
+	lp->tx_ring[lp->txRingSize - 1].des1 |= cpu_to_le32(TD_TER);
+
+	/* Tell the adapter where the TX/RX rings are located. */
+	outl(lp->dma_rings, DE4X5_RRBA);
+	outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
+	     DE4X5_TRBA);
+	    
+	/* Initialise the IRQ mask and Enable/Disable */
+	lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM;
+	lp->irq_en   = IMR_NIM | IMR_AIM;
+
+	/* Create a loopback packet frame for later media probing */
+	create_packet(dev, lp->frame, sizeof(lp->frame));
+
+	/* Check if the RX overflow bug needs testing for */
+	i = cfrv & 0x000000fe;
+	if ((lp->chipset == DC21140) && (i == 0x20)) {
+	    lp->rx_ovf = 1;
+	}
+
+	/* Initialise the SROM pointers if possible */
+	if (lp->useSROM) {
+	    lp->state = INITIALISED;
+	    if (srom_infoleaf_info(dev)) {
+		return -ENXIO;
+	    }
+	    srom_init(dev);
+	}
+
+	lp->state = CLOSED;
+
+	/*
+	** Check for an MII interface
+	*/
+	if ((lp->chipset != DC21040) && (lp->chipset != DC21041)) {
+	    mii_get_phy(dev);
+	}
+	
+#ifndef __sparc_v9__
+	printk("      and requires IRQ%d (provided by %s).\n", dev->irq,
+#else
+	printk("      and requires IRQ%x (provided by %s).\n", dev->irq,
+#endif
+	       ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG"));
+    }
+    
+    if (de4x5_debug & DEBUG_VERSION) {
+	printk(version);
+    }
+    
+    /* The DE4X5-specific entries in the device structure. */
+    dev->open = &de4x5_open;
+    dev->hard_start_xmit = &de4x5_queue_pkt;
+    dev->stop = &de4x5_close;
+    dev->get_stats = &de4x5_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    dev->do_ioctl = &de4x5_ioctl;
+    
+    dev->mem_start = 0;
+    
+    /* Fill in the generic fields of the device structure. */
+    ether_setup(dev);
+    
+    /* Let the adapter sleep to save power */
+    yawn(dev, SLEEP);
+    
+    return status;
+}
+
+
+static int
+de4x5_open(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int i, status = 0;
+    s32 omr;
+
+    /* Allocate the RX buffers */
+    for (i=0; i<lp->rxRingSize; i++) {
+	if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) {
+	    de4x5_free_rx_buffs(dev);
+	    return -EAGAIN;
+	}
+    }
+
+    /*
+    ** Wake up the adapter
+    */
+    yawn(dev, WAKEUP);
+
+    /* 
+    ** Re-initialize the DE4X5... 
+    */
+    status = de4x5_init(dev);
+    lp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+    lp->state = OPEN;
+    de4x5_dbg_open(dev);
+    
+    if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, 
+		                                     lp->adapter_name, dev)) {
+	printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
+	if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+			                             lp->adapter_name, dev)) {
+	    printk("\n              Cannot get IRQ- reconfigure your hardware.\n");
+	    disable_ast(dev);
+	    de4x5_free_rx_buffs(dev);
+	    de4x5_free_tx_buffs(dev);
+	    yawn(dev, SLEEP);
+	    lp->state = CLOSED;
+	    return -EAGAIN;
+	} else {
+	    printk("\n              Succeeded, but you should reconfigure your hardware to avoid this.\n");
+	    printk("WARNING: there may be IRQ related problems in heavily loaded systems.\n");
+	}
+    }
+
+    lp->interrupt = UNMASK_INTERRUPTS;
+    dev->trans_start = jiffies;
+    
+    START_DE4X5;
+	
+    de4x5_setup_intr(dev);
+    
+    if (de4x5_debug & DEBUG_OPEN) {
+	printk("\tsts:  0x%08x\n", inl(DE4X5_STS));
+	printk("\tbmr:  0x%08x\n", inl(DE4X5_BMR));
+	printk("\timr:  0x%08x\n", inl(DE4X5_IMR));
+	printk("\tomr:  0x%08x\n", inl(DE4X5_OMR));
+	printk("\tsisr: 0x%08x\n", inl(DE4X5_SISR));
+	printk("\tsicr: 0x%08x\n", inl(DE4X5_SICR));
+	printk("\tstrr: 0x%08x\n", inl(DE4X5_STRR));
+	printk("\tsigr: 0x%08x\n", inl(DE4X5_SIGR));
+    }
+    
+    MOD_INC_USE_COUNT;
+    
+    return status;
+}
+
+/*
+** Initialize the DE4X5 operating conditions. NB: a chip problem with the
+** DC21140 requires using perfect filtering mode for that chip. Since I can't
+** see why I'd want > 14 multicast addresses, I have changed all chips to use
+** the perfect filtering mode. Keep the DMA burst length at 8: there seems
+** to be data corruption problems if it is larger (UDP errors seen from a
+** ttcp source).
+*/
+static int
+de4x5_init(struct net_device *dev)
+{  
+    /* Lock out other processes whilst setting up the hardware */
+    netif_stop_queue(dev);
+    
+    de4x5_sw_reset(dev);
+    
+    /* Autoconfigure the connected port */
+    autoconf_media(dev);
+    
+    return 0;
+}
+
+static int
+de4x5_sw_reset(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int i, j, status = 0;
+    s32 bmr, omr;
+    
+    /* Select the MII or SRL port now and RESET the MAC */
+    if (!lp->useSROM) {
+	if (lp->phy[lp->active].id != 0) {
+	    lp->infoblock_csr6 = OMR_SDP | OMR_PS | OMR_HBD;
+	} else {
+	    lp->infoblock_csr6 = OMR_SDP | OMR_TTM;
+	}
+	de4x5_switch_mac_port(dev);
+    }
+
+    /* 
+    ** Set the programmable burst length to 8 longwords for all the DC21140
+    ** Fasternet chips and 4 longwords for all others: DMA errors result
+    ** without these values. Cache align 16 long.
+    */
+    bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | DE4X5_CACHE_ALIGN;
+    bmr |= ((lp->chipset & ~0x00ff)==DC2114x ? BMR_RML : 0);
+    outl(bmr, DE4X5_BMR);
+
+    omr = inl(DE4X5_OMR) & ~OMR_PR;             /* Turn off promiscuous mode */
+    if (lp->chipset == DC21140) {
+	omr |= (OMR_SDP | OMR_SB);
+    }
+    lp->setup_f = PERFECT;
+    outl(lp->dma_rings, DE4X5_RRBA);
+    outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
+	 DE4X5_TRBA);
+    
+    lp->rx_new = lp->rx_old = 0;
+    lp->tx_new = lp->tx_old = 0;
+    
+    for (i = 0; i < lp->rxRingSize; i++) {
+	lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+    }
+    
+    for (i = 0; i < lp->txRingSize; i++) {
+	lp->tx_ring[i].status = cpu_to_le32(0);
+    }
+    
+    barrier();
+
+    /* Build the setup frame depending on filtering mode */
+    SetMulticastFilter(dev);
+    
+    load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, (struct sk_buff *)1);
+    outl(omr|OMR_ST, DE4X5_OMR);
+
+    /* Poll for setup frame completion (adapter interrupts are disabled now) */
+    sti();                                       /* Ensure timer interrupts */
+    for (j=0, i=0;(i<500) && (j==0);i++) {       /* Upto 500ms delay */
+	mdelay(1);
+	if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1;
+    }
+    outl(omr, DE4X5_OMR);                        /* Stop everything! */
+
+    if (j == 0) {
+	printk("%s: Setup frame timed out, status %08x\n", dev->name, 
+	       inl(DE4X5_STS));
+	status = -EIO;
+    }
+    
+    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+    lp->tx_old = lp->tx_new;
+
+    return status;
+}
+
+/* 
+** Writes a socket buffer address to the next available transmit descriptor.
+*/
+static int
+de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int status = 0;
+    u_long flags = 0;
+
+    netif_stop_queue(dev);
+    if (lp->tx_enable == NO) {                   /* Cannot send for now */
+	return -1;                                
+    }
+    
+    /*
+    ** Clean out the TX ring asynchronously to interrupts - sometimes the
+    ** interrupts are lost by delayed descriptor status updates relative to
+    ** the irq assertion, especially with a busy PCI bus.
+    */
+    spin_lock_irqsave(&lp->lock, flags);
+    de4x5_tx(dev);
+    spin_unlock_irqrestore(&lp->lock, flags);
+
+    /* Test if cache is already locked - requeue skb if so */
+    if (test_and_set_bit(0, (void *)&lp->cache.lock) && !lp->interrupt) 
+	return -1;
+
+    /* Transmit descriptor ring full or stale skb */
+    if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) {
+	if (lp->interrupt) {
+	    de4x5_putb_cache(dev, skb);          /* Requeue the buffer */
+	} else {
+	    de4x5_put_cache(dev, skb);
+	}
+	if (de4x5_debug & DEBUG_TX) {
+	    printk("%s: transmit busy, lost media or stale skb found:\n  STS:%08x\n  tbusy:%d\n  IMR:%08x\n  OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), netif_queue_stopped(dev), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO");
+	}
+    } else if (skb->len > 0) {
+	/* If we already have stuff queued locally, use that first */
+	if (lp->cache.skb && !lp->interrupt) {
+	    de4x5_put_cache(dev, skb);
+	    skb = de4x5_get_cache(dev);
+	}
+
+	while (skb && !netif_queue_stopped(dev) &&
+	       (u_long) lp->tx_skb[lp->tx_new] <= 1) {
+	    spin_lock_irqsave(&lp->lock, flags);
+	    netif_stop_queue(dev);
+	    load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+ 	    lp->stats.tx_bytes += skb->len;
+	    outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */
+		
+	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+	    dev->trans_start = jiffies;
+		    
+	    if (TX_BUFFS_AVAIL) {
+		netif_start_queue(dev);         /* Another pkt may be queued */
+	    }
+	    skb = de4x5_get_cache(dev);
+	    spin_unlock_irqrestore(&lp->lock, flags);
+	}
+	if (skb) de4x5_putb_cache(dev, skb);
+    }
+    
+    lp->cache.lock = 0;
+
+    return status;
+}
+
+/*
+** The DE4X5 interrupt handler. 
+** 
+** I/O Read/Writes through intermediate PCI bridges are never 'posted',
+** so that the asserted interrupt always has some real data to work with -
+** if these I/O accesses are ever changed to memory accesses, ensure the
+** STS write is read immediately to complete the transaction if the adapter
+** is not on bus 0. Lost interrupts can still occur when the PCI bus load
+** is high and descriptor status bits cannot be set before the associated
+** interrupt is asserted and this routine entered.
+*/
+static void
+de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    struct de4x5_private *lp;
+    s32 imr, omr, sts, limit;
+    u_long iobase;
+    
+    if (dev == NULL) {
+	printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
+	return;
+    }
+    lp = (struct de4x5_private *)dev->priv;
+    spin_lock(&lp->lock);
+    iobase = dev->base_addr;
+	
+    DISABLE_IRQs;                        /* Ensure non re-entrancy */
+
+    if (test_and_set_bit(MASK_INTERRUPTS, (void*) &lp->interrupt))
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+    synchronize_irq();
+	
+    for (limit=0; limit<8; limit++) {
+	sts = inl(DE4X5_STS);            /* Read IRQ status */
+	outl(sts, DE4X5_STS);            /* Reset the board interrupts */
+	    
+	if (!(sts & lp->irq_mask)) break;/* All done */
+	    
+	if (sts & (STS_RI | STS_RU))     /* Rx interrupt (packet[s] arrived) */
+	  de4x5_rx(dev);
+	    
+	if (sts & (STS_TI | STS_TU))     /* Tx interrupt (packet sent) */
+	  de4x5_tx(dev); 
+	    
+	if (sts & STS_LNF) {             /* TP Link has failed */
+	    lp->irq_mask &= ~IMR_LFM;
+	}
+	    
+	if (sts & STS_UNF) {             /* Transmit underrun */
+	    de4x5_txur(dev);
+	}
+	    
+	if (sts & STS_SE) {              /* Bus Error */
+	    STOP_DE4X5;
+	    printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n",
+		   dev->name, sts);
+	    spin_unlock(&lp->lock);
+	    return;
+	}
+    }
+
+    /* Load the TX ring with any locally stored packets */
+    if (!test_and_set_bit(0, (void *)&lp->cache.lock)) {
+	while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) {
+	    de4x5_queue_pkt(de4x5_get_cache(dev), dev);
+	}
+	lp->cache.lock = 0;
+    }
+
+    lp->interrupt = UNMASK_INTERRUPTS;
+    ENABLE_IRQs;
+    spin_unlock(&lp->lock);
+    
+    return;
+}
+
+static int
+de4x5_rx(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int entry;
+    s32 status;
+    
+    for (entry=lp->rx_new; (s32)le32_to_cpu(lp->rx_ring[entry].status)>=0;
+	                                                    entry=lp->rx_new) {
+	status = (s32)le32_to_cpu(lp->rx_ring[entry].status);
+	
+	if (lp->rx_ovf) {
+	    if (inl(DE4X5_MFC) & MFC_FOCM) {
+		de4x5_rx_ovfc(dev);
+		break;
+	    }
+	}
+
+	if (status & RD_FS) {                 /* Remember the start of frame */
+	    lp->rx_old = entry;
+	}
+	
+	if (status & RD_LS) {                 /* Valid frame status */
+	    if (lp->tx_enable) lp->linkOK++;
+	    if (status & RD_ES) {	      /* There was an error. */
+		lp->stats.rx_errors++;        /* Update the error stats. */
+		if (status & (RD_RF | RD_TL)) lp->stats.rx_frame_errors++;
+		if (status & RD_CE)           lp->stats.rx_crc_errors++;
+		if (status & RD_OF)           lp->stats.rx_fifo_errors++;
+		if (status & RD_TL)           lp->stats.rx_length_errors++;
+		if (status & RD_RF)           lp->pktStats.rx_runt_frames++;
+		if (status & RD_CS)           lp->pktStats.rx_collision++;
+		if (status & RD_DB)           lp->pktStats.rx_dribble++;
+		if (status & RD_OF)           lp->pktStats.rx_overflow++;
+	    } else {                          /* A valid frame received */
+		struct sk_buff *skb;
+		short pkt_len = (short)(le32_to_cpu(lp->rx_ring[entry].status)
+					                            >> 16) - 4;
+		
+		if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) {
+		    printk("%s: Insufficient memory; nuking packet.\n", 
+			                                            dev->name);
+		    lp->stats.rx_dropped++;
+		} else {
+		    de4x5_dbg_rx(skb, pkt_len);
+
+		    /* Push up the protocol stack */
+		    skb->protocol=eth_type_trans(skb,dev);
+		    de4x5_local_stats(dev, skb->data, pkt_len);
+		    netif_rx(skb);
+		    
+		    /* Update stats */
+		    dev->last_rx = jiffies;
+		    lp->stats.rx_packets++;
+ 		    lp->stats.rx_bytes += pkt_len;
+		}
+	    }
+	    
+	    /* Change buffer ownership for this frame, back to the adapter */
+	    for (;lp->rx_old!=entry;lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
+		lp->rx_ring[lp->rx_old].status = cpu_to_le32(R_OWN);
+		barrier();
+	    }
+	    lp->rx_ring[entry].status = cpu_to_le32(R_OWN);
+	    barrier();
+	}
+	
+	/*
+	** Update entry information
+	*/
+	lp->rx_new = (++lp->rx_new) % lp->rxRingSize;
+    }
+    
+    return 0;
+}
+
+static inline void
+de4x5_free_tx_buff(struct de4x5_private *lp, int entry)
+{
+    pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf),
+		     le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1,
+		     PCI_DMA_TODEVICE);
+    if ((u_long) lp->tx_skb[entry] > 1)
+	dev_kfree_skb_irq(lp->tx_skb[entry]);
+    lp->tx_skb[entry] = NULL;
+}
+
+/*
+** Buffer sent - check for TX buffer errors.
+*/
+static int
+de4x5_tx(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int entry;
+    s32 status;
+    
+    for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+	status = (s32)le32_to_cpu(lp->tx_ring[entry].status);
+	if (status < 0) {                     /* Buffer not sent yet */
+	    break;
+	} else if (status != 0x7fffffff) {    /* Not setup frame */
+	    if (status & TD_ES) {             /* An error happened */
+		lp->stats.tx_errors++; 
+		if (status & TD_NC) lp->stats.tx_carrier_errors++;
+		if (status & TD_LC) lp->stats.tx_window_errors++;
+		if (status & TD_UF) lp->stats.tx_fifo_errors++;
+		if (status & TD_EC) lp->pktStats.excessive_collisions++;
+		if (status & TD_DE) lp->stats.tx_aborted_errors++;
+	    
+		if (TX_PKT_PENDING) {
+		    outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */
+		}
+	    } else {                      /* Packet sent */
+		lp->stats.tx_packets++;
+		if (lp->tx_enable) lp->linkOK++;
+	    }
+	    /* Update the collision counter */
+	    lp->stats.collisions += ((status & TD_EC) ? 16 : 
+				                      ((status & TD_CC) >> 3));
+
+	    /* Free the buffer. */
+	    if (lp->tx_skb[entry] != NULL)
+	    	de4x5_free_tx_buff(lp, entry);
+	}
+	
+	/* Update all the pointers */
+	lp->tx_old = (++lp->tx_old) % lp->txRingSize;
+    }
+
+    /* Any resources available? */
+    if (TX_BUFFS_AVAIL && netif_queue_stopped(dev)) {
+	if (lp->interrupt)
+	    netif_wake_queue(dev);
+	else
+	    netif_start_queue(dev);
+    }
+	
+    return 0;
+}
+
+static int
+de4x5_ast(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    
+    disable_ast(dev);
+    
+    if (lp->useSROM) {
+	next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21140) {
+	next_tick = dc21140m_autoconf(dev);
+    } else if (lp->chipset == DC21041) {
+	next_tick = dc21041_autoconf(dev);
+    } else if (lp->chipset == DC21040) {
+	next_tick = dc21040_autoconf(dev);
+    }
+    lp->linkOK = 0;
+    enable_ast(dev, next_tick);
+    
+    return 0;
+}
+
+static int
+de4x5_txur(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int omr;
+
+    omr = inl(DE4X5_OMR);
+    if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) {
+	omr &= ~(OMR_ST|OMR_SR);
+	outl(omr, DE4X5_OMR);
+	while (inl(DE4X5_STS) & STS_TS);
+	if ((omr & OMR_TR) < OMR_TR) {
+	    omr += 0x4000;
+	} else {
+	    omr |= OMR_SF;
+	}
+	outl(omr | OMR_ST | OMR_SR, DE4X5_OMR);
+    }
+    
+    return 0;
+}
+
+static int 
+de4x5_rx_ovfc(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int omr;
+
+    omr = inl(DE4X5_OMR);
+    outl(omr & ~OMR_SR, DE4X5_OMR);
+    while (inl(DE4X5_STS) & STS_RS);
+
+    for (; (s32)le32_to_cpu(lp->rx_ring[lp->rx_new].status)>=0;) {
+	lp->rx_ring[lp->rx_new].status = cpu_to_le32(R_OWN);
+	lp->rx_new = (++lp->rx_new % lp->rxRingSize);
+    }
+
+    outl(omr, DE4X5_OMR);
+    
+    return 0;
+}
+
+static int
+de4x5_close(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 imr, omr;
+    
+    disable_ast(dev);
+
+    netif_stop_queue(dev);
+    
+    if (de4x5_debug & DEBUG_CLOSE) {
+	printk("%s: Shutting down ethercard, status was %8.8x.\n",
+	       dev->name, inl(DE4X5_STS));
+    }
+    
+    /* 
+    ** We stop the DE4X5 here... mask interrupts and stop TX & RX
+    */
+    DISABLE_IRQs;
+    STOP_DE4X5;
+    
+    /* Free the associated irq */
+    free_irq(dev->irq, dev);
+    lp->state = CLOSED;
+
+    /* Free any socket buffers */
+    de4x5_free_rx_buffs(dev);
+    de4x5_free_tx_buffs(dev);
+    
+    MOD_DEC_USE_COUNT;
+    
+    /* Put the adapter to sleep to save power */
+    yawn(dev, SLEEP);
+    
+    return 0;
+}
+
+static struct net_device_stats *
+de4x5_get_stats(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    
+    lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
+    
+    return &lp->stats;
+}
+
+static void
+de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
+        if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
+	    lp->pktStats.bins[i]++;
+	    i = DE4X5_PKT_STAT_SZ;
+	}
+    }
+    if (buf[0] & 0x01) {          /* Multicast/Broadcast */
+        if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
+	    lp->pktStats.broadcast++;
+	} else {
+	    lp->pktStats.multicast++;
+	}
+    } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+	       (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
+        lp->pktStats.unicast++;
+    }
+		
+    lp->pktStats.bins[0]++;       /* Duplicates stats.rx_packets */
+    if (lp->pktStats.bins[0] == 0) { /* Reset counters */
+        memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
+    }
+
+    return;
+}
+
+/*
+** Removes the TD_IC flag from previous descriptor to improve TX performance.
+** If the flag is changed on a descriptor that is being read by the hardware,
+** I assume PCI transaction ordering will mean you are either successful or
+** just miss asserting the change to the hardware. Anyway you're messing with
+** a descriptor you don't own, but this shouldn't kill the chip provided
+** the descriptor register is read only to the hardware.
+*/
+static void
+load_packet(struct net_device *dev, char *buf, u32 flags, struct sk_buff *skb)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1);
+    dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1, PCI_DMA_TODEVICE);
+
+    lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma);
+    lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER);
+    lp->tx_ring[lp->tx_new].des1 |= cpu_to_le32(flags);
+    lp->tx_skb[lp->tx_new] = skb;
+    lp->tx_ring[entry].des1 &= cpu_to_le32(~TD_IC);
+    barrier();
+
+    lp->tx_ring[lp->tx_new].status = cpu_to_le32(T_OWN);
+    barrier();
+}
+
+/*
+** Set or clear the multicast filter for this adaptor.
+*/
+static void
+set_multicast_list(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    /* First, double check that the adapter is open */
+    if (lp->state == OPEN) {
+	if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */
+	    u32 omr;
+	    omr = inl(DE4X5_OMR);
+	    omr |= OMR_PR;
+	    outl(omr, DE4X5_OMR);
+	} else { 
+	    SetMulticastFilter(dev);
+	    load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+			                                SETUP_FRAME_LEN, (struct sk_buff *)1);
+	    
+	    lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+	    outl(POLL_DEMAND, DE4X5_TPD);       /* Start the TX */
+	    dev->trans_start = jiffies;
+	}
+    }
+    
+    return;
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Little endian crc one liner from Matt Thomas, DEC.
+*/
+static void
+SetMulticastFilter(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct dev_mc_list *dmi=dev->mc_list;
+    u_long iobase = dev->base_addr;
+    int i, j, bit, byte;
+    u16 hashcode;
+    u32 omr, crc;
+    char *pa;
+    unsigned char *addrs;
+
+    omr = inl(DE4X5_OMR);
+    omr &= ~(OMR_PR | OMR_PM);
+    pa = build_setup_frame(dev, ALL);        /* Build the basic frame */
+    
+    if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 14)) {
+	omr |= OMR_PM;                       /* Pass all multicasts */
+    } else if (lp->setup_f == HASH_PERF) {   /* Hash Filtering */
+	for (i=0;i<dev->mc_count;i++) {      /* for each address in the list */
+	    addrs=dmi->dmi_addr;
+	    dmi=dmi->next;
+	    if ((*addrs & 0x01) == 1) {      /* multicast address? */ 
+		crc = ether_crc_le(ETH_ALEN, addrs);
+		hashcode = crc & HASH_BITS;  /* hashcode is 9 LSb of CRC */
+		
+		byte = hashcode >> 3;        /* bit[3-8] -> byte in filter */
+		bit = 1 << (hashcode & 0x07);/* bit[0-2] -> bit in byte */
+		
+		byte <<= 1;                  /* calc offset into setup frame */
+		if (byte & 0x02) {
+		    byte -= 1;
+		}
+		lp->setup_frame[byte] |= bit;
+	    }
+	}
+    } else {                                 /* Perfect filtering */
+	for (j=0; j<dev->mc_count; j++) {
+	    addrs=dmi->dmi_addr;
+	    dmi=dmi->next;
+	    for (i=0; i<ETH_ALEN; i++) { 
+		*(pa + (i&1)) = *addrs++;
+		if (i & 0x01) pa += 4;
+	    }
+	}
+    }
+    outl(omr, DE4X5_OMR);
+    
+    return;
+}
+
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+/*
+** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
+** the motherboard. Upto 15 EISA devices are supported.
+*/
+static void __init 
+eisa_probe(struct net_device *dev, u_long ioaddr)
+{
+    int i, maxSlots, status, device;
+    u_char irq;
+    u_short vendor;
+    u32 cfid;
+    u_long iobase;
+    struct bus_type *lp = &bus;
+    char name[DE4X5_STRLEN];
+
+    if (lastEISA == MAX_EISA_SLOTS) return;/* No more EISA devices to search */
+
+    lp->bus = EISA;
+    
+    if (ioaddr == 0) {                     /* Autoprobing */
+	iobase = EISA_SLOT_INC;            /* Get the first slot address */
+	i = 1;
+	maxSlots = MAX_EISA_SLOTS;
+    } else {                               /* Probe a specific location */
+	iobase = ioaddr;
+	i = (ioaddr >> 12);
+	maxSlots = i + 1;
+    }
+    
+    for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue;
+	if (!EISA_signature(name, EISA_ID)) continue;
+
+	cfid = (u32) inl(PCI_CFID);
+	cfrv = (u_short) inl(PCI_CFRV);
+	device = (cfid >> 8) & 0x00ffff00;
+	vendor = (u_short) cfid;
+	    
+	/* Read the EISA Configuration Registers */
+	irq = inb(EISA_REG0);
+	irq = de4x5_irq[(irq >> 1) & 0x03];
+
+	if (is_DC2114x) {
+	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+	}
+	lp->chipset = device;
+
+	/* Write the PCI Configuration Registers */
+	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
+	outl(0x00006000, PCI_CFLT);
+	outl(iobase, PCI_CBIO);
+	    
+	DevicePresent(EISA_APROM);
+
+	dev->irq = irq;
+	if ((status = de4x5_hw_init(dev, iobase, NULL)) == 0) {
+	    num_de4x5s++;
+	    if (loading_module) link_modules(lastModule, dev);
+	    lastEISA = i;
+	    return;
+	}
+    }
+
+    if (ioaddr == 0) lastEISA = i;
+
+    return;
+}
+#endif          /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__) */
+
+/*
+** PCI bus I/O device probe
+** NB: PCI I/O accesses and Bus Mastering are enabled by the PCI BIOS, not
+** the driver. Some PCI BIOS's, pre V2.1, need the slot + features to be
+** enabled by the user first in the set up utility. Hence we just check for
+** enabled features and silently ignore the card if they're not.
+**
+** STOP PRESS: Some BIOS's __require__ the driver to enable the bus mastering
+** bit. Here, check for I/O accesses and then set BM. If you put the card in
+** a non BM slot, you're on your own (and complain to the PC vendor that your
+** PC doesn't conform to the PCI standard)!
+**
+** This function is only compatible with the *latest* 2.1.x kernels. For 2.0.x
+** kernels use the V0.535[n] drivers.
+*/
+#define PCI_LAST_DEV  32
+
+static void __init 
+pci_probe(struct net_device *dev, u_long ioaddr)
+{
+    u_char pb, pbus, dev_num, dnum, timer;
+    u_short vendor, index, status;
+    u_int irq = 0, device, class = DE4X5_CLASS_CODE;
+    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
+    struct bus_type *lp = &bus;
+
+    if (lastPCI == NO_MORE_PCI) return;
+
+    if (!pcibios_present()) {
+	lastPCI = NO_MORE_PCI;
+	return;          /* No PCI bus in this machine! */
+    }
+    
+    lp->bus = PCI;
+    lp->bus_num = 0;
+
+    if ((ioaddr < 0x1000) && loading_module) {
+	pbus = (u_short)(ioaddr >> 8);
+	dnum = (u_short)(ioaddr & 0xff);
+    } else {
+	pbus = 0;
+	dnum = 0;
+    }
+
+    for (index=lastPCI+1;(pdev = pci_find_class(class, pdev))!=NULL;index++) {
+	dev_num = PCI_SLOT(pdev->devfn);
+	pb = pdev->bus->number;
+	if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue;
+
+	vendor = pdev->vendor;
+	device = pdev->device << 8;
+	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
+
+	/* Search for an SROM on this bus */
+	if (lp->bus_num != pb) {
+	    lp->bus_num = pb;
+	    srom_search(pdev);
+	}
+
+	/* Get the chip configuration revision register */
+	pcibios_read_config_dword(pb, pdev->devfn, PCI_REVISION_ID, &cfrv);
+
+	/* Set the device number information */
+	lp->device = dev_num;
+	lp->bus_num = pb;
+	    
+	/* Set the chipset information */
+	if (is_DC2114x) {
+	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+	}
+	lp->chipset = device;
+
+	/* Get the board I/O address (64 bits on sparc64) */
+	iobase = pci_resource_start(pdev, 0);
+
+	/* Fetch the IRQ to be used */
+	irq = pdev->irq;
+	if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+	    
+	/* Check if I/O accesses and Bus Mastering are enabled */
+	pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
+#ifdef __powerpc__
+	if (!(status & PCI_COMMAND_IO)) {
+	    status |= PCI_COMMAND_IO;
+	    pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
+	    pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
+	}
+#endif /* __powerpc__ */
+	if (!(status & PCI_COMMAND_IO)) continue;
+
+	if (!(status & PCI_COMMAND_MASTER)) {
+	    status |= PCI_COMMAND_MASTER;
+	    pcibios_write_config_word(pb, pdev->devfn, PCI_COMMAND, status);
+	    pcibios_read_config_word(pb, pdev->devfn, PCI_COMMAND, &status);
+	}
+	if (!(status & PCI_COMMAND_MASTER)) continue;
+
+	/* Check the latency timer for values >= 0x60 */
+	pcibios_read_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, &timer);
+	if (timer < 0x60) {
+	    pcibios_write_config_byte(pb, pdev->devfn, PCI_LATENCY_TIMER, 0x60);
+	}
+
+	DevicePresent(DE4X5_APROM);
+	if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+	    dev->irq = irq;
+	    if ((status = de4x5_hw_init(dev, iobase, pdev)) == 0) {
+		num_de4x5s++;
+		lastPCI = index;
+		if (loading_module) link_modules(lastModule, dev);
+		return;
+	    }
+	} else if (ioaddr != 0) {
+	    printk("%s: region already allocated at 0x%04lx.\n", dev->name,
+		   iobase);
+	}
+    }
+
+    lastPCI = NO_MORE_PCI;
+
+    return;
+}
+
+/*
+** This function searches the current bus (which is >0) for a DECchip with an
+** SROM, so that in multiport cards that have one SROM shared between multiple 
+** DECchips, we can find the base SROM irrespective of the BIOS scan direction.
+** For single port cards this is a time waster...
+*/
+static void __init 
+srom_search(struct pci_dev *dev)
+{
+    u_char pb;
+    u_short vendor, status;
+    u_int irq = 0, device;
+    u_long iobase = 0;                     /* Clear upper 32 bits in Alphas */
+    int i, j;
+    struct bus_type *lp = &bus;
+    struct list_head *walk = &dev->bus_list;
+
+    for (walk = walk->next; walk != &dev->bus_list; walk = walk->next) {
+	struct pci_dev *this_dev = pci_dev_b(walk);
+
+	/* Skip the pci_bus list entry */
+	if (list_entry(walk, struct pci_bus, devices) == dev->bus) continue;
+
+	vendor = this_dev->vendor;
+	device = this_dev->device << 8;
+	if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue;
+
+	/* Get the chip configuration revision register */
+	pb = this_dev->bus->number;
+	pcibios_read_config_dword(pb, this_dev->devfn, PCI_REVISION_ID, &cfrv);
+
+	/* Set the device number information */
+	lp->device = PCI_SLOT(this_dev->devfn);
+	lp->bus_num = pb;
+	    
+	/* Set the chipset information */
+	if (is_DC2114x) {
+	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+	}
+	lp->chipset = device;
+
+	/* Get the board I/O address (64 bits on sparc64) */
+	iobase = pci_resource_start(this_dev, 0);
+
+	/* Fetch the IRQ to be used */
+	irq = this_dev->irq;
+	if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue;
+	    
+	/* Check if I/O accesses are enabled */
+	pcibios_read_config_word(pb, this_dev->devfn, PCI_COMMAND, &status);
+	if (!(status & PCI_COMMAND_IO)) continue;
+
+	/* Search for a valid SROM attached to this DECchip */
+	DevicePresent(DE4X5_APROM);
+	for (j=0, i=0; i<ETH_ALEN; i++) {
+	    j += (u_char) *((u_char *)&lp->srom + SROM_HWADD + i);
+	}
+	if ((j != 0) && (j != 0x5fa)) {
+	    last.chipset = device;
+	    last.bus = pb;
+	    last.irq = irq;
+	    for (i=0; i<ETH_ALEN; i++) {
+		last.addr[i] = (u_char)*((u_char *)&lp->srom + SROM_HWADD + i);
+	    }
+	    return;
+	}
+    }
+
+    return;
+}
+
+static void __init 
+link_modules(struct net_device *dev, struct net_device *tmp)
+{
+    struct net_device *p=dev;
+
+    if (p) {
+	while (((struct de4x5_private *)(p->priv))->next_module) {
+	    p = ((struct de4x5_private *)(p->priv))->next_module;
+	}
+
+	if (dev != tmp) {
+	    ((struct de4x5_private *)(p->priv))->next_module = tmp;
+	} else {
+	    ((struct de4x5_private *)(p->priv))->next_module = NULL;
+	}
+    }
+
+    return;
+}
+
+/*
+** Auto configure the media here rather than setting the port at compile
+** time. This routine is called by de4x5_init() and when a loss of media is
+** detected (excessive collisions, loss of carrier, no carrier or link fail
+** [TP] or no recent receive activity) to check whether the user has been 
+** sneaky and changed the port on us.
+*/
+static int
+autoconf_media(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    lp->linkOK = 0;
+    lp->c_media = AUTO;                     /* Bogus last media */
+    disable_ast(dev);
+    inl(DE4X5_MFC);                         /* Zero the lost frames counter */
+    lp->media = INIT;
+    lp->tcount = 0;
+
+    if (lp->useSROM) {
+	next_tick = srom_autoconf(dev);
+    } else if (lp->chipset == DC21040) {
+	next_tick = dc21040_autoconf(dev);
+    } else if (lp->chipset == DC21041) {
+	next_tick = dc21041_autoconf(dev);
+    } else if (lp->chipset == DC21140) {
+	next_tick = dc21140m_autoconf(dev);
+    }
+
+    enable_ast(dev, next_tick);
+    
+    return (lp->media);
+}
+
+/*
+** Autoconfigure the media when using the DC21040. AUI cannot be distinguished
+** from BNC as the port has a jumper to set thick or thin wire. When set for
+** BNC, the BNC port will indicate activity if it's not terminated correctly.
+** The only way to test for that is to place a loopback packet onto the
+** network and watch for errors. Since we're messing with the interrupt mask
+** register, disable the board interrupts and do not allow any more packets to
+** be queued to the hardware. Re-enable everything only when the media is
+** found.
+** I may have to "age out" locally queued packets so that the higher layer
+** timeouts don't effectively duplicate packets on the network.
+*/
+static int
+dc21040_autoconf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    s32 imr;
+    
+    switch (lp->media) {
+    case INIT:
+	DISABLE_IRQs;
+	lp->tx_enable = NO;
+	lp->timeout = -1;
+	de4x5_save_skbs(dev);
+	if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
+	    lp->media = TP;
+	} else if ((lp->autosense == BNC) || (lp->autosense == AUI) || (lp->autosense == BNC_AUI)) {
+	    lp->media = BNC_AUI;
+	} else if (lp->autosense == EXT_SIA) {
+	    lp->media = EXT_SIA;
+	} else {
+	    lp->media = NC;
+	}
+	lp->local_state = 0;
+	next_tick = dc21040_autoconf(dev);
+	break;
+	
+    case TP:
+	next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, 
+		                                         TP_SUSPECT, test_tp);
+	break;
+	
+    case TP_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf);
+	break;
+	
+    case BNC:
+    case AUI:
+    case BNC_AUI:
+	next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, 
+		                                  BNC_AUI_SUSPECT, ping_media);
+	break;
+	
+    case BNC_AUI_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf);
+	break;
+	
+    case EXT_SIA:
+	next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, 
+		                              NC, EXT_SIA_SUSPECT, ping_media);
+	break;
+	
+    case EXT_SIA_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf);
+	break;
+	
+    case NC:
+	/* default to TP for all */
+	reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tx_enable = NO;
+	break;
+    }
+    
+    return next_tick;
+}
+
+static int
+dc21040_state(struct net_device *dev, int csr13, int csr14, int csr15, int timeout,
+	      int next_state, int suspect_state, 
+	      int (*fn)(struct net_device *, int))
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    int linkBad;
+
+    switch (lp->local_state) {
+    case 0:
+	reset_init_sia(dev, csr13, csr14, csr15);
+	lp->local_state++;
+	next_tick = 500;
+	break;
+	    
+    case 1:
+	if (!lp->tx_enable) {
+	    linkBad = fn(dev, timeout);
+	    if (linkBad < 0) {
+		next_tick = linkBad & ~TIMER_CB;
+	    } else {
+		if (linkBad && (lp->autosense == AUTO)) {
+		    lp->local_state = 0;
+		    lp->media = next_state;
+		} else {
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = suspect_state;
+	    next_tick = 3000;
+	}
+	break;
+    }
+    
+    return next_tick;
+}
+
+static int
+de4x5_suspect_state(struct net_device *dev, int timeout, int prev_state,
+		      int (*fn)(struct net_device *, int),
+		      int (*asfn)(struct net_device *))
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    int linkBad;
+
+    switch (lp->local_state) {
+    case 1:
+	if (lp->linkOK) {
+	    lp->media = prev_state;
+	} else {
+	    lp->local_state++;
+	    next_tick = asfn(dev);
+	}
+	break;
+
+    case 2:
+	linkBad = fn(dev, timeout);
+	if (linkBad < 0) {
+	    next_tick = linkBad & ~TIMER_CB;
+	} else if (!linkBad) {
+	    lp->local_state--;
+	    lp->media = prev_state;
+	} else {
+	    lp->media = INIT;
+	    lp->tcount++;
+	}
+    }
+
+    return next_tick;
+}
+
+/*
+** Autoconfigure the media when using the DC21041. AUI needs to be tested
+** before BNC, because the BNC port will indicate activity if it's not
+** terminated correctly. The only way to test for that is to place a loopback
+** packet onto the network and watch for errors. Since we're messing with
+** the interrupt mask register, disable the board interrupts and do not allow
+** any more packets to be queued to the hardware. Re-enable everything only
+** when the media is found.
+*/
+static int
+dc21041_autoconf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 sts, irqs, irq_mask, imr, omr;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    
+    switch (lp->media) {
+    case INIT:
+	DISABLE_IRQs;
+	lp->tx_enable = NO;
+	lp->timeout = -1;
+	de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+	if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
+	    lp->media = TP;            /* On chip auto negotiation is broken */
+	} else if (lp->autosense == TP) {
+	    lp->media = TP;
+	} else if (lp->autosense == BNC) {
+	    lp->media = BNC;
+	} else if (lp->autosense == AUI) {
+	    lp->media = AUI;
+	} else {
+	    lp->media = NC;
+	}
+	lp->local_state = 0;
+	next_tick = dc21041_autoconf(dev);
+	break;
+	
+    case TP_NW:
+	if (lp->timeout < 0) {
+	    omr = inl(DE4X5_OMR);/* Set up full duplex for the autonegotiate */
+	    outl(omr | OMR_FDX, DE4X5_OMR);
+	}
+	irqs = STS_LNF | STS_LNP;
+	irq_mask = IMR_LFM | IMR_LPM;
+	sts = test_media(dev, irqs, irq_mask, 0xef01, 0xffff, 0x0008, 2400);
+	if (sts < 0) {
+	    next_tick = sts & ~TIMER_CB;
+	} else {
+	    if (sts & STS_LNP) {
+		lp->media = ANS;
+	    } else {
+		lp->media = AUI;
+	    }
+	    next_tick = dc21041_autoconf(dev);
+	}
+	break;
+	
+    case ANS:
+	if (!lp->tx_enable) {
+	    irqs = STS_LNP;
+	    irq_mask = IMR_LPM;
+	    sts = test_ans(dev, irqs, irq_mask, 3000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+		    lp->media = TP;
+		    next_tick = dc21041_autoconf(dev);
+		} else {
+		    lp->local_state = 1;
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = ANS_SUSPECT;
+	    next_tick = 3000;
+	}
+	break;
+	
+    case ANS_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf);
+	break;
+	
+    case TP:
+	if (!lp->tx_enable) {
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for TP */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = STS_LNF | STS_LNP;
+	    irq_mask = IMR_LFM | IMR_LPM;
+	    sts = test_media(dev,irqs, irq_mask, 0xef01, 0xff3f, 0x0008, 2400);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		if (!(sts & STS_LNP) && (lp->autosense == AUTO)) {
+		    if (inl(DE4X5_SISR) & SISR_NRA) {
+			lp->media = AUI;       /* Non selected port activity */
+		    } else {
+			lp->media = BNC;
+		    }
+		    next_tick = dc21041_autoconf(dev);
+		} else {
+		    lp->local_state = 1;
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = TP_SUSPECT;
+	    next_tick = 3000;
+	}
+	break;
+	
+    case TP_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf);
+	break;
+	
+    case AUI:
+	if (!lp->tx_enable) {
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for AUI */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+		    lp->media = BNC;
+		    next_tick = dc21041_autoconf(dev);
+		} else {
+		    lp->local_state = 1;
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = AUI_SUSPECT;
+	    next_tick = 3000;
+	}
+	break;
+	
+    case AUI_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf);
+	break;
+	
+    case BNC:
+	switch (lp->local_state) {
+	case 0:
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		lp->local_state++;             /* Ensure media connected */
+		next_tick = dc21041_autoconf(dev);
+	    }
+	    break;
+	    
+	case 1:
+	    if (!lp->tx_enable) {
+		if ((sts = ping_media(dev, 3000)) < 0) {
+		    next_tick = sts & ~TIMER_CB;
+		} else {
+		    if (sts) {
+			lp->local_state = 0;
+			lp->media = NC;
+		    } else {
+			de4x5_init_connection(dev);
+		    }
+		}
+	    } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+		lp->media = BNC_SUSPECT;
+		next_tick = 3000;
+	    }
+	    break;
+	}
+	break;
+	
+    case BNC_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf);
+	break;
+	
+    case NC:
+	omr = inl(DE4X5_OMR);    /* Set up full duplex for the autonegotiate */
+	outl(omr | OMR_FDX, DE4X5_OMR);
+	reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */
+	if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tx_enable = NO;
+	break;
+    }
+    
+    return next_tick;
+}
+
+/*
+** Some autonegotiation chips are broken in that they do not return the
+** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement
+** register, except at the first power up negotiation.
+*/
+static int
+dc21140m_autoconf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int ana, anlpa, cap, cr, slnk, sr;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+    u_long imr, omr, iobase = dev->base_addr;
+    
+    switch(lp->media) {
+    case INIT: 
+        if (lp->timeout < 0) {
+	    DISABLE_IRQs;
+	    lp->tx_enable = FALSE;
+	    lp->linkOK = 0;
+	    de4x5_save_skbs(dev);          /* Save non transmitted skb's */
+	}
+	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+	    next_tick &= ~TIMER_CB;
+	} else {
+	    if (lp->useSROM) {
+		if (srom_map_media(dev) < 0) {
+		    lp->tcount++;
+		    return next_tick;
+		}
+		srom_exec(dev, lp->phy[lp->active].gep);
+		if (lp->infoblock_media == ANS) {
+		    ana = lp->phy[lp->active].ana | MII_ANA_CSMA;
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		}
+	    } else {
+		lp->tmp = MII_SR_ASSC;     /* Fake out the MII speed set */
+		SET_10Mb;
+		if (lp->autosense == _100Mb) {
+		    lp->media = _100Mb;
+		} else if (lp->autosense == _10Mb) {
+		    lp->media = _10Mb;
+		} else if ((lp->autosense == AUTO) && 
+			            ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    lp->media = ANS;
+		} else if (lp->autosense == AUTO) {
+		    lp->media = SPD_DET;
+		} else if (is_spd_100(dev) && is_100_up(dev)) {
+		    lp->media = _100Mb;
+		} else {
+		    lp->media = NC;
+		}
+	    }
+	    lp->local_state = 0;
+	    next_tick = dc21140m_autoconf(dev);
+	}
+	break;
+	
+    case ANS:
+	switch (lp->local_state) {
+	case 0:
+	    if (lp->timeout < 0) {
+		mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+	    }
+	    cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+	    if (cr < 0) {
+		next_tick = cr & ~TIMER_CB;
+	    } else {
+		if (cr) {
+		    lp->local_state = 0;
+		    lp->media = SPD_DET;
+		} else {
+		    lp->local_state++;
+		}
+		next_tick = dc21140m_autoconf(dev);
+	    }
+	    break;
+	    
+	case 1:
+	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+		next_tick = sr & ~TIMER_CB;
+	    } else {
+		lp->media = SPD_DET;
+		lp->local_state = 0;
+		if (sr) {                         /* Success! */
+		    lp->tmp = MII_SR_ASSC;
+		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    if (!(anlpa & MII_ANLPA_RF) && 
+			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
+			if (cap & MII_ANA_100M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+			    lp->media = _100Mb;
+			} else if (cap & MII_ANA_10M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+
+			    lp->media = _10Mb;
+			}
+		    }
+		}                       /* Auto Negotiation failed to finish */
+		next_tick = dc21140m_autoconf(dev);
+	    }                           /* Auto Negotiation failed to start */
+	    break;
+	}
+	break;
+	
+    case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+        if (lp->timeout < 0) {
+	    lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : 
+		                                  (~gep_rd(dev) & GEP_LNP));
+	    SET_100Mb_PDET;
+	}
+        if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+	    next_tick = slnk & ~TIMER_CB;
+	} else {
+	    if (is_spd_100(dev) && is_100_up(dev)) {
+		lp->media = _100Mb;
+	    } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) {
+		lp->media = _10Mb;
+	    } else {
+		lp->media = NC;
+	    }
+	    next_tick = dc21140m_autoconf(dev);
+	}
+	break;
+	
+    case _100Mb:                               /* Set 100Mb/s */
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_100Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+
+    case BNC:
+    case AUI:
+    case _10Mb:                                /* Set 10Mb/s */
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_10Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+	
+    case NC:
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tx_enable = FALSE;
+	break;
+    }
+    
+    return next_tick;
+}
+
+/*
+** This routine may be merged into dc21140m_autoconf() sometime as I'm
+** changing how I figure out the media - but trying to keep it backwards
+** compatible with the de500-xa and de500-aa.
+** Whether it's BNC, AUI, SYM or MII is sorted out in the infoblock
+** functions and set during de4x5_mac_port() and/or de4x5_reset_phy().
+** This routine just has to figure out whether 10Mb/s or 100Mb/s is
+** active.
+** When autonegotiation is working, the ANS part searches the SROM for
+** the highest common speed (TP) link that both can run and if that can
+** be full duplex. That infoblock is executed and then the link speed set.
+**
+** Only _10Mb and _100Mb are tested here.
+*/
+static int
+dc2114x_autoconf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    switch (lp->media) {
+    case INIT:
+        if (lp->timeout < 0) {
+	    DISABLE_IRQs;
+	    lp->tx_enable = FALSE;
+	    lp->linkOK = 0;
+            lp->timeout = -1;
+	    de4x5_save_skbs(dev);            /* Save non transmitted skb's */
+	    if (lp->params.autosense & ~AUTO) {
+		srom_map_media(dev);         /* Fixed media requested      */
+		if (lp->media != lp->params.autosense) {
+		    lp->tcount++;
+		    lp->media = INIT;
+		    return next_tick;
+		}
+		lp->media = INIT;
+	    }
+	}
+	if ((next_tick = de4x5_reset_phy(dev)) < 0) {
+	    next_tick &= ~TIMER_CB;
+	} else {
+	    if (lp->autosense == _100Mb) {
+		lp->media = _100Mb;
+	    } else if (lp->autosense == _10Mb) {
+		lp->media = _10Mb;
+	    } else if (lp->autosense == TP) {
+		lp->media = TP;
+	    } else if (lp->autosense == BNC) {
+		lp->media = BNC;
+	    } else if (lp->autosense == AUI) {
+		lp->media = AUI;
+	    } else {
+		lp->media = SPD_DET;
+		if ((lp->infoblock_media == ANS) && 
+		                    ((sr=is_anc_capable(dev)) & MII_SR_ANC)) {
+		    ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA);
+		    ana &= (lp->fdx ? ~0 : ~MII_ANA_FDAM);
+		    mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    lp->media = ANS;
+		}
+	    }
+	    lp->local_state = 0;
+	    next_tick = dc2114x_autoconf(dev);
+        }
+	break;
+	
+    case ANS:
+	switch (lp->local_state) {
+	case 0:
+	    if (lp->timeout < 0) {
+		mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+	    }
+	    cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+	    if (cr < 0) {
+		next_tick = cr & ~TIMER_CB;
+	    } else {
+		if (cr) {
+		    lp->local_state = 0;
+		    lp->media = SPD_DET;
+		} else {
+		    lp->local_state++;
+		}
+		next_tick = dc2114x_autoconf(dev);
+	    }
+	    break;
+	    
+	case 1:
+	    if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+		next_tick = sr & ~TIMER_CB;
+	    } else {
+		lp->media = SPD_DET;
+		lp->local_state = 0;
+		if (sr) {                         /* Success! */
+		    lp->tmp = MII_SR_ASSC;
+		    anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII);
+		    ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII);
+		    if (!(anlpa & MII_ANLPA_RF) && 
+			 (cap = anlpa & MII_ANLPA_TAF & ana)) {
+			if (cap & MII_ANA_100M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+			    lp->media = _100Mb;
+			} else if (cap & MII_ANA_10M) {
+			    lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+			    lp->media = _10Mb;
+			}
+		    }
+		}                       /* Auto Negotiation failed to finish */
+		next_tick = dc2114x_autoconf(dev);
+	    }                           /* Auto Negotiation failed to start  */
+	    break;
+	}
+	break;
+
+    case AUI:
+	if (!lp->tx_enable) {
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);   /* Set up half duplex for AUI        */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		if (!(inl(DE4X5_SISR) & SISR_SRA) && (lp->autosense == AUTO)) {
+		    lp->media = BNC;
+		    next_tick = dc2114x_autoconf(dev);
+		} else {
+		    lp->local_state = 1;
+		    de4x5_init_connection(dev);
+		}
+	    }
+	} else if (!lp->linkOK && (lp->autosense == AUTO)) {
+	    lp->media = AUI_SUSPECT;
+	    next_tick = 3000;
+	}
+	break;
+	
+    case AUI_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc2114x_autoconf);
+	break;
+	
+    case BNC:
+	switch (lp->local_state) {
+	case 0:
+	    if (lp->timeout < 0) {
+		omr = inl(DE4X5_OMR);          /* Set up half duplex for BNC */
+		outl(omr & ~OMR_FDX, DE4X5_OMR);
+	    }
+	    irqs = 0;
+	    irq_mask = 0;
+	    sts = test_media(dev,irqs, irq_mask, 0, 0, 0, 1000);
+	    if (sts < 0) {
+		next_tick = sts & ~TIMER_CB;
+	    } else {
+		lp->local_state++;             /* Ensure media connected */
+		next_tick = dc2114x_autoconf(dev);
+	    }
+	    break;
+	    
+	case 1:
+	    if (!lp->tx_enable) {
+		if ((sts = ping_media(dev, 3000)) < 0) {
+		    next_tick = sts & ~TIMER_CB;
+		} else {
+		    if (sts) {
+			lp->local_state = 0;
+			lp->tcount++;
+			lp->media = INIT;
+		    } else {
+			de4x5_init_connection(dev);
+		    }
+		}
+	    } else if (!lp->linkOK && (lp->autosense == AUTO)) {
+		lp->media = BNC_SUSPECT;
+		next_tick = 3000;
+	    }
+	    break;
+	}
+	break;
+	
+    case BNC_SUSPECT:
+	next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc2114x_autoconf);
+	break;
+	
+    case SPD_DET:                              /* Choose 10Mb/s or 100Mb/s */
+	  if (srom_map_media(dev) < 0) {
+	      lp->tcount++;
+	      lp->media = INIT;
+	      return next_tick;
+	  }
+	  if (lp->media == _100Mb) {
+	      if ((slnk = test_for_100Mb(dev, 6500)) < 0) {
+		  lp->media = SPD_DET;
+		  return  (slnk & ~TIMER_CB);
+	      }
+	  } else {
+	      if (wait_for_link(dev) < 0) {
+		  lp->media = SPD_DET;
+		  return PDET_LINK_WAIT;
+	      }
+	  }
+	  if (lp->media == ANS) {           /* Do MII parallel detection */
+	      if (is_spd_100(dev)) {
+		  lp->media = _100Mb;
+	      } else {
+		  lp->media = _10Mb;
+	      }
+	      next_tick = dc2114x_autoconf(dev);
+	  } else if (((lp->media == _100Mb) && is_100_up(dev)) ||
+		     (((lp->media == _10Mb) || (lp->media == TP) ||
+		       (lp->media == BNC)   || (lp->media == AUI)) && 
+		      is_10_up(dev))) {
+	      next_tick = dc2114x_autoconf(dev);
+	  } else {
+	      lp->tcount++;
+	      lp->media = INIT;
+	  }
+	  break;
+	
+    case _10Mb:
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_10Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_10_up(dev) || (!lp->useSROM && is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+
+    case _100Mb:
+        next_tick = 3000;
+	if (!lp->tx_enable) {
+	    SET_100Mb;
+	    de4x5_init_connection(dev);
+	} else {
+	    if (!lp->linkOK && (lp->autosense == AUTO)) {
+		if (!is_100_up(dev) || (!lp->useSROM && !is_spd_100(dev))) {
+		    lp->media = INIT;
+		    lp->tcount++;
+		    next_tick = DE4X5_AUTOSENSE_MS;
+		}
+	    }
+	}
+	break;
+
+    default:
+	lp->tcount++;
+printk("Huh?: media:%02x\n", lp->media);
+	lp->media = INIT;
+	break;
+    }
+    
+    return next_tick;
+}
+
+static int
+srom_autoconf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    return lp->infoleaf_fn(dev);
+}
+
+/*
+** This mapping keeps the original media codes and FDX flag unchanged.
+** While it isn't strictly necessary, it helps me for the moment...
+** The early return avoids a media state / SROM media space clash.
+*/
+static int
+srom_map_media(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    lp->fdx = 0;
+    if (lp->infoblock_media == lp->media) 
+      return 0;
+
+    switch(lp->infoblock_media) {
+      case SROM_10BASETF:
+	if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_10BASET:
+	if (lp->params.fdx && !lp->fdx) return -1;
+	if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
+	    lp->media = _10Mb;
+	} else {
+	    lp->media = TP;
+	}
+	break;
+
+      case SROM_10BASE2:
+	lp->media = BNC;
+	break;
+
+      case SROM_10BASE5:
+	lp->media = AUI;
+	break;
+
+      case SROM_100BASETF:
+        if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_100BASET:
+	if (lp->params.fdx && !lp->fdx) return -1;
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASET4:
+	lp->media = _100Mb;
+	break;
+
+      case SROM_100BASEFF:
+	if (!lp->params.fdx) return -1;
+	lp->fdx = TRUE;
+      case SROM_100BASEF: 
+	if (lp->params.fdx && !lp->fdx) return -1;
+	lp->media = _100Mb;
+	break;
+
+      case ANS:
+	lp->media = ANS;
+	lp->fdx = lp->params.fdx;
+	break;
+
+      default: 
+	printk("%s: Bad media code [%d] detected in SROM!\n", dev->name, 
+	                                                  lp->infoblock_media);
+	return -1;
+	break;
+    }
+
+    return 0;
+}
+
+static void
+de4x5_init_connection(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_long flags = 0;
+
+    if (lp->media != lp->c_media) {
+        de4x5_dbg_media(dev);
+	lp->c_media = lp->media;          /* Stop scrolling media messages */
+    }
+
+    spin_lock_irqsave(&lp->lock, flags);
+    de4x5_rst_desc_ring(dev);
+    de4x5_setup_intr(dev);
+    lp->tx_enable = YES;
+    spin_unlock_irqrestore(&lp->lock, flags);
+    outl(POLL_DEMAND, DE4X5_TPD);
+
+    netif_wake_queue(dev);
+
+    return;
+}
+
+/*
+** General PHY reset function. Some MII devices don't reset correctly
+** since their MII address pins can float at voltages that are dependent
+** on the signal pin use. Do a double reset to ensure a reset.
+*/
+static int
+de4x5_reset_phy(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int next_tick = 0;
+
+    if ((lp->useSROM) || (lp->phy[lp->active].id)) {
+	if (lp->timeout < 0) {
+	    if (lp->useSROM) {
+		if (lp->phy[lp->active].rst) {
+		    srom_exec(dev, lp->phy[lp->active].rst);
+		    srom_exec(dev, lp->phy[lp->active].rst);
+		} else if (lp->rst) {          /* Type 5 infoblock reset */
+		    srom_exec(dev, lp->rst);
+		    srom_exec(dev, lp->rst);
+		}
+	    } else {
+		PHY_HARD_RESET;
+	    }
+	    if (lp->useMII) {
+	        mii_wr(MII_CR_RST, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
+            }
+        }
+	if (lp->useMII) {
+	    next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+	}
+    } else if (lp->chipset == DC21140) {
+	PHY_HARD_RESET;
+    }
+
+    return next_tick;
+}
+
+static int
+test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 sts, csr12;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+	if (!lp->useSROM) {      /* Already done if by SROM, else dc2104[01] */
+	    reset_init_sia(dev, csr13, csr14, csr15);
+	}
+
+	/* set up the interrupt mask */
+	outl(irq_mask, DE4X5_IMR);
+
+	/* clear all pending interrupts */
+	sts = inl(DE4X5_STS);
+	outl(sts, DE4X5_STS);
+	
+	/* clear csr12 NRA and SRA bits */
+	if ((lp->chipset == DC21041) || lp->useSROM) {
+	    csr12 = inl(DE4X5_SISR);
+	    outl(csr12, DE4X5_SISR);
+	}
+    }
+    
+    sts = inl(DE4X5_STS) & ~TIMER_CB;
+    
+    if (!(sts & irqs) && --lp->timeout) {
+	sts = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return sts;
+}
+
+static int
+test_tp(struct net_device *dev, s32 msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int sisr;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+    }
+    
+    sisr = (inl(DE4X5_SISR) & ~TIMER_CB) & (SISR_LKF | SISR_NCR);
+
+    if (sisr && --lp->timeout) {
+	sisr = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return sisr;
+}
+
+/*
+** Samples the 100Mb Link State Signal. The sample interval is important
+** because too fast a rate can give erroneous results and confuse the
+** speed sense algorithm.
+*/
+#define SAMPLE_INTERVAL 500  /* ms */
+#define SAMPLE_DELAY    2000 /* ms */
+static int
+test_for_100Mb(struct net_device *dev, int msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK);
+
+    if (lp->timeout < 0) {
+	if ((msec/SAMPLE_INTERVAL) <= 0) return 0;
+	if (msec > SAMPLE_DELAY) {
+	    lp->timeout = (msec - SAMPLE_DELAY)/SAMPLE_INTERVAL;
+	    gep = SAMPLE_DELAY | TIMER_CB;
+	    return gep;
+	} else {
+	    lp->timeout = msec/SAMPLE_INTERVAL;
+	}
+    }
+    
+    if (lp->phy[lp->active].id || lp->useSROM) {
+	gep = is_100_up(dev) | is_spd_100(dev);
+    } else {
+	gep = (~gep_rd(dev) & (GEP_SLNK | GEP_LNP));
+    }
+    if (!(gep & ret) && --lp->timeout) {
+	gep = SAMPLE_INTERVAL | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return gep;
+}
+
+static int
+wait_for_link(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+
+    if (lp->timeout < 0) {
+	lp->timeout = 1;
+    }
+    
+    if (lp->timeout--) {
+	return TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return 0;
+}
+
+/*
+**
+**
+*/
+static int
+test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int test;
+    u_long iobase = dev->base_addr;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+    }
+    
+    if (pol) pol = ~0;
+    reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
+    test = (reg ^ pol) & mask;
+    
+    if (test && --lp->timeout) {
+	reg = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return reg;
+}
+
+static int
+is_spd_100(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int spd;
+    
+    if (lp->useMII) {
+	spd = mii_rd(lp->phy[lp->active].spd.reg, lp->phy[lp->active].addr, DE4X5_MII);
+	spd = ~(spd ^ lp->phy[lp->active].spd.value);
+	spd &= lp->phy[lp->active].spd.mask;
+    } else if (!lp->useSROM) {                      /* de500-xa */
+	spd = ((~gep_rd(dev)) & GEP_SLNK);
+    } else {
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+	spd = (lp->asBitValid & (lp->asPolarity ^ (gep_rd(dev) & lp->asBit))) |
+	          (lp->linkOK & ~lp->asBitValid);
+    }
+    
+    return spd;
+}
+
+static int
+is_100_up(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    
+    if (lp->useMII) {
+	/* Double read for sticky bits & temporary drops */
+	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
+	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+	return ((~gep_rd(dev)) & GEP_SLNK);
+    } else {
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return ((lp->chipset == DC21143)?(~inl(DE4X5_SISR)&SISR_LS100):0);
+
+        return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
+    }
+}
+
+static int
+is_10_up(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    
+    if (lp->useMII) {
+	/* Double read for sticky bits & temporary drops */
+	mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);
+	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_LKS);
+    } else if (!lp->useSROM) {                       /* de500-xa */
+	return ((~gep_rd(dev)) & GEP_LNP);
+    } else {
+	if ((lp->ibn == 2) || !lp->asBitValid)
+	    return (((lp->chipset & ~0x00ff) == DC2114x) ?
+		    (~inl(DE4X5_SISR)&SISR_LS10):
+		    0);
+
+	return ((lp->asBitValid&(lp->asPolarity^(gep_rd(dev)&lp->asBit))) |
+		(lp->linkOK & ~lp->asBitValid));
+    }
+}
+
+static int
+is_anc_capable(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    
+    if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+	return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII));
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	return (inl(DE4X5_SISR) & SISR_LPN) >> 12;
+    } else {
+	return 0;
+    }
+}
+
+/*
+** Send a packet onto the media and watch for send errors that indicate the
+** media is bad or unconnected.
+*/
+static int
+ping_media(struct net_device *dev, int msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int sisr;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+	
+	lp->tmp = lp->tx_new;                /* Remember the ring position */
+	load_packet(dev, lp->frame, TD_LS | TD_FS | sizeof(lp->frame), (struct sk_buff *)1);
+	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+	outl(POLL_DEMAND, DE4X5_TPD);
+    }
+    
+    sisr = inl(DE4X5_SISR);
+
+    if ((!(sisr & SISR_NCR)) && 
+	((s32)le32_to_cpu(lp->tx_ring[lp->tmp].status) < 0) && 
+	 (--lp->timeout)) {
+	sisr = 100 | TIMER_CB;
+    } else {
+	if ((!(sisr & SISR_NCR)) && 
+	    !(le32_to_cpu(lp->tx_ring[lp->tmp].status) & (T_OWN | TD_ES)) &&
+	    lp->timeout) {
+	    sisr = 0;
+	} else {
+	    sisr = 1;
+	}
+	lp->timeout = -1;
+    }
+    
+    return sisr;
+}
+
+/*
+** This function does 2 things: on Intels it kmalloc's another buffer to
+** replace the one about to be passed up. On Alpha's it kmallocs a buffer
+** into which the packet is copied.
+*/
+static struct sk_buff *
+de4x5_alloc_rx_buff(struct net_device *dev, int index, int len)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p;
+
+#if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY)
+    struct sk_buff *ret;
+    u_long i=0, tmp;
+
+    p = dev_alloc_skb(IEEE802_3_SZ + DE4X5_ALIGN + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    tmp = virt_to_bus(p->data);
+    i = ((tmp + DE4X5_ALIGN) & ~DE4X5_ALIGN) - tmp;
+    skb_reserve(p, i);
+    lp->rx_ring[index].buf = cpu_to_le32(tmp + i);
+
+    ret = lp->rx_skb[index];
+    lp->rx_skb[index] = p;
+
+    if ((u_long) ret > 1) {
+	skb_put(ret, len);
+    }
+
+    return ret;
+
+#else
+    if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */
+
+    p = dev_alloc_skb(len + 2);
+    if (!p) return NULL;
+
+    p->dev = dev;
+    skb_reserve(p, 2);	                               /* Align */
+    if (index < lp->rx_old) {                          /* Wrapped buffer */
+	short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
+	memcpy(skb_put(p,tlen),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,tlen);
+	memcpy(skb_put(p,len-tlen),lp->rx_bufs,len-tlen);
+    } else {                                           /* Linear buffer */
+	memcpy(skb_put(p,len),lp->rx_bufs + lp->rx_old * RX_BUFF_SZ,len);
+    }
+		    
+    return p;
+#endif
+}
+
+static void
+de4x5_free_rx_buffs(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->rxRingSize; i++) {
+	if ((u_long) lp->rx_skb[i] > 1) {
+	    dev_kfree_skb(lp->rx_skb[i]);
+	}
+	lp->rx_ring[i].status = 0;
+	lp->rx_skb[i] = (struct sk_buff *)1;    /* Dummy entry */
+    }
+
+    return;
+}
+
+static void
+de4x5_free_tx_buffs(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+
+    for (i=0; i<lp->txRingSize; i++) {
+	if (lp->tx_skb[i])
+	    de4x5_free_tx_buff(lp, i);
+	lp->tx_ring[i].status = 0;
+    }
+
+    /* Unload the locally queued packets */
+    while (lp->cache.skb) {
+	dev_kfree_skb(de4x5_get_cache(dev));
+    }
+
+    return;
+}
+
+/*
+** When a user pulls a connection, the DECchip can end up in a
+** 'running - waiting for end of transmission' state. This means that we
+** have to perform a chip soft reset to ensure that we can synchronize
+** the hardware and software and make any media probes using a loopback
+** packet meaningful.
+*/
+static void
+de4x5_save_skbs(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 omr;
+
+    if (!lp->cache.save_cnt) {
+	STOP_DE4X5;
+	de4x5_tx(dev);                          /* Flush any sent skb's */
+	de4x5_free_tx_buffs(dev);
+	de4x5_cache_state(dev, DE4X5_SAVE_STATE);
+	de4x5_sw_reset(dev);
+	de4x5_cache_state(dev, DE4X5_RESTORE_STATE);
+	lp->cache.save_cnt++;
+	START_DE4X5;
+    }
+
+    return;
+}
+
+static void
+de4x5_rst_desc_ring(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int i;
+    s32 omr;
+
+    if (lp->cache.save_cnt) {
+	STOP_DE4X5;
+	outl(lp->dma_rings, DE4X5_RRBA);
+	outl(lp->dma_rings + NUM_RX_DESC * sizeof(struct de4x5_desc),
+	     DE4X5_TRBA);
+    
+	lp->rx_new = lp->rx_old = 0;
+	lp->tx_new = lp->tx_old = 0;
+    
+	for (i = 0; i < lp->rxRingSize; i++) {
+	    lp->rx_ring[i].status = cpu_to_le32(R_OWN);
+	}
+    
+	for (i = 0; i < lp->txRingSize; i++) {
+	    lp->tx_ring[i].status = cpu_to_le32(0);
+	}
+    
+	barrier();
+	lp->cache.save_cnt--;
+	START_DE4X5;
+    }
+        
+    return;
+}
+
+static void
+de4x5_cache_state(struct net_device *dev, int flag)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    switch(flag) {
+      case DE4X5_SAVE_STATE:
+	lp->cache.csr0 = inl(DE4X5_BMR);
+	lp->cache.csr6 = (inl(DE4X5_OMR) & ~(OMR_ST | OMR_SR));
+	lp->cache.csr7 = inl(DE4X5_IMR);
+	break;
+
+      case DE4X5_RESTORE_STATE:
+	outl(lp->cache.csr0, DE4X5_BMR);
+	outl(lp->cache.csr6, DE4X5_OMR);
+	outl(lp->cache.csr7, DE4X5_IMR);
+	if (lp->chipset == DC21140) {
+	    gep_wr(lp->cache.gepc, dev);
+	    gep_wr(lp->cache.gep, dev);
+	} else {
+	    reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, 
+			                                      lp->cache.csr15);
+	}
+	break;
+    }
+
+    return;
+}
+
+static void
+de4x5_put_cache(struct net_device *dev, struct sk_buff *skb)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p;
+
+    if (lp->cache.skb) {
+	for (p=lp->cache.skb; p->next; p=p->next);
+	p->next = skb;
+    } else {
+	lp->cache.skb = skb;
+    }
+    skb->next = NULL;
+
+    return;
+}
+
+static void
+de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p = lp->cache.skb;
+
+    lp->cache.skb = skb;
+    skb->next = p;
+
+    return;
+}
+
+static struct sk_buff *
+de4x5_get_cache(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct sk_buff *p = lp->cache.skb;
+
+    if (p) {
+	lp->cache.skb = p->next;
+	p->next = NULL;
+    }
+
+    return p;
+}
+
+/*
+** Check the Auto Negotiation State. Return OK when a link pass interrupt
+** is received and the auto-negotiation status is NWAY OK.
+*/
+static int
+test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 sts, ans;
+    
+    if (lp->timeout < 0) {
+	lp->timeout = msec/100;
+	outl(irq_mask, DE4X5_IMR);
+	
+	/* clear all pending interrupts */
+	sts = inl(DE4X5_STS);
+	outl(sts, DE4X5_STS);
+    }
+    
+    ans = inl(DE4X5_SISR) & SISR_ANS;
+    sts = inl(DE4X5_STS) & ~TIMER_CB;
+    
+    if (!(sts & irqs) && (ans ^ ANS_NWOK) && --lp->timeout) {
+	sts = 100 | TIMER_CB;
+    } else {
+	lp->timeout = -1;
+    }
+    
+    return sts;
+}
+
+static void
+de4x5_setup_intr(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 imr, sts;
+    
+    if (inl(DE4X5_OMR) & OMR_SR) {   /* Only unmask if TX/RX is enabled */
+	imr = 0;
+	UNMASK_IRQs;
+	sts = inl(DE4X5_STS);        /* Reset any pending (stale) interrupts */
+	outl(sts, DE4X5_STS);
+	ENABLE_IRQs;
+    }
+    
+    return;
+}
+
+/*
+**
+*/
+static void
+reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    RESET_SIA;
+    if (lp->useSROM) {
+	if (lp->ibn == 3) {
+	    srom_exec(dev, lp->phy[lp->active].rst);
+	    srom_exec(dev, lp->phy[lp->active].gep);
+	    outl(1, DE4X5_SICR);
+	    return;
+	} else {
+	    csr15 = lp->cache.csr15;
+	    csr14 = lp->cache.csr14;
+	    csr13 = lp->cache.csr13;
+	    outl(csr15 | lp->cache.gepc, DE4X5_SIGR);
+	    outl(csr15 | lp->cache.gep, DE4X5_SIGR);
+	}
+    } else {
+	outl(csr15, DE4X5_SIGR);
+    }
+    outl(csr14, DE4X5_STRR);
+    outl(csr13, DE4X5_SICR);
+
+    mdelay(10);
+
+    return;
+}
+
+/*
+** Create a loopback ethernet packet
+*/
+static void
+create_packet(struct net_device *dev, char *frame, int len)
+{
+    int i;
+    char *buf = frame;
+    
+    for (i=0; i<ETH_ALEN; i++) {             /* Use this source address */
+	*buf++ = dev->dev_addr[i];
+    }
+    for (i=0; i<ETH_ALEN; i++) {             /* Use this destination address */
+	*buf++ = dev->dev_addr[i];
+    }
+    
+    *buf++ = 0;                              /* Packet length (2 bytes) */
+    *buf++ = 1;
+    
+    return;
+}
+
+/*
+** Look for a particular board name in the EISA configuration space
+*/
+static int
+EISA_signature(char *name, s32 eisa_id)
+{
+    static c_char *signatures[] = DE4X5_SIGNATURE;
+    char ManCode[DE4X5_STRLEN];
+    union {
+	s32 ID;
+	char Id[4];
+    } Eisa;
+    int i, status = 0, siglen = sizeof(signatures)/sizeof(c_char *);
+    
+    *name = '\0';
+    Eisa.ID = inl(eisa_id);
+    
+    ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
+    ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
+    ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
+    ManCode[3]=((Eisa.Id[2]&0x0f)+0x30);
+    ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
+    ManCode[5]='\0';
+    
+    for (i=0;i<siglen;i++) {
+	if (strstr(ManCode, signatures[i]) != NULL) {
+	    strcpy(name,ManCode);
+	    status = 1;
+	    break;
+	}
+    }
+    
+    return status;                         /* return the device name string */
+}
+
+/*
+** Look for a particular board name in the PCI configuration space
+*/
+static int
+PCI_signature(char *name, struct bus_type *lp)
+{
+    static c_char *de4x5_signatures[] = DE4X5_SIGNATURE;
+    int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+    
+    if (lp->chipset == DC21040) {
+	strcpy(name, "DE434/5");
+	return status;
+    } else {                           /* Search for a DEC name in the SROM */
+	int i = *((char *)&lp->srom + 19) * 3;
+	strncpy(name, (char *)&lp->srom + 26 + i, 8);
+    }
+    name[8] = '\0';
+    for (i=0; i<siglen; i++) {
+	if (strstr(name,de4x5_signatures[i])!=NULL) break;
+    }
+    if (i == siglen) {
+	if (dec_only) {
+	    *name = '\0';
+	} else {                        /* Use chip name to avoid confusion */
+	    strcpy(name, (((lp->chipset == DC21040) ? "DC21040" :
+			   ((lp->chipset == DC21041) ? "DC21041" :
+			    ((lp->chipset == DC21140) ? "DC21140" :
+			     ((lp->chipset == DC21142) ? "DC21142" :
+			      ((lp->chipset == DC21143) ? "DC21143" : "UNKNOWN"
+			     )))))));
+	}
+	if (lp->chipset != DC21041) {
+	    useSROM = TRUE;             /* card is not recognisably DEC */
+	}
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	useSROM = TRUE;
+    }
+    
+    return status;
+}
+
+/*
+** Set up the Ethernet PROM counter to the start of the Ethernet address on
+** the DC21040, else  read the SROM for the other chips.
+** The SROM may not be present in a multi-MAC card, so first read the
+** MAC address and check for a bad address. If there is a bad one then exit
+** immediately with the prior srom contents intact (the h/w address will
+** be fixed up later).
+*/
+static void
+DevicePresent(u_long aprom_addr)
+{
+    int i, j=0;
+    struct bus_type *lp = &bus;
+    
+    if (lp->chipset == DC21040) {
+	if (lp->bus == EISA) {
+	    enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */
+	} else {
+	    outl(0, aprom_addr);       /* Reset Ethernet Address ROM Pointer */
+	}
+    } else {                           /* Read new srom */
+	u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD);
+	for (i=0; i<(ETH_ALEN>>1); i++) {
+	    tmp = srom_rd(aprom_addr, (SROM_HWADD>>1) + i);
+	    *p = le16_to_cpu(tmp);
+	    j += *p++;
+	}
+	if ((j == 0) || (j == 0x2fffd)) {
+	    return;
+	}
+
+	p=(short *)&lp->srom;
+	for (i=0; i<(sizeof(struct de4x5_srom)>>1); i++) {
+	    tmp = srom_rd(aprom_addr, i);
+	    *p++ = le16_to_cpu(tmp);
+	}
+	de4x5_dbg_srom((struct de4x5_srom *)&lp->srom);
+    }
+    
+    return;
+}
+
+/*
+** Since the write on the Enet PROM register doesn't seem to reset the PROM
+** pointer correctly (at least on my DE425 EISA card), this routine should do
+** it...from depca.c.
+*/
+static void
+enet_addr_rst(u_long aprom_addr)
+{
+    union {
+	struct {
+	    u32 a;
+	    u32 b;
+	} llsig;
+	char Sig[sizeof(u32) << 1];
+    } dev;
+    short sigLength=0;
+    s8 data;
+    int i, j;
+    
+    dev.llsig.a = ETH_PROM_SIG;
+    dev.llsig.b = ETH_PROM_SIG;
+    sigLength = sizeof(u32) << 1;
+    
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+	data = inb(aprom_addr);
+	if (dev.Sig[j] == data) {    /* track signature */
+	    j++;
+	} else {                     /* lost signature; begin search again */
+	    if (data == dev.Sig[0]) {  /* rare case.... */
+		j=1;
+	    } else {
+		j=0;
+	    }
+	}
+    }
+    
+    return;
+}
+
+/*
+** For the bad status case and no SROM, then add one to the previous
+** address. However, need to add one backwards in case we have 0xff
+** as one or more of the bytes. Only the last 3 bytes should be checked
+** as the first three are invariant - assigned to an organisation.
+*/
+static int
+get_hw_addr(struct net_device *dev)
+{
+    u_long iobase = dev->base_addr;
+    int broken, i, k, tmp, status = 0;
+    u_short j,chksum;
+    struct bus_type *lp = &bus;
+
+    broken = de4x5_bad_srom(lp);
+
+    for (i=0,k=0,j=0;j<3;j++) {
+	k <<= 1;
+	if (k > 0xffff) k-=0xffff;
+	
+	if (lp->bus == PCI) {
+	    if (lp->chipset == DC21040) {
+		while ((tmp = inl(DE4X5_APROM)) < 0);
+		k += (u_char) tmp;
+		dev->dev_addr[i++] = (u_char) tmp;
+		while ((tmp = inl(DE4X5_APROM)) < 0);
+		k += (u_short) (tmp << 8);
+		dev->dev_addr[i++] = (u_char) tmp;
+	    } else if (!broken) {
+		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+		dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++;
+	    } else if ((broken == SMC) || (broken == ACCTON)) {
+		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
+		dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++;
+	    }
+	} else {
+	    k += (u_char) (tmp = inb(EISA_APROM));
+	    dev->dev_addr[i++] = (u_char) tmp;
+	    k += (u_short) ((tmp = inb(EISA_APROM)) << 8);
+	    dev->dev_addr[i++] = (u_char) tmp;
+	}
+	
+	if (k > 0xffff) k-=0xffff;
+    }
+    if (k == 0xffff) k=0;
+    
+    if (lp->bus == PCI) {
+	if (lp->chipset == DC21040) {
+	    while ((tmp = inl(DE4X5_APROM)) < 0);
+	    chksum = (u_char) tmp;
+	    while ((tmp = inl(DE4X5_APROM)) < 0);
+	    chksum |= (u_short) (tmp << 8);
+	    if ((k != chksum) && (dec_only)) status = -1;
+	}
+    } else {
+	chksum = (u_char) inb(EISA_APROM);
+	chksum |= (u_short) (inb(EISA_APROM) << 8);
+	if ((k != chksum) && (dec_only)) status = -1;
+    }
+
+    /* If possible, try to fix a broken card - SMC only so far */
+    srom_repair(dev, broken);
+
+#ifdef CONFIG_PPC
+    /* 
+    ** If the address starts with 00 a0, we have to bit-reverse
+    ** each byte of the address.
+    */
+    if ( (ppc_md.ppc_machine & _MACH_Pmac) &&
+	 (dev->dev_addr[0] == 0) &&
+	 (dev->dev_addr[1] == 0xa0) )
+    {
+	    for (i = 0; i < ETH_ALEN; ++i)
+	    {
+		    int x = dev->dev_addr[i];
+		    x = ((x & 0xf) << 4) + ((x & 0xf0) >> 4);
+		    x = ((x & 0x33) << 2) + ((x & 0xcc) >> 2);
+		    dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
+	    }
+    }
+#endif /* CONFIG_PPC */
+
+    /* Test for a bad enet address */
+    status = test_bad_enet(dev, status);
+
+    return status;
+}
+
+/*
+** Test for enet addresses in the first 32 bytes. The built-in strncmp
+** didn't seem to work here...?
+*/
+static int
+de4x5_bad_srom(struct bus_type *lp)
+{
+    int i, status = 0;
+
+    for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) {
+	if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) &&
+	    !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) {
+	    if (i == 0) {
+		status = SMC;
+	    } else if (i == 1) {
+		status = ACCTON;
+	    }
+	    break;
+	}
+    }
+
+    return status;
+}
+
+static int
+de4x5_strncmp(char *a, char *b, int n)
+{
+    int ret=0;
+
+    for (;n && !ret;n--) {
+	ret = *a++ - *b++;
+    }
+
+    return ret;
+}
+
+static void
+srom_repair(struct net_device *dev, int card)
+{
+    struct bus_type *lp = &bus;
+
+    switch(card) {
+      case SMC:
+	memset((char *)&bus.srom, 0, sizeof(struct de4x5_srom));
+	memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
+	memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
+	useSROM = TRUE;
+	break;
+    }
+
+    return;
+}
+
+/*
+** Assume that the irq's do not follow the PCI spec - this is seems
+** to be true so far (2 for 2).
+*/
+static int
+test_bad_enet(struct net_device *dev, int status)
+{
+    struct bus_type *lp = &bus;
+    int i, tmp;
+
+    for (tmp=0,i=0; i<ETH_ALEN; i++) tmp += (u_char)dev->dev_addr[i];
+    if ((tmp == 0) || (tmp == 0x5fa)) {
+	if ((lp->chipset == last.chipset) && 
+	    (lp->bus_num == last.bus) && (lp->bus_num > 0)) {
+	    for (i=0; i<ETH_ALEN; i++) dev->dev_addr[i] = last.addr[i];
+	    for (i=ETH_ALEN-1; i>2; --i) {
+		dev->dev_addr[i] += 1;
+		if (dev->dev_addr[i] != 0) break;
+	    }
+	    for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+	    if (!an_exception(lp)) {
+		dev->irq = last.irq;
+	    }
+
+	    status = 0;
+	}
+    } else if (!status) {
+	last.chipset = lp->chipset;
+	last.bus = lp->bus_num;
+	last.irq = dev->irq;
+	for (i=0; i<ETH_ALEN; i++) last.addr[i] = dev->dev_addr[i];
+    }
+
+    return status;
+}
+
+/*
+** List of board exceptions with correctly wired IRQs
+*/
+static int
+an_exception(struct bus_type *lp)
+{
+    if ((*(u_short *)lp->srom.sub_vendor_id == 0x00c0) && 
+	(*(u_short *)lp->srom.sub_system_id == 0x95e0)) {
+	return -1;
+    }
+
+    return 0;
+}
+
+/*
+** SROM Read
+*/
+static short
+srom_rd(u_long addr, u_char offset)
+{
+    sendto_srom(SROM_RD | SROM_SR, addr);
+    
+    srom_latch(SROM_RD | SROM_SR | DT_CS, addr);
+    srom_command(SROM_RD | SROM_SR | DT_IN | DT_CS, addr);
+    srom_address(SROM_RD | SROM_SR | DT_CS, addr, offset);
+    
+    return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
+}
+
+static void
+srom_latch(u_int command, u_long addr)
+{
+    sendto_srom(command, addr);
+    sendto_srom(command | DT_CLK, addr);
+    sendto_srom(command, addr);
+    
+    return;
+}
+
+static void
+srom_command(u_int command, u_long addr)
+{
+    srom_latch(command, addr);
+    srom_latch(command, addr);
+    srom_latch((command & 0x0000ff00) | DT_CS, addr);
+    
+    return;
+}
+
+static void
+srom_address(u_int command, u_long addr, u_char offset)
+{
+    int i, a;
+    
+    a = offset << 2;
+    for (i=0; i<6; i++, a <<= 1) {
+	srom_latch(command | ((a & 0x80) ? DT_IN : 0), addr);
+    }
+    udelay(1);
+    
+    i = (getfrom_srom(addr) >> 3) & 0x01;
+    
+    return;
+}
+
+static short
+srom_data(u_int command, u_long addr)
+{
+    int i;
+    short word = 0;
+    s32 tmp;
+    
+    for (i=0; i<16; i++) {
+	sendto_srom(command  | DT_CLK, addr);
+	tmp = getfrom_srom(addr);
+	sendto_srom(command, addr);
+	
+	word = (word << 1) | ((tmp >> 3) & 0x01);
+    }
+    
+    sendto_srom(command & 0x0000ff00, addr);
+    
+    return word;
+}
+
+/*
+static void
+srom_busy(u_int command, u_long addr)
+{
+   sendto_srom((command & 0x0000ff00) | DT_CS, addr);
+   
+   while (!((getfrom_srom(addr) >> 3) & 0x01)) {
+       mdelay(1);
+   }
+   
+   sendto_srom(command & 0x0000ff00, addr);
+   
+   return;
+}
+*/
+
+static void
+sendto_srom(u_int command, u_long addr)
+{
+    outl(command, addr);
+    udelay(1);
+    
+    return;
+}
+
+static int
+getfrom_srom(u_long addr)
+{
+    s32 tmp;
+    
+    tmp = inl(addr);
+    udelay(1);
+    
+    return tmp;
+}
+
+static int
+srom_infoleaf_info(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i, count;
+    u_char *p;
+
+    /* Find the infoleaf decoder function that matches this chipset */
+    for (i=0; i<INFOLEAF_SIZE; i++) {
+	if (lp->chipset == infoleaf_array[i].chipset) break;
+    }
+    if (i == INFOLEAF_SIZE) {
+	lp->useSROM = FALSE;
+	printk("%s: Cannot find correct chipset for SROM decoding!\n", 
+	                                                          dev->name);
+	return -ENXIO;
+    }
+
+    lp->infoleaf_fn = infoleaf_array[i].fn;
+
+    /* Find the information offset that this function should use */
+    count = *((u_char *)&lp->srom + 19);
+    p  = (u_char *)&lp->srom + 26;
+
+    if (count > 1) {
+	for (i=count; i; --i, p+=3) {
+	    if (lp->device == *p) break;
+	}
+	if (i == 0) {
+	    lp->useSROM = FALSE;
+	    printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n", 
+	                                               dev->name, lp->device);
+	    return -ENXIO;
+	}
+    }
+
+    lp->infoleaf_offset = TWIDDLE(p+1);
+
+    return 0;
+}
+
+/*
+** This routine loads any type 1 or 3 MII info into the mii device
+** struct and executes any type 5 code to reset PHY devices for this
+** controller.
+** The info for the MII devices will be valid since the index used
+** will follow the discovery process from MII address 1-31 then 0.
+*/
+static void
+srom_init(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    u_char count;
+
+    p+=2;
+    if (lp->chipset == DC21140) {
+	lp->cache.gepc = (*p++ | GEP_CTRL);
+	gep_wr(lp->cache.gepc, dev);
+    }
+
+    /* Block count */
+    count = *p++;
+
+    /* Jump the infoblocks to find types */
+    for (;count; --count) {
+	if (*p < 128) {
+	    p += COMPACT_LEN;
+	} else if (*(p+1) == 5) {
+	    type5_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 4) {
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 3) {
+	    type3_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 2) {
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else if (*(p+1) == 1) {
+	    type1_infoblock(dev, 1, p);
+	    p += ((*p & BLOCK_LEN) + 1);
+	} else {
+	    p += ((*p & BLOCK_LEN) + 1);
+	}
+    }
+
+    return;
+}
+
+/*
+** A generic routine that writes GEP control, data and reset information
+** to the GEP register (21140) or csr15 GEP portion (2114[23]).
+*/
+static void
+srom_exec(struct net_device *dev, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    u_char count = (p ? *p++ : 0);
+    u_short *w = (u_short *)p;
+
+    if (((lp->ibn != 1) && (lp->ibn != 3) && (lp->ibn != 5)) || !count) return;
+
+    if (lp->chipset != DC21140) RESET_SIA;
+ 
+    while (count--) {
+	gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? 
+		                                   *p++ : TWIDDLE(w++)), dev);
+	mdelay(2);                          /* 2ms per action */
+    }
+
+    if (lp->chipset != DC21140) {
+	outl(lp->cache.csr14, DE4X5_STRR);
+	outl(lp->cache.csr13, DE4X5_SICR);
+    }
+
+    return;
+}
+
+/*
+** Basically this function is a NOP since it will never be called,
+** unless I implement the DC21041 SROM functions. There's no need
+** since the existing code will be satisfactory for all boards.
+*/
+static int 
+dc21041_infoleaf(struct net_device *dev)
+{
+    return DE4X5_AUTOSENSE_MS;
+}
+
+static int 
+dc21140_infoleaf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* GEP control */
+    lp->cache.gepc = (*p++ | GEP_CTRL);
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
+}
+
+static int 
+dc21142_infoleaf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
+}
+
+static int 
+dc21143_infoleaf(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char count = 0;
+    u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset;
+    int next_tick = DE4X5_AUTOSENSE_MS;
+
+    /* Read the connection type */
+    p+=2;
+
+    /* Block count */
+    count = *p++;
+
+    /* Recursively figure out the info blocks */
+    if (*p < 128) {
+	next_tick = dc_infoblock[COMPACT](dev, count, p);
+    } else {
+	next_tick = dc_infoblock[*(p+1)](dev, count, p);
+    }
+    if (lp->tcount == count) {
+	lp->media = NC;
+        if (lp->media != lp->c_media) {
+	    de4x5_dbg_media(dev);
+	    lp->c_media = lp->media;
+	}
+	lp->media = INIT;
+	lp->tcount = 0;
+	lp->tx_enable = FALSE;
+    }
+
+    return next_tick & ~TIMER_CB;
+}
+
+/*
+** The compact infoblock is only designed for DC21140[A] chips, so
+** we'll reuse the dc21140m_autoconf function. Non MII media only.
+*/
+static int 
+compact_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+COMPACT_LEN) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+COMPACT_LEN);
+	} else {
+	    return dc_infoblock[*(p+COMPACT_LEN+1)](dev, count, p+COMPACT_LEN);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = COMPACT;
+        lp->active = 0;
+	gep_wr(lp->cache.gepc, dev);
+	lp->infoblock_media = (*p++) & COMPACT_MC;
+	lp->cache.gep = *p++;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/*
+** This block describes non MII media for the DC21140[A] only.
+*/
+static int 
+type0_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 0;
+        lp->active = 0;
+        gep_wr(lp->cache.gepc, dev);
+	p+=2;
+	lp->infoblock_media = (*p++) & BLOCK0_MC;
+	lp->cache.gep = *p++;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+/* These functions are under construction! */
+
+static int 
+type1_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    p += 2;
+    if (lp->state == INITIALISED) {
+        lp->ibn = 1;
+	lp->active = *p++;
+	lp->phy[lp->active].gep = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].rst = (*p ? p : 0); p += (*p + 1);
+	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ttm = TWIDDLE(p);
+	return 0;
+    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 1;
+        lp->active = *p;
+	lp->infoblock_csr6 = OMR_MII_100;
+	lp->useMII = TRUE;
+	lp->infoblock_media = ANS;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc21140m_autoconf(dev);
+}
+
+static int 
+type2_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 2;
+        lp->active = 0;
+	p += 2;
+	lp->infoblock_media = (*p) & MEDIA_CODE;
+
+        if ((*p++) & EXT_FIELD) {
+	    lp->cache.csr13 = TWIDDLE(p); p += 2;
+	    lp->cache.csr14 = TWIDDLE(p); p += 2;
+	    lp->cache.csr15 = TWIDDLE(p); p += 2;
+	} else {
+	    lp->cache.csr13 = CSR13;
+	    lp->cache.csr14 = CSR14;
+	    lp->cache.csr15 = CSR15;
+	}
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16);
+	lp->infoblock_csr6 = OMR_SIA;
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
+}
+
+static int 
+type3_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    p += 2;
+    if (lp->state == INITIALISED) {
+        lp->ibn = 3;
+        lp->active = *p++;
+	if (MOTO_SROM_BUG) lp->active = 0;
+	lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
+	lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
+	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+	lp->phy[lp->active].mci = *p;
+	return 0;
+    } else if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 3;
+	lp->active = *p;
+	if (MOTO_SROM_BUG) lp->active = 0;
+	lp->infoblock_csr6 = OMR_MII_100;
+	lp->useMII = TRUE;
+	lp->infoblock_media = ANS;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
+}
+
+static int 
+type4_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char flags, csr6, len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    if ((lp->media == INIT) && (lp->timeout < 0)) {
+        lp->ibn = 4;
+        lp->active = 0;
+	p+=2;
+	lp->infoblock_media = (*p++) & MEDIA_CODE;
+        lp->cache.csr13 = CSR13;              /* Hard coded defaults */
+	lp->cache.csr14 = CSR14;
+	lp->cache.csr15 = CSR15;
+        lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
+        lp->cache.gep  = ((s32)(TWIDDLE(p)) << 16); p += 2;
+	csr6 = *p++;
+	flags = *p++;
+
+	lp->asBitValid = (flags & 0x80) ? 0 : -1;
+	lp->defMedium = (flags & 0x40) ? -1 : 0;
+	lp->asBit = 1 << ((csr6 >> 1) & 0x07);
+	lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
+	lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
+	lp->useMII = FALSE;
+
+	de4x5_switch_mac_port(dev);
+    }
+
+    return dc2114x_autoconf(dev);
+}
+
+/*
+** This block type provides information for resetting external devices
+** (chips) through the General Purpose Register.
+*/
+static int 
+type5_infoblock(struct net_device *dev, u_char count, u_char *p)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_char len = (*p & BLOCK_LEN)+1;
+
+    /* Recursively figure out the info blocks */
+    if (--count > lp->tcount) {
+	if (*(p+len) < 128) {
+	    return dc_infoblock[COMPACT](dev, count, p+len);
+	} else {
+	    return dc_infoblock[*(p+len+1)](dev, count, p+len);
+	}
+    }
+
+    /* Must be initializing to run this code */
+    if ((lp->state == INITIALISED) || (lp->media == INIT)) {
+	p+=2;
+        lp->rst = p;
+        srom_exec(dev, lp->rst);
+    }
+
+    return DE4X5_AUTOSENSE_MS;
+}
+
+/*
+** MII Read/Write
+*/
+
+static int
+mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr)
+{
+    mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
+    mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
+    mii_wdata(MII_STRD, 4, ioaddr);        /* SFD and Read operation         */
+    mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
+    mii_address(phyreg, ioaddr);           /* PHY Register to read           */
+    mii_ta(MII_STRD, ioaddr);              /* Turn around time - 2 MDC       */
+    
+    return mii_rdata(ioaddr);              /* Read data                      */
+}
+
+static void
+mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr)
+{
+    mii_wdata(MII_PREAMBLE,  2, ioaddr);   /* Start of 34 bit preamble...    */
+    mii_wdata(MII_PREAMBLE, 32, ioaddr);   /* ...continued                   */
+    mii_wdata(MII_STWR, 4, ioaddr);        /* SFD and Write operation        */
+    mii_address(phyaddr, ioaddr);          /* PHY address to be accessed     */
+    mii_address(phyreg, ioaddr);           /* PHY Register to write          */
+    mii_ta(MII_STWR, ioaddr);              /* Turn around time - 2 MDC       */
+    data = mii_swap(data, 16);             /* Swap data bit ordering         */
+    mii_wdata(data, 16, ioaddr);           /* Write data                     */
+    
+    return;
+}
+
+static int
+mii_rdata(u_long ioaddr)
+{
+    int i;
+    s32 tmp = 0;
+    
+    for (i=0; i<16; i++) {
+	tmp <<= 1;
+	tmp |= getfrom_mii(MII_MRD | MII_RD, ioaddr);
+    }
+    
+    return tmp;
+}
+
+static void
+mii_wdata(int data, int len, u_long ioaddr)
+{
+    int i;
+    
+    for (i=0; i<len; i++) {
+	sendto_mii(MII_MWR | MII_WR, data, ioaddr);
+	data >>= 1;
+    }
+    
+    return;
+}
+
+static void
+mii_address(u_char addr, u_long ioaddr)
+{
+    int i;
+    
+    addr = mii_swap(addr, 5);
+    for (i=0; i<5; i++) {
+	sendto_mii(MII_MWR | MII_WR, addr, ioaddr);
+	addr >>= 1;
+    }
+    
+    return;
+}
+
+static void
+mii_ta(u_long rw, u_long ioaddr)
+{
+    if (rw == MII_STWR) {
+	sendto_mii(MII_MWR | MII_WR, 1, ioaddr);  
+	sendto_mii(MII_MWR | MII_WR, 0, ioaddr);  
+    } else {
+	getfrom_mii(MII_MRD | MII_RD, ioaddr);        /* Tri-state MDIO */
+    }
+    
+    return;
+}
+
+static int
+mii_swap(int data, int len)
+{
+    int i, tmp = 0;
+    
+    for (i=0; i<len; i++) {
+	tmp <<= 1;
+	tmp |= (data & 1);
+	data >>= 1;
+    }
+    
+    return tmp;
+}
+
+static void
+sendto_mii(u32 command, int data, u_long ioaddr)
+{
+    u32 j;
+    
+    j = (data & 1) << 17;
+    outl(command | j, ioaddr);
+    udelay(1);
+    outl(command | MII_MDC | j, ioaddr);
+    udelay(1);
+    
+    return;
+}
+
+static int
+getfrom_mii(u32 command, u_long ioaddr)
+{
+    outl(command, ioaddr);
+    udelay(1);
+    outl(command | MII_MDC, ioaddr);
+    udelay(1);
+    
+    return ((inl(ioaddr) >> 19) & 1);
+}
+
+/*
+** Here's 3 ways to calculate the OUI from the ID registers.
+*/
+static int
+mii_get_oui(u_char phyaddr, u_long ioaddr)
+{
+/*
+    union {
+	u_short reg;
+	u_char breg[2];
+    } a;
+    int i, r2, r3, ret=0;*/
+    int r2, r3;
+
+    /* Read r2 and r3 */
+    r2 = mii_rd(MII_ID0, phyaddr, ioaddr);
+    r3 = mii_rd(MII_ID1, phyaddr, ioaddr);
+                                                /* SEEQ and Cypress way * /
+    / * Shuffle r2 and r3 * /
+    a.reg=0;
+    r3 = ((r3>>10)|(r2<<6))&0x0ff;
+    r2 = ((r2>>2)&0x3fff);
+
+    / * Bit reverse r3 * /
+    for (i=0;i<8;i++) {
+	ret<<=1;
+	ret |= (r3&1);
+	r3>>=1;
+    }
+
+    / * Bit reverse r2 * /
+    for (i=0;i<16;i++) {
+	a.reg<<=1;
+	a.reg |= (r2&1);
+	r2>>=1;
+    }
+
+    / * Swap r2 bytes * /
+    i=a.breg[0];
+    a.breg[0]=a.breg[1];
+    a.breg[1]=i;
+
+    return ((a.reg<<8)|ret); */                 /* SEEQ and Cypress way */
+/*    return ((r2<<6)|(u_int)(r3>>10)); */      /* NATIONAL and BROADCOM way */
+    return r2;                                  /* (I did it) My way */
+}
+
+/*
+** The SROM spec forces us to search addresses [1-31 0]. Bummer.
+*/
+static int
+mii_get_phy(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
+    int id;
+    
+    lp->active = 0;
+    lp->useMII = TRUE;
+
+    /* Search the MII address space for possible PHY devices */
+    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
+	lp->phy[lp->active].addr = i;
+	if (i==0) n++;                             /* Count cycles */
+	while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
+	id = mii_get_oui(i, DE4X5_MII); 
+	if ((id == 0) || (id == 65535)) continue;  /* Valid ID? */
+	for (j=0; j<limit; j++) {                  /* Search PHY table */
+	    if (id != phy_info[j].id) continue;    /* ID match? */
+	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+	    if (k < DE4X5_MAX_PHY) {
+		memcpy((char *)&lp->phy[k],
+		       (char *)&phy_info[j], sizeof(struct phy_table));
+		lp->phy[k].addr = i;
+		lp->mii_cnt++;
+		lp->active++;
+	    } else {
+		goto purgatory;                    /* Stop the search */
+	    }
+	    break;
+	}
+	if ((j == limit) && (i < DE4X5_MAX_MII)) {
+	    for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++);
+	    lp->phy[k].addr = i;
+	    lp->phy[k].id = id;
+	    lp->phy[k].spd.reg = GENERIC_REG;      /* ANLPA register         */
+	    lp->phy[k].spd.mask = GENERIC_MASK;    /* 100Mb/s technologies   */
+	    lp->phy[k].spd.value = GENERIC_VALUE;  /* TX & T4, H/F Duplex    */
+	    lp->mii_cnt++;
+	    lp->active++;
+	    printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name);
+	    j = de4x5_debug;
+	    de4x5_debug |= DEBUG_MII;
+	    de4x5_dbg_mii(dev, k);
+	    de4x5_debug = j;
+	    printk("\n");
+	}
+    }
+  purgatory:
+    lp->active = 0;
+    if (lp->phy[0].id) {                           /* Reset the PHY devices */
+	for (k=0; lp->phy[k].id && (k < DE4X5_MAX_PHY); k++) { /*For each PHY*/
+	    mii_wr(MII_CR_RST, MII_CR, lp->phy[k].addr, DE4X5_MII);
+	    while (mii_rd(MII_CR, lp->phy[k].addr, DE4X5_MII) & MII_CR_RST);
+	    
+	    de4x5_dbg_mii(dev, k);
+	}
+    }
+    if (!lp->mii_cnt) lp->useMII = FALSE;
+
+    return lp->mii_cnt;
+}
+
+static char *
+build_setup_frame(struct net_device *dev, int mode)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+    char *pa = lp->setup_frame;
+    
+    /* Initialise the setup frame */
+    if (mode == ALL) {
+	memset(lp->setup_frame, 0, SETUP_FRAME_LEN);
+    }
+    
+    if (lp->setup_f == HASH_PERF) {
+	for (pa=lp->setup_frame+IMPERF_PA_OFFSET, i=0; i<ETH_ALEN; i++) {
+	    *(pa + i) = dev->dev_addr[i];                 /* Host address */
+	    if (i & 0x01) pa += 2;
+	}
+	*(lp->setup_frame + (HASH_TABLE_LEN >> 3) - 3) = 0x80;
+    } else {
+	for (i=0; i<ETH_ALEN; i++) { /* Host address */
+	    *(pa + (i&1)) = dev->dev_addr[i];
+	    if (i & 0x01) pa += 4;
+	}
+	for (i=0; i<ETH_ALEN; i++) { /* Broadcast address */
+	    *(pa + (i&1)) = (char) 0xff;
+	    if (i & 0x01) pa += 4;
+	}
+    }
+    
+    return pa;                     /* Points to the next entry */
+}
+
+static void
+enable_ast(struct net_device *dev, u32 time_out)
+{
+    timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out);
+    
+    return;
+}
+
+static void
+disable_ast(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    
+    del_timer(&lp->timer);
+    
+    return;
+}
+
+static long
+de4x5_switch_mac_port(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    s32 omr;
+
+    STOP_DE4X5;
+
+    /* Assert the OMR_PS bit in CSR6 */
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR |
+			                                             OMR_FDX));
+    omr |= lp->infoblock_csr6;
+    if (omr & OMR_PS) omr |= OMR_HBD;
+    outl(omr, DE4X5_OMR);
+    
+    /* Soft Reset */
+    RESET_DE4X5;
+    
+    /* Restore the GEP - especially for COMPACT and Type 0 Infoblocks */
+    if (lp->chipset == DC21140) {
+	gep_wr(lp->cache.gepc, dev);
+	gep_wr(lp->cache.gep, dev);
+    } else if ((lp->chipset & ~0x0ff) == DC2114x) {
+	reset_init_sia(dev, lp->cache.csr13, lp->cache.csr14, lp->cache.csr15);
+    }
+
+    /* Restore CSR6 */
+    outl(omr, DE4X5_OMR);
+
+    /* Reset CSR8 */
+    inl(DE4X5_MFC);
+
+    return omr;
+}
+
+static void
+gep_wr(s32 data, struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+	outl(data, DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	outl((data<<16) | lp->cache.csr15, DE4X5_SIGR);
+    }
+
+    return;
+}
+
+static int
+gep_rd(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if (lp->chipset == DC21140) {
+	return inl(DE4X5_GEP);
+    } else if ((lp->chipset & ~0x00ff) == DC2114x) {
+	return (inl(DE4X5_SIGR) & 0x000fffff);
+    }
+
+    return 0;
+}
+
+static void
+timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int dt;
+    
+    /* First, cancel any pending timer events */
+    del_timer(&lp->timer);
+    
+    /* Convert msec to ticks */
+    dt = (msec * HZ) / 1000;
+    if (dt==0) dt=1;
+    
+    /* Set up timer */
+    lp->timer.expires = jiffies + dt;
+    lp->timer.function = fn;
+    lp->timer.data = data;
+    add_timer(&lp->timer);
+    
+    return;
+}
+
+static void
+yawn(struct net_device *dev, int state)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+
+    if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return;
+
+    if(lp->bus == EISA) {
+	switch(state) {
+	  case WAKEUP:
+	    outb(WAKEUP, PCI_CFPM);
+	    mdelay(10);
+	    break;
+
+	  case SNOOZE:
+	    outb(SNOOZE, PCI_CFPM);
+	    break;
+
+	  case SLEEP:
+	    outl(0, DE4X5_SICR);
+	    outb(SLEEP, PCI_CFPM);
+	    break;
+	}
+    } else {
+	switch(state) {
+	  case WAKEUP:
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, WAKEUP);
+	    mdelay(10);
+	    break;
+
+	  case SNOOZE:
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, SNOOZE);
+	    break;
+
+	  case SLEEP:
+	    outl(0, DE4X5_SICR);
+	    pcibios_write_config_byte(lp->bus_num, lp->device << 3, 
+				      PCI_CFDA_PSM, SLEEP);
+	    break;
+	}
+    }
+
+    return;
+}
+
+static void
+de4x5_parse_params(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    char *p, *q, t;
+
+    lp->params.fdx = 0;
+    lp->params.autosense = AUTO;
+
+    if (args == NULL) return;
+
+    if ((p = strstr(args, dev->name))) {
+	if (!(q = strstr(p+strlen(dev->name), "eth"))) q = p + strlen(p);
+	t = *q;
+	*q = '\0';
+
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+	if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1;
+#endif
+	if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
+
+	if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
+	    if (strstr(p, "TP")) {
+		lp->params.autosense = TP;
+	    } else if (strstr(p, "TP_NW")) {
+		lp->params.autosense = TP_NW;
+	    } else if (strstr(p, "BNC")) {
+		lp->params.autosense = BNC;
+	    } else if (strstr(p, "AUI")) {
+		lp->params.autosense = AUI;
+	    } else if (strstr(p, "BNC_AUI")) {
+		lp->params.autosense = BNC;
+	    } else if (strstr(p, "10Mb")) {
+		lp->params.autosense = _10Mb;
+	    } else if (strstr(p, "100Mb")) {
+		lp->params.autosense = _100Mb;
+	    } else if (strstr(p, "AUTO")) {
+		lp->params.autosense = AUTO;
+	    }
+	}
+	*q = t;
+    }
+
+    return;
+}
+
+static void
+de4x5_dbg_open(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    int i;
+    
+    if (de4x5_debug & DEBUG_OPEN) {
+	printk("%s: de4x5 opening with irq %d\n",dev->name,dev->irq);
+	printk("\tphysical address: ");
+	for (i=0;i<6;i++) {
+	    printk("%2.2x:",(short)dev->dev_addr[i]);
+	}
+	printk("\n");
+	printk("Descriptor head addresses:\n");
+	printk("\t0x%8.8lx  0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
+	printk("Descriptor addresses:\nRX: ");
+	for (i=0;i<lp->rxRingSize-1;i++){
+	    if (i < 3) {
+		printk("0x%8.8lx  ",(u_long)&lp->rx_ring[i].status);
+	    }
+	}
+	printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
+	printk("TX: ");
+	for (i=0;i<lp->txRingSize-1;i++){
+	    if (i < 3) {
+		printk("0x%8.8lx  ", (u_long)&lp->tx_ring[i].status);
+	    }
+	}
+	printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
+	printk("Descriptor buffers:\nRX: ");
+	for (i=0;i<lp->rxRingSize-1;i++){
+	    if (i < 3) {
+		printk("0x%8.8x  ",le32_to_cpu(lp->rx_ring[i].buf));
+	    }
+	}
+	printk("...0x%8.8x\n",le32_to_cpu(lp->rx_ring[i].buf));
+	printk("TX: ");
+	for (i=0;i<lp->txRingSize-1;i++){
+	    if (i < 3) {
+		printk("0x%8.8x  ", le32_to_cpu(lp->tx_ring[i].buf));
+	    }
+	}
+	printk("...0x%8.8x\n", le32_to_cpu(lp->tx_ring[i].buf));
+	printk("Ring size: \nRX: %d\nTX: %d\n", 
+	       (short)lp->rxRingSize, 
+	       (short)lp->txRingSize); 
+    }
+    
+    return;
+}
+
+static void
+de4x5_dbg_mii(struct net_device *dev, int k)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    u_long iobase = dev->base_addr;
+    
+    if (de4x5_debug & DEBUG_MII) {
+	printk("\nMII device address: %d\n", lp->phy[k].addr);
+	printk("MII CR:  %x\n",mii_rd(MII_CR,lp->phy[k].addr,DE4X5_MII));
+	printk("MII SR:  %x\n",mii_rd(MII_SR,lp->phy[k].addr,DE4X5_MII));
+	printk("MII ID0: %x\n",mii_rd(MII_ID0,lp->phy[k].addr,DE4X5_MII));
+	printk("MII ID1: %x\n",mii_rd(MII_ID1,lp->phy[k].addr,DE4X5_MII));
+	if (lp->phy[k].id != BROADCOM_T4) {
+	    printk("MII ANA: %x\n",mii_rd(0x04,lp->phy[k].addr,DE4X5_MII));
+	    printk("MII ANC: %x\n",mii_rd(0x05,lp->phy[k].addr,DE4X5_MII));
+	}
+	printk("MII 16:  %x\n",mii_rd(0x10,lp->phy[k].addr,DE4X5_MII));
+	if (lp->phy[k].id != BROADCOM_T4) {
+	    printk("MII 17:  %x\n",mii_rd(0x11,lp->phy[k].addr,DE4X5_MII));
+	    printk("MII 18:  %x\n",mii_rd(0x12,lp->phy[k].addr,DE4X5_MII));
+	} else {
+	    printk("MII 20:  %x\n",mii_rd(0x14,lp->phy[k].addr,DE4X5_MII));
+	}
+    }
+    
+    return;
+}
+
+static void
+de4x5_dbg_media(struct net_device *dev)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    
+    if (lp->media != lp->c_media) {
+	if (de4x5_debug & DEBUG_MEDIA) {
+	    printk("%s: media is %s%s\n", dev->name,
+		   (lp->media == NC  ? "unconnected, link down or incompatible connection" :
+		    (lp->media == TP  ? "TP" :
+		     (lp->media == ANS ? "TP/Nway" :
+		      (lp->media == BNC ? "BNC" : 
+		       (lp->media == AUI ? "AUI" : 
+			(lp->media == BNC_AUI ? "BNC/AUI" : 
+			 (lp->media == EXT_SIA ? "EXT SIA" : 
+			  (lp->media == _100Mb  ? "100Mb/s" :
+			   (lp->media == _10Mb   ? "10Mb/s" :
+			    "???"
+			    ))))))))), (lp->fdx?" full duplex.":"."));
+	}
+	lp->c_media = lp->media;
+    }
+    
+    return;
+}
+
+static void
+de4x5_dbg_srom(struct de4x5_srom *p)
+{
+    int i;
+
+    if (de4x5_debug & DEBUG_SROM) {
+	printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
+	printk("Sub-system ID:        %04x\n", *((u_short *)p->sub_system_id));
+	printk("ID Block CRC:         %02x\n", (u_char)(p->id_block_crc));
+	printk("SROM version:         %02x\n", (u_char)(p->version));
+	printk("# controllers:         %02x\n", (u_char)(p->num_controllers));
+
+	printk("Hardware Address:     ");
+	for (i=0;i<ETH_ALEN-1;i++) {
+	    printk("%02x:", (u_char)*(p->ieee_addr+i));
+	}
+	printk("%02x\n", (u_char)*(p->ieee_addr+i));
+	printk("CRC checksum:         %04x\n", (u_short)(p->chksum));
+	for (i=0; i<64; i++) {
+	    printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
+	}
+    }
+
+    return;
+}
+
+static void
+de4x5_dbg_rx(struct sk_buff *skb, int len)
+{
+    int i, j;
+
+    if (de4x5_debug & DEBUG_RX) {
+	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
+	       (u_char)skb->data[0],
+	       (u_char)skb->data[1],
+	       (u_char)skb->data[2],
+	       (u_char)skb->data[3],
+	       (u_char)skb->data[4],
+	       (u_char)skb->data[5],
+	       (u_char)skb->data[6],
+	       (u_char)skb->data[7],
+	       (u_char)skb->data[8],
+	       (u_char)skb->data[9],
+	       (u_char)skb->data[10],
+	       (u_char)skb->data[11],
+	       (u_char)skb->data[12],
+	       (u_char)skb->data[13],
+	       len);
+	for (j=0; len>0;j+=16, len-=16) {
+	  printk("    %03x: ",j);
+	  for (i=0; i<16 && i<len; i++) {
+	    printk("%02x ",(u_char)skb->data[i+j]);
+	  }
+	  printk("\n");
+	}
+    }
+
+    return;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases. In the normal course of events
+** this function is only used for my testing.
+*/
+static int
+de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+    struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
+    u_long iobase = dev->base_addr;
+    int i, j, status = 0;
+    s32 omr;
+    union {
+	u8  addr[144];
+	u16 sval[72];
+	u32 lval[36];
+    } tmp;
+    u_long flags = 0;
+    
+    switch(ioc->cmd) {
+    case DE4X5_GET_HWADDR:           /* Get the hardware address */
+	ioc->len = ETH_ALEN;
+	for (i=0; i<ETH_ALEN; i++) {
+	    tmp.addr[i] = dev->dev_addr[i];
+	}
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
+	break;
+
+    case DE4X5_SET_HWADDR:           /* Set the hardware address */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT;
+	if (netif_queue_stopped(dev))
+		return -EBUSY;
+	netif_stop_queue(dev);
+	for (i=0; i<ETH_ALEN; i++) {
+	    dev->dev_addr[i] = tmp.addr[i];
+	}
+	build_setup_frame(dev, PHYS_ADDR_ONLY);
+	/* Set up the descriptor and give ownership to the card */
+	load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | 
+		                                       SETUP_FRAME_LEN, (struct sk_buff *)1);
+	lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+	outl(POLL_DEMAND, DE4X5_TPD);                /* Start the TX */
+	netif_wake_queue(dev);                      /* Unlock the TX ring */
+	break;
+
+    case DE4X5_SET_PROM:             /* Set Promiscuous Mode */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	omr = inl(DE4X5_OMR);
+	omr |= OMR_PR;
+	outl(omr, DE4X5_OMR);
+	dev->flags |= IFF_PROMISC;
+	break;
+
+    case DE4X5_CLR_PROM:             /* Clear Promiscuous Mode */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	omr = inl(DE4X5_OMR);
+	omr &= ~OMR_PR;
+	outl(omr, DE4X5_OMR);
+	dev->flags &= ~IFF_PROMISC;
+	break;
+
+    case DE4X5_SAY_BOO:              /* Say "Boo!" to the kernel log file */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	printk("%s: Boo!\n", dev->name);
+	break;
+
+    case DE4X5_MCA_EN:               /* Enable pass all multicast addressing */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	omr = inl(DE4X5_OMR);
+	omr |= OMR_PM;
+	outl(omr, DE4X5_OMR);
+	break;
+
+    case DE4X5_GET_STATS:            /* Get the driver statistics */
+    {
+        struct pkt_stats statbuf;
+	ioc->len = sizeof(statbuf);
+	spin_lock_irqsave(&lp->lock, flags);
+	memcpy(&statbuf, &lp->pktStats, ioc->len);
+	spin_unlock_irqrestore(&lp->lock, flags);
+	if (copy_to_user(ioc->data, &statbuf, ioc->len)) 
+		return -EFAULT; 
+	break;
+    }
+    case DE4X5_CLR_STATS:            /* Zero out the driver statistics */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	spin_lock_irqsave(&lp->lock, flags);
+	memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+	spin_unlock_irqrestore(&lp->lock, flags);
+	break;
+
+    case DE4X5_GET_OMR:              /* Get the OMR Register contents */
+	tmp.addr[0] = inl(DE4X5_OMR);
+	if (copy_to_user(ioc->data, tmp.addr, 1)) return -EFAULT;
+	break;
+
+    case DE4X5_SET_OMR:              /* Set the OMR Register contents */
+	if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	if (copy_from_user(tmp.addr, ioc->data, 1)) return -EFAULT;
+	outl(tmp.addr[0], DE4X5_OMR);
+	break;
+
+    case DE4X5_GET_REG:              /* Get the DE4X5 Registers */
+	j = 0;
+	tmp.lval[0] = inl(DE4X5_STS); j+=4;
+	tmp.lval[1] = inl(DE4X5_BMR); j+=4;
+	tmp.lval[2] = inl(DE4X5_IMR); j+=4;
+	tmp.lval[3] = inl(DE4X5_OMR); j+=4;
+	tmp.lval[4] = inl(DE4X5_SISR); j+=4;
+	tmp.lval[5] = inl(DE4X5_SICR); j+=4;
+	tmp.lval[6] = inl(DE4X5_STRR); j+=4;
+	tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
+	ioc->len = j;
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
+	break;
+	
+#define DE4X5_DUMP              0x0f /* Dump the DE4X5 Status */
+/*	
+      case DE4X5_DUMP:
+	j = 0;
+	tmp.addr[j++] = dev->irq;
+	for (i=0; i<ETH_ALEN; i++) {
+	    tmp.addr[j++] = dev->dev_addr[i];
+	}
+	tmp.addr[j++] = lp->rxRingSize;
+	tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
+	tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
+	
+	for (i=0;i<lp->rxRingSize-1;i++){
+	    if (i < 3) {
+		tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+	    }
+	}
+	tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+	for (i=0;i<lp->txRingSize-1;i++){
+	    if (i < 3) {
+		tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+	    }
+	}
+	tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+	
+	for (i=0;i<lp->rxRingSize-1;i++){
+	    if (i < 3) {
+		tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
+	    }
+	}
+	tmp.lval[j>>2] = (s32)le32_to_cpu(lp->rx_ring[i].buf); j+=4;
+	for (i=0;i<lp->txRingSize-1;i++){
+	    if (i < 3) {
+		tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
+	    }
+	}
+	tmp.lval[j>>2] = (s32)le32_to_cpu(lp->tx_ring[i].buf); j+=4;
+	
+	for (i=0;i<lp->rxRingSize;i++){
+	    tmp.lval[j>>2] = le32_to_cpu(lp->rx_ring[i].status); j+=4;
+	}
+	for (i=0;i<lp->txRingSize;i++){
+	    tmp.lval[j>>2] = le32_to_cpu(lp->tx_ring[i].status); j+=4;
+	}
+	
+	tmp.lval[j>>2] = inl(DE4X5_BMR);  j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_TPD);  j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_RPD);  j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_RRBA); j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_TRBA); j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_STS);  j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_OMR);  j+=4;
+	tmp.lval[j>>2] = inl(DE4X5_IMR);  j+=4;
+	tmp.lval[j>>2] = lp->chipset; j+=4; 
+	if (lp->chipset == DC21140) {
+	    tmp.lval[j>>2] = gep_rd(dev);  j+=4;
+	} else {
+	    tmp.lval[j>>2] = inl(DE4X5_SISR); j+=4;
+	    tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
+	    tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
+	    tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4; 
+	}
+	tmp.lval[j>>2] = lp->phy[lp->active].id; j+=4; 
+	if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) {
+	    tmp.lval[j>>2] = lp->active; j+=4; 
+	    tmp.lval[j>>2]=mii_rd(MII_CR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    tmp.lval[j>>2]=mii_rd(MII_SR,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    tmp.lval[j>>2]=mii_rd(MII_ID0,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    tmp.lval[j>>2]=mii_rd(MII_ID1,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    if (lp->phy[lp->active].id != BROADCOM_T4) {
+		tmp.lval[j>>2]=mii_rd(MII_ANA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+		tmp.lval[j>>2]=mii_rd(MII_ANLPA,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    }
+	    tmp.lval[j>>2]=mii_rd(0x10,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    if (lp->phy[lp->active].id != BROADCOM_T4) {
+		tmp.lval[j>>2]=mii_rd(0x11,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+		tmp.lval[j>>2]=mii_rd(0x12,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    } else {
+		tmp.lval[j>>2]=mii_rd(0x14,lp->phy[lp->active].addr,DE4X5_MII); j+=4;
+	    }
+	}
+	
+	tmp.addr[j++] = lp->txRingSize;
+	tmp.addr[j++] = netif_queue_stopped(dev);
+	
+	ioc->len = j;
+	if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT;
+	break;
+
+*/
+    default:
+	return -EOPNOTSUPP;
+    }
+    
+    return status;
+}
+
+#ifdef MODULE
+/*
+** Note now that module autoprobing is allowed under EISA and PCI. The
+** IRQ lines will not be auto-detected; instead I'll rely on the BIOSes
+** to "do the right thing".
+*/
+#define LP(a) ((struct de4x5_private *)(a))
+static struct net_device *mdev = NULL;
+static int io=0x0;/* EDIT THIS LINE FOR YOUR CONFIGURATION IF NEEDED        */
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "de4x5 I/O base address");
+
+int
+init_module(void)
+{
+    int i, num, status = -EIO;
+    struct net_device *p;
+
+    num = count_adapters();
+
+    for (i=0; i<num; i++) {
+	if ((p = insert_device(NULL, io, de4x5_probe)) == NULL) 
+	    return -ENOMEM;
+
+	if (!mdev) mdev = p;
+
+	if (register_netdev(p) != 0) {
+	    struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+	    if (lp) {
+		release_region(p->base_addr, (lp->bus == PCI ? 
+					      DE4X5_PCI_TOTAL_SIZE :
+					      DE4X5_EISA_TOTAL_SIZE));
+		if (lp->cache.priv) {       /* Private area allocated?   */
+		    kfree(lp->cache.priv);  /* Free the private area     */
+		}
+		if (lp->rx_ring) {
+		    pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring,
+					lp->dma_rings);
+		}
+	    }
+	    kfree(p);
+	} else {
+	    status = 0;                 /* At least one adapter will work */
+	    lastModule = p;
+	}
+    }
+
+    return status;
+}
+
+void
+cleanup_module(void)
+{
+    while (mdev != NULL) {
+	mdev = unlink_modules(mdev);
+    }
+
+    return;
+}
+
+static struct net_device *
+unlink_modules(struct net_device *p)
+{
+    struct net_device *next = NULL;
+
+    if (p->priv) {                          /* Private areas allocated?  */
+	struct de4x5_private *lp = (struct de4x5_private *)p->priv;
+
+	next = lp->next_module;
+	if (lp->rx_ring) {
+		pci_free_consistent(lp->pdev, lp->dma_size, lp->rx_ring,
+				    lp->dma_rings);
+	}
+	release_region(p->base_addr, (lp->bus == PCI ? 
+				      DE4X5_PCI_TOTAL_SIZE :
+				      DE4X5_EISA_TOTAL_SIZE));
+	kfree(lp->cache.priv);              /* Free the private area     */
+    }
+    unregister_netdev(p);
+    kfree(p);                               /* Free the device structure */
+    
+    return next;
+}
+
+static int
+count_adapters(void)
+{
+    int i, j=0;
+    u_short vendor;
+    u_int class = DE4X5_CLASS_CODE;
+    u_int device;
+
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+    char name[DE4X5_STRLEN];
+    u_long iobase = 0x1000;
+
+    for (i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+	if (EISA_signature(name, EISA_ID)) j++;
+    }
+#endif
+    if (!pcibios_present()) return j;
+
+    for (i=0; (pdev=pci_find_class(class, pdev))!= NULL; i++) {
+	vendor = pdev->vendor;
+	device = pdev->device << 8;
+	if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++;
+    }
+
+    return j;
+}
+
+/*
+** If at end of eth device list and can't use current entry, malloc
+** one up. If memory could not be allocated, print an error message.
+*/
+static struct net_device * __init 
+insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *))
+{
+    struct net_device *new;
+
+    new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    if (new == NULL) {
+	printk("de4x5.c: Device not initialised, insufficient memory\n");
+	return NULL;
+    } else {
+	memset((char *)new, 0, sizeof(struct net_device));
+	new->base_addr = iobase;       /* assign the io address */
+	new->init = init;              /* initialisation routine */
+    }
+
+    return new;
+}
+
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ *
+ * Delete -DMODVERSIONS below if you didn't define this in your kernel
+ *
+ *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
+ * End:
+ */
diff -urN linux-2.5.6-pre3/drivers/net/tulip/de4x5.h linux-2.5.6/drivers/net/tulip/de4x5.h
--- linux-2.5.6-pre3/drivers/net/tulip/de4x5.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/de4x5.h	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,1031 @@
+/*
+    Copyright 1994 Digital Equipment Corporation.
+
+    This software may be used and distributed according to  the terms of the
+    GNU General Public License, incorporated herein by reference.
+
+    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
+    Equipment Corporation, 550 King Street, Littleton MA 01460.
+
+    =========================================================================
+*/
+
+/*
+** DC21040 CSR<1..15> Register Address Map
+*/
+#define DE4X5_BMR    iobase+(0x000 << lp->bus)  /* Bus Mode Register */
+#define DE4X5_TPD    iobase+(0x008 << lp->bus)  /* Transmit Poll Demand Reg */
+#define DE4X5_RPD    iobase+(0x010 << lp->bus)  /* Receive Poll Demand Reg */
+#define DE4X5_RRBA   iobase+(0x018 << lp->bus)  /* RX Ring Base Address Reg */
+#define DE4X5_TRBA   iobase+(0x020 << lp->bus)  /* TX Ring Base Address Reg */
+#define DE4X5_STS    iobase+(0x028 << lp->bus)  /* Status Register */
+#define DE4X5_OMR    iobase+(0x030 << lp->bus)  /* Operation Mode Register */
+#define DE4X5_IMR    iobase+(0x038 << lp->bus)  /* Interrupt Mask Register */
+#define DE4X5_MFC    iobase+(0x040 << lp->bus)  /* Missed Frame Counter */
+#define DE4X5_APROM  iobase+(0x048 << lp->bus)  /* Ethernet Address PROM */
+#define DE4X5_BROM   iobase+(0x048 << lp->bus)  /* Boot ROM Register */
+#define DE4X5_SROM   iobase+(0x048 << lp->bus)  /* Serial ROM Register */
+#define DE4X5_MII    iobase+(0x048 << lp->bus)  /* MII Interface Register */
+#define DE4X5_DDR    iobase+(0x050 << lp->bus)  /* Data Diagnostic Register */
+#define DE4X5_FDR    iobase+(0x058 << lp->bus)  /* Full Duplex Register */
+#define DE4X5_GPT    iobase+(0x058 << lp->bus)  /* General Purpose Timer Reg.*/
+#define DE4X5_GEP    iobase+(0x060 << lp->bus)  /* General Purpose Register */
+#define DE4X5_SISR   iobase+(0x060 << lp->bus)  /* SIA Status Register */
+#define DE4X5_SICR   iobase+(0x068 << lp->bus)  /* SIA Connectivity Register */
+#define DE4X5_STRR   iobase+(0x070 << lp->bus)  /* SIA TX/RX Register */
+#define DE4X5_SIGR   iobase+(0x078 << lp->bus)  /* SIA General Register */
+
+/*
+** EISA Register Address Map
+*/
+#define EISA_ID      iobase+0x0c80   /* EISA ID Registers */ 
+#define EISA_ID0     iobase+0x0c80   /* EISA ID Register 0 */ 
+#define EISA_ID1     iobase+0x0c81   /* EISA ID Register 1 */ 
+#define EISA_ID2     iobase+0x0c82   /* EISA ID Register 2 */ 
+#define EISA_ID3     iobase+0x0c83   /* EISA ID Register 3 */ 
+#define EISA_CR      iobase+0x0c84   /* EISA Control Register */
+#define EISA_REG0    iobase+0x0c88   /* EISA Configuration Register 0 */
+#define EISA_REG1    iobase+0x0c89   /* EISA Configuration Register 1 */
+#define EISA_REG2    iobase+0x0c8a   /* EISA Configuration Register 2 */
+#define EISA_REG3    iobase+0x0c8f   /* EISA Configuration Register 3 */
+#define EISA_APROM   iobase+0x0c90   /* Ethernet Address PROM */
+
+/*
+** PCI/EISA Configuration Registers Address Map
+*/
+#define PCI_CFID     iobase+0x0008   /* PCI Configuration ID Register */
+#define PCI_CFCS     iobase+0x000c   /* PCI Command/Status Register */
+#define PCI_CFRV     iobase+0x0018   /* PCI Revision Register */
+#define PCI_CFLT     iobase+0x001c   /* PCI Latency Timer Register */
+#define PCI_CBIO     iobase+0x0028   /* PCI Base I/O Register */
+#define PCI_CBMA     iobase+0x002c   /* PCI Base Memory Address Register */
+#define PCI_CBER     iobase+0x0030   /* PCI Expansion ROM Base Address Reg. */
+#define PCI_CFIT     iobase+0x003c   /* PCI Configuration Interrupt Register */
+#define PCI_CFDA     iobase+0x0040   /* PCI Driver Area Register */
+#define PCI_CFDD     iobase+0x0041   /* PCI Driver Dependent Area Register */
+#define PCI_CFPM     iobase+0x0043   /* PCI Power Management Area Register */
+
+/*
+** EISA Configuration Register 0 bit definitions
+*/
+#define ER0_BSW       0x80           /* EISA Bus Slave Width, 1: 32 bits */
+#define ER0_BMW       0x40           /* EISA Bus Master Width, 1: 32 bits */
+#define ER0_EPT       0x20           /* EISA PREEMPT Time, 0: 23 BCLKs */
+#define ER0_ISTS      0x10           /* Interrupt Status (X) */
+#define ER0_LI        0x08           /* Latch Interrupts */
+#define ER0_INTL      0x06           /* INTerrupt Level */
+#define ER0_INTT      0x01           /* INTerrupt Type, 0: Level, 1: Edge */
+
+/*
+** EISA Configuration Register 1 bit definitions
+*/
+#define ER1_IAM       0xe0           /* ISA Address Mode */
+#define ER1_IAE       0x10           /* ISA Addressing Enable */
+#define ER1_UPIN      0x0f           /* User Pins */
+
+/*
+** EISA Configuration Register 2 bit definitions
+*/
+#define ER2_BRS       0xc0           /* Boot ROM Size */
+#define ER2_BRA       0x3c           /* Boot ROM Address <16:13> */
+
+/*
+** EISA Configuration Register 3 bit definitions
+*/
+#define ER3_BWE       0x40           /* Burst Write Enable */
+#define ER3_BRE       0x04           /* Burst Read Enable */
+#define ER3_LSR       0x02           /* Local Software Reset */
+
+/*
+** PCI Configuration ID Register (PCI_CFID). The Device IDs are left
+** shifted 8 bits to allow detection of DC21142 and DC21143 variants with
+** the configuration revision register step number.
+*/
+#define CFID_DID    0xff00           /* Device ID */
+#define CFID_VID    0x00ff           /* Vendor ID */
+#define DC21040_DID 0x0200           /* Unique Device ID # */
+#define DC21040_VID 0x1011           /* DC21040 Manufacturer */
+#define DC21041_DID 0x1400           /* Unique Device ID # */
+#define DC21041_VID 0x1011           /* DC21041 Manufacturer */
+#define DC21140_DID 0x0900           /* Unique Device ID # */
+#define DC21140_VID 0x1011           /* DC21140 Manufacturer */
+#define DC2114x_DID 0x1900           /* Unique Device ID # */
+#define DC2114x_VID 0x1011           /* DC2114[23] Manufacturer */
+
+/*
+** Chipset defines
+*/
+#define DC21040     DC21040_DID
+#define DC21041     DC21041_DID
+#define DC21140     DC21140_DID
+#define DC2114x     DC2114x_DID
+#define DC21142     (DC2114x_DID | 0x0010)
+#define DC21143     (DC2114x_DID | 0x0030)
+#define DC2114x_BRK 0x0020           /* CFRV break between DC21142 & DC21143 */
+
+#define is_DC21040 ((vendor == DC21040_VID) && (device == DC21040_DID))
+#define is_DC21041 ((vendor == DC21041_VID) && (device == DC21041_DID))
+#define is_DC21140 ((vendor == DC21140_VID) && (device == DC21140_DID))
+#define is_DC2114x ((vendor == DC2114x_VID) && (device == DC2114x_DID))
+#define is_DC21142 ((vendor == DC2114x_VID) && (device == DC21142))
+#define is_DC21143 ((vendor == DC2114x_VID) && (device == DC21143))
+
+/*
+** PCI Configuration Command/Status Register (PCI_CFCS)
+*/
+#define CFCS_DPE    0x80000000       /* Detected Parity Error (S) */
+#define CFCS_SSE    0x40000000       /* Signal System Error   (S) */
+#define CFCS_RMA    0x20000000       /* Receive Master Abort  (S) */
+#define CFCS_RTA    0x10000000       /* Receive Target Abort  (S) */
+#define CFCS_DST    0x06000000       /* DEVSEL Timing         (S) */
+#define CFCS_DPR    0x01000000       /* Data Parity Report    (S) */
+#define CFCS_FBB    0x00800000       /* Fast Back-To-Back     (S) */
+#define CFCS_SEE    0x00000100       /* System Error Enable   (C) */
+#define CFCS_PER    0x00000040       /* Parity Error Response (C) */
+#define CFCS_MO     0x00000004       /* Master Operation      (C) */
+#define CFCS_MSA    0x00000002       /* Memory Space Access   (C) */
+#define CFCS_IOSA   0x00000001       /* I/O Space Access      (C) */
+
+/*
+** PCI Configuration Revision Register (PCI_CFRV)
+*/
+#define CFRV_BC     0xff000000       /* Base Class */
+#define CFRV_SC     0x00ff0000       /* Subclass */
+#define CFRV_RN     0x000000f0       /* Revision Number */
+#define CFRV_SN     0x0000000f       /* Step Number */
+#define BASE_CLASS  0x02000000       /* Indicates Network Controller */
+#define SUB_CLASS   0x00000000       /* Indicates Ethernet Controller */
+#define STEP_NUMBER 0x00000020       /* Increments for future chips */
+#define REV_NUMBER  0x00000003       /* 0x00, 0x01, 0x02, 0x03: Rev in Step */
+#define CFRV_MASK   0xffff0000       /* Register mask */
+
+/*
+** PCI Configuration Latency Timer Register (PCI_CFLT)
+*/
+#define CFLT_BC     0x0000ff00       /* Latency Timer bits */
+
+/*
+** PCI Configuration Base I/O Address Register (PCI_CBIO)
+*/
+#define CBIO_MASK   -128             /* Base I/O Address Mask */
+#define CBIO_IOSI   0x00000001       /* I/O Space Indicator (RO, value is 1) */
+
+/*
+** PCI Configuration Card Information Structure Register (PCI_CCIS)
+*/
+#define CCIS_ROMI   0xf0000000       /* ROM Image */
+#define CCIS_ASO    0x0ffffff8       /* Address Space Offset */
+#define CCIS_ASI    0x00000007       /* Address Space Indicator */
+
+/*
+** PCI Configuration Subsystem ID Register (PCI_SSID)
+*/
+#define SSID_SSID   0xffff0000       /* Subsystem ID */
+#define SSID_SVID   0x0000ffff       /* Subsystem Vendor ID */
+
+/*
+** PCI Configuration Expansion ROM Base Address Register (PCI_CBER)
+*/
+#define CBER_MASK   0xfffffc00       /* Expansion ROM Base Address Mask */
+#define CBER_ROME   0x00000001       /* ROM Enable */
+
+/*
+** PCI Configuration Interrupt Register (PCI_CFIT)
+*/
+#define CFIT_MXLT   0xff000000       /* MAX_LAT Value (0.25us periods) */
+#define CFIT_MNGT   0x00ff0000       /* MIN_GNT Value (0.25us periods) */
+#define CFIT_IRQP   0x0000ff00       /* Interrupt Pin */
+#define CFIT_IRQL   0x000000ff       /* Interrupt Line */
+
+/*
+** PCI Configuration Power Management Area Register (PCI_CFPM)
+*/
+#define SLEEP       0x80             /* Power Saving Sleep Mode */
+#define SNOOZE      0x40             /* Power Saving Snooze Mode */
+#define WAKEUP      0x00             /* Power Saving Wakeup */
+
+#define PCI_CFDA_DSU 0x41            /* 8 bit Configuration Space Address */
+#define PCI_CFDA_PSM 0x43            /* 8 bit Configuration Space Address */
+
+/*
+** DC21040 Bus Mode Register (DE4X5_BMR)
+*/
+#define BMR_RML    0x00200000       /* [Memory] Read Multiple */
+#define BMR_DBO    0x00100000       /* Descriptor Byte Ordering (Endian) */
+#define BMR_TAP    0x000e0000       /* Transmit Automatic Polling */
+#define BMR_DAS    0x00010000       /* Diagnostic Address Space */
+#define BMR_CAL    0x0000c000       /* Cache Alignment */
+#define BMR_PBL    0x00003f00       /* Programmable Burst Length */
+#define BMR_BLE    0x00000080       /* Big/Little Endian */
+#define BMR_DSL    0x0000007c       /* Descriptor Skip Length */
+#define BMR_BAR    0x00000002       /* Bus ARbitration */
+#define BMR_SWR    0x00000001       /* Software Reset */
+
+                                    /* Timings here are for 10BASE-T/AUI only*/
+#define TAP_NOPOLL 0x00000000       /* No automatic polling */
+#define TAP_200US  0x00020000       /* TX automatic polling every 200us */
+#define TAP_800US  0x00040000       /* TX automatic polling every 800us */
+#define TAP_1_6MS  0x00060000       /* TX automatic polling every 1.6ms */
+#define TAP_12_8US 0x00080000       /* TX automatic polling every 12.8us */
+#define TAP_25_6US 0x000a0000       /* TX automatic polling every 25.6us */
+#define TAP_51_2US 0x000c0000       /* TX automatic polling every 51.2us */
+#define TAP_102_4US 0x000e0000      /* TX automatic polling every 102.4us */
+
+#define CAL_NOUSE  0x00000000       /* Not used */
+#define CAL_8LONG  0x00004000       /* 8-longword alignment */
+#define CAL_16LONG 0x00008000       /* 16-longword alignment */
+#define CAL_32LONG 0x0000c000       /* 32-longword alignment */
+
+#define PBL_0      0x00000000       /*  DMA burst length = amount in RX FIFO */
+#define PBL_1      0x00000100       /*  1 longword  DMA burst length */
+#define PBL_2      0x00000200       /*  2 longwords DMA burst length */
+#define PBL_4      0x00000400       /*  4 longwords DMA burst length */
+#define PBL_8      0x00000800       /*  8 longwords DMA burst length */
+#define PBL_16     0x00001000       /* 16 longwords DMA burst length */
+#define PBL_32     0x00002000       /* 32 longwords DMA burst length */
+
+#define DSL_0      0x00000000       /*  0 longword  / descriptor */
+#define DSL_1      0x00000004       /*  1 longword  / descriptor */
+#define DSL_2      0x00000008       /*  2 longwords / descriptor */
+#define DSL_4      0x00000010       /*  4 longwords / descriptor */
+#define DSL_8      0x00000020       /*  8 longwords / descriptor */
+#define DSL_16     0x00000040       /* 16 longwords / descriptor */
+#define DSL_32     0x00000080       /* 32 longwords / descriptor */
+
+/*
+** DC21040 Transmit Poll Demand Register (DE4X5_TPD)
+*/
+#define TPD        0x00000001       /* Transmit Poll Demand */
+
+/*
+** DC21040 Receive Poll Demand Register (DE4X5_RPD)
+*/
+#define RPD        0x00000001       /* Receive Poll Demand */
+
+/*
+** DC21040 Receive Ring Base Address Register (DE4X5_RRBA)
+*/
+#define RRBA       0xfffffffc       /* RX Descriptor List Start Address */
+
+/*
+** DC21040 Transmit Ring Base Address Register (DE4X5_TRBA)
+*/
+#define TRBA       0xfffffffc       /* TX Descriptor List Start Address */
+
+/*
+** Status Register (DE4X5_STS)
+*/
+#define STS_GPI    0x04000000       /* General Purpose Port Interrupt */
+#define STS_BE     0x03800000       /* Bus Error Bits */
+#define STS_TS     0x00700000       /* Transmit Process State */
+#define STS_RS     0x000e0000       /* Receive Process State */
+#define STS_NIS    0x00010000       /* Normal Interrupt Summary */
+#define STS_AIS    0x00008000       /* Abnormal Interrupt Summary */
+#define STS_ER     0x00004000       /* Early Receive */
+#define STS_FBE    0x00002000       /* Fatal Bus Error */
+#define STS_SE     0x00002000       /* System Error */
+#define STS_LNF    0x00001000       /* Link Fail */
+#define STS_FD     0x00000800       /* Full-Duplex Short Frame Received */
+#define STS_TM     0x00000800       /* Timer Expired (DC21041) */
+#define STS_ETI    0x00000400       /* Early Transmit Interrupt */
+#define STS_AT     0x00000400       /* AUI/TP Pin */
+#define STS_RWT    0x00000200       /* Receive Watchdog Time-Out */
+#define STS_RPS    0x00000100       /* Receive Process Stopped */
+#define STS_RU     0x00000080       /* Receive Buffer Unavailable */
+#define STS_RI     0x00000040       /* Receive Interrupt */
+#define STS_UNF    0x00000020       /* Transmit Underflow */
+#define STS_LNP    0x00000010       /* Link Pass */
+#define STS_ANC    0x00000010       /* Autonegotiation Complete */
+#define STS_TJT    0x00000008       /* Transmit Jabber Time-Out */
+#define STS_TU     0x00000004       /* Transmit Buffer Unavailable */
+#define STS_TPS    0x00000002       /* Transmit Process Stopped */
+#define STS_TI     0x00000001       /* Transmit Interrupt */
+
+#define EB_PAR     0x00000000       /* Parity Error */
+#define EB_MA      0x00800000       /* Master Abort */
+#define EB_TA      0x01000000       /* Target Abort */
+#define EB_RES0    0x01800000       /* Reserved */
+#define EB_RES1    0x02000000       /* Reserved */
+
+#define TS_STOP    0x00000000       /* Stopped */
+#define TS_FTD     0x00100000       /* Fetch Transmit Descriptor */
+#define TS_WEOT    0x00200000       /* Wait for End Of Transmission */
+#define TS_QDAT    0x00300000       /* Queue skb data into TX FIFO */
+#define TS_RES     0x00400000       /* Reserved */
+#define TS_SPKT    0x00500000       /* Setup Packet */
+#define TS_SUSP    0x00600000       /* Suspended */
+#define TS_CLTD    0x00700000       /* Close Transmit Descriptor */
+
+#define RS_STOP    0x00000000       /* Stopped */
+#define RS_FRD     0x00020000       /* Fetch Receive Descriptor */
+#define RS_CEOR    0x00040000       /* Check for End of Receive Packet */
+#define RS_WFRP    0x00060000       /* Wait for Receive Packet */
+#define RS_SUSP    0x00080000       /* Suspended */
+#define RS_CLRD    0x000a0000       /* Close Receive Descriptor */
+#define RS_FLUSH   0x000c0000       /* Flush RX FIFO */
+#define RS_QRFS    0x000e0000       /* Queue RX FIFO into RX Skb */
+
+#define INT_CANCEL 0x0001ffff       /* For zeroing all interrupt sources */
+
+/*
+** Operation Mode Register (DE4X5_OMR)
+*/
+#define OMR_SC     0x80000000       /* Special Capture Effect Enable */
+#define OMR_RA     0x40000000       /* Receive All */
+#define OMR_SDP    0x02000000       /* SD Polarity - MUST BE ASSERTED */
+#define OMR_SCR    0x01000000       /* Scrambler Mode */
+#define OMR_PCS    0x00800000       /* PCS Function */
+#define OMR_TTM    0x00400000       /* Transmit Threshold Mode */
+#define OMR_SF     0x00200000       /* Store and Forward */
+#define OMR_HBD    0x00080000       /* HeartBeat Disable */
+#define OMR_PS     0x00040000       /* Port Select */
+#define OMR_CA     0x00020000       /* Capture Effect Enable */
+#define OMR_BP     0x00010000       /* Back Pressure */
+#define OMR_TR     0x0000c000       /* Threshold Control Bits */
+#define OMR_ST     0x00002000       /* Start/Stop Transmission Command */
+#define OMR_FC     0x00001000       /* Force Collision Mode */
+#define OMR_OM     0x00000c00       /* Operating Mode */
+#define OMR_FDX    0x00000200       /* Full Duplex Mode */
+#define OMR_FKD    0x00000100       /* Flaky Oscillator Disable */
+#define OMR_PM     0x00000080       /* Pass All Multicast */
+#define OMR_PR     0x00000040       /* Promiscuous Mode */
+#define OMR_SB     0x00000020       /* Start/Stop Backoff Counter */
+#define OMR_IF     0x00000010       /* Inverse Filtering */
+#define OMR_PB     0x00000008       /* Pass Bad Frames */
+#define OMR_HO     0x00000004       /* Hash Only Filtering Mode */
+#define OMR_SR     0x00000002       /* Start/Stop Receive */
+#define OMR_HP     0x00000001       /* Hash/Perfect Receive Filtering Mode */
+
+#define TR_72      0x00000000       /* Threshold set to 72 (128) bytes */
+#define TR_96      0x00004000       /* Threshold set to 96 (256) bytes */
+#define TR_128     0x00008000       /* Threshold set to 128 (512) bytes */
+#define TR_160     0x0000c000       /* Threshold set to 160 (1024) bytes */
+
+#define OMR_DEF     (OMR_SDP)
+#define OMR_SIA     (OMR_SDP | OMR_TTM)
+#define OMR_SYM     (OMR_SDP | OMR_SCR | OMR_PCS | OMR_HBD | OMR_PS)
+#define OMR_MII_10  (OMR_SDP | OMR_TTM | OMR_PS)
+#define OMR_MII_100 (OMR_SDP | OMR_HBD | OMR_PS)
+
+/*
+** DC21040 Interrupt Mask Register (DE4X5_IMR)
+*/
+#define IMR_GPM    0x04000000       /* General Purpose Port Mask */
+#define IMR_NIM    0x00010000       /* Normal Interrupt Summary Mask */
+#define IMR_AIM    0x00008000       /* Abnormal Interrupt Summary Mask */
+#define IMR_ERM    0x00004000       /* Early Receive Mask */
+#define IMR_FBM    0x00002000       /* Fatal Bus Error Mask */
+#define IMR_SEM    0x00002000       /* System Error Mask */
+#define IMR_LFM    0x00001000       /* Link Fail Mask */
+#define IMR_FDM    0x00000800       /* Full-Duplex (Short Frame) Mask */
+#define IMR_TMM    0x00000800       /* Timer Expired Mask (DC21041) */
+#define IMR_ETM    0x00000400       /* Early Transmit Interrupt Mask */
+#define IMR_ATM    0x00000400       /* AUI/TP Switch Mask */
+#define IMR_RWM    0x00000200       /* Receive Watchdog Time-Out Mask */
+#define IMR_RSM    0x00000100       /* Receive Stopped Mask */
+#define IMR_RUM    0x00000080       /* Receive Buffer Unavailable Mask */
+#define IMR_RIM    0x00000040       /* Receive Interrupt Mask */
+#define IMR_UNM    0x00000020       /* Underflow Interrupt Mask */
+#define IMR_ANM    0x00000010       /* Autonegotiation Complete Mask */
+#define IMR_LPM    0x00000010       /* Link Pass */
+#define IMR_TJM    0x00000008       /* Transmit Time-Out Jabber Mask */
+#define IMR_TUM    0x00000004       /* Transmit Buffer Unavailable Mask */
+#define IMR_TSM    0x00000002       /* Transmission Stopped Mask */
+#define IMR_TIM    0x00000001       /* Transmit Interrupt Mask */
+
+/*
+** Missed Frames and FIFO Overflow Counters (DE4X5_MFC)
+*/
+#define MFC_FOCO   0x10000000       /* FIFO Overflow Counter Overflow Bit */
+#define MFC_FOC    0x0ffe0000       /* FIFO Overflow Counter Bits */
+#define MFC_OVFL   0x00010000       /* Missed Frames Counter Overflow Bit */
+#define MFC_CNTR   0x0000ffff       /* Missed Frames Counter Bits */
+#define MFC_FOCM   0x1ffe0000       /* FIFO Overflow Counter Mask */
+
+/*
+** DC21040 Ethernet Address PROM (DE4X5_APROM)
+*/
+#define APROM_DN   0x80000000       /* Data Not Valid */
+#define APROM_DT   0x000000ff       /* Address Byte */
+
+/*
+** DC21041 Boot/Ethernet Address ROM (DE4X5_BROM)
+*/
+#define BROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
+#define BROM_RD   0x00004000       /* Read from Boot ROM */
+#define BROM_WR   0x00002000       /* Write to Boot ROM */
+#define BROM_BR   0x00001000       /* Select Boot ROM when set */
+#define BROM_SR   0x00000800       /* Select Serial ROM when set */
+#define BROM_REG  0x00000400       /* External Register Select */
+#define BROM_DT   0x000000ff       /* Data Byte */
+
+/*
+** DC21041 Serial/Ethernet Address ROM (DE4X5_SROM, DE4X5_MII)
+*/
+#define MII_MDI   0x00080000       /* MII Management Data In */
+#define MII_MDO   0x00060000       /* MII Management Mode/Data Out */
+#define MII_MRD   0x00040000       /* MII Management Define Read Mode */
+#define MII_MWR   0x00000000       /* MII Management Define Write Mode */
+#define MII_MDT   0x00020000       /* MII Management Data Out */
+#define MII_MDC   0x00010000       /* MII Management Clock */
+#define MII_RD    0x00004000       /* Read from MII */
+#define MII_WR    0x00002000       /* Write to MII */
+#define MII_SEL   0x00000800       /* Select MII when RESET */
+
+#define SROM_MODE 0x00008000       /* MODE_1: 0,  MODE_0: 1  (read only) */
+#define SROM_RD   0x00004000       /* Read from Boot ROM */
+#define SROM_WR   0x00002000       /* Write to Boot ROM */
+#define SROM_BR   0x00001000       /* Select Boot ROM when set */
+#define SROM_SR   0x00000800       /* Select Serial ROM when set */
+#define SROM_REG  0x00000400       /* External Register Select */
+#define SROM_DT   0x000000ff       /* Data Byte */
+
+#define DT_OUT    0x00000008       /* Serial Data Out */
+#define DT_IN     0x00000004       /* Serial Data In */
+#define DT_CLK    0x00000002       /* Serial ROM Clock */
+#define DT_CS     0x00000001       /* Serial ROM Chip Select */
+
+#define MII_PREAMBLE 0xffffffff    /* MII Management Preamble */
+#define MII_TEST     0xaaaaaaaa    /* MII Test Signal */
+#define MII_STRD     0x06          /* Start of Frame+Op Code: use low nibble */
+#define MII_STWR     0x0a          /* Start of Frame+Op Code: use low nibble */
+
+#define MII_CR       0x00          /* MII Management Control Register */
+#define MII_SR       0x01          /* MII Management Status Register */
+#define MII_ID0      0x02          /* PHY Identifier Register 0 */
+#define MII_ID1      0x03          /* PHY Identifier Register 1 */
+#define MII_ANA      0x04          /* Auto Negotiation Advertisement */
+#define MII_ANLPA    0x05          /* Auto Negotiation Link Partner Ability */
+#define MII_ANE      0x06          /* Auto Negotiation Expansion */
+#define MII_ANP      0x07          /* Auto Negotiation Next Page TX */
+
+#define DE4X5_MAX_MII 32           /* Maximum address of MII PHY devices */
+
+/*
+** MII Management Control Register
+*/
+#define MII_CR_RST  0x8000         /* RESET the PHY chip */
+#define MII_CR_LPBK 0x4000         /* Loopback enable */
+#define MII_CR_SPD  0x2000         /* 0: 10Mb/s; 1: 100Mb/s */
+#define MII_CR_10   0x0000         /* Set 10Mb/s */
+#define MII_CR_100  0x2000         /* Set 100Mb/s */
+#define MII_CR_ASSE 0x1000         /* Auto Speed Select Enable */
+#define MII_CR_PD   0x0800         /* Power Down */
+#define MII_CR_ISOL 0x0400         /* Isolate Mode */
+#define MII_CR_RAN  0x0200         /* Restart Auto Negotiation */
+#define MII_CR_FDM  0x0100         /* Full Duplex Mode */
+#define MII_CR_CTE  0x0080         /* Collision Test Enable */
+
+/*
+** MII Management Status Register
+*/
+#define MII_SR_T4C  0x8000         /* 100BASE-T4 capable */
+#define MII_SR_TXFD 0x4000         /* 100BASE-TX Full Duplex capable */
+#define MII_SR_TXHD 0x2000         /* 100BASE-TX Half Duplex capable */
+#define MII_SR_TFD  0x1000         /* 10BASE-T Full Duplex capable */
+#define MII_SR_THD  0x0800         /* 10BASE-T Half Duplex capable */
+#define MII_SR_ASSC 0x0020         /* Auto Speed Selection Complete*/
+#define MII_SR_RFD  0x0010         /* Remote Fault Detected */
+#define MII_SR_ANC  0x0008         /* Auto Negotiation capable */
+#define MII_SR_LKS  0x0004         /* Link Status */
+#define MII_SR_JABD 0x0002         /* Jabber Detect */
+#define MII_SR_XC   0x0001         /* Extended Capabilities */
+
+/*
+** MII Management Auto Negotiation Advertisement Register
+*/
+#define MII_ANA_TAF  0x03e0        /* Technology Ability Field */
+#define MII_ANA_T4AM 0x0200        /* T4 Technology Ability Mask */
+#define MII_ANA_TXAM 0x0180        /* TX Technology Ability Mask */
+#define MII_ANA_FDAM 0x0140        /* Full Duplex Technology Ability Mask */
+#define MII_ANA_HDAM 0x02a0        /* Half Duplex Technology Ability Mask */
+#define MII_ANA_100M 0x0380        /* 100Mb Technology Ability Mask */
+#define MII_ANA_10M  0x0060        /* 10Mb Technology Ability Mask */
+#define MII_ANA_CSMA 0x0001        /* CSMA-CD Capable */
+
+/*
+** MII Management Auto Negotiation Remote End Register
+*/
+#define MII_ANLPA_NP   0x8000      /* Next Page (Enable) */
+#define MII_ANLPA_ACK  0x4000      /* Remote Acknowledge */
+#define MII_ANLPA_RF   0x2000      /* Remote Fault */
+#define MII_ANLPA_TAF  0x03e0      /* Technology Ability Field */
+#define MII_ANLPA_T4AM 0x0200      /* T4 Technology Ability Mask */
+#define MII_ANLPA_TXAM 0x0180      /* TX Technology Ability Mask */
+#define MII_ANLPA_FDAM 0x0140      /* Full Duplex Technology Ability Mask */
+#define MII_ANLPA_HDAM 0x02a0      /* Half Duplex Technology Ability Mask */
+#define MII_ANLPA_100M 0x0380      /* 100Mb Technology Ability Mask */
+#define MII_ANLPA_10M  0x0060      /* 10Mb Technology Ability Mask */
+#define MII_ANLPA_CSMA 0x0001      /* CSMA-CD Capable */
+
+/*
+** SROM Media Definitions (ABG SROM Section)
+*/
+#define MEDIA_NWAY     0x0080      /* Nway (Auto Negotiation) on PHY */
+#define MEDIA_MII      0x0040      /* MII Present on the adapter */
+#define MEDIA_FIBRE    0x0008      /* Fibre Media present */
+#define MEDIA_AUI      0x0004      /* AUI Media present */
+#define MEDIA_TP       0x0002      /* TP Media present */
+#define MEDIA_BNC      0x0001      /* BNC Media present */
+
+/*
+** SROM Definitions (Digital Semiconductor Format)
+*/
+#define SROM_SSVID     0x0000      /* Sub-system Vendor ID offset */
+#define SROM_SSID      0x0002      /* Sub-system ID offset */
+#define SROM_CISPL     0x0004      /* CardBus CIS Pointer low offset */
+#define SROM_CISPH     0x0006      /* CardBus CIS Pointer high offset */
+#define SROM_IDCRC     0x0010      /* ID Block CRC offset*/
+#define SROM_RSVD2     0x0011      /* ID Reserved 2 offset */
+#define SROM_SFV       0x0012      /* SROM Format Version offset */
+#define SROM_CCNT      0x0013      /* Controller Count offset */
+#define SROM_HWADD     0x0014      /* Hardware Address offset */
+#define SROM_MRSVD     0x007c      /* Manufacturer Reserved offset*/
+#define SROM_CRC       0x007e      /* SROM CRC offset */
+
+/*
+** SROM Media Connection Definitions
+*/
+#define SROM_10BT      0x0000      /*  10BASE-T half duplex */
+#define SROM_10BTN     0x0100      /*  10BASE-T with Nway */
+#define SROM_10BTF     0x0204      /*  10BASE-T full duplex */
+#define SROM_10BTNLP   0x0400      /*  10BASE-T without Link Pass test */
+#define SROM_10B2      0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10B5      0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BTH    0x0003      /*  100BASE-T half duplex */
+#define SROM_100BTF    0x0205      /*  100BASE-T full duplex */
+#define SROM_100BT4    0x0006      /*  100BASE-T4 */
+#define SROM_100BFX    0x0007      /*  100BASE-FX half duplex (Fiber) */
+#define SROM_M10BT     0x0009      /*  MII 10BASE-T half duplex */
+#define SROM_M10BTF    0x020a      /*  MII 10BASE-T full duplex */
+#define SROM_M100BT    0x000d      /*  MII 100BASE-T half duplex */
+#define SROM_M100BTF   0x020e      /*  MII 100BASE-T full duplex */
+#define SROM_M100BT4   0x000f      /*  MII 100BASE-T4 */
+#define SROM_M100BF    0x0010      /*  MII 100BASE-FX half duplex */
+#define SROM_M100BFF   0x0211      /*  MII 100BASE-FX full duplex */
+#define SROM_PDA       0x0800      /*  Powerup & Dynamic Autosense */
+#define SROM_PAO       0x8800      /*  Powerup Autosense Only */
+#define SROM_NSMI      0xffff      /*  No Selected Media Information */
+
+/*
+** SROM Media Definitions
+*/
+#define SROM_10BASET   0x0000      /*  10BASE-T half duplex */
+#define SROM_10BASE2   0x0001      /*  10BASE-2 (BNC) */
+#define SROM_10BASE5   0x0002      /*  10BASE-5 (AUI) */
+#define SROM_100BASET  0x0003      /*  100BASE-T half duplex */
+#define SROM_10BASETF  0x0004      /*  10BASE-T full duplex */
+#define SROM_100BASETF 0x0005      /*  100BASE-T full duplex */
+#define SROM_100BASET4 0x0006      /*  100BASE-T4 */
+#define SROM_100BASEF  0x0007      /*  100BASE-FX half duplex */
+#define SROM_100BASEFF 0x0008      /*  100BASE-FX full duplex */
+
+#define BLOCK_LEN      0x7f        /* Extended blocks length mask */
+#define EXT_FIELD      0x40        /* Extended blocks extension field bit */
+#define MEDIA_CODE     0x3f        /* Extended blocks media code mask */
+
+/*
+** SROM Compact Format Block Masks
+*/
+#define COMPACT_FI      0x80       /* Format Indicator */
+#define COMPACT_LEN     0x04       /* Length */
+#define COMPACT_MC      0x3f       /* Media Code */
+
+/*
+** SROM Extended Format Block Type 0 Masks
+*/
+#define BLOCK0_FI      0x80        /* Format Indicator */
+#define BLOCK0_MCS     0x80        /* Media Code byte Sign */
+#define BLOCK0_MC      0x3f        /* Media Code */
+
+/*
+** DC21040 Full Duplex Register (DE4X5_FDR)
+*/
+#define FDR_FDACV  0x0000ffff      /* Full Duplex Auto Configuration Value */
+
+/*
+** DC21041 General Purpose Timer Register (DE4X5_GPT)
+*/
+#define GPT_CON  0x00010000        /* One shot: 0,  Continuous: 1 */
+#define GPT_VAL  0x0000ffff        /* Timer Value */
+
+/*
+** DC21140 General Purpose Register (DE4X5_GEP) (hardware dependent bits)
+*/
+/* Valid ONLY for DE500 hardware */
+#define GEP_LNP  0x00000080        /* Link Pass               (input)        */
+#define GEP_SLNK 0x00000040        /* SYM LINK                (input)        */
+#define GEP_SDET 0x00000020        /* Signal Detect           (input)        */
+#define GEP_HRST 0x00000010        /* Hard RESET (to PHY)     (output)       */
+#define GEP_FDXD 0x00000008        /* Full Duplex Disable     (output)       */
+#define GEP_PHYL 0x00000004        /* PHY Loopback            (output)       */
+#define GEP_FLED 0x00000002        /* Force Activity LED on   (output)       */
+#define GEP_MODE 0x00000001        /* 0: 10Mb/s,  1: 100Mb/s                 */
+#define GEP_INIT 0x0000011f        /* Setup inputs (0) and outputs (1)       */
+#define GEP_CTRL 0x00000100        /* GEP control bit                        */
+
+/*
+** SIA Register Defaults
+*/
+#define CSR13 0x00000001
+#define CSR14 0x0003ff7f           /* Autonegotiation disabled               */
+#define CSR15 0x00000008
+
+/*
+** SIA Status Register (DE4X5_SISR)
+*/
+#define SISR_LPC   0xffff0000      /* Link Partner's Code Word               */
+#define SISR_LPN   0x00008000      /* Link Partner Negotiable                */
+#define SISR_ANS   0x00007000      /* Auto Negotiation Arbitration State     */
+#define SISR_NSN   0x00000800      /* Non Stable NLPs Detected (DC21041)     */
+#define SISR_TRF   0x00000800      /* Transmit Remote Fault                  */
+#define SISR_NSND  0x00000400      /* Non Stable NLPs Detected (DC21142)     */
+#define SISR_ANR_FDS 0x00000400    /* Auto Negotiate Restart/Full Duplex Sel.*/
+#define SISR_TRA   0x00000200      /* 10BASE-T Receive Port Activity         */
+#define SISR_NRA   0x00000200      /* Non Selected Port Receive Activity     */
+#define SISR_ARA   0x00000100      /* AUI Receive Port Activity              */
+#define SISR_SRA   0x00000100      /* Selected Port Receive Activity         */
+#define SISR_DAO   0x00000080      /* PLL All One                            */
+#define SISR_DAZ   0x00000040      /* PLL All Zero                           */
+#define SISR_DSP   0x00000020      /* PLL Self-Test Pass                     */
+#define SISR_DSD   0x00000010      /* PLL Self-Test Done                     */
+#define SISR_APS   0x00000008      /* Auto Polarity State                    */
+#define SISR_LKF   0x00000004      /* Link Fail Status                       */
+#define SISR_LS10  0x00000004      /* 10Mb/s Link Fail Status                */
+#define SISR_NCR   0x00000002      /* Network Connection Error               */
+#define SISR_LS100 0x00000002      /* 100Mb/s Link Fail Status               */
+#define SISR_PAUI  0x00000001      /* AUI_TP Indication                      */
+#define SISR_MRA   0x00000001      /* MII Receive Port Activity              */
+
+#define ANS_NDIS   0x00000000      /* Nway disable                           */
+#define ANS_TDIS   0x00001000      /* Transmit Disable                       */
+#define ANS_ADET   0x00002000      /* Ability Detect                         */
+#define ANS_ACK    0x00003000      /* Acknowledge                            */
+#define ANS_CACK   0x00004000      /* Complete Acknowledge                   */
+#define ANS_NWOK   0x00005000      /* Nway OK - FLP Link Good                */
+#define ANS_LCHK   0x00006000      /* Link Check                             */
+
+#define SISR_RST   0x00000301      /* CSR12 reset                            */
+#define SISR_ANR   0x00001301      /* Autonegotiation restart                */
+
+/*
+** SIA Connectivity Register (DE4X5_SICR)
+*/
+#define SICR_SDM   0xffff0000       /* SIA Diagnostics Mode */
+#define SICR_OE57  0x00008000       /* Output Enable 5 6 7 */
+#define SICR_OE24  0x00004000       /* Output Enable 2 4 */
+#define SICR_OE13  0x00002000       /* Output Enable 1 3 */
+#define SICR_IE    0x00001000       /* Input Enable */
+#define SICR_EXT   0x00000000       /* SIA MUX Select External SIA Mode */
+#define SICR_D_SIA 0x00000400       /* SIA MUX Select Diagnostics - SIA Sigs */
+#define SICR_DPLL  0x00000800       /* SIA MUX Select Diagnostics - DPLL Sigs*/
+#define SICR_APLL  0x00000a00       /* SIA MUX Select Diagnostics - DPLL Sigs*/
+#define SICR_D_RxM 0x00000c00       /* SIA MUX Select Diagnostics - RxM Sigs */
+#define SICR_M_RxM 0x00000d00       /* SIA MUX Select Diagnostics - RxM Sigs */
+#define SICR_LNKT  0x00000e00       /* SIA MUX Select Diagnostics - Link Test*/
+#define SICR_SEL   0x00000f00       /* SIA MUX Select AUI or TP with LEDs */
+#define SICR_ASE   0x00000080       /* APLL Start Enable*/
+#define SICR_SIM   0x00000040       /* Serial Interface Input Multiplexer */
+#define SICR_ENI   0x00000020       /* Encoder Input Multiplexer */
+#define SICR_EDP   0x00000010       /* SIA PLL External Input Enable */
+#define SICR_AUI   0x00000008       /* 10Base-T (0) or AUI (1) */
+#define SICR_CAC   0x00000004       /* CSR Auto Configuration */
+#define SICR_PS    0x00000002       /* Pin AUI/TP Selection */
+#define SICR_SRL   0x00000001       /* SIA Reset */
+#define SIA_RESET  0x00000000       /* SIA Reset Value */
+
+/*
+** SIA Transmit and Receive Register (DE4X5_STRR)
+*/
+#define STRR_TAS   0x00008000       /* 10Base-T/AUI Autosensing Enable */
+#define STRR_SPP   0x00004000       /* Set Polarity Plus */
+#define STRR_APE   0x00002000       /* Auto Polarity Enable */
+#define STRR_LTE   0x00001000       /* Link Test Enable */
+#define STRR_SQE   0x00000800       /* Signal Quality Enable */
+#define STRR_CLD   0x00000400       /* Collision Detect Enable */
+#define STRR_CSQ   0x00000200       /* Collision Squelch Enable */
+#define STRR_RSQ   0x00000100       /* Receive Squelch Enable */
+#define STRR_ANE   0x00000080       /* Auto Negotiate Enable */
+#define STRR_HDE   0x00000040       /* Half Duplex Enable */
+#define STRR_CPEN  0x00000030       /* Compensation Enable */
+#define STRR_LSE   0x00000008       /* Link Pulse Send Enable */
+#define STRR_DREN  0x00000004       /* Driver Enable */
+#define STRR_LBK   0x00000002       /* Loopback Enable */
+#define STRR_ECEN  0x00000001       /* Encoder Enable */
+#define STRR_RESET 0xffffffff       /* Reset value for STRR */
+
+/*
+** SIA General Register (DE4X5_SIGR)
+*/
+#define SIGR_RMI   0x40000000       /* Receive Match Interrupt */
+#define SIGR_GI1   0x20000000       /* General Port Interrupt 1 */
+#define SIGR_GI0   0x10000000       /* General Port Interrupt 0 */
+#define SIGR_CWE   0x08000000       /* Control Write Enable */
+#define SIGR_RME   0x04000000       /* Receive Match Enable */
+#define SIGR_GEI1  0x02000000       /* GEP Interrupt Enable on Port 1 */
+#define SIGR_GEI0  0x01000000       /* GEP Interrupt Enable on Port 0 */
+#define SIGR_LGS3  0x00800000       /* LED/GEP3 Select */
+#define SIGR_LGS2  0x00400000       /* LED/GEP2 Select */
+#define SIGR_LGS1  0x00200000       /* LED/GEP1 Select */
+#define SIGR_LGS0  0x00100000       /* LED/GEP0 Select */
+#define SIGR_MD    0x000f0000       /* General Purpose Mode and Data */
+#define SIGR_LV2   0x00008000       /* General Purpose LED2 value */
+#define SIGR_LE2   0x00004000       /* General Purpose LED2 enable */
+#define SIGR_FRL   0x00002000       /* Force Receiver Low */
+#define SIGR_DPST  0x00001000       /* PLL Self Test Start */
+#define SIGR_LSD   0x00000800       /* LED Stretch Disable */
+#define SIGR_FLF   0x00000400       /* Force Link Fail */
+#define SIGR_FUSQ  0x00000200       /* Force Unsquelch */
+#define SIGR_TSCK  0x00000100       /* Test Clock */
+#define SIGR_LV1   0x00000080       /* General Purpose LED1 value */
+#define SIGR_LE1   0x00000040       /* General Purpose LED1 enable */
+#define SIGR_RWR   0x00000020       /* Receive Watchdog Release */
+#define SIGR_RWD   0x00000010       /* Receive Watchdog Disable */
+#define SIGR_ABM   0x00000008       /* BNC: 0,  AUI:1 */
+#define SIGR_JCK   0x00000004       /* Jabber Clock */
+#define SIGR_HUJ   0x00000002       /* Host Unjab */
+#define SIGR_JBD   0x00000001       /* Jabber Disable */
+#define SIGR_RESET 0xffff0000       /* Reset value for SIGR */
+
+/*
+** Receive Descriptor Bit Summary
+*/
+#define R_OWN      0x80000000       /* Own Bit */
+#define RD_FF      0x40000000       /* Filtering Fail */
+#define RD_FL      0x3fff0000       /* Frame Length */
+#define RD_ES      0x00008000       /* Error Summary */
+#define RD_LE      0x00004000       /* Length Error */
+#define RD_DT      0x00003000       /* Data Type */
+#define RD_RF      0x00000800       /* Runt Frame */
+#define RD_MF      0x00000400       /* Multicast Frame */
+#define RD_FS      0x00000200       /* First Descriptor */
+#define RD_LS      0x00000100       /* Last Descriptor */
+#define RD_TL      0x00000080       /* Frame Too Long */
+#define RD_CS      0x00000040       /* Collision Seen */
+#define RD_FT      0x00000020       /* Frame Type */
+#define RD_RJ      0x00000010       /* Receive Watchdog */
+#define RD_RE      0x00000008       /* Report on MII Error */
+#define RD_DB      0x00000004       /* Dribbling Bit */
+#define RD_CE      0x00000002       /* CRC Error */
+#define RD_OF      0x00000001       /* Overflow */
+
+#define RD_RER     0x02000000       /* Receive End Of Ring */
+#define RD_RCH     0x01000000       /* Second Address Chained */
+#define RD_RBS2    0x003ff800       /* Buffer 2 Size */
+#define RD_RBS1    0x000007ff       /* Buffer 1 Size */
+
+/*
+** Transmit Descriptor Bit Summary
+*/
+#define T_OWN      0x80000000       /* Own Bit */
+#define TD_ES      0x00008000       /* Error Summary */
+#define TD_TO      0x00004000       /* Transmit Jabber Time-Out */
+#define TD_LO      0x00000800       /* Loss Of Carrier */
+#define TD_NC      0x00000400       /* No Carrier */
+#define TD_LC      0x00000200       /* Late Collision */
+#define TD_EC      0x00000100       /* Excessive Collisions */
+#define TD_HF      0x00000080       /* Heartbeat Fail */
+#define TD_CC      0x00000078       /* Collision Counter */
+#define TD_LF      0x00000004       /* Link Fail */
+#define TD_UF      0x00000002       /* Underflow Error */
+#define TD_DE      0x00000001       /* Deferred */
+
+#define TD_IC      0x80000000       /* Interrupt On Completion */
+#define TD_LS      0x40000000       /* Last Segment */
+#define TD_FS      0x20000000       /* First Segment */
+#define TD_FT1     0x10000000       /* Filtering Type */
+#define TD_SET     0x08000000       /* Setup Packet */
+#define TD_AC      0x04000000       /* Add CRC Disable */
+#define TD_TER     0x02000000       /* Transmit End Of Ring */
+#define TD_TCH     0x01000000       /* Second Address Chained */
+#define TD_DPD     0x00800000       /* Disabled Padding */
+#define TD_FT0     0x00400000       /* Filtering Type */
+#define TD_TBS2    0x003ff800       /* Buffer 2 Size */
+#define TD_TBS1    0x000007ff       /* Buffer 1 Size */
+
+#define PERFECT_F  0x00000000
+#define HASH_F     TD_FT0
+#define INVERSE_F  TD_FT1
+#define HASH_O_F   (TD_FT1 | TD_F0)
+
+/*
+** Media / mode state machine definitions
+** User selectable:
+*/
+#define TP              0x0040     /* 10Base-T (now equiv to _10Mb)        */
+#define TP_NW           0x0002     /* 10Base-T with Nway                   */
+#define BNC             0x0004     /* Thinwire                             */
+#define AUI             0x0008     /* Thickwire                            */
+#define BNC_AUI         0x0010     /* BNC/AUI on DC21040 indistinguishable */
+#define _10Mb           0x0040     /* 10Mb/s Ethernet                      */
+#define _100Mb          0x0080     /* 100Mb/s Ethernet                     */
+#define AUTO            0x4000     /* Auto sense the media or speed        */
+
+/*
+** Internal states
+*/
+#define NC              0x0000     /* No Connection                        */
+#define ANS             0x0020     /* Intermediate AutoNegotiation State   */
+#define SPD_DET         0x0100     /* Parallel speed detection             */
+#define INIT            0x0200     /* Initial state                        */
+#define EXT_SIA         0x0400     /* External SIA for motherboard chip    */
+#define ANS_SUSPECT     0x0802     /* Suspect the ANS (TP) port is down    */
+#define TP_SUSPECT      0x0803     /* Suspect the TP port is down          */
+#define BNC_AUI_SUSPECT 0x0804     /* Suspect the BNC or AUI port is down  */
+#define EXT_SIA_SUSPECT 0x0805     /* Suspect the EXT SIA port is down     */
+#define BNC_SUSPECT     0x0806     /* Suspect the BNC port is down         */
+#define AUI_SUSPECT     0x0807     /* Suspect the AUI port is down         */
+#define MII             0x1000     /* MII on the 21143                     */
+
+#define TIMER_CB        0x80000000 /* Timer callback detection             */
+
+/*
+** DE4X5 DEBUG Options
+*/
+#define DEBUG_NONE      0x0000     /* No DEBUG messages */
+#define DEBUG_VERSION   0x0001     /* Print version message */
+#define DEBUG_MEDIA     0x0002     /* Print media messages */
+#define DEBUG_TX        0x0004     /* Print TX (queue_pkt) messages */
+#define DEBUG_RX        0x0008     /* Print RX (de4x5_rx) messages */
+#define DEBUG_SROM      0x0010     /* Print SROM messages */
+#define DEBUG_MII       0x0020     /* Print MII messages */
+#define DEBUG_OPEN      0x0040     /* Print de4x5_open() messages */
+#define DEBUG_CLOSE     0x0080     /* Print de4x5_close() messages */
+#define DEBUG_PCICFG    0x0100
+#define DEBUG_ALL       0x01ff
+
+/*
+** Miscellaneous
+*/
+#define PCI  0
+#define EISA 1
+
+#define HASH_TABLE_LEN   512       /* Bits */
+#define HASH_BITS        0x01ff    /* 9 LS bits */
+
+#define SETUP_FRAME_LEN  192       /* Bytes */
+#define IMPERF_PA_OFFSET 156       /* Bytes */
+
+#define POLL_DEMAND          1
+
+#define LOST_MEDIA_THRESHOLD 3
+
+#define MASK_INTERRUPTS      1
+#define UNMASK_INTERRUPTS    0
+
+#define DE4X5_STRLEN         8
+
+#define DE4X5_INIT           0     /* Initialisation time */
+#define DE4X5_RUN            1     /* Run time */
+
+#define DE4X5_SAVE_STATE     0
+#define DE4X5_RESTORE_STATE  1
+
+/*
+** Address Filtering Modes
+*/
+#define PERFECT              0     /* 16 perfect physical addresses */
+#define HASH_PERF            1     /* 1 perfect, 512 multicast addresses */
+#define PERFECT_REJ          2     /* Reject 16 perfect physical addresses */
+#define ALL_HASH             3     /* Hashes all physical & multicast addrs */
+
+#define ALL                  0     /* Clear out all the setup frame */
+#define PHYS_ADDR_ONLY       1     /* Update the physical address only */
+
+/*
+** Booleans
+*/
+#define NO                   0
+#define FALSE                0
+
+#define YES                  ~0
+#define TRUE                 ~0
+
+/*
+** Adapter state
+*/
+#define INITIALISED          0     /* After h/w initialised and mem alloc'd */
+#define CLOSED               1     /* Ready for opening */
+#define OPEN                 2     /* Running */
+
+/*
+** Various wait times
+*/
+#define PDET_LINK_WAIT    1200    /* msecs to wait for link detect bits     */
+#define ANS_FINISH_WAIT   1000    /* msecs to wait for link detect bits     */
+
+/*
+** IEEE OUIs for various PHY vendor/chip combos - Reg 2 values only. Since
+** the vendors seem split 50-50 on how to calculate the OUI register values
+** anyway, just reading Reg2 seems reasonable for now [see de4x5_get_oui()].
+*/
+#define NATIONAL_TX 0x2000
+#define BROADCOM_T4 0x03e0
+#define SEEQ_T4     0x0016
+#define CYPRESS_T4  0x0014
+
+/*
+** Speed Selection stuff
+*/
+#define SET_10Mb {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_10|(lp->fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr |= ((lp->fdx ? OMR_FDX : 0) | OMR_TTM);\
+    outl(omr, DE4X5_OMR);\
+    if (!lp->useSROM) lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | (lp->infoblock_csr6 & ~(OMR_SCR | OMR_HBD)), DE4X5_OMR);\
+  } else {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | OMR_SDP | OMR_TTM, DE4X5_OMR);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD);\
+    gep_wr(lp->cache.gep, dev);\
+  }\
+}
+
+#define SET_100Mb {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
+    int fdx=0;\
+    if (lp->phy[lp->active].id == NATIONAL_TX) {\
+        mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\
+                      0x18, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX);\
+    sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\
+    if (!(sr & MII_ANA_T4AM) && lp->fdx) fdx=1;\
+    if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\
+      mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    }\
+    if (fdx) omr |= OMR_FDX;\
+    outl(omr, DE4X5_OMR);\
+    if (!lp->useSROM) lp->cache.gep = 0;\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | lp->infoblock_csr6, DE4X5_OMR);\
+  } else {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    omr |= (lp->fdx ? OMR_FDX : 0);\
+    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\
+    lp->cache.gep = (lp->fdx ? 0 : GEP_FDXD) | GEP_MODE;\
+    gep_wr(lp->cache.gep, dev);\
+  }\
+}
+
+/* FIX ME so I don't jam 10Mb networks */
+#define SET_100Mb_PDET {\
+  if ((lp->phy[lp->active].id) && (!lp->useSROM || lp->useMII)) {\
+    mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    outl(omr, DE4X5_OMR);\
+  } else if (lp->useSROM && !lp->useMII) {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    outl(omr, DE4X5_OMR);\
+  } else {\
+    omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FDX));\
+    outl(omr | OMR_SDP | OMR_PS | OMR_HBD | OMR_PCS, DE4X5_OMR);\
+    lp->cache.gep = (GEP_FDXD | GEP_MODE);\
+    gep_wr(lp->cache.gep, dev);\
+  }\
+}
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define	DE4X5IOCTL	SIOCDEVPRIVATE
+
+struct de4x5_ioctl {
+	unsigned short cmd;                /* Command to run */
+	unsigned short len;                /* Length of the data buffer */
+	unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised commands for the driver 
+*/
+#define DE4X5_GET_HWADDR	0x01 /* Get the hardware address */
+#define DE4X5_SET_HWADDR	0x02 /* Set the hardware address */
+#define DE4X5_SET_PROM  	0x03 /* Set Promiscuous Mode */
+#define DE4X5_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
+#define DE4X5_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
+#define DE4X5_GET_MCA   	0x06 /* Get a multicast address */
+#define DE4X5_SET_MCA   	0x07 /* Set a multicast address */
+#define DE4X5_CLR_MCA    	0x08 /* Clear a multicast address */
+#define DE4X5_MCA_EN    	0x09 /* Enable a multicast address group */
+#define DE4X5_GET_STATS  	0x0a /* Get the driver statistics */
+#define DE4X5_CLR_STATS 	0x0b /* Zero out the driver statistics */
+#define DE4X5_GET_OMR           0x0c /* Get the OMR Register contents */
+#define DE4X5_SET_OMR           0x0d /* Set the OMR Register contents */
+#define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#define MOTO_SROM_BUG    ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((s32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
diff -urN linux-2.5.6-pre3/drivers/net/tulip/dmfe.c linux-2.5.6/drivers/net/tulip/dmfe.c
--- linux-2.5.6-pre3/drivers/net/tulip/dmfe.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/dmfe.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,2070 @@
+/*
+    A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
+    ethernet driver for Linux.
+    Copyright (C) 1997  Sten Wang
+
+    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.
+
+    DAVICOM Web-Site: www.davicom.com.tw
+
+    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
+    Maintainer: Tobias Ringstrom <tori@unhappy.mine.nu>
+
+    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
+
+    Marcelo Tosatti <marcelo@conectiva.com.br> :
+    Made it compile in 2.3 (device to net_device)
+
+    Alan Cox <alan@redhat.com> :
+    Cleaned up for kernel merge.
+    Removed the back compatibility support
+    Reformatted, fixing spelling etc as I went
+    Removed IRQ 0-15 assumption
+
+    Jeff Garzik <jgarzik@mandrakesoft.com> :
+    Updated to use new PCI driver API.
+    Resource usage cleanups.
+    Report driver version to user.
+
+    Tobias Ringstrom <tori@unhappy.mine.nu> :
+    Cleaned up and added SMP safety.  Thanks go to Jeff Garzik,
+    Andrew Morton and Frank Davis for the SMP safety fixes.
+
+    Vojtech Pavlik <vojtech@suse.cz> :
+    Cleaned up pointer arithmetics.
+    Fixed a lot of 64bit issues.
+    Cleaned up printk()s a bit.
+    Fixed some obvious big endian problems.
+
+    Tobias Ringstrom <tori@unhappy.mine.nu> :
+    Use time_after for jiffies calculation.  Added ethtool
+    support.  Updated PCI resource allocation.  Do not
+    forget to unmap PCI mapped skbs.
+
+    TODO
+
+    Implement pci_driver::suspend() and pci_driver::resume()
+    power management methods.
+
+    Check on 64 bit boxes.
+    Check and fix on big endian boxes.
+
+    Test and make sure PCI latency is now correct for all cases.
+*/
+
+#define DRV_NAME	"dmfe"
+#define DRV_VERSION	"1.36.4"
+#define DRV_RELDATE	"2002-01-17"
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/crc32.h>
+
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+
+/* Board/System/Debug information/definition ---------------- */
+#define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
+#define PCI_DM9102_ID   0x91021282      /* Davicom DM9102 ID */
+#define PCI_DM9100_ID   0x91001282      /* Davicom DM9100 ID */
+#define PCI_DM9009_ID   0x90091282      /* Davicom DM9009 ID */
+
+#define DM9102_IO_SIZE  0x80
+#define DM9102A_IO_SIZE 0x100
+#define TX_MAX_SEND_CNT 0x1             /* Maximum tx packet per time */
+#define TX_DESC_CNT     0x10            /* Allocated Tx descriptors */
+#define RX_DESC_CNT     0x20            /* Allocated Rx descriptors */
+#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
+#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
+#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
+#define TX_BUF_ALLOC    0x600
+#define RX_ALLOC_SIZE   0x620
+#define DM910X_RESET    1
+#define CR0_DEFAULT     0x00E00000      /* TX & RX burst mode */
+#define CR6_DEFAULT     0x00080000      /* HD */
+#define CR7_DEFAULT     0x180c1
+#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
+#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
+#define MAX_PACKET_SIZE 1514
+#define DMFE_MAX_MULTICAST 14
+#define RX_COPY_SIZE	100
+#define MAX_CHECK_PACKET 0x8000
+#define DM9801_NOISE_FLOOR 8
+#define DM9802_NOISE_FLOOR 5
+
+#define DMFE_10MHF      0
+#define DMFE_100MHF     1
+#define DMFE_10MFD      4
+#define DMFE_100MFD     5
+#define DMFE_AUTO       8
+#define DMFE_1M_HPNA    0x10
+
+#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
+#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
+#define DMFE_TXTH_128	0x0000		/* TX TH 128 byte */
+#define DMFE_TXTH_256	0x4000		/* TX TH 256 byte */
+#define DMFE_TXTH_512	0x8000		/* TX TH 512 byte */
+#define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
+
+#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
+#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
+#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
+
+#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value))
+
+#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half");
+
+
+/* CR9 definition: SROM/MII */
+#define CR9_SROM_READ   0x4800
+#define CR9_SRCS        0x1
+#define CR9_SRCLK       0x2
+#define CR9_CRDOUT      0x8
+#define SROM_DATA_0     0x0
+#define SROM_DATA_1     0x4
+#define PHY_DATA_1      0x20000
+#define PHY_DATA_0      0x00000
+#define MDCLKH          0x10000
+
+#define PHY_POWER_DOWN	0x800
+
+#define SROM_V41_CODE   0x14
+
+#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);
+
+#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE
+#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)
+
+/* Sten Check */
+#define DEVICE net_device
+
+/* Structure/enum declaration ------------------------------- */
+struct tx_desc {
+        u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+        char *tx_buf_ptr;               /* Data for us */
+        struct tx_desc *next_tx_desc;
+} __attribute__(( aligned(32) ));
+
+struct rx_desc {
+	u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+	struct sk_buff *rx_skb_ptr;	/* Data for us */
+	struct rx_desc *next_rx_desc;
+} __attribute__(( aligned(32) ));
+
+struct dmfe_board_info {
+	u32 chip_id;			/* Chip vendor/Device ID */
+	u32 chip_revision;		/* Chip revision */
+	struct DEVICE *next_dev;	/* next device */
+	struct pci_dev *pdev;		/* PCI device */
+	spinlock_t lock;
+
+	long ioaddr;			/* I/O base address */
+	u32 cr0_data;
+	u32 cr5_data;
+	u32 cr6_data;
+	u32 cr7_data;
+	u32 cr15_data;
+
+	/* pointer for memory physical address */
+	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
+	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
+	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
+	dma_addr_t first_tx_desc_dma;
+	dma_addr_t first_rx_desc_dma;
+
+	/* descriptor pointer */
+	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
+	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
+	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
+	struct tx_desc *first_tx_desc;
+	struct tx_desc *tx_insert_ptr;
+	struct tx_desc *tx_remove_ptr;
+	struct rx_desc *first_rx_desc;
+	struct rx_desc *rx_insert_ptr;
+	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
+	unsigned long tx_packet_cnt;	/* transmitted packet count */
+	unsigned long tx_queue_cnt;	/* wait to send packet count */
+	unsigned long rx_avail_cnt;	/* available rx descriptor count */
+	unsigned long interval_rx_cnt;	/* rx packet count a callback time */
+
+	u16 HPNA_command;		/* For HPNA register 16 */
+	u16 HPNA_timer;			/* For HPNA remote device check */
+	u16 dbug_cnt;
+	u16 NIC_capability;		/* NIC media capability */
+	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
+
+	u8 HPNA_present;		/* 0:none, 1:DM9801, 2:DM9802 */
+	u8 chip_type;			/* Keep DM9102A chip type */
+	u8 media_mode;			/* user specify media mode */
+	u8 op_mode;			/* real work media mode */
+	u8 phy_addr;
+	u8 link_failed;			/* Ever link failed */
+	u8 wait_reset;			/* Hardware failed, need to reset */
+	u8 dm910x_chk_mode;		/* Operating mode check */
+	u8 first_in_callback;		/* Flag to record state */
+	struct timer_list timer;
+
+	/* System defined statistic counter */
+	struct net_device_stats stats;
+
+	/* Driver defined statistic counter */
+	unsigned long tx_fifo_underrun;
+	unsigned long tx_loss_carrier;
+	unsigned long tx_no_carrier;
+	unsigned long tx_late_collision;
+	unsigned long tx_excessive_collision;
+	unsigned long tx_jabber_timeout;
+	unsigned long reset_count;
+	unsigned long reset_cr8;
+	unsigned long reset_fatal;
+	unsigned long reset_TXtimeout;
+
+	/* NIC SROM data */
+	unsigned char srom[128];
+};
+
+enum dmfe_offsets {
+	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
+	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
+	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
+	DCR15 = 0x78
+};
+
+enum dmfe_CR6_bits {
+	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
+	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
+	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
+};
+
+/* Global variable declaration ----------------------------- */
+static int __devinitdata printed_version;
+static char version[] __devinitdata =
+	KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version "
+	DRV_VERSION " (" DRV_RELDATE ")\n";
+
+static int dmfe_debug;
+static unsigned char dmfe_media_mode = DMFE_AUTO;
+static u32 dmfe_cr6_user_set;
+
+/* For module input parameter */
+static int debug;
+static u32 cr6set;
+static unsigned char mode = 8;
+static u8 chkmode = 1;
+static u8 HPNA_mode;		/* Default: Low Power/High Speed */
+static u8 HPNA_rx_cmd;		/* Default: Disable Rx remote command */
+static u8 HPNA_tx_cmd;		/* Default: Don't issue remote command */
+static u8 HPNA_NoiseFloor;	/* Default: HPNA NoiseFloor */
+static u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
+				   4: TX pause packet */
+
+
+/* function declaration ------------------------------------- */
+static int dmfe_open(struct DEVICE *);
+static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *);
+static int dmfe_stop(struct DEVICE *);
+static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
+static void dmfe_set_filter_mode(struct DEVICE *);
+static int dmfe_do_ioctl(struct DEVICE *, struct ifreq *, int);
+static u16 read_srom_word(long ,int);
+static void dmfe_interrupt(int , void *, struct pt_regs *);
+static void dmfe_descriptor_init(struct dmfe_board_info *, unsigned long);
+static void allocate_rx_buffer(struct dmfe_board_info *);
+static void update_cr6(u32, unsigned long);
+static void send_filter_frame(struct DEVICE * ,int);
+static void dm9132_id_table(struct DEVICE * ,int);
+static u16 phy_read(unsigned long, u8, u8, u32);
+static void phy_write(unsigned long, u8, u8, u16, u32);
+static void phy_write_1bit(unsigned long, u32);
+static u16 phy_read_1bit(unsigned long);
+static u8 dmfe_sense_speed(struct dmfe_board_info *);
+static void dmfe_process_mode(struct dmfe_board_info *);
+static void dmfe_timer(unsigned long);
+static void dmfe_rx_packet(struct DEVICE *, struct dmfe_board_info *);
+static void dmfe_free_tx_pkt(struct DEVICE *, struct dmfe_board_info *);
+static void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
+static void dmfe_dynamic_reset(struct DEVICE *);
+static void dmfe_free_rxbuffer(struct dmfe_board_info *);
+static void dmfe_init_dm910x(struct DEVICE *);
+static inline u32 cal_CRC(unsigned char *, unsigned int, u8);
+static void dmfe_parse_srom(struct dmfe_board_info *);
+static void dmfe_program_DM9801(struct dmfe_board_info *, int);
+static void dmfe_program_DM9802(struct dmfe_board_info *);
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
+static void dmfe_set_phyxcer(struct dmfe_board_info *);
+
+/* DM910X network baord routine ---------------------------- */
+
+/*
+ *	Search DM910X board ,allocate space and register it
+ */
+
+static int __devinit dmfe_init_one (struct pci_dev *pdev,
+				    const struct pci_device_id *ent)
+{
+	struct dmfe_board_info *db;	/* board information structure */
+	struct net_device *dev;
+	u32 dev_rev, pci_pmr;
+	int i, err;
+
+	DMFE_DBUG(0, "dmfe_init_one()", 0);
+
+	if (!printed_version++)
+		printk(version);
+
+	/* Init network device */
+	dev = alloc_etherdev(sizeof(*db));
+	if (dev == NULL)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+
+	if (pci_set_dma_mask(pdev, 0xffffffff)) {
+		printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
+		err = -ENODEV;
+		goto err_out_free;
+	}
+
+	/* Enable Master/IO access, Disable memory access */
+	err = pci_enable_device(pdev);
+	if (err)
+		goto err_out_free;
+
+	if (!pci_resource_start(pdev, 0)) {
+		printk(KERN_ERR DRV_NAME ": I/O base is zero\n");
+		err = -ENODEV;
+		goto err_out_disable;
+	}
+
+	/* Read Chip revision */
+	pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
+
+	if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {
+		printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
+		err = -ENODEV;
+		goto err_out_disable;
+	}
+
+#if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
+
+	/* Set Latency Timer 80h */
+	/* FIXME: setting values > 32 breaks some SiS 559x stuff.
+	   Need a PCI quirk.. */
+
+	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+#endif
+
+	if (pci_request_regions(pdev, DRV_NAME)) {
+		printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n");
+		err = -ENODEV;
+		goto err_out_disable;
+	}
+
+	/* Init system & device */
+	db = dev->priv;
+
+	/* Allocate Tx/Rx descriptor memory */
+	db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr);
+	db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr);
+
+	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
+	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
+	db->buf_pool_start = db->buf_pool_ptr;
+	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
+
+	db->chip_id = ent->driver_data;
+	db->ioaddr = pci_resource_start(pdev, 0);
+	db->chip_revision = dev_rev;
+
+	db->pdev = pdev;
+
+	dev->base_addr = db->ioaddr;
+	dev->irq = pdev->irq;
+	pci_set_drvdata(pdev, dev);
+	dev->open = &dmfe_open;
+	dev->hard_start_xmit = &dmfe_start_xmit;
+	dev->stop = &dmfe_stop;
+	dev->get_stats = &dmfe_get_stats;
+	dev->set_multicast_list = &dmfe_set_filter_mode;
+	dev->do_ioctl = &dmfe_do_ioctl;
+	spin_lock_init(&db->lock);
+
+	pci_read_config_dword(pdev, 0x50, &pci_pmr);
+	pci_pmr &= 0x70000;
+	if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) )
+		db->chip_type = 1;	/* DM9102A E3 */
+	else
+		db->chip_type = 0;
+
+	/* read 64 word srom data */
+	for (i = 0; i < 64; i++)
+		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+
+	/* Set Node address */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = db->srom[20 + i];
+
+	err = register_netdev (dev);
+	if (err)
+		goto err_out_res;
+
+	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,",
+		dev->name,
+		ent->driver_data >> 16,
+		pdev->slot_name);
+	for (i = 0; i < 6; i++)
+		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(", irq %d.\n", dev->irq);
+
+	pci_set_master(pdev);
+
+	return 0;
+
+err_out_res:
+	pci_release_regions(pdev);
+err_out_disable:
+	pci_disable_device(pdev);
+err_out_free:
+	pci_set_drvdata(pdev, NULL);
+	kfree(dev);
+
+	return err;
+}
+
+
+static void __exit dmfe_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct dmfe_board_info *db = dev->priv;
+
+	DMFE_DBUG(0, "dmfe_remove_one()", 0);
+
+ 	if (dev) {
+		pci_free_consistent(db->pdev, sizeof(struct tx_desc) *
+					DESC_ALL_CNT + 0x20, db->desc_pool_ptr,
+ 					db->desc_pool_dma_ptr);
+		pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
+					db->buf_pool_ptr, db->buf_pool_dma_ptr);
+		unregister_netdev(dev);
+		pci_release_regions(pdev);
+		kfree(dev);	/* free board information */
+		pci_set_drvdata(pdev, NULL);
+	}
+
+	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
+}
+
+
+/*
+ *	Open the interface.
+ *	The interface is opened whenever "ifconfig" actives it.
+ */
+
+static int dmfe_open(struct DEVICE *dev)
+{
+	int ret;
+	struct dmfe_board_info *db = dev->priv;
+
+	DMFE_DBUG(0, "dmfe_open", 0);
+
+	ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
+	if (ret)
+		return ret;
+
+	/* system variable init */
+	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
+	db->tx_packet_cnt = 0;
+	db->tx_queue_cnt = 0;
+	db->rx_avail_cnt = 0;
+	db->link_failed = 1;
+	db->wait_reset = 0;
+
+	db->first_in_callback = 0;
+	db->NIC_capability = 0xf;	/* All capability*/
+	db->PHY_reg4 = 0x1e0;
+
+	/* CR6 operation mode decision */
+	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
+		(db->chip_revision >= 0x02000030) ) {
+    		db->cr6_data |= DMFE_TXTH_256;
+		db->cr0_data = CR0_DEFAULT;
+		db->dm910x_chk_mode=4;		/* Enter the normal mode */
+ 	} else {
+		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
+		db->cr0_data = 0;
+		db->dm910x_chk_mode = 1;	/* Enter the check mode */
+	}
+
+	/* Initilize DM910X board */
+	dmfe_init_dm910x(dev);
+
+	/* Active System Interface */
+	netif_wake_queue(dev);
+
+	/* set and active a timer process */
+	init_timer(&db->timer);
+	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
+	db->timer.data = (unsigned long)dev;
+	db->timer.function = &dmfe_timer;
+	add_timer(&db->timer);
+
+	return 0;
+}
+
+
+/*	Initilize DM910X board
+ *	Reset DM910X board
+ *	Initilize TX/Rx descriptor chain structure
+ *	Send the set-up frame
+ *	Enable Tx/Rx machine
+ */
+
+static void dmfe_init_dm910x(struct DEVICE *dev)
+{
+	struct dmfe_board_info *db = dev->priv;
+	unsigned long ioaddr = db->ioaddr;
+
+	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
+
+	/* Reset DM910x MAC controller */
+	outl(DM910X_RESET, ioaddr + DCR0);	/* RESET MAC */
+	udelay(100);
+	outl(db->cr0_data, ioaddr + DCR0);
+	udelay(5);
+
+	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
+	db->phy_addr = 1;
+
+	/* Parser SROM and media mode */
+	dmfe_parse_srom(db);
+	db->media_mode = dmfe_media_mode;
+
+	/* RESET Phyxcer Chip by GPR port bit 7 */
+	outl(0x180, ioaddr + DCR12);		/* Let bit 7 output port */
+	if (db->chip_id == PCI_DM9009_ID) {
+		outl(0x80, ioaddr + DCR12);	/* Issue RESET signal */
+		mdelay(300);			/* Delay 300 ms */
+	}
+	outl(0x0, ioaddr + DCR12);	/* Clear RESET signal */
+
+	/* Process Phyxcer Media Mode */
+	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
+		dmfe_set_phyxcer(db);
+
+	/* Media Mode Process */
+	if ( !(db->media_mode & DMFE_AUTO) )
+		db->op_mode = db->media_mode; 	/* Force Mode */
+
+	/* Initiliaze Transmit/Receive decriptor and CR3/4 */
+	dmfe_descriptor_init(db, ioaddr);
+
+	/* Init CR6 to program DM910x operation */
+	update_cr6(db->cr6_data, ioaddr);
+
+	/* Send setup frame */
+	if (db->chip_id == PCI_DM9132_ID)
+		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
+	else
+		send_filter_frame(dev, dev->mc_count);	/* DM9102/DM9102A */
+
+	/* Init CR7, interrupt active bit */
+	db->cr7_data = CR7_DEFAULT;
+	outl(db->cr7_data, ioaddr + DCR7);
+
+	/* Init CR15, Tx jabber and Rx watchdog timer */
+	outl(db->cr15_data, ioaddr + DCR15);
+
+	/* Enable DM910X Tx/Rx function */
+	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
+	update_cr6(db->cr6_data, ioaddr);
+}
+
+
+/*
+ *	Hardware start transmission.
+ *	Send a packet to media from the upper layer.
+ */
+
+static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
+{
+	struct dmfe_board_info *db = dev->priv;
+	struct tx_desc *txptr;
+	unsigned long flags;
+
+	DMFE_DBUG(0, "dmfe_start_xmit", 0);
+
+	/* Resource flag check */
+	netif_stop_queue(dev);
+
+	/* Too large packet check */
+	if (skb->len > MAX_PACKET_SIZE) {
+		printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	spin_lock_irqsave(&db->lock, flags);
+
+	/* No Tx resource check, it never happen nromally */
+	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
+		spin_unlock_irqrestore(&db->lock, flags);
+		printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);
+		return 1;
+	}
+
+	/* Disable NIC interrupt */
+	outl(0, dev->base_addr + DCR7);
+
+	/* transmit this packet */
+	txptr = db->tx_insert_ptr;
+	memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
+	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
+
+	/* Point to next transmit free descriptor */
+	db->tx_insert_ptr = txptr->next_tx_desc;
+
+	/* Transmit Packet Process */
+	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
+		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
+		db->tx_packet_cnt++;			/* Ready to send */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+		dev->trans_start = jiffies;		/* saved time stamp */
+	} else {
+		db->tx_queue_cnt++;			/* queue TX packet */
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+	}
+
+	/* Tx resource check */
+	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
+		netif_wake_queue(dev);
+
+	/* free this SKB */
+	dev_kfree_skb(skb);
+
+	/* Restore CR7 to enable interrupt */
+	spin_unlock_irqrestore(&db->lock, flags);
+	outl(db->cr7_data, dev->base_addr + DCR7);
+
+	return 0;
+}
+
+
+/*
+ *	Stop the interface.
+ *	The interface is stopped when it is brought.
+ */
+
+static int dmfe_stop(struct DEVICE *dev)
+{
+	struct dmfe_board_info *db = dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+
+	DMFE_DBUG(0, "dmfe_stop", 0);
+
+	/* disable system */
+	netif_stop_queue(dev);
+
+	/* deleted timer */
+	del_timer_sync(&db->timer);
+
+	/* Reset & stop DM910X board */
+	outl(DM910X_RESET, ioaddr + DCR0);
+	udelay(5);
+	phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
+
+	/* free interrupt */
+	free_irq(dev->irq, dev);
+
+	/* free allocated rx buffer */
+	dmfe_free_rxbuffer(db);
+
+#if 0
+	/* show statistic counter */
+	printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
+		db->tx_fifo_underrun, db->tx_excessive_collision,
+		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
+		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
+		db->reset_fatal, db->reset_TXtimeout);
+#endif
+
+	return 0;
+}
+
+
+/*
+ *	DM9102 insterrupt handler
+ *	receive the packet to upper layer, free the transmitted packet
+ */
+
+static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct DEVICE *dev = dev_id;
+	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+	unsigned long ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	DMFE_DBUG(0, "dmfe_interrupt()", 0);
+
+	if (!dev) {
+		DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
+		return;
+	}
+
+	spin_lock_irqsave(&db->lock, flags);
+
+	/* Got DM910X status */
+	db->cr5_data = inl(ioaddr + DCR5);
+	outl(db->cr5_data, ioaddr + DCR5);
+	if ( !(db->cr5_data & 0xc1) ) {
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
+	outl(0, ioaddr + DCR7);
+
+	/* Check system status */
+	if (db->cr5_data & 0x2000) {
+		/* system bus error happen */
+		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
+		db->reset_fatal++;
+		db->wait_reset = 1;	/* Need to RESET */
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	 /* Received the coming packet */
+	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
+		dmfe_rx_packet(dev, db);
+
+	/* reallocate rx descriptor buffer */
+	if (db->rx_avail_cnt<RX_DESC_CNT)
+		allocate_rx_buffer(db);
+
+	/* Free the transmitted descriptor */
+	if ( db->cr5_data & 0x01)
+		dmfe_free_tx_pkt(dev, db);
+
+	/* Mode Check */
+	if (db->dm910x_chk_mode & 0x2) {
+		db->dm910x_chk_mode = 0x4;
+		db->cr6_data |= 0x100;
+		update_cr6(db->cr6_data, db->ioaddr);
+	}
+
+	/* Restore CR7 to enable interrupt mask */
+	outl(db->cr7_data, ioaddr + DCR7);
+
+	spin_unlock_irqrestore(&db->lock, flags);
+}
+
+
+/*
+ *	Free TX resource after TX complete
+ */
+
+static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
+{
+	struct tx_desc *txptr;
+	unsigned long ioaddr = dev->base_addr;
+	u32 tdes0;
+
+	txptr = db->tx_remove_ptr;
+	while(db->tx_packet_cnt) {
+		tdes0 = le32_to_cpu(txptr->tdes0);
+		/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+		if (tdes0 & 0x80000000)
+			break;
+
+		/* A packet sent completed */
+		db->tx_packet_cnt--;
+		db->stats.tx_packets++;
+
+		/* Transmit statistic counter */
+		if ( tdes0 != 0x7fffffff ) {
+			/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
+			db->stats.collisions += (tdes0 >> 3) & 0xf;
+			db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
+			if (tdes0 & TDES0_ERR_MASK) {
+				db->stats.tx_errors++;
+
+				if (tdes0 & 0x0002) {	/* UnderRun */
+					db->tx_fifo_underrun++;
+					if ( !(db->cr6_data & CR6_SFT) ) {
+						db->cr6_data = db->cr6_data | CR6_SFT;
+						update_cr6(db->cr6_data, db->ioaddr);
+					}
+				}
+				if (tdes0 & 0x0100)
+					db->tx_excessive_collision++;
+				if (tdes0 & 0x0200)
+					db->tx_late_collision++;
+				if (tdes0 & 0x0400)
+					db->tx_no_carrier++;
+				if (tdes0 & 0x0800)
+					db->tx_loss_carrier++;
+				if (tdes0 & 0x4000)
+					db->tx_jabber_timeout++;
+			}
+		}
+
+    		txptr = txptr->next_tx_desc;
+	}/* End of while */
+
+	/* Update TX remove pointer to next */
+	db->tx_remove_ptr = txptr;
+
+	/* Send the Tx packet in queue */
+	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
+		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
+		db->tx_packet_cnt++;			/* Ready to send */
+		db->tx_queue_cnt--;
+		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */
+		dev->trans_start = jiffies;		/* saved time stamp */
+	}
+
+	/* Resource available check */
+	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
+		netif_wake_queue(dev);	/* Active upper layer, send again */
+}
+
+
+/*
+ *	Receive the come packet and pass to upper layer
+ */
+
+static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
+{
+	struct rx_desc *rxptr;
+	struct sk_buff *skb;
+	int rxlen;
+	u32 rdes0;
+
+	rxptr = db->rx_ready_ptr;
+
+	while(db->rx_avail_cnt) {
+		rdes0 = le32_to_cpu(rxptr->rdes0);
+		if (rdes0 & 0x80000000)	/* packet owner check */
+			break;
+
+		db->rx_avail_cnt--;
+		db->interval_rx_cnt++;
+
+		pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
+		if ( (rdes0 & 0x300) != 0x300) {
+			/* A packet without First/Last flag */
+			/* reuse this SKB */
+			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
+			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
+		} else {
+			/* A packet with First/Last flag */
+			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
+
+			/* error summary bit check */
+			if (rdes0 & 0x8000) {
+				/* This is a error packet */
+				//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
+				db->stats.rx_errors++;
+				if (rdes0 & 1)
+					db->stats.rx_fifo_errors++;
+				if (rdes0 & 2)
+					db->stats.rx_crc_errors++;
+				if (rdes0 & 0x80)
+					db->stats.rx_length_errors++;
+			}
+
+			if ( !(rdes0 & 0x8000) ||
+				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
+				skb = rxptr->rx_skb_ptr;
+
+				/* Received Packet CRC check need or not */
+				if ( (db->dm910x_chk_mode & 1) &&
+					(cal_CRC(skb->tail, rxlen, 1) !=
+					(*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
+					/* Found a error received packet */
+					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
+					db->dm910x_chk_mode = 3;
+				} else {
+					/* Good packet, send to upper layer */
+					/* Shorst packet used new SKB */
+					if ( (rxlen < RX_COPY_SIZE) &&
+						( (skb = dev_alloc_skb(rxlen + 2) )
+						!= NULL) ) {
+						/* size less than COPY_SIZE, allocate a rxlen SKB */
+						skb->dev = dev;
+						skb_reserve(skb, 2); /* 16byte align */
+						memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
+						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
+					} else {
+						skb->dev = dev;
+						skb_put(skb, rxlen);
+					}
+					skb->protocol = eth_type_trans(skb, dev);
+					netif_rx(skb);
+					dev->last_rx = jiffies;
+					db->stats.rx_packets++;
+					db->stats.rx_bytes += rxlen;
+				}
+			} else {
+				/* Reuse SKB buffer when the packet is error */
+				DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
+				dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
+			}
+		}
+
+		rxptr = rxptr->next_rx_desc;
+	}
+
+	db->rx_ready_ptr = rxptr;
+}
+
+
+/*
+ *	Get statistics from driver.
+ */
+
+static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
+{
+	struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;
+
+	DMFE_DBUG(0, "dmfe_get_stats", 0);
+	return &db->stats;
+}
+
+
+/*
+ * Set DM910X multicast address
+ */
+
+static void dmfe_set_filter_mode(struct DEVICE * dev)
+{
+	struct dmfe_board_info *db = dev->priv;
+	unsigned long flags;
+
+	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
+	spin_lock_irqsave(&db->lock, flags);
+
+	if (dev->flags & IFF_PROMISC) {
+		DMFE_DBUG(0, "Enable PROM Mode", 0);
+		db->cr6_data |= CR6_PM | CR6_PBF;
+		update_cr6(db->cr6_data, db->ioaddr);
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST) {
+		DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
+		db->cr6_data &= ~(CR6_PM | CR6_PBF);
+		db->cr6_data |= CR6_PAM;
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	DMFE_DBUG(0, "Set multicast address", dev->mc_count);
+	if (db->chip_id == PCI_DM9132_ID)
+		dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
+	else
+		send_filter_frame(dev, dev->mc_count); 	/* DM9102/DM9102A */
+	spin_unlock_irqrestore(&db->lock, flags);
+}
+
+
+/*
+ *	Process the ethtool ioctl command
+ */
+
+static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct dmfe_board_info *db = dev->priv;
+	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO:
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		if (db->pdev)
+			strcpy(info.bus_info, db->pdev->slot_name);
+		else
+			sprintf(info.bus_info, "EISA 0x%lx %d",
+				dev->base_addr, dev->irq);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+        }
+
+	return -EOPNOTSUPP;
+}
+
+
+/*
+ *	Process the upper socket ioctl command
+ */
+
+static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
+{
+	int retval = -EOPNOTSUPP;
+	DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data);
+	}
+
+	return retval;
+}
+
+
+/*
+ *	A periodic timer routine
+ *	Dynamic media sense, allocate Rx buffer...
+ */
+
+static void dmfe_timer(unsigned long data)
+{
+	u32 tmp_cr8;
+	unsigned char tmp_cr12;
+	struct DEVICE *dev = (struct DEVICE *) data;
+	struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
+ 	unsigned long flags;
+
+	DMFE_DBUG(0, "dmfe_timer()", 0);
+	spin_lock_irqsave(&db->lock, flags);
+
+	/* Media mode process when Link OK before enter this route */
+	if (db->first_in_callback == 0) {
+		db->first_in_callback = 1;
+		if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
+			db->cr6_data &= ~0x40000;
+			update_cr6(db->cr6_data, db->ioaddr);
+			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+			db->cr6_data |= 0x40000;
+			update_cr6(db->cr6_data, db->ioaddr);
+			db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
+			add_timer(&db->timer);
+			spin_unlock_irqrestore(&db->lock, flags);
+			return;
+		}
+	}
+
+
+	/* Operating Mode Check */
+	if ( (db->dm910x_chk_mode & 0x1) &&
+		(db->stats.rx_packets > MAX_CHECK_PACKET) )
+		db->dm910x_chk_mode = 0x4;
+
+	/* Dynamic reset DM910X : system error or transmit time-out */
+	tmp_cr8 = inl(db->ioaddr + DCR8);
+	if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
+		db->reset_cr8++;
+		db->wait_reset = 1;
+	}
+	db->interval_rx_cnt = 0;
+
+	/* TX polling kick monitor */
+	if ( db->tx_packet_cnt &&
+	     time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) {
+		outl(0x1, dev->base_addr + DCR1);   /* Tx polling again */
+
+		/* TX Timeout */
+		if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
+			db->reset_TXtimeout++;
+			db->wait_reset = 1;
+			printk(KERN_WARNING "%s: Tx timeout - resetting\n",
+			       dev->name);
+		}
+	}
+
+	if (db->wait_reset) {
+		DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
+		db->reset_count++;
+		dmfe_dynamic_reset(dev);
+		db->first_in_callback = 0;
+		db->timer.expires = DMFE_TIMER_WUT;
+		add_timer(&db->timer);
+		spin_unlock_irqrestore(&db->lock, flags);
+		return;
+	}
+
+	/* Link status check, Dynamic media type change */
+	if (db->chip_id == PCI_DM9132_ID)
+		tmp_cr12 = inb(db->ioaddr + DCR9 + 3);	/* DM9132 */
+	else
+		tmp_cr12 = inb(db->ioaddr + DCR12);	/* DM9102/DM9102A */
+
+	if ( ((db->chip_id == PCI_DM9102_ID) &&
+		(db->chip_revision == 0x02000030)) ||
+		((db->chip_id == PCI_DM9132_ID) &&
+		(db->chip_revision == 0x02000010)) ) {
+		/* DM9102A Chip */
+		if (tmp_cr12 & 2)
+			tmp_cr12 = 0x0;		/* Link failed */
+		else
+			tmp_cr12 = 0x3;	/* Link OK */
+	}
+
+	if ( !(tmp_cr12 & 0x3) && !db->link_failed ) {
+		/* Link Failed */
+		DMFE_DBUG(0, "Link Failed", tmp_cr12);
+		db->link_failed = 1;
+
+		/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
+		/* AUTO or force 1M Homerun/Longrun don't need */
+		if ( !(db->media_mode & 0x38) )
+			phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
+
+		/* AUTO mode, if INT phyxcer link failed, select EXT device */
+		if (db->media_mode & DMFE_AUTO) {
+			/* 10/100M link failed, used 1M Home-Net */
+			db->cr6_data|=0x00040000;	/* bit18=1, MII */
+			db->cr6_data&=~0x00000200;	/* bit9=0, HD mode */
+			update_cr6(db->cr6_data, db->ioaddr);
+		}
+	} else
+		if ((tmp_cr12 & 0x3) && db->link_failed) {
+			DMFE_DBUG(0, "Link link OK", tmp_cr12);
+			db->link_failed = 0;
+
+			/* Auto Sense Speed */
+			if ( (db->media_mode & DMFE_AUTO) &&
+				dmfe_sense_speed(db) )
+				db->link_failed = 1;
+			dmfe_process_mode(db);
+			/* SHOW_MEDIA_TYPE(db->op_mode); */
+		}
+
+	/* HPNA remote command check */
+	if (db->HPNA_command & 0xf00) {
+		db->HPNA_timer--;
+		if (!db->HPNA_timer)
+			dmfe_HPNA_remote_cmd_chk(db);
+	}
+
+	/* Timer active again */
+	db->timer.expires = DMFE_TIMER_WUT;
+	add_timer(&db->timer);
+	spin_unlock_irqrestore(&db->lock, flags);
+}
+
+
+/*
+ *	Dynamic reset the DM910X board
+ *	Stop DM910X board
+ *	Free Tx/Rx allocated memory
+ *	Reset DM910X board
+ *	Re-initilize DM910X board
+ */
+
+static void dmfe_dynamic_reset(struct DEVICE *dev)
+{
+	struct dmfe_board_info *db = dev->priv;
+
+	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
+
+	/* Sopt MAC controller */
+	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
+	update_cr6(db->cr6_data, dev->base_addr);
+	outl(0, dev->base_addr + DCR7);		/* Disable Interrupt */
+	outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+	/* Disable upper layer interface */
+	netif_stop_queue(dev);
+
+	/* Free Rx Allocate buffer */
+	dmfe_free_rxbuffer(db);
+
+	/* system variable init */
+	db->tx_packet_cnt = 0;
+	db->tx_queue_cnt = 0;
+	db->rx_avail_cnt = 0;
+	db->link_failed = 1;
+	db->wait_reset = 0;
+
+	/* Re-initilize DM910X board */
+	dmfe_init_dm910x(dev);
+
+	/* Restart upper layer interface */
+	netif_wake_queue(dev);
+}
+
+
+/*
+ *	free all allocated rx buffer
+ */
+
+static void dmfe_free_rxbuffer(struct dmfe_board_info * db)
+{
+	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
+
+	/* free allocated rx buffer */
+	while (db->rx_avail_cnt) {
+		dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
+		db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
+		db->rx_avail_cnt--;
+	}
+}
+
+
+/*
+ *	Reuse the SK buffer
+ */
+
+static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
+{
+	struct rx_desc *rxptr = db->rx_insert_ptr;
+
+	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
+		rxptr->rx_skb_ptr = skb;
+		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		wmb();
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
+		db->rx_avail_cnt++;
+		db->rx_insert_ptr = rxptr->next_rx_desc;
+	} else
+		DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
+}
+
+
+/*
+ *	Initialize transmit/Receive descriptor
+ *	Using Chain structure, and allocate Tx/Rx buffer
+ */
+
+static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr)
+{
+	struct tx_desc *tmp_tx;
+	struct rx_desc *tmp_rx;
+	unsigned char *tmp_buf;
+	dma_addr_t tmp_tx_dma, tmp_rx_dma;
+	dma_addr_t tmp_buf_dma;
+	int i;
+
+	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);
+
+	/* tx descriptor start pointer */
+	db->tx_insert_ptr = db->first_tx_desc;
+	db->tx_remove_ptr = db->first_tx_desc;
+	outl(db->first_tx_desc_dma, ioaddr + DCR4);     /* TX DESC address */
+
+	/* rx descriptor start pointer */
+	db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT;
+	db->first_rx_desc_dma =  db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT;
+	db->rx_insert_ptr = db->first_rx_desc;
+	db->rx_ready_ptr = db->first_rx_desc;
+	outl(db->first_rx_desc_dma, ioaddr + DCR3);	/* RX DESC address */
+
+	/* Init Transmit chain */
+	tmp_buf = db->buf_pool_start;
+	tmp_buf_dma = db->buf_pool_dma_start;
+	tmp_tx_dma = db->first_tx_desc_dma;
+	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
+		tmp_tx->tx_buf_ptr = tmp_buf;
+		tmp_tx->tdes0 = cpu_to_le32(0);
+		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
+		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
+		tmp_tx_dma += sizeof(struct tx_desc);
+		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
+		tmp_tx->next_tx_desc = tmp_tx + 1;
+		tmp_buf = tmp_buf + TX_BUF_ALLOC;
+		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
+	}
+	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
+	tmp_tx->next_tx_desc = db->first_tx_desc;
+
+	 /* Init Receive descriptor chain */
+	tmp_rx_dma=db->first_rx_desc_dma;
+	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
+		tmp_rx->rdes0 = cpu_to_le32(0);
+		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
+		tmp_rx_dma += sizeof(struct rx_desc);
+		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
+		tmp_rx->next_rx_desc = tmp_rx + 1;
+	}
+	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
+	tmp_rx->next_rx_desc = db->first_rx_desc;
+
+	/* pre-allocate Rx buffer */
+	allocate_rx_buffer(db);
+}
+
+
+/*
+ *	Update CR6 value
+ *	Firstly stop DM910X , then written value and start
+ */
+
+static void update_cr6(u32 cr6_data, unsigned long ioaddr)
+{
+	u32 cr6_tmp;
+
+	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */
+	outl(cr6_tmp, ioaddr + DCR6);
+	udelay(5);
+	outl(cr6_data, ioaddr + DCR6);
+	udelay(5);
+}
+
+
+/*
+ *	Send a setup frame for DM9132
+ *	This setup frame initilize DM910X addres filter mode
+*/
+
+static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
+{
+	struct dev_mc_list *mcptr;
+	u16 * addrptr;
+	unsigned long ioaddr = dev->base_addr+0xc0;		/* ID Table */
+	u32 hash_val;
+	u16 i, hash_table[4];
+
+	DMFE_DBUG(0, "dm9132_id_table()", 0);
+
+	/* Node address */
+	addrptr = (u16 *) dev->dev_addr;
+	outw(addrptr[0], ioaddr);
+	ioaddr += 4;
+	outw(addrptr[1], ioaddr);
+	ioaddr += 4;
+	outw(addrptr[2], ioaddr);
+	ioaddr += 4;
+
+	/* Clear Hash Table */
+	for (i = 0; i < 4; i++)
+		hash_table[i] = 0x0;
+
+	/* broadcast address */
+	hash_table[3] = 0x8000;
+
+	/* the multicast address in Hash Table : 64 bits */
+	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+		hash_val = cal_CRC( (char *) mcptr->dmi_addr, 6, 0) & 0x3f;
+		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
+	}
+
+	/* Write the hash table to MAC MD table */
+	for (i = 0; i < 4; i++, ioaddr += 4)
+		outw(hash_table[i], ioaddr);
+}
+
+
+/*
+ *	Send a setup frame for DM9102/DM9102A
+ *	This setup frame initilize DM910X addres filter mode
+ */
+
+static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
+{
+	struct dmfe_board_info *db = dev->priv;
+	struct dev_mc_list *mcptr;
+	struct tx_desc *txptr;
+	u16 * addrptr;
+	u32 * suptr;
+	int i;
+
+	DMFE_DBUG(0, "send_filter_frame()", 0);
+
+	txptr = db->tx_insert_ptr;
+	suptr = (u32 *) txptr->tx_buf_ptr;
+
+	/* Node address */
+	addrptr = (u16 *) dev->dev_addr;
+	*suptr++ = addrptr[0];
+	*suptr++ = addrptr[1];
+	*suptr++ = addrptr[2];
+
+	/* broadcast address */
+	*suptr++ = 0xffff;
+	*suptr++ = 0xffff;
+	*suptr++ = 0xffff;
+
+	/* fit the multicast address */
+	for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) {
+		addrptr = (u16 *) mcptr->dmi_addr;
+		*suptr++ = addrptr[0];
+		*suptr++ = addrptr[1];
+		*suptr++ = addrptr[2];
+	}
+
+	for (; i<14; i++) {
+		*suptr++ = 0xffff;
+		*suptr++ = 0xffff;
+		*suptr++ = 0xffff;
+	}
+
+	/* prepare the setup frame */
+	db->tx_insert_ptr = txptr->next_tx_desc;
+	txptr->tdes1 = cpu_to_le32(0x890000c0);
+
+	/* Resource Check and Send the setup packet */
+	if (!db->tx_packet_cnt) {
+		/* Resource Empty */
+		db->tx_packet_cnt++;
+		txptr->tdes0 = cpu_to_le32(0x80000000);
+		update_cr6(db->cr6_data | 0x2000, dev->base_addr);
+		outl(0x1, dev->base_addr + DCR1);	/* Issue Tx polling */
+		update_cr6(db->cr6_data, dev->base_addr);
+		dev->trans_start = jiffies;
+	} else
+		db->tx_queue_cnt++;	/* Put in TX queue */
+}
+
+
+/*
+ *	Allocate rx buffer,
+ *	As possible as allocate maxiumn Rx buffer
+ */
+
+static void allocate_rx_buffer(struct dmfe_board_info *db)
+{
+	struct rx_desc *rxptr;
+	struct sk_buff *skb;
+
+	rxptr = db->rx_insert_ptr;
+
+	while(db->rx_avail_cnt < RX_DESC_CNT) {
+		if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
+			break;
+		rxptr->rx_skb_ptr = skb; /* FIXME (?) */
+		rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+		wmb();
+		rxptr->rdes0 = cpu_to_le32(0x80000000);
+		rxptr = rxptr->next_rx_desc;
+		db->rx_avail_cnt++;
+	}
+
+	db->rx_insert_ptr = rxptr;
+}
+
+
+/*
+ *	Read one word data from the serial ROM
+ */
+
+static u16 read_srom_word(long ioaddr, int offset)
+{
+	int i;
+	u16 srom_data = 0;
+	long cr9_ioaddr = ioaddr + DCR9;
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	/* Send the Read Command 110b */
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
+	SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);
+
+	/* Send the offset */
+	for (i = 5; i >= 0; i--) {
+		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
+		SROM_CLK_WRITE(srom_data, cr9_ioaddr);
+	}
+
+	outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+
+	for (i = 16; i > 0; i--) {
+		outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
+		udelay(5);
+		srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
+		outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
+		udelay(5);
+	}
+
+	outl(CR9_SROM_READ, cr9_ioaddr);
+	return srom_data;
+}
+
+
+/*
+ *	Auto sense the media mode
+ */
+
+static u8 dmfe_sense_speed(struct dmfe_board_info * db)
+{
+	u8 ErrFlag = 0;
+	u16 phy_mode;
+
+	/* CR6 bit18=0, select 10/100M */
+	update_cr6( (db->cr6_data & ~0x40000), db->ioaddr);
+
+	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+	phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
+
+	if ( (phy_mode & 0x24) == 0x24 ) {
+		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
+			phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000;
+		else 				/* DM9102/DM9102A */
+			phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000;
+		/* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
+		switch (phy_mode) {
+		case 0x1000: db->op_mode = DMFE_10MHF; break;
+		case 0x2000: db->op_mode = DMFE_10MFD; break;
+		case 0x4000: db->op_mode = DMFE_100MHF; break;
+		case 0x8000: db->op_mode = DMFE_100MFD; break;
+		default: db->op_mode = DMFE_10MHF;
+			ErrFlag = 1;
+			break;
+		}
+	} else {
+		db->op_mode = DMFE_10MHF;
+		DMFE_DBUG(0, "Link Failed :", phy_mode);
+		ErrFlag = 1;
+	}
+
+	return ErrFlag;
+}
+
+
+/*
+ *	Set 10/100 phyxcer capability
+ *	AUTO mode : phyxcer register4 is NIC capability
+ *	Force mode: phyxcer register4 is the force media
+ */
+
+static void dmfe_set_phyxcer(struct dmfe_board_info *db)
+{
+	u16 phy_reg;
+
+	/* Select 10/100M phyxcer */
+	db->cr6_data &= ~0x40000;
+	update_cr6(db->cr6_data, db->ioaddr);
+
+	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
+	if (db->chip_id == PCI_DM9009_ID) {
+		phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
+		phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id);
+	}
+
+	/* Phyxcer capability setting */
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
+
+	if (db->media_mode & DMFE_AUTO) {
+		/* AUTO Mode */
+		phy_reg |= db->PHY_reg4;
+	} else {
+		/* Force Mode */
+		switch(db->media_mode) {
+		case DMFE_10MHF: phy_reg |= 0x20; break;
+		case DMFE_10MFD: phy_reg |= 0x40; break;
+		case DMFE_100MHF: phy_reg |= 0x80; break;
+		case DMFE_100MFD: phy_reg |= 0x100; break;
+		}
+		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
+	}
+
+  	/* Write new capability to Phyxcer Reg4 */
+	if ( !(phy_reg & 0x01e0)) {
+		phy_reg|=db->PHY_reg4;
+		db->media_mode|=DMFE_AUTO;
+	}
+	phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
+
+ 	/* Restart Auto-Negotiation */
+	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+		phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
+	if ( !db->chip_type )
+		phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
+}
+
+
+/*
+ *	Process op-mode
+ *	AUTO mode : PHY controller in Auto-negotiation Mode
+ *	Force mode: PHY controller in force mode with HUB
+ *			N-way force capability with SWITCH
+ */
+
+static void dmfe_process_mode(struct dmfe_board_info *db)
+{
+	u16 phy_reg;
+
+	/* Full Duplex Mode Check */
+	if (db->op_mode & 0x4)
+		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
+	else
+		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
+
+	/* Transciver Selection */
+	if (db->op_mode & 0x10)		/* 1M HomePNA */
+		db->cr6_data |= 0x40000;/* External MII select */
+	else
+		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */
+
+	update_cr6(db->cr6_data, db->ioaddr);
+
+	/* 10/100M phyxcer force mode need */
+	if ( !(db->media_mode & 0x18)) {
+		/* Forece Mode */
+		phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
+		if ( !(phy_reg & 0x1) ) {
+			/* parter without N-Way capability */
+			phy_reg = 0x0;
+			switch(db->op_mode) {
+			case DMFE_10MHF: phy_reg = 0x0; break;
+			case DMFE_10MFD: phy_reg = 0x100; break;
+			case DMFE_100MHF: phy_reg = 0x2000; break;
+			case DMFE_100MFD: phy_reg = 0x2100; break;
+			}
+			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+       			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
+				mdelay(20);
+			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
+		}
+	}
+}
+
+
+/*
+ *	Write a word to Phy register
+ */
+
+static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id)
+{
+	u16 i;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_DM9132_ID) {
+		ioaddr = iobase + 0x80 + offset * 4;
+		outw(phy_data, ioaddr);
+	} else {
+		/* DM9102/DM9102A Chip */
+		ioaddr = iobase + DCR9;
+
+		/* Send 33 synchronization clock to Phy controller */
+		for (i = 0; i < 35; i++)
+			phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send start command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send write command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send Phy addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+
+		/* Send register addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+
+		/* written trasnition */
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+
+		/* Write a word data to PHY controller */
+		for ( i = 0x8000; i > 0; i >>= 1)
+			phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
+	}
+}
+
+
+/*
+ *	Read a word data from phy register
+ */
+
+static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id)
+{
+	int i;
+	u16 phy_data;
+	unsigned long ioaddr;
+
+	if (chip_id == PCI_DM9132_ID) {
+		/* DM9132 Chip */
+		ioaddr = iobase + 0x80 + offset * 4;
+		phy_data = inw(ioaddr);
+	} else {
+		/* DM9102/DM9102A Chip */
+		ioaddr = iobase + DCR9;
+
+		/* Send 33 synchronization clock to Phy controller */
+		for (i = 0; i < 35; i++)
+			phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send start command(01) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+
+		/* Send read command(10) to Phy */
+		phy_write_1bit(ioaddr, PHY_DATA_1);
+		phy_write_1bit(ioaddr, PHY_DATA_0);
+
+		/* Send Phy addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
+
+		/* Send register addres */
+		for (i = 0x10; i > 0; i = i >> 1)
+			phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0);
+
+		/* Skip transition state */
+		phy_read_1bit(ioaddr);
+
+		/* read 16bit data */
+		for (phy_data = 0, i = 0; i < 16; i++) {
+			phy_data <<= 1;
+			phy_data |= phy_read_1bit(ioaddr);
+		}
+	}
+
+	return phy_data;
+}
+
+
+/*
+ *	Write one bit data to Phy Controller
+ */
+
+static void phy_write_1bit(unsigned long ioaddr, u32 phy_data)
+{
+	outl(phy_data, ioaddr);			/* MII Clock Low */
+	udelay(1);
+	outl(phy_data | MDCLKH, ioaddr);	/* MII Clock High */
+	udelay(1);
+	outl(phy_data, ioaddr);			/* MII Clock Low */
+	udelay(1);
+}
+
+
+/*
+ *	Read one bit phy data from PHY controller
+ */
+
+static u16 phy_read_1bit(unsigned long ioaddr)
+{
+	u16 phy_data;
+
+	outl(0x50000, ioaddr);
+	udelay(1);
+	phy_data = ( inl(ioaddr) >> 19 ) & 0x1;
+	outl(0x40000, ioaddr);
+	udelay(1);
+
+	return phy_data;
+}
+
+
+/*
+ *	Calculate the CRC valude of the Rx packet
+ *	flag = 	1 : return the reverse CRC (for the received packet CRC)
+ *		0 : return the normal CRC (for Hash Table index)
+ */
+
+static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
+{
+	u32 crc = crc32(~0, Data, Len);
+	if (flag) crc = ~crc;
+	return crc;
+}
+
+
+/*
+ *	Parser SROM and media mode
+ */
+
+static void dmfe_parse_srom(struct dmfe_board_info * db)
+{
+	char * srom = db->srom;
+	int dmfe_mode, tmp_reg;
+
+	DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
+
+	/* Init CR15 */
+	db->cr15_data = CR15_DEFAULT;
+
+	/* Check SROM Version */
+	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
+		/* SROM V4.01 */
+		/* Get NIC support media mode */
+		db->NIC_capability = le16_to_cpup(srom + 34);
+		db->PHY_reg4 = 0;
+		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
+			switch( db->NIC_capability & tmp_reg ) {
+			case 0x1: db->PHY_reg4 |= 0x0020; break;
+			case 0x2: db->PHY_reg4 |= 0x0040; break;
+			case 0x4: db->PHY_reg4 |= 0x0080; break;
+			case 0x8: db->PHY_reg4 |= 0x0100; break;
+			}
+		}
+
+		/* Media Mode Force or not check */
+		dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36);
+		switch(dmfe_mode) {
+		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
+		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
+		case 0x8: dmfe_media_mode = DMFE_100MFD; break;	/* 100MFD */
+		case 0x100:
+		case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */
+		}
+
+		/* Special Function setting */
+		/* VLAN function */
+		if ( (SF_mode & 0x1) || (srom[43] & 0x80) )
+			db->cr15_data |= 0x40;
+
+		/* Flow Control */
+		if ( (SF_mode & 0x2) || (srom[40] & 0x1) )
+			db->cr15_data |= 0x400;
+
+		/* TX pause packet */
+		if ( (SF_mode & 0x4) || (srom[40] & 0xe) )
+			db->cr15_data |= 0x9800;
+	}
+
+	/* Parse HPNA parameter */
+	db->HPNA_command = 1;
+
+	/* Accept remote command or not */
+	if (HPNA_rx_cmd == 0)
+		db->HPNA_command |= 0x8000;
+
+	 /* Issue remote command & operation mode */
+	if (HPNA_tx_cmd == 1)
+		switch(HPNA_mode) {	/* Issue Remote Command */
+		case 0: db->HPNA_command |= 0x0904; break;
+		case 1: db->HPNA_command |= 0x0a00; break;
+		case 2: db->HPNA_command |= 0x0506; break;
+		case 3: db->HPNA_command |= 0x0602; break;
+		}
+	else
+		switch(HPNA_mode) {	/* Don't Issue */
+		case 0: db->HPNA_command |= 0x0004; break;
+		case 1: db->HPNA_command |= 0x0000; break;
+		case 2: db->HPNA_command |= 0x0006; break;
+		case 3: db->HPNA_command |= 0x0002; break;
+		}
+
+	/* Check DM9801 or DM9802 present or not */
+	db->HPNA_present = 0;
+	update_cr6(db->cr6_data|0x40000, db->ioaddr);
+	tmp_reg = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
+	if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
+		/* DM9801 or DM9802 present */
+		db->HPNA_timer = 8;
+		if ( phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
+			/* DM9801 HomeRun */
+			db->HPNA_present = 1;
+			dmfe_program_DM9801(db, tmp_reg);
+		} else {
+			/* DM9802 LongRun */
+			db->HPNA_present = 2;
+			dmfe_program_DM9802(db);
+		}
+	}
+
+}
+
+
+/*
+ *	Init HomeRun DM9801
+ */
+
+static void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
+{
+	uint reg17, reg25;
+
+	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
+	switch(HPNA_rev) {
+	case 0xb900: /* DM9801 E3 */
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
+		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		break;
+	case 0xb901: /* DM9801 E4 */
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
+		break;
+	case 0xb902: /* DM9801 E5 */
+	case 0xb903: /* DM9801 E6 */
+	default:
+		db->HPNA_command |= 0x1000;
+		reg25 = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
+		reg17 = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
+		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
+		break;
+	}
+	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
+	phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
+}
+
+
+/*
+ *	Init HomeRun DM9802
+ */
+
+static void dmfe_program_DM9802(struct dmfe_board_info * db)
+{
+	uint phy_reg;
+
+	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
+	phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
+	phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
+	phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
+}
+
+
+/*
+ *	Check remote HPNA power and speed status. If not correct,
+ *	issue command again.
+*/
+
+static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
+{
+	uint phy_reg;
+
+	/* Got remote device status */
+	phy_reg = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
+	switch(phy_reg) {
+	case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
+	case 0x20: phy_reg = 0x0900;break; /* LP/HS */
+	case 0x40: phy_reg = 0x0600;break; /* HP/LS */
+	case 0x60: phy_reg = 0x0500;break; /* HP/HS */
+	}
+
+	/* Check remote device status match our setting ot not */
+	if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
+		phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
+		db->HPNA_timer=8;
+	} else
+		db->HPNA_timer=600;	/* Match, every 10 minutes, check */
+}
+
+
+
+static struct pci_device_id dmfe_pci_tbl[] __devinitdata = {
+	{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
+	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
+	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
+	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
+
+
+static struct pci_driver dmfe_driver = {
+	name:		"dmfe",
+	id_table:	dmfe_pci_tbl,
+	probe:		dmfe_init_one,
+	remove:		__devexit_p(dmfe_remove_one),
+};
+
+MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
+MODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(mode, "i");
+MODULE_PARM(cr6set, "i");
+MODULE_PARM(chkmode, "i");
+MODULE_PARM(HPNA_mode, "i");
+MODULE_PARM(HPNA_rx_cmd, "i");
+MODULE_PARM(HPNA_tx_cmd, "i");
+MODULE_PARM(HPNA_NoiseFloor, "i");
+MODULE_PARM(SF_mode, "i");
+MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
+MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
+MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
+
+/*	Description:
+ *	when user used insmod to add module, system invoked init_module()
+ *	to initilize and register.
+ */
+
+static int __init dmfe_init_module(void)
+{
+	int rc;
+
+	printk(version);
+	printed_version = 1;
+
+	DMFE_DBUG(0, "init_module() ", debug);
+
+	if (debug)
+		dmfe_debug = debug;	/* set debug flag */
+	if (cr6set)
+		dmfe_cr6_user_set = cr6set;
+
+ 	switch(mode) {
+   	case DMFE_10MHF:
+	case DMFE_100MHF:
+	case DMFE_10MFD:
+	case DMFE_100MFD:
+	case DMFE_1M_HPNA:
+		dmfe_media_mode = mode;
+		break;
+	default:dmfe_media_mode = DMFE_AUTO;
+		break;
+	}
+
+	if (HPNA_mode > 4)
+		HPNA_mode = 0;		/* Default: LP/HS */
+	if (HPNA_rx_cmd > 1)
+		HPNA_rx_cmd = 0;	/* Default: Ignored remote cmd */
+	if (HPNA_tx_cmd > 1)
+		HPNA_tx_cmd = 0;	/* Default: Don't issue remote cmd */
+	if (HPNA_NoiseFloor > 15)
+		HPNA_NoiseFloor = 0;
+
+	rc = pci_module_init(&dmfe_driver);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+
+/*
+ *	Description:
+ *	when user used rmmod to delete module, system invoked clean_module()
+ *	to un-register all registered services.
+ */
+
+static void __exit dmfe_cleanup_module(void)
+{
+	DMFE_DBUG(0, "dmfe_clean_module() ", debug);
+	pci_unregister_driver(&dmfe_driver);
+}
+
+module_init(dmfe_init_module);
+module_exit(dmfe_cleanup_module);
diff -urN linux-2.5.6-pre3/drivers/net/tulip/tulip_core.c linux-2.5.6/drivers/net/tulip/tulip_core.c
--- linux-2.5.6-pre3/drivers/net/tulip/tulip_core.c	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/tulip/tulip_core.c	Thu Mar  7 18:24:48 2002
@@ -15,8 +15,8 @@
 */
 
 #define DRV_NAME	"tulip"
-#define DRV_VERSION	"1.1.11"
-#define DRV_RELDATE	"Feb 08, 2002"
+#define DRV_VERSION	"1.1.12"
+#define DRV_RELDATE	"Mar 07, 2002"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -1164,7 +1164,7 @@
 {
 	struct tulip_private *tp = dev->priv;
 	u8 cache;
-	u16 pci_command, new_command;
+	u16 pci_command;
 	u32 csr0;
 
 	if (tulip_debug > 3)
@@ -1172,24 +1172,6 @@
 
 	tp->csr0 = csr0 = 0;
 
-	/* check for sane cache line size. from acenic.c. */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
-	if ((cache << 2) != SMP_CACHE_BYTES) {
-		printk(KERN_WARNING "%s: PCI cache line size set incorrectly "
-		       "(%i bytes) by BIOS/FW, correcting to %i\n",
-		       pdev->slot_name, (cache << 2), SMP_CACHE_BYTES);
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
-				      SMP_CACHE_BYTES >> 2);
-		udelay(5);
-	}
-
-	/* read cache line size again, hardware may not have accepted
-	 * our cache line size change
-	 */
-	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
-	if (!cache)
-		goto out;
-
 	/* if we have any cache line size at all, we can do MRM */
 	csr0 |= MRM;
 
@@ -1200,15 +1182,19 @@
 	/* set or disable MWI in the standard PCI command bit.
 	 * Check for the case where  mwi is desired but not available
 	 */
+	if (csr0 & MWI)	pci_set_mwi(pdev);
+	else		pci_clear_mwi(pdev);
+
+	/* read result from hardware (in case bit refused to enable) */
 	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	if (csr0 & MWI)	new_command = pci_command | PCI_COMMAND_INVALIDATE;
-	else		new_command = pci_command & ~PCI_COMMAND_INVALIDATE;
-	if (new_command != pci_command) {
-		pci_write_config_word(pdev, PCI_COMMAND, new_command);
-		udelay(5);
-		pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-		if ((csr0 & MWI) && (!(pci_command & PCI_COMMAND_INVALIDATE)))
-			csr0 &= ~MWI;
+	if ((csr0 & MWI) && (!(pci_command & PCI_COMMAND_INVALIDATE)))
+		csr0 &= ~MWI;
+
+	/* if cache line size hardwired to zero, no MWI */
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if ((csr0 & MWI) && (cache == 0)) {
+		csr0 &= ~MWI;
+		pci_clear_mwi(pdev);
 	}
 
 	/* assign per-cacheline-size cache alignment and
@@ -1225,20 +1211,29 @@
 		csr0 |= MRL | (3 << CALShift) | (32 << BurstLenShift);
 		break;
 	default:
-		goto out;
+		cache = 0;
+		break;
 	}
 
-	tp->csr0 = csr0;
-	goto out;
+	/* if we have a good cache line size, we by now have a good
+	 * csr0, so save it and exit
+	 */
+	if (cache)
+		goto out;
 
+	/* we don't have a good csr0 or cache line size, disable MWI */
 	if (csr0 & MWI) {
-		pci_command &= ~PCI_COMMAND_INVALIDATE;
-		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+		pci_clear_mwi(pdev);
 		csr0 &= ~MWI;
 	}
-	tp->csr0 = csr0 | (8 << BurstLenShift) | (1 << CALShift);
+
+	/* sane defaults for burst length and cache alignment
+	 * originally from de4x5 driver
+	 */
+	csr0 |= (8 << BurstLenShift) | (1 << CALShift);
 
 out:
+	tp->csr0 = csr0;
 	if (tulip_debug > 2)
 		printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n",
 		       pdev->slot_name, cache, csr0);
diff -urN linux-2.5.6-pre3/drivers/net/tulip/winbond-840.c linux-2.5.6/drivers/net/tulip/winbond-840.c
--- linux-2.5.6-pre3/drivers/net/tulip/winbond-840.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/winbond-840.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,1757 @@
+/* winbond-840.c: A Linux PCI network adapter device driver. */
+/*
+	Written 1998-2001 by Donald Becker.
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+	Support and updates available at
+	http://www.scyld.com/network/drivers.html
+
+	Do not remove the copyright infomation.
+	Do not change the version information unless an improvement has been made.
+	Merely removing my name, as Compex has done in the past, does not count
+	as an improvement.
+
+	Changelog:
+	* ported to 2.4
+		???
+	* spin lock update, memory barriers, new style dma mappings
+		limit each tx buffer to < 1024 bytes
+		remove DescIntr from Rx descriptors (that's an Tx flag)
+		remove next pointer from Tx descriptors
+		synchronize tx_q_bytes
+		software reset in tx_timeout
+			Copyright (C) 2000 Manfred Spraul
+	* further cleanups
+		power management.
+		support for big endian descriptors
+			Copyright (C) 2001 Manfred Spraul
+  	* ethtool support (jgarzik)
+	* Replace some MII-related magic numbers with constants (jgarzik)
+  
+	TODO:
+	* enable pci_power_off
+	* Wake-On-LAN
+*/
+  
+#define DRV_NAME	"winbond-840"
+#define DRV_VERSION	"1.01-d"
+#define DRV_RELDATE	"Nov-17-2001"
+
+
+/* Automatically extracted configuration info:
+probe-func: winbond840_probe
+config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
+
+c-help-name: Winbond W89c840 PCI Ethernet support
+c-help-symbol: CONFIG_WINBOND_840
+c-help: This driver is for the Winbond W89c840 chip.  It also works with
+c-help: the TX9882 chip on the Compex RL100-ATX board.
+c-help: More specific information and updates are available from 
+c-help: http://www.scyld.com/network/drivers.html
+*/
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int max_interrupt_work = 20;
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+   The '840 uses a 64 element hash table based on the Ethernet CRC.  */
+static int multicast_filter_limit = 32;
+
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1518 effectively disables this feature. */
+static int rx_copybreak;
+
+/* Used to pass the media type, etc.
+   Both 'options[]' and 'full_duplex[]' should exist for driver
+   interoperability.
+   The media type is usually passed in 'options[]'.
+*/
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Operational parameters that are set at compile time. */
+
+/* Keep the ring sizes a power of two for compile efficiency.
+   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
+#define TX_QUEUE_LEN_RESTART	5
+#define RX_RING_SIZE	32
+
+#define TX_BUFLIMIT	(1024-128)
+
+/* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
+   To avoid overflowing we don't queue again until we have room for a
+   full-size packet.
+ */
+#define TX_FIFO_SIZE (2048)
+#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
+
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+/* Include files, designed to support most kernel versions 2.0.0 and later. */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/rtnetlink.h>
+#include <linux/crc32.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
+KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM_DESC(max_interrupt_work, "winbond-840 maximum events handled per interrupt");
+MODULE_PARM_DESC(debug, "winbond-840 debug level (0-6)");
+MODULE_PARM_DESC(rx_copybreak, "winbond-840 copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(multicast_filter_limit, "winbond-840 maximum number of filtered multicast addresses");
+MODULE_PARM_DESC(options, "winbond-840: Bits 0-3: media type, bit 17: full duplex");
+MODULE_PARM_DESC(full_duplex, "winbond-840 full duplex setting(s) (1)");
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This driver is for the Winbond w89c840 chip.
+
+II. Board-specific settings
+
+None.
+
+III. Driver operation
+
+This chip is very similar to the Digital 21*4* "Tulip" family.  The first
+twelve registers and the descriptor format are nearly identical.  Read a
+Tulip manual for operational details.
+
+A significant difference is that the multicast filter and station address are
+stored in registers rather than loaded through a pseudo-transmit packet.
+
+Unlike the Tulip, transmit buffers are limited to 1KB.  To transmit a
+full-sized packet we must use both data buffers in a descriptor.  Thus the
+driver uses ring mode where descriptors are implicitly sequential in memory,
+rather than using the second descriptor address as a chain pointer to
+subsequent descriptors.
+
+IV. Notes
+
+If you are going to almost clone a Tulip, why not go all the way and avoid
+the need for a new driver?
+
+IVb. References
+
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
+http://www.winbond.com.tw/
+
+IVc. Errata
+
+A horrible bug exists in the transmit FIFO.  Apparently the chip doesn't
+correctly detect a full FIFO, and queuing more than 2048 bytes may result in
+silent data corruption.
+
+Test with 'ping -s 10000' on a fast computer.
+
+*/
+
+
+
+/*
+  PCI probe table.
+*/
+enum pci_id_flags_bits {
+        /* Set PCI command register bits before calling probe1(). */
+        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+        /* Read and map the single following PCI BAR. */
+        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
+        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
+};
+enum chip_capability_flags {
+	CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
+#ifdef USE_IO_OPS
+#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
+#else
+#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
+#endif
+
+static struct pci_device_id w840_pci_tbl[] __devinitdata = {
+	{ 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
+	{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
+
+struct pci_id_info {
+        const char *name;
+        struct match_info {
+                int     pci, pci_mask, subsystem, subsystem_mask;
+                int revision, revision_mask;                            /* Only 8 bits. */
+        } id;
+        enum pci_id_flags_bits pci_flags;
+        int io_size;                            /* Needed for I/O region check or ioremap(). */
+        int drv_flags;                          /* Driver use, intended as capability flags. */
+};
+static struct pci_id_info pci_id_tbl[] = {
+	{"Winbond W89c840",			/* Sometime a Level-One switch card. */
+	 { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
+	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
+	{"Winbond W89c840", { 0x08401050, 0xffffffff, },
+	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+	{"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
+	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
+	{0,},						/* 0 terminated list. */
+};
+
+/* This driver was written to use PCI memory space, however some x86 systems
+   work only with I/O space accesses.  Pass -DUSE_IO_OPS to use PCI I/O space
+   accesses instead of memory space. */
+
+#ifdef USE_IO_OPS
+#undef readb
+#undef readw
+#undef readl
+#undef writeb
+#undef writew
+#undef writel
+#define readb inb
+#define readw inw
+#define readl inl
+#define writeb outb
+#define writew outw
+#define writel outl
+#endif
+
+/* Offsets to the Command and Status Registers, "CSRs".
+   While similar to the Tulip, these registers are longword aligned.
+   Note: It's not useful to define symbolic names for every register bit in
+   the device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+*/
+enum w840_offsets {
+	PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
+	RxRingPtr=0x0C, TxRingPtr=0x10,
+	IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
+	RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
+	CurRxDescAddr=0x30, CurRxBufAddr=0x34,			/* Debug use */
+	MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
+	CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
+};
+
+/* Bits in the interrupt status/enable registers. */
+/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
+enum intr_status_bits {
+	NormalIntr=0x10000, AbnormalIntr=0x8000,
+	IntrPCIErr=0x2000, TimerInt=0x800,
+	IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
+	TxFIFOUnderflow=0x20, RxErrIntr=0x10,
+	TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
+};
+
+/* Bits in the NetworkConfig register. */
+enum rx_mode_bits {
+	AcceptErr=0x80, AcceptRunt=0x40,
+	AcceptBroadcast=0x20, AcceptMulticast=0x10,
+	AcceptAllPhys=0x08, AcceptMyPhys=0x02,
+};
+
+enum mii_reg_bits {
+	MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
+	MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
+};
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct w840_rx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1;
+	u32 buffer2;
+};
+
+struct w840_tx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;
+};
+
+/* Bits in network_desc.status */
+enum desc_status_bits {
+	DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
+	DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
+	DescIntr=0x80000000,
+};
+
+#define PRIV_ALIGN	15 	/* Required alignment mask */
+#define MII_CNT		1 /* winbond only supports one MII */
+struct netdev_private {
+	struct w840_rx_desc *rx_ring;
+	dma_addr_t	rx_addr[RX_RING_SIZE];
+	struct w840_tx_desc *tx_ring;
+	dma_addr_t	tx_addr[TX_RING_SIZE];
+	dma_addr_t ring_dma_addr;
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for later free(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media monitoring timer. */
+	/* Frequently used values: keep some adjacent for cache effect. */
+	spinlock_t lock;
+	int chip_id, drv_flags;
+	struct pci_dev *pci_dev;
+	int csr6;
+	struct w840_rx_desc *rx_head_desc;
+	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
+	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
+	unsigned int cur_tx, dirty_tx;
+	unsigned int tx_q_bytes;
+	unsigned int tx_full;				/* The Tx queue is full. */
+	/* MII transceiver section. */
+	int mii_cnt;						/* MII device addresses. */
+	unsigned char phys[MII_CNT];		/* MII device addresses, but only the first is used */
+	u32 mii;
+	struct mii_if_info mii_if;
+};
+
+static int  eeprom_read(long ioaddr, int location);
+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 int  update_link(struct net_device *dev);
+static void netdev_timer(unsigned long data);
+static void init_rxtx_rings(struct net_device *dev);
+static void free_rxtx_rings(struct netdev_private *np);
+static void init_registers(struct net_device *dev);
+static void tx_timeout(struct net_device *dev);
+static int alloc_ringdesc(struct net_device *dev);
+static void free_ringdesc(struct netdev_private *np);
+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 void netdev_error(struct net_device *dev, int intr_status);
+static int  netdev_rx(struct net_device *dev);
+static u32 __set_rx_mode(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int  netdev_close(struct net_device *dev);
+
+
+
+static int __devinit w840_probe1 (struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	struct net_device *dev;
+	struct netdev_private *np;
+	static int find_cnt;
+	int chip_idx = ent->driver_data;
+	int irq;
+	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
+	long ioaddr;
+
+	i = pci_enable_device(pdev);
+	if (i) return i;
+
+	pci_set_master(pdev);
+
+	irq = pdev->irq;
+
+	if (pci_set_dma_mask(pdev,0xFFFFffff)) {
+		printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
+		       pdev->slot_name);
+		return -EIO;
+	}
+	dev = alloc_etherdev(sizeof(*np));
+	if (!dev)
+		return -ENOMEM;
+	SET_MODULE_OWNER(dev);
+
+	if (pci_request_regions(pdev, DRV_NAME))
+		goto err_out_netdev;
+
+#ifdef USE_IO_OPS
+	ioaddr = pci_resource_start(pdev, 0);
+#else
+	ioaddr = pci_resource_start(pdev, 1);
+	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
+	if (!ioaddr)
+		goto err_out_free_res;
+#endif
+
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
+
+	/* Reset the chip to erase previous misconfiguration.
+	   No hold time required! */
+	writel(0x00000001, ioaddr + PCIBusCfg);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	np = dev->priv;
+	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
+	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
+	spin_lock_init(&np->lock);
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+	
+	pci_set_drvdata(pdev, dev);
+
+	if (dev->mem_start)
+		option = dev->mem_start;
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x200)
+			np->mii_if.full_duplex = 1;
+		if (option & 15)
+			printk(KERN_INFO "%s: ignoring user supplied media type %d",
+				dev->name, option & 15);
+	}
+	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
+		np->mii_if.full_duplex = 1;
+
+	if (np->mii_if.full_duplex)
+		np->mii_if.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 = &netdev_ioctl;
+	dev->tx_timeout = &tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	i = register_netdev(dev);
+	if (i)
+		goto err_out_cleardev;
+
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);
+	for (i = 0; i < 5; i++)
+			printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+	if (np->drv_flags & CanHaveMII) {
+		int phy, phy_idx = 0;
+		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
+						mdio_read(dev, phy, MII_PHYSID2);
+				printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
+					   "0x%4.4x advertising %4.4x.\n",
+					   dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
+			}
+		}
+		np->mii_cnt = phy_idx;
+		np->mii_if.phy_id = np->phys[0];
+		if (phy_idx == 0) {
+				printk(KERN_WARNING "%s: MII PHY not found -- this device may "
+					   "not operate correctly.\n", dev->name);
+		}
+	}
+
+	find_cnt++;
+	return 0;
+
+err_out_cleardev:
+	pci_set_drvdata(pdev, NULL);
+#ifndef USE_IO_OPS
+	iounmap((void *)ioaddr);
+err_out_free_res:
+#endif
+	pci_release_regions(pdev);
+err_out_netdev:
+	kfree (dev);
+	return -ENODEV;
+}
+
+
+/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
+   often serial bit streams generated by the host processor.
+   The example below is for the common 93c46 EEPROM, 64 16 bit words. */
+
+/* Delay between EEPROM clock transitions.
+   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
+   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
+   made udelay() unreliable.
+   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
+   depricated.
+*/
+#define eeprom_delay(ee_addr)	readl(ee_addr)
+
+enum EEPROM_Ctrl_Bits {
+	EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
+	EE_ChipSelect=0x801, EE_DataIn=0x08,
+};
+
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+	EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
+};
+
+static int eeprom_read(long addr, int location)
+{
+	int i;
+	int retval = 0;
+	long ee_addr = addr + EECtrl;
+	int read_cmd = location | EE_ReadCmd;
+	writel(EE_ChipSelect, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 10; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
+		writel(dataval, ee_addr);
+		eeprom_delay(ee_addr);
+		writel(dataval | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+	writel(EE_ChipSelect, ee_addr);
+	eeprom_delay(ee_addr);
+
+	for (i = 16; i > 0; i--) {
+		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
+		eeprom_delay(ee_addr);
+		retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
+		writel(EE_ChipSelect, ee_addr);
+		eeprom_delay(ee_addr);
+	}
+
+	/* Terminate the EEPROM access. */
+	writel(0, ee_addr);
+	return retval;
+}
+
+/*  MII transceiver control section.
+	Read and write the MII registers using software-generated serial
+	MDIO protocol.  See the MII specifications or DP83840A data sheet
+	for details.
+
+	The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+	met by back-to-back 33Mhz PCI cycles. */
+#define mdio_delay(mdio_addr) readl(mdio_addr)
+
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with older tranceivers, so the extra
+   code size of a per-interface flag is not worthwhile. */
+static char mii_preamble_required = 1;
+
+#define MDIO_WRITE0 (MDIO_EnbOutput)
+#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(long mdio_addr)
+{
+	int bits = 32;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (--bits >= 0) {
+		writel(MDIO_WRITE1, mdio_addr);
+		mdio_delay(mdio_addr);
+		writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	long mdio_addr = dev->base_addr + MIICtrl;
+	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int i, retval = 0;
+
+	if (mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		writel(dataval, mdio_addr);
+		mdio_delay(mdio_addr);
+		writel(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 20; i > 0; i--) {
+		writel(MDIO_EnbIn, mdio_addr);
+		mdio_delay(mdio_addr);
+		retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
+		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	struct netdev_private *np = dev->priv;
+	long mdio_addr = dev->base_addr + MIICtrl;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	int i;
+
+	if (location == 4  &&  phy_id == np->phys[0])
+		np->mii_if.advertising = value;
+
+	if (mii_preamble_required)
+		mdio_sync(mdio_addr);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
+
+		writel(dataval, mdio_addr);
+		mdio_delay(mdio_addr);
+		writel(dataval | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		writel(MDIO_EnbIn, mdio_addr);
+		mdio_delay(mdio_addr);
+		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
+		mdio_delay(mdio_addr);
+	}
+	return;
+}
+
+
+static int netdev_open(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	writel(0x00000001, ioaddr + PCIBusCfg);		/* Reset */
+
+	netif_device_detach(dev);
+	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+	if (i)
+		goto out_err;
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
+			   dev->name, dev->irq);
+
+	if((i=alloc_ringdesc(dev)))
+		goto out_err;
+
+	spin_lock_irq(&np->lock);
+	netif_device_attach(dev);
+	init_registers(dev);
+	spin_unlock_irq(&np->lock);
+
+	netif_start_queue(dev);
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
+
+	/* Set the timer to check for link beat. */
+	init_timer(&np->timer);
+	np->timer.expires = jiffies + 1*HZ;
+	np->timer.data = (unsigned long)dev;
+	np->timer.function = &netdev_timer;				/* timer handler */
+	add_timer(&np->timer);
+	return 0;
+out_err:
+	netif_device_attach(dev);
+	return i;
+}
+
+#define MII_DAVICOM_DM9101	0x0181b800
+
+static int update_link(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int duplex, fasteth, result, mii_reg;
+
+	/* BSMR */
+	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
+
+	if (mii_reg == 0xffff)
+		return np->csr6;
+	/* reread: the link status bit is sticky */
+	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
+	if (!(mii_reg & 0x4)) {
+		if (netif_carrier_ok(dev)) {
+			if (debug)
+				printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n",
+					dev->name, np->phys[0]);
+			netif_carrier_off(dev);
+		}
+		return np->csr6;
+	}
+	if (!netif_carrier_ok(dev)) {
+		if (debug)
+			printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n",
+				dev->name, np->phys[0]);
+		netif_carrier_on(dev);
+	}
+	
+	if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) {
+		/* If the link partner doesn't support autonegotiation
+		 * the MII detects it's abilities with the "parallel detection".
+		 * Some MIIs update the LPA register to the result of the parallel
+		 * detection, some don't.
+		 * The Davicom PHY [at least 0181b800] doesn't.
+		 * Instead bit 9 and 13 of the BMCR are updated to the result
+		 * of the negotiation..
+		 */
+		mii_reg = mdio_read(dev, np->phys[0], MII_BMCR);
+		duplex = mii_reg & BMCR_FULLDPLX;
+		fasteth = mii_reg & BMCR_SPEED100;
+	} else {
+		int negotiated;
+		mii_reg	= mdio_read(dev, np->phys[0], MII_LPA);
+		negotiated = mii_reg & np->mii_if.advertising;
+
+		duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
+		fasteth = negotiated & 0x380;
+	}
+	duplex |= np->mii_if.duplex_lock;
+	/* remove fastether and fullduplex */
+	result = np->csr6 & ~0x20000200;
+	if (duplex)
+		result |= 0x200;
+	if (fasteth)
+		result |= 0x20000000;
+	if (result != np->csr6 && debug)
+		printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n",
+				 dev->name, fasteth ? 100 : 10, 
+			   	duplex ? "full" : "half", np->phys[0]);
+	return result;
+}
+
+#define RXTX_TIMEOUT	2000
+static inline void update_csr6(struct net_device *dev, int new)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int limit = RXTX_TIMEOUT;
+
+	if (!netif_device_present(dev))
+		new = 0;
+	if (new==np->csr6)
+		return;
+	/* stop both Tx and Rx processes */
+	writel(np->csr6 & ~0x2002, ioaddr + NetworkConfig);
+	/* wait until they have really stopped */
+	for (;;) {
+		int csr5 = readl(ioaddr + IntrStatus);
+		int t;
+
+		t = (csr5 >> 17) & 0x07;
+		if (t==0||t==1) {
+			/* rx stopped */
+			t = (csr5 >> 20) & 0x07;
+			if (t==0||t==1)
+				break;
+		}
+
+		limit--;
+		if(!limit) {
+			printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n",
+					dev->name, csr5);
+			break;
+		}
+		udelay(1);
+	}
+	np->csr6 = new;
+	/* and restart them with the new configuration */
+	writel(np->csr6, ioaddr + NetworkConfig);
+	if (new & 0x200)
+		np->mii_if.full_duplex = 1;
+}
+
+static void netdev_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
+			   "config %8.8x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus),
+			   (int)readl(ioaddr + NetworkConfig));
+	spin_lock_irq(&np->lock);
+	update_csr6(dev, update_link(dev));
+	spin_unlock_irq(&np->lock);
+	np->timer.expires = jiffies + 10*HZ;
+	add_timer(&np->timer);
+}
+
+static void init_rxtx_rings(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	np->rx_head_desc = &np->rx_ring[0];
+	np->tx_ring = (struct w840_tx_desc*)&np->rx_ring[RX_RING_SIZE];
+
+	/* Initial all Rx descriptors. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].length = np->rx_buf_sz;
+		np->rx_ring[i].status = 0;
+		np->rx_skbuff[i] = 0;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	np->rx_ring[i-1].length |= DescEndRing;
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail,
+					skb->len,PCI_DMA_FROMDEVICE);
+
+		np->rx_ring[i].buffer1 = np->rx_addr[i];
+		np->rx_ring[i].status = DescOwn;
+	}
+
+	np->cur_rx = 0;
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* Initialize the Tx descriptors */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_skbuff[i] = 0;
+		np->tx_ring[i].status = 0;
+	}
+	np->tx_full = 0;
+	np->tx_q_bytes = np->dirty_tx = np->cur_tx = 0;
+
+	writel(np->ring_dma_addr, dev->base_addr + RxRingPtr);
+	writel(np->ring_dma_addr+sizeof(struct w840_rx_desc)*RX_RING_SIZE,
+		dev->base_addr + TxRingPtr);
+
+}
+
+static void free_rxtx_rings(struct netdev_private* np)
+{
+	int i;
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].status = 0;
+		if (np->rx_skbuff[i]) {
+			pci_unmap_single(np->pci_dev,
+						np->rx_addr[i],
+						np->rx_skbuff[i]->len,
+						PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_skbuff[i]);
+		}
+		np->rx_skbuff[i] = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (np->tx_skbuff[i]) {
+			pci_unmap_single(np->pci_dev,
+						np->tx_addr[i],
+						np->tx_skbuff[i]->len,
+						PCI_DMA_TODEVICE);
+			dev_kfree_skb(np->tx_skbuff[i]);
+		}
+		np->tx_skbuff[i] = 0;
+	}
+}
+
+static void init_registers(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	for (i = 0; i < 6; i++)
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
+
+	/* Initialize other registers. */
+#ifdef __BIG_ENDIAN
+	i = (1<<20);	/* Big-endian descriptors */
+#else
+	i = 0;
+#endif
+	i |= (0x04<<2);		/* skip length 4 u32 */
+	i |= 0x02;		/* give Rx priority */
+
+	/* Configure the PCI bus bursts and FIFO thresholds.
+	   486: Set 8 longword cache alignment, 8 longword burst.
+	   586: Set 16 longword cache alignment, no burst limit.
+	   Cache alignment bits 15:14	     Burst length 13:8
+		0000	<not allowed> 		0000 align to cache	0800 8 longwords
+		4000	8  longwords		0100 1 longword		1000 16 longwords
+		8000	16 longwords		0200 2 longwords	2000 32 longwords
+		C000	32  longwords		0400 4 longwords */
+
+#if defined (__i386__) && !defined(MODULE)
+	/* When not a module we can work around broken '486 PCI boards. */
+	if (boot_cpu_data.x86 <= 4) {
+		i |= 0x4800;
+		printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
+			   "alignment to 8 longwords.\n", dev->name);
+	} else {
+		i |= 0xE000;
+	}
+#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
+	i |= 0xE000;
+#elif defined(__sparc__)
+	i |= 0x4800;
+#else
+#warning Processor architecture undefined
+	i |= 0x4800;
+#endif
+	writel(i, ioaddr + PCIBusCfg);
+
+	np->csr6 = 0;
+	/* 128 byte Tx threshold; 
+		Transmit on; Receive on; */
+	update_csr6(dev, 0x00022002 | update_link(dev) | __set_rx_mode(dev));
+
+	/* Clear and Enable interrupts by setting the interrupt mask. */
+	writel(0x1A0F5, ioaddr + IntrStatus);
+	writel(0x1A0F5, ioaddr + IntrEnable);
+
+	writel(0, ioaddr + RxStartDemand);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
+		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
+
+	{
+		int i;
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %8.8x", np->tx_ring[i].status);
+		printk("\n");
+	}
+	printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n",
+				np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
+	printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));
+
+	disable_irq(dev->irq);
+	spin_lock_irq(&np->lock);
+	/*
+	 * Under high load dirty_tx and the internal tx descriptor pointer
+	 * come out of sync, thus perform a software reset and reinitialize
+	 * everything.
+	 */
+
+	writel(1, dev->base_addr+PCIBusCfg);
+	udelay(1);
+
+	free_rxtx_rings(np);
+	init_rxtx_rings(dev);
+	init_registers(dev);
+	spin_unlock_irq(&np->lock);
+	enable_irq(dev->irq);
+
+	netif_wake_queue(dev);
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	return;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static int alloc_ringdesc(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	np->rx_ring = pci_alloc_consistent(np->pci_dev,
+			sizeof(struct w840_rx_desc)*RX_RING_SIZE +
+			sizeof(struct w840_tx_desc)*TX_RING_SIZE,
+			&np->ring_dma_addr);
+	if(!np->rx_ring)
+		return -ENOMEM;
+	init_rxtx_rings(dev);
+	return 0;
+}
+
+static void free_ringdesc(struct netdev_private *np)
+{
+	pci_free_consistent(np->pci_dev,
+			sizeof(struct w840_rx_desc)*RX_RING_SIZE +
+			sizeof(struct w840_tx_desc)*TX_RING_SIZE,
+			np->rx_ring, np->ring_dma_addr);
+
+}
+
+static int start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	unsigned entry;
+
+	/* Caution: the write order is important here, set the field
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = np->cur_tx % TX_RING_SIZE;
+
+	np->tx_addr[entry] = pci_map_single(np->pci_dev,
+				skb->data,skb->len, PCI_DMA_TODEVICE);
+	np->tx_skbuff[entry] = skb;
+
+	np->tx_ring[entry].buffer1 = np->tx_addr[entry];
+	if (skb->len < TX_BUFLIMIT) {
+		np->tx_ring[entry].length = DescWholePkt | skb->len;
+	} else {
+		int len = skb->len - TX_BUFLIMIT;
+
+		np->tx_ring[entry].buffer2 = np->tx_addr[entry]+TX_BUFLIMIT;
+		np->tx_ring[entry].length = DescWholePkt | (len << 11) | TX_BUFLIMIT;
+	}
+	if(entry == TX_RING_SIZE-1)
+		np->tx_ring[entry].length |= DescEndRing;
+
+	/* Now acquire the irq spinlock.
+	 * The difficult race is the the ordering between
+	 * increasing np->cur_tx and setting DescOwn:
+	 * - if np->cur_tx is increased first the interrupt
+	 *   handler could consider the packet as transmitted
+	 *   since DescOwn is cleared.
+	 * - If DescOwn is set first the NIC could report the
+	 *   packet as sent, but the interrupt handler would ignore it
+	 *   since the np->cur_tx was not yet increased.
+	 */
+	spin_lock_irq(&np->lock);
+	np->cur_tx++;
+
+	wmb(); /* flush length, buffer1, buffer2 */
+	np->tx_ring[entry].status = DescOwn;
+	wmb(); /* flush status and kick the hardware */
+	writel(0, dev->base_addr + TxStartDemand);
+	np->tx_q_bytes += skb->len;
+	/* Work around horrible bug in the chip by marking the queue as full
+	   when we do not have FIFO room for a maximum sized packet. */
+	if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN ||
+		((np->drv_flags & HasBrokenTx) && np->tx_q_bytes > TX_BUG_FIFO_LIMIT)) {
+		netif_stop_queue(dev);
+		wmb();
+		np->tx_full = 1;
+	}
+	spin_unlock_irq(&np->lock);
+
+	dev->trans_start = jiffies;
+
+	if (debug > 4) {
+		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
+			   dev->name, np->cur_tx, entry);
+	}
+	return 0;
+}
+
+static void netdev_tx_done(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+		int entry = np->dirty_tx % TX_RING_SIZE;
+		int tx_status = np->tx_ring[entry].status;
+
+		if (tx_status < 0)
+			break;
+		if (tx_status & 0x8000) { 	/* There was an error, log it. */
+#ifndef final_version
+			if (debug > 1)
+				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+					   dev->name, tx_status);
+#endif
+			np->stats.tx_errors++;
+			if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
+			if (tx_status & 0x0C80) np->stats.tx_carrier_errors++;
+			if (tx_status & 0x0200) np->stats.tx_window_errors++;
+			if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
+			if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
+				np->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+			if (tx_status & 0x0100) np->stats.collisions16++;
+#endif
+		} else {
+#ifdef ETHER_STATS
+			if (tx_status & 0x0001) np->stats.tx_deferred++;
+#endif
+#ifndef final_version
+			if (debug > 3)
+				printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
+					   dev->name, entry, tx_status);
+#endif
+			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
+			np->stats.collisions += (tx_status >> 3) & 15;
+			np->stats.tx_packets++;
+		}
+		/* Free the original skb. */
+		pci_unmap_single(np->pci_dev,np->tx_addr[entry],
+					np->tx_skbuff[entry]->len,
+					PCI_DMA_TODEVICE);
+		np->tx_q_bytes -= np->tx_skbuff[entry]->len;
+		dev_kfree_skb_irq(np->tx_skbuff[entry]);
+		np->tx_skbuff[entry] = 0;
+	}
+	if (np->tx_full &&
+		np->cur_tx - np->dirty_tx < TX_QUEUE_LEN_RESTART &&
+		np->tx_q_bytes < TX_BUG_FIFO_LIMIT) {
+		/* The ring is no longer full, clear tbusy. */
+		np->tx_full = 0;
+		wmb();
+		netif_wake_queue(dev);
+	}
+}
+
+/* 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)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int work_limit = max_interrupt_work;
+
+	if (!netif_device_present(dev))
+		return;
+	do {
+		u32 intr_status = readl(ioaddr + IntrStatus);
+
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		writel(intr_status & 0x001ffff, ioaddr + IntrStatus);
+
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
+				   dev->name, intr_status);
+
+		if ((intr_status & (NormalIntr|AbnormalIntr)) == 0)
+			break;
+
+		if (intr_status & (IntrRxDone | RxNoBuf))
+			netdev_rx(dev);
+		if (intr_status & RxNoBuf)
+			writel(0, ioaddr + RxStartDemand);
+
+		if (intr_status & (TxIdle | IntrTxDone) &&
+			np->cur_tx != np->dirty_tx) {
+			spin_lock(&np->lock);
+			netdev_tx_done(dev);
+			spin_unlock(&np->lock);
+		}
+
+		/* Abnormal error summary/uncommon events handlers. */
+		if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
+						   TimerInt | IntrTxStopped))
+			netdev_error(dev, intr_status);
+
+		if (--work_limit < 0) {
+			printk(KERN_WARNING "%s: Too much work at interrupt, "
+				   "status=0x%4.4x.\n", dev->name, intr_status);
+			/* Set the timer to re-enable the other interrupts after
+			   10*82usec ticks. */
+			spin_lock(&np->lock);
+			if (netif_device_present(dev)) {
+				writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable);
+				writel(10, ioaddr + GPTimer);
+			}
+			spin_unlock(&np->lock);
+			break;
+		}
+	} while (1);
+
+	if (debug > 3)
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus));
+}
+
+/* This routine is logically part of the interrupt handler, but separated
+   for clarity and better register allocation. */
+static int netdev_rx(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int entry = np->cur_rx % RX_RING_SIZE;
+	int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+
+	if (debug > 4) {
+		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
+			   entry, np->rx_ring[entry].status);
+	}
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while (--work_limit >= 0) {
+		struct w840_rx_desc *desc = np->rx_head_desc;
+		s32 status = desc->status;
+
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
+				   status);
+		if (status < 0)
+			break;
+		if ((status & 0x38008300) != 0x0300) {
+			if ((status & 0x38000300) != 0x0300) {
+				/* Ingore earlier buffers. */
+				if ((status & 0xffff) != 0x7fff) {
+					printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
+						   "multiple buffers, entry %#x status %4.4x!\n",
+						   dev->name, np->cur_rx, status);
+					np->stats.rx_length_errors++;
+				}
+			} else if (status & 0x8000) {
+				/* There was a fatal error. */
+				if (debug > 2)
+					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+						   dev->name, status);
+				np->stats.rx_errors++; /* end of a packet.*/
+				if (status & 0x0890) np->stats.rx_length_errors++;
+				if (status & 0x004C) np->stats.rx_frame_errors++;
+				if (status & 0x0002) np->stats.rx_crc_errors++;
+			}
+		} else {
+			struct sk_buff *skb;
+			/* Omit the four octet CRC from the length. */
+			int pkt_len = ((status >> 16) & 0x7ff) - 4;
+
+#ifndef final_version
+			if (debug > 4)
+				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
+					   " status %x.\n", pkt_len, status);
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+				pci_dma_sync_single(np->pci_dev,np->rx_addr[entry],
+							np->rx_skbuff[entry]->len,
+							PCI_DMA_FROMDEVICE);
+				/* Call copy + cksum if available. */
+#if HAS_IP_COPYSUM
+				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+					   pkt_len);
+#endif
+			} else {
+				pci_unmap_single(np->pci_dev,np->rx_addr[entry],
+							np->rx_skbuff[entry]->len,
+							PCI_DMA_FROMDEVICE);
+				skb_put(skb = np->rx_skbuff[entry], pkt_len);
+				np->rx_skbuff[entry] = NULL;
+			}
+#ifndef final_version				/* Remove after testing. */
+			/* You will want this info for the initial debug. */
+			if (debug > 5)
+				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
+					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
+					   "%d.%d.%d.%d.\n",
+					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
+					   skb->data[8], skb->data[9], skb->data[10],
+					   skb->data[11], skb->data[12], skb->data[13],
+					   skb->data[14], skb->data[15], skb->data[16],
+					   skb->data[17]);
+#endif
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			np->stats.rx_packets++;
+			np->stats.rx_bytes += pkt_len;
+		}
+		entry = (++np->cur_rx) % RX_RING_SIZE;
+		np->rx_head_desc = &np->rx_ring[entry];
+	}
+
+	/* Refill the Rx ring buffers. */
+	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+		struct sk_buff *skb;
+		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;
+			if (skb == NULL)
+				break;			/* Better luck next round. */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			np->rx_addr[entry] = pci_map_single(np->pci_dev,
+							skb->tail,
+							skb->len, PCI_DMA_FROMDEVICE);
+			np->rx_ring[entry].buffer1 = np->rx_addr[entry];
+		}
+		wmb();
+		np->rx_ring[entry].status = DescOwn;
+	}
+
+	return 0;
+}
+
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
+			   dev->name, intr_status);
+	if (intr_status == 0xffffffff)
+		return;
+	spin_lock(&np->lock);
+	if (intr_status & TxFIFOUnderflow) {
+		int new;
+		/* Bump up the Tx threshold */
+#if 0
+		/* This causes lots of dropped packets,
+		 * and under high load even tx_timeouts
+		 */
+		new = np->csr6 + 0x4000;
+#else
+		new = (np->csr6 >> 14)&0x7f;
+		if (new < 64)
+			new *= 2;
+		 else
+		 	new = 127; /* load full packet before starting */
+		new = (np->csr6 & ~(0x7F << 14)) | (new<<14);
+#endif
+		printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n",
+			   dev->name, new);
+		update_csr6(dev, new);
+	}
+	if (intr_status & IntrRxDied) {		/* Missed a Rx frame. */
+		np->stats.rx_errors++;
+	}
+	if (intr_status & TimerInt) {
+		/* Re-enable other interrupts. */
+		if (netif_device_present(dev))
+			writel(0x1A0F5, ioaddr + IntrEnable);
+	}
+	np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
+	writel(0, ioaddr + RxStartDemand);
+	spin_unlock(&np->lock);
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	/* The chip only need report frame silently dropped. */
+	spin_lock_irq(&np->lock);
+	if (netif_running(dev) && netif_device_present(dev))
+		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
+	spin_unlock_irq(&np->lock);
+
+	return &np->stats;
+}
+
+
+static u32 __set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 mc_filter[2];			/* Multicast hash filter */
+	u32 rx_mode;
+
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
+			| AcceptMyPhys;
+	} else if ((dev->mc_count > multicast_filter_limit)
+			   ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		memset(mc_filter, 0xff, sizeof(mc_filter));
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	} else {
+		struct dev_mc_list *mclist;
+		int i;
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+			 i++, mclist = mclist->next) {
+			set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F,
+					mc_filter);
+		}
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	}
+	writel(mc_filter[0], ioaddr + MulticastFilter0);
+	writel(mc_filter[1], ioaddr + MulticastFilter1);
+	return rx_mode;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	u32 rx_mode = __set_rx_mode(dev);
+	spin_lock_irq(&np->lock);
+	update_csr6(dev, (np->csr6 & ~0x00F8) | rx_mode);
+	spin_unlock_irq(&np->lock);
+}
+
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+        switch (ethcmd) {
+        case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		strcpy(info.bus_info, np->pci_dev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&np->lock);
+		mii_ethtool_gset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int r;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&np->lock);
+		r = mii_ethtool_sset(&np->mii_if, &ecmd);
+		spin_unlock_irq(&np->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&np->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&np->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		debug = edata.data;
+		return 0;
+	}
+        }
+	
+	return -EOPNOTSUPP;
+}
+
+static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
+	struct netdev_private *np = dev->priv;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
+		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
+		/* Fall Through */
+
+	case SIOCGMIIREG:		/* Read MII PHY register. */
+		spin_lock_irq(&np->lock);
+		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
+		spin_unlock_irq(&np->lock);
+		return 0;
+
+	case SIOCSMIIREG:		/* Write MII PHY register. */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irq(&np->lock);
+		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+		spin_unlock_irq(&np->lock);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int netdev_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	netif_stop_queue(dev);
+
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x "
+			   "Config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus),
+			   (int)readl(ioaddr + NetworkConfig));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+	}
+
+ 	/* Stop the chip's Tx and Rx processes. */
+	spin_lock_irq(&np->lock);
+	netif_device_detach(dev);
+	update_csr6(dev, 0);
+	writel(0x0000, ioaddr + IntrEnable);
+	spin_unlock_irq(&np->lock);
+
+	free_irq(dev->irq, dev);
+	wmb();
+	netif_device_attach(dev);
+
+	if (readl(ioaddr + NetworkConfig) != 0xffffffff)
+		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
+
+#ifdef __i386__
+	if (debug > 2) {
+		int i;
+
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   (int)np->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" #%d desc. %4.4x %4.4x %8.8x.\n",
+				   i, np->tx_ring[i].length,
+				   np->tx_ring[i].status, np->tx_ring[i].buffer1);
+		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
+			   (int)np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
+				   i, np->rx_ring[i].length,
+				   np->rx_ring[i].status, np->rx_ring[i].buffer1);
+		}
+	}
+#endif /* __i386__ debugging only */
+
+	del_timer_sync(&np->timer);
+
+	free_rxtx_rings(np);
+	free_ringdesc(np);
+
+	return 0;
+}
+
+static void __devexit w840_remove1 (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	if (dev) {
+		unregister_netdev(dev);
+		pci_release_regions(pdev);
+#ifndef USE_IO_OPS
+		iounmap((char *)(dev->base_addr));
+#endif
+		kfree(dev);
+	}
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * suspend/resume synchronization:
+ * - open, close, do_ioctl:
+ * 	rtnl_lock, & netif_device_detach after the rtnl_unlock.
+ * - get_stats:
+ * 	spin_lock_irq(np->lock), doesn't touch hw if not present
+ * - hard_start_xmit:
+ * 	netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
+ * - tx_timeout:
+ * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
+ * - set_multicast_list
+ * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
+ * - interrupt handler
+ * 	doesn't touch hw if not present, synchronize_irq waits for
+ * 	running instances of the interrupt handler.
+ *
+ * Disabling hw requires clearing csr6 & IntrEnable.
+ * update_csr6 & all function that write IntrEnable check netif_device_present
+ * before settings any bits.
+ *
+ * Detach must occur under spin_unlock_irq(), interrupts from a detached
+ * device would cause an irq storm.
+ */
+static int w840_suspend (struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	rtnl_lock();
+	if (netif_running (dev)) {
+		del_timer_sync(&np->timer);
+
+		spin_lock_irq(&np->lock);
+		netif_device_detach(dev);
+		update_csr6(dev, 0);
+		writel(0, ioaddr + IntrEnable);
+		netif_stop_queue(dev);
+		spin_unlock_irq(&np->lock);
+
+		spin_unlock_wait(&dev->xmit_lock);
+		synchronize_irq();
+	
+		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
+
+		/* no more hardware accesses behind this line. */
+
+		if (np->csr6) BUG();
+		if (readl(ioaddr + IntrEnable)) BUG();
+
+		/* pci_power_off(pdev, -1); */
+
+		free_rxtx_rings(np);
+	} else {
+		netif_device_detach(dev);
+	}
+	rtnl_unlock();
+	return 0;
+}
+
+
+static int w840_resume (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata (pdev);
+	struct netdev_private *np = dev->priv;
+
+	rtnl_lock();
+	if (netif_device_present(dev))
+		goto out; /* device not suspended */
+	if (netif_running(dev)) {
+		pci_enable_device(pdev);
+	/*	pci_power_on(pdev); */
+
+		spin_lock_irq(&np->lock);
+		writel(1, dev->base_addr+PCIBusCfg);
+		readl(dev->base_addr+PCIBusCfg);
+		udelay(1);
+		netif_device_attach(dev);
+		init_rxtx_rings(dev);
+		init_registers(dev);
+		spin_unlock_irq(&np->lock);
+
+		netif_wake_queue(dev);
+
+		np->timer.expires = jiffies + 1*HZ;
+		add_timer(&np->timer);
+	} else {
+		netif_device_attach(dev);
+	}
+out:
+	rtnl_unlock();
+	return 0;
+}
+#endif
+
+static struct pci_driver w840_driver = {
+	name:		DRV_NAME,
+	id_table:	w840_pci_tbl,
+	probe:		w840_probe1,
+	remove:		__devexit_p(w840_remove1),
+#ifdef CONFIG_PM
+	suspend:	w840_suspend,
+	resume:		w840_resume,
+#endif
+};
+
+static int __init w840_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
+	return pci_module_init(&w840_driver);
+}
+
+static void __exit w840_exit(void)
+{
+	pci_unregister_driver(&w840_driver);
+}
+
+module_init(w840_init);
+module_exit(w840_exit);
diff -urN linux-2.5.6-pre3/drivers/net/tulip/xircom_cb.c linux-2.5.6/drivers/net/tulip/xircom_cb.c
--- linux-2.5.6-pre3/drivers/net/tulip/xircom_cb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/xircom_cb.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,1245 @@
+/*
+ * xircom_cb: A driver for the (tulip-like) Xircom Cardbus ethernet cards 
+ *
+ * This software is (C) by the respective authors, and licensed under the GPL
+ * License.
+ *
+ * Written by Arjan van de Ven for Red Hat, Inc.
+ * Based on work by Jeff Garzik, Doug Ledford and Donald Becker 
+ *
+ *  	This software may be used and distributed according to the terms
+ *      of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * 	$Id: xircom_cb.c,v 1.33 2001/03/19 14:02:07 arjanv Exp $
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+
+
+#ifdef DEBUG
+#define enter(x)   printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
+#define leave(x)   printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__)
+#else
+#define enter(x)   do {} while (0)
+#define leave(x)   do {} while (0)
+#endif
+
+
+MODULE_DESCRIPTION("Xircom Cardbus ethernet driver");
+MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");
+MODULE_LICENSE("GPL");
+
+
+
+/* IO registers on the card, offsets */
+#define CSR0	0x00
+#define CSR1	0x08
+#define CSR2	0x10
+#define CSR3	0x18
+#define CSR4	0x20
+#define CSR5	0x28
+#define CSR6	0x30
+#define CSR7	0x38
+#define CSR8	0x40
+#define CSR9	0x48
+#define CSR10	0x50
+#define CSR11	0x58
+#define CSR12	0x60
+#define CSR13	0x68
+#define CSR14	0x70
+#define CSR15	0x78
+#define CSR16	0x80
+
+/* PCI registers */
+#define PCI_POWERMGMT 	0x40
+
+/* Offsets of the buffers within the descriptor pages, in bytes */
+
+#define NUMDESCRIPTORS 4
+
+static int bufferoffsets[NUMDESCRIPTORS] = {128,2048,4096,6144};
+
+
+struct xircom_private {
+	/* Send and receive buffers, kernel-addressable and dma addressable forms */
+
+	unsigned int *rx_buffer;
+	unsigned int *tx_buffer;
+
+	dma_addr_t rx_dma_handle;
+	dma_addr_t tx_dma_handle;
+
+	struct sk_buff *tx_skb[4];
+
+	unsigned long io_port;
+	int open;
+	
+	/* transmit_used is the rotating counter that indicates which transmit
+	   descriptor has to be used next */
+	int transmit_used;
+
+	/* Spinlock to serialize register operations.
+	   It must be helt while manipulating the following registers:
+	   CSR0, CSR6, CSR7, CSR9, CSR10, CSR15
+	 */
+	spinlock_t lock;
+
+
+	struct pci_dev *pdev;
+	struct net_device *dev;
+	struct net_device_stats stats;
+};
+
+
+/* Function prototypes */
+static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void xircom_remove(struct pci_dev *pdev);
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int xircom_open(struct net_device *dev);
+static int xircom_close(struct net_device *dev);
+static void xircom_up(struct xircom_private *card);
+static struct net_device_stats *xircom_get_stats(struct net_device *dev);
+
+static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset);
+static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset);
+static void read_mac_address(struct xircom_private *card);
+static void tranceiver_voodoo(struct xircom_private *card);
+static void initialize_card(struct xircom_private *card);
+static void trigger_transmit(struct xircom_private *card);
+static void trigger_receive(struct xircom_private *card);
+static void setup_descriptors(struct xircom_private *card);
+static void remove_descriptors(struct xircom_private *card);
+static int link_status_changed(struct xircom_private *card);
+static void activate_receiver(struct xircom_private *card);
+static void deactivate_receiver(struct xircom_private *card);
+static void activate_transmitter(struct xircom_private *card);
+static void deactivate_transmitter(struct xircom_private *card);
+static void enable_transmit_interrupt(struct xircom_private *card);
+static void enable_receive_interrupt(struct xircom_private *card);
+static void enable_link_interrupt(struct xircom_private *card);
+static void disable_all_interrupts(struct xircom_private *card);
+static int link_status(struct xircom_private *card);
+
+
+
+static struct pci_device_id xircom_pci_table[] __devinitdata = {
+	{0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,},
+};
+MODULE_DEVICE_TABLE(pci, xircom_pci_table);
+
+static struct pci_driver xircom_ops = {
+	name:		"xircom_cb", 
+	id_table:	xircom_pci_table, 
+	probe:		xircom_probe, 
+	remove:		xircom_remove, 
+	suspend:NULL,
+	resume:NULL
+};
+
+
+#ifdef DEBUG
+static void print_binary(unsigned int number)
+{
+	int i,i2;
+	char buffer[64];
+	memset(buffer,0,64);
+	i2=0;
+	for (i=31;i>=0;i--) {
+		if (number & (1<<i))
+			buffer[i2++]='1';
+		else
+			buffer[i2++]='0';
+		if ((i&3)==0) 
+			buffer[i2++]=' ';
+	}
+	printk("%s\n",buffer);
+}
+#endif
+
+/* xircom_probe is the code that gets called on device insertion.
+   it sets up the hardware and registers the device to the networklayer.
+   
+   TODO: Send 1 or 2 "dummy" packets here as the card seems to discard the
+         first two packets that get send, and pump hates that.
+         
+ */
+static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net_device *dev = NULL;
+	struct xircom_private *private;
+	unsigned char chip_rev;
+	unsigned long flags;
+	unsigned short tmp16;
+	enter("xircom_probe");
+	
+	/* First do the PCI initialisation */
+
+	if (pci_enable_device(pdev))
+		return -ENODEV;
+
+	/* disable all powermanagement */
+	pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
+	
+	pci_set_master(pdev); /* Why isn't this done by pci_enable_device ?*/
+
+	/* clear PCI status, if any */ 
+	pci_read_config_word (pdev,PCI_STATUS, &tmp16); 
+	pci_write_config_word (pdev, PCI_STATUS,tmp16);
+	
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
+	
+	if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
+		printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
+		return -ENODEV;
+	}
+
+	
+	/* 
+	   Before changing the hardware, allocate the memory.
+	   This way, we can fail gracefully if not enough memory
+	   is available. 
+	 */
+	private = kmalloc(sizeof(*private),GFP_KERNEL);
+	memset(private, 0, sizeof(struct xircom_private));
+	
+	/* Allocate the send/receive buffers */
+	private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle);
+	
+	if (private->rx_buffer == NULL) {
+ 		printk(KERN_ERR "xircom_probe: no memory for rx buffer \n");
+ 		kfree(private);
+		return -ENODEV;
+	}	
+	private->tx_buffer = pci_alloc_consistent(pdev,8192,&private->tx_dma_handle);
+	if (private->tx_buffer == NULL) {
+		printk(KERN_ERR "xircom_probe: no memory for tx buffer \n");
+		kfree(private->rx_buffer);
+		kfree(private);
+		return -ENODEV;
+	}
+	dev = init_etherdev(dev, 0);
+	if (dev == NULL) {
+		printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n");
+		kfree(private->rx_buffer);
+		kfree(private->tx_buffer);
+		kfree(private);
+		return -ENODEV;
+	}
+	SET_MODULE_OWNER(dev);
+	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
+
+	private->dev = dev;
+	private->pdev = pdev;
+	private->io_port = pci_resource_start(pdev, 0);
+	private->lock = SPIN_LOCK_UNLOCKED;
+	dev->irq = pdev->irq;
+	dev->base_addr = private->io_port;
+	
+	
+	initialize_card(private);
+	read_mac_address(private);
+	setup_descriptors(private);
+	
+	dev->open = &xircom_open;
+	dev->hard_start_xmit = &xircom_start_xmit;
+	dev->stop = &xircom_close;
+	dev->get_stats = &xircom_get_stats;
+	dev->priv = private;
+	pdev->driver_data = dev;
+
+	
+	/* start the transmitter to get a heartbeat */
+	/* TODO: send 2 dummy packets here */
+	tranceiver_voodoo(private);
+	
+	spin_lock_irqsave(&private->lock,flags);
+	  activate_transmitter(private);
+	  activate_receiver(private);
+	spin_unlock_irqrestore(&private->lock,flags);
+	
+	trigger_receive(private);
+	
+	leave("xircom_probe");
+	return 0;
+}
+
+
+/*
+ xircom_remove is called on module-unload or on device-eject.
+ it unregisters the irq, io-region and network device.
+ Interrupts and such are already stopped in the "ifconfig ethX down"
+ code.
+ */
+static void __devexit xircom_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pdev->driver_data;
+	struct xircom_private *card;
+	enter("xircom_remove");
+	if (dev!=NULL) {
+		card=dev->priv;
+		if (card!=NULL) {	
+			if (card->rx_buffer!=NULL)
+				pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
+			card->rx_buffer = NULL;
+			if (card->tx_buffer!=NULL)
+				pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
+			card->tx_buffer = NULL;			
+		}
+		kfree(card);
+	}
+	release_region(dev->base_addr, 128);
+	unregister_netdev(dev);
+	kfree(dev);
+	leave("xircom_remove");
+} 
+
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct xircom_private *card = (struct xircom_private *) dev->priv;
+	unsigned int status;
+	int i;
+
+	enter("xircom_interrupt\n");
+
+	spin_lock(&card->lock);
+	status = inl(card->io_port+CSR5);
+
+#if DEBUG	
+	print_binary(status);
+	printk("tx status 0x%08x 0x%08x \n",card->tx_buffer[0],card->tx_buffer[4]);
+	printk("rx status 0x%08x 0x%08x \n",card->rx_buffer[0],card->rx_buffer[4]);
+#endif	
+
+	if (link_status_changed(card)) {
+		int newlink;
+		printk(KERN_DEBUG "xircom_cb: Link status has changed \n");
+		newlink = link_status(card);
+		printk(KERN_INFO  "xircom_cb: Link is %i mbit \n",newlink);
+		if (newlink)
+			netif_carrier_on(dev);
+		else
+			netif_carrier_off(dev);
+		
+	}
+
+	/* Clear all remaining interrupts */	
+	status |= 0xffffffff; /* FIXME: make this clear only the
+				        real existing bits */
+	outl(status,card->io_port+CSR5);
+	
+
+	for (i=0;i<NUMDESCRIPTORS;i++) 
+		investigate_write_descriptor(dev,card,i,bufferoffsets[i]);
+	for (i=0;i<NUMDESCRIPTORS;i++) 
+		investigate_read_descriptor(dev,card,i,bufferoffsets[i]);
+
+	
+	spin_unlock(&card->lock);
+	leave("xircom_interrupt");
+}
+
+static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct xircom_private *card;
+	unsigned long flags;
+	int nextdescriptor;
+	int desc;
+	enter("xircom_start_xmit");
+	
+	card = (struct xircom_private*)dev->priv;
+	spin_lock_irqsave(&card->lock,flags);
+	
+	/* First see if we can free some descriptors */
+	for (desc=0;desc<NUMDESCRIPTORS;desc++) 
+		investigate_write_descriptor(dev,card,desc,bufferoffsets[desc]);
+	
+	
+	nextdescriptor = (card->transmit_used +1) % (NUMDESCRIPTORS);
+	desc = card->transmit_used;
+	
+	/* only send the packet if the descriptor is free */
+	if (card->tx_buffer[4*desc]==0) {
+			/* Copy the packet data; zero the memory first as the card
+			   sometimes sends more than you ask it to. */
+			
+			memset(&card->tx_buffer[bufferoffsets[desc]/4],0,1536);
+			memcpy(&(card->tx_buffer[bufferoffsets[desc]/4]),skb->data,skb->len);
+	
+	
+			/* FIXME: The specification tells us that the length we send HAS to be a multiple of
+			   4 bytes. */
+			   
+			card->tx_buffer[4*desc+1] = skb->len;
+			if (desc == NUMDESCRIPTORS-1)
+				card->tx_buffer[4*desc+1] |= (1<<25);  /* bit 25: last descriptor of the ring */
+
+			card->tx_buffer[4*desc+1] |= 0xF0000000;
+						 /* 0xF0... means want interrupts*/ 
+			card->tx_skb[desc] = skb;
+			
+			wmb();
+			/* This gives the descriptor to the card */
+			card->tx_buffer[4*desc] = 0x80000000;
+			trigger_transmit(card);
+			if (((int)card->tx_buffer[nextdescriptor*4])<0) {	/* next descriptor is occupied... */
+				netif_stop_queue(dev);
+			}
+			card->transmit_used = nextdescriptor;
+			leave("xircom-start_xmit - sent");	
+			spin_unlock_irqrestore(&card->lock,flags);
+			return 0;
+	}
+	
+
+
+	/* Uh oh... no free descriptor... drop the packet */
+	netif_stop_queue(dev);
+	spin_unlock_irqrestore(&card->lock,flags);
+	trigger_transmit(card);
+	
+	return -EIO;
+}
+
+
+
+
+static int xircom_open(struct net_device *dev)
+{
+	struct xircom_private *xp = (struct xircom_private *) dev->priv;
+	int retval;
+	enter("xircom_open");
+	printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
+	retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		leave("xircom_open - No IRQ");
+		return retval;
+	}
+	
+	xircom_up(xp);
+	xp->open = 1;
+	leave("xircom_open");
+	return 0;
+}
+
+static int xircom_close(struct net_device *dev)
+{
+	struct xircom_private *card;
+	unsigned long flags;
+	
+	enter("xircom_close");
+	card = dev->priv;
+	netif_stop_queue(dev); /* we don't want new packets */
+
+	
+	spin_lock_irqsave(&card->lock,flags);
+	
+	disable_all_interrupts(card);
+#if 0	
+	/* We can enable this again once we send dummy packets on ifconfig ethX up */
+	deactivate_receiver(card);
+	deactivate_transmitter(card);
+#endif	
+	remove_descriptors(card);
+	
+	spin_unlock_irqrestore(&card->lock,flags);
+	
+	card->open = 0;
+	free_irq(dev->irq,dev);
+	
+	leave("xircom_close");
+	
+	return 0;
+	
+}
+
+
+
+static struct net_device_stats *xircom_get_stats(struct net_device *dev)
+{
+        struct xircom_private *card = (struct xircom_private *)dev->priv;
+        return &card->stats;
+} 
+                                                 
+
+
+
+static void initialize_card(struct xircom_private *card)
+{
+	unsigned int val;
+	unsigned long flags;
+	enter("initialize_card");
+
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	/* First: reset the card */
+	val = inl(card->io_port + CSR0);
+	val |= 0x01;		/* Software reset */
+	outl(val, card->io_port + CSR0);
+
+	udelay(100);		/* give the card some time to reset */
+
+	val = inl(card->io_port + CSR0);
+	val &= ~0x01;		/* disable Software reset */
+	outl(val, card->io_port + CSR0);
+
+
+	val = 0;		/* Value 0x00 is a safe and conservative value 
+				   for the PCI configuration settings */
+	outl(val, card->io_port + CSR0);
+
+
+	disable_all_interrupts(card);
+	deactivate_receiver(card);
+	deactivate_transmitter(card);
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	leave("initialize_card");
+}
+
+/*
+trigger_transmit causes the card to check for frames to be transmitted.
+This is accomplished by writing to the CSR1 port. The documentation
+claims that the act of writing is sufficient and that the value is
+ignored; I chose zero.
+*/
+static void trigger_transmit(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("trigger_transmit");
+
+	val = 0;
+	outl(val, card->io_port + CSR1);
+
+	leave("trigger_transmit");
+}
+
+/*
+trigger_receive causes the card to check for empty frames in the
+descriptor list in which packets can be received.
+This is accomplished by writing to the CSR2 port. The documentation
+claims that the act of writing is sufficient and that the value is
+ignored; I chose zero.
+*/
+static void trigger_receive(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("trigger_receive");
+
+	val = 0;
+	outl(val, card->io_port + CSR2);
+
+	leave("trigger_receive");
+}
+
+/*
+setup_descriptors initializes the send and receive buffers to be valid
+descriptors and programs the addresses into the card.
+*/
+static void setup_descriptors(struct xircom_private *card)
+{
+	unsigned int val;
+	unsigned int address;
+	int i;
+	enter("setup_descriptors");
+
+
+	if (card->rx_buffer == NULL)
+		BUG();
+	if (card->tx_buffer == NULL)
+		BUG();
+
+	/* Receive descriptors */
+	memset(card->rx_buffer, 0, 128);	/* clear the descriptors */
+	for (i=0;i<NUMDESCRIPTORS;i++ ) {
+
+		/* Rx Descr0: It's empty, let the card own it, no errors -> 0x80000000 */
+		card->rx_buffer[i*4 + 0] = 0x80000000;
+		/* Rx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
+		card->rx_buffer[i*4 + 1] = 1536;
+		if (i==NUMDESCRIPTORS-1)
+			card->rx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
+
+		/* Rx Descr2: address of the buffer
+		   we store the buffer at the 2nd half of the page */
+	
+		address = (unsigned long) card->rx_dma_handle;
+		card->rx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
+		/* Rx Desc3: address of 2nd buffer -> 0 */
+		card->rx_buffer[i*4 + 3] = 0;
+	}
+	
+	wmb();
+	/* Write the receive descriptor ring address to the card */
+	address = (unsigned long) card->rx_dma_handle;
+	val = cpu_to_le32(address); 
+	outl(val, card->io_port + CSR3);	/* Receive descr list address */
+
+
+	/* transmit descriptors */
+	memset(card->tx_buffer, 0, 128);	/* clear the descriptors */
+	
+	for (i=0;i<NUMDESCRIPTORS;i++ ) {
+		/* Tx Descr0: Empty, we own it, no errors -> 0x00000000 */
+		card->tx_buffer[i*4 + 0] = 0x00000000;
+		/* Tx Descr1: buffer 1 is 1536 bytes, buffer 2 is 0 bytes */
+		card->tx_buffer[i*4 + 1] = 1536;
+		if (i==NUMDESCRIPTORS-1)
+			card->tx_buffer[i*4 + 1] |= (1 << 25); /* bit 25 is "last descriptor" */
+		
+		/* Tx Descr2: address of the buffer
+		   we store the buffer at the 2nd half of the page */
+		address = (unsigned long) card->tx_dma_handle;
+		card->tx_buffer[i*4 + 2] = cpu_to_le32(address + bufferoffsets[i]);
+		/* Tx Desc3: address of 2nd buffer -> 0 */
+		card->tx_buffer[i*4 + 3] = 0;
+	}
+
+	wmb();
+	/* wite the transmit descriptor ring to the card */
+	address = (unsigned long) card->tx_dma_handle;
+	val =cpu_to_le32(address);
+	outl(val, card->io_port + CSR4);	/* xmit descr list address */
+
+	leave("setup_descriptors");
+}
+
+/*
+remove_descriptors informs the card the descriptors are no longer
+valid by setting the address in the card to 0x00.
+*/
+static void remove_descriptors(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("remove_descriptors");
+
+	val = 0;
+	outl(val, card->io_port + CSR3);	/* Receive descriptor address */
+	outl(val, card->io_port + CSR4);	/* Send descriptor address */
+
+	leave("remove_descriptors");
+}
+
+/*
+link_status_changed returns 1 if the card has indicated that
+the link status has changed. The new link status has to be read from CSR12.
+
+This function also clears the status-bit.
+*/
+static int link_status_changed(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("link_status_changed");
+
+	val = inl(card->io_port + CSR5);	/* Status register */
+
+	if ((val & (1 << 27)) == 0) {	/* no change */
+		leave("link_status_changed - nochange");
+		return 0;
+	}
+
+	/* clear the event by writing a 1 to the bit in the
+	   status register. */
+	val = (1 << 27);
+	outl(val, card->io_port + CSR5);
+
+	leave("link_status_changed - changed");
+	return 1;
+}
+
+
+/*
+transmit_active returns 1 if the transmitter on the card is
+in a non-stopped state.
+*/
+static int transmit_active(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("transmit_active");
+
+	val = inl(card->io_port + CSR5);	/* Status register */
+
+	if ((val & (7 << 20)) == 0) {	/* transmitter disabled */
+		leave("transmit_active - inactive");
+		return 0;
+	}
+
+	leave("transmit_active - active");
+	return 1;
+}
+
+/*
+receive_active returns 1 if the receiver on the card is
+in a non-stopped state.
+*/
+static int receive_active(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("receive_active");
+
+
+	val = inl(card->io_port + CSR5);	/* Status register */
+
+	if ((val & (7 << 17)) == 0) {	/* receiver disabled */
+		leave("receive_active - inactive");
+		return 0;
+	}
+
+	leave("receive_active - active");
+	return 1;
+}
+
+/*
+activate_receiver enables the receiver on the card.
+Before being allowed to active the receiver, the receiver
+must be completely de-activated. To achieve this,
+this code actually disables the receiver first; then it waits for the 
+receiver to become inactive, then it activates the receiver and then
+it waits for the receiver to be active.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void activate_receiver(struct xircom_private *card)
+{
+	unsigned int val;
+	int counter;
+	enter("activate_receiver");
+
+
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+	
+	/* If the "active" bit is set and the receiver is already
+	   active, no need to do the expensive thing */
+	if ((val&2) && (receive_active(card)))
+		return;
+	
+	
+	val = val & ~2;		/* disable the receiver */
+	outl(val, card->io_port + CSR6);
+
+	counter = 10;
+	while (counter > 0) {
+		if (!receive_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+	}
+
+	/* enable the receiver */
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+	val = val | 2;				/* enable the receiver */
+	outl(val, card->io_port + CSR6);
+
+	/* now wait for the card to activate again */
+	counter = 10;
+	while (counter > 0) {
+		if (receive_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Receiver failed to re-activate\n");
+	}
+
+	leave("activate_receiver");
+}
+
+/*
+deactivate_receiver disables the receiver on the card.
+To achieve this this code disables the receiver first; 
+then it waits for the receiver to become inactive.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void deactivate_receiver(struct xircom_private *card)
+{
+	unsigned int val;
+	int counter;
+	enter("deactivate_receiver");
+
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+	val = val & ~2;				/* disable the receiver */
+	outl(val, card->io_port + CSR6);
+
+	counter = 10;
+	while (counter > 0) {
+		if (!receive_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Receiver failed to deactivate\n");
+	}
+
+
+	leave("deactivate_receiver");
+}
+
+
+/*
+activate_transmitter enables the transmitter on the card.
+Before being allowed to active the transmitter, the transmitter
+must be completely de-activated. To achieve this,
+this code actually disables the transmitter first; then it waits for the 
+transmitter to become inactive, then it activates the transmitter and then
+it waits for the transmitter to be active again.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void activate_transmitter(struct xircom_private *card)
+{
+	unsigned int val;
+	int counter;
+	enter("activate_transmitter");
+
+
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+
+	/* If the "active" bit is set and the receiver is already
+	   active, no need to do the expensive thing */	 
+	if ((val&(1<<13)) && (transmit_active(card)))
+		return;
+
+	val = val & ~(1 << 13);	/* disable the transmitter */
+	outl(val, card->io_port + CSR6);
+
+	counter = 10;
+	while (counter > 0) {
+		if (!transmit_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+	}
+
+	/* enable the transmitter */
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+	val = val | (1 << 13);	/* enable the transmitter */
+	outl(val, card->io_port + CSR6);
+
+	/* now wait for the card to activate again */
+	counter = 10;
+	while (counter > 0) {
+		if (transmit_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Transmitter failed to re-activate\n");
+	}
+
+	leave("activate_transmitter");
+}
+
+/*
+deactivate_transmitter disables the transmitter on the card.
+To achieve this this code disables the transmitter first; 
+then it waits for the transmitter to become inactive.
+
+must be called with the lock held and interrupts disabled.
+*/
+static void deactivate_transmitter(struct xircom_private *card)
+{
+	unsigned int val;
+	int counter;
+	enter("deactivate_transmitter");
+
+	val = inl(card->io_port + CSR6);	/* Operation mode */
+	val = val & ~2;		/* disable the transmitter */
+	outl(val, card->io_port + CSR6);
+
+	counter = 20;
+	while (counter > 0) {
+		if (!transmit_active(card))
+			break;
+		/* wait a while */
+		udelay(50);
+		counter--;
+		if (counter <= 0)
+			printk(KERN_ERR "xircom_cb: Transmitter failed to deactivate\n");
+	}
+
+
+	leave("deactivate_transmitter");
+}
+
+
+/*
+enable_transmit_interrupt enables the transmit interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_transmit_interrupt(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_transmit_interrupt");
+
+	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
+	val |= 1;				/* enable the transmit interrupt */
+	outl(val, card->io_port + CSR7);
+
+	leave("enable_transmit_interrupt");
+}
+
+
+/*
+enable_receive_interrupt enables the receive interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_receive_interrupt(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_receive_interrupt");
+
+	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
+	val = val | (1 << 6);			/* enable the receive interrupt */
+	outl(val, card->io_port + CSR7);
+
+	leave("enable_receive_interrupt");
+}
+
+/*
+enable_link_interrupt enables the link status change interrupt
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_link_interrupt(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_link_interrupt");
+
+	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
+	val = val | (1 << 27);			/* enable the link status chage interrupt */
+	outl(val, card->io_port + CSR7);
+
+	leave("enable_link_interrupt");
+}
+
+
+
+/*
+disable_all_interrupts disables all interrupts
+
+must be called with the lock held and interrupts disabled.
+*/
+static void disable_all_interrupts(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_all_interrupts");
+	
+	val = 0;				/* disable all interrupts */
+	outl(val, card->io_port + CSR7);
+
+	leave("disable_all_interrupts");
+}
+
+/*
+enable_common_interrupts enables several weird interrupts
+
+must be called with the lock held and interrupts disabled.
+*/
+static void enable_common_interrupts(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_link_interrupt");
+
+	val = inl(card->io_port + CSR7);	/* Interrupt enable register */
+	val |= (1<<16); /* Normal Interrupt Summary */
+	val |= (1<<15); /* Abnormal Interrupt Summary */
+	val |= (1<<13); /* Fatal bus error */
+	val |= (1<<8);  /* Receive Process Stopped */
+	val |= (1<<7);  /* Receive Buffer Unavailable */
+	val |= (1<<5);  /* Transmit Underflow */
+	val |= (1<<2);  /* Transmit Buffer Unavailable */
+	val |= (1<<1);  /* Transmit Process Stopped */
+	outl(val, card->io_port + CSR7);
+
+	leave("enable_link_interrupt");
+}
+
+/*
+enable_promisc starts promisc mode
+
+must be called with the lock held and interrupts disabled.
+*/
+static int enable_promisc(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("enable_promisc");
+
+	val = inl(card->io_port + CSR6);	
+	val = val | (1 << 6);	
+	outl(val, card->io_port + CSR6);
+
+	leave("enable_promisc");
+	return 1;
+}
+
+
+
+
+/* 
+link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+
+Must be called in locked state with interrupts disabled
+*/
+static int link_status(struct xircom_private *card)
+{
+	unsigned int val;
+	enter("link_status");
+	
+	val = inb(card->io_port + CSR12);
+	
+	if (!(val&(1<<2)))  /* bit 2 is 0 for 10mbit link, 1 for not an 10mbit link */
+		return 10;
+	if (!(val&(1<<1)))  /* bit 1 is 0 for 100mbit link, 1 for not an 100mbit link */
+		return 100;
+		
+	/* If we get here -> no link at all */	
+
+	leave("link_status");
+	return 0;
+}
+
+
+
+
+
+/*
+  read_mac_address() reads the MAC address from the NIC and stores it in the "dev" structure.
+ 
+  This function will take the spinlock itself and can, as a result, not be called with the lock helt.
+ */
+static void read_mac_address(struct xircom_private *card)
+{
+	unsigned char j, tuple, link, data_id, data_count;
+	unsigned long flags;
+	int i;
+
+	enter("read_mac_address");
+		
+	spin_lock_irqsave(&card->lock, flags);
+
+	outl(1 << 12, card->io_port + CSR9);	/* enable boot rom access */
+	for (i = 0x100; i < 0x1f7; i += link + 2) {
+		outl(i, card->io_port + CSR10);
+		tuple = inl(card->io_port + CSR9) & 0xff;
+		outl(i + 1, card->io_port + CSR10);
+		link = inl(card->io_port + CSR9) & 0xff;
+		outl(i + 2, card->io_port + CSR10);
+		data_id = inl(card->io_port + CSR9) & 0xff;
+		outl(i + 3, card->io_port + CSR10);
+		data_count = inl(card->io_port + CSR9) & 0xff;
+		if ((tuple == 0x22) && (data_id == 0x04) && (data_count == 0x06)) {
+			/* 
+			 * This is it.  We have the data we want.
+			 */
+			for (j = 0; j < 6; j++) {
+				outl(i + j + 4, card->io_port + CSR10);
+				card->dev->dev_addr[j] = inl(card->io_port + CSR9) & 0xff;
+			}
+			break;
+		} else if (link == 0) {
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&card->lock, flags);
+#ifdef DEBUG
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
+	printk("\n");
+#endif
+	leave("read_mac_address");
+}
+
+
+/*
+ tranceiver_voodoo() enables the external UTP plug thingy.
+ it's called voodoo as I stole this code and cannot cross-reference
+ it with the specification.
+ */
+static void tranceiver_voodoo(struct xircom_private *card)
+{
+	unsigned long flags;
+
+	enter("tranceiver_voodoo");
+
+	/* disable all powermanagement */
+	pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
+
+	setup_descriptors(card);
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	outl(0x0008, card->io_port + CSR15);
+        udelay(25);  
+        outl(0xa8050000, card->io_port + CSR15);
+        udelay(25);
+        outl(0xa00f0000, card->io_port + CSR15);
+        udelay(25);
+        
+        spin_unlock_irqrestore(&card->lock, flags);
+
+	netif_start_queue(card->dev);
+	leave("tranceiver_voodoo");
+}
+
+
+static void xircom_up(struct xircom_private *card)
+{
+	unsigned long flags;
+	int i;
+
+	enter("xircom_up");
+
+	/* disable all powermanagement */
+	pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
+
+	setup_descriptors(card);
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	
+	enable_link_interrupt(card);
+	enable_transmit_interrupt(card);
+	enable_receive_interrupt(card);
+	enable_common_interrupts(card);
+	enable_promisc(card);
+	
+	/* The card can have received packets already, read them away now */
+	for (i=0;i<NUMDESCRIPTORS;i++) 
+		investigate_read_descriptor(card->dev,card,i,bufferoffsets[i]);
+
+
+	spin_unlock_irqrestore(&card->lock, flags);
+	trigger_receive(card);
+	trigger_transmit(card);
+	netif_start_queue(card->dev);
+	leave("xircom_up");
+}
+
+/* Bufferoffset is in BYTES */
+static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
+{
+		int status;		
+		
+		enter("investigate_read_descriptor");
+		status = card->rx_buffer[4*descnr];
+		
+		if ((status > 0)) {	/* packet received */
+		
+			/* TODO: discard error packets */
+			
+			short pkt_len = ((status >> 16) & 0x7ff) - 4;	/* minus 4, we don't want the CRC */
+			struct sk_buff *skb;
+
+			if (pkt_len > 1518) {
+				printk(KERN_ERR "xircom_cb: Packet length %i is bogus \n",pkt_len);
+				pkt_len = 1518;
+			}
+
+			skb = dev_alloc_skb(pkt_len + 2);
+			if (skb == NULL) {
+				card->stats.rx_dropped++;
+				goto out;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);
+			eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0);
+			skb_put(skb, pkt_len);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			card->stats.rx_packets++;
+			card->stats.rx_bytes += pkt_len;
+			
+		      out:
+			/* give the buffer back to the card */
+			card->rx_buffer[4*descnr] =  0x80000000;
+			trigger_receive(card);
+		}
+
+		leave("investigate_read_descriptor");
+
+}
+
+
+/* Bufferoffset is in BYTES */
+static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset)
+{
+		int status;
+
+		enter("investigate_write_descriptor");
+		
+		status = card->tx_buffer[4*descnr];
+#if 0		
+		if (status & 0x8000) {	/* Major error */
+			printk(KERN_ERR "Major transmit error status %x \n", status);
+			card->tx_buffer[4*descnr] = 0;
+			netif_wake_queue (dev);
+		}
+#endif
+		if (status > 0) {	/* bit 31 is 0 when done */
+			if (card->tx_skb[descnr]!=NULL) {
+				card->stats.tx_bytes += card->tx_skb[descnr]->len;
+				dev_kfree_skb_irq(card->tx_skb[descnr]);
+			}
+			card->tx_skb[descnr] = NULL;
+			/* Bit 8 in the status field is 1 if there was a collision */
+			if (status&(1<<8))
+				card->stats.collisions++;
+			card->tx_buffer[4*descnr] = 0; /* descriptor is free again */
+			netif_wake_queue (dev);
+			card->stats.tx_packets++;
+		}
+
+		leave("investigate_write_descriptor");
+		
+}
+
+
+static int __init xircom_init(void)
+{
+	pci_register_driver(&xircom_ops);
+	return 0;
+}
+
+static void __exit xircom_exit(void)
+{
+	pci_unregister_driver(&xircom_ops);
+} 
+
+module_init(xircom_init) 
+module_exit(xircom_exit)
+
diff -urN linux-2.5.6-pre3/drivers/net/tulip/xircom_tulip_cb.c linux-2.5.6/drivers/net/tulip/xircom_tulip_cb.c
--- linux-2.5.6-pre3/drivers/net/tulip/xircom_tulip_cb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/tulip/xircom_tulip_cb.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,1744 @@
+/* xircom_tulip_cb.c: A Xircom CBE-100 ethernet driver for Linux. */
+/*
+	Written/copyright 1994-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU General Public License, incorporated herein by reference.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+	-----------------------------------------------------------
+
+	Linux kernel-specific changes:
+
+	LK1.0 (Ion Badulescu)
+	- Major cleanup
+	- Use 2.4 PCI API
+	- Support ethtool
+	- Rewrite perfect filter/hash code
+	- Use interrupts for media changes
+
+	LK1.1 (Ion Badulescu)
+	- Disallow negotiation of unsupported full-duplex modes
+*/
+
+#define DRV_NAME	"xircom_tulip_cb"
+#define DRV_VERSION	"0.91+LK1.1"
+#define DRV_RELDATE	"October 11, 2001"
+
+#define CARDBUS 1
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 4
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS];
+static int options[MAX_UNITS];
+static int mtu[MAX_UNITS];			/* Jumbo MTU for interfaces. */
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+  Set the bus performance register.
+	Typical: Set 16 longword cache alignment, no burst limit.
+	Cache alignment bits 15:14	     Burst length 13:8
+		0000	No alignment  0x00000000 unlimited		0800 8 longwords
+		4000	8  longwords		0100 1 longword		1000 16 longwords
+		8000	16 longwords		0200 2 longwords	2000 32 longwords
+		C000	32  longwords		0400 4 longwords
+	Warning: many older 486 systems are broken and require setting 0x00A04800
+	   8 longword cache alignment, 8 longword burst.
+	ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__powerpc__)
+static int csr0 = 0x01B00000 | 0x8000;
+#elif defined(__sparc__)
+static int csr0 = 0x01B00080 | 0x8000;
+#elif defined(__i386__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT		(4 * HZ)
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+#define PKT_SETUP_SZ		192			/* Size of the setup frame */
+
+/* PCI registers */
+#define PCI_POWERMGMT 	0x40
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/uaccess.h>
+
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME ".c derived from tulip.c:v0.91 4/14/99 becker@scyld.com\n"
+KERN_INFO " unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE "\n";
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Xircom CBE-100 ethernet driver");
+MODULE_LICENSE("GPL v2");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+#define RUN_AT(x) (jiffies + (x))
+
+#define xircom_debug debug
+#ifdef XIRCOM_DEBUG
+static int xircom_debug = XIRCOM_DEBUG;
+#else
+static int xircom_debug = 1;
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver was forked from the driver for the DECchip "Tulip",
+Digital's single-chip ethernet controllers for PCI.  It supports Xircom's
+almost-Tulip-compatible CBE-100 CardBus adapters.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Xircom can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Xircom as receive data buffers.  When an incoming frame is less than
+RX_COPYBREAK bytes long, 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 and replaced by a newly allocated
+skbuff.
+
+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
+frames.  For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information).  For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.  A subtle aspect of this
+choice is that the Xircom only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)	 After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840A.html
+
+IVc. Errata
+
+*/
+
+/* A full-duplex map for media types. */
+enum MediaIs {
+	MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+	MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
+
+/* Offsets to the Command and Status Registers, "CSRs".  All accesses
+   must be longword instructions and quadword aligned. */
+enum xircom_offsets {
+	CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+	CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+	CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x04, };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+	LinkChange=0x08000000,
+	NormalIntr=0x10000, NormalIntrMask=0x00014045,
+	AbnormalIntr=0x8000, AbnormalIntrMask=0x0a00a5a2,
+	ReservedIntrMask=0xe0001a18,
+	EarlyRxIntr=0x4000, BusErrorIntr=0x2000,
+	EarlyTxIntr=0x400, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+	TxFIFOUnderflow=0x20, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+enum csr0_control_bits {
+	EnableMWI=0x01000000, EnableMRL=0x00800000,
+	EnableMRM=0x00200000, EqualBusPrio=0x02,
+	SoftwareReset=0x01,
+};
+
+enum csr6_control_bits {
+	ReceiveAllBit=0x40000000, AllMultiBit=0x80, PromiscBit=0x40,
+	HashFilterBit=0x01, FullDuplexBit=0x0200,
+	TxThresh10=0x400000, TxStoreForw=0x200000,
+	TxThreshMask=0xc000, TxThreshShift=14,
+	EnableTx=0x2000, EnableRx=0x02,
+	ReservedZeroMask=0x8d930134, ReservedOneMask=0x320c0000,
+	EnableTxRx=(EnableTx | EnableRx),
+};
+
+
+enum tbl_flag {
+	HAS_MII=1, HAS_ACPI=2,
+};
+static struct xircom_chip_table {
+	char *chip_name;
+	int valid_intrs;			/* CSR7 interrupt enable settings */
+	int flags;
+} xircom_tbl[] = {
+  { "Xircom Cardbus Adapter",
+	LinkChange | NormalIntr | AbnormalIntr | BusErrorIntr |
+	RxDied | RxNoBuf | RxIntr | TxFIFOUnderflow | TxNoBuf | TxDied | TxIntr,
+	HAS_MII | HAS_ACPI, },
+  { NULL, },
+};
+/* This matches the table above. */
+enum chips {
+	X3201_3,
+};
+
+
+/* The Xircom Rx and Tx buffer descriptors. */
+struct xircom_rx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;
+};
+
+struct xircom_tx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;				/* We use only buffer 1.  */
+};
+
+enum tx_desc0_status_bits {
+	Tx0DescOwned=0x80000000, Tx0DescError=0x8000, Tx0NoCarrier=0x0800,
+	Tx0LateColl=0x0200, Tx0ManyColl=0x0100, Tx0Underflow=0x02,
+};
+enum tx_desc1_status_bits {
+	Tx1ComplIntr=0x80000000, Tx1LastSeg=0x40000000, Tx1FirstSeg=0x20000000,
+	Tx1SetupPkt=0x08000000, Tx1DisableCRC=0x04000000, Tx1RingWrap=0x02000000,
+	Tx1ChainDesc=0x01000000, Tx1NoPad=0x800000, Tx1HashSetup=0x400000,
+	Tx1WholePkt=(Tx1FirstSeg | Tx1LastSeg),
+};
+enum rx_desc0_status_bits {
+	Rx0DescOwned=0x80000000, Rx0DescError=0x8000, Rx0NoSpace=0x4000,
+	Rx0Runt=0x0800, Rx0McastPkt=0x0400, Rx0FirstSeg=0x0200, Rx0LastSeg=0x0100,
+	Rx0HugeFrame=0x80, Rx0CRCError=0x02,
+	Rx0WholePkt=(Rx0FirstSeg | Rx0LastSeg),
+};
+enum rx_desc1_status_bits {
+	Rx1RingWrap=0x02000000, Rx1ChainDesc=0x01000000,
+};
+
+struct xircom_private {
+	struct xircom_rx_desc rx_ring[RX_RING_SIZE];
+	struct xircom_tx_desc tx_ring[TX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+#ifdef CARDBUS
+	/* The X3201-3 requires 4-byte aligned tx bufs */
+	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
+#endif
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)];	/* Pseudo-Tx frame to init address table. */
+	int chip_id;
+	struct net_device_stats stats;
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int speed100:1;
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int autoneg:1;
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int open:1;
+	unsigned int csr0;					/* CSR0 setting. */
+	unsigned int csr6;					/* Current CSR6 control settings. */
+	u16 to_advertise;					/* NWay capabilities advertised.  */
+	u16 advertising[4];
+	signed char phys[4], mii_cnt;		/* MII device addresses. */
+	int saved_if_port;
+	struct pci_dev *pdev;
+	spinlock_t lock;
+};
+
+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 void xircom_up(struct net_device *dev);
+static void xircom_down(struct net_device *dev);
+static int xircom_open(struct net_device *dev);
+static void xircom_tx_timeout(struct net_device *dev);
+static void xircom_init_ring(struct net_device *dev);
+static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int xircom_rx(struct net_device *dev);
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int xircom_close(struct net_device *dev);
+static struct net_device_stats *xircom_get_stats(struct net_device *dev);
+static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void set_rx_mode(struct net_device *dev);
+static void check_duplex(struct net_device *dev);
+
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+   manipulated.  Keith Owens <kaos@ocs.com.au>. */
+static void outl_CSR6(u32 newcsr6, long ioaddr)
+{
+	const int strict_bits =
+		TxThresh10 | TxStoreForw | TxThreshMask | EnableTxRx | FullDuplexBit;
+    int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+    long flags;
+    save_flags(flags);
+    cli();
+	/* mask out the reserved bits that always read 0 on the Xircom cards */
+	newcsr6 &= ~ReservedZeroMask;
+	/* or in the reserved bits that always read 1 */
+	newcsr6 |= ReservedOneMask;
+    currcsr6 = inl(ioaddr + CSR6);
+    if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+	((currcsr6 & ~EnableTxRx) == 0)) {
+		outl(newcsr6, ioaddr + CSR6);	/* safe */
+		restore_flags(flags);
+		return;
+    }
+    /* make sure the transmitter and receiver are stopped first */
+    currcsr6 &= ~EnableTxRx;
+    while (1) {
+		csr5 = inl(ioaddr + CSR5);
+		if (csr5 == 0xffffffff)
+			break;  /* cannot read csr5, card removed? */
+		csr5_22_20 = csr5 & 0x700000;
+		csr5_19_17 = csr5 & 0x0e0000;
+		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+			(csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+			break;  /* both are stopped or suspended */
+		if (!--attempts) {
+			printk(KERN_INFO DRV_NAME ": outl_CSR6 too many attempts,"
+				   "csr5=0x%08x\n", csr5);
+			outl(newcsr6, ioaddr + CSR6);  /* unsafe but do it anyway */
+			restore_flags(flags);
+			return;
+		}
+		outl(currcsr6, ioaddr + CSR6);
+		udelay(1);
+    }
+    /* now it is safe to change csr6 */
+    outl(newcsr6, ioaddr + CSR6);
+    restore_flags(flags);
+}
+
+
+static void __devinit read_mac_address(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	int i, j;
+	unsigned char tuple, link, data_id, data_count;
+
+	/* Xircom has its address stored in the CIS;
+	 * we access it through the boot rom interface for now
+	 * this might not work, as the CIS is not parsed but I
+	 * (danilo) use the offset I found on my card's CIS !!!
+	 *
+	 * Doug Ledford: I changed this routine around so that it
+	 * walks the CIS memory space, parsing the config items, and
+	 * finds the proper lan_node_id tuple and uses the data
+	 * stored there.
+	 */
+	outl(1 << 12, ioaddr + CSR9); /* enable boot rom access */
+	for (i = 0x100; i < 0x1f7; i += link+2) {
+		outl(i, ioaddr + CSR10);
+		tuple = inl(ioaddr + CSR9) & 0xff;
+		outl(i + 1, ioaddr + CSR10);
+		link = inl(ioaddr + CSR9) & 0xff;
+		outl(i + 2, ioaddr + CSR10);
+		data_id = inl(ioaddr + CSR9) & 0xff;
+		outl(i + 3, ioaddr + CSR10);
+		data_count = inl(ioaddr + CSR9) & 0xff;
+		if ( (tuple == 0x22) &&
+			 (data_id == 0x04) && (data_count == 0x06) ) {
+			/*
+			 * This is it.  We have the data we want.
+			 */
+			for (j = 0; j < 6; j++) {
+				outl(i + j + 4, ioaddr + CSR10);
+				dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;
+			}
+			break;
+		} else if (link == 0) {
+			break;
+		}
+	}
+}
+
+
+/*
+ * locate the MII interfaces and initialize them.
+ * we disable full-duplex modes here,
+ * because we don't know how to handle them.
+ */
+static void find_mii_transceivers(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	int phy, phy_idx;
+
+	if (media_cap[tp->default_port] & MediaIsMII) {
+		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+		tp->to_advertise = media2advert[tp->default_port - 9];
+	} else
+		tp->to_advertise =
+			/*ADVERTISE_100BASE4 | ADVERTISE_100FULL |*/ ADVERTISE_100HALF |
+			/*ADVERTISE_10FULL |*/ ADVERTISE_10HALF | ADVERTISE_CSMA;
+
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later,
+	   but takes much time. */
+	for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+		int mii_status = mdio_read(dev, phy, MII_BMSR);
+		if ((mii_status & (BMSR_100BASE4 | BMSR_100HALF | BMSR_10HALF)) == BMSR_100BASE4 ||
+			((mii_status & BMSR_100BASE4) == 0 &&
+			 (mii_status & (BMSR_100FULL | BMSR_100HALF | BMSR_10FULL | BMSR_10HALF)) != 0)) {
+			int mii_reg0 = mdio_read(dev, phy, MII_BMCR);
+			int mii_advert = mdio_read(dev, phy, MII_ADVERTISE);
+			int reg4 = ((mii_status >> 6) & tp->to_advertise) | ADVERTISE_CSMA;
+			tp->phys[phy_idx] = phy;
+			tp->advertising[phy_idx++] = reg4;
+			printk(KERN_INFO "%s:  MII transceiver #%d "
+				   "config %4.4x status %4.4x advertising %4.4x.\n",
+				   dev->name, phy, mii_reg0, mii_status, mii_advert);
+		}
+	}
+	tp->mii_cnt = phy_idx;
+	if (phy_idx == 0) {
+		printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+			   dev->name);
+		tp->phys[0] = 0;
+	}
+}
+
+
+/*
+ * To quote Arjan van de Ven:
+ *   tranceiver_voodoo() enables the external UTP plug thingy.
+ *   it's called voodoo as I stole this code and cannot cross-reference
+ *   it with the specification.
+ * Actually it seems to go like this:
+ * - GPIO2 enables the MII itself so we can talk to it. The MII gets reset
+ *   so any prior MII settings are lost.
+ * - GPIO0 enables the TP port so the MII can talk to the network.
+ * - a software reset will reset both GPIO pins.
+ * I also moved the software reset here, because doing it in xircom_up()
+ * required enabling the GPIO pins each time, which reset the MII each time.
+ * Thus we couldn't control the MII -- which sucks because we don't know
+ * how to handle full-duplex modes so we *must* disable them.
+ */
+static void transceiver_voodoo(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+	outl(SoftwareReset, ioaddr + CSR0);
+	udelay(2);
+
+	/* Deassert reset. */
+	outl(tp->csr0, ioaddr + CSR0);
+
+	/* Reset the xcvr interface and turn on heartbeat. */
+	outl(0x0008, ioaddr + CSR15);
+	udelay(5);  /* The delays are Xircom-recommended to give the
+				 * chipset time to reset the actual hardware
+				 * on the PCMCIA card
+				 */
+	outl(0xa8050000, ioaddr + CSR15);
+	udelay(5);
+	outl(0xa00f0000, ioaddr + CSR15);
+	udelay(5);
+
+	outl_CSR6(0, ioaddr);
+	//outl_CSR6(FullDuplexBit, ioaddr);
+}
+
+
+static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net_device *dev;
+	struct xircom_private *tp;
+	static int board_idx = -1;
+	int chip_idx = id->driver_data;
+	long ioaddr;
+	int i;
+	u8 chip_rev;
+
+/* when built into the kernel, we only print version if device is found */
+#ifndef MODULE
+	static int printed_version;
+	if (!printed_version++)
+		printk(version);
+#endif
+
+	//printk(KERN_INFO "xircom_init_one(%s)\n", pdev->slot_name);
+
+	board_idx++;
+
+	if (pci_enable_device(pdev))
+		return -ENODEV;
+
+	pci_set_master(pdev);
+
+	ioaddr = pci_resource_start(pdev, 0);
+	dev = alloc_etherdev(sizeof(*tp));
+	if (!dev) {
+		printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+
+	dev->base_addr = ioaddr;
+	dev->irq = pdev->irq;
+
+	if (pci_request_regions(pdev, dev->name)) {
+		printk (KERN_ERR DRV_NAME " %d: cannot reserve PCI resources, aborting\n", board_idx);
+		goto err_out_free_netdev;
+	}
+
+	/* Bring the chip out of sleep mode.
+	   Caution: Snooze mode does not work with some boards! */
+	if (xircom_tbl[chip_idx].flags & HAS_ACPI)
+		pci_write_config_dword(pdev, PCI_POWERMGMT, 0);
+
+	/* Stop the chip's Tx and Rx processes. */
+	outl_CSR6(inl(ioaddr + CSR6) & ~EnableTxRx, ioaddr);
+	/* Clear the missed-packet counter. */
+	(volatile int)inl(ioaddr + CSR8);
+
+	tp = dev->priv;
+
+	tp->lock = SPIN_LOCK_UNLOCKED;
+	tp->pdev = pdev;
+	tp->chip_id = chip_idx;
+	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. */
+	/* XXX: is this necessary for Xircom? */
+	tp->csr0 = csr0 & ~EnableMWI;
+
+	pci_set_drvdata(pdev, dev);
+
+	/* The lower four bits are the media type. */
+	if (board_idx >= 0 && board_idx < MAX_UNITS) {
+		tp->default_port = options[board_idx] & 15;
+		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+			tp->full_duplex = 1;
+		if (mtu[board_idx] > 0)
+			dev->mtu = mtu[board_idx];
+	}
+	if (dev->mem_start)
+		tp->default_port = dev->mem_start;
+	if (tp->default_port) {
+		if (media_cap[tp->default_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
+	}
+	if (tp->full_duplex)
+		tp->autoneg = 0;
+	else
+		tp->autoneg = 1;
+	tp->speed100 = 1;
+
+	/* The Xircom-specific entries in the device structure. */
+	dev->open = &xircom_open;
+	dev->hard_start_xmit = &xircom_start_xmit;
+	dev->stop = &xircom_close;
+	dev->get_stats = &xircom_get_stats;
+	dev->do_ioctl = &xircom_ioctl;
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_rx_mode;
+#endif
+	dev->tx_timeout = xircom_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+
+	transceiver_voodoo(dev);
+
+	read_mac_address(dev);
+
+	if (register_netdev(dev))
+		goto err_out_cleardev;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
+	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+	       dev->name, xircom_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(", IRQ %d.\n", dev->irq);
+
+	if (xircom_tbl[chip_idx].flags & HAS_MII) {
+		find_mii_transceivers(dev);
+		check_duplex(dev);
+	}
+
+	return 0;
+
+err_out_cleardev:
+	pci_set_drvdata(pdev, NULL);
+	pci_release_regions(pdev);
+err_out_free_netdev:
+	unregister_netdev(dev);
+	kfree(dev);
+	return -ENODEV;
+}
+
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK	0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN		0x40000
+#define MDIO_DATA_READ	0x80000
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	int i;
+	int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
+
+	/* Establish sync by sending 32 logic ones. */
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+
+
+static void
+xircom_up(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	/* Clear the tx ring */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0;
+	}
+
+	if (xircom_debug > 1)
+		printk(KERN_DEBUG "%s: xircom_up() irq %d.\n", dev->name, dev->irq);
+
+	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+	tp->saved_if_port = dev->if_port;
+	if (dev->if_port == 0)
+		dev->if_port = tp->default_port;
+
+	tp->csr6 = TxThresh10 /*| FullDuplexBit*/;						/* XXX: why 10 and not 100? */
+
+	set_rx_mode(dev);
+
+	/* Start the chip's Tx to process setup frame. */
+	outl_CSR6(tp->csr6, ioaddr);
+	outl_CSR6(tp->csr6 | EnableTx, ioaddr);
+
+	/* Acknowledge all outstanding interrupts sources */
+	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+	/* Enable interrupts by setting the interrupt mask. */
+	outl(xircom_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+	/* Enable Rx */
+	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
+	/* Rx poll demand */
+	outl(0, ioaddr + CSR2);
+
+	/* Tell the net layer we're ready */
+	netif_start_queue (dev);
+
+	if (xircom_debug > 2) {
+		printk(KERN_DEBUG "%s: Done xircom_up(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+			   inl(ioaddr + CSR6));
+	}
+}
+
+
+static int
+xircom_open(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+
+	if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+
+	xircom_init_ring(dev);
+
+	xircom_up(dev);
+	tp->open = 1;
+
+	return 0;
+}
+
+
+static void xircom_tx_timeout(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		/* Do nothing -- the media monitor should handle this. */
+		if (xircom_debug > 1)
+			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+				   dev->name);
+	}
+
+#if defined(way_too_many_messages)
+	if (xircom_debug > 3) {
+		int i;
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+			int j;
+			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "
+				   "%2.2x %2.2x %2.2x.\n",
+				   i, (unsigned int)tp->rx_ring[i].status,
+				   (unsigned int)tp->rx_ring[i].length,
+				   (unsigned int)tp->rx_ring[i].buffer1,
+				   (unsigned int)tp->rx_ring[i].buffer2,
+				   buf[0], buf[1], buf[2]);
+			for (j = 0; buf[j] != 0xee && j < 1600; j++)
+				if (j < 100) printk(" %2.2x", buf[j]);
+			printk(" j=%d.\n", j);
+		}
+		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+		printk("\n");
+	}
+#endif
+
+	/* Stop and restart the chip's Tx/Rx processes . */
+	outl_CSR6(tp->csr6 | EnableRx, ioaddr);
+	outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
+	/* Trigger an immediate transmit demand. */
+	outl(0, ioaddr + CSR1);
+
+	dev->trans_start = jiffies;
+	netif_wake_queue (dev);
+	tp->stats.tx_errors++;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void xircom_init_ring(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	int i;
+
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		tp->rx_ring[i].status = 0;
+		tp->rx_ring[i].length = PKT_BUF_SZ;
+		tp->rx_ring[i].buffer2 = virt_to_bus(&tp->rx_ring[i+1]);
+		tp->rx_skbuff[i] = NULL;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	tp->rx_ring[i-1].length = PKT_BUF_SZ | Rx1RingWrap;
+	tp->rx_ring[i-1].buffer2 = virt_to_bus(&tp->rx_ring[0]);
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		/* Note the receive buffer must be longword aligned.
+		   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+		   use skb_reserve() to align the IP header! */
+		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+		tp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		tp->rx_ring[i].status = Rx0DescOwned;	/* Owned by Xircom chip */
+		tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+	}
+	tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* The Tx buffer descriptor is filled in as needed, but we
+	   do need to clear the ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0;
+		tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
+#ifdef CARDBUS
+		if (tp->chip_id == X3201_3)
+			tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
+#endif /* CARDBUS */
+	}
+	tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
+}
+
+
+static int
+xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	int entry;
+	u32 flag;
+
+	/* Caution: the write order is important here, set the base address
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % TX_RING_SIZE;
+
+	tp->tx_skbuff[entry] = skb;
+#ifdef CARDBUS
+	if (tp->chip_id == X3201_3) {
+		memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
+		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
+	} else
+#endif
+		tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
+
+	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+		flag = Tx1WholePkt; /* No interrupt */
+	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+		flag = Tx1WholePkt | Tx1ComplIntr; /* Tx-done intr. */
+	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+		flag = Tx1WholePkt; /* No Tx-done intr. */
+	} else {
+		/* Leave room for set_rx_mode() to fill entries. */
+		flag = Tx1WholePkt | Tx1ComplIntr; /* Tx-done intr. */
+		tp->tx_full = 1;
+	}
+	if (entry == TX_RING_SIZE - 1)
+		flag |= Tx1WholePkt | Tx1ComplIntr | Tx1RingWrap;
+
+	tp->tx_ring[entry].length = skb->len | flag;
+	tp->tx_ring[entry].status = Tx0DescOwned;	/* Pass ownership to the chip. */
+	tp->cur_tx++;
+	if (tp->tx_full)
+		netif_stop_queue (dev);
+	else
+		netif_wake_queue (dev);
+
+	/* Trigger an immediate transmit demand. */
+	outl(0, dev->base_addr + CSR1);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+
+static void xircom_media_change(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 reg0, reg1, reg4, reg5;
+	u32 csr6 = inl(ioaddr + CSR6), newcsr6;
+
+	/* reset status first */
+	mdio_read(dev, tp->phys[0], MII_BMCR);
+	mdio_read(dev, tp->phys[0], MII_BMSR);
+
+	reg0 = mdio_read(dev, tp->phys[0], MII_BMCR);
+	reg1 = mdio_read(dev, tp->phys[0], MII_BMSR);
+
+	if (reg1 & BMSR_LSTATUS) {
+		/* link is up */
+		if (reg0 & BMCR_ANENABLE) {
+			/* autonegotiation is enabled */
+			reg4 = mdio_read(dev, tp->phys[0], MII_ADVERTISE);
+			reg5 = mdio_read(dev, tp->phys[0], MII_LPA);
+			if (reg4 & ADVERTISE_100FULL && reg5 & LPA_100FULL) {
+				tp->speed100 = 1;
+				tp->full_duplex = 1;
+			} else if (reg4 & ADVERTISE_100HALF && reg5 & LPA_100HALF) {
+				tp->speed100 = 1;
+				tp->full_duplex = 0;
+			} else if (reg4 & ADVERTISE_10FULL && reg5 & LPA_10FULL) {
+				tp->speed100 = 0;
+				tp->full_duplex = 1;
+			} else {
+				tp->speed100 = 0;
+				tp->full_duplex = 0;
+			}
+		} else {
+			/* autonegotiation is disabled */
+			if (reg0 & BMCR_SPEED100)
+				tp->speed100 = 1;
+			else
+				tp->speed100 = 0;
+			if (reg0 & BMCR_FULLDPLX)
+				tp->full_duplex = 1;
+			else
+				tp->full_duplex = 0;
+		}
+		printk(KERN_DEBUG "%s: Link is up, running at %sMbit %s-duplex\n",
+		       dev->name,
+		       tp->speed100 ? "100" : "10",
+		       tp->full_duplex ? "full" : "half");
+		newcsr6 = csr6 & ~FullDuplexBit;
+		if (tp->full_duplex)
+			newcsr6 |= FullDuplexBit;
+		if (newcsr6 != csr6)
+			outl_CSR6(newcsr6, ioaddr + CSR6);
+	} else {
+		printk(KERN_DEBUG "%s: Link is down\n", dev->name);
+	}
+}
+
+
+static void check_duplex(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	u16 reg0;
+
+	mdio_write(dev, tp->phys[0], MII_BMCR, BMCR_RESET);
+	udelay(500);
+	while (mdio_read(dev, tp->phys[0], MII_BMCR) & BMCR_RESET);
+
+	reg0 = mdio_read(dev, tp->phys[0], MII_BMCR);
+	mdio_write(dev, tp->phys[0], MII_ADVERTISE, tp->advertising[0]);
+
+	if (tp->autoneg) {
+		reg0 &= ~(BMCR_SPEED100 | BMCR_FULLDPLX);
+		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
+	} else {
+		reg0 &= ~(BMCR_ANENABLE | BMCR_ANRESTART);
+		if (tp->speed100)
+			reg0 |= BMCR_SPEED100;
+		if (tp->full_duplex)
+			reg0 |= BMCR_FULLDPLX;
+		printk(KERN_DEBUG "%s: Link forced to %sMbit %s-duplex\n",
+		       dev->name,
+		       tp->speed100 ? "100" : "10",
+		       tp->full_duplex ? "full" : "half");
+	}
+	mdio_write(dev, tp->phys[0], MII_BMCR, reg0);
+}
+
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_instance;
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr5, work_budget = max_interrupt_work;
+
+	spin_lock (&tp->lock);
+
+	do {
+		csr5 = inl(ioaddr + CSR5);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+		if (xircom_debug > 4)
+			printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+				   dev->name, csr5, inl(dev->base_addr + CSR5));
+
+		if (csr5 == 0xffffffff)
+			break;	/* all bits set, assume PCMCIA card removed */
+
+		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+			break;
+
+		if (csr5 & (RxIntr | RxNoBuf))
+			work_budget -= xircom_rx(dev);
+
+		if (csr5 & (TxNoBuf | TxDied | TxIntr)) {
+			unsigned int dirty_tx;
+
+			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+				 dirty_tx++) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int status = tp->tx_ring[entry].status;
+
+				if (status < 0)
+					break;			/* It still hasn't been Txed */
+				/* Check for Rx filter setup frames. */
+				if (tp->tx_skbuff[entry] == NULL)
+				  continue;
+
+				if (status & Tx0DescError) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (xircom_debug > 1)
+						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, status);
+#endif
+					tp->stats.tx_errors++;
+					if (status & Tx0ManyColl) {
+						tp->stats.tx_aborted_errors++;
+#ifdef ETHER_STATS
+						tp->stats.collisions16++;
+#endif
+					}
+					if (status & Tx0NoCarrier) tp->stats.tx_carrier_errors++;
+					if (status & Tx0LateColl) tp->stats.tx_window_errors++;
+					if (status & Tx0Underflow) tp->stats.tx_fifo_errors++;
+				} else {
+					tp->stats.tx_bytes += tp->tx_ring[entry].length & 0x7ff;
+					tp->stats.collisions += (status >> 3) & 15;
+					tp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb_irq(tp->tx_skbuff[entry]);
+				tp->tx_skbuff[entry] = 0;
+			}
+
+#ifndef final_version
+			if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (tp->tx_full &&
+			    tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2)
+				/* The ring is no longer full */
+				tp->tx_full = 0;
+
+			if (tp->tx_full)
+				netif_stop_queue (dev);
+			else
+				netif_wake_queue (dev);
+
+			tp->dirty_tx = dirty_tx;
+			if (csr5 & TxDied) {
+				if (xircom_debug > 2)
+					printk(KERN_WARNING "%s: The transmitter stopped."
+						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+				outl_CSR6(tp->csr6 | EnableRx, ioaddr);
+				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
+			}
+		}
+
+		/* Log errors. */
+		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
+			if (csr5 & LinkChange)
+				xircom_media_change(dev);
+			if (csr5 & TxFIFOUnderflow) {
+				if ((tp->csr6 & TxThreshMask) != TxThreshMask)
+					tp->csr6 += (1 << TxThreshShift);	/* Bump up the Tx threshold */
+				else
+					tp->csr6 |= TxStoreForw;  /* Store-n-forward. */
+				/* Restart the transmit process. */
+				outl_CSR6(tp->csr6 | EnableRx, ioaddr);
+				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
+			}
+			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+				tp->stats.rx_errors++;
+				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+				outl_CSR6(tp->csr6 | EnableTxRx, ioaddr);
+			}
+			/* Clear all error sources, included undocumented ones! */
+			outl(0x0800f7ba, ioaddr + CSR5);
+		}
+		if (--work_budget < 0) {
+			if (xircom_debug > 1)
+				printk(KERN_WARNING "%s: Too much work during an interrupt, "
+					   "csr5=0x%8.8x.\n", dev->name, csr5);
+			/* Acknowledge all interrupt sources. */
+			outl(0x8001ffff, ioaddr + CSR5);
+			break;
+		}
+	} while (1);
+
+	if (xircom_debug > 3)
+		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	spin_unlock (&tp->lock);
+}
+
+
+static int
+xircom_rx(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	int entry = tp->cur_rx % RX_RING_SIZE;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+	int work_done = 0;
+
+	if (xircom_debug > 4)
+		printk(KERN_DEBUG " In xircom_rx(), entry %d %8.8x.\n", entry,
+			   tp->rx_ring[entry].status);
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while (tp->rx_ring[entry].status >= 0) {
+		s32 status = tp->rx_ring[entry].status;
+
+		if (xircom_debug > 5)
+			printk(KERN_DEBUG " In xircom_rx(), entry %d %8.8x.\n", entry,
+				   tp->rx_ring[entry].status);
+		if (--rx_work_limit < 0)
+			break;
+		if ((status & 0x38008300) != 0x0300) {
+			if ((status & 0x38000300) != 0x0300) {
+				/* Ignore earlier buffers. */
+				if ((status & 0xffff) != 0x7fff) {
+					if (xircom_debug > 1)
+						printk(KERN_WARNING "%s: Oversized Ethernet frame "
+							   "spanned multiple buffers, status %8.8x!\n",
+							   dev->name, status);
+					tp->stats.rx_length_errors++;
+				}
+			} else if (status & Rx0DescError) {
+				/* There was a fatal error. */
+				if (xircom_debug > 2)
+					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+						   dev->name, status);
+				tp->stats.rx_errors++; /* end of a packet.*/
+				if (status & (Rx0Runt | Rx0HugeFrame)) tp->stats.rx_length_errors++;
+				if (status & Rx0CRCError) tp->stats.rx_crc_errors++;
+			}
+		} else {
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = ((status >> 16) & 0x7ff) - 4;
+			struct sk_buff *skb;
+
+#ifndef final_version
+			if (pkt_len > 1518) {
+				printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+					   dev->name, pkt_len, pkt_len);
+				pkt_len = 1518;
+				tp->stats.rx_length_errors++;
+			}
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if ! defined(__alpha__)
+				eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+								 pkt_len, 0);
+				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(tp->rx_ring[entry].buffer1), pkt_len);
+#endif
+				work_done++;
+			} else { 	/* Pass up the skb already on the Rx ring. */
+				skb_put(skb = tp->rx_skbuff[entry], pkt_len);
+				tp->rx_skbuff[entry] = NULL;
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			tp->stats.rx_packets++;
+			tp->stats.rx_bytes += pkt_len;
+		}
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+	}
+
+	/* Refill the Rx ring buffers. */
+	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+		entry = tp->dirty_rx % RX_RING_SIZE;
+		if (tp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;
+			skb->dev = dev;			/* Mark as being used by this device. */
+			tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+			work_done++;
+		}
+		tp->rx_ring[entry].status = Rx0DescOwned;
+	}
+
+	return work_done;
+}
+
+
+static void
+xircom_down(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct xircom_private *tp = dev->priv;
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0, ioaddr + CSR7);
+	/* Stop the chip's Tx and Rx processes. */
+	outl_CSR6(inl(ioaddr + CSR6) & ~EnableTxRx, ioaddr);
+
+	if (inl(ioaddr + CSR6) != 0xffffffff)
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	dev->if_port = tp->saved_if_port;
+}
+
+
+static int
+xircom_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct xircom_private *tp = dev->priv;
+	int i;
+
+	if (xircom_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	netif_stop_queue(dev);
+
+	if (netif_device_present(dev))
+		xircom_down(dev);
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = tp->rx_skbuff[i];
+		tp->rx_skbuff[i] = 0;
+		tp->rx_ring[i].status = 0;		/* Not owned by Xircom chip. */
+		tp->rx_ring[i].length = 0;
+		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+		if (skb) {
+			dev_kfree_skb(skb);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff[i])
+			dev_kfree_skb(tp->tx_skbuff[i]);
+		tp->tx_skbuff[i] = 0;
+	}
+
+	tp->open = 0;
+	return 0;
+}
+
+
+static struct net_device_stats *xircom_get_stats(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (netif_device_present(dev))
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	return &tp->stats;
+}
+
+
+static int xircom_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	struct ethtool_cmd ecmd;
+	struct xircom_private *tp = dev->priv;
+
+	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+		return -EFAULT;
+
+	switch (ecmd.cmd) {
+	case ETHTOOL_GSET:
+		ecmd.supported =
+			SUPPORTED_10baseT_Half |
+			SUPPORTED_10baseT_Full |
+			SUPPORTED_100baseT_Half |
+			SUPPORTED_100baseT_Full |
+			SUPPORTED_Autoneg |
+			SUPPORTED_MII;
+
+		ecmd.advertising = ADVERTISED_MII;
+		if (tp->advertising[0] & ADVERTISE_10HALF)
+			ecmd.advertising |= ADVERTISED_10baseT_Half;
+		if (tp->advertising[0] & ADVERTISE_10FULL)
+			ecmd.advertising |= ADVERTISED_10baseT_Full;
+		if (tp->advertising[0] & ADVERTISE_100HALF)
+			ecmd.advertising |= ADVERTISED_100baseT_Half;
+		if (tp->advertising[0] & ADVERTISE_100FULL)
+			ecmd.advertising |= ADVERTISED_100baseT_Full;
+		if (tp->autoneg) {
+			ecmd.advertising |= ADVERTISED_Autoneg;
+			ecmd.autoneg = AUTONEG_ENABLE;
+		} else
+			ecmd.autoneg = AUTONEG_DISABLE;
+
+		ecmd.port = PORT_MII;
+		ecmd.transceiver = XCVR_INTERNAL;
+		ecmd.phy_address = tp->phys[0];
+		ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10;
+		ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+		ecmd.maxtxpkt = TX_RING_SIZE / 2;
+		ecmd.maxrxpkt = 0;
+
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+
+	case ETHTOOL_SSET: {
+		u16 autoneg, speed100, full_duplex;
+
+		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
+		speed100 = (ecmd.speed == SPEED_100);
+		full_duplex = (ecmd.duplex == DUPLEX_FULL);
+
+		tp->autoneg = autoneg;
+		if (speed100 != tp->speed100 ||
+		    full_duplex != tp->full_duplex) {
+			tp->speed100 = speed100;
+			tp->full_duplex = full_duplex;
+			/* change advertising bits */
+			tp->advertising[0] &= ~(ADVERTISE_10HALF |
+					     ADVERTISE_10FULL |
+					     ADVERTISE_100HALF |
+					     ADVERTISE_100FULL |
+					     ADVERTISE_100BASE4);
+			if (speed100) {
+				if (full_duplex)
+					tp->advertising[0] |= ADVERTISE_100FULL;
+				else
+					tp->advertising[0] |= ADVERTISE_100HALF;
+			} else {
+				if (full_duplex)
+					tp->advertising[0] |= ADVERTISE_10FULL;
+				else
+					tp->advertising[0] |= ADVERTISE_10HALF;
+			}
+		}
+		check_duplex(dev);
+		return 0;
+	}
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info;
+		memset(&info, 0, sizeof(info));
+		info.cmd = ecmd.cmd;
+		strcpy(info.driver, DRV_NAME);
+		strcpy(info.version, DRV_VERSION);
+		*info.fw_version = 0;
+		strcpy(info.bus_info, tp->pdev->slot_name);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+		       return -EFAULT;
+		return 0;
+	}
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct xircom_private *tp = dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = tp->phys[0] & 0x1f;
+	long flags;
+
+	switch(cmd) {
+	case SIOCETHTOOL:
+		return xircom_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	/* Legacy mii-diag interface */
+	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
+		if (tp->mii_cnt)
+			data[0] = phy;
+		else
+			return -ENODEV;
+		return 0;
+	case SIOCGMIIREG:		/* Read MII PHY register. */
+		save_flags(flags);
+		cli();
+		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+		restore_flags(flags);
+		return 0;
+	case SIOCSMIIREG:		/* Write MII PHY register. */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		save_flags(flags);
+		cli();
+		if (data[0] == tp->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				if (value & (BMCR_RESET | BMCR_ANENABLE))
+					/* Autonegotiation. */
+					tp->autoneg = 1;
+				else {
+					tp->full_duplex = (value & BMCR_FULLDPLX) ? 1 : 0;
+					tp->autoneg = 0;
+				}
+				break;
+			case 4:
+				tp->advertising[0] = value;
+				break;
+			}
+			check_duplex(dev);
+		}
+		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		restore_flags(flags);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+static void set_rx_mode(struct net_device *dev)
+{
+	struct xircom_private *tp = dev->priv;
+	struct dev_mc_list *mclist;
+	long ioaddr = dev->base_addr;
+	int csr6 = inl(ioaddr + CSR6);
+	u16 *eaddrs, *setup_frm;
+	u32 tx_flags;
+	int i;
+
+	tp->csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);
+	csr6 &= ~(AllMultiBit | PromiscBit | HashFilterBit);
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		tp->csr6 |= PromiscBit;
+		csr6 |= PromiscBit;
+		goto out;
+	}
+
+	if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter well -- accept all multicasts. */
+		tp->csr6 |= AllMultiBit;
+		csr6 |= AllMultiBit;
+		goto out;
+	}
+
+	tx_flags = Tx1WholePkt | Tx1SetupPkt | PKT_SETUP_SZ;
+
+	/* Note that only the low-address shortword of setup_frame is valid! */
+	setup_frm = tp->setup_frame;
+	mclist = dev->mc_list;
+
+	/* Fill the first entry with our physical address. */
+	eaddrs = (u16 *)dev->dev_addr;
+	*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;
+	*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;
+	*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;
+
+	if (dev->mc_count > 14) { /* Must use a multicast hash table. */
+		u32 *hash_table = (u32 *)(tp->setup_frame + 4 * 12);
+		u32 hash, hash2;
+
+		tx_flags |= Tx1HashSetup;
+		tp->csr6 |= HashFilterBit;
+		csr6 |= HashFilterBit;
+
+		/* Fill the unused 3 entries with the broadcast address.
+		   At least one entry *must* contain the broadcast address!!!*/
+		for (i = 0; i < 3; i++) {
+			*setup_frm = 0xffff; setup_frm += 2;
+			*setup_frm = 0xffff; setup_frm += 2;
+			*setup_frm = 0xffff; setup_frm += 2;
+		}
+
+		/* Truly brain-damaged hash filter layout */
+		/* XXX: not sure if I should take the last or the first 9 bits */
+		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {
+			u32 *hptr;
+			hash = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x1ff;
+			if (hash < 384) {
+				hash2 = hash + ((hash >> 4) << 4) +
+					((hash >> 5) << 5);
+			} else {
+				hash -= 384;
+				hash2 = 64 + hash + (hash >> 4) * 80;
+			}
+			hptr = &hash_table[hash2 & ~0x1f];
+			*hptr |= cpu_to_le32(1 << (hash2 & 0x1f));
+		}
+	} else {
+		/* We have <= 14 mcast addresses so we can use Xircom's
+		   wonderful 16-address perfect filter. */
+		for (i = 0; i < dev->mc_count; i++, mclist = mclist->next) {
+			eaddrs = (u16 *)mclist->dmi_addr;
+			*setup_frm = cpu_to_le16(eaddrs[0]); setup_frm += 2;
+			*setup_frm = cpu_to_le16(eaddrs[1]); setup_frm += 2;
+			*setup_frm = cpu_to_le16(eaddrs[2]); setup_frm += 2;
+		}
+		/* Fill the unused entries with the broadcast address.
+		   At least one entry *must* contain the broadcast address!!!*/
+		for (; i < 15; i++) {
+			*setup_frm = 0xffff; setup_frm += 2;
+			*setup_frm = 0xffff; setup_frm += 2;
+			*setup_frm = 0xffff; setup_frm += 2;
+		}
+	}
+
+	/* Now add this frame to the Tx list. */
+	if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+		/* Same setup recently queued, we need not add it. */
+		/* XXX: Huh? All it means is that the Tx list is full...*/
+	} else {
+		unsigned long flags;
+		unsigned int entry;
+		int dummy = -1;
+
+		save_flags(flags); cli();
+		entry = tp->cur_tx++ % TX_RING_SIZE;
+
+		if (entry != 0) {
+			/* Avoid a chip errata by prefixing a dummy entry. */
+			tp->tx_skbuff[entry] = 0;
+			tp->tx_ring[entry].length =
+				(entry == TX_RING_SIZE - 1) ? Tx1RingWrap : 0;
+			tp->tx_ring[entry].buffer1 = 0;
+			/* race with chip, set Tx0DescOwned later */
+			dummy = entry;
+			entry = tp->cur_tx++ % TX_RING_SIZE;
+		}
+
+		tp->tx_skbuff[entry] = 0;
+		/* Put the setup frame on the Tx list. */
+		if (entry == TX_RING_SIZE - 1)
+			tx_flags |= Tx1RingWrap;		/* Wrap ring. */
+		tp->tx_ring[entry].length = tx_flags;
+		tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame);
+		tp->tx_ring[entry].status = Tx0DescOwned;
+		if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+			tp->tx_full = 1;
+			netif_stop_queue (dev);
+		}
+		if (dummy >= 0)
+			tp->tx_ring[dummy].status = Tx0DescOwned;
+		restore_flags(flags);
+		/* Trigger an immediate transmit demand. */
+		outl(0, ioaddr + CSR1);
+	}
+
+out:
+	outl_CSR6(csr6, ioaddr);
+}
+
+
+static struct pci_device_id xircom_pci_table[] __devinitdata = {
+  { 0x115D, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 },
+  {0},
+};
+MODULE_DEVICE_TABLE(pci, xircom_pci_table);
+
+
+#ifdef CONFIG_PM
+static int xircom_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct xircom_private *tp = dev->priv;
+	printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);
+	if (tp->open)
+		xircom_down(dev);
+	return 0;
+}
+
+
+static int xircom_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct xircom_private *tp = dev->priv;
+	printk(KERN_INFO "xircom_resume(%s)\n", dev->name);
+
+	/* Bring the chip out of sleep mode.
+	   Caution: Snooze mode does not work with some boards! */
+	if (xircom_tbl[tp->chip_id].flags & HAS_ACPI)
+		pci_write_config_dword(tp->pdev, PCI_POWERMGMT, 0);
+
+	transceiver_voodoo(dev);
+	if (xircom_tbl[tp->chip_id].flags & HAS_MII)
+		check_duplex(dev);
+
+	if (tp->open)
+		xircom_up(dev);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+static void __devexit xircom_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	printk(KERN_INFO "xircom_remove_one(%s)\n", dev->name);
+	unregister_netdev(dev);
+	pci_release_regions(pdev);
+	kfree(dev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+
+static struct pci_driver xircom_driver = {
+	name:		DRV_NAME,
+	id_table:	xircom_pci_table,
+	probe:		xircom_init_one,
+	remove:		__devexit_p(xircom_remove_one),
+#ifdef CONFIG_PM
+	suspend:	xircom_suspend,
+	resume:		xircom_resume
+#endif /* CONFIG_PM */
+};
+
+
+static int __init xircom_init(void)
+{
+/* when a module, this is printed whether or not devices are found in probe */
+#ifdef MODULE
+	printk(version);
+#endif
+	return pci_module_init(&xircom_driver);
+}
+
+
+static void __exit xircom_exit(void)
+{
+	pci_unregister_driver(&xircom_driver);
+}
+
+module_init(xircom_init)
+module_exit(xircom_exit)
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -urN linux-2.5.6-pre3/drivers/net/wan/Config.help linux-2.5.6/drivers/net/wan/Config.help
--- linux-2.5.6-pre3/drivers/net/wan/Config.help	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/drivers/net/wan/Config.help	Thu Mar  7 18:24:48 2002
@@ -41,14 +41,15 @@
   This driver supports the FarSync T-Series X.21 (and V.35/V.24) cards
   from FarSite Communications Ltd.
   Synchronous communication is supported on all ports at speeds up to
-  8Mb/s (128K on V.24) using synchronous PPP or Cisco HDLC.
+  8Mb/s (128K on V.24) using synchronous PPP, Cisco HDLC, raw HDLC,
+  Frame Relay or X.25/LAPB.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want)
   say M here and read <file:Documentation/modules.txt>.
   The module will be called farsync.o and if you want the module to be
   automatically loaded when the interface is referenced then you
-  should add "alias syncX farsync" to /etc/modules.conf for each
+  should add "alias hdlcX farsync" to /etc/modules.conf for each
   interface, where X is 0, 1, 2, ...
 
 CONFIG_DLCI
diff -urN linux-2.5.6-pre3/drivers/net/wan/Config.in linux-2.5.6/drivers/net/wan/Config.in
--- linux-2.5.6-pre3/drivers/net/wan/Config.in	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/drivers/net/wan/Config.in	Thu Mar  7 18:24:48 2002
@@ -39,9 +39,6 @@
 
    dep_tristate '  Etinc PCISYNC serial board support (EXPERIMENTAL)' CONFIG_DSCC4 m
 
-# FarSite Communications' cards
-
-   tristate '  FarSync T-Series X.21 (and V.35/V.24) cards' CONFIG_FARSYNC
 
 #
 # Lan Media's board. Currently 1000, 1200, 5200, 5245
@@ -55,8 +52,13 @@
 
    tristate '  SyncLink HDLC/SYNCPPP support' CONFIG_SYNCLINK_SYNCPPP
 
-   tristate '  Generic HDLC driver' CONFIG_HDLC
+# Generic HDLC
+
+   tristate '  Generic HDLC layer' CONFIG_HDLC
    if [ "$CONFIG_HDLC" != "n" ]; then
+      bool '    Raw HDLC support' CONFIG_HDLC_RAW
+      bool '    Cisco HDLC support' CONFIG_HDLC_CISCO
+      bool '    Frame Relay support' CONFIG_HDLC_FR
       bool '    Synchronous Point-to-Point Protocol (PPP) support' CONFIG_HDLC_PPP
       if [ "$CONFIG_LAPB" = "m" -a "$CONFIG_HDLC" = "m" -o "$CONFIG_LAPB" = "y" ]; then
 	 bool '    X.25 protocol support' CONFIG_HDLC_X25
@@ -65,6 +67,11 @@
       fi
       dep_tristate '    SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
       dep_tristate '    Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
+      dep_tristate '    FarSync T-Series support' CONFIG_FARSYNC $CONFIG_HDLC
+      bool '    Debug received/transmitted packets' CONFIG_HDLC_DEBUG_PKT
+      bool '    Debug hard_header routines' CONFIG_HDLC_DEBUG_HARD_HEADER
+      bool '    Debug FECN/BECN conditions' CONFIG_HDLC_DEBUG_ECN
+      bool '    Debug RX/TX packet rings' CONFIG_HDLC_DEBUG_RINGS
    fi
 
    tristate '  Frame relay DLCI support' CONFIG_DLCI
diff -urN linux-2.5.6-pre3/drivers/net/wan/Makefile linux-2.5.6/drivers/net/wan/Makefile
--- linux-2.5.6-pre3/drivers/net/wan/Makefile	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/wan/Makefile	Thu Mar  7 18:24:48 2002
@@ -9,7 +9,7 @@
 
 O_TARGET := wan.o
 
-export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc.o
+export-objs =	z85230.o syncppp.o comx.o sdladrv.o cycx_drv.o hdlc_generic.o
 list-multi =	wanpipe.o cyclomx.o
 
 wanpipe-objs = sdlamain.o sdla_ft1.o $(wanpipe-y)
@@ -22,6 +22,11 @@
 cyclomx-objs = cycx_main.o $(cyclomx-y)  
 cyclomx-$(CONFIG_CYCLOMX_X25)	+= cycx_x25.o
 
+hdlc-$(CONFIG_HDLC_RAW)		+= hdlc_raw.o
+hdlc-$(CONFIG_HDLC_CISCO)	+= hdlc_cisco.o
+hdlc-$(CONFIG_HDLC_FR)		+= hdlc_fr.o
+hdlc-$(CONFIG_HDLC_PPP)		+= hdlc_ppp.o
+hdlc-$(CONFIG_HDLC_X25)		+= hdlc_x25.o
 
 obj-$(CONFIG_HOSTESS_SV11)	+= z85230.o	syncppp.o	hostess_sv11.o
 obj-$(CONFIG_SEALEVEL_4021)	+= z85230.o	syncppp.o	sealevel.o
@@ -56,12 +61,17 @@
 obj-$(CONFIG_LAPBETHER)		+= lapbether.o
 obj-$(CONFIG_SBNI)		+= sbni.o
 obj-$(CONFIG_HDLC)		+= hdlc.o
-obj-$(CONFIG_HDLC_PPP)		+= syncppp.o
+ifeq ($(CONFIG_HDLC_PPP),y)
+  obj-$(CONFIG_HDLC)		+= syncppp.o
+endif
 obj-$(CONFIG_N2)		+= n2.o
 obj-$(CONFIG_C101)		+= c101.o
 
 include $(TOPDIR)/Rules.make
 
+hdlc.o: hdlc_generic.o $(hdlc-y)
+	$(LD) -r -o $@ hdlc_generic.o $(hdlc-y)
+
 wanpipe.o: $(wanpipe-objs)
 	$(LD) -r -o $@ $(wanpipe-objs)
 
diff -urN linux-2.5.6-pre3/drivers/net/wan/c101.c linux-2.5.6/drivers/net/wan/c101.c
--- linux-2.5.6-pre3/drivers/net/wan/c101.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/wan/c101.c	Thu Mar  7 18:24:48 2002
@@ -1,7 +1,7 @@
 /*
  * Moxa C101 synchronous serial card driver for Linux
  *
- * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000-2001 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -15,6 +15,7 @@
  *    Moxa C101 User's Manual
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -29,10 +30,8 @@
 
 #include "hd64570.h"
 
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
 
-static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4";
+static const char* version = "Moxa C101 driver version: 1.09";
 static const char* devname = "C101";
 
 #define C101_PAGE 0x1D00
@@ -51,12 +50,12 @@
 typedef struct card_s {
 	hdlc_device hdlc;	/* HDLC device struct - must be first */
 	spinlock_t lock;	/* TX lock */
-	int clkmode;		/* clock mode */
-	int clkrate;		/* clock speed */
-	int line;		/* loopback only */
 	u8 *win0base;		/* ISA window base address */
 	u32 phy_winbase;	/* ISA physical base address */
 	u16 buff_offset;	/* offset of first buffer of first channel */
+	sync_serial_settings settings;
+	unsigned short encoding;
+	unsigned short parity;
 	u8 rxs, txs, tmc;	/* SCA registers */
 	u8 irq;			/* IRQ (3-15) */
 	u8 ring_buffers;	/* number of buffers in a ring */
@@ -72,6 +71,9 @@
 
 typedef card_t port_t;
 
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
 
 #define sca_in(reg, card)	   readb((card)->win0base + C101_SCA + (reg))
 #define sca_out(value, reg, card)  writeb(value, (card)->win0base + C101_SCA + (reg))
@@ -105,13 +107,13 @@
 #include "hd6457x.c"
 
 
-static int c101_set_clock(port_t *port, int value)
+static int c101_set_iface(port_t *port)
 {
 	u8 msci = get_msci(port);
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	switch(value) {
+	switch(port->settings.clock_type) {
 	case CLOCK_EXT:
 		rxs |= CLK_LINE_RX; /* RXC input */
 		txs |= CLK_LINE_TX; /* TXC input */
@@ -140,76 +142,76 @@
 	port->txs = txs;
 	sca_out(rxs, msci + RXS, port);
 	sca_out(txs, msci + TXS, port);
-	port->clkmode = value;
+	sca_set_port(port);
 	return 0;
 }
 
 
-static int c101_open(hdlc_device *hdlc)
+static int c101_open(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
+	int result = hdlc_open(hdlc);
+	if (result)
+		return result;
 
 	MOD_INC_USE_COUNT;
 	writeb(1, port->win0base + C101_DTR);
 	sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
 	sca_open(hdlc);
-	c101_set_clock(port, port->clkmode);
-	return 0;
+	return c101_set_iface(port);
 }
 
 
-static void c101_close(hdlc_device *hdlc)
+static int c101_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
 	sca_close(hdlc);
 	writeb(0, port->win0base + C101_DTR);
 	sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
-static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	int value = ifr->ifr_ifru.ifru_ivalue;
-	int result = 0;
+	union line_settings *line = &ifr->ifr_settings->ifs_line;
+	const size_t size = sizeof(sync_serial_settings);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	switch(cmd) {
-	case HDLCSCLOCK:
-		result = c101_set_clock(port, value);
-	case HDLCGCLOCK:
-		value = port->clkmode;
-		break;
-
-	case HDLCSCLOCKRATE:
-		port->clkrate = value;
-		sca_set_clock(port);
-	case HDLCGCLOCKRATE:
-		value = port->clkrate;
-		break;
-
-	case HDLCSLINE:
-		result = sca_set_loopback(port, value);
-	case HDLCGLINE:
-		value = port->line;
-		break;
-
-#ifdef DEBUG_RINGS
-	case HDLCRUN:
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
 		sca_dump_rings(hdlc);
 		return 0;
-#endif /* DEBUG_RINGS */
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	switch(ifr->ifr_settings->type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+		if (copy_to_user(&line->sync, &port->settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_IFACE_SYNC_SERIAL:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&port->settings, &line->sync, size))
+			return -EFAULT;
+		/* FIXME - put sanity checks here */
+		return c101_set_iface(port);
 
 	default:
-		return -EINVAL;
+		return hdlc_ioctl(dev, ifr, cmd);
 	}
-
-	ifr->ifr_ifru.ifru_ivalue = value;
-	return result;
 }
 
 
@@ -231,6 +233,7 @@
 
 static int c101_run(unsigned long irq, unsigned long winbase)
 {
+	struct net_device *dev;
 	card_t *card;
 	int result;
 
@@ -284,15 +287,19 @@
 
 	sca_init(card, 0);
 
+	dev = hdlc_to_dev(&card->hdlc);
+
 	spin_lock_init(&card->lock);
-	hdlc_to_dev(&card->hdlc)->irq = irq;
-	hdlc_to_dev(&card->hdlc)->mem_start = winbase;
-	hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
-	hdlc_to_dev(&card->hdlc)->tx_queue_len = 50;
-	card->hdlc.ioctl = c101_ioctl;
-	card->hdlc.open = c101_open;
-	card->hdlc.close = c101_close;
+	dev->irq = irq;
+	dev->mem_start = winbase;
+	dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
+	dev->tx_queue_len = 50;
+	dev->do_ioctl = c101_ioctl;
+	dev->open = c101_open;
+	dev->stop = c101_close;
+	card->hdlc.attach = sca_attach;
 	card->hdlc.xmit = sca_xmit;
+	card->settings.clock_type = CLOCK_EXT;
 
 	result = register_hdlc_device(&card->hdlc);
 	if (result) {
@@ -319,7 +326,7 @@
 		return -ENOSYS;	/* no parameters specified, abort */
 	}
 
-	printk(KERN_INFO "%s\n", version);
+	printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
 
 	do {
 		unsigned long irq, ram;
diff -urN linux-2.5.6-pre3/drivers/net/wan/dscc4.c linux-2.5.6/drivers/net/wan/dscc4.c
--- linux-2.5.6-pre3/drivers/net/wan/dscc4.c	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/drivers/net/wan/dscc4.c	Thu Mar  7 18:24:48 2002
@@ -72,7 +72,7 @@
  * the documentation/chipset releases. An on-line errata would be welcome.
  *
  * TODO:
- * - syncppp oopses. X25 untested.
+ * - test X25.
  * - use polling at high irq/s,
  * - performance analysis,
  * - endianness.
@@ -91,6 +91,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/list.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -114,7 +115,7 @@
 #include <linux/hdlc.h>
 
 /* Version */
-static const char version[] = "$Id: dscc4.c,v 1.157 2002/01/28 01:54:19 romieu Exp $\n";
+static const char version[] = "$Id: dscc4.c,v 1.158 2002/01/30 00:40:37 romieu Exp $\n";
 static int debug;
 static int quartz;
 
@@ -168,9 +169,9 @@
 #define BRR_DIVIDER_MAX 64*0x00008000
 #define dev_per_card	4
 
-#define SOURCE_ID(flags) ((flags >> 28 ) & 0x03)
-#define TO_SIZE(state) ((state >> 16) & 0x1fff)
-#define TO_STATE(len) cpu_to_le32((len & TxSizeMax) << 16)
+#define SOURCE_ID(flags) (((flags) >> 28 ) & 0x03)
+#define TO_SIZE(state) (((state) >> 16) & 0x1fff)
+#define TO_STATE(len) cpu_to_le32(((len) & TxSizeMax) << 16)
 #define RX_MAX(len) ((((len) >> 5) + 1)<< 5)
 #define SCC_REG_START(id) SCC_START+(id)*SCC_OFFSET
 
@@ -343,6 +344,11 @@
 static int dscc4_tx_poll(struct dscc4_dev_priv *, struct net_device *);
 #endif
 
+static inline struct dscc4_dev_priv *dscc4_priv(struct net_device *dev)
+{
+	return list_entry(dev, struct dscc4_dev_priv, hdlc.netdev);
+}
+
 static inline void dscc4_patch_register(u32 ioaddr, u32 mask, u32 value)
 {
 	u32 state;
@@ -479,52 +485,49 @@
 
 static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv)
 {
-	int cur, ret = 0;
-	s16 i;
+	int cur = dpriv->iqtx_current%IRQ_RING_SIZE;
+	s16 i = 0;
 
-	cur = dpriv->iqtx_current%IRQ_RING_SIZE;
-	for (i = 0; i >= 0; i++) {
+	do {
 		if (!(dpriv->flags & (NeedIDR | NeedIDT)) ||
 		    (dpriv->iqtx[cur] & Xpr))
 			break;
 		smp_rmb();
-	}
-	if (i < 0) {
-		printk(KERN_ERR "%s: %s timeout\n", "dscc4", "XPR");
-		ret = -1;
-	}
-	return ret;
+	} while (i++ >= 0);
+
+	return i;
 }
 
 static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, int cur,
 	struct RxFD *rx_fd, struct net_device *dev)
 {
+	struct net_device_stats *stats = &dev_to_hdlc(dev)->stats;
 	struct pci_dev *pdev = dpriv->pci_priv->pdev;
 	struct sk_buff *skb;
 	int pkt_len;
 
 	skb = dpriv->rx_skbuff[cur];
-	pkt_len = TO_SIZE(rx_fd->state2) - 1;
-	pci_dma_sync_single(pdev, rx_fd->data, pkt_len + 1, PCI_DMA_FROMDEVICE);
-	if((skb->data[pkt_len] & FrameOk) == FrameOk) {
+	pkt_len = TO_SIZE(rx_fd->state2);
+	pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE);
+	if((skb->data[--pkt_len] & FrameOk) == FrameOk) {
 		pci_unmap_single(pdev, rx_fd->data, skb->len, PCI_DMA_FROMDEVICE);
-		dev_to_hdlc(dev)->stats.rx_packets++;
-		dev_to_hdlc(dev)->stats.rx_bytes += pkt_len;
+		stats->rx_packets++;
+		stats->rx_bytes += pkt_len;
 		skb->tail += pkt_len;
 		skb->len = pkt_len;
-       		if (netif_running(hdlc_to_dev(&dpriv->hdlc)))
+       		if (netif_running(dev))
 			skb->protocol = htons(ETH_P_HDLC);
 		netif_rx(skb);
 		try_get_rx_skb(dpriv, cur, dev);
 	} else {
 		if(skb->data[pkt_len] & FrameRdo)
-			dev_to_hdlc(dev)->stats.rx_fifo_errors++;
+			stats->rx_fifo_errors++;
 		else if(!(skb->data[pkt_len] | ~FrameCrc))
-			dev_to_hdlc(dev)->stats.rx_crc_errors++;
+			stats->rx_crc_errors++;
 		else if(!(skb->data[pkt_len] | ~(FrameVfr | FrameRab)))
-			dev_to_hdlc(dev)->stats.rx_length_errors++;
+			stats->rx_length_errors++;
 		else
-			dev_to_hdlc(dev)->stats.rx_errors++;
+			stats->rx_errors++;
 	}
 	rx_fd->state1 |= Hold;
 	rx_fd->state2 = 0x00000000;
@@ -612,7 +615,7 @@
 	 * SCC 0-3 private rx/tx irq structures 
 	 * IQRX/TXi needs to be set soon. Learned it the hard way...
 	 */
-	for(i = 0; i < dev_per_card; i++) {
+	for (i = 0; i < dev_per_card; i++) {
 		dpriv = priv->root + i;
 		dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma);
@@ -620,7 +623,7 @@
 			goto err_out_free_iqtx;
 		writel(dpriv->iqtx_dma, ioaddr + IQTX0 + i*4);
 	}
-	for(i = 0; i < dev_per_card; i++) {
+	for (i = 0; i < dev_per_card; i++) {
 		dpriv = priv->root + i;
 		dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev,
 			IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma);
@@ -740,7 +743,6 @@
 		dpriv->dev_id = i;
 		dpriv->pci_priv = ppriv;
 		spin_lock_init(&dpriv->lock);
-		d->priv = dpriv;
 
 		hdlc->xmit = dscc4_start_xmit;
 		hdlc->attach = dscc4_hdlc_attach;
@@ -778,7 +780,7 @@
 	struct dscc4_dev_priv *dpriv;
 	struct dscc4_pci_priv *ppriv;
 
-	dpriv = dev->priv;
+	dpriv = dscc4_priv(dev);
 	if (netif_queue_stopped(dev) && 
 	   ((jiffies - dev->trans_start) > TX_TIMEOUT)) {
 		ppriv = dpriv->pci_priv;
@@ -844,7 +846,7 @@
 
 static int dscc4_open(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	hdlc_device *hdlc = &dpriv->hdlc;
 	struct dscc4_pci_priv *ppriv;
 	u32 ioaddr;
@@ -893,8 +895,10 @@
 	 * WARNING, a really missing XPR usually means a hardware 
 	 * reset is needed. Suggestions anyone ?
 	 */
-	if (dscc4_xpr_ack(dpriv))
+	if (dscc4_xpr_ack(dpriv) < 0) {
+		printk(KERN_ERR "%s: %s timeout\n", DRV_NAME, "XPR");
 		goto err_free_ring;
+	}
 	
 	netif_start_queue(dev);
 
@@ -925,7 +929,7 @@
 
 static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	struct dscc4_pci_priv *ppriv;
 	struct TxFD *tx_fd;
 	int cur, next;
@@ -935,7 +939,6 @@
 	next = dpriv->tx_current%TX_RING_SIZE;
 	dpriv->tx_skbuff[next] = skb;
 	tx_fd = dpriv->tx_fd + next;
-	printk(KERN_DEBUG "%s: %d sent\n", dev->name, skb->len);
 	tx_fd->state = FrameEnd | Hold | TO_STATE(skb->len);
 	tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len,
 				     PCI_DMA_TODEVICE);
@@ -972,7 +975,7 @@
 
 static int dscc4_close(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	u32 ioaddr = dev->base_addr;
 	int dev_id;
 	hdlc_device *hdlc = dev_to_hdlc(dev);
@@ -1011,7 +1014,7 @@
 
 static int dscc4_set_clock(struct net_device *dev, u32 *bps, u32 *state)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	u32 brr;
 
 	*state &= ~Ccr0ClockMask;
@@ -1062,37 +1065,29 @@
 
 static int dscc4_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
-	struct if_settings *if_s = &ifr->ifr_settings;
+	union line_settings *line = &ifr->ifr_settings->ifs_line;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	const size_t size = sizeof(dpriv->settings);
 	int ret = 0;
 
         if (dev->flags & IFF_UP)
                 return -EBUSY;
 
-	if (cmd != SIOCDEVICE)
+	if (cmd != SIOCWANDEV)
 		return -EOPNOTSUPP;
 
-	switch(ifr->ifr_settings.type) {
+	switch(ifr->ifr_settings->type) {
 	case IF_GET_IFACE:
-		if_s->type = IF_IFACE_SYNC_SERIAL;
-		if (if_s->data_length == 0)
-			return 0;
-		if (if_s->data_length < size)
-			return -ENOMEM;
-		if (copy_to_user(if_s->data, &dpriv->settings, size))
+		ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+		if (copy_to_user(&line->sync, &dpriv->settings, size))
 			return -EFAULT;
-		if_s->data_length = size;
 		break;
 
 	case IF_IFACE_SYNC_SERIAL:
 		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if (if_s->data_length != size)
-			return -ENOMEM;
-
-		if (copy_from_user(&dpriv->settings, if_s->data, size))
+		if (copy_from_user(&dpriv->settings, &line->sync, size))
 			return -EFAULT;
 		ret = dscc4_set_iface(dev);
 		break;
@@ -1133,7 +1128,7 @@
 
 static int dscc4_clock_setting(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	sync_serial_settings *settings = &dpriv->settings;
 	u32 bps, state;
 	u32 ioaddr;
@@ -1160,7 +1155,7 @@
 
 static int dscc4_encoding_setting(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	struct thingie encoding[] = {
 		{ ENCODING_NRZ,		0x00000000 },
 		{ ENCODING_NRZI,	0x00200000 },
@@ -1184,7 +1179,7 @@
 
 static int dscc4_loopback_setting(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	sync_serial_settings *settings = &dpriv->settings;
 	u32 ioaddr, state;
 
@@ -1203,7 +1198,7 @@
 
 static int dscc4_crc_setting(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	struct thingie crc[] = {
 		{ PARITY_CRC16_PR0_CCITT,	0x00000010 },
 		{ PARITY_CRC16_PR1_CCITT,	0x00000000 },
@@ -1516,7 +1511,6 @@
 		}
 	} else { /* ! SccEvt */
 #ifdef DEBUG_PARANOIA
-		int i;
 		static struct {
 			u32 mask;
 			const char *irq_name;
@@ -1528,21 +1522,21 @@
 			{ 0x00000008, "PLLA"},
 			{ 0x00000004, "CDSC"},
 			{ 0, NULL}
-		};
+		}, *evt;
 #endif /* DEBUG_PARANOIA */
 		state &= 0x00ffffff;
 #ifdef DEBUG_PARANOIA
-		for (i = 0; evts[i].irq_name; i++) {
-			if (state & evts[i].mask) {
+		for (evt = evts; evt->irq_name; evt++) {
+			if (state & evt->mask) {
 				printk(KERN_DEBUG "%s: %s\n", dev->name, 
-					evts[i].irq_name);
-				if (!(state &= ~evts[i].mask))
+					evt->irq_name);
+				if (!(state &= ~evt->mask))
 					goto try;
 			}
 		}
 #endif /* DEBUG_PARANOIA */
 		/*
-		 * Receive Data Overflow (FIXME: untested)
+		 * Receive Data Overflow (FIXME: fscked)
 		 */
 		if (state & Rdo) {
 			u32 ioaddr, scc_offset, scc_addr;
@@ -1633,7 +1627,7 @@
 
 static int dscc4_init_ring(struct net_device *dev)
 {
-	struct dscc4_dev_priv *dpriv = (struct dscc4_dev_priv *)dev->priv;
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 	struct TxFD *tx_fd;
 	struct RxFD *rx_fd;
 	int i;
@@ -1654,7 +1648,7 @@
 	dpriv->tx_dirty = 0;
 
 	/* the dma core of the dscc4 will be locked on the first desc */
-	for(i = 0; i < TX_RING_SIZE; ) {
+	for (i = 0; i < TX_RING_SIZE; ) {
 		reset_TxFD(tx_fd);
 	        /* FIXME: NULL should be ok - to be tried */
 	        tx_fd->data = dpriv->tx_fd_dma;
@@ -1689,7 +1683,7 @@
 				     skb->len, PCI_DMA_TODEVICE);
 	dpriv->tx_skbuff[0] = skb;
 }
-	for (i = 0; i < RX_RING_SIZE;) {
+	for (i = 0; i < RX_RING_SIZE; ) {
 		/* size set by the host. Multiple of 4 bytes please */
 	        rx_fd->state1 = HiDesc; /* Hi, no Hold */
 	        rx_fd->state2 = 0x00000000;
@@ -1753,7 +1747,8 @@
 static int dscc4_hdlc_attach(hdlc_device *hdlc, unsigned short encoding, 
 	unsigned short parity)
 {
-	struct dscc4_dev_priv *dpriv = hdlc_to_dev(hdlc)->priv;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	struct dscc4_dev_priv *dpriv = dscc4_priv(dev);
 
 	if (encoding != ENCODING_NRZ &&
 	    encoding != ENCODING_NRZI &&
@@ -1782,7 +1777,7 @@
 MODULE_DEVICE_TABLE(pci, dscc4_pci_tbl);
 
 static struct pci_driver dscc4_driver = {
-	name:           "dscc4",
+	name:           DRV_NAME,
 	id_table:       dscc4_pci_tbl,
 	probe:          dscc4_init_one,
 	remove:         dscc4_remove_one,
diff -urN linux-2.5.6-pre3/drivers/net/wan/farsync.c linux-2.5.6/drivers/net/wan/farsync.c
--- linux-2.5.6-pre3/drivers/net/wan/farsync.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/wan/farsync.c	Thu Mar  7 18:24:48 2002
@@ -1,5 +1,5 @@
 /*
- *      FarSync X21 driver for Linux (2.4.x kernel version)
+ *      FarSync X21 driver for Linux (generic HDLC version)
  *
  *      Actually sync driver for X.21, V.35 and V.24 on FarSync T-series cards
  *
@@ -18,11 +18,10 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-#include <linux/netdevice.h>
 #include <linux/init.h>
-#include <linux/if_arp.h>
 #include <asm/uaccess.h>
-#include <net/syncppp.h>
+#include <linux/if.h>
+#include <linux/hdlc.h>
 
 #include "farsync.h"
 
@@ -32,6 +31,7 @@
  */
 MODULE_AUTHOR("R.J.Dunlop <bob.dunlop@farsite.co.uk>");
 MODULE_DESCRIPTION("FarSync T-Series X21 driver. FarSite Communications Ltd.");
+MODULE_LICENSE("GPL");
 
 EXPORT_NO_SYMBOLS;
 
@@ -331,26 +331,15 @@
 /*      Per port (line or channel) information
  */
 struct fst_port_info {
-        void                   *if_ptr; /* Some drivers describe this as a
-                                         * general purpose pointer. However if
-                                         * using syncPPP it has a very specific
-                                         * purpose: it must be the first item in
-                                         * the structure pointed to by dev->priv
-                                         * and must in turn point to the
-                                         * associated ppp_device structure.
-                                         */
+        hdlc_device             hdlc;   /* HDLC device struct - must be first */
         struct fst_card_info   *card;   /* Card we're associated with */
         int                     index;  /* Port index on the card */
-        int                     proto;  /* Protocol we are running */
         int                     hwif;   /* Line hardware (lineInterface copy) */
         int                     run;    /* Port is running */
         int                     rxpos;  /* Next Rx buffer to use */
         int                     txpos;  /* Next Tx buffer to use */
         int                     txipos; /* Next Tx buffer to check for free */
         int                     txcnt;  /* Count of Tx buffers in use */
-        struct net_device      *dev;    /* Kernel network device entry */
-        struct net_device_stats stats;  /* Standard statistics */
-        struct ppp_device       pppdev; /* Link to syncPPP */
 };
 
 /*      Per card information
@@ -370,6 +359,11 @@
         struct fst_port_info ports[ FST_MAX_PORTS ];
 };
 
+/* Convert an HDLC device pointer into a port info pointer and similar */
+#define hdlc_to_port(H) ((struct fst_port_info *)(H))
+#define dev_to_port(D)  hdlc_to_port(dev_to_hdlc(D))
+#define port_to_dev(P)  hdlc_to_dev(&(P)->hdlc)
+
 
 /*
  *      Shared memory window access macros
@@ -632,25 +626,18 @@
 
         if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE : IPSTS_DCD ))
         {
-                if ( ! netif_carrier_ok ( port->dev ))
+                if ( ! netif_carrier_ok ( port_to_dev ( port )))
                 {
                         dbg ( DBG_INTR,"DCD active\n");
-
-                        /* Poke sPPP to renegotiate */
-                        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-                        {
-                                sppp_reopen ( port->dev );
-                        }
-
-                        netif_carrier_on ( port->dev );
+                        netif_carrier_on ( port_to_dev ( port ));
                 }
         }
         else
         {
-                if ( netif_carrier_ok ( port->dev ))
+                if ( netif_carrier_ok ( port_to_dev ( port )))
                 {
                         dbg ( DBG_INTR,"DCD lost\n");
-                        netif_carrier_off ( port->dev );
+                        netif_carrier_off ( port_to_dev ( port ));
                 }
         }
 }
@@ -693,24 +680,24 @@
                                         len );
         if ( dmabits != ( RX_STP | RX_ENP ) || len > LEN_RX_BUFFER - 2 )
         {
-                port->stats.rx_errors++;
+                port->hdlc.stats.rx_errors++;
 
                 /* Update error stats and discard buffer */
                 if ( dmabits & RX_OFLO )
                 {
-                        port->stats.rx_fifo_errors++;
+                        port->hdlc.stats.rx_fifo_errors++;
                 }
                 if ( dmabits & RX_CRC )
                 {
-                        port->stats.rx_crc_errors++;
+                        port->hdlc.stats.rx_crc_errors++;
                 }
                 if ( dmabits & RX_FRAM )
                 {
-                        port->stats.rx_frame_errors++;
+                        port->hdlc.stats.rx_frame_errors++;
                 }
                 if ( dmabits == ( RX_STP | RX_ENP ))
                 {
-                        port->stats.rx_length_errors++;
+                        port->hdlc.stats.rx_length_errors++;
                 }
 
                 /* Discard buffer descriptors until we see the end of packet
@@ -747,7 +734,7 @@
         {
                 dbg ( DBG_RX,"intr_rx: can't allocate buffer\n");
 
-                port->stats.rx_dropped++;
+                port->hdlc.stats.rx_dropped++;
 
                 /* Return descriptor to card */
                 FST_WRB ( card, rxDescrRing[pi][rxp].bits, DMA_OWN );
@@ -771,29 +758,16 @@
                 port->rxpos = rxp;
 
         /* Update stats */
-        port->stats.rx_packets++;
-        port->stats.rx_bytes += len;
+        port->hdlc.stats.rx_packets++;
+        port->hdlc.stats.rx_bytes += len;
 
         /* Push upstream */
-        if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-        {
-                /* Mark for further processing by sPPP module */
-                skb->protocol = htons ( ETH_P_WAN_PPP );
-        }
-        else
-        {
-                /* DEC customer specific protocol (since nothing defined for
-                 * marking raw data), at least one other driver uses this value
-                 * for this purpose.
-                 */
-                skb->protocol = htons ( ETH_P_CUST );
-                skb->pkt_type = PACKET_HOST;
-        }
         skb->mac.raw = skb->data;
-        skb->dev = port->dev;
+        skb->dev = hdlc_to_dev ( &port->hdlc );
+        skb->protocol = htons ( ETH_P_HDLC );
         netif_rx ( skb );
 
-        port->dev->last_rx = jiffies;
+        port_to_dev ( port )->last_rx = jiffies;
 }
 
 
@@ -844,7 +818,7 @@
                 case CTLB_CHG:
                 case CTLC_CHG:
                 case CTLD_CHG:
-                        if ( port->run && port->dev != NULL )
+                        if ( port->run )
                                 fst_intr_ctlchg ( card, port );
                         break;
 
@@ -863,9 +837,8 @@
                          * always load up the entire packet for DMA.
                          */
                         dbg ( DBG_TX,"Tx underflow port %d\n", event & 0x03 );
-
-                        port->stats.tx_errors++;
-                        port->stats.tx_fifo_errors++;
+                        port->hdlc.stats.tx_errors++;
+                        port->hdlc.stats.tx_fifo_errors++;
                         break;
 
                 case INIT_CPLT:
@@ -890,7 +863,7 @@
 
         for ( pi = 0, port = card->ports ; pi < card->nports ; pi++, port++ )
         {
-                if ( port->dev == NULL || ! port->run )
+                if ( ! port->run )
                         continue;
 
                 /* Check for rx completions */
@@ -907,7 +880,7 @@
                         --port->txcnt;
                         if ( ++port->txipos >= NUM_TX_BUFFER )
                                 port->txipos = 0;
-                        netif_wake_queue ( port->dev );
+                        netif_wake_queue ( port_to_dev ( port ));
                 }
         }
 
@@ -969,145 +942,28 @@
 
 
 static int
-fst_change_mtu ( struct net_device *dev, int new_mtu )
-{
-        if ( new_mtu < 128 || new_mtu > FST_MAX_MTU )
-                return -EINVAL;
-        dev->mtu = new_mtu;
-        return 0;
-}
-
-
-/* Sooner or later you can't avoid a forward declaration */
-static int fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd );
-
-static int
-switch_proto ( struct fst_port_info *port, int new_proto )
-{
-        int err;
-        int orig_mtu;
-        struct net_device *dev;
-
-        dev = port->dev;
-
-        /* Turn off sPPP module ? */
-        if (( new_proto != FST_HDLC && new_proto != FST_PPP )
-                && ( port->proto == FST_HDLC || port->proto == FST_PPP ))
-        {
-                sppp_close ( port->pppdev.dev );
-                sppp_detach ( port->pppdev.dev );
-
-                /* Reset some fields overwritten by sPPP */
-                dev->hard_header     = NULL;
-                dev->rebuild_header  = NULL;
-                dev->tx_queue_len    = FST_TX_QUEUE_LEN;
-                dev->type            = ARPHRD_MYTYPE;
-                dev->addr_len        = 0;
-                dev->hard_header_len = 0;
-                dev->do_ioctl        = fst_ioctl;
-                dev->change_mtu      = fst_change_mtu;
-                dev->flags           = IFF_POINTOPOINT|IFF_NOARP;
-
-                return 0;
-        }
-
-        /* Turn on sPPP ? */
-        if (( new_proto == FST_HDLC || new_proto == FST_PPP )
-                && ( port->proto != FST_HDLC && port->proto != FST_PPP ))
-        {
-                orig_mtu = dev->mtu;
-
-                /* Attach to sync PPP module */
-                port->pppdev.dev = dev;
-                sppp_attach ( &port->pppdev );
-
-                if ( orig_mtu < dev->mtu )
-                        dev->change_mtu ( dev, orig_mtu );
-
-                /* Claw back the ioctl routine. We promise to be good and call
-                 * the sync PPP routines once we've eliminated our functions.
-                 */
-                dev->do_ioctl = fst_ioctl;
-
-                /* Set the mode */
-                if ( new_proto == FST_HDLC )
-                {
-                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
-                                                                SPPPIOCCISCO );
-                }
-                else
-                {
-                        err = sppp_do_ioctl ( port->pppdev.dev, NULL,
-                                                                SPPPIOCPPP );
-                }
-
-                /* Open the device */
-                if ( err == 0 )
-                {
-                        (void) sppp_open ( port->dev );
-                }
-
-                return err;
-        }
-
-        /* Switch sPPP mode to that desired */
-        err = 0;
-        if ( new_proto == FST_HDLC && port->pppdev.dev != NULL )
-        {
-                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCCISCO );
-        }
-        else if ( new_proto == FST_PPP && port->pppdev.dev != NULL )
-        {
-                err = sppp_do_ioctl ( port->pppdev.dev, NULL, SPPPIOCPPP );
-        }
-
-        /* Anything else is switching from one raw mode to another which is
-         * basically a NOP
-         */
-
-        return err;
-}
-
-
-static int
 set_conf_from_info ( struct fst_card_info *card, struct fst_port_info *port,
                 struct fstioc_info *info )
 {
         int err;
 
-        /* Set things according to the user set valid flags */
+        /* Set things according to the user set valid flags.
+         * Several of the old options have been invalidated/replaced by the
+         * generic HDLC package.
+         */
         err = 0;
         if ( info->valid & FSTVAL_PROTO )
-        {
-                if ( port->proto != info->proto )
-                {
-                        err = switch_proto ( port, info->proto );
-                        if ( err == 0 )
-                                port->proto = info->proto;
-                }
-        }
+                err = -EINVAL;
         if ( info->valid & FSTVAL_CABLE )
-        {
-                FST_WRB ( card, portConfig[port->index].lineInterface,
-                                        info->lineInterface );
-                port->hwif = info->lineInterface;
-        }
+                err = -EINVAL;
         if ( info->valid & FSTVAL_SPEED )
-        {
-                FST_WRL ( card, portConfig[port->index].lineSpeed,
-                                        info->lineSpeed );
-                FST_WRB ( card, portConfig[port->index].internalClock,
-                                        info->internalClock );
-        }
+                err = -EINVAL;
+
         if ( info->valid & FSTVAL_MODE )
-        {
                 FST_WRW ( card, cardMode, info->cardMode );
-        }
 #if FST_DEBUG
         if ( info->valid & FSTVAL_DEBUG )
-        {
                 fst_debug_mask = info->debug;
-        }
 #endif
 
         return err;
@@ -1125,7 +981,7 @@
         info->nports = card->nports;
         info->type   = card->type;
         info->state  = card->state;
-        info->proto  = port->proto;
+        info->proto  = FST_GEN_HDLC;
         info->index  = i;
 #if FST_DEBUG
         info->debug  = fst_debug_mask;
@@ -1154,6 +1010,102 @@
 
 
 static int
+fst_set_iface ( struct fst_card_info *card, struct fst_port_info *port,
+                struct ifreq *ifr )
+{
+	union line_settings *line = &ifr->ifr_settings->ifs_line;
+        sync_serial_settings sync;
+        int i;
+
+        if ( copy_from_user ( &sync, &line->sync, sizeof ( sync )))
+                return -EFAULT;
+
+        if ( sync.loopback )
+                return -EINVAL;
+
+        i = port->index;
+
+        switch ( ifr->ifr_settings->type )
+        {
+        case IF_IFACE_V35:
+                FST_WRW ( card, portConfig[i].lineInterface, V35 );
+                port->hwif = V35;
+                break;
+
+        case IF_IFACE_V24:
+                FST_WRW ( card, portConfig[i].lineInterface, V24 );
+                port->hwif = V24;
+                break;
+
+        case IF_IFACE_X21:
+                FST_WRW ( card, portConfig[i].lineInterface, X21 );
+                port->hwif = X21;
+                break;
+
+        case IF_IFACE_SYNC_SERIAL:
+                break;
+
+        default:
+                return -EINVAL;
+        }
+
+        switch ( sync.clock_type )
+        {
+        case CLOCK_EXT:
+                FST_WRB ( card, portConfig[i].internalClock, EXTCLK );
+                break;
+
+        case CLOCK_INT:
+                FST_WRB ( card, portConfig[i].internalClock, INTCLK );
+                break;
+
+        default:
+                return -EINVAL;
+        }
+        FST_WRL ( card, portConfig[i].lineSpeed, sync.clock_rate );
+        return 0;
+}
+
+static int
+fst_get_iface ( struct fst_card_info *card, struct fst_port_info *port,
+                struct ifreq *ifr )
+{
+	union line_settings *line = &ifr->ifr_settings->ifs_line;
+        sync_serial_settings sync;
+        int i;
+
+        /* First check what line type is set, we'll default to reporting X.21
+         * if nothing is set as IF_IFACE_SYNC_SERIAL implies it can't be
+         * changed
+         */
+        switch ( port->hwif )
+        {
+        case V35:
+                ifr->ifr_settings->type = IF_IFACE_V35;
+                break;
+        case V24:
+                ifr->ifr_settings->type = IF_IFACE_V24;
+                break;
+        case X21:
+        default:
+                ifr->ifr_settings->type = IF_IFACE_X21;
+                break;
+        }
+
+        i = port->index;
+        sync.clock_rate = FST_RDL ( card, portConfig[i].lineSpeed );
+        /* Lucky card and linux use same encoding here */
+        sync.clock_type = FST_RDB ( card, portConfig[i].internalClock );
+        sync.loopback = 0;
+
+        if ( copy_to_user (&line->sync, &sync, sizeof ( sync )))
+                return -EFAULT;
+
+        return 0;
+}
+
+
+static int
 fst_ioctl ( struct net_device *dev, struct ifreq *ifr, int cmd )
 {
         struct fst_card_info *card;
@@ -1164,7 +1116,7 @@
 
         dbg ( DBG_IOCTL,"ioctl: %x, %p\n", cmd, ifr->ifr_data );
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
         card = port->card;
 
         if ( !capable ( CAP_NET_ADMIN ))
@@ -1201,7 +1153,7 @@
                  * when going over the top
                  */
                 if ( wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE
-                                || wrthdr.size + wrthdr.offset > FST_MEMSIZE )
+				|| wrthdr.size + wrthdr.offset > FST_MEMSIZE )
                 {
                         return -ENXIO;
                 }
@@ -1261,6 +1213,9 @@
 
         case FSTSETCONF:
 
+                /* Most of the setting have been moved to the generic ioctls
+                 * this just covers debug and board ident mode now
+                 */
                 if ( copy_from_user ( &info,  ifr->ifr_data, sizeof ( info )))
                 {
                         return -EFAULT;
@@ -1268,12 +1223,25 @@
 
                 return set_conf_from_info ( card, port, &info );
 
+        case SIOCWANDEV:
+                switch ( ifr->ifr_settings->type )
+                {
+                case IF_GET_IFACE:
+                        return fst_get_iface ( card, port, ifr );
+
+                case IF_IFACE_SYNC_SERIAL:
+                case IF_IFACE_V35:
+                case IF_IFACE_V24:
+                case IF_IFACE_X21:
+                        return fst_set_iface ( card, port, ifr );
+
+                default:
+                        return hdlc_ioctl ( dev, ifr, cmd );
+                }
+
         default:
-                /* Not one of ours. Pass it through to sPPP package */
-                if ( port->proto == FST_HDLC || port->proto == FST_PPP )
-                        return sppp_do_ioctl ( dev, ifr, cmd );
-                else
-                        return -EINVAL;
+                /* Not one of ours. Pass through to HDLC package */
+                return hdlc_ioctl ( dev, ifr, cmd );
         }
 }
 
@@ -1306,9 +1274,9 @@
                 signals = FST_RDL ( port->card, v24DebouncedSts[port->index]);
                 if ( signals & (( port->hwif == X21 ) ? IPSTS_INDICATE
                                                       : IPSTS_DCD ))
-                        netif_carrier_on ( port->dev );
+                        netif_carrier_on ( port_to_dev ( port ));
                 else
-                        netif_carrier_off ( port->dev );
+                        netif_carrier_off ( port_to_dev ( port ));
         }
 }
 
@@ -1335,64 +1303,15 @@
 static int
 fst_open ( struct net_device *dev )
 {
-        struct fst_card_info *card;
-        struct fst_port_info *port;
-        int orig_mtu;
         int err;
 
-        MOD_INC_USE_COUNT;
-
-        port = dev->priv;
-        card = port->card;
-
-        switch ( port->proto )
-        {
-        case FST_HDLC:
-        case FST_PPP:
-
-                orig_mtu = dev->mtu;
-
-                /* Attach to sync PPP module */
-                port->pppdev.dev = dev;
-                sppp_attach ( &port->pppdev );
-
-                if ( orig_mtu < dev->mtu )
-                        dev->change_mtu ( dev, orig_mtu );
-
-                /* Claw back the ioctl routine. We promise to be good and call
-                 * the sync PPP routines once we've eliminated our functions.
-                 */
-                dev->do_ioctl = fst_ioctl;
-
-                err = sppp_do_ioctl ( dev, NULL, port->proto == FST_HDLC
-                                                ? SPPPIOCCISCO : SPPPIOCPPP );
-                if ( err )
-		{
-			sppp_detach ( dev );
-			MOD_DEC_USE_COUNT;
-			return err;
-		}
-
-                err = sppp_open ( dev );
-                if ( err )
-		{
-			sppp_detach ( dev );
-			MOD_DEC_USE_COUNT;
-			return err;
-		}
-                break;
-
-        case FST_MONITOR:
-        case FST_RAW:
-                break;
-
-        default:
-                dbg ( DBG_OPEN,"open: Unknown proto %d\n", port->proto );
-                break;
-        }
+        err = hdlc_open ( dev_to_hdlc ( dev ));
+        if ( err )
+                return err;
 
-        fst_openport ( port );
+        MOD_INC_USE_COUNT;
 
+        fst_openport ( dev_to_port ( dev ));
         netif_wake_queue ( dev );
         return 0;
 }
@@ -1400,34 +1319,22 @@
 static int
 fst_close ( struct net_device *dev )
 {
-        struct fst_port_info *port;
-
-        port = dev->priv;
-
         netif_stop_queue ( dev );
-        switch ( port->proto )
-        {
-        case FST_HDLC:
-        case FST_PPP:
-                sppp_close ( dev );
-                sppp_detach ( dev );
-                break;
-
-        case FST_MONITOR:
-        case FST_RAW:
-                break;
-
-        default:
-                dbg ( DBG_OPEN,"close: Unknown proto %d\n", port->proto );
-                break;
-        }
-
-        fst_closeport ( port );
-
+        fst_closeport ( dev_to_port ( dev ));
+        hdlc_close ( dev_to_hdlc  ( dev ));
         MOD_DEC_USE_COUNT;
         return 0;
 }
 
+static int
+fst_attach ( hdlc_device *hdlc, unsigned short encoding, unsigned short parity )
+{
+        /* Setting currently fixed in FarSync card so we check and forget */
+        if ( encoding != ENCODING_NRZ || parity != PARITY_CRC16_PR1_CCITT )
+                return -EINVAL;
+        return 0;
+}
+
 
 static void
 fst_tx_timeout ( struct net_device *dev )
@@ -1436,10 +1343,10 @@
 
         dbg ( DBG_INTR | DBG_TX,"tx_timeout\n");
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
 
-        port->stats.tx_errors++;
-        port->stats.tx_aborted_errors++;
+        port->hdlc.stats.tx_errors++;
+        port->hdlc.stats.tx_aborted_errors++;
 
         if ( port->txcnt > 0 )
                 fst_issue_cmd ( port, ABORTTX );
@@ -1459,22 +1366,15 @@
         int pi;
         int txp;
 
-        port = dev->priv;
+        port = dev_to_port ( dev );
         card = port->card;
 
-        /* Drop packet if in monitor (rx only) mode */
-        if ( port->proto == FST_MONITOR )
-        {
-                dev_kfree_skb ( skb );
-                return 0;
-        }
-
         /* Drop packet with error if we don't have carrier */
         if ( ! netif_carrier_ok ( dev ))
         {
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
-                port->stats.tx_carrier_errors++;
+                port->hdlc.stats.tx_errors++;
+                port->hdlc.stats.tx_carrier_errors++;
                 return 0;
         }
 
@@ -1484,7 +1384,7 @@
                 dbg ( DBG_TX,"Packet too large %d vs %d\n", skb->len,
                                                 LEN_TX_BUFFER );
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
+                port->hdlc.stats.tx_errors++;
                 return 0;
         }
 
@@ -1498,7 +1398,7 @@
                 spin_unlock_irqrestore ( &card->card_lock, flags );
                 dbg ( DBG_TX,"Out of Tx buffers\n");
                 dev_kfree_skb ( skb );
-                port->stats.tx_errors++;
+                port->hdlc.stats.tx_errors++;
                 return 0;
         }
         if ( ++port->txpos >= NUM_TX_BUFFER )
@@ -1518,8 +1418,8 @@
         FST_WRW ( card, txDescrRing[pi][txp].bcnt, cnv_bcnt ( skb->len ));
         FST_WRB ( card, txDescrRing[pi][txp].bits, DMA_OWN | TX_STP | TX_ENP );
 
-        port->stats.tx_packets++;
-        port->stats.tx_bytes += skb->len;
+        port->hdlc.stats.tx_packets++;
+        port->hdlc.stats.tx_bytes += skb->len;
 
         dev_kfree_skb ( skb );
 
@@ -1528,18 +1428,6 @@
 }
 
 
-static struct net_device_stats *
-fst_get_stats ( struct net_device *dev )
-{
-        struct fst_port_info *port;
-
-        if (( port = dev->priv ) != NULL )
-                return &port->stats;
-        else
-                return NULL;
-}
-
-
 /*
  *      Card setup having checked hardware resources.
  *      Should be pretty bizarre if we get an error here (kernel memory
@@ -1566,34 +1454,13 @@
          */
         for ( i = 0 ; i < card->nports ; i++ )
         {
-                card->ports[i].if_ptr = &card->ports[i].pppdev;
                 card->ports[i].card   = card;
                 card->ports[i].index  = i;
-                card->ports[i].proto  = FST_HDLC;
                 card->ports[i].run    = 0;
 
-                dev = kmalloc ( sizeof ( struct net_device ), GFP_KERNEL );
-                if ( dev == NULL )
-                {
-                        printk_err ("Cannot allocate net_device for port %d\n",
-                                        i );
-                        /* No point going any further */
-                        card->nports = i;
-                        break;
-                }
-                memset ( dev, 0, sizeof ( struct net_device ));
-                card->ports[i].dev = dev;
-
-                if ( dev_alloc_name ( dev, FST_NDEV_NAME "%d") < 0 )
-                {
-                        printk_err ("Cannot allocate i/f name for port %d\n",
-                                        i );
-                        kfree ( dev );
-                        card->nports = i;
-                        break;
-                }
+                dev = hdlc_to_dev ( &card->ports[i].hdlc );
 
-                /* Fill in remainder of the net device info */
+                /* Fill in the net device info */
                                 /* Since this is a PCI setup this is purely
                                  * informational. Give them the buffer addresses
                                  * and basic card I/O.
@@ -1609,26 +1476,19 @@
                 dev->base_addr   = card->pci_conf;
                 dev->irq         = card->irq;
 
-                dev->get_stats          = fst_get_stats;
-                dev->mtu                = FST_DEF_MTU;
-                dev->change_mtu         = fst_change_mtu;
-                dev->priv               = &card->ports[i];
-                dev->tx_queue_len       = FST_TX_QUEUE_LEN;
-                dev->type               = ARPHRD_MYTYPE;
-                dev->addr_len           = 0;
-                dev->open               = fst_open;
-                dev->stop               = fst_close;
-                dev->hard_start_xmit    = fst_start_xmit;
-                dev->do_ioctl           = fst_ioctl;
-                dev->watchdog_timeo     = FST_TX_TIMEOUT;
-                dev->tx_timeout         = fst_tx_timeout;
-                dev->flags              = IFF_POINTOPOINT|IFF_NOARP;
-
-                if (( err = register_netdev ( dev )) < 0 )
-                {
-                        printk_err ("Cannot register %s (errno %d)\n",
-                                        dev->name, -err );
-                        kfree ( dev );
+                dev->tx_queue_len          = FST_TX_QUEUE_LEN;
+                dev->open                  = fst_open;
+                dev->stop                  = fst_close;
+                dev->do_ioctl              = fst_ioctl;
+                dev->watchdog_timeo        = FST_TX_TIMEOUT;
+                dev->tx_timeout            = fst_tx_timeout;
+                card->ports[i].hdlc.attach = fst_attach;
+                card->ports[i].hdlc.xmit   = fst_start_xmit;
+
+                if (( err = register_hdlc_device ( &card->ports[i].hdlc )) < 0 )
+                {
+                        printk_err ("Cannot register HDLC device for port %d"
+                                    " (errno %d)\n", i, -err );
                         card->nports = i;
                         break;
                 }
@@ -1637,8 +1497,8 @@
         spin_lock_init ( &card->card_lock );
 
         printk ( KERN_INFO "%s-%s: %s IRQ%d, %d ports\n",
-                        card->ports[0].dev->name,
-                        card->ports[card->nports-1].dev->name,
+                        hdlc_to_dev(&card->ports[0].hdlc)->name,
+                        hdlc_to_dev(&card->ports[card->nports-1].hdlc)->name,
                         type_strings[card->type], card->irq, card->nports );
 }
 
@@ -1789,8 +1649,7 @@
 
         for ( i = 0 ; i < card->nports ; i++ )
         {
-                unregister_netdev ( card->ports[i].dev );
-                kfree ( card->ports[i].dev );
+                unregister_hdlc_device ( &card->ports[i].hdlc );
         }
 
         fst_disable_intr ( card );
@@ -1830,4 +1689,3 @@
 module_init ( fst_init );
 module_exit ( fst_cleanup_module );
 
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.6-pre3/drivers/net/wan/farsync.h linux-2.5.6/drivers/net/wan/farsync.h
--- linux-2.5.6-pre3/drivers/net/wan/farsync.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/drivers/net/wan/farsync.h	Thu Mar  7 18:24:48 2002
@@ -32,13 +32,8 @@
  *      A short common prefix is useful for routines within the driver to avoid
  *      conflict with other similar drivers and I chosen to use "fst_" for this
  *      purpose (FarSite T-series).
- *
- *      Finally the device driver needs a short network interface name. Since
- *      "hdlc" is already in use I've chosen the even less informative "sync"
- *      for the present.
  */
 #define FST_NAME                "fst"           /* In debug/info etc */
-#define FST_NDEV_NAME           "sync"          /* For net interface */
 #define FST_DEV_NAME            "farsync"       /* For misc interfaces */
 
 
diff -urN linux-2.5.6-pre3/drivers/net/wan/hd64570.h linux-2.5.6/drivers/net/wan/hd64570.h
--- linux-2.5.6-pre3/drivers/net/wan/hd64570.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/drivers/net/wan/hd64570.h	Thu Mar  7 18:24:48 2002
@@ -152,7 +152,7 @@
 	u32 bp;			/* Buffer Pointer (24 bits) */
 	u16 len;		/* Data Length */
 	u8 stat;		/* Status */
-	u8 unused2;
+	u8 unused;		/* pads to 2-byte boundary */
 }__attribute__ ((packed)) pkt_desc;
 
 
@@ -202,7 +202,11 @@
 #define MD0_CRC_ITU_0 0x06
 #define MD0_CRC_ITU   0x07
 
-#define MD2_NRZI      0x20	/* NRZI mode */
+#define MD2_NRZ	      0x00
+#define MD2_NRZI      0x20
+#define MD2_MANCHESTER 0x80
+#define MD2_FM_MARK   0xA0
+#define MD2_FM_SPACE  0xC0
 #define MD2_LOOPBACK  0x03      /* Local data Loopback */
 
 #define CTL_NORTS     0x01
diff -urN linux-2.5.6-pre3/drivers/net/wan/hd6457x.c linux-2.5.6/drivers/net/wan/hd6457x.c
--- linux-2.5.6-pre3/drivers/net/wan/hd6457x.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/wan/hd6457x.c	Thu Mar  7 18:24:48 2002
@@ -42,13 +42,7 @@
 #error Either hd64570.h or hd64572.h must be included
 #endif
 
-
-static card_t *first_card;
-static card_t **new_card = &first_card;
-
-
-/* Maximum events to handle at each interrupt - should I increase it? */
-#define INTR_WORK 4
+static char sca_version[]="1.09";
 
 #define get_msci(port)	  (phy_node(port) ?   MSCI1_OFFSET :   MSCI0_OFFSET)
 #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET)
@@ -63,11 +57,19 @@
 #define sca_ina(reg, card)		sca_inw(reg, card)
 #define writea(value, ptr)		writew(value, ptr)
 
+#else /* HD64572 */
+#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
+#define sca_ina(reg, card)		sca_inl(reg, card)
+#define writea(value, ptr)		writel(value, ptr)
+#endif
+
 static inline int sca_intr_status(card_t *card)
 {
+	u8 result = 0;
+
+#ifdef __HD64570_H /* HD64570 */
 	u8 isr0 = sca_in(ISR0, card);
 	u8 isr1 = sca_in(ISR1, card);
-	u8 result = 0;
 
 	if (isr1 & 0x03) result |= SCA_INTR_DMAC_RX(0);
 	if (isr1 & 0x0C) result |= SCA_INTR_DMAC_TX(0);
@@ -76,19 +78,8 @@
 	if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0);
 	if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1);
 
-	return result;
-}
-
 #else /* HD64572 */
-#define sca_outa(value, reg, card)	sca_outl(value, reg, card)
-#define sca_ina(reg, card)		sca_inl(reg, card)
-#define writea(value, ptr)		writel(value, ptr)
-
-
-static inline int sca_intr_status(card_t *card)
-{
 	u32 isr0 = sca_inl(ISR0, card);
-	u8 result = 0;
 
 	if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0);
 	if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0);
@@ -97,11 +88,17 @@
 	if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0);
 	if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1);
 
-	return result;
-}
-
 #endif /* HD64570 vs HD64572 */
 
+	if (!(result & SCA_INTR_DMAC_TX(0)))
+		if (sca_in(DSR_TX(0), card) & DSR_EOM)
+			result |= SCA_INTR_DMAC_TX(0);
+	if (!(result & SCA_INTR_DMAC_TX(1)))
+		if (sca_in(DSR_TX(1), card) & DSR_EOM)
+			result |= SCA_INTR_DMAC_TX(1);
+
+	return result;
+}
 
 
 
@@ -250,8 +247,7 @@
 
 
 
-static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc,
-			      u8 rxin)
+static inline void sca_rx(card_t *card, port_t *port, pkt_desc *desc, u8 rxin)
 {
 	struct sk_buff *skb;
 	u16 len;
@@ -289,13 +285,16 @@
 	openwin(card, 0);
 #endif
 	skb_put(skb, len);
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 	printk(KERN_DEBUG "%s RX(%i):", hdlc_to_name(&port->hdlc), skb->len);
 	debug_frame(skb);
 #endif
 	port->hdlc.stats.rx_packets++;
 	port->hdlc.stats.rx_bytes += skb->len;
-	hdlc_netif_rx(&port->hdlc, skb);
+	skb->mac.raw = skb->data;
+	skb->dev = hdlc_to_dev(&port->hdlc);
+	skb->protocol = htons(ETH_P_HDLC);
+	netif_rx(skb);
 }
 
 
@@ -320,14 +319,9 @@
 		pkt_desc *desc;
 		u32 cda = sca_ina(dmac + CDAL, card);
 
-		if (cda == desc_off)
+		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* No frame received */
 
-#ifdef __HD64572_H
-		if (cda == desc_off + 8)
-			break;	/* SCA-II updates CDA in 2 steps */
-#endif
-
 		desc = desc_address(port, port->rxin, 0);
 		stat = readb(&desc->stat);
 		if (!(stat & ST_RX_EOM))
@@ -371,20 +365,17 @@
 		DSR_TX(phy_node(port)), card);
 
 	while (1) {
-		u32 desc_off = desc_offset(port, port->txlast, 1);
 		pkt_desc *desc;
-		u16 len;
 
-		if (sca_ina(dmac + CDAL, card) == desc_off)
+		u32 desc_off = desc_offset(port, port->txlast, 1);
+		u32 cda = sca_ina(dmac + CDAL, card);
+		if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc)))
 			break;	/* Transmitter is/will_be sending this frame */
 
 		desc = desc_address(port, port->txlast, 1);
-		len = readw(&desc->len);
-
 		port->hdlc.stats.tx_packets++;
-		port->hdlc.stats.tx_bytes += len;
+		port->hdlc.stats.tx_bytes += readw(&desc->len);
 		writeb(0, &desc->stat);	/* Free descriptor */
-
 		port->txlast = (port->txlast + 1) %
 			port_to_card(port)->ring_buffers;
 	}
@@ -398,7 +389,8 @@
 static void sca_intr(int irq, void* dev_id, struct pt_regs *regs)
 {
 	card_t *card = dev_id;
-	int boguscnt = INTR_WORK;
+/* Maximum events to handle at each interrupt - should I increase it? */
+	int boguscnt = 4;
 	int i;
 	u8 stat;
 
@@ -421,9 +413,11 @@
 			}
 
 			if (--boguscnt < 0) {
+#if 0
 				printk(KERN_ERR "%s: too much work at "
 				       "interrupt\n",
 				       hdlc_to_name(&port->hdlc));
+#endif
 				goto exit;
 			}
 		}
@@ -437,47 +431,22 @@
 
 
 
-static inline int sca_set_loopback(port_t *port, int line)
+static void sca_set_port(port_t *port)
 {
 	card_t* card = port_to_card(port);
 	u8 msci = get_msci(port);
 	u8 md2 = sca_in(msci + MD2, card);
-
-	switch(line) {
-	case LINE_DEFAULT:
-		md2 &= ~MD2_LOOPBACK;
-		port->line &= ~LINE_LOOPBACK;
-		break;
-
-	case LINE_LOOPBACK:
-		md2 |= MD2_LOOPBACK;
-		port->line |= LINE_LOOPBACK;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	sca_out(md2, msci + MD2, card);
-	return 0;
-}
-
-
-
-static void sca_set_clock(port_t *port)
-{
-	card_t *card = port_to_card(port);
-	u8 msci = get_msci(port);
 	unsigned int tmc, br = 10, brv = 1024;
 
-	if (port->clkrate > 0) {
+
+	if (port->settings.clock_rate > 0) {
 		/* Try lower br for better accuracy*/
 		do {
 			br--;
 			brv >>= 1; /* brv = 2^9 = 512 max in specs */
 
 			/* Baud Rate = CLOCK_BASE / TMC / 2^BR */
-			tmc = CLOCK_BASE / (brv * port->clkrate);
+			tmc = CLOCK_BASE / (brv * port->settings.clock_rate);
 		}while(br > 1 && tmc <= 128);
 
 		if (tmc < 1) {
@@ -487,11 +456,11 @@
 		} else if (tmc > 255)
 			tmc = 256; /* tmc=0 means 256 - low baud rates */
 
-		port->clkrate = CLOCK_BASE / (brv * tmc);
+		port->settings.clock_rate = CLOCK_BASE / (brv * tmc);
 	} else {
 		br = 9; /* Minimum clock rate */
 		tmc = 256;	/* 8bit = 0 */
-		port->clkrate = CLOCK_BASE / (256 * 512);
+		port->settings.clock_rate = CLOCK_BASE / (256 * 512);
 	}
 
 	port->rxs = (port->rxs & ~CLK_BRG_MASK) | br;
@@ -509,27 +478,59 @@
 	/* Set BRG bits */
 	sca_out(port->rxs, msci + RXS, card);
 	sca_out(port->txs, msci + TXS, card);
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+	else
+		md2 &= ~MD2_LOOPBACK;
+
+	sca_out(md2, msci + MD2, card);
+
 }
 
 
 
-static void sca_set_hdlc_mode(port_t *port, u8 idle, u8 crc, u8 nrzi)
+static void sca_open(hdlc_device *hdlc)
 {
+	port_t *port = hdlc_to_port(hdlc);
 	card_t* card = port_to_card(port);
 	u8 msci = get_msci(port);
-	u8 md2 = (nrzi ? MD2_NRZI : 0) |
-		((port->line & LINE_LOOPBACK) ? MD2_LOOPBACK : 0);
-	u8 ctl = (idle ? CTL_IDLE : 0);
-#ifdef __HD64572_H
-	ctl |= CTL_URCT | CTL_URSKP; /* Skip the rest of underrun frame */
-#endif
+	u8 md0, md2;
+
+	switch(port->encoding) {
+	case ENCODING_NRZ:	md2 = MD2_NRZ;		break;
+	case ENCODING_NRZI:	md2 = MD2_NRZI;		break;
+	case ENCODING_FM_MARK:	md2 = MD2_FM_MARK;	break;
+	case ENCODING_FM_SPACE:	md2 = MD2_FM_SPACE;	break;
+	default:		md2 = MD2_MANCHESTER;
+	}
+
+	if (port->settings.loopback)
+		md2 |= MD2_LOOPBACK;
+
+	switch(port->parity) {
+	case PARITY_CRC16_PR0:	     md0 = MD0_HDLC | MD0_CRC_16_0;  break;
+	case PARITY_CRC16_PR1:	     md0 = MD0_HDLC | MD0_CRC_16;    break;
+#ifdef __HD64570_H
+	case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break;
+#else
+	case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break;
+#endif	
+	case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU;   break;
+	default:		     md0 = MD0_HDLC | MD0_CRC_NONE;
+	}
 
 	sca_out(CMD_RESET, msci + CMD, card);
-	sca_out(MD0_HDLC | crc, msci + MD0, card);
+	sca_out(md0, msci + MD0, card);
 	sca_out(0x00, msci + MD1, card); /* no address field check */
 	sca_out(md2, msci + MD2, card);
 	sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */
-	sca_out(ctl, msci + CTL, card);
+#ifdef __HD64570_H
+	sca_out(CTL_IDLE, msci + CTL, card);
+#else
+	/* Skip the rest of underrun frame */
+	sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card);
+#endif
 
 #ifdef __HD64570_H
 	/* Allow at least 8 bytes before requesting RX DMA operation */
@@ -539,24 +540,28 @@
 	sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */
 #else
 	sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */
-	/* Setting than to larger value may cause Illegal Access */
-	sca_out(0x20, msci + TNR0, card); /* =TX DMA activation condition */
-	sca_out(0x30, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
-	sca_out(0x04, msci + TCR, card); /* =Critical TX DMA activ condition */
+	sca_out(0x3C, msci + TFS, card); /* +1 = TX start */
+	sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */
+	sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */
+	sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/
 #endif
 
+/* We're using the following interrupts:
+   - TXINT (DMAC completed all transmisions, underflow or CTS change)
+   - all DMA interrupts
+*/
 
 #ifdef __HD64570_H
 	/* MSCI TX INT IRQ enable */
 	sca_out(IE0_TXINT, msci + IE0, card);
-	sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun IRQ */
+	sca_out(IE1_UDRN, msci + IE1, card); /* TX underrun -> TXINT */
 	sca_out(sca_in(IER0, card) | (phy_node(port) ? 0x80 : 0x08),
 		IER0, card);
 	/* DMA IRQ enable */
 	sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F),
 		IER1, card);
 #else
-	/* MSCI TX INT and underrrun IRQ enable */
+	/* MSCI TX INT IRQ enable */
 	sca_outl(IE0_TXINT | IE0_UDRN, msci + IE0, card);
 	/* DMA & MSCI IRQ enable */
 	sca_outl(sca_in(IER0, card) |
@@ -573,11 +578,52 @@
 	sca_out(port->txs, msci + TXS, card);
 	sca_out(CMD_TX_ENABLE, msci + CMD, card);
 	sca_out(CMD_RX_ENABLE, msci + CMD, card);
+
+	netif_start_queue(hdlc_to_dev(hdlc));
+}
+
+
+
+static void sca_close(hdlc_device *hdlc)
+{
+	port_t *port = hdlc_to_port(hdlc);
+
+	/* reset channel */
+	netif_stop_queue(hdlc_to_dev(hdlc));
+	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
 }
 
 
 
-#ifdef DEBUG_RINGS
+static int sca_attach(hdlc_device *hdlc, unsigned short encoding,
+		      unsigned short parity)
+{
+	if (encoding != ENCODING_NRZ &&
+	    encoding != ENCODING_NRZI &&
+	    encoding != ENCODING_FM_MARK &&
+	    encoding != ENCODING_FM_SPACE &&
+	    encoding != ENCODING_MANCHESTER)
+		return -EINVAL;
+
+	if (parity != PARITY_NONE &&
+	    parity != PARITY_CRC16_PR0 &&
+	    parity != PARITY_CRC16_PR1 &&
+#ifdef __HD64570_H
+	    parity != PARITY_CRC16_PR0_CCITT &&
+#else
+	    parity != PARITY_CRC32_PR1_CCITT &&
+#endif	
+	    parity != PARITY_CRC16_PR1_CCITT)
+		return -EINVAL;
+
+	hdlc_to_port(hdlc)->encoding = encoding;
+	hdlc_to_port(hdlc)->parity = parity;
+	return 0;
+}
+
+
+
+#ifdef CONFIG_HDLC_DEBUG_RINGS
 static void sca_dump_rings(hdlc_device *hdlc)
 {
 	port_t *port = hdlc_to_port(hdlc);
@@ -644,34 +690,14 @@
 	openwin(card, page); /* Restore original page */
 #endif
 }
-#endif /* DEBUG_RINGS */
-
-
-
-static void sca_open(hdlc_device *hdlc)
-{
-	port_t *port = hdlc_to_port(hdlc);
-
-	sca_set_hdlc_mode(port, 1, MD0_CRC_ITU, 0);
-	netif_start_queue(hdlc_to_dev(hdlc));
-}
-
-
-static void sca_close(hdlc_device *hdlc)
-{
-	port_t *port = hdlc_to_port(hdlc);
-
-	/* reset channel */
-	netif_stop_queue(hdlc_to_dev(hdlc));
-	sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port));
-}
+#endif /* CONFIG_HDLC_DEBUG_RINGS */
 
 
 
-static int sca_xmit(hdlc_device *hdlc, struct sk_buff *skb)
+static int sca_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
-	struct net_device *dev = hdlc_to_dev(hdlc);
 	card_t *card = port_to_card(port);
 	pkt_desc *desc;
 	u32 buff, len;
@@ -685,7 +711,7 @@
 	desc = desc_address(port, port->txin + 1, 1);
 	if (readb(&desc->stat)) { /* allow 1 packet gap */
 		/* should never happen - previous xmit should stop queue */
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 		printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name);
 #endif
 		netif_stop_queue(dev);
@@ -693,7 +719,7 @@
 		return 1;	/* request packet to be queued */
 	}
 
-#ifdef DEBUG_PKT
+#ifdef CONFIG_HDLC_DEBUG_PKT
 	printk(KERN_DEBUG "%s TX(%i):", hdlc_to_name(hdlc), skb->len);
 	debug_frame(skb);
 #endif
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc.c linux-2.5.6/drivers/net/wan/hdlc.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/drivers/net/wan/hdlc.c	Wed Dec 31 16:00:00 1969
@@ -1,1453 +0,0 @@
-/*
- * Generic HDLC support routines for Linux
- *
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
- *
- * 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.
- *
- * Current status:
- *    - this is work in progress
- *    - not heavily tested on SMP
- *    - currently supported:
- *	* raw IP-in-HDLC
- *	* Cisco HDLC
- *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
- *	* PPP (using syncppp.c)
- *	* X.25
- *
- * Use sethdlc utility to set line parameters, protocol and PVCs
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include <linux/lapb.h>
-#include <linux/rtnetlink.h>
-#include <linux/hdlc.h>
-
-/* #define DEBUG_PKT */
-/* #define DEBUG_HARD_HEADER */
-/* #define DEBUG_FECN */
-/* #define DEBUG_BECN */
-
-static const char* version = "HDLC support module revision 1.02 for Linux 2.4";
-
-
-#define CISCO_MULTICAST		0x8F	/* Cisco multicast address */
-#define CISCO_UNICAST		0x0F	/* Cisco unicast address */
-#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
-#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
-#define CISCO_ADDR_REQ		0	/* Cisco address request */
-#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
-#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-
-/********************************************************
- *
- * Cisco HDLC support
- *
- *******************************************************/
-
-static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
-			     u16 type, void *daddr, void *saddr,
-			     unsigned int len)
-{
-	hdlc_header *data;
-#ifdef DEBUG_HARD_HEADER
-	printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
-#endif
-
-	skb_push(skb, sizeof(hdlc_header));
-	data = (hdlc_header*)skb->data;
-	if (type == CISCO_KEEPALIVE)
-		data->address = CISCO_MULTICAST;
-	else
-		data->address = CISCO_UNICAST;
-	data->control = 0;
-	data->protocol = htons(type);
-
-	return sizeof(hdlc_header);
-}
-
-
-
-static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
-				 u32 par1, u32 par2)
-{
-	struct sk_buff *skb;
-	cisco_packet *data;
-
-	skb = dev_alloc_skb(sizeof(hdlc_header)+sizeof(cisco_packet));
-	if (!skb) {
-		printk(KERN_WARNING "%s: Memory squeeze on cisco_keepalive_send()\n",
-			       hdlc_to_name(hdlc));
-		return;
-	}
-	skb_reserve(skb, 4);
-	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
-			  NULL, NULL, 0);
-	data = (cisco_packet*)skb->tail;
-
-	data->type = htonl(type);
-	data->par1 = htonl(par1);
-	data->par2 = htonl(par2);
-	data->rel = 0xFFFF;
-	data->time = htonl(jiffies * 1000 / HZ);
-
-	skb_put(skb, sizeof(cisco_packet));
-	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
-
-	dev_queue_xmit(skb);
-}
-
-
-
-static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	hdlc_header *data = (hdlc_header*)skb->data;
-	cisco_packet *cisco_data;
-	struct in_device *in_dev;
-	u32 addr, mask;
-
-	if (skb->len<sizeof(hdlc_header))
-		goto rx_error;
-
-	if (data->address != CISCO_MULTICAST &&
-	    data->address != CISCO_UNICAST)
-		goto rx_error;
-
-	skb_pull(skb, sizeof(hdlc_header));
-
-	switch(ntohs(data->protocol)) {
-	case ETH_P_IP:
-	case ETH_P_IPX:
-	case ETH_P_IPV6:
-		skb->protocol = data->protocol;
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-		return;
-
-	case CISCO_SYS_INFO:
-		/* Packet is not needed, drop it. */
-		dev_kfree_skb_any(skb);
-		return;
-
-	case CISCO_KEEPALIVE:
-		if (skb->len != CISCO_PACKET_LEN &&
-		    skb->len != CISCO_BIG_PACKET_LEN) {
-			printk(KERN_INFO "%s: Invalid length of Cisco "
-			       "control packet (%d bytes)\n",
-			       hdlc_to_name(hdlc), skb->len);
-			goto rx_error;
-		}
-
-		cisco_data = (cisco_packet*)skb->data;
-
-		switch(ntohl (cisco_data->type)) {
-		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
-			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
-			addr = 0;
-			mask = ~0; /* is the mask correct? */
-
-			if (in_dev != NULL) {
-				struct in_ifaddr **ifap = &in_dev->ifa_list;
-
-				while (*ifap != NULL) {
-					if (strcmp(hdlc_to_name(hdlc),
-						   (*ifap)->ifa_label) == 0) {
-						addr = (*ifap)->ifa_local;
-						mask = (*ifap)->ifa_mask;
-						break;
-					}
-					ifap = &(*ifap)->ifa_next;
-				}
-
-				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
-						     addr, mask);
-			}
-			dev_kfree_skb_any(skb);
-			return;
-
-		case CISCO_ADDR_REPLY:
-			printk(KERN_INFO "%s: Unexpected Cisco IP address "
-			       "reply\n", hdlc_to_name(hdlc));
-			goto rx_error;
-
-		case CISCO_KEEPALIVE_REQ:
-			hdlc->lmi.rxseq = ntohl(cisco_data->par1);
-			if (ntohl(cisco_data->par2) == hdlc->lmi.txseq) {
-				hdlc->lmi.last_poll = jiffies;
-				if (!(hdlc->lmi.state & LINK_STATE_RELIABLE)) {
-					u32 sec, min, hrs, days;
-					sec = ntohl(cisco_data->time) / 1000;
-					min = sec / 60; sec -= min * 60;
-					hrs = min / 60; min -= hrs * 60;
-					days = hrs / 24; hrs -= days * 24;
-					printk(KERN_INFO "%s: Link up (peer "
-					       "uptime %ud%uh%um%us)\n",
-					       hdlc_to_name(hdlc), days, hrs,
-					       min, sec);
-				}
-				hdlc->lmi.state |= LINK_STATE_RELIABLE;
-			}
-
-			dev_kfree_skb_any(skb);
-			return;
-		} /* switch(keepalive type) */
-	} /* switch(protocol) */
-
-	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
-	       data->protocol);
-	dev_kfree_skb_any(skb);
-	return;
-
- rx_error:
-	hdlc->stats.rx_errors++; /* Mark error */
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static void cisco_timer(unsigned long arg)
-{
-	hdlc_device *hdlc = (hdlc_device*)arg;
-
-	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
-	    (jiffies - hdlc->lmi.last_poll >= hdlc->lmi.T392 * HZ)) {
-		hdlc->lmi.state &= ~LINK_STATE_RELIABLE;
-		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
-	}
-
-	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ, ++hdlc->lmi.txseq,
-			     hdlc->lmi.rxseq);
-	hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
-
-	hdlc->timer.function = cisco_timer;
-	hdlc->timer.data = arg;
-	add_timer(&hdlc->timer);
-}
-
-
-
-/******************************************************************
- *
- *     generic Frame Relay routines
- *
- *****************************************************************/
-
-
-static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
-			  u16 type, void *daddr, void *saddr, unsigned int len)
-{
-	u16 head_len;
-
-	if (!daddr)
-		daddr = dev->broadcast;
-
-#ifdef DEBUG_HARD_HEADER
-	printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
-#endif
-
-	switch(type) {
-	case ETH_P_IP:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IP;
-		break;
-
-	case ETH_P_IPV6:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = NLPID_IPV6;
-		break;
-
-	case LMI_PROTO:
-		head_len = 4;
-		skb_push(skb, head_len);
-		skb->data[3] = LMI_PROTO;
-		break;
-
-	default:
-		head_len = 10;
-		skb_push(skb, head_len);
-		skb->data[3] = FR_PAD;
-		skb->data[4] = NLPID_SNAP;
-		skb->data[5] = FR_PAD;
-		skb->data[6] = FR_PAD;
-		skb->data[7] = FR_PAD;
-		skb->data[8] = type>>8;
-		skb->data[9] = (u8)type;
-	}
-
-	memcpy(skb->data, daddr, 2);
-	skb->data[2] = FR_UI;
-
-	return head_len;
-}
-
-
-
-static inline void fr_log_dlci_active(pvc_device *pvc)
-{
-	printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
-	       pvc->state & PVC_STATE_ACTIVE ? "" : "in",
-	       pvc->state & PVC_STATE_NEW ? " new" : "");
-}
-
-
-
-static inline u8 fr_lmi_nextseq(u8 x)
-{
-	x++;
-	return x ? x : 1;
-}
-
-
-
-static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
-{
-	struct sk_buff *skb;
-	pvc_device *pvc = hdlc->first_pvc;
-	int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH;
-	int stat_len = 3;
-	u8 *data;
-	int i = 0;
-
-	if (mode_is(hdlc, MODE_DCE) && fullrep) {
-		len += hdlc->pvc_count * (2 + stat_len);
-		if (len > HDLC_MAX_MTU) {
-			printk(KERN_WARNING "%s: Too many PVCs while sending "
-			       "LMI full report\n", hdlc_to_name(hdlc));
-			return;
-		}
-	}
-
-	skb = dev_alloc_skb(len);
-	if (!skb) {
-		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
-			       hdlc_to_name(hdlc));
-		return;
-	}
-	memset(skb->data, 0, len);
-	skb_reserve(skb, 4);
-	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
-	data = skb->tail;
-	data[i++] = LMI_CALLREF;
-	data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY;
-	if (mode_is(hdlc, MODE_FR_ANSI))
-		data[i++] = LMI_ANSI_LOCKSHIFT;
-	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE :
-		LMI_REPTYPE;
-	data[i++] = LMI_REPT_LEN;
-	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
-
-	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE;
-	data[i++] = LMI_INTEG_LEN;
-	data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq);
-	data[i++] = hdlc->lmi.rxseq;
-
-	if (mode_is(hdlc, MODE_DCE) && fullrep) {
-		while (pvc) {
-			data[i++] = mode_is(hdlc, MODE_FR_CCITT) ?
-				LMI_CCITT_PVCSTAT:LMI_PVCSTAT;
-			data[i++] = stat_len;
-
-			if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
-			    (pvc->netdev.flags & IFF_UP) &&
-			    !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) {
-				pvc->state |= PVC_STATE_NEW;
-				fr_log_dlci_active(pvc);
-			}
-
-			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
-				       data+i, pvc->state);
-			i += stat_len;
-			pvc = pvc->next;
-		}
-	}
-
-	skb_put(skb, i);
-	skb->priority = TC_PRIO_CONTROL;
-	skb->dev = hdlc_to_dev(hdlc);
-
-	dev_queue_xmit(skb);
-}
-
-
-
-static void fr_timer(unsigned long arg)
-{
-	hdlc_device *hdlc = (hdlc_device*)arg;
-	int i, cnt = 0, reliable;
-	u32 list;
-
-	if (mode_is(hdlc, MODE_DCE))
-		reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ);
-	else {
-		hdlc->lmi.last_errors <<= 1; /* Shift the list */
-		if (hdlc->lmi.state & LINK_STATE_REQUEST) {
-			printk(KERN_INFO "%s: No LMI status reply received\n",
-			       hdlc_to_name(hdlc));
-			hdlc->lmi.last_errors |= 1;
-		}
-
-		for (i = 0, list = hdlc->lmi.last_errors; i < hdlc->lmi.N393;
-		     i++, list >>= 1)
-			cnt += (list & 1);	/* errors count */
-
-		reliable = (cnt < hdlc->lmi.N392);
-	}
-
-	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) !=
-	    (reliable ? LINK_STATE_RELIABLE : 0)) {
-		pvc_device *pvc = hdlc->first_pvc;
-
-		while (pvc) {/* Deactivate all PVCs */
-			pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE);
-			pvc = pvc->next;
-		}
-
-		hdlc->lmi.state ^= LINK_STATE_RELIABLE;
-		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
-		       reliable ? "" : "un");
-
-		if (reliable) {
-			hdlc->lmi.N391cnt = 0; /* Request full status */
-			hdlc->lmi.state |= LINK_STATE_CHANGED;
-		}
-	}
-
-	if (mode_is(hdlc, MODE_DCE))
-		hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ;
-	else {
-		if (hdlc->lmi.N391cnt)
-			hdlc->lmi.N391cnt--;
-
-		fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0);
-
-		hdlc->lmi.state |= LINK_STATE_REQUEST;
-		hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
-	}
-
-	hdlc->timer.function = fr_timer;
-	hdlc->timer.data = arg;
-	add_timer(&hdlc->timer);
-}
-
-
-
-static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	int stat_len;
-	pvc_device *pvc;
-	int reptype = -1, error;
-	u8 rxseq, txseq;
-	int i;
-
-	if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ?
-			LMI_ANSI_LENGTH : LMI_LENGTH)) {
-		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
-		return 1;
-	}
-
-	if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ?
-			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
-		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
-		       hdlc_to_name(hdlc), skb->data[2],
-		       mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply");
-		return 1;
-	}
-
-	i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6;
-
-	if (skb->data[i] !=
-	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
-		printk(KERN_INFO "%s: Not a report type=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
-		return 1;
-	}
-	i++;
-
-	i++;				/* Skip length field */
-
-	reptype = skb->data[i++];
-
-	if (skb->data[i]!=
-	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
-		printk(KERN_INFO "%s: Unsupported status element=%x\n",
-		       hdlc_to_name(hdlc), skb->data[i]);
-		return 1;
-	}
-	i++;
-
-	i++;			/* Skip length field */
-
-	hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */
-	rxseq = skb->data[i++];	/* Should confirm our sequence */
-
-	txseq = hdlc->lmi.txseq;
-
-	if (mode_is(hdlc, MODE_DCE)) {
-		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
-			printk(KERN_INFO "%s: Unsupported report type=%x\n",
-			       hdlc_to_name(hdlc), reptype);
-			return 1;
-		}
-	}
-
-	error = 0;
-	if (!(hdlc->lmi.state & LINK_STATE_RELIABLE))
-		error = 1;
-
-	if (rxseq == 0 || rxseq != txseq) {
-		hdlc->lmi.N391cnt = 0; /* Ask for full report next time */
-		error = 1;
-	}
-
-	if (mode_is(hdlc, MODE_DCE)) {
-		if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) {
-/* Stop sending full report - the last one has been confirmed by DTE */
-			hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT;
-			pvc = hdlc->first_pvc;
-			while (pvc) {
-				if (pvc->state & PVC_STATE_NEW) {
-					pvc->state &= ~PVC_STATE_NEW;
-					pvc->state |= PVC_STATE_ACTIVE;
-					fr_log_dlci_active(pvc);
-
-/* Tell DTE that new PVC is now active */
-					hdlc->lmi.state |= LINK_STATE_CHANGED;
-				}
-				pvc = pvc->next;
-			}
-		}
-
-		if (hdlc->lmi.state & LINK_STATE_CHANGED) {
-			reptype = LMI_FULLREP;
-			hdlc->lmi.state |= LINK_STATE_FULLREP_SENT;
-			hdlc->lmi.state &= ~LINK_STATE_CHANGED;
-		}
-
-		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
-		return 0;
-	}
-
-	/* DTE */
-
-	if (reptype != LMI_FULLREP || error)
-		return 0;
-
-	stat_len = 3;
-	pvc = hdlc->first_pvc;
-
-	while (pvc) {
-		pvc->newstate = 0;
-		pvc = pvc->next;
-	}
-
-	while (skb->len >= i + 2 + stat_len) {
-		u16 dlci;
-		u8 state = 0;
-
-		if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ?
-				     LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
-			return 1;
-		}
-		i++;
-
-		if (skb->data[i] != stat_len) {
-			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
-			       hdlc_to_name(hdlc), skb->data[i]);
-			return 1;
-		}
-		i++;
-
-		dlci = status_to_dlci(hdlc, skb->data+i, &state);
-		pvc = find_pvc(hdlc, dlci);
-
-		if (pvc)
-			pvc->newstate = state;
-		else if (state == PVC_STATE_NEW)
-			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
-			       hdlc_to_name(hdlc), dlci);
-
-		i += stat_len;
-	}
-
-	pvc = hdlc->first_pvc;
-
-	while (pvc) {
-		if (pvc->newstate == PVC_STATE_NEW)
-			pvc->newstate = PVC_STATE_ACTIVE;
-
-		pvc->newstate |= (pvc->state &
-				  ~(PVC_STATE_NEW|PVC_STATE_ACTIVE));
-		if (pvc->state != pvc->newstate) {
-			pvc->state = pvc->newstate;
-			fr_log_dlci_active(pvc);
-		}
-		pvc = pvc->next;
-	}
-
-	/* Next full report after N391 polls */
-	hdlc->lmi.N391cnt = hdlc->lmi.N391;
-
-	return 0;
-}
-
-
-
-static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb)
-{
-	fr_hdr *fh = (fr_hdr*)skb->data;
-	u8 *data = skb->data;
-	u16 dlci;
-	pvc_device *pvc;
-
-	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
-		goto rx_error;
-
-	dlci = q922_to_dlci(skb->data);
-
-	if (dlci == LMI_DLCI) {
-		if (data[3] == LMI_PROTO) {
-			if (fr_lmi_recv(hdlc, skb))
-				goto rx_error;
-			else {
-				/* No request pending */
-				hdlc->lmi.state &= ~LINK_STATE_REQUEST;
-				hdlc->lmi.last_poll = jiffies;
-				dev_kfree_skb_any(skb);
-				return;
-			}
-		}
-
-		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
-		       hdlc_to_name(hdlc));
-		goto rx_error;
-	}
-
-	pvc = find_pvc(hdlc, dlci);
-	if (!pvc) {
-#ifdef DEBUG_PKT
-		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
-		       hdlc_to_name(hdlc), dlci);
-#endif
-		goto rx_error;
-	}
-
-	if ((pvc->netdev.flags & IFF_UP) == 0) {
-#ifdef DEBUG_PKT
-		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
-		       hdlc_to_name(hdlc), dlci);
-#endif
-		goto rx_error;
-	}
-
-	pvc->stats.rx_packets++; /* PVC traffic */
-	pvc->stats.rx_bytes += skb->len;
-
-	if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) {
-#ifdef DEBUG_FECN
-		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
-		       fh->fecn ? "N" : "FF");
-#endif
-		pvc->state ^= PVC_STATE_FECN;
-	}
-
-	if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) {
-#ifdef DEBUG_FECN
-		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
-		       fh->becn ? "N" : "FF");
-#endif
-		pvc->state ^= PVC_STATE_BECN;
-	}
-
-	if (pvc->state & PVC_STATE_BECN)
-		pvc->stats.rx_compressed++;
-
-	if (data[3] == NLPID_IP) {
-		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
-		skb->protocol = htons(ETH_P_IP);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-
-	if (data[3] == NLPID_IPV6) {
-		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
-		skb->protocol = htons(ETH_P_IPV6);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD &&
-	    data[6] == FR_PAD && data[7] == FR_PAD &&
-	    ((data[8]<<8) | data[9]) == ETH_P_ARP) {
-		skb_pull(skb, 10);
-		skb->protocol = htons(ETH_P_ARP);
-		skb->dev = &pvc->netdev;
-		netif_rx(skb);
-		return;
-	}
-
-	printk(KERN_INFO "%s: Unusupported protocol %x\n",
-	       hdlc_to_name(hdlc), data[3]);
-	dev_kfree_skb_any(skb);
-	return;
-
- rx_error:
-	hdlc->stats.rx_errors++; /* Mark error */
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static void fr_cisco_open(hdlc_device *hdlc)
-{
-	hdlc->lmi.state = LINK_STATE_CHANGED;
-	hdlc->lmi.txseq = hdlc->lmi.rxseq = 0;
-	hdlc->lmi.last_errors = 0xFFFFFFFF;
-	hdlc->lmi.N391cnt = 0;
-
-	init_timer(&hdlc->timer);
-	hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */
-	hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer;
-	hdlc->timer.data = (unsigned long)hdlc;
-	add_timer(&hdlc->timer);
-}
-
-
-
-static void fr_cisco_close(hdlc_device *hdlc)
-{
-	pvc_device *pvc = hdlc->first_pvc;
-
-	del_timer_sync(&hdlc->timer);
-
-	while(pvc) {		/* NULL in Cisco mode */
-		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
-		pvc = pvc->next;
-	}
-}
-
-
-
-/******************************************************************
- *
- *     generic HDLC routines
- *
- *****************************************************************/
-
-
-
-static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-
-
-/********************************************************
- *
- * PVC device routines
- *
- *******************************************************/
-
-static int pvc_open(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	int result = 0;
-
-	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
-		return -EIO;  /* Master must be UP in order to activate PVC */
-
-	memset(&(pvc->stats), 0, sizeof(struct net_device_stats));
-	pvc->state = 0;
-
-	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc)
-		result = pvc->master->open_pvc(pvc);
-	if (result)
-		return result;
-
-	pvc->master->lmi.state |= LINK_STATE_CHANGED;
-	return 0;
-}
-
-
-
-static int pvc_close(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	pvc->state = 0;
-
-	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc)
-		pvc->master->close_pvc(pvc);
-
-	pvc->master->lmi.state |= LINK_STATE_CHANGED;
-	return 0;
-}
-
-
-
-static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-
-	if (pvc->state & PVC_STATE_ACTIVE) {
-		skb->dev = hdlc_to_dev(pvc->master);
-		pvc->stats.tx_bytes += skb->len;
-		pvc->stats.tx_packets++;
-		if (pvc->state & PVC_STATE_FECN)
-			pvc->stats.tx_compressed++; /* TX Congestion counter */
-		dev_queue_xmit(skb);
-	} else {
-		pvc->stats.tx_dropped++;
-		dev_kfree_skb(skb);
-	}
-
-	return 0;
-}
-
-
-
-static struct net_device_stats *pvc_get_stats(struct net_device *dev)
-{
-	pvc_device *pvc = dev_to_pvc(dev);
-	return &pvc->stats;
-}
-
-
-
-static int pvc_change_mtu(struct net_device *dev, int new_mtu)
-{
-	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
-		return -EINVAL;
-	dev->mtu = new_mtu;
-	return 0;
-}
-
-
-
-static void destroy_pvc_list(hdlc_device *hdlc)
-{
-	pvc_device *pvc = hdlc->first_pvc;
-	while(pvc) {
-		pvc_device *next = pvc->next;
-		unregister_netdevice(&pvc->netdev);
-		kfree(pvc);
-		pvc = next;
-	}
-
-	hdlc->first_pvc = NULL;	/* All PVCs destroyed */
-	hdlc->pvc_count = 0;
-	hdlc->lmi.state |= LINK_STATE_CHANGED;
-}
-
-
-
-/********************************************************
- *
- * X.25 protocol support routines
- *
- *******************************************************/
-
-#ifdef CONFIG_HDLC_X25
-/* These functions are callbacks called by LAPB layer */
-
-void x25_connect_disconnect(void *token, int reason, int code)
-{
-	hdlc_device *hdlc = token;
-	struct sk_buff *skb;
-	unsigned char *ptr;
-
-	if ((skb = dev_alloc_skb(1)) == NULL) {
-		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
-		return;
-	}
-
-	ptr = skb_put(skb, 1);
-	*ptr = code;
-
-	skb->dev = hdlc_to_dev(hdlc);
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	netif_rx(skb);
-}
-
-void x25_connected(void *token, int reason)
-{
-	x25_connect_disconnect(token, reason, 1);
-}
-
-void x25_disconnected(void *token, int reason)
-{
-	x25_connect_disconnect(token, reason, 2);
-}
-
-
-int x25_data_indication(void *token, struct sk_buff *skb)
-{
-	hdlc_device *hdlc = token;
-	unsigned char *ptr;
-
-	ptr = skb_push(skb, 1);
-	*ptr = 0;
-
-	skb->dev = hdlc_to_dev(hdlc);
-	skb->protocol = htons(ETH_P_X25);
-	skb->mac.raw = skb->data;
-	skb->pkt_type = PACKET_HOST;
-
-	return netif_rx(skb);
-}
-
-
-void x25_data_transmit(void *token, struct sk_buff *skb)
-{
-	hdlc_device *hdlc = token;
-	hdlc->xmit(hdlc, skb);	/* Ignore return value :-( */
-}
-#endif /* CONFIG_HDLC_X25 */
-
-
-/********************************************************
- *
- * HDLC device routines
- *
- *******************************************************/
-
-static int hdlc_open(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-	int result;
-
-	if (hdlc->mode == MODE_NONE)
-		return -ENOSYS;
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
-	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-		fr_cisco_open(hdlc);
-#ifdef CONFIG_HDLC_PPP
-	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-		sppp_attach(&hdlc->pppdev);
-		/* sppp_attach nukes them. We don't need syncppp's ioctl */
-		dev->do_ioctl = hdlc_ioctl;
-		hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO;
-		dev->type = ARPHRD_PPP;
-		result = sppp_open(dev);
-		if (result) {
-			sppp_detach(dev);
-			return result;
-		}
-	}
-#endif
-#ifdef CONFIG_HDLC_X25
-	else if (mode_is(hdlc, MODE_X25)) {
-		struct lapb_register_struct cb;
-
-		cb.connect_confirmation = x25_connected;
-		cb.connect_indication = x25_connected;
-		cb.disconnect_confirmation = x25_disconnected;
-		cb.disconnect_indication = x25_disconnected;
-		cb.data_indication = x25_data_indication;
-		cb.data_transmit = x25_data_transmit;
-
-		result = lapb_register(hdlc, &cb);
-		if (result != LAPB_OK)
-			return result;
-	}
-#endif
-	result = hdlc->open(hdlc);
-	if (result) {
-		if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-		    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-			fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
-		else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-			sppp_close(dev);
-			sppp_detach(dev);
-			dev->rebuild_header = NULL;
-			dev->change_mtu = hdlc_change_mtu;
-			dev->mtu = HDLC_MAX_MTU;
-			dev->hard_header_len = 16;
-		}
-#endif
-#ifdef CONFIG_HDLC_X25
-		else if (mode_is(hdlc, MODE_X25))
-			lapb_unregister(hdlc);
-#endif
-	}
-
-	return result;
-}
-
-
-
-static int hdlc_close(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	hdlc->close(hdlc);
-
-	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
-	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
-		fr_cisco_close(hdlc);
-#ifdef CONFIG_HDLC_PPP
-	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
-		sppp_close(dev);
-		sppp_detach(dev);
-		dev->rebuild_header = NULL;
-		dev->change_mtu = hdlc_change_mtu;
-		dev->mtu = HDLC_MAX_MTU;
-		dev->hard_header_len = 16;
-	}
-#endif
-#ifdef CONFIG_HDLC_X25
-	else if (mode_is(hdlc, MODE_X25))
-		lapb_unregister(hdlc);
-#endif
-	return 0;
-}
-
-
-
-static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-#ifdef CONFIG_HDLC_X25
-	if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) {
-		int result;
-
-
-		/* X.25 to LAPB */
-		switch (skb->data[0]) {
-		case 0:		/* Data to be transmitted */
-			skb_pull(skb, 1);
-			if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
-				dev_kfree_skb(skb);
-			return 0;
-
-		case 1:
-			if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
-				if (result == LAPB_CONNECTED) {
-				/* Send connect confirm. msg to level 3 */
-					x25_connected(hdlc, 0);
-				} else {
-					printk(KERN_ERR "%s: LAPB connect "
-					       "request failed, error code = "
-					       "%i\n", hdlc_to_name(hdlc),
-					       result);
-				}
-			}
-			break;
-
-		case 2:
-			if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) {
-				if (result == LAPB_NOTCONNECTED) {
-				/* Send disconnect confirm. msg to level 3 */
-					x25_disconnected(hdlc, 0);
-				} else {
-					printk(KERN_ERR "%s: LAPB disconnect "
-					       "request failed, error code = "
-					       "%i\n", hdlc_to_name(hdlc),
-					       result);
-				}
-			}
-			break;
-
-		default:
-			/* to be defined */
-			break;
-		}
-
-		dev_kfree_skb(skb);
-		return 0;
-	} /* MODE_X25 */
-#endif /* CONFIG_HDLC_X25 */
-
-	return hdlc->xmit(hdlc, skb);
-}
-
-
-
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb)
-{
-/* skb contains raw HDLC frame, in both hard- and software modes */
-	skb->mac.raw = skb->data;
-
-	switch(hdlc->mode & MODE_MASK) {
-	case MODE_HDLC:
-		skb->protocol = htons(ETH_P_IP);
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-		return;
-
-	case MODE_FR:
-		fr_netif(hdlc, skb);
-		return;
-
-	case MODE_CISCO:
-		cisco_netif(hdlc, skb);
-		return;
-
-#ifdef CONFIG_HDLC_PPP
-	case MODE_PPP:
-#if 0
-		sppp_input(hdlc_to_dev(hdlc), skb);
-#else
-		skb->protocol = htons(ETH_P_WAN_PPP);
-		skb->dev = hdlc_to_dev(hdlc);
-		netif_rx(skb);
-#endif
-		return;
-#endif
-#ifdef CONFIG_HDLC_X25
-	case MODE_X25:
-		skb->dev = hdlc_to_dev(hdlc);
-		if (lapb_data_received(hdlc, skb) == LAPB_OK)
-			return;
-		break;
-#endif
-	}
-
-	hdlc->stats.rx_errors++;
-	dev_kfree_skb_any(skb);
-}
-
-
-
-static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
-{
-	return &dev_to_hdlc(dev)->stats;
-}
-
-
-
-static int hdlc_set_mode(hdlc_device *hdlc, int mode)
-{
-	int result = -1;	/* Default to soft modes */
-	struct net_device *dev = hdlc_to_dev(hdlc);
-
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if(dev->flags & IFF_UP)
-		return -EBUSY;
-
-	dev->addr_len = 0;
-	dev->hard_header = NULL;
-	hdlc->mode = MODE_NONE;
-
-	if (!(mode & MODE_SOFT))
-		switch(mode & MODE_MASK) {
-		case MODE_HDLC:
-			result = hdlc->set_mode ?
-				hdlc->set_mode(hdlc, MODE_HDLC) : 0;
-			break;
-
-		case MODE_CISCO: /* By card */
-#ifdef CONFIG_HDLC_PPP
-		case MODE_PPP:
-#endif
-#ifdef CONFIG_HDLC_X25
-		case MODE_X25:
-#endif
-		case MODE_FR:
-			result = hdlc->set_mode ?
-				hdlc->set_mode(hdlc, mode) : -ENOSYS;
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-	if (result) {
-		mode |= MODE_SOFT; /* Try "host software" protocol */
-
-		switch(mode & MODE_MASK) {
-		case MODE_CISCO:
-			dev->hard_header = cisco_hard_header;
-			break;
-
-#ifdef CONFIG_HDLC_PPP
-		case MODE_PPP:
-			break;
-#endif
-#ifdef CONFIG_HDLC_X25
-		case MODE_X25:
-			break;
-#endif
-
-		case MODE_FR:
-			dev->hard_header = fr_hard_header;
-			dev->addr_len = 2;
-			*(u16*)dev->dev_addr = htons(LMI_DLCI);
-			dlci_to_q922(dev->broadcast, LMI_DLCI);
-			break;
-
-		default:
-			return -EINVAL;
-		}
-
-		result = hdlc->set_mode ?
-			hdlc->set_mode(hdlc, MODE_HDLC) : 0;
-	}
-
-	if (result)
-		return result;
-
-	hdlc->mode = mode;
-	switch(mode & MODE_MASK) {
-#ifdef CONFIG_HDLC_PPP
-	case MODE_PPP:   dev->type = ARPHRD_PPP;   break;
-#endif
-#ifdef CONFIG_HDLC_X25
-	case MODE_X25:   dev->type = ARPHRD_X25;   break;
-#endif
-	case MODE_FR:    dev->type = ARPHRD_FRAD;  break;
-	case MODE_CISCO: dev->type = ARPHRD_CISCO; break;
-	default:         dev->type = ARPHRD_RAWHDLC;
-	}
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-	destroy_pvc_list(hdlc);
-	return 0;
-}
-
-
-
-static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci)
-{
-	pvc_device **pvc_p = &hdlc->first_pvc;
-	pvc_device *pvc;
-	int result, create = 1;	/* Create or delete PVC */
-
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	if(dlci<0) {
-		dlci = -dlci;
-		create = 0;
-	}
-
-	if(dlci <= 0 || dlci >= 1024)
-		return -EINVAL;	/* Only 10 bits for DLCI, DLCI=0 is reserved */
-
-	if(!mode_is(hdlc, MODE_FR))
-		return -EINVAL;	/* Only meaningfull on FR */
-
-	while(*pvc_p) {
-		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
-			break;
-		pvc_p = &(*pvc_p)->next;
-	}
-
-	if (create) {		/* Create PVC */
-		if (*pvc_p != NULL)
-			return -EEXIST;
-
-		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
-		if (!pvc) {
-			printk(KERN_WARNING "%s: Memory squeeze on "
-			       "hdlc_fr_pvc()\n", hdlc_to_name(hdlc));
-			return -ENOBUFS;
-		}
-		memset(pvc, 0, sizeof(pvc_device));
-
-		pvc->netdev.hard_start_xmit = pvc_xmit;
-		pvc->netdev.get_stats = pvc_get_stats;
-		pvc->netdev.open = pvc_open;
-		pvc->netdev.stop = pvc_close;
-		pvc->netdev.change_mtu = pvc_change_mtu;
-		pvc->netdev.mtu = HDLC_MAX_MTU;
-
-		pvc->netdev.type = ARPHRD_DLCI;
-		pvc->netdev.hard_header_len = 16;
-		pvc->netdev.hard_header = fr_hard_header;
-		pvc->netdev.tx_queue_len = 0;
-		pvc->netdev.flags = IFF_POINTOPOINT;
-
-		pvc->master = hdlc;
-		*(u16*)pvc->netdev.dev_addr = htons(dlci);
-		dlci_to_q922(pvc->netdev.broadcast, dlci);
-		pvc->netdev.addr_len = 2;
-		pvc->netdev.irq = hdlc_to_dev(hdlc)->irq;
-
-		result = dev_alloc_name(&pvc->netdev, "pvc%d");
-		if (result < 0) {
-			kfree(pvc);
-			*pvc_p = NULL;
-			return result;
-		}
-
-		if (register_netdevice(&pvc->netdev) != 0) {
-			kfree(pvc);
-			*pvc_p = NULL;
-			return -EIO;
-		}
-
-		if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) {
-			result = hdlc->create_pvc(pvc);
-			if (result) {
-				unregister_netdevice(&pvc->netdev);
-				kfree(pvc);
-				*pvc_p = NULL;
-				return result;
-			}
-		}
-
-		hdlc->lmi.state |= LINK_STATE_CHANGED;
-		hdlc->pvc_count++;
-		return 0;
-	}
-
-	if (*pvc_p == NULL)		/* Delete PVC */
-		return -ENOENT;
-
-	pvc = *pvc_p;
-
-	if (pvc->netdev.flags & IFF_UP)
-		return -EBUSY;		/* PVC in use */
-
-	if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc)
-		hdlc->destroy_pvc(pvc);
-
-	hdlc->lmi.state |= LINK_STATE_CHANGED;
-	hdlc->pvc_count--;
-	*pvc_p = pvc->next;
-	unregister_netdevice(&pvc->netdev);
-	kfree(pvc);
-	return 0;
-}
-
-
-
-static int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	switch(cmd) {
-	case HDLCGMODE:
-		ifr->ifr_ifru.ifru_ivalue = hdlc->mode;
-		return 0;
-
-	case HDLCSMODE:
-		return hdlc_set_mode(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
-	case HDLCPVC:
-		return hdlc_fr_pvc(hdlc, ifr->ifr_ifru.ifru_ivalue);
-
-	default:
-		if (hdlc->ioctl != NULL)
-			return hdlc->ioctl(hdlc, ifr, cmd);
-	}
-
-	return -EINVAL;
-}
-
-
-
-static int hdlc_init(struct net_device *dev)
-{
-	hdlc_device *hdlc = dev_to_hdlc(dev);
-
-	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
-
-	dev->get_stats = hdlc_get_stats;
-	dev->open = hdlc_open;
-	dev->stop = hdlc_close;
-	dev->hard_start_xmit = hdlc_xmit;
-	dev->do_ioctl = hdlc_ioctl;
-	dev->change_mtu = hdlc_change_mtu;
-	dev->mtu = HDLC_MAX_MTU;
-
-	dev->type = ARPHRD_RAWHDLC;
-	dev->hard_header_len = 16;
-
-	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
-	return 0;
-}
-
-
-
-int register_hdlc_device(hdlc_device *hdlc)
-{
-	int result;
-	struct net_device *dev = hdlc_to_dev(hdlc);
-
-	dev->init = hdlc_init;
-	dev->priv = &hdlc->syncppp_ptr;
-	hdlc->syncppp_ptr = &hdlc->pppdev;
-	hdlc->pppdev.dev = dev;
-	hdlc->mode = MODE_NONE;
-	hdlc->lmi.T391 = 10;	/* polling verification timer */
-	hdlc->lmi.T392 = 15;	/* link integrity verification polling timer */
-	hdlc->lmi.N391 = 6;	/* full status polling counter */
-	hdlc->lmi.N392 = 3;	/* error threshold */
-	hdlc->lmi.N393 = 4;	/* monitored events count */
-
-	result = dev_alloc_name(dev, "hdlc%d");
-	if (result<0)
-		return result;
-
-	result = register_netdev(dev);
-	if (result != 0)
-		return -EIO;
-
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-
-
-void unregister_hdlc_device(hdlc_device *hdlc)
-{
-	destroy_pvc_list(hdlc);
-	unregister_netdev(hdlc_to_dev(hdlc));
-	MOD_DEC_USE_COUNT;
-}
-
-MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
-MODULE_DESCRIPTION("HDLC support module");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(hdlc_netif_rx);
-EXPORT_SYMBOL(register_hdlc_device);
-EXPORT_SYMBOL(unregister_hdlc_device);
-
-static int __init hdlc_module_init(void)
-{
-	printk(KERN_INFO "%s\n", version);
-	return 0;
-}
-
-
-module_init(hdlc_module_init);
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_cisco.c linux-2.5.6/drivers/net/wan/hdlc_cisco.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_cisco.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_cisco.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,293 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Cisco HDLC support
+ *
+ * Copyright (C) 2000 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+#define CISCO_MULTICAST		0x8F	/* Cisco multicast address */
+#define CISCO_UNICAST		0x0F	/* Cisco unicast address */
+#define CISCO_KEEPALIVE		0x8035	/* Cisco keepalive protocol */
+#define CISCO_SYS_INFO		0x2000	/* Cisco interface/system info */
+#define CISCO_ADDR_REQ		0	/* Cisco address request */
+#define CISCO_ADDR_REPLY	1	/* Cisco address reply */
+#define CISCO_KEEPALIVE_REQ	2	/* Cisco keepalive request */
+
+
+static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
+			     u16 type, void *daddr, void *saddr,
+			     unsigned int len)
+{
+	hdlc_header *data;
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
+#endif
+
+	skb_push(skb, sizeof(hdlc_header));
+	data = (hdlc_header*)skb->data;
+	if (type == CISCO_KEEPALIVE)
+		data->address = CISCO_MULTICAST;
+	else
+		data->address = CISCO_UNICAST;
+	data->control = 0;
+	data->protocol = htons(type);
+
+	return sizeof(hdlc_header);
+}
+
+
+
+static void cisco_keepalive_send(hdlc_device *hdlc, u32 type,
+				 u32 par1, u32 par2)
+{
+	struct sk_buff *skb;
+	cisco_packet *data;
+
+	skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+	if (!skb) {
+		printk(KERN_WARNING
+		       "%s: Memory squeeze on cisco_keepalive_send()\n",
+		       hdlc_to_name(hdlc));
+		return;
+	}
+	skb_reserve(skb, 4);
+	cisco_hard_header(skb, hdlc_to_dev(hdlc), CISCO_KEEPALIVE,
+			  NULL, NULL, 0);
+	data = (cisco_packet*)skb->tail;
+
+	data->type = htonl(type);
+	data->par1 = htonl(par1);
+	data->par2 = htonl(par2);
+	data->rel = 0xFFFF;
+	data->time = htonl(jiffies * 1000 / HZ);
+
+	skb_put(skb, sizeof(cisco_packet));
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void cisco_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	hdlc_header *data = (hdlc_header*)skb->data;
+	cisco_packet *cisco_data;
+	struct in_device *in_dev;
+	u32 addr, mask;
+
+	if (skb->len < sizeof(hdlc_header))
+		goto rx_error;
+
+	if (data->address != CISCO_MULTICAST &&
+	    data->address != CISCO_UNICAST)
+		goto rx_error;
+
+	skb_pull(skb, sizeof(hdlc_header));
+
+	switch(ntohs(data->protocol)) {
+	case ETH_P_IP:
+	case ETH_P_IPX:
+	case ETH_P_IPV6:
+		skb->protocol = data->protocol;
+		skb->dev = hdlc_to_dev(hdlc);
+		netif_rx(skb);
+		return;
+
+	case CISCO_SYS_INFO:
+		/* Packet is not needed, drop it. */
+		dev_kfree_skb_any(skb);
+		return;
+
+	case CISCO_KEEPALIVE:
+		if (skb->len != CISCO_PACKET_LEN &&
+		    skb->len != CISCO_BIG_PACKET_LEN) {
+			printk(KERN_INFO "%s: Invalid length of Cisco "
+			       "control packet (%d bytes)\n",
+			       hdlc_to_name(hdlc), skb->len);
+			goto rx_error;
+		}
+
+		cisco_data = (cisco_packet*)skb->data;
+
+		switch(ntohl (cisco_data->type)) {
+		case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
+			in_dev = hdlc_to_dev(hdlc)->ip_ptr;
+			addr = 0;
+			mask = ~0; /* is the mask correct? */
+
+			if (in_dev != NULL) {
+				struct in_ifaddr **ifap = &in_dev->ifa_list;
+
+				while (*ifap != NULL) {
+					if (strcmp(hdlc_to_name(hdlc),
+						   (*ifap)->ifa_label) == 0) {
+						addr = (*ifap)->ifa_local;
+						mask = (*ifap)->ifa_mask;
+						break;
+					}
+					ifap = &(*ifap)->ifa_next;
+				}
+
+				cisco_keepalive_send(hdlc, CISCO_ADDR_REPLY,
+						     addr, mask);
+			}
+			dev_kfree_skb_any(skb);
+			return;
+
+		case CISCO_ADDR_REPLY:
+			printk(KERN_INFO "%s: Unexpected Cisco IP address "
+			       "reply\n", hdlc_to_name(hdlc));
+			goto rx_error;
+
+		case CISCO_KEEPALIVE_REQ:
+			hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
+			if (ntohl(cisco_data->par2) == hdlc->state.cisco.txseq) {
+				hdlc->state.cisco.last_poll = jiffies;
+				if (!hdlc->state.cisco.up) {
+					u32 sec, min, hrs, days;
+					sec = ntohl(cisco_data->time) / 1000;
+					min = sec / 60; sec -= min * 60;
+					hrs = min / 60; min -= hrs * 60;
+					days = hrs / 24; hrs -= days * 24;
+					printk(KERN_INFO "%s: Link up (peer "
+					       "uptime %ud%uh%um%us)\n",
+					       hdlc_to_name(hdlc), days, hrs,
+					       min, sec);
+				}
+				hdlc->state.cisco.up = 1;
+			}
+
+			dev_kfree_skb_any(skb);
+			return;
+		} /* switch(keepalive type) */
+	} /* switch(protocol) */
+
+	printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc_to_name(hdlc),
+	       data->protocol);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static void cisco_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+
+	if (hdlc->state.cisco.up &&
+	    jiffies - hdlc->state.cisco.last_poll >=
+	    hdlc->state.cisco.settings.timeout * HZ) {
+		hdlc->state.cisco.up = 0;
+		printk(KERN_INFO "%s: Link down\n", hdlc_to_name(hdlc));
+	}
+
+	cisco_keepalive_send(hdlc, CISCO_KEEPALIVE_REQ,
+			     ++hdlc->state.cisco.txseq,
+			     hdlc->state.cisco.rxseq);
+	hdlc->state.cisco.timer.expires = jiffies +
+		hdlc->state.cisco.settings.interval * HZ;
+	hdlc->state.cisco.timer.function = cisco_timer;
+	hdlc->state.cisco.timer.data = arg;
+	add_timer(&hdlc->state.cisco.timer);
+}
+
+
+
+static int cisco_open(hdlc_device *hdlc)
+{
+	hdlc->state.cisco.last_poll = 0;
+	hdlc->state.cisco.up = 0;
+	hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
+
+	init_timer(&hdlc->state.cisco.timer);
+	hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
+	hdlc->state.cisco.timer.function = cisco_timer;
+	hdlc->state.cisco.timer.data = (unsigned long)hdlc;
+	add_timer(&hdlc->state.cisco.timer);
+	return 0;
+}
+
+
+
+static void cisco_close(hdlc_device *hdlc)
+{
+	del_timer_sync(&hdlc->state.cisco.timer);
+}
+
+
+
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	cisco_proto *cisco_s = &ifr->ifr_settings->ifs_hdlc.cisco;
+	const size_t size = sizeof(cisco_proto);
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings->type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings->type = IF_PROTO_CISCO;
+		if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_CISCO:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&hdlc->state.cisco.settings, cisco_s, size))
+			return -EFAULT;
+
+		/* FIXME - put sanity checks here */
+		hdlc_detach(hdlc);
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result) {
+			hdlc->proto = -1;
+			return result;
+		}
+
+		hdlc->open = cisco_open;
+		hdlc->stop = cisco_close;
+		hdlc->netif_rx = cisco_rx;
+		hdlc->proto = IF_PROTO_CISCO;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = cisco_hard_header;
+		dev->type = ARPHRD_CISCO;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_fr.c linux-2.5.6/drivers/net/wan/hdlc_fr.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_fr.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_fr.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,842 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Frame Relay support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+__inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+{
+	pvc_device *pvc=hdlc->state.fr.first_pvc;
+	
+	while (pvc) {
+		if (netdev_dlci(&pvc->netdev) == dlci)
+			return pvc;
+		pvc = pvc->next;
+	}
+
+	return NULL;
+}
+
+
+
+__inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status,
+			      int *active, int *new)
+{
+	*new = (status[2] & 0x08);
+	*active = (!*new && (status[2] & 0x02));
+
+	return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
+}
+
+
+__inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+			       int active, int new)
+{
+	status[0] = (dlci>>4) & 0x3F;
+	status[1] = ((dlci<<3) & 0x78) | 0x80;
+	status[2] = 0x80;
+
+	if (new)
+		status[2] |= 0x08;
+	else if (active)
+		status[2] |= 0x02;
+}
+
+
+
+static int fr_hard_header(struct sk_buff *skb, struct net_device *dev,
+			  u16 type, void *daddr, void *saddr, unsigned int len)
+{
+	u16 head_len;
+
+	if (!daddr)
+		daddr = dev->broadcast;
+
+#ifdef CONFIG_HDLC_DEBUG_HARD_HEADER
+	printk(KERN_DEBUG "%s: fr_hard_header called\n", dev->name);
+#endif
+
+	switch(type) {
+	case ETH_P_IP:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IP;
+		break;
+
+	case ETH_P_IPV6:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = NLPID_IPV6;
+		break;
+
+	case LMI_PROTO:
+		head_len = 4;
+		skb_push(skb, head_len);
+		skb->data[3] = LMI_PROTO;
+		break;
+
+	default:
+		head_len = 10;
+		skb_push(skb, head_len);
+		skb->data[3] = FR_PAD;
+		skb->data[4] = NLPID_SNAP;
+		skb->data[5] = FR_PAD;
+		skb->data[6] = FR_PAD;
+		skb->data[7] = FR_PAD;
+		skb->data[8] = type>>8;
+		skb->data[9] = (u8)type;
+	}
+
+	memcpy(skb->data, daddr, 2);
+	skb->data[2] = FR_UI;
+
+	return head_len;
+}
+
+
+
+static int pvc_open(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+
+	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)
+		return -EIO;  /* Master must be UP in order to activate PVC */
+
+	if (pvc->master->state.fr.settings.lmi != LMI_NONE)
+		pvc->state.active = 0;
+	else
+		pvc->state.active = 1;
+
+	pvc->state.new = 0;
+	pvc->master->state.fr.changed = 1;
+	return 0;
+}
+
+
+
+static int pvc_close(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	pvc->state.active = pvc->state.new = 0;
+	pvc->master->state.fr.changed = 1;
+	return 0;
+}
+
+
+
+static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+
+	if (pvc->state.active) {
+		skb->dev = hdlc_to_dev(pvc->master);
+		pvc->stats.tx_bytes += skb->len;
+		pvc->stats.tx_packets++;
+		if (pvc->state.fecn)
+			pvc->stats.tx_compressed++; /* TX Congestion counter */
+		dev_queue_xmit(skb);
+	} else {
+		pvc->stats.tx_dropped++;
+		dev_kfree_skb(skb);
+	}
+
+	return 0;
+}
+
+
+
+static struct net_device_stats *pvc_get_stats(struct net_device *dev)
+{
+	pvc_device *pvc = dev_to_pvc(dev);
+	return &pvc->stats;
+}
+
+
+
+static int pvc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+static inline void fr_log_dlci_active(pvc_device *pvc)
+{
+	printk(KERN_INFO "%s: %sactive%s\n", pvc_to_name(pvc),
+	       pvc->state.active ? "" : "in",
+	       pvc->state.new ? " new" : "");
+}
+
+
+
+static inline u8 fr_lmi_nextseq(u8 x)
+{
+	x++;
+	return x ? x : 1;
+}
+
+
+
+static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
+{
+	struct sk_buff *skb;
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+	int len = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? LMI_ANSI_LENGTH
+		: LMI_LENGTH;
+	int stat_len = 3;
+	u8 *data;
+	int i = 0;
+
+	if (hdlc->state.fr.settings.dce && fullrep) {
+		len += hdlc->state.fr.pvc_count * (2 + stat_len);
+		if (len > HDLC_MAX_MTU) {
+			printk(KERN_WARNING "%s: Too many PVCs while sending "
+			       "LMI full report\n", hdlc_to_name(hdlc));
+			return;
+		}
+	}
+
+	skb = dev_alloc_skb(len);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Memory squeeze on fr_lmi_send()\n",
+			       hdlc_to_name(hdlc));
+		return;
+	}
+	memset(skb->data, 0, len);
+	skb_reserve(skb, 4);
+	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
+	data = skb->tail;
+	data[i++] = LMI_CALLREF;
+	data[i++] = hdlc->state.fr.settings.dce
+		? LMI_STATUS : LMI_STATUS_ENQUIRY;
+	if (hdlc->state.fr.settings.lmi == LMI_ANSI)
+		data[i++] = LMI_ANSI_LOCKSHIFT;
+	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+		? LMI_CCITT_REPTYPE : LMI_REPTYPE;
+	data[i++] = LMI_REPT_LEN;
+	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
+
+	data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+		? LMI_CCITT_ALIVE : LMI_ALIVE;
+	data[i++] = LMI_INTEG_LEN;
+	data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
+	data[i++] = hdlc->state.fr.rxseq;
+
+	if (hdlc->state.fr.settings.dce && fullrep) {
+		while (pvc) {
+			data[i++] = (hdlc->state.fr.settings.lmi == LMI_CCITT)
+				? LMI_CCITT_PVCSTAT : LMI_PVCSTAT;
+			data[i++] = stat_len;
+
+			if (hdlc->state.fr.reliable &&
+			    (pvc->netdev.flags & IFF_UP) &&
+			    !pvc->state.active &&
+			    !pvc->state.new) {
+				pvc->state.new = 1;
+				fr_log_dlci_active(pvc);
+			}
+
+			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
+				       data + i,
+				       pvc->state.active, pvc->state.new);
+			i += stat_len;
+			pvc = pvc->next;
+		}
+	}
+
+	skb_put(skb, i);
+	skb->priority = TC_PRIO_CONTROL;
+	skb->dev = hdlc_to_dev(hdlc);
+
+	dev_queue_xmit(skb);
+}
+
+
+
+static void fr_timer(unsigned long arg)
+{
+	hdlc_device *hdlc = (hdlc_device*)arg;
+	int i, cnt = 0, reliable;
+	u32 list;
+
+	if (hdlc->state.fr.settings.dce)
+		reliable = (jiffies - hdlc->state.fr.last_poll <
+			    hdlc->state.fr.settings.t392 * HZ);
+	else {
+		hdlc->state.fr.last_errors <<= 1; /* Shift the list */
+		if (hdlc->state.fr.request) {
+			if (hdlc->state.fr.reliable)
+				printk(KERN_INFO "%s: No LMI status reply "
+				       "received\n", hdlc_to_name(hdlc));
+			hdlc->state.fr.last_errors |= 1;
+		}
+
+		list = hdlc->state.fr.last_errors;
+		for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+			cnt += (list & 1);	/* errors count */
+
+		reliable = (cnt < hdlc->state.fr.settings.n392);
+	}
+
+	if (hdlc->state.fr.reliable != reliable) {
+		pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+		hdlc->state.fr.reliable = reliable;
+		printk(KERN_INFO "%s: Link %sreliable\n", hdlc_to_name(hdlc),
+		       reliable ? "" : "un");
+
+		if (reliable) {
+			hdlc->state.fr.n391cnt = 0; /* Request full status */
+			hdlc->state.fr.changed = 1;
+		} else {
+			while (pvc) {	/* Deactivate all PVCs */
+				pvc->state.new = pvc->state.active = 0;
+				pvc = pvc->next;
+			}
+		}
+	}
+
+	if (hdlc->state.fr.settings.dce)
+		hdlc->state.fr.timer.expires = jiffies +
+			hdlc->state.fr.settings.t392 * HZ;
+	else {
+		if (hdlc->state.fr.n391cnt)
+			hdlc->state.fr.n391cnt--;
+
+		fr_lmi_send(hdlc, hdlc->state.fr.n391cnt == 0);
+
+		hdlc->state.fr.request = 1;
+		hdlc->state.fr.timer.expires = jiffies +
+			hdlc->state.fr.settings.t391 * HZ;
+	}
+
+	hdlc->state.fr.timer.function = fr_timer;
+	hdlc->state.fr.timer.data = arg;
+	add_timer(&hdlc->state.fr.timer);
+}
+
+
+
+static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
+{
+	int stat_len;
+	pvc_device *pvc;
+	int reptype = -1, error;
+	u8 rxseq, txseq;
+	int i;
+
+	if (skb->len < ((hdlc->state.fr.settings.lmi == LMI_ANSI)
+			? LMI_ANSI_LENGTH : LMI_LENGTH)) {
+		printk(KERN_INFO "%s: Short LMI frame\n", hdlc_to_name(hdlc));
+		return 1;
+	}
+
+	if (skb->data[5] != (!hdlc->state.fr.settings.dce ?
+			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
+		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
+		       hdlc_to_name(hdlc), skb->data[2],
+		       hdlc->state.fr.settings.dce ? "enquiry" : "reply");
+		return 1;
+	}
+
+	i = (hdlc->state.fr.settings.lmi == LMI_ANSI) ? 7 : 6;
+
+	if (skb->data[i] !=
+	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+	     ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
+		printk(KERN_INFO "%s: Not a report type=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;				/* Skip length field */
+
+	reptype = skb->data[i++];
+
+	if (skb->data[i]!=
+	    ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+	     ? LMI_CCITT_ALIVE : LMI_ALIVE)) {
+		printk(KERN_INFO "%s: Unsupported status element=%x\n",
+		       hdlc_to_name(hdlc), skb->data[i]);
+		return 1;
+	}
+	i++;
+
+	i++;			/* Skip length field */
+
+	hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+	rxseq = skb->data[i++];	/* Should confirm our sequence */
+
+	txseq = hdlc->state.fr.txseq;
+
+	if (hdlc->state.fr.settings.dce) {
+		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {
+			printk(KERN_INFO "%s: Unsupported report type=%x\n",
+			       hdlc_to_name(hdlc), reptype);
+			return 1;
+		}
+	}
+
+	error = 0;
+	if (!hdlc->state.fr.reliable)
+		error = 1;
+
+	if (rxseq == 0 || rxseq != txseq) {
+		hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+		error = 1;
+	}
+
+	if (hdlc->state.fr.settings.dce) {
+		if (hdlc->state.fr.fullrep_sent && !error) {
+/* Stop sending full report - the last one has been confirmed by DTE */
+			hdlc->state.fr.fullrep_sent = 0;
+			pvc = hdlc->state.fr.first_pvc;
+			while (pvc) {
+				if (pvc->state.new) {
+					pvc->state.new = 0;
+					pvc->state.active = 1;
+					fr_log_dlci_active(pvc);
+
+/* Tell DTE that new PVC is now active */
+					hdlc->state.fr.changed = 1;
+				}
+				pvc = pvc->next;
+			}
+		}
+
+		if (hdlc->state.fr.changed) {
+			reptype = LMI_FULLREP;
+			hdlc->state.fr.fullrep_sent = 1;
+			hdlc->state.fr.changed = 0;
+		}
+
+		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);
+		return 0;
+	}
+
+	/* DTE */
+
+	if (reptype != LMI_FULLREP || error)
+		return 0;
+
+	stat_len = 3;
+	pvc = hdlc->state.fr.first_pvc;
+
+	while (pvc) {
+		pvc->state.deleted = pvc->state.active; /* mark active PVCs */
+		pvc = pvc->next;
+	}
+
+	while (skb->len >= i + 2 + stat_len) {
+		u16 dlci;
+		int active, new;
+
+		if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_CCITT)
+				     ? LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		if (skb->data[i] != stat_len) {
+			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
+			       hdlc_to_name(hdlc), skb->data[i]);
+			return 1;
+		}
+		i++;
+
+		dlci = status_to_dlci(hdlc, skb->data + i, &active, &new);
+		pvc = find_pvc(hdlc, dlci);
+
+		active |= new;
+		if (pvc) {
+			if (active && !pvc->state.active &&
+			    (pvc->netdev.flags & IFF_UP)) {
+				pvc->state.active = active;
+				fr_log_dlci_active(pvc);
+			}
+			pvc->state.deleted = 0;
+		}
+		else if (new)
+			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",
+			       hdlc_to_name(hdlc), dlci);
+
+		i += stat_len;
+	}
+
+	pvc = hdlc->state.fr.first_pvc;
+
+	while (pvc) {
+		if (pvc->state.deleted) {
+			pvc->state.active = pvc->state.new = 0;
+			fr_log_dlci_active(pvc);
+			pvc->state.deleted = 0;
+		}
+		pvc = pvc->next;
+	}
+
+	/* Next full report after N391 polls */
+	hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+
+	return 0;
+}
+
+
+
+static void fr_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+	fr_hdr *fh = (fr_hdr*)skb->data;
+	u8 *data = skb->data;
+	u16 dlci;
+	pvc_device *pvc;
+
+	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)
+		goto rx_error;
+
+	dlci = q922_to_dlci(skb->data);
+
+	if (dlci == LMI_DLCI) {
+		if (hdlc->state.fr.settings.lmi == LMI_NONE)
+			goto rx_error; /* LMI packet with no LMI? */
+
+		if (data[3] == LMI_PROTO) {
+			if (fr_lmi_recv(hdlc, skb))
+				goto rx_error;
+			else {
+				/* No request pending */
+				hdlc->state.fr.request = 0;
+				hdlc->state.fr.last_poll = jiffies;
+				dev_kfree_skb_any(skb);
+				return;
+			}
+		}
+
+		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+		       hdlc_to_name(hdlc));
+		goto rx_error;
+	}
+
+	pvc = find_pvc(hdlc, dlci);
+	if (!pvc) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	if ((pvc->netdev.flags & IFF_UP) == 0) {
+#ifdef CONFIG_HDLC_DEBUG_PKT
+		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",
+		       hdlc_to_name(hdlc), dlci);
+#endif
+		goto rx_error;
+	}
+
+	pvc->stats.rx_packets++; /* PVC traffic */
+	pvc->stats.rx_bytes += skb->len;
+
+	if (pvc->state.fecn != (fh->fecn ? PVC_STATE_FECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),
+		       fh->fecn ? "N" : "FF");
+#endif
+		pvc->state.fecn ^= 1;
+	}
+
+	if (pvc->state.becn != (fh->becn ? PVC_STATE_BECN : 0)) {
+#ifdef CONFIG_HDLC_DEBUG_ECN
+		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),
+		       fh->becn ? "N" : "FF");
+#endif
+		pvc->state.becn ^= 1;
+	}
+
+	if (pvc->state.becn)
+		pvc->stats.rx_compressed++;
+
+	skb->dev = &pvc->netdev;
+
+	if (data[3] == NLPID_IP) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IP);
+		netif_rx(skb);
+		return;
+	}
+
+
+	if (data[3] == NLPID_IPV6) {
+		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */
+		skb->protocol = htons(ETH_P_IPV6);
+		netif_rx(skb);
+		return;
+	}
+
+	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {
+		u16 oui = ntohl(*(u16*)(data + 6));
+		u16 pid = ntohl(*(u16*)(data + 8));
+		skb_pull(skb, 10);
+
+		switch ((((u32)oui) << 16) | pid) {
+		case ETH_P_ARP: /* routed frame with SNAP */
+		case ETH_P_IPX:
+			skb->protocol = htons(pid);
+			break;
+
+		default:
+			printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
+			       "PID=%x\n", hdlc_to_name(hdlc), oui, pid);
+			dev_kfree_skb_any(skb);
+			return;
+		}
+
+		netif_rx(skb);
+		return;
+	}
+
+	printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x\n",
+	       hdlc_to_name(hdlc), data[3]);
+	dev_kfree_skb_any(skb);
+	return;
+
+ rx_error:
+	hdlc->stats.rx_errors++; /* Mark error */
+	dev_kfree_skb_any(skb);
+}
+
+
+
+static int fr_open(hdlc_device *hdlc)
+{
+	if (hdlc->state.fr.settings.lmi != LMI_NONE) {
+		hdlc->state.fr.last_poll = 0;
+		hdlc->state.fr.reliable = 0;
+		hdlc->state.fr.changed = 1;
+		hdlc->state.fr.request = 0;
+		hdlc->state.fr.fullrep_sent = 0;
+		hdlc->state.fr.last_errors = 0xFFFFFFFF;
+		hdlc->state.fr.n391cnt = 0;
+		hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
+
+		init_timer(&hdlc->state.fr.timer);
+		/* First poll after 1 s */
+		hdlc->state.fr.timer.expires = jiffies + HZ;
+		hdlc->state.fr.timer.function = fr_timer;
+		hdlc->state.fr.timer.data = (unsigned long)hdlc;
+		add_timer(&hdlc->state.fr.timer);
+	} else
+		hdlc->state.fr.reliable = 1;
+
+	return 0;
+}
+
+
+
+static void fr_close(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+
+	if (hdlc->state.fr.settings.lmi != LMI_NONE)
+		del_timer_sync(&hdlc->state.fr.timer);
+
+	while(pvc) {
+		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */
+		pvc = pvc->next;
+	}
+}
+
+
+
+static int fr_pvc(hdlc_device *hdlc, unsigned int dlci, int create)
+{
+	pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+	pvc_device *pvc;
+	int result;
+
+	if(dlci <= 0 || dlci >= 1024)
+		return -EINVAL;	/* Only 10 bits for DLCI, DLCI 0 reserved */
+
+	while(*pvc_p) {
+		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)
+			break;
+		pvc_p = &(*pvc_p)->next;
+	}
+
+	if (create) {		/* Create PVC */
+		if (*pvc_p != NULL)
+			return -EEXIST;
+
+		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);
+		if (!pvc) {
+			printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
+			       hdlc_to_name(hdlc));
+			return -ENOBUFS;
+		}
+		memset(pvc, 0, sizeof(pvc_device));
+
+		pvc->netdev.hard_start_xmit = pvc_xmit;
+		pvc->netdev.get_stats = pvc_get_stats;
+		pvc->netdev.open = pvc_open;
+		pvc->netdev.stop = pvc_close;
+		pvc->netdev.change_mtu = pvc_change_mtu;
+		pvc->netdev.mtu = HDLC_MAX_MTU;
+
+		pvc->netdev.type = ARPHRD_DLCI;
+		pvc->netdev.hard_header_len = 16;
+		pvc->netdev.hard_header = fr_hard_header;
+		pvc->netdev.tx_queue_len = 0;
+		pvc->netdev.flags = IFF_POINTOPOINT;
+
+		pvc->master = hdlc;
+		*(u16*)pvc->netdev.dev_addr = htons(dlci);
+		dlci_to_q922(pvc->netdev.broadcast, dlci);
+		pvc->netdev.addr_len = 2;
+
+		result = dev_alloc_name(&pvc->netdev, "pvc%d");
+		if (result < 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return result;
+		}
+
+		if (register_netdevice(&pvc->netdev) != 0) {
+			kfree(pvc);
+			*pvc_p = NULL;
+			return -EIO;
+		}
+
+		hdlc->state.fr.changed = 1;
+		hdlc->state.fr.pvc_count++;
+		return 0;
+	}
+
+	if (*pvc_p == NULL)		/* Delete PVC */
+		return -ENOENT;
+
+	pvc = *pvc_p;
+
+	if (pvc->netdev.flags & IFF_UP)
+		return -EBUSY;		/* PVC in use */
+
+	hdlc->state.fr.changed = 1;
+	hdlc->state.fr.pvc_count--;
+	*pvc_p = pvc->next;
+	unregister_netdevice(&pvc->netdev);
+	kfree(pvc);
+	return 0;
+}
+
+
+
+static void fr_destroy(hdlc_device *hdlc)
+{
+	pvc_device *pvc = hdlc->state.fr.first_pvc;
+	while(pvc) {
+		pvc_device *next = pvc->next;
+		unregister_netdevice(&pvc->netdev);
+		kfree(pvc);
+		pvc = next;
+	}
+
+	hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
+	hdlc->state.fr.pvc_count = 0;
+	hdlc->state.fr.changed = 1;
+}
+
+
+
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	fr_proto *fr_s = &ifr->ifr_settings->ifs_hdlc.fr;
+	const size_t size = sizeof(fr_proto);
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	fr_proto_pvc pvc;
+	int result;
+
+	switch (ifr->ifr_settings->type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings->type = IF_PROTO_FR;
+		if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_FR:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&hdlc->state.fr.settings, fr_s, size))
+			return -EFAULT;
+
+		/* FIXME - put sanity checks here */
+		if (hdlc->proto != IF_PROTO_FR) {
+			hdlc_detach(hdlc);
+			hdlc->state.fr.first_pvc = NULL;
+			hdlc->state.fr.pvc_count = 0;
+		}
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result) {
+			hdlc->proto = -1;
+			return result;
+		}
+
+		hdlc->open = fr_open;
+		hdlc->stop = fr_close;
+		hdlc->netif_rx = fr_rx;
+		hdlc->detach = fr_destroy;
+		hdlc->proto = IF_PROTO_FR;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = fr_hard_header;
+		dev->type = ARPHRD_FRAD;
+		dev->addr_len = 2;
+		*(u16*)dev->dev_addr = htons(LMI_DLCI);
+		dlci_to_q922(dev->broadcast, LMI_DLCI);
+		return 0;
+
+	case IF_PROTO_FR_ADD_PVC:
+	case IF_PROTO_FR_DEL_PVC:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&pvc, &ifr->ifr_settings->ifs_hdlc.fr_pvc,
+				   sizeof(fr_proto_pvc)))
+			return -EFAULT;
+
+		return fr_pvc(hdlc, pvc.dlci,
+			      ifr->ifr_settings->type == IF_PROTO_FR_ADD_PVC);
+	}
+
+	return -EINVAL;
+}
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_generic.c linux-2.5.6/drivers/net/wan/hdlc_generic.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_generic.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_generic.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,188 @@
+/*
+ * Generic HDLC support routines for Linux
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Current status:
+ *    - this is work in progress
+ *    - not heavily tested on SMP
+ *    - currently supported:
+ *	* raw IP-in-HDLC
+ *	* Cisco HDLC
+ *	* Frame Relay with ANSI or CCITT LMI (both user and network side)
+ *	* PPP
+ *	* X.25
+ *
+ * Use sethdlc utility to set line parameters, protocol and PVCs
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static const char* version = "HDLC support module revision 1.08";
+
+
+static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+
+static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
+{
+	return &dev_to_hdlc(dev)->stats;
+}
+
+
+
+static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
+		    struct packet_type *p)
+{
+	dev_to_hdlc(dev)->netif_rx(skb);
+	return 0;
+}
+
+
+
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	unsigned int proto;
+
+	if (cmd != SIOCWANDEV)
+		return -EINVAL;
+
+	switch(ifr->ifr_settings->type) {
+	case IF_PROTO_HDLC:
+	case IF_PROTO_PPP:
+	case IF_PROTO_CISCO:
+	case IF_PROTO_FR:
+	case IF_PROTO_X25:
+		proto = ifr->ifr_settings->type;
+		break;
+
+	default:
+		proto = hdlc->proto;
+	}
+
+	switch(proto) {
+#ifdef CONFIG_HDLC_RAW
+	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_PPP
+	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_CISCO
+	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_FR
+	case IF_PROTO_FR:	return hdlc_fr_ioctl(hdlc, ifr);
+#endif
+#ifdef CONFIG_HDLC_X25
+	case IF_PROTO_X25:	return hdlc_x25_ioctl(hdlc, ifr);
+#endif
+	default:		return -ENOSYS;
+	}
+}
+
+
+
+int register_hdlc_device(hdlc_device *hdlc)
+{
+	int result;
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	dev->get_stats = hdlc_get_stats;
+	dev->change_mtu = hdlc_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+
+	dev->type = ARPHRD_RAWHDLC;
+	dev->hard_header_len = 16;
+
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+	hdlc->proto = -1;
+	hdlc->detach = NULL;
+
+	result = dev_alloc_name(dev, "hdlc%d");
+	if (result<0)
+		return result;
+
+	result = register_netdev(dev);
+	if (result != 0)
+		return -EIO;
+
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+
+void unregister_hdlc_device(hdlc_device *hdlc)
+{
+	hdlc_detach(hdlc);
+
+	unregister_netdev(hdlc_to_dev(hdlc));
+	MOD_DEC_USE_COUNT;
+}
+
+
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("HDLC support module");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(hdlc_ioctl);
+EXPORT_SYMBOL(register_hdlc_device);
+EXPORT_SYMBOL(unregister_hdlc_device);
+
+struct packet_type hdlc_packet_type=
+{
+        __constant_htons(ETH_P_HDLC),
+        NULL,
+        hdlc_rcv,
+        NULL,
+        NULL
+};
+
+
+static int __init hdlc_module_init(void)
+{
+	printk(KERN_INFO "%s\n", version);
+        dev_add_pack(&hdlc_packet_type);
+	return 0;
+}
+
+
+
+static void __exit hdlc_module_exit(void)
+{
+	dev_remove_pack(&hdlc_packet_type);
+}
+
+
+module_init(hdlc_module_init);
+module_exit(hdlc_module_exit);
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_ppp.c linux-2.5.6/drivers/net/wan/hdlc_ppp.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_ppp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_ppp.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,119 @@
+/*
+ * Generic HDLC support routines for Linux
+ * Point-to-point protocol support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static int ppp_open(hdlc_device *hdlc)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	void *old_ioctl;
+	int result;
+
+	dev->priv = &hdlc->state.ppp.syncppp_ptr;
+	hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
+	hdlc->state.ppp.pppdev.dev = dev;
+
+	old_ioctl = dev->do_ioctl;
+	hdlc->state.ppp.old_change_mtu = dev->change_mtu;
+	sppp_attach(&hdlc->state.ppp.pppdev);
+	/* sppp_attach nukes them. We don't need syncppp's ioctl */
+	dev->do_ioctl = old_ioctl;
+	hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+	dev->type = ARPHRD_PPP;
+	result = sppp_open(dev);
+	if (result) {
+		sppp_detach(dev);
+		return result;
+	}
+
+	return 0;
+}
+
+
+
+static void ppp_close(hdlc_device *hdlc)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+
+	sppp_close(dev);
+	sppp_detach(dev);
+	dev->rebuild_header = NULL;
+	dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+	dev->mtu = HDLC_MAX_MTU;
+	dev->hard_header_len = 16;
+}
+
+
+
+static void ppp_rx(struct sk_buff *skb)
+{
+	skb->protocol = htons(ETH_P_WAN_PPP);
+	netif_rx(skb);
+}
+
+
+
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings->type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings->type = IF_PROTO_PPP;
+		return 0; /* return protocol only, no settable parameters */
+
+	case IF_PROTO_PPP:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		/* no settable parameters */
+
+		hdlc_detach(hdlc);
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result) {
+			hdlc->proto = -1;
+			return result;
+		}
+
+		hdlc->open = ppp_open;
+		hdlc->stop = ppp_close;
+		hdlc->netif_rx = ppp_rx;
+		hdlc->proto = IF_PROTO_PPP;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_PPP;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_raw.c linux-2.5.6/drivers/net/wan/hdlc_raw.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_raw.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_raw.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,84 @@
+/*
+ * Generic HDLC support routines for Linux
+ * HDLC support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+
+static void raw_rx(struct sk_buff *skb)
+{
+	skb->protocol = htons(ETH_P_IP);
+	netif_rx(skb);
+}
+
+
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	raw_hdlc_proto *raw_s = &ifr->ifr_settings->ifs_hdlc.raw_hdlc;
+	const size_t size = sizeof(raw_hdlc_proto);
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings->type) {
+	case IF_GET_PROTO:
+		if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_PROTO_HDLC:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		if (copy_from_user(&hdlc->state.raw_hdlc.settings, raw_s, size))
+			return -EFAULT;
+
+
+		/* FIXME - put sanity checks here */
+		hdlc_detach(hdlc);
+
+		result=hdlc->attach(hdlc, hdlc->state.raw_hdlc.settings.encoding,
+				    hdlc->state.raw_hdlc.settings.parity);
+		if (result) {
+			hdlc->proto = -1;
+			return result;
+		}
+
+		hdlc->open = NULL;
+		hdlc->stop = NULL;
+		hdlc->netif_rx = raw_rx;
+		hdlc->proto = IF_PROTO_HDLC;
+		dev->hard_start_xmit = hdlc->xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_RAWHDLC;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -urN linux-2.5.6-pre3/drivers/net/wan/hdlc_x25.c linux-2.5.6/drivers/net/wan/hdlc_x25.c
--- linux-2.5.6-pre3/drivers/net/wan/hdlc_x25.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/drivers/net/wan/hdlc_x25.c	Thu Mar  7 18:24:48 2002
@@ -0,0 +1,219 @@
+/*
+ * Generic HDLC support routines for Linux
+ * X.25 support
+ *
+ * Copyright (C) 1999 - 2001 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/if_arp.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/pkt_sched.h>
+#include <linux/inetdevice.h>
+#include <linux/lapb.h>
+#include <linux/rtnetlink.h>
+#include <linux/hdlc.h>
+
+/* These functions are callbacks called by LAPB layer */
+
+static void x25_connect_disconnect(void *token, int reason, int code)
+{
+	hdlc_device *hdlc = token;
+	struct sk_buff *skb;
+	unsigned char *ptr;
+
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));
+		return;
+	}
+
+	ptr = skb_put(skb, 1);
+	*ptr = code;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	netif_rx(skb);
+}
+
+
+
+static void x25_connected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 1);
+}
+
+
+
+static void x25_disconnected(void *token, int reason)
+{
+	x25_connect_disconnect(token, reason, 2);
+}
+
+
+
+static int x25_data_indication(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	unsigned char *ptr;
+
+	ptr = skb_push(skb, 1);
+	*ptr = 0;
+
+	skb->dev = hdlc_to_dev(hdlc);
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
+
+	return netif_rx(skb);
+}
+
+
+
+static void x25_data_transmit(void *token, struct sk_buff *skb)
+{
+	hdlc_device *hdlc = token;
+	hdlc->xmit(skb, hdlc_to_dev(hdlc)); /* Ignore return value :-( */
+}
+
+
+
+static int x25_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	hdlc_device *hdlc = dev_to_hdlc(dev);
+	int result;
+
+
+	/* X.25 to LAPB */
+	switch (skb->data[0]) {
+	case 0:		/* Data to be transmitted */
+		skb_pull(skb, 1);
+		if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
+			dev_kfree_skb(skb);
+		return 0;
+
+	case 1:
+		if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
+			if (result == LAPB_CONNECTED)
+				/* Send connect confirm. msg to level 3 */
+				x25_connected(hdlc, 0);
+			else
+				printk(KERN_ERR "%s: LAPB connect request "
+				       "failed, error code = %i\n",
+				       hdlc_to_name(hdlc), result);
+		}
+		break;
+
+	case 2:
+		if ((result = lapb_disconnect_request(hdlc)) != LAPB_OK) {
+			if (result == LAPB_NOTCONNECTED)
+				/* Send disconnect confirm. msg to level 3 */
+				x25_disconnected(hdlc, 0);
+			else
+				printk(KERN_ERR "%s: LAPB disconnect request "
+				       "failed, error code = %i\n",
+				       hdlc_to_name(hdlc), result);
+		}
+		break;
+
+	default:		/* to be defined */
+		break;
+	}
+
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+
+
+static int x25_open(hdlc_device *hdlc)
+{
+	struct lapb_register_struct cb;
+	int result;
+
+	cb.connect_confirmation = x25_connected;
+	cb.connect_indication = x25_connected;
+	cb.disconnect_confirmation = x25_disconnected;
+	cb.disconnect_indication = x25_disconnected;
+	cb.data_indication = x25_data_indication;
+	cb.data_transmit = x25_data_transmit;
+
+	result = lapb_register(hdlc, &cb);
+	if (result != LAPB_OK)
+		return result;
+	return 0;
+}
+
+
+
+static void x25_close(hdlc_device *hdlc)
+{
+	lapb_unregister(hdlc);
+}
+
+
+
+static void x25_rx(struct sk_buff *skb)
+{
+	hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+
+	if (lapb_data_received(hdlc, skb) == LAPB_OK)
+		return;
+	hdlc->stats.rx_errors++;
+	dev_kfree_skb_any(skb);
+}
+
+
+
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr)
+{
+	struct net_device *dev = hdlc_to_dev(hdlc);
+	int result;
+
+	switch (ifr->ifr_settings->type) {
+	case IF_GET_PROTO:
+		ifr->ifr_settings->type = IF_PROTO_X25;
+		return 0; /* return protocol only, no settable parameters */
+
+	case IF_PROTO_X25:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if(dev->flags & IFF_UP)
+			return -EBUSY;
+
+		hdlc_detach(hdlc);
+
+		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+		if (result) {
+			hdlc->proto = -1;
+			return result;
+		}
+
+		hdlc->open = x25_open;
+		hdlc->stop = x25_close;
+		hdlc->netif_rx = x25_rx;
+		hdlc->proto = IF_PROTO_X25;
+		dev->hard_start_xmit = x25_xmit;
+		dev->hard_header = NULL;
+		dev->type = ARPHRD_X25;
+		dev->addr_len = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
diff -urN linux-2.5.6-pre3/drivers/net/wan/n2.c linux-2.5.6/drivers/net/wan/n2.c
--- linux-2.5.6-pre3/drivers/net/wan/n2.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/net/wan/n2.c	Thu Mar  7 18:24:48 2002
@@ -1,7 +1,7 @@
 /*
  * SDL Inc. RISCom/N2 synchronous serial card driver for Linux
  *
- * Copyright (C) 1998-2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1998-2001 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -17,6 +17,7 @@
  *    SDL Inc. PPP/HDLC/CISCO driver
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -33,10 +34,8 @@
 #include <asm/io.h>
 #include "hd64570.h"
 
-#define DEBUG_RINGS
-/* #define DEBUG_PKT */
 
-static const char* version = "SDL RISCom/N2 driver revision: 1.02 for Linux 2.4";
+static const char* version = "SDL RISCom/N2 driver version: 1.09";
 static const char* devname = "RISCom/N2";
 
 #define USE_WINDOWSIZE 16384
@@ -87,9 +86,9 @@
 	hdlc_device hdlc;	/* HDLC device struct - must be first */
 	struct card_s *card;
 	spinlock_t lock;	/* TX lock */
-	int clkmode;		/* clock mode */
-	int clkrate;		/* clock rate */
-	int line;		/* loopback only */
+	sync_serial_settings settings;
+	unsigned short encoding;
+	unsigned short parity;
 	u8 rxs, txs, tmc;	/* SCA registers */
 	u8 valid;		/* port enabled */
 	u8 phy_node;		/* physical port # - 0 or 1 */
@@ -116,6 +115,9 @@
 }card_t;
 
 
+static card_t *first_card;
+static card_t **new_card = &first_card;
+
 
 #define sca_reg(reg, card) (0x8000 | (card)->io | \
 			    ((reg) & 0x0F) | (((reg) & 0xF0) << 6))
@@ -157,7 +159,7 @@
 
 
 
-static int n2_set_clock(port_t *port, int value)
+static int n2_set_iface(port_t *port)
 {
 	card_t *card = port->card;
 	int io = card->io;
@@ -166,7 +168,7 @@
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
-	switch(value) {
+	switch(port->settings.clock_type) {
 	case CLOCK_EXT:
 		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
 		rxs |= CLK_LINE_RX; /* RXC input */
@@ -200,17 +202,22 @@
 	port->txs = txs;
 	sca_out(rxs, msci + RXS, card);
 	sca_out(txs, msci + TXS, card);
-	port->clkmode = value;
+	sca_set_port(port);
 	return 0;
 }
 
 
 
-static int n2_open(hdlc_device *hdlc)
+static int n2_open(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 	int io = port->card->io;
-	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
+	u8 mcr = inb(io + N2_MCR) | (port->phy_node ? TX422_PORT1:TX422_PORT0);
+
+	int result = hdlc_open(hdlc);
+	if (result)
+		return result;
 
 	MOD_INC_USE_COUNT;
 	mcr &= port->phy_node ? ~DTR_PORT1 : ~DTR_PORT0; /* set DTR ON */
@@ -219,14 +226,14 @@
 	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
 	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
 	sca_open(hdlc);
-	n2_set_clock(port, port->clkmode);
-	return 0;
+	return n2_set_iface(port);
 }
 
 
 
-static void n2_close(hdlc_device *hdlc)
+static int n2_close(struct net_device *dev)
 {
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 	int io = port->card->io;
 	u8 mcr = inb(io+N2_MCR) | (port->phy_node ? TX422_PORT1 : TX422_PORT0);
@@ -234,52 +241,48 @@
 	sca_close(hdlc);
 	mcr |= port->phy_node ? DTR_PORT1 : DTR_PORT0; /* set DTR OFF */
 	outb(mcr, io + N2_MCR);
+	hdlc_close(hdlc);
 	MOD_DEC_USE_COUNT;
+	return 0;
 }
 
 
 
-static int n2_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd)
+static int n2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-	int value = ifr->ifr_ifru.ifru_ivalue;
-	int result = 0;
+	union line_settings *line = &ifr->ifr_settings->ifs_line;
+	const size_t size = sizeof(sync_serial_settings);
+	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
-	if(!capable(CAP_NET_ADMIN))
-		return -EPERM;
-
-	switch(cmd) {
-	case HDLCSCLOCK:
-		result = n2_set_clock(port, value);
-	case HDLCGCLOCK:
-		value = port->clkmode;
-		break;
-
-	case HDLCSCLOCKRATE:
-		port->clkrate = value;
-		sca_set_clock(port);
-	case HDLCGCLOCKRATE:
-		value = port->clkrate;
-		break;
-
-	case HDLCSLINE:
-		result = sca_set_loopback(port, value);
-	case HDLCGLINE:
-		value = port->line;
-		break;
-
-#ifdef DEBUG_RINGS
-	case HDLCRUN:
+#ifdef CONFIG_HDLC_DEBUG_RINGS
+	if (cmd == SIOCDEVPRIVATE) {
 		sca_dump_rings(hdlc);
 		return 0;
-#endif /* DEBUG_RINGS */
+	}
+#endif
+	if (cmd != SIOCWANDEV)
+		return hdlc_ioctl(dev, ifr, cmd);
+
+	switch(ifr->ifr_settings->type) {
+	case IF_GET_IFACE:
+		ifr->ifr_settings->type = IF_IFACE_SYNC_SERIAL;
+		if (copy_to_user(&line->sync, &port->settings, size))
+			return -EFAULT;
+		return 0;
+
+	case IF_IFACE_SYNC_SERIAL:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (copy_from_user(&port->settings, &line->sync, size))
+			return -EFAULT;
+		/* FIXME - put sanity checks here */
+		return n2_set_iface(port);
 
 	default:
-		return -EINVAL;
+		return hdlc_ioctl(dev, ifr, cmd);
 	}
-
-	ifr->ifr_ifru.ifru_ivalue = value;
-	return result;
 }
 
 
@@ -465,6 +468,7 @@
 	sca_init(card, 0);
 	for (cnt = 0; cnt < 2; cnt++) {
 		port_t *port = &card->ports[cnt];
+		struct net_device *dev = hdlc_to_dev(&port->hdlc);
 
 		if ((cnt == 0 && !valid0) || (cnt == 1 && !valid1))
 			continue;
@@ -476,14 +480,16 @@
 			port->log_node = 1;
 
 		spin_lock_init(&port->lock);
-		hdlc_to_dev(&port->hdlc)->irq = irq;
-		hdlc_to_dev(&port->hdlc)->mem_start = winbase;
-		hdlc_to_dev(&port->hdlc)->mem_end = winbase + USE_WINDOWSIZE-1;
-		hdlc_to_dev(&port->hdlc)->tx_queue_len = 50;
-		port->hdlc.ioctl = n2_ioctl;
-		port->hdlc.open = n2_open;
-		port->hdlc.close = n2_close;
+		dev->irq = irq;
+		dev->mem_start = winbase;
+		dev->mem_end = winbase + USE_WINDOWSIZE-1;
+		dev->tx_queue_len = 50;
+		dev->do_ioctl = n2_ioctl;
+		dev->open = n2_open;
+		dev->stop = n2_close;
+		port->hdlc.attach = sca_attach;
 		port->hdlc.xmit = sca_xmit;
+		port->settings.clock_type = CLOCK_EXT;
 
 		if (register_hdlc_device(&port->hdlc)) {
 			printk(KERN_WARNING "n2: unable to register hdlc "
@@ -515,7 +521,7 @@
 		return -ENOSYS;	/* no parameters specified, abort */
 	}
 
-	printk(KERN_INFO "%s\n", version);
+	printk(KERN_INFO "%s (SCA-%s)\n", version, sca_version);
 
 	do {
 		unsigned long io, irq, ram;
diff -urN linux-2.5.6-pre3/drivers/net/wd.c linux-2.5.6/drivers/net/wd.c
--- linux-2.5.6-pre3/drivers/net/wd.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/drivers/net/wd.c	Thu Mar  7 18:24:48 2002
@@ -450,10 +450,11 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
 MODULE_PARM(mem_end, "1-" __MODULE_STRING(MAX_WD_CARDS) "i");
-MODULE_PARM_DESC(io, "WD80x3 I/O base address(es)");
-MODULE_PARM_DESC(irq, "WD80x3 IRQ number(s) (ignored for PureData boards)");
-MODULE_PARM_DESC(mem, "WD80x3 memory base address(es)(ignored for PureData boards)");
-MODULE_PARM_DESC(mem_end, "WD80x3 memory end address(es)");
+MODULE_PARM_DESC(io, "I/O base address(es)");
+MODULE_PARM_DESC(irq, "IRQ number(s) (ignored for PureData boards)");
+MODULE_PARM_DESC(mem, "memory base address(es)(ignored for PureData boards)");
+MODULE_PARM_DESC(mem_end, "memory end address(es)");
+MODULE_DESCRIPTION("ISA Western Digital wd8003/wd8013 ; SMC Elite, Elite16 ethernet driver");
 MODULE_LICENSE("GPL");
 
 /* This is set up so that only a single autoprobe takes place per call.
diff -urN linux-2.5.6-pre3/drivers/net/winbond-840.c linux-2.5.6/drivers/net/winbond-840.c
--- linux-2.5.6-pre3/drivers/net/winbond-840.c	Thu Mar  7 18:24:28 2002
+++ linux-2.5.6/drivers/net/winbond-840.c	Wed Dec 31 16:00:00 1969
@@ -1,1757 +0,0 @@
-/* winbond-840.c: A Linux PCI network adapter device driver. */
-/*
-	Written 1998-2001 by Donald Becker.
-
-	This software may be used and distributed according to the terms of
-	the GNU General Public License (GPL), incorporated herein by reference.
-	Drivers based on or derived from this code fall under the GPL and must
-	retain the authorship, copyright and license notice.  This file is not
-	a complete program and may only be used when the entire operating
-	system is licensed under the GPL.
-
-	The author may be reached as becker@scyld.com, or C/O
-	Scyld Computing Corporation
-	410 Severn Ave., Suite 210
-	Annapolis MD 21403
-
-	Support and updates available at
-	http://www.scyld.com/network/drivers.html
-
-	Do not remove the copyright infomation.
-	Do not change the version information unless an improvement has been made.
-	Merely removing my name, as Compex has done in the past, does not count
-	as an improvement.
-
-	Changelog:
-	* ported to 2.4
-		???
-	* spin lock update, memory barriers, new style dma mappings
-		limit each tx buffer to < 1024 bytes
-		remove DescIntr from Rx descriptors (that's an Tx flag)
-		remove next pointer from Tx descriptors
-		synchronize tx_q_bytes
-		software reset in tx_timeout
-			Copyright (C) 2000 Manfred Spraul
-	* further cleanups
-		power management.
-		support for big endian descriptors
-			Copyright (C) 2001 Manfred Spraul
-  	* ethtool support (jgarzik)
-	* Replace some MII-related magic numbers with constants (jgarzik)
-  
-	TODO:
-	* enable pci_power_off
-	* Wake-On-LAN
-*/
-  
-#define DRV_NAME	"winbond-840"
-#define DRV_VERSION	"1.01-d"
-#define DRV_RELDATE	"Nov-17-2001"
-
-
-/* Automatically extracted configuration info:
-probe-func: winbond840_probe
-config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840
-
-c-help-name: Winbond W89c840 PCI Ethernet support
-c-help-symbol: CONFIG_WINBOND_840
-c-help: This driver is for the Winbond W89c840 chip.  It also works with
-c-help: the TX9882 chip on the Compex RL100-ATX board.
-c-help: More specific information and updates are available from 
-c-help: http://www.scyld.com/network/drivers.html
-*/
-
-/* The user-configurable values.
-   These may be modified when a driver module is loaded.*/
-
-static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
-static int max_interrupt_work = 20;
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
-   The '840 uses a 64 element hash table based on the Ethernet CRC.  */
-static int multicast_filter_limit = 32;
-
-/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
-   Setting to > 1518 effectively disables this feature. */
-static int rx_copybreak;
-
-/* Used to pass the media type, etc.
-   Both 'options[]' and 'full_duplex[]' should exist for driver
-   interoperability.
-   The media type is usually passed in 'options[]'.
-*/
-#define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for compile efficiency.
-   The compiler will convert <unsigned>'%'<2^N> into a bit mask.
-   Making the Tx ring too large decreases the effectiveness of channel
-   bonding and packet priority.
-   There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
-#define TX_QUEUE_LEN_RESTART	5
-#define RX_RING_SIZE	32
-
-#define TX_BUFLIMIT	(1024-128)
-
-/* The presumed FIFO size for working around the Tx-FIFO-overflow bug.
-   To avoid overflowing we don't queue again until we have room for a
-   full-size packet.
- */
-#define TX_FIFO_SIZE (2048)
-#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16)
-
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT  (2*HZ)
-
-#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
-
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-#if !defined(__OPTIMIZE__)
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-/* Include files, designed to support most kernel versions 2.0.0 and later. */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ethtool.h>
-#include <linux/mii.h>
-#include <linux/rtnetlink.h>
-#include <linux/crc32.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
-
-MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
-MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(debug, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM_DESC(max_interrupt_work, "winbond-840 maximum events handled per interrupt");
-MODULE_PARM_DESC(debug, "winbond-840 debug level (0-6)");
-MODULE_PARM_DESC(rx_copybreak, "winbond-840 copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(multicast_filter_limit, "winbond-840 maximum number of filtered multicast addresses");
-MODULE_PARM_DESC(options, "winbond-840: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "winbond-840 full duplex setting(s) (1)");
-
-/*
-				Theory of Operation
-
-I. Board Compatibility
-
-This driver is for the Winbond w89c840 chip.
-
-II. Board-specific settings
-
-None.
-
-III. Driver operation
-
-This chip is very similar to the Digital 21*4* "Tulip" family.  The first
-twelve registers and the descriptor format are nearly identical.  Read a
-Tulip manual for operational details.
-
-A significant difference is that the multicast filter and station address are
-stored in registers rather than loaded through a pseudo-transmit packet.
-
-Unlike the Tulip, transmit buffers are limited to 1KB.  To transmit a
-full-sized packet we must use both data buffers in a descriptor.  Thus the
-driver uses ring mode where descriptors are implicitly sequential in memory,
-rather than using the second descriptor address as a chain pointer to
-subsequent descriptors.
-
-IV. Notes
-
-If you are going to almost clone a Tulip, why not go all the way and avoid
-the need for a new driver?
-
-IVb. References
-
-http://www.scyld.com/expert/100mbps.html
-http://www.scyld.com/expert/NWay.html
-http://www.winbond.com.tw/
-
-IVc. Errata
-
-A horrible bug exists in the transmit FIFO.  Apparently the chip doesn't
-correctly detect a full FIFO, and queuing more than 2048 bytes may result in
-silent data corruption.
-
-Test with 'ping -s 10000' on a fast computer.
-
-*/
-
-
-
-/*
-  PCI probe table.
-*/
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-enum chip_capability_flags {
-	CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
-#ifdef USE_IO_OPS
-#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
-#else
-#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
-#endif
-
-static struct pci_device_id w840_pci_tbl[] __devinitdata = {
-	{ 0x1050, 0x0840, PCI_ANY_ID, 0x8153,     0, 0, 0 },
-	{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
-	{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
-
-struct pci_id_info {
-        const char *name;
-        struct match_info {
-                int     pci, pci_mask, subsystem, subsystem_mask;
-                int revision, revision_mask;                            /* Only 8 bits. */
-        } id;
-        enum pci_id_flags_bits pci_flags;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
-        int drv_flags;                          /* Driver use, intended as capability flags. */
-};
-static struct pci_id_info pci_id_tbl[] = {
-	{"Winbond W89c840",			/* Sometime a Level-One switch card. */
-	 { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
-	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
-	{"Winbond W89c840", { 0x08401050, 0xffffffff, },
-	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
-	{"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
-	 W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
-	{0,},						/* 0 terminated list. */
-};
-
-/* This driver was written to use PCI memory space, however some x86 systems
-   work only with I/O space accesses.  Pass -DUSE_IO_OPS to use PCI I/O space
-   accesses instead of memory space. */
-
-#ifdef USE_IO_OPS
-#undef readb
-#undef readw
-#undef readl
-#undef writeb
-#undef writew
-#undef writel
-#define readb inb
-#define readw inw
-#define readl inl
-#define writeb outb
-#define writew outw
-#define writel outl
-#endif
-
-/* Offsets to the Command and Status Registers, "CSRs".
-   While similar to the Tulip, these registers are longword aligned.
-   Note: It's not useful to define symbolic names for every register bit in
-   the device.  The name can only partially document the semantics and make
-   the driver longer and more difficult to read.
-*/
-enum w840_offsets {
-	PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08,
-	RxRingPtr=0x0C, TxRingPtr=0x10,
-	IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C,
-	RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C,
-	CurRxDescAddr=0x30, CurRxBufAddr=0x34,			/* Debug use */
-	MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40,
-	CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
-};
-
-/* Bits in the interrupt status/enable registers. */
-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
-enum intr_status_bits {
-	NormalIntr=0x10000, AbnormalIntr=0x8000,
-	IntrPCIErr=0x2000, TimerInt=0x800,
-	IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
-	TxFIFOUnderflow=0x20, RxErrIntr=0x10,
-	TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
-};
-
-/* Bits in the NetworkConfig register. */
-enum rx_mode_bits {
-	AcceptErr=0x80, AcceptRunt=0x40,
-	AcceptBroadcast=0x20, AcceptMulticast=0x10,
-	AcceptAllPhys=0x08, AcceptMyPhys=0x02,
-};
-
-enum mii_reg_bits {
-	MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000,
-	MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000,
-};
-
-/* The Tulip Rx and Tx buffer descriptors. */
-struct w840_rx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1;
-	u32 buffer2;
-};
-
-struct w840_tx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1, buffer2;
-};
-
-/* Bits in network_desc.status */
-enum desc_status_bits {
-	DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
-	DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
-	DescIntr=0x80000000,
-};
-
-#define PRIV_ALIGN	15 	/* Required alignment mask */
-#define MII_CNT		1 /* winbond only supports one MII */
-struct netdev_private {
-	struct w840_rx_desc *rx_ring;
-	dma_addr_t	rx_addr[RX_RING_SIZE];
-	struct w840_tx_desc *tx_ring;
-	dma_addr_t	tx_addr[TX_RING_SIZE];
-	dma_addr_t ring_dma_addr;
-	/* The addresses of receive-in-place skbuffs. */
-	struct sk_buff* rx_skbuff[RX_RING_SIZE];
-	/* The saved address of a sent-in-place packet/buffer, for later free(). */
-	struct sk_buff* tx_skbuff[TX_RING_SIZE];
-	struct net_device_stats stats;
-	struct timer_list timer;	/* Media monitoring timer. */
-	/* Frequently used values: keep some adjacent for cache effect. */
-	spinlock_t lock;
-	int chip_id, drv_flags;
-	struct pci_dev *pci_dev;
-	int csr6;
-	struct w840_rx_desc *rx_head_desc;
-	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	unsigned int cur_tx, dirty_tx;
-	unsigned int tx_q_bytes;
-	unsigned int tx_full;				/* The Tx queue is full. */
-	/* MII transceiver section. */
-	int mii_cnt;						/* MII device addresses. */
-	unsigned char phys[MII_CNT];		/* MII device addresses, but only the first is used */
-	u32 mii;
-	struct mii_if_info mii_if;
-};
-
-static int  eeprom_read(long ioaddr, int location);
-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 int  update_link(struct net_device *dev);
-static void netdev_timer(unsigned long data);
-static void init_rxtx_rings(struct net_device *dev);
-static void free_rxtx_rings(struct netdev_private *np);
-static void init_registers(struct net_device *dev);
-static void tx_timeout(struct net_device *dev);
-static int alloc_ringdesc(struct net_device *dev);
-static void free_ringdesc(struct netdev_private *np);
-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 void netdev_error(struct net_device *dev, int intr_status);
-static int  netdev_rx(struct net_device *dev);
-static u32 __set_rx_mode(struct net_device *dev);
-static void set_rx_mode(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int  netdev_close(struct net_device *dev);
-
-
-
-static int __devinit w840_probe1 (struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
-{
-	struct net_device *dev;
-	struct netdev_private *np;
-	static int find_cnt;
-	int chip_idx = ent->driver_data;
-	int irq;
-	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
-	long ioaddr;
-
-	i = pci_enable_device(pdev);
-	if (i) return i;
-
-	pci_set_master(pdev);
-
-	irq = pdev->irq;
-
-	if (pci_set_dma_mask(pdev,0xFFFFffff)) {
-		printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
-		       pdev->slot_name);
-		return -EIO;
-	}
-	dev = alloc_etherdev(sizeof(*np));
-	if (!dev)
-		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
-
-	if (pci_request_regions(pdev, DRV_NAME))
-		goto err_out_netdev;
-
-#ifdef USE_IO_OPS
-	ioaddr = pci_resource_start(pdev, 0);
-#else
-	ioaddr = pci_resource_start(pdev, 1);
-	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
-	if (!ioaddr)
-		goto err_out_free_res;
-#endif
-
-	for (i = 0; i < 3; i++)
-		((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
-
-	/* Reset the chip to erase previous misconfiguration.
-	   No hold time required! */
-	writel(0x00000001, ioaddr + PCIBusCfg);
-
-	dev->base_addr = ioaddr;
-	dev->irq = irq;
-
-	np = dev->priv;
-	np->pci_dev = pdev;
-	np->chip_id = chip_idx;
-	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
-	spin_lock_init(&np->lock);
-	np->mii_if.dev = dev;
-	np->mii_if.mdio_read = mdio_read;
-	np->mii_if.mdio_write = mdio_write;
-	
-	pci_set_drvdata(pdev, dev);
-
-	if (dev->mem_start)
-		option = dev->mem_start;
-
-	/* The lower four bits are the media type. */
-	if (option > 0) {
-		if (option & 0x200)
-			np->mii_if.full_duplex = 1;
-		if (option & 15)
-			printk(KERN_INFO "%s: ignoring user supplied media type %d",
-				dev->name, option & 15);
-	}
-	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
-		np->mii_if.full_duplex = 1;
-
-	if (np->mii_if.full_duplex)
-		np->mii_if.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 = &netdev_ioctl;
-	dev->tx_timeout = &tx_timeout;
-	dev->watchdog_timeo = TX_TIMEOUT;
-
-	i = register_netdev(dev);
-	if (i)
-		goto err_out_cleardev;
-
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
-		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
-
-	if (np->drv_flags & CanHaveMII) {
-		int phy, phy_idx = 0;
-		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, MII_BMSR);
-			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
-				np->phys[phy_idx++] = phy;
-				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
-				np->mii = (mdio_read(dev, phy, MII_PHYSID1) << 16)+
-						mdio_read(dev, phy, MII_PHYSID2);
-				printk(KERN_INFO "%s: MII PHY %8.8xh found at address %d, status "
-					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, np->mii, phy, mii_status, np->mii_if.advertising);
-			}
-		}
-		np->mii_cnt = phy_idx;
-		np->mii_if.phy_id = np->phys[0];
-		if (phy_idx == 0) {
-				printk(KERN_WARNING "%s: MII PHY not found -- this device may "
-					   "not operate correctly.\n", dev->name);
-		}
-	}
-
-	find_cnt++;
-	return 0;
-
-err_out_cleardev:
-	pci_set_drvdata(pdev, NULL);
-#ifndef USE_IO_OPS
-	iounmap((void *)ioaddr);
-err_out_free_res:
-#endif
-	pci_release_regions(pdev);
-err_out_netdev:
-	kfree (dev);
-	return -ENODEV;
-}
-
-
-/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are
-   often serial bit streams generated by the host processor.
-   The example below is for the common 93c46 EEPROM, 64 16 bit words. */
-
-/* Delay between EEPROM clock transitions.
-   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need
-   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that
-   made udelay() unreliable.
-   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is
-   depricated.
-*/
-#define eeprom_delay(ee_addr)	readl(ee_addr)
-
-enum EEPROM_Ctrl_Bits {
-	EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,
-	EE_ChipSelect=0x801, EE_DataIn=0x08,
-};
-
-/* The EEPROM commands include the alway-set leading bit. */
-enum EEPROM_Cmds {
-	EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
-};
-
-static int eeprom_read(long addr, int location)
-{
-	int i;
-	int retval = 0;
-	long ee_addr = addr + EECtrl;
-	int read_cmd = location | EE_ReadCmd;
-	writel(EE_ChipSelect, ee_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 10; i >= 0; i--) {
-		short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;
-		writel(dataval, ee_addr);
-		eeprom_delay(ee_addr);
-		writel(dataval | EE_ShiftClk, ee_addr);
-		eeprom_delay(ee_addr);
-	}
-	writel(EE_ChipSelect, ee_addr);
-	eeprom_delay(ee_addr);
-
-	for (i = 16; i > 0; i--) {
-		writel(EE_ChipSelect | EE_ShiftClk, ee_addr);
-		eeprom_delay(ee_addr);
-		retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);
-		writel(EE_ChipSelect, ee_addr);
-		eeprom_delay(ee_addr);
-	}
-
-	/* Terminate the EEPROM access. */
-	writel(0, ee_addr);
-	return retval;
-}
-
-/*  MII transceiver control section.
-	Read and write the MII registers using software-generated serial
-	MDIO protocol.  See the MII specifications or DP83840A data sheet
-	for details.
-
-	The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
-	met by back-to-back 33Mhz PCI cycles. */
-#define mdio_delay(mdio_addr) readl(mdio_addr)
-
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with older tranceivers, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static char mii_preamble_required = 1;
-
-#define MDIO_WRITE0 (MDIO_EnbOutput)
-#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)
-
-/* Generate the preamble required for initial synchronization and
-   a few older transceivers. */
-static void mdio_sync(long mdio_addr)
-{
-	int bits = 32;
-
-	/* Establish sync by sending at least 32 logic ones. */
-	while (--bits >= 0) {
-		writel(MDIO_WRITE1, mdio_addr);
-		mdio_delay(mdio_addr);
-		writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);
-		mdio_delay(mdio_addr);
-	}
-}
-
-static int mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	long mdio_addr = dev->base_addr + MIICtrl;
-	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
-	int i, retval = 0;
-
-	if (mii_preamble_required)
-		mdio_sync(mdio_addr);
-
-	/* Shift the read command bits out. */
-	for (i = 15; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-
-		writel(dataval, mdio_addr);
-		mdio_delay(mdio_addr);
-		writel(dataval | MDIO_ShiftClk, mdio_addr);
-		mdio_delay(mdio_addr);
-	}
-	/* Read the two transition, 16 data, and wire-idle bits. */
-	for (i = 20; i > 0; i--) {
-		writel(MDIO_EnbIn, mdio_addr);
-		mdio_delay(mdio_addr);
-		retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);
-		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-		mdio_delay(mdio_addr);
-	}
-	return (retval>>1) & 0xffff;
-}
-
-static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
-{
-	struct netdev_private *np = dev->priv;
-	long mdio_addr = dev->base_addr + MIICtrl;
-	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
-	int i;
-
-	if (location == 4  &&  phy_id == np->phys[0])
-		np->mii_if.advertising = value;
-
-	if (mii_preamble_required)
-		mdio_sync(mdio_addr);
-
-	/* Shift the command bits out. */
-	for (i = 31; i >= 0; i--) {
-		int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
-
-		writel(dataval, mdio_addr);
-		mdio_delay(mdio_addr);
-		writel(dataval | MDIO_ShiftClk, mdio_addr);
-		mdio_delay(mdio_addr);
-	}
-	/* Clear out extra bits. */
-	for (i = 2; i > 0; i--) {
-		writel(MDIO_EnbIn, mdio_addr);
-		mdio_delay(mdio_addr);
-		writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);
-		mdio_delay(mdio_addr);
-	}
-	return;
-}
-
-
-static int netdev_open(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-
-	writel(0x00000001, ioaddr + PCIBusCfg);		/* Reset */
-
-	netif_device_detach(dev);
-	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
-	if (i)
-		goto out_err;
-
-	if (debug > 1)
-		printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n",
-			   dev->name, dev->irq);
-
-	if((i=alloc_ringdesc(dev)))
-		goto out_err;
-
-	spin_lock_irq(&np->lock);
-	netif_device_attach(dev);
-	init_registers(dev);
-	spin_unlock_irq(&np->lock);
-
-	netif_start_queue(dev);
-	if (debug > 2)
-		printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name);
-
-	/* Set the timer to check for link beat. */
-	init_timer(&np->timer);
-	np->timer.expires = jiffies + 1*HZ;
-	np->timer.data = (unsigned long)dev;
-	np->timer.function = &netdev_timer;				/* timer handler */
-	add_timer(&np->timer);
-	return 0;
-out_err:
-	netif_device_attach(dev);
-	return i;
-}
-
-#define MII_DAVICOM_DM9101	0x0181b800
-
-static int update_link(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	int duplex, fasteth, result, mii_reg;
-
-	/* BSMR */
-	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
-
-	if (mii_reg == 0xffff)
-		return np->csr6;
-	/* reread: the link status bit is sticky */
-	mii_reg = mdio_read(dev, np->phys[0], MII_BMSR);
-	if (!(mii_reg & 0x4)) {
-		if (netif_carrier_ok(dev)) {
-			if (debug)
-				printk(KERN_INFO "%s: MII #%d reports no link. Disabling watchdog.\n",
-					dev->name, np->phys[0]);
-			netif_carrier_off(dev);
-		}
-		return np->csr6;
-	}
-	if (!netif_carrier_ok(dev)) {
-		if (debug)
-			printk(KERN_INFO "%s: MII #%d link is back. Enabling watchdog.\n",
-				dev->name, np->phys[0]);
-		netif_carrier_on(dev);
-	}
-	
-	if ((np->mii & ~0xf) == MII_DAVICOM_DM9101) {
-		/* If the link partner doesn't support autonegotiation
-		 * the MII detects it's abilities with the "parallel detection".
-		 * Some MIIs update the LPA register to the result of the parallel
-		 * detection, some don't.
-		 * The Davicom PHY [at least 0181b800] doesn't.
-		 * Instead bit 9 and 13 of the BMCR are updated to the result
-		 * of the negotiation..
-		 */
-		mii_reg = mdio_read(dev, np->phys[0], MII_BMCR);
-		duplex = mii_reg & BMCR_FULLDPLX;
-		fasteth = mii_reg & BMCR_SPEED100;
-	} else {
-		int negotiated;
-		mii_reg	= mdio_read(dev, np->phys[0], MII_LPA);
-		negotiated = mii_reg & np->mii_if.advertising;
-
-		duplex = (negotiated & LPA_100FULL) || ((negotiated & 0x02C0) == LPA_10FULL);
-		fasteth = negotiated & 0x380;
-	}
-	duplex |= np->mii_if.duplex_lock;
-	/* remove fastether and fullduplex */
-	result = np->csr6 & ~0x20000200;
-	if (duplex)
-		result |= 0x200;
-	if (fasteth)
-		result |= 0x20000000;
-	if (result != np->csr6 && debug)
-		printk(KERN_INFO "%s: Setting %dMBit-%s-duplex based on MII#%d\n",
-				 dev->name, fasteth ? 100 : 10, 
-			   	duplex ? "full" : "half", np->phys[0]);
-	return result;
-}
-
-#define RXTX_TIMEOUT	2000
-static inline void update_csr6(struct net_device *dev, int new)
-{
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int limit = RXTX_TIMEOUT;
-
-	if (!netif_device_present(dev))
-		new = 0;
-	if (new==np->csr6)
-		return;
-	/* stop both Tx and Rx processes */
-	writel(np->csr6 & ~0x2002, ioaddr + NetworkConfig);
-	/* wait until they have really stopped */
-	for (;;) {
-		int csr5 = readl(ioaddr + IntrStatus);
-		int t;
-
-		t = (csr5 >> 17) & 0x07;
-		if (t==0||t==1) {
-			/* rx stopped */
-			t = (csr5 >> 20) & 0x07;
-			if (t==0||t==1)
-				break;
-		}
-
-		limit--;
-		if(!limit) {
-			printk(KERN_INFO "%s: couldn't stop rxtx, IntrStatus %xh.\n",
-					dev->name, csr5);
-			break;
-		}
-		udelay(1);
-	}
-	np->csr6 = new;
-	/* and restart them with the new configuration */
-	writel(np->csr6, ioaddr + NetworkConfig);
-	if (new & 0x200)
-		np->mii_if.full_duplex = 1;
-}
-
-static void netdev_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	if (debug > 2)
-		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x "
-			   "config %8.8x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus),
-			   (int)readl(ioaddr + NetworkConfig));
-	spin_lock_irq(&np->lock);
-	update_csr6(dev, update_link(dev));
-	spin_unlock_irq(&np->lock);
-	np->timer.expires = jiffies + 10*HZ;
-	add_timer(&np->timer);
-}
-
-static void init_rxtx_rings(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	int i;
-
-	np->rx_head_desc = &np->rx_ring[0];
-	np->tx_ring = (struct w840_tx_desc*)&np->rx_ring[RX_RING_SIZE];
-
-	/* Initial all Rx descriptors. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].length = np->rx_buf_sz;
-		np->rx_ring[i].status = 0;
-		np->rx_skbuff[i] = 0;
-	}
-	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].length |= DescEndRing;
-
-	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
-		np->rx_skbuff[i] = skb;
-		if (skb == NULL)
-			break;
-		skb->dev = dev;			/* Mark as being used by this device. */
-		np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail,
-					skb->len,PCI_DMA_FROMDEVICE);
-
-		np->rx_ring[i].buffer1 = np->rx_addr[i];
-		np->rx_ring[i].status = DescOwn;
-	}
-
-	np->cur_rx = 0;
-	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
-
-	/* Initialize the Tx descriptors */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].status = 0;
-	}
-	np->tx_full = 0;
-	np->tx_q_bytes = np->dirty_tx = np->cur_tx = 0;
-
-	writel(np->ring_dma_addr, dev->base_addr + RxRingPtr);
-	writel(np->ring_dma_addr+sizeof(struct w840_rx_desc)*RX_RING_SIZE,
-		dev->base_addr + TxRingPtr);
-
-}
-
-static void free_rxtx_rings(struct netdev_private* np)
-{
-	int i;
-	/* Free all the skbuffs in the Rx queue. */
-	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].status = 0;
-		if (np->rx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev,
-						np->rx_addr[i],
-						np->rx_skbuff[i]->len,
-						PCI_DMA_FROMDEVICE);
-			dev_kfree_skb(np->rx_skbuff[i]);
-		}
-		np->rx_skbuff[i] = 0;
-	}
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (np->tx_skbuff[i]) {
-			pci_unmap_single(np->pci_dev,
-						np->tx_addr[i],
-						np->tx_skbuff[i]->len,
-						PCI_DMA_TODEVICE);
-			dev_kfree_skb(np->tx_skbuff[i]);
-		}
-		np->tx_skbuff[i] = 0;
-	}
-}
-
-static void init_registers(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int i;
-
-	for (i = 0; i < 6; i++)
-		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
-
-	/* Initialize other registers. */
-#ifdef __BIG_ENDIAN
-	i = (1<<20);	/* Big-endian descriptors */
-#else
-	i = 0;
-#endif
-	i |= (0x04<<2);		/* skip length 4 u32 */
-	i |= 0x02;		/* give Rx priority */
-
-	/* Configure the PCI bus bursts and FIFO thresholds.
-	   486: Set 8 longword cache alignment, 8 longword burst.
-	   586: Set 16 longword cache alignment, no burst limit.
-	   Cache alignment bits 15:14	     Burst length 13:8
-		0000	<not allowed> 		0000 align to cache	0800 8 longwords
-		4000	8  longwords		0100 1 longword		1000 16 longwords
-		8000	16 longwords		0200 2 longwords	2000 32 longwords
-		C000	32  longwords		0400 4 longwords */
-
-#if defined (__i386__) && !defined(MODULE)
-	/* When not a module we can work around broken '486 PCI boards. */
-	if (boot_cpu_data.x86 <= 4) {
-		i |= 0x4800;
-		printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache "
-			   "alignment to 8 longwords.\n", dev->name);
-	} else {
-		i |= 0xE000;
-	}
-#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
-	i |= 0xE000;
-#elif defined(__sparc__)
-	i |= 0x4800;
-#else
-#warning Processor architecture undefined
-	i |= 0x4800;
-#endif
-	writel(i, ioaddr + PCIBusCfg);
-
-	np->csr6 = 0;
-	/* 128 byte Tx threshold; 
-		Transmit on; Receive on; */
-	update_csr6(dev, 0x00022002 | update_link(dev) | __set_rx_mode(dev));
-
-	/* Clear and Enable interrupts by setting the interrupt mask. */
-	writel(0x1A0F5, ioaddr + IntrStatus);
-	writel(0x1A0F5, ioaddr + IntrEnable);
-
-	writel(0, ioaddr + RxStartDemand);
-}
-
-static void tx_timeout(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-		   " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
-
-	{
-		int i;
-		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %8.8x", np->tx_ring[i].status);
-		printk("\n");
-	}
-	printk(KERN_DEBUG "Tx cur %d Tx dirty %d Tx Full %d, q bytes %d.\n",
-				np->cur_tx, np->dirty_tx, np->tx_full, np->tx_q_bytes);
-	printk(KERN_DEBUG "Tx Descriptor addr %xh.\n",readl(ioaddr+0x4C));
-
-	disable_irq(dev->irq);
-	spin_lock_irq(&np->lock);
-	/*
-	 * Under high load dirty_tx and the internal tx descriptor pointer
-	 * come out of sync, thus perform a software reset and reinitialize
-	 * everything.
-	 */
-
-	writel(1, dev->base_addr+PCIBusCfg);
-	udelay(1);
-
-	free_rxtx_rings(np);
-	init_rxtx_rings(dev);
-	init_registers(dev);
-	spin_unlock_irq(&np->lock);
-	enable_irq(dev->irq);
-
-	netif_wake_queue(dev);
-	dev->trans_start = jiffies;
-	np->stats.tx_errors++;
-	return;
-}
-
-/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-static int alloc_ringdesc(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-
-	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
-
-	np->rx_ring = pci_alloc_consistent(np->pci_dev,
-			sizeof(struct w840_rx_desc)*RX_RING_SIZE +
-			sizeof(struct w840_tx_desc)*TX_RING_SIZE,
-			&np->ring_dma_addr);
-	if(!np->rx_ring)
-		return -ENOMEM;
-	init_rxtx_rings(dev);
-	return 0;
-}
-
-static void free_ringdesc(struct netdev_private *np)
-{
-	pci_free_consistent(np->pci_dev,
-			sizeof(struct w840_rx_desc)*RX_RING_SIZE +
-			sizeof(struct w840_tx_desc)*TX_RING_SIZE,
-			np->rx_ring, np->ring_dma_addr);
-
-}
-
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	unsigned entry;
-
-	/* Caution: the write order is important here, set the field
-	   with the "ownership" bits last. */
-
-	/* Calculate the next Tx descriptor entry. */
-	entry = np->cur_tx % TX_RING_SIZE;
-
-	np->tx_addr[entry] = pci_map_single(np->pci_dev,
-				skb->data,skb->len, PCI_DMA_TODEVICE);
-	np->tx_skbuff[entry] = skb;
-
-	np->tx_ring[entry].buffer1 = np->tx_addr[entry];
-	if (skb->len < TX_BUFLIMIT) {
-		np->tx_ring[entry].length = DescWholePkt | skb->len;
-	} else {
-		int len = skb->len - TX_BUFLIMIT;
-
-		np->tx_ring[entry].buffer2 = np->tx_addr[entry]+TX_BUFLIMIT;
-		np->tx_ring[entry].length = DescWholePkt | (len << 11) | TX_BUFLIMIT;
-	}
-	if(entry == TX_RING_SIZE-1)
-		np->tx_ring[entry].length |= DescEndRing;
-
-	/* Now acquire the irq spinlock.
-	 * The difficult race is the the ordering between
-	 * increasing np->cur_tx and setting DescOwn:
-	 * - if np->cur_tx is increased first the interrupt
-	 *   handler could consider the packet as transmitted
-	 *   since DescOwn is cleared.
-	 * - If DescOwn is set first the NIC could report the
-	 *   packet as sent, but the interrupt handler would ignore it
-	 *   since the np->cur_tx was not yet increased.
-	 */
-	spin_lock_irq(&np->lock);
-	np->cur_tx++;
-
-	wmb(); /* flush length, buffer1, buffer2 */
-	np->tx_ring[entry].status = DescOwn;
-	wmb(); /* flush status and kick the hardware */
-	writel(0, dev->base_addr + TxStartDemand);
-	np->tx_q_bytes += skb->len;
-	/* Work around horrible bug in the chip by marking the queue as full
-	   when we do not have FIFO room for a maximum sized packet. */
-	if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN ||
-		((np->drv_flags & HasBrokenTx) && np->tx_q_bytes > TX_BUG_FIFO_LIMIT)) {
-		netif_stop_queue(dev);
-		wmb();
-		np->tx_full = 1;
-	}
-	spin_unlock_irq(&np->lock);
-
-	dev->trans_start = jiffies;
-
-	if (debug > 4) {
-		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx, entry);
-	}
-	return 0;
-}
-
-static void netdev_tx_done(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-		int entry = np->dirty_tx % TX_RING_SIZE;
-		int tx_status = np->tx_ring[entry].status;
-
-		if (tx_status < 0)
-			break;
-		if (tx_status & 0x8000) { 	/* There was an error, log it. */
-#ifndef final_version
-			if (debug > 1)
-				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
-					   dev->name, tx_status);
-#endif
-			np->stats.tx_errors++;
-			if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
-			if (tx_status & 0x0C80) np->stats.tx_carrier_errors++;
-			if (tx_status & 0x0200) np->stats.tx_window_errors++;
-			if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
-			if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
-				np->stats.tx_heartbeat_errors++;
-#ifdef ETHER_STATS
-			if (tx_status & 0x0100) np->stats.collisions16++;
-#endif
-		} else {
-#ifdef ETHER_STATS
-			if (tx_status & 0x0001) np->stats.tx_deferred++;
-#endif
-#ifndef final_version
-			if (debug > 3)
-				printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
-					   dev->name, entry, tx_status);
-#endif
-			np->stats.tx_bytes += np->tx_skbuff[entry]->len;
-			np->stats.collisions += (tx_status >> 3) & 15;
-			np->stats.tx_packets++;
-		}
-		/* Free the original skb. */
-		pci_unmap_single(np->pci_dev,np->tx_addr[entry],
-					np->tx_skbuff[entry]->len,
-					PCI_DMA_TODEVICE);
-		np->tx_q_bytes -= np->tx_skbuff[entry]->len;
-		dev_kfree_skb_irq(np->tx_skbuff[entry]);
-		np->tx_skbuff[entry] = 0;
-	}
-	if (np->tx_full &&
-		np->cur_tx - np->dirty_tx < TX_QUEUE_LEN_RESTART &&
-		np->tx_q_bytes < TX_BUG_FIFO_LIMIT) {
-		/* The ring is no longer full, clear tbusy. */
-		np->tx_full = 0;
-		wmb();
-		netif_wake_queue(dev);
-	}
-}
-
-/* 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)
-{
-	struct net_device *dev = (struct net_device *)dev_instance;
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-	int work_limit = max_interrupt_work;
-
-	if (!netif_device_present(dev))
-		return;
-	do {
-		u32 intr_status = readl(ioaddr + IntrStatus);
-
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		writel(intr_status & 0x001ffff, ioaddr + IntrStatus);
-
-		if (debug > 4)
-			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
-				   dev->name, intr_status);
-
-		if ((intr_status & (NormalIntr|AbnormalIntr)) == 0)
-			break;
-
-		if (intr_status & (IntrRxDone | RxNoBuf))
-			netdev_rx(dev);
-		if (intr_status & RxNoBuf)
-			writel(0, ioaddr + RxStartDemand);
-
-		if (intr_status & (TxIdle | IntrTxDone) &&
-			np->cur_tx != np->dirty_tx) {
-			spin_lock(&np->lock);
-			netdev_tx_done(dev);
-			spin_unlock(&np->lock);
-		}
-
-		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
-						   TimerInt | IntrTxStopped))
-			netdev_error(dev, intr_status);
-
-		if (--work_limit < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=0x%4.4x.\n", dev->name, intr_status);
-			/* Set the timer to re-enable the other interrupts after
-			   10*82usec ticks. */
-			spin_lock(&np->lock);
-			if (netif_device_present(dev)) {
-				writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable);
-				writel(10, ioaddr + GPTimer);
-			}
-			spin_unlock(&np->lock);
-			break;
-		}
-	} while (1);
-
-	if (debug > 3)
-		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
-			   dev->name, (int)readl(ioaddr + IntrStatus));
-}
-
-/* This routine is logically part of the interrupt handler, but separated
-   for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	int entry = np->cur_rx % RX_RING_SIZE;
-	int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-
-	if (debug > 4) {
-		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-			   entry, np->rx_ring[entry].status);
-	}
-
-	/* If EOP is set on the next entry, it's a new packet. Send it up. */
-	while (--work_limit >= 0) {
-		struct w840_rx_desc *desc = np->rx_head_desc;
-		s32 status = desc->status;
-
-		if (debug > 4)
-			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
-				   status);
-		if (status < 0)
-			break;
-		if ((status & 0x38008300) != 0x0300) {
-			if ((status & 0x38000300) != 0x0300) {
-				/* Ingore earlier buffers. */
-				if ((status & 0xffff) != 0x7fff) {
-					printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "
-						   "multiple buffers, entry %#x status %4.4x!\n",
-						   dev->name, np->cur_rx, status);
-					np->stats.rx_length_errors++;
-				}
-			} else if (status & 0x8000) {
-				/* There was a fatal error. */
-				if (debug > 2)
-					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
-						   dev->name, status);
-				np->stats.rx_errors++; /* end of a packet.*/
-				if (status & 0x0890) np->stats.rx_length_errors++;
-				if (status & 0x004C) np->stats.rx_frame_errors++;
-				if (status & 0x0002) np->stats.rx_crc_errors++;
-			}
-		} else {
-			struct sk_buff *skb;
-			/* Omit the four octet CRC from the length. */
-			int pkt_len = ((status >> 16) & 0x7ff) - 4;
-
-#ifndef final_version
-			if (debug > 4)
-				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
-					   " status %x.\n", pkt_len, status);
-#endif
-			/* Check if the packet is long enough to accept without copying
-			   to a minimally-sized skbuff. */
-			if (pkt_len < rx_copybreak
-				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
-				skb->dev = dev;
-				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-				pci_dma_sync_single(np->pci_dev,np->rx_addr[entry],
-							np->rx_skbuff[entry]->len,
-							PCI_DMA_FROMDEVICE);
-				/* Call copy + cksum if available. */
-#if HAS_IP_COPYSUM
-				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
-				skb_put(skb, pkt_len);
-#else
-				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
-					   pkt_len);
-#endif
-			} else {
-				pci_unmap_single(np->pci_dev,np->rx_addr[entry],
-							np->rx_skbuff[entry]->len,
-							PCI_DMA_FROMDEVICE);
-				skb_put(skb = np->rx_skbuff[entry], pkt_len);
-				np->rx_skbuff[entry] = NULL;
-			}
-#ifndef final_version				/* Remove after testing. */
-			/* You will want this info for the initial debug. */
-			if (debug > 5)
-				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-					   "%d.%d.%d.%d.\n",
-					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-					   skb->data[8], skb->data[9], skb->data[10],
-					   skb->data[11], skb->data[12], skb->data[13],
-					   skb->data[14], skb->data[15], skb->data[16],
-					   skb->data[17]);
-#endif
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			np->stats.rx_packets++;
-			np->stats.rx_bytes += pkt_len;
-		}
-		entry = (++np->cur_rx) % RX_RING_SIZE;
-		np->rx_head_desc = &np->rx_ring[entry];
-	}
-
-	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
-		struct sk_buff *skb;
-		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;
-			if (skb == NULL)
-				break;			/* Better luck next round. */
-			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_addr[entry] = pci_map_single(np->pci_dev,
-							skb->tail,
-							skb->len, PCI_DMA_FROMDEVICE);
-			np->rx_ring[entry].buffer1 = np->rx_addr[entry];
-		}
-		wmb();
-		np->rx_ring[entry].status = DescOwn;
-	}
-
-	return 0;
-}
-
-static void netdev_error(struct net_device *dev, int intr_status)
-{
-	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
-
-	if (debug > 2)
-		printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n",
-			   dev->name, intr_status);
-	if (intr_status == 0xffffffff)
-		return;
-	spin_lock(&np->lock);
-	if (intr_status & TxFIFOUnderflow) {
-		int new;
-		/* Bump up the Tx threshold */
-#if 0
-		/* This causes lots of dropped packets,
-		 * and under high load even tx_timeouts
-		 */
-		new = np->csr6 + 0x4000;
-#else
-		new = (np->csr6 >> 14)&0x7f;
-		if (new < 64)
-			new *= 2;
-		 else
-		 	new = 127; /* load full packet before starting */
-		new = (np->csr6 & ~(0x7F << 14)) | (new<<14);
-#endif
-		printk(KERN_DEBUG "%s: Tx underflow, new csr6 %8.8x.\n",
-			   dev->name, new);
-		update_csr6(dev, new);
-	}
-	if (intr_status & IntrRxDied) {		/* Missed a Rx frame. */
-		np->stats.rx_errors++;
-	}
-	if (intr_status & TimerInt) {
-		/* Re-enable other interrupts. */
-		if (netif_device_present(dev))
-			writel(0x1A0F5, ioaddr + IntrEnable);
-	}
-	np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-	writel(0, ioaddr + RxStartDemand);
-	spin_unlock(&np->lock);
-}
-
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
-
-	/* The chip only need report frame silently dropped. */
-	spin_lock_irq(&np->lock);
-	if (netif_running(dev) && netif_device_present(dev))
-		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-	spin_unlock_irq(&np->lock);
-
-	return &np->stats;
-}
-
-
-static u32 __set_rx_mode(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	u32 mc_filter[2];			/* Multicast hash filter */
-	u32 rx_mode;
-
-	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
-		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
-		memset(mc_filter, 0xff, sizeof(mc_filter));
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
-			| AcceptMyPhys;
-	} else if ((dev->mc_count > multicast_filter_limit)
-			   ||  (dev->flags & IFF_ALLMULTI)) {
-		/* Too many to match, or accept all multicasts. */
-		memset(mc_filter, 0xff, sizeof(mc_filter));
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-	} else {
-		struct dev_mc_list *mclist;
-		int i;
-		memset(mc_filter, 0, sizeof(mc_filter));
-		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
-			 i++, mclist = mclist->next) {
-			set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F,
-					mc_filter);
-		}
-		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-	}
-	writel(mc_filter[0], ioaddr + MulticastFilter0);
-	writel(mc_filter[1], ioaddr + MulticastFilter1);
-	return rx_mode;
-}
-
-static void set_rx_mode(struct net_device *dev)
-{
-	struct netdev_private *np = dev->priv;
-	u32 rx_mode = __set_rx_mode(dev);
-	spin_lock_irq(&np->lock);
-	update_csr6(dev, (np->csr6 & ~0x00F8) | rx_mode);
-	spin_unlock_irq(&np->lock);
-}
-
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
-{
-	struct netdev_private *np = dev->priv;
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, np->pci_dev->slot_name);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&np->lock);
-		mii_ethtool_gset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		r = mii_ethtool_sset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&np->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = mii_link_ok(&np->mii_if);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-        }
-	
-	return -EOPNOTSUPP;
-}
-
-static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
-	struct netdev_private *np = dev->priv;
-
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
-	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		data->phy_id = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;
-		/* Fall Through */
-
-	case SIOCGMIIREG:		/* Read MII PHY register. */
-		spin_lock_irq(&np->lock);
-		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
-		spin_unlock_irq(&np->lock);
-		return 0;
-
-	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		spin_lock_irq(&np->lock);
-		mdio_write(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
-		spin_unlock_irq(&np->lock);
-		return 0;
-	default:
-		return -EOPNOTSUPP;
-	}
-}
-
-static int netdev_close(struct net_device *dev)
-{
-	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
-
-	netif_stop_queue(dev);
-
-	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x "
-			   "Config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus),
-			   (int)readl(ioaddr + NetworkConfig));
-		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-	}
-
- 	/* Stop the chip's Tx and Rx processes. */
-	spin_lock_irq(&np->lock);
-	netif_device_detach(dev);
-	update_csr6(dev, 0);
-	writel(0x0000, ioaddr + IntrEnable);
-	spin_unlock_irq(&np->lock);
-
-	free_irq(dev->irq, dev);
-	wmb();
-	netif_device_attach(dev);
-
-	if (readl(ioaddr + NetworkConfig) != 0xffffffff)
-		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-
-#ifdef __i386__
-	if (debug > 2) {
-		int i;
-
-		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
-			   (int)np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" #%d desc. %4.4x %4.4x %8.8x.\n",
-				   i, np->tx_ring[i].length,
-				   np->tx_ring[i].status, np->tx_ring[i].buffer1);
-		printk("\n"KERN_DEBUG "  Rx ring %8.8x:\n",
-			   (int)np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++) {
-			printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n",
-				   i, np->rx_ring[i].length,
-				   np->rx_ring[i].status, np->rx_ring[i].buffer1);
-		}
-	}
-#endif /* __i386__ debugging only */
-
-	del_timer_sync(&np->timer);
-
-	free_rxtx_rings(np);
-	free_ringdesc(np);
-
-	return 0;
-}
-
-static void __devexit w840_remove1 (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-	
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	if (dev) {
-		unregister_netdev(dev);
-		pci_release_regions(pdev);
-#ifndef USE_IO_OPS
-		iounmap((char *)(dev->base_addr));
-#endif
-		kfree(dev);
-	}
-
-	pci_set_drvdata(pdev, NULL);
-}
-
-#ifdef CONFIG_PM
-
-/*
- * suspend/resume synchronization:
- * - open, close, do_ioctl:
- * 	rtnl_lock, & netif_device_detach after the rtnl_unlock.
- * - get_stats:
- * 	spin_lock_irq(np->lock), doesn't touch hw if not present
- * - hard_start_xmit:
- * 	netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
- * - tx_timeout:
- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
- * - set_multicast_list
- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
- * - interrupt handler
- * 	doesn't touch hw if not present, synchronize_irq waits for
- * 	running instances of the interrupt handler.
- *
- * Disabling hw requires clearing csr6 & IntrEnable.
- * update_csr6 & all function that write IntrEnable check netif_device_present
- * before settings any bits.
- *
- * Detach must occur under spin_unlock_irq(), interrupts from a detached
- * device would cause an irq storm.
- */
-static int w840_suspend (struct pci_dev *pdev, u32 state)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct netdev_private *np = dev->priv;
-	long ioaddr = dev->base_addr;
-
-	rtnl_lock();
-	if (netif_running (dev)) {
-		del_timer_sync(&np->timer);
-
-		spin_lock_irq(&np->lock);
-		netif_device_detach(dev);
-		update_csr6(dev, 0);
-		writel(0, ioaddr + IntrEnable);
-		netif_stop_queue(dev);
-		spin_unlock_irq(&np->lock);
-
-		spin_unlock_wait(&dev->xmit_lock);
-		synchronize_irq();
-	
-		np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff;
-
-		/* no more hardware accesses behind this line. */
-
-		if (np->csr6) BUG();
-		if (readl(ioaddr + IntrEnable)) BUG();
-
-		/* pci_power_off(pdev, -1); */
-
-		free_rxtx_rings(np);
-	} else {
-		netif_device_detach(dev);
-	}
-	rtnl_unlock();
-	return 0;
-}
-
-
-static int w840_resume (struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata (pdev);
-	struct netdev_private *np = dev->priv;
-
-	rtnl_lock();
-	if (netif_device_present(dev))
-		goto out; /* device not suspended */
-	if (netif_running(dev)) {
-		pci_enable_device(pdev);
-	/*	pci_power_on(pdev); */
-
-		spin_lock_irq(&np->lock);
-		writel(1, dev->base_addr+PCIBusCfg);
-		readl(dev->base_addr+PCIBusCfg);
-		udelay(1);
-		netif_device_attach(dev);
-		init_rxtx_rings(dev);
-		init_registers(dev);
-		spin_unlock_irq(&np->lock);
-
-		netif_wake_queue(dev);
-
-		np->timer.expires = jiffies + 1*HZ;
-		add_timer(&np->timer);
-	} else {
-		netif_device_attach(dev);
-	}
-out:
-	rtnl_unlock();
-	return 0;
-}
-#endif
-
-static struct pci_driver w840_driver = {
-	name:		DRV_NAME,
-	id_table:	w840_pci_tbl,
-	probe:		w840_probe1,
-	remove:		__devexit_p(w840_remove1),
-#ifdef CONFIG_PM
-	suspend:	w840_suspend,
-	resume:		w840_resume,
-#endif
-};
-
-static int __init w840_init(void)
-{
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-	printk(version);
-#endif
-	return pci_module_init(&w840_driver);
-}
-
-static void __exit w840_exit(void)
-{
-	pci_unregister_driver(&w840_driver);
-}
-
-module_init(w840_init);
-module_exit(w840_exit);
diff -urN linux-2.5.6-pre3/drivers/net/wireless/orinoco.c linux-2.5.6/drivers/net/wireless/orinoco.c
--- linux-2.5.6-pre3/drivers/net/wireless/orinoco.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/drivers/net/wireless/orinoco.c	Thu Mar  7 18:24:49 2002
@@ -1253,6 +1253,7 @@
 
 	/* Pass the packet to the networking stack */
 	netif_rx(skb);
+	dev->last_rx = jiffies;
 	stats->rx_packets++;
 	stats->rx_bytes += length;
 
diff -urN linux-2.5.6-pre3/drivers/pci/pci.c linux-2.5.6/drivers/pci/pci.c
--- linux-2.5.6-pre3/drivers/pci/pci.c	Thu Mar  7 18:24:29 2002
+++ linux-2.5.6/drivers/pci/pci.c	Thu Mar  7 18:24:49 2002
@@ -23,6 +23,7 @@
 #include <linux/kmod.h>		/* for hotplug_path */
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/cache.h>
 
 #include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
@@ -848,6 +849,100 @@
 	pcibios_set_master(dev);
 }
 
+/**
+ * pdev_set_mwi - arch helper function for pcibios_set_mwi
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Helper function for implementation the arch-specific pcibios_set_mwi
+ * function.  Originally copied from drivers/net/acenic.c.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pdev_set_mwi(struct pci_dev *dev)
+{
+	int rc = 0;
+	u8 cache_size;
+
+	/*
+	 * 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(dev, PCI_CACHE_LINE_SIZE, &cache_size);
+	cache_size <<= 2;
+	if (cache_size != SMP_CACHE_BYTES) {
+		printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, ",
+		       dev->slot_name, cache_size);
+		if (cache_size > SMP_CACHE_BYTES) {
+			printk("expecting %i\n", SMP_CACHE_BYTES);
+			rc = -EINVAL;
+		} else {
+			printk("correcting to %i\n", SMP_CACHE_BYTES);
+			pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+					      SMP_CACHE_BYTES >> 2);
+		}
+	}
+
+	return rc;
+}
+
+/**
+ * pci_set_mwi - enables memory-write-validate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
+ * and then calls @pcibios_set_mwi to do the needed arch specific
+ * operations or a generic mwi-prep function.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pci_set_mwi(struct pci_dev *dev)
+{
+	int rc;
+	u16 cmd;
+
+#ifdef HAVE_ARCH_PCI_MWI
+	rc = pcibios_set_mwi(dev);
+#else
+	rc = pdev_set_mwi(dev);
+#endif
+
+	if (rc)
+		return rc;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (! (cmd & PCI_COMMAND_INVALIDATE)) {
+		DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name);
+		cmd |= PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+	
+	return 0;
+}
+
+/**
+ * pci_clear_mwi - disables Memory-Write-Invalidate for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables PCI Memory-Write-Invalidate transaction on the device
+ */
+void
+pci_clear_mwi(struct pci_dev *dev)
+{
+	u16 cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	if (cmd & PCI_COMMAND_INVALIDATE) {
+		cmd &= ~PCI_COMMAND_INVALIDATE;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
 int
 pci_set_dma_mask(struct pci_dev *dev, u64 mask)
 {
@@ -2002,6 +2097,9 @@
 EXPORT_SYMBOL(pci_find_slot);
 EXPORT_SYMBOL(pci_find_subsys);
 EXPORT_SYMBOL(pci_set_master);
+EXPORT_SYMBOL(pci_set_mwi);
+EXPORT_SYMBOL(pci_clear_mwi);
+EXPORT_SYMBOL(pdev_set_mwi);
 EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_dac_set_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
@@ -2019,11 +2117,13 @@
 EXPORT_SYMBOL(pci_add_new_bus);
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
 EXPORT_SYMBOL(pci_proc_attach_bus);
 EXPORT_SYMBOL(pci_proc_detach_bus);
 #endif
+#endif
 
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
diff -urN linux-2.5.6-pre3/drivers/pci/pci.ids linux-2.5.6/drivers/pci/pci.ids
--- linux-2.5.6-pre3/drivers/pci/pci.ids	Thu Mar  7 18:24:29 2002
+++ linux-2.5.6/drivers/pci/pci.ids	Thu Mar  7 18:24:49 2002
@@ -4183,12 +4183,18 @@
 14e3  AMTELCO
 14e4  BROADCOM Corporation
 	1644  NetXtreme BCM5700 Gigabit Ethernet
+		1014 0277  Broadcom Vigil B5700 1000Base-T
+		1028 00d1  Broadcom BCM5700
+		1028 0106  Broadcom BCM5700
+		1028 0109  Broadcom BCM5700
+		1028 010a  Broadcom BCM5700
 		10b7 1000  3C996-T 1000BaseTX
 		10b7 1001  3C996B-T 1000BaseTX
 		10b7 1002  3C996C-T 1000BaseTX
 		10b7 1003  3C997-T 1000BaseTX
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1005  3C997-SX 1000BaseSX
+		10b7 1008  3C942 Gigabit LOM (31X31)
 		14e4 0002  NetXtreme 1000BaseSX
 		14e4 0003  NetXtreme 1000BaseSX
 		14e4 0004  NetXtreme 1000BaseTX
@@ -4197,6 +4203,7 @@
 		0e11 007c  NC7770 1000BaseTX
 		0e11 007d  NC6770 1000BaseSX
 		0e11 0085  NC7780 1000BaseTX
+		1028 0121  Broadcom BCM5701
 		10b7 1004  3C996-SX 1000BaseSX
 		10b7 1006  3C996B-T 1000BaseTX
 		10b7 1007  3C1000-T 1000BaseTX
@@ -4207,7 +4214,16 @@
 		14e4 0007  NetXtreme BCM5701 1000BaseSX
 		14e4 0008  NetXtreme BCM5701 1000BaseTX
 		14e4 8008  NetXtreme BCM5701 1000BaseTX
+	1646  NetXtreme BCM5702 Gigabit Ethernet
+		14e4 8009  Broadcom BCM5702
 	1647  NetXtreme BCM5703 Gigabit Ethernet
+		0e11 009a  NC7770
+		0e11 0099  NC7780
+		14e4 0009  Broadcom BCM5703
+		14e4 8009  Broadcom BCM5703
+	164d  NetXtreme BCM5702FE Gigabit Ethernet
+	16a6  NetXtreme BCM5702X Gigabit Ethernet
+	16a7  NetXtreme BCM5703X Gigabit Ethernet
 	5820  BCM5820 Crypto Accelerator
 14e5  Pixelfusion Ltd
 14e6  SHINING Technology Inc
@@ -4647,6 +4663,8 @@
 	0400  FarSync T2P (2 port X.21/V.35/V.24)
 	0440  FarSync T4P (4 port X.21/V.35/V.24)
 1668  Action Tec Electronics Inc
+173b  Altima (nee BroadCom)
+	03e8  AC1000 Gigabit Ethernet
 1813  Ambient Technologies Inc
 1a08  Sierra semiconductor
 	0000  SC15064
diff -urN linux-2.5.6-pre3/drivers/pnp/pnpbios_core.c linux-2.5.6/drivers/pnp/pnpbios_core.c
--- linux-2.5.6-pre3/drivers/pnp/pnpbios_core.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/drivers/pnp/pnpbios_core.c	Thu Mar  7 18:24:49 2002
@@ -1189,7 +1189,7 @@
 
 subsys_initcall(pnpbios_init);
 
-void __init pnpbios_init(void)
+int __init pnpbios_init(void)
 {
 	union pnp_bios_expansion_header *check;
 	u8 sum;
@@ -1200,7 +1200,7 @@
 
 	if(pnpbios_disabled) {
 		printk(KERN_INFO "PnPBIOS: Disabled.\n");
-		return;
+		return 0;
 	}
 
 	if ( is_sony_vaio_laptop )
@@ -1253,6 +1253,7 @@
 	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
 		unloading = 0;
 #endif		
+	return 0;
 }
 
 #ifdef MODULE
diff -urN linux-2.5.6-pre3/drivers/s390/net/ctctty.c linux-2.5.6/drivers/s390/net/ctctty.c
--- linux-2.5.6-pre3/drivers/s390/net/ctctty.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/drivers/s390/net/ctctty.c	Thu Mar  7 18:24:50 2002
@@ -286,7 +286,7 @@
 
 	if (!info->netdev) {
 		if (skb)
-			kfree(skb);
+			kfree_skb(skb);
 		return 0;
 	}
 	if (info->flags & CTC_ASYNC_TX_LINESTAT) {
diff -urN linux-2.5.6-pre3/drivers/scsi/sr.c linux-2.5.6/drivers/scsi/sr.c
--- linux-2.5.6-pre3/drivers/scsi/sr.c	Thu Mar  7 18:24:31 2002
+++ linux-2.5.6/drivers/scsi/sr.c	Thu Mar  7 18:24:50 2002
@@ -99,11 +99,13 @@
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
-	if (scsi_CDs[minor(cdi->dev)].device->sector_size > 2048)
+	Scsi_CD *SCp = cdi->handle;
+
+	if (SCp->device->sector_size > 2048)
 		sr_set_blocklength(minor(cdi->dev), 2048);
-	scsi_CDs[minor(cdi->dev)].device->access_count--;
-	if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
-		__MOD_DEC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
+	SCp->device->access_count--;
+	if (SCp->device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(SCp->device->host->hostt->module);
 	if (sr_template.module)
 		__MOD_DEC_USE_COUNT(sr_template.module);
 }
@@ -144,28 +146,27 @@
 
 int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
+	Scsi_CD *SCp = cdi->handle;
 	int retval;
 
 	if (CDSL_CURRENT != slot) {
 		/* no changer support */
 		return -EINVAL;
 	}
-	retval = scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
-			    SCSI_IOCTL_TEST_UNIT_READY, 0);
 
+	retval = scsi_ioctl(SCp->device, SCSI_IOCTL_TEST_UNIT_READY, 0);
 	if (retval) {
 		/* Unable to test, unit probably not ready.  This usually
 		 * means there is no disc in the drive.  Mark as changed,
 		 * and we will figure it out later once the drive is
 		 * available again.  */
-
-		scsi_CDs[minor(cdi->dev)].device->changed = 1;
+		SCp->device->changed = 1;
 		return 1;	/* This will force a flush, if called from
 				 * check_disk_change */
 	};
 
-	retval = scsi_CDs[minor(cdi->dev)].device->changed;
-	scsi_CDs[minor(cdi->dev)].device->changed = 0;
+	retval = SCp->device->changed;
+	SCp->device->changed = 0;
 	/* If the disk changed, the capacity will now be different,
 	 * so we force a re-read of this information */
 	if (retval) {
@@ -179,9 +180,8 @@
 		 * be trying to use something that is too small if the disc
 		 * has changed.
 		 */
-		scsi_CDs[minor(cdi->dev)].needs_sector_size = 1;
-
-		scsi_CDs[minor(cdi->dev)].device->sector_size = 2048;
+		SCp->needs_sector_size = 1;
+		SCp->device->sector_size = 2048;
 	}
 	return retval;
 }
@@ -198,6 +198,7 @@
 	int good_sectors = (result == 0 ? this_count : 0);
 	int block_sectors = 0;
 	int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
+	Scsi_CD *SCp = &scsi_CDs[device_nr];
 
 #ifdef DEBUG
 	printk("sr.c done: %x %p\n", result, SCpnt->request.bh->b_data);
@@ -222,7 +223,7 @@
 			block_sectors = bio_sectors(SCpnt->request.bio);
 		if (block_sectors < 4)
 			block_sectors = 4;
-		if (scsi_CDs[device_nr].device->sector_size == 2048)
+		if (SCp->device->sector_size == 2048)
 			error_sector <<= 2;
 		error_sector &= ~(block_sectors - 1);
 		good_sectors = error_sector - SCpnt->request.sector;
@@ -235,7 +236,7 @@
 		 * 75 2K sectors, we decrease the saved size value.
 		 */
 		if ((error_sector >> 1) < sr_sizes[device_nr] &&
-		    scsi_CDs[device_nr].capacity - error_sector < 4 * 75)
+		    SCp->capacity - error_sector < 4 * 75)
 			sr_sizes[device_nr] = error_sector >> 1;
 	}
 
@@ -250,32 +251,34 @@
 
 static request_queue_t *sr_find_queue(kdev_t dev)
 {
-	/*
-	 * No such device
-	 */
-	if (minor(dev) >= sr_template.dev_max || !scsi_CDs[minor(dev)].device)
-		return NULL;
+	Scsi_CD *SCp;
 
-	return &scsi_CDs[minor(dev)].device->request_queue;
+	if (minor(dev) >= sr_template.dev_max)
+		return NULL;
+	SCp = &scsi_CDs[minor(dev)];
+	if (!SCp->device)
+		return NULL;
+	return &SCp->device->request_queue;
 }
 
 static int sr_init_command(Scsi_Cmnd * SCpnt)
 {
 	int dev, devm, block=0, this_count, s_size;
+	Scsi_CD *SCp;
 
 	devm = minor(SCpnt->request.rq_dev);
 	dev = DEVICE_NR(SCpnt->request.rq_dev);
+	SCp = &scsi_CDs[dev];
 
 	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %d, block = %d\n", devm, block));
 
-	if (dev >= sr_template.nr_dev ||
-	    !scsi_CDs[dev].device ||
-	    !scsi_CDs[dev].device->online) {
+	if (dev >= sr_template.nr_dev || !SCp->device || !SCp->device->online) {
 		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
 		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
 		return 0;
 	}
-	if (scsi_CDs[dev].device->changed) {
+
+	if (SCp->device->changed) {
 		/*
 		 * quietly refuse to do anything to a changed disc until the
 		 * changed bit has been reset
@@ -292,7 +295,7 @@
 	 * we do lazy blocksize switching (when reading XA sectors,
 	 * see CDROMREADMODE2 ioctl) 
 	 */
-	s_size = scsi_CDs[dev].device->sector_size;
+	s_size = SCp->device->sector_size;
 	if (s_size > 2048) {
 		if (!in_interrupt())
 			sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev), 2048);
@@ -306,7 +309,7 @@
 	}
 
 	if (rq_data_dir(&SCpnt->request) == WRITE) {
-		if (!scsi_CDs[dev].device->writeable)
+		if (!SCp->device->writeable)
 			return 0;
 		SCpnt->cmnd[0] = WRITE_10;
 		SCpnt->sc_data_direction = SCSI_DATA_WRITE;
@@ -355,7 +358,7 @@
 	 * host adapter, it's safe to assume that we can at least transfer
 	 * this many bytes between each connect / disconnect.
 	 */
-	SCpnt->transfersize = scsi_CDs[dev].device->sector_size;
+	SCpnt->transfersize = SCp->device->sector_size;
 	SCpnt->underflow = this_count << 9;
 
 	SCpnt->allowed = MAX_RETRIES;
@@ -397,22 +400,23 @@
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
+	Scsi_CD *SCp = cdi->handle;
+
 	check_disk_change(cdi->dev);
 
-	if (minor(cdi->dev) >= sr_template.dev_max
-	    || !scsi_CDs[minor(cdi->dev)].device) {
+	if (minor(cdi->dev) >= sr_template.dev_max || !SCp->device) {
 		return -ENXIO;	/* No such device */
 	}
 	/*
 	 * If the device is in error recovery, wait until it is done.
 	 * If the device is offline, then disallow any access to it.
 	 */
-	if (!scsi_block_when_processing_errors(scsi_CDs[minor(cdi->dev)].device)) {
+	if (!scsi_block_when_processing_errors(SCp->device)) {
 		return -ENXIO;
 	}
-	scsi_CDs[minor(cdi->dev)].device->access_count++;
-	if (scsi_CDs[minor(cdi->dev)].device->host->hostt->module)
-		__MOD_INC_USE_COUNT(scsi_CDs[minor(cdi->dev)].device->host->hostt->module);
+	SCp->device->access_count++;
+	if (SCp->device->host->hostt->module)
+		__MOD_INC_USE_COUNT(SCp->device->host->hostt->module);
 	if (sr_template.module)
 		__MOD_INC_USE_COUNT(sr_template.module);
 
@@ -421,7 +425,7 @@
 	 * this is the case, and try again.
 	 */
 
-	if (scsi_CDs[minor(cdi->dev)].needs_sector_size)
+	if (SCp->needs_sector_size)
 		get_sectorsize(minor(cdi->dev));
 
 	return 0;
@@ -472,31 +476,25 @@
 {
 	unsigned char cmd[10];
 	unsigned char *buffer;
-	int the_result, retries;
+	int the_result, retries = 3;
 	int sector_size;
-	Scsi_Request *SRpnt;
+	Scsi_Request *SRpnt = NULL;
+	Scsi_CD *SCp;
 	request_queue_t *queue;
 
-	buffer = (unsigned char *) kmalloc(512, GFP_DMA);
-	SRpnt = scsi_allocate_request(scsi_CDs[i].device);
-	
-	if(buffer == NULL || SRpnt == NULL)
-	{
-		scsi_CDs[i].capacity = 0x1fffff;
-		sector_size = 2048;	/* A guess, just in case */
-		scsi_CDs[i].needs_sector_size = 1;
-		if(buffer)
-			kfree(buffer);
-		if(SRpnt)
-			scsi_release_request(SRpnt);
-		return;
-	}	
+	SCp = &scsi_CDs[i];
+
+	buffer = kmalloc(512, GFP_DMA);
+	if (!buffer)
+		goto Enomem;
+	SRpnt = scsi_allocate_request(SCp->device);
+	if (!SRpnt)
+		goto Enomem;
 
-	retries = 3;
 	do {
 		cmd[0] = READ_CAPACITY;
-		cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
-			 ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
+		cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+			 ((SCp->device->lun << 5) & 0xe0) : 0;
 		memset((void *) &cmd[2], 0, 8);
 		SRpnt->sr_request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
 		SRpnt->sr_cmd_len = 0;
@@ -519,15 +517,15 @@
 	SRpnt = NULL;
 
 	if (the_result) {
-		scsi_CDs[i].capacity = 0x1fffff;
+		SCp->capacity = 0x1fffff;
 		sector_size = 2048;	/* A guess, just in case */
-		scsi_CDs[i].needs_sector_size = 1;
+		SCp->needs_sector_size = 1;
 	} else {
 #if 0
 		if (cdrom_get_last_written(mkdev(MAJOR_NR, i),
 					   &scsi_CDs[i].capacity))
 #endif
-			scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
+			SCp->capacity = 1 + ((buffer[0] << 24) |
 						    (buffer[1] << 16) |
 						    (buffer[2] << 8) |
 						    buffer[3]);
@@ -546,33 +544,45 @@
 			sector_size = 2048;
 			/* fall through */
 		case 2048:
-			scsi_CDs[i].capacity *= 4;
+			SCp->capacity *= 4;
 			/* fall through */
 		case 512:
 			break;
 		default:
 			printk("sr%d: unsupported sector size %d.\n",
 			       i, sector_size);
-			scsi_CDs[i].capacity = 0;
-			scsi_CDs[i].needs_sector_size = 1;
+			SCp->capacity = 0;
+			SCp->needs_sector_size = 1;
 		}
 
-		scsi_CDs[i].device->sector_size = sector_size;
+		SCp->device->sector_size = sector_size;
 
 		/*
 		 * Add this so that we have the ability to correctly gauge
 		 * what the device is capable of.
 		 */
-		scsi_CDs[i].needs_sector_size = 0;
-		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
+		SCp->needs_sector_size = 0;
+		sr_sizes[i] = SCp->capacity >> (BLOCK_SIZE_BITS - 9);
 	}
-	queue = &scsi_CDs[i].device->request_queue;
+
+	queue = &SCp->device->request_queue;
 	blk_queue_hardsect_size(queue, sector_size);
+out:
 	kfree(buffer);
+	return;
+
+Enomem:
+	SCp->capacity = 0x1fffff;
+	sector_size = 2048;	/* A guess, just in case */
+	SCp->needs_sector_size = 1;
+	if (SRpnt)
+		scsi_release_request(SRpnt);
+	goto out;
 }
 
 void get_capabilities(int i)
 {
+	Scsi_CD *SCp;
 	unsigned char cmd[6];
 	unsigned char *buffer;
 	int rc, n;
@@ -589,15 +599,16 @@
 		""
 	};
 
-	buffer = (unsigned char *) kmalloc(512, GFP_DMA);
+	SCp = &scsi_CDs[i];
+	buffer = kmalloc(512, GFP_DMA);
 	if (!buffer)
 	{
 		printk(KERN_ERR "sr: out of memory.\n");
 		return;
 	}
 	cmd[0] = MODE_SENSE;
-	cmd[1] = (scsi_CDs[i].device->scsi_level <= SCSI_2) ?
-		 ((scsi_CDs[i].device->lun << 5) & 0xe0) : 0;
+	cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+		 ((SCp->device->lun << 5) & 0xe0) : 0;
 	cmd[2] = 0x2a;
 	cmd[4] = 128;
 	cmd[3] = cmd[5] = 0;
@@ -605,8 +616,8 @@
 
 	if (rc) {
 		/* failed, drive doesn't have capabilities mode page */
-		scsi_CDs[i].cdi.speed = 1;
-		scsi_CDs[i].cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
+		SCp->cdi.speed = 1;
+		SCp->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
 					 CDC_DVD | CDC_DVD_RAM |
 					 CDC_SELECT_DISC | CDC_SELECT_SPEED);
 		kfree(buffer);
@@ -614,13 +625,13 @@
 		return;
 	}
 	n = buffer[3] + 4;
-	scsi_CDs[i].cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
-	scsi_CDs[i].readcd_known = 1;
-	scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01;
+	SCp->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
+	SCp->readcd_known = 1;
+	SCp->readcd_cdda = buffer[n + 5] & 0x01;
 	/* print some capability bits */
 	printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", i,
 	       ((buffer[n + 14] << 8) + buffer[n + 15]) / 176,
-	       scsi_CDs[i].cdi.speed,
+	       SCp->cdi.speed,
 	       buffer[n + 3] & 0x01 ? "writer " : "",	/* CD Writer */
 	       buffer[n + 3] & 0x20 ? "dvd-ram " : "",
 	       buffer[n + 2] & 0x02 ? "cd/rw " : "",	/* can read rewriteable */
@@ -629,38 +640,38 @@
 	       loadmech[buffer[n + 6] >> 5]);
 	if ((buffer[n + 6] >> 5) == 0)
 		/* caddy drives can't close tray... */
-		scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+		SCp->cdi.mask |= CDC_CLOSE_TRAY;
 	if ((buffer[n + 2] & 0x8) == 0)
 		/* not a DVD drive */
-		scsi_CDs[i].cdi.mask |= CDC_DVD;
+		SCp->cdi.mask |= CDC_DVD;
 	if ((buffer[n + 3] & 0x20) == 0) {
 		/* can't write DVD-RAM media */
-		scsi_CDs[i].cdi.mask |= CDC_DVD_RAM;
+		SCp->cdi.mask |= CDC_DVD_RAM;
 	} else {
-		scsi_CDs[i].device->writeable = 1;
+		SCp->device->writeable = 1;
 	}
 	if ((buffer[n + 3] & 0x10) == 0)
 		/* can't write DVD-R media */
-		scsi_CDs[i].cdi.mask |= CDC_DVD_R;
+		SCp->cdi.mask |= CDC_DVD_R;
 	if ((buffer[n + 3] & 0x2) == 0)
 		/* can't write CD-RW media */
-		scsi_CDs[i].cdi.mask |= CDC_CD_RW;
+		SCp->cdi.mask |= CDC_CD_RW;
 	if ((buffer[n + 3] & 0x1) == 0)
 		/* can't write CD-R media */
-		scsi_CDs[i].cdi.mask |= CDC_CD_R;
+		SCp->cdi.mask |= CDC_CD_R;
 	if ((buffer[n + 6] & 0x8) == 0)
 		/* can't eject */
-		scsi_CDs[i].cdi.mask |= CDC_OPEN_TRAY;
+		SCp->cdi.mask |= CDC_OPEN_TRAY;
 
 	if ((buffer[n + 6] >> 5) == mechtype_individual_changer ||
 	    (buffer[n + 6] >> 5) == mechtype_cartridge_changer)
-		scsi_CDs[i].cdi.capacity =
-		    cdrom_number_of_slots(&(scsi_CDs[i].cdi));
-	if (scsi_CDs[i].cdi.capacity <= 1)
+		SCp->cdi.capacity =
+		    cdrom_number_of_slots(&SCp->cdi);
+	if (SCp->cdi.capacity <= 1)
 		/* not a changer */
-		scsi_CDs[i].cdi.mask |= CDC_SELECT_DISC;
+		SCp->cdi.mask |= CDC_SELECT_DISC;
 	/*else    I don't think it can close its tray
-	   scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY; */
+		SCp->cdi.mask |= CDC_CLOSE_TRAY; */
 
 	kfree(buffer);
 }
@@ -671,8 +682,9 @@
  */
 static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
 {
-	Scsi_Device *device = scsi_CDs[minor(cdi->dev)].device;
-
+	Scsi_CD *SCp = cdi->handle;
+	Scsi_Device *device = SCp->device;
+	
 	/* set the LUN */
 	if (device->scsi_level <= SCSI_2)
 		cgc->cmd[1] |= device->lun << 5;
@@ -743,47 +755,47 @@
 	blk_size[MAJOR_NR] = sr_sizes;
 
 	for (i = 0; i < sr_template.nr_dev; ++i) {
+		Scsi_CD *SCp = &scsi_CDs[i];
 		/* If we have already seen this, then skip it.  Comes up
 		 * with loadable modules. */
-		if (scsi_CDs[i].capacity)
+		if (SCp->capacity)
 			continue;
-		scsi_CDs[i].capacity = 0x1fffff;
-		scsi_CDs[i].device->sector_size = 2048;		/* A guess, just in case */
-		scsi_CDs[i].needs_sector_size = 1;
-		scsi_CDs[i].device->changed = 1;	/* force recheck CD type */
+		SCp->capacity = 0x1fffff;
+		SCp->device->sector_size = 2048;/* A guess, just in case */
+		SCp->needs_sector_size = 1;
+		SCp->device->changed = 1;	/* force recheck CD type */
 #if 0
 		/* seems better to leave this for later */
 		get_sectorsize(i);
-		printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
+		printk("Scd sectorsize = %d bytes.\n", SCp->sector_size);
 #endif
-		scsi_CDs[i].use = 1;
+		SCp->use = 1;
 
-		scsi_CDs[i].device->ten = 1;
-		scsi_CDs[i].device->remap = 1;
-		scsi_CDs[i].readcd_known = 0;
-		scsi_CDs[i].readcd_cdda = 0;
-		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
-
-		scsi_CDs[i].cdi.ops = &sr_dops;
-		scsi_CDs[i].cdi.handle = &scsi_CDs[i];
-		scsi_CDs[i].cdi.dev = mk_kdev(MAJOR_NR, i);
-		scsi_CDs[i].cdi.mask = 0;
-		scsi_CDs[i].cdi.capacity = 1;
+		SCp->device->ten = 1;
+		SCp->device->remap = 1;
+		SCp->readcd_known = 0;
+		SCp->readcd_cdda = 0;
+		sr_sizes[i] = SCp->capacity >> (BLOCK_SIZE_BITS - 9);
+
+		SCp->cdi.ops = &sr_dops;
+		SCp->cdi.handle = SCp;
+		SCp->cdi.dev = mk_kdev(MAJOR_NR, i);
+		SCp->cdi.mask = 0;
+		SCp->cdi.capacity = 1;
 		/*
 		 *	FIXME: someone needs to handle a get_capabilities
 		 *	failure properly ??
 		 */
 		get_capabilities(i);
-		sr_vendor_init(i);
+		sr_vendor_init(SCp);
 
 		sprintf(name, "sr%d", i);
-		strcpy(scsi_CDs[i].cdi.name, name);
-                scsi_CDs[i].cdi.de =
-                    devfs_register (scsi_CDs[i].device->de, "cd",
+		strcpy(SCp->cdi.name, name);
+                SCp->cdi.de = devfs_register(SCp->device->de, "cd",
                                     DEVFS_FL_DEFAULT, MAJOR_NR, i,
                                     S_IFBLK | S_IRUGO | S_IWUGO,
                                     &sr_bdops, NULL);
-		register_cdrom(&scsi_CDs[i].cdi);
+		register_cdrom(&SCp->cdi);
 	}
 }
 
diff -urN linux-2.5.6-pre3/drivers/scsi/sr.h linux-2.5.6/drivers/scsi/sr.h
--- linux-2.5.6-pre3/drivers/scsi/sr.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/drivers/scsi/sr.h	Thu Mar  7 18:24:50 2002
@@ -53,7 +53,7 @@
 int sr_is_xa(int minor);
 
 /* sr_vendor.c */
-void sr_vendor_init(int minor);
+void sr_vendor_init(Scsi_CD *);
 int sr_cd_check(struct cdrom_device_info *);
 int sr_set_blocklength(int minor, int blocklength);
 
diff -urN linux-2.5.6-pre3/drivers/scsi/sr_ioctl.c linux-2.5.6/drivers/scsi/sr_ioctl.c
--- linux-2.5.6-pre3/drivers/scsi/sr_ioctl.c	Thu Mar  7 18:24:31 2002
+++ linux-2.5.6/drivers/scsi/sr_ioctl.c	Thu Mar  7 18:24:51 2002
@@ -84,7 +84,7 @@
 	char *bounce_buffer;
 
 	SDev = scsi_CDs[target].device;
-	SRpnt = scsi_allocate_request(scsi_CDs[target].device);
+	SRpnt = scsi_allocate_request(SDev);
         if (!SRpnt) {
                 printk("Unable to allocate SCSI request in sr_do_ioctl");
                 return -ENOMEM;
@@ -124,7 +124,7 @@
 	if (driver_byte(result) != 0) {
 		switch (SRpnt->sr_sense_buffer[2] & 0xf) {
 		case UNIT_ATTENTION:
-			scsi_CDs[target].device->changed = 1;
+			SDev->changed = 1;
 			if (!quiet)
 				printk(KERN_INFO "sr%d: disc change detected.\n", target);
 			if (retries++ < 10)
@@ -192,22 +192,25 @@
 
 static int test_unit_ready(int minor)
 {
+	Scsi_CD *SCp;
 	u_char sr_cmd[10];
 
+	SCp = &scsi_CDs[minor];
 	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
-	sr_cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[minor].device->lun) << 5) : 0;
+	sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	            ((SCp->device->lun) << 5) : 0;
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 	return sr_do_ioctl(minor, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
 }
 
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
+	Scsi_CD *SCp = cdi->handle;
 	u_char sr_cmd[10];
 
 	sr_cmd[0] = GPCMD_START_STOP_UNIT;
-	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	            ((SCp->device->lun) << 5) : 0;
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
 
@@ -216,9 +219,10 @@
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 {
-	return scsi_ioctl(scsi_CDs[minor(cdi->dev)].device,
-		      lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
-			  0);
+	Scsi_CD *SCp = cdi->handle;
+
+	return scsi_ioctl(SCp->device, lock ? SCSI_IOCTL_DOORLOCK :
+			SCSI_IOCTL_DOORUNLOCK, 0);
 }
 
 int sr_drive_status(struct cdrom_device_info *cdi, int slot)
@@ -235,6 +239,7 @@
 
 int sr_disk_status(struct cdrom_device_info *cdi)
 {
+	Scsi_CD *SCp = cdi->handle;
 	struct cdrom_tochdr toc_h;
 	struct cdrom_tocentry toc_e;
 	int i, rc, have_datatracks = 0;
@@ -256,7 +261,7 @@
 	if (!have_datatracks)
 		return CDS_AUDIO;
 
-	if (scsi_CDs[minor(cdi->dev)].xa_flag)
+	if (SCp->xa_flag)
 		return CDS_XA_2_1;
 	else
 		return CDS_DATA_1;
@@ -265,22 +270,24 @@
 int sr_get_last_session(struct cdrom_device_info *cdi,
 			struct cdrom_multisession *ms_info)
 {
-	ms_info->addr.lba = scsi_CDs[minor(cdi->dev)].ms_offset;
-	ms_info->xa_flag = scsi_CDs[minor(cdi->dev)].xa_flag ||
-	    (scsi_CDs[minor(cdi->dev)].ms_offset > 0);
+	Scsi_CD *SCp = cdi->handle;
+
+	ms_info->addr.lba = SCp->ms_offset;
+	ms_info->xa_flag = SCp->xa_flag || SCp->ms_offset > 0;
 
 	return 0;
 }
 
 int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
+	Scsi_CD *SCp = cdi->handle;
 	u_char sr_cmd[10];
 	char buffer[32];
 	int result;
 
 	sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
-	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	            ((SCp->device->lun) << 5) : 0;
 	sr_cmd[2] = 0x40;	/* I do want the subchannel info */
 	sr_cmd[3] = 0x02;	/* Give me medium catalog number info */
 	sr_cmd[4] = sr_cmd[5] = 0;
@@ -305,6 +312,7 @@
 
 int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 {
+	Scsi_CD *SCp = cdi->handle;
 	u_char sr_cmd[MAX_COMMAND_SIZE];
 
 	if (speed == 0)
@@ -314,8 +322,8 @@
 
 	memset(sr_cmd, 0, MAX_COMMAND_SIZE);
 	sr_cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
-	sr_cmd[1] = (scsi_CDs[minor(cdi->dev)].device->scsi_level <= SCSI_2) ?
-	            ((scsi_CDs[minor(cdi->dev)].device->lun) << 5) : 0;
+	sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	            ((SCp->device->lun) << 5) : 0;
 	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
 	sr_cmd[3] = speed & 0xff;	/* LSB */
 
@@ -332,6 +340,7 @@
 
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
+	Scsi_CD *SCp = cdi->handle;
 	u_char sr_cmd[10];
 	int result, target = minor(cdi->dev);
 	unsigned char buffer[32];
@@ -344,8 +353,8 @@
 			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 
 			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
-			            ((scsi_CDs[target].device->lun) << 5) : 0;
+			sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+			            ((SCp->device->lun) << 5) : 0;
 			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 			sr_cmd[8] = 12;		/* LSB of length */
 
@@ -362,8 +371,8 @@
 			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
 
 			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
-			            ((scsi_CDs[target].device->lun) << 5) : 0;
+			sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+			            ((SCp->device->lun) << 5) : 0;
 			sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
 			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
 			sr_cmd[6] = tocentry->cdte_track;
@@ -389,8 +398,8 @@
 		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
 
 		sr_cmd[0] = GPCMD_PLAYAUDIO_TI;
-		sr_cmd[1] = (scsi_CDs[target].device->scsi_level <= SCSI_2) ?
-		            (scsi_CDs[target].device->lun << 5) : 0;
+		sr_cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+		            (SCp->device->lun << 5) : 0;
 		sr_cmd[4] = ti->cdti_trk0;
 		sr_cmd[5] = ti->cdti_ind0;
 		sr_cmd[7] = ti->cdti_trk1;
@@ -432,6 +441,7 @@
 int sr_read_cd(int minor, unsigned char *dest, int lba, int format, int blksize)
 {
 	unsigned char cmd[MAX_COMMAND_SIZE];
+	Scsi_CD *SCp = &scsi_CDs[minor];
 
 #ifdef DEBUG
 	printk("sr%d: sr_read_cd lba=%d format=%d blksize=%d\n",
@@ -440,8 +450,8 @@
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = GPCMD_READ_CD;	/* READ_CD */
-	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-	         (scsi_CDs[minor].device->lun << 5) : 0;
+	cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	         (SCp->device->lun << 5) : 0;
 	cmd[1] |= ((format & 7) << 2);
 	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
 	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
@@ -472,19 +482,20 @@
 int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest)
 {
 	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
+	Scsi_CD *SCp = &scsi_CDs[minor];
 	int rc;
 
 	/* we try the READ CD command first... */
-	if (scsi_CDs[minor].readcd_known) {
+	if (SCp->readcd_known) {
 		rc = sr_read_cd(minor, dest, lba, 0, blksize);
 		if (-EDRIVE_CANT_DO_THIS != rc)
 			return rc;
-		scsi_CDs[minor].readcd_known = 0;
+		SCp->readcd_known = 0;
 		printk("CDROM does'nt support READ CD (0xbe) command\n");
 		/* fall & retry the other way */
 	}
 	/* ... if this fails, we switch the blocksize using MODE SELECT */
-	if (blksize != scsi_CDs[minor].device->sector_size) {
+	if (blksize != SCp->device->sector_size) {
 		if (0 != (rc = sr_set_blocklength(minor, blksize)))
 			return rc;
 	}
@@ -494,8 +505,8 @@
 
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = GPCMD_READ_10;
-	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-	         (scsi_CDs[minor].device->lun << 5) : 0;
+	cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	         (SCp->device->lun << 5) : 0;
 	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
 	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
 	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
@@ -514,6 +525,7 @@
 int sr_is_xa(int minor)
 {
 	unsigned char *raw_sector;
+	Scsi_CD *SCp = &scsi_CDs[minor];
 	int is_xa;
 
 	if (!xa_test)
@@ -522,7 +534,7 @@
 	raw_sector = (unsigned char *) kmalloc(2048, GFP_DMA | GFP_KERNEL);
 	if (!raw_sector)
 		return -ENOMEM;
-	if (0 == sr_read_sector(minor, scsi_CDs[minor].ms_offset + 16,
+	if (0 == sr_read_sector(minor, SCp->ms_offset + 16,
 				CD_FRAMESIZE_RAW1, raw_sector)) {
 		is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
 	} else {
@@ -539,18 +551,16 @@
 int sr_dev_ioctl(struct cdrom_device_info *cdi,
 		 unsigned int cmd, unsigned long arg)
 {
-	int target;
-
-	target = minor(cdi->dev);
+	Scsi_CD *SCp = cdi->handle;
 
 	switch (cmd) {
 	case BLKGETSIZE:
-		return put_user(scsi_CDs[target].capacity, (unsigned long *) arg);
+		return put_user(SCp->capacity, (unsigned long *) arg);
 	case BLKGETSIZE64:
-		return put_user((u64)scsi_CDs[target].capacity << 9, (u64 *)arg);
+		return put_user((u64)SCp->capacity << 9, (u64 *)arg);
 
 	default:
-		return scsi_ioctl(scsi_CDs[target].device, cmd, (void *) arg);
+		return scsi_ioctl(SCp->device, cmd, (void *)arg);
 	}
 }
 
diff -urN linux-2.5.6-pre3/drivers/scsi/sr_vendor.c linux-2.5.6/drivers/scsi/sr_vendor.c
--- linux-2.5.6-pre3/drivers/scsi/sr_vendor.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/scsi/sr_vendor.c	Thu Mar  7 18:24:51 2002
@@ -58,27 +58,25 @@
 #define VENDOR_TOSHIBA         3
 #define VENDOR_WRITER          4	/* pre-scsi3 writers */
 
-#define VENDOR_ID (scsi_CDs[minor].vendor)
-
-void sr_vendor_init(int minor)
+void sr_vendor_init(Scsi_CD *SCp)
 {
 #ifndef CONFIG_BLK_DEV_SR_VENDOR
-	VENDOR_ID = VENDOR_SCSI3;
+	SCp->vendor = VENDOR_SCSI3;
 #else
-	char *vendor = scsi_CDs[minor].device->vendor;
-	char *model = scsi_CDs[minor].device->model;
-
+	char *vendor = SCp->device->vendor;
+	char *model = SCp->device->model;
+	
 	/* default */
-	VENDOR_ID = VENDOR_SCSI3;
-	if (scsi_CDs[minor].readcd_known)
+	SCp->vendor = VENDOR_SCSI3;
+	if (SCp->readcd_known)
 		/* this is true for scsi3/mmc drives - no more checks */
 		return;
 
-	if (scsi_CDs[minor].device->type == TYPE_WORM) {
-		VENDOR_ID = VENDOR_WRITER;
+	if (SCp->device->type == TYPE_WORM) {
+		SCp->vendor = VENDOR_WRITER;
 
 	} else if (!strncmp(vendor, "NEC", 3)) {
-		VENDOR_ID = VENDOR_NEC;
+		SCp->vendor = VENDOR_NEC;
 		if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
 		    !strncmp(model, "CD-ROM DRIVE:36", 15) ||
 		    !strncmp(model, "CD-ROM DRIVE:83", 15) ||
@@ -90,10 +88,10 @@
 #endif
 		    )
 			/* these can't handle multisession, may hang */
-			scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
+			SCp->cdi.mask |= CDC_MULTI_SESSION;
 
 	} else if (!strncmp(vendor, "TOSHIBA", 7)) {
-		VENDOR_ID = VENDOR_TOSHIBA;
+		SCp->vendor = VENDOR_TOSHIBA;
 
 	}
 #endif
@@ -108,10 +106,11 @@
 	unsigned char *buffer;	/* the buffer for the ioctl */
 	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
 	struct ccs_modesel_head *modesel;
+	Scsi_CD *SCp = &scsi_CDs[minor];
 	int rc, density = 0;
 
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
-	if (VENDOR_ID == VENDOR_TOSHIBA)
+	if (SCp->vendor == VENDOR_TOSHIBA)
 		density = (blocklength > 2048) ? 0x81 : 0x83;
 #endif
 
@@ -124,8 +123,8 @@
 #endif
 	memset(cmd, 0, MAX_COMMAND_SIZE);
 	cmd[0] = MODE_SELECT;
-	cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-	         (scsi_CDs[minor].device->lun << 5) : 0;
+	cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+	         (SCp->device->lun << 5) : 0;
 	cmd[1] |= (1 << 4);
 	cmd[4] = 12;
 	modesel = (struct ccs_modesel_head *) buffer;
@@ -135,7 +134,7 @@
 	modesel->block_length_med = (blocklength >> 8) & 0xff;
 	modesel->block_length_lo = blocklength & 0xff;
 	if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) {
-		scsi_CDs[minor].device->sector_size = blocklength;
+		SCp->device->sector_size = blocklength;
 	}
 #ifdef DEBUG
 	else
@@ -153,13 +152,14 @@
 
 int sr_cd_check(struct cdrom_device_info *cdi)
 {
+	Scsi_CD *SCp = cdi->handle;
 	unsigned long sector;
 	unsigned char *buffer;	/* the buffer for the ioctl */
 	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
 	int rc, no_multi, minor;
 
 	minor = minor(cdi->dev);
-	if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
+	if (SCp->cdi.mask & CDC_MULTI_SESSION)
 		return 0;
 
 	buffer = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
@@ -170,13 +170,13 @@
 	no_multi = 0;		/* flag: the drive can't handle multisession */
 	rc = 0;
 
-	switch (VENDOR_ID) {
+	switch (SCp->vendor) {
 
 	case VENDOR_SCSI3:
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_TOC;
-		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-		         (scsi_CDs[minor].device->lun << 5) : 0;
+		cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+		         (SCp->device->lun << 5) : 0;
 		cmd[8] = 12;
 		cmd[9] = 0x40;
 		rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
@@ -201,8 +201,8 @@
 			unsigned long min, sec, frame;
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xde;
-			cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-			         (scsi_CDs[minor].device->lun << 5) : 0;
+			cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+			         (SCp->device->lun << 5) : 0;
 			cmd[1] |= 0x03;
 			cmd[2] = 0xb0;
 			rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
@@ -228,8 +228,8 @@
 			 * where starts the last session ?) */
 			memset(cmd, 0, MAX_COMMAND_SIZE);
 			cmd[0] = 0xc7;
-			cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-			         (scsi_CDs[minor].device->lun << 5) : 0;
+			cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+			         (SCp->device->lun << 5) : 0;
 			cmd[1] |= 0x03;
 			rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
 			if (rc == -EINVAL) {
@@ -253,8 +253,8 @@
 	case VENDOR_WRITER:
 		memset(cmd, 0, MAX_COMMAND_SIZE);
 		cmd[0] = READ_TOC;
-		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-		         (scsi_CDs[minor].device->lun << 5) : 0;
+		cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+		         (SCp->device->lun << 5) : 0;
 		cmd[8] = 0x04;
 		cmd[9] = 0x40;
 		rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
@@ -267,8 +267,8 @@
 			break;
 		}
 		cmd[0] = READ_TOC;	/* Read TOC */
-		cmd[1] = (scsi_CDs[minor].device->scsi_level <= SCSI_2) ?
-		         (scsi_CDs[minor].device->lun << 5) : 0;
+		cmd[1] = (SCp->device->scsi_level <= SCSI_2) ?
+		         (SCp->device->lun << 5) : 0;
 		cmd[6] = rc & 0x7f;	/* number of last session */
 		cmd[8] = 0x0c;
 		cmd[9] = 0x40;
@@ -285,17 +285,17 @@
 		/* should not happen */
 		printk(KERN_WARNING
 		   "sr%d: unknown vendor code (%i), not initialized ?\n",
-		       minor, VENDOR_ID);
+		       minor, SCp->vendor);
 		sector = 0;
 		no_multi = 1;
 		break;
 	}
-	scsi_CDs[minor].ms_offset = sector;
-	scsi_CDs[minor].xa_flag = 0;
+	SCp->ms_offset = sector;
+	SCp->xa_flag = 0;
 	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(minor))
-		scsi_CDs[minor].xa_flag = 1;
+		SCp->xa_flag = 1;
 
-	if (2048 != scsi_CDs[minor].device->sector_size) {
+	if (2048 != SCp->device->sector_size) {
 		sr_set_blocklength(minor, 2048);
 	}
 	if (no_multi)
diff -urN linux-2.5.6-pre3/drivers/usb/Config.in linux-2.5.6/drivers/usb/Config.in
--- linux-2.5.6-pre3/drivers/usb/Config.in	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/drivers/usb/Config.in	Thu Mar  7 18:24:51 2002
@@ -8,7 +8,7 @@
 if [ "$CONFIG_USB" = "y" -o  "$CONFIG_USB" = "m" ]; then
    bool '  USB verbose debug messages' CONFIG_USB_DEBUG
 
-comment 'Miscellaneous USB options'
+   comment 'Miscellaneous USB options'
    bool '  USB device filesystem' CONFIG_USB_DEVICEFS
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool '  Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH
@@ -16,90 +16,90 @@
       define_bool CONFIG_USB_BANDWIDTH n
    fi
    bool '  Long timeout for slow-responding devices (some MGE Ellipse UPSes)' CONFIG_USB_LONG_TIMEOUT
-fi
 
-comment 'USB Host Controller Drivers'
-source drivers/usb/hcd/Config.in
-if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-   dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-fi
-if [ "$CONFIG_USB_UHCI" != "y" ]; then
-   dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-else
-   define_bool CONFIG_USB_UHCI_ALT n
-fi
-dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+   comment 'USB Host Controller Drivers'
+   source drivers/usb/hcd/Config.in
+   if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
+      dep_tristate '  UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
+   fi
+   if [ "$CONFIG_USB_UHCI" != "y" ]; then
+      dep_tristate '  UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
+   else
+      define_bool CONFIG_USB_UHCI_ALT n
+   fi
+   dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
-comment 'USB Device Class drivers'
-dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
-dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_SCSI" = "n" ]; then
-   comment '  SCSI support is needed for USB Storage'
-fi
-dep_tristate '  USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
-   dep_mbool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
-   dep_mbool '    Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
-   dep_mbool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM  $CONFIG_USB_STORAGE
-   dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
-   dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
-   dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
-   dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
-   dep_mbool '    Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
-dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-
-comment 'USB Human Interface Devices (HID)'
-if [ "$CONFIG_INPUT" = "n" ]; then
-   comment '  Input core support is needed for USB HID'
-else
-   dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
-      dep_mbool '    /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
-   if [ "$CONFIG_USB_HID" != "y" ]; then
-      dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
-      dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
+   comment 'USB Device Class drivers'
+   dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+   dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_SCSI" = "n" ]; then
+      comment '  SCSI support is needed for USB Storage'
+   fi
+   dep_tristate '  USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
+      dep_mbool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
+      dep_mbool '    Datafab MDCFE-B Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+      dep_mbool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM  $CONFIG_USB_STORAGE
+      dep_mbool '    ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
+      dep_mbool '    Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
+      dep_mbool '    HP CD-Writer 82xx support' CONFIG_USB_STORAGE_HP8200e $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+      dep_mbool '    SanDisk SDDR-09 (and other SmartMedia) support' CONFIG_USB_STORAGE_SDDR09 $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+      dep_mbool '    Lexar Jumpshot Compact Flash Reader' CONFIG_USB_STORAGE_JUMPSHOT $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
+
+   comment 'USB Human Interface Devices (HID)'
+   if [ "$CONFIG_INPUT" = "n" ]; then
+      comment '  Input core support is needed for USB HID'
+   else
+      dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB $CONFIG_INPUT
+         dep_mbool '    /dev/hiddev raw HID device support (EXPERIMENTAL)' CONFIG_USB_HIDDEV $CONFIG_USB_HID
+      if [ "$CONFIG_USB_HID" != "y" ]; then
+         dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT
+         dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT
+      fi
+      dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
    fi
-   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_INPUT
-fi
 
-comment 'USB Imaging devices'
-dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
-dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
-dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
-dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
-
-comment 'USB Multimedia devices'
-if [ "$CONFIG_VIDEO_DEV" = "n" ]; then
-   comment '  Video4Linux support is needed for USB Multimedia device support'
-else
-   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
-   dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
-   dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
-   dep_tristate '  USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
-fi
+   comment 'USB Imaging devices'
+   dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+   dep_tristate '  Microtek X6USB scanner support' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI
+   dep_tristate '  HP53xx USB scanner support (EXPERIMENTAL)' CONFIG_USB_HPUSBSCSI $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+
+   comment 'USB Multimedia devices'
+   if [ "$CONFIG_VIDEO_DEV" = "n" ]; then
+      comment '  Video4Linux support is needed for USB Multimedia device support'
+   else
+      dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB Philips Cameras' CONFIG_USB_PWC $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB SE401 Camera support' CONFIG_USB_SE401 $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB STV680 (Pencam) Camera support' CONFIG_USB_STV680 $CONFIG_USB $CONFIG_VIDEO_DEV
+      dep_tristate '  USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)' CONFIG_USB_VICAM $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+      dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+      dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+      dep_tristate '  USB Konica Webcam support' CONFIG_USB_KONICAWC $CONFIG_USB $CONFIG_VIDEO_DEV
+   fi
 
-comment 'USB Network adaptors'
-if [ "$CONFIG_NET" = "n" ]; then
-   comment '  Networking support is needed for USB Networking device support'
-else
-   dep_tristate '  USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-fi
+   comment 'USB Network adaptors'
+   if [ "$CONFIG_NET" = "n" ]; then
+      comment '  Networking support is needed for USB Networking device support'
+   else
+      dep_tristate '  USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB CATC NetMate-based Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB Communication Class Ethernet device support (EXPERIMENTAL)' CONFIG_USB_CDCETHER $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB-to-USB Networking cable device support (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   fi
 
-comment 'USB port drivers'
-dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
-source drivers/usb/serial/Config.in
-
-comment 'USB Miscellaneous drivers'
-dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
+   comment 'USB port drivers'
+   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+   source drivers/usb/serial/Config.in
+
+   comment 'USB Miscellaneous drivers'
+   dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Auerswald ISDN support (EXPERIMENTAL)' CONFIG_USB_AUERSWALD $CONFIG_USB $CONFIG_EXPERIMENTAL
 
+fi
 endmenu
diff -urN linux-2.5.6-pre3/drivers/usb/hcd/ehci-hcd.c linux-2.5.6/drivers/usb/hcd/ehci-hcd.c
--- linux-2.5.6-pre3/drivers/usb/hcd/ehci-hcd.c	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd/ehci-hcd.c	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2001 by David Brownell
+ * Copyright (c) 2000-2002 by David Brownell
  * 
  * 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
@@ -31,10 +31,6 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 
-#ifndef CONFIG_USB_DEBUG
-	#define CONFIG_USB_DEBUG	/* this is still experimental! */
-#endif
-
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
 #else
@@ -73,19 +69,25 @@
  *	...
  *
  * HISTORY:
+ *
+ * 2002-03-05	Initial high-speed ISO support; reduce ITD memory; shift
+ *	more checking to generic hcd framework (db).  Make it work with
+ *	Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
  * 2002-01-14	Minor cleanup; version synch.
  * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
  * 2002-01-04	Control/Bulk queuing behaves.
+ *
  * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
+ * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "$Revision: 0.26 $"
+#define DRIVER_VERSION "$Revision: 0.27 $"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
 
 // #define EHCI_VERBOSE_DEBUG
-// #define have_iso
+// #define have_split_iso
 
 #ifdef	CONFIG_DEBUG_SLAB
 #	define	EHCI_SLAB_FLAGS		(SLAB_POISON)
@@ -187,6 +189,9 @@
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
+	/* cache this readonly data; minimize PCI reads */
+	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -204,7 +209,7 @@
 
 	ehci->async = 0;
 	ehci->reclaim = 0;
-	ehci->next_frame = -1;
+	ehci->next_uframe = -1;
 
 	/* controller state:  unknown --> reset */
 
@@ -310,7 +315,7 @@
 
 	// root hub is shut down separately (first, when possible)
 	scan_async (ehci);
-	if (ehci->next_frame != -1)
+	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
 	ehci_mem_cleanup (ehci);
 
@@ -332,14 +337,12 @@
 static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			params;
 	int			ports;
 	int			i;
 
 	dbg ("%s: suspend to %d", hcd->bus_name, state);
 
-	params = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (params);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 
 	// FIXME:  This assumes what's probably a D3 level suspend...
 
@@ -375,14 +378,12 @@
 static int ehci_resume (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			params;
 	int			ports;
 	int			i;
 
 	dbg ("%s: resume", hcd->bus_name);
 
-	params = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (params);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 
 	// FIXME:  if controller didn't retain state,
 	// return and let generic code clean it up
@@ -426,7 +427,7 @@
 	if (ehci->reclaim_ready)
 		end_unlink_async (ehci);
 	scan_async (ehci);
-	if (ehci->next_frame != -1)
+	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
 
 	// FIXME:  when nothing is connected to the root hub,
@@ -440,20 +441,20 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			status = readl (&ehci->regs->status);
-	int			bh = 0;
+	int			bh;
 
-	/* clear (just) interrupts */
 	status &= INTR_MASK;
+	if (!status)			/* irq sharing? */
+		return;
+
+	/* clear (just) interrupts */
 	writel (status, &ehci->regs->status);
 	readl (&ehci->regs->command);	/* unblock posted write */
-
-	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
-		return;
+	bh = 0;
 
 #ifdef	EHCI_VERBOSE_DEBUG
 	/* unrequested/ignored: Port Change Detect, Frame List Rollover */
-	if (status & INTR_MASK)
-		dbg_status (ehci, "irq", status);
+	dbg_status (ehci, "irq", status);
 #endif
 
 	/* INT, ERR, and IAA interrupt rates can be throttled */
@@ -520,17 +521,15 @@
 		return intr_submit (ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
-#ifdef have_iso
 		if (urb->dev->speed == USB_SPEED_HIGH)
-			return itd_submit (ehci, urb);
+			return itd_submit (ehci, urb, mem_flags);
+#ifdef have_split_iso
 		else
-			return sitd_submit (ehci, urb);
+			return sitd_submit (ehci, urb, mem_flags);
 #else
-		// FIXME highspeed iso stuff is written but never run/tested.
-		// and the split iso support isn't even written yet.
-		dbg ("no iso support yet");
+		dbg ("no split iso support yet");
 		return -ENOSYS;
-#endif /* have_iso */
+#endif /* have_split_iso */
 
 	}
 	return 0;
diff -urN linux-2.5.6-pre3/drivers/usb/hcd/ehci-hub.c linux-2.5.6/drivers/usb/hcd/ehci-hub.c
--- linux-2.5.6-pre3/drivers/usb/hcd/ehci-hub.c	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd/ehci-hub.c	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -68,8 +68,7 @@
 
 	/* init status to no-changes */
 	buf [0] = 0;
-	temp = readl (&ehci->caps->hcs_params);
-	ports = HCS_N_PORTS (temp);
+	ports = HCS_N_PORTS (ehci->hcs_params);
 	if (ports > 7) {
 		buf [1] = 0;
 		retval++;
@@ -107,8 +106,7 @@
 	struct ehci_hcd			*ehci,
 	struct usb_hub_descriptor	*desc
 ) {
-	u32		params = readl (&ehci->caps->hcs_params);
-	int		ports = HCS_N_PORTS (params);
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	u16		temp;
 
 	desc->bDescriptorType = 0x29;
@@ -124,10 +122,10 @@
 	memset (&desc->bitmap [temp], 0xff, temp);
 
 	temp = 0x0008;			/* per-port overcurrent reporting */
-	if (HCS_PPC (params))		/* per-port power control */
-	    temp |= 0x0001;
-	if (HCS_INDICATOR (params))	/* per-port indicators (LEDs) */
-	    temp |= 0x0080;
+	if (HCS_PPC (ehci->hcs_params))
+		temp |= 0x0001;		/* per-port power control */
+	if (HCS_INDICATOR (ehci->hcs_params))
+		temp |= 0x0080;		/* per-port indicators (LEDs) */
 	desc->wHubCharacteristics = cpu_to_le16 (temp);
 }
 
@@ -142,8 +140,7 @@
 	u16		wLength
 ) {
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
-	u32		params = readl (&ehci->caps->hcs_params);
-	int		ports = HCS_N_PORTS (params);
+	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	u32		temp;
 	unsigned long	flags;
 	int		retval = 0;
@@ -189,7 +186,7 @@
 			/* ? */
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (params))
+			if (HCS_PPC (ehci->hcs_params))
 				writel (temp & ~PORT_POWER,
 					&ehci->regs->port_status [wIndex]);
 			break;
@@ -300,7 +297,7 @@
 				&ehci->regs->port_status [wIndex]);
 			break;
 		case USB_PORT_FEAT_POWER:
-			if (HCS_PPC (params))
+			if (HCS_PPC (ehci->hcs_params))
 				writel (temp | PORT_POWER,
 					&ehci->regs->port_status [wIndex]);
 			break;
@@ -312,6 +309,13 @@
 					hcd->bus_name, wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
+				/* Philips 1562 wants CMD_RUN to reset */
+				if (!HCD_IS_RUNNING(ehci->hcd.state)) {
+					u32 cmd = readl (&ehci->regs->command);
+					cmd |= CMD_RUN;
+					writel (cmd, &ehci->regs->command);	
+					ehci->hcd.state = USB_STATE_RUNNING;
+				}
 				vdbg ("%s port %d reset",
 					hcd->bus_name, wIndex + 1);
 				temp |= PORT_RESET;
diff -urN linux-2.5.6-pre3/drivers/usb/hcd/ehci-q.c linux-2.5.6/drivers/usb/hcd/ehci-q.c
--- linux-2.5.6-pre3/drivers/usb/hcd/ehci-q.c	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd/ehci-q.c	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -643,12 +643,19 @@
 		if (usb_pipecontrol (urb->pipe)) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
 		} else if (usb_pipebulk (urb->pipe)) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else
-			info1 |= usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe)) << 16;
+		} else {
+			u32	temp;
+			temp = usb_maxpacket (urb->dev, urb->pipe,
+						usb_pipeout (urb->pipe));
+			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
+			/* HS intr can be "high bandwidth" */
+			temp = 1 + ((temp >> 11) & 0x03);
+			info2 |= temp << 30;		/* mult */
+		}
 		break;
 	default:
 #ifdef DEBUG
diff -urN linux-2.5.6-pre3/drivers/usb/hcd/ehci-sched.c linux-2.5.6/drivers/usb/hcd/ehci-sched.c
--- linux-2.5.6-pre3/drivers/usb/hcd/ehci-sched.c	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd/ehci-sched.c	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -55,12 +55,12 @@
 		return &periodic->qh->qh_next;
 	case Q_TYPE_FSTN:
 		return &periodic->fstn->fstn_next;
-#ifdef have_iso
 	case Q_TYPE_ITD:
 		return &periodic->itd->itd_next;
+#ifdef have_split_iso
 	case Q_TYPE_SITD:
 		return &periodic->sitd->sitd_next;
-#endif /* have_iso */
+#endif /* have_split_iso */
 	}
 	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
 	// BUG ();
@@ -109,9 +109,6 @@
 	u32			*hw_p = &ehci->periodic [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	unsigned		usecs = 0;
-#ifdef have_iso
-	u32			temp = 0;
-#endif
 
 	while (q->ptr) {
 		switch (Q_NEXT_TYPE (*hw_p)) {
@@ -130,15 +127,13 @@
 			}
 			q = &q->fstn->fstn_next;
 			break;
-#ifdef have_iso
 		case Q_TYPE_ITD:
-			temp = le32_to_cpu (q->itd->transaction [uframe]);
-			temp >>= 16;
-			temp &= 0x0fff;
-			if (temp)
-				usecs += HS_USECS_ISO (temp);
+			/* NOTE the "one uframe per itd" policy */
+			if (q->itd->hw_transaction [uframe] != 0)
+				usecs += q->itd->usecs;
 			q = &q->itd->itd_next;
 			break;
+#ifdef have_split_iso
 		case Q_TYPE_SITD:
 			temp = q->sitd->hw_fullspeed_ep &
 				__constant_cpu_to_le32 (1 << 31);
@@ -163,7 +158,7 @@
 			}
 			q = &q->sitd->sitd_next;
 			break;
-#endif /* have_iso */
+#endif /* have_split_iso */
 		default:
 			BUG ();
 		}
@@ -178,6 +173,45 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void enable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+
+	/* did clearing PSE did take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	while (readl (&ehci->regs->status) & STS_PSS)
+		udelay (20);
+
+	cmd = readl (&ehci->regs->command) | CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... PSS happens later */
+	ehci->hcd.state = USB_STATE_RUNNING;
+
+	/* make sure tasklet scans these */
+	ehci->next_uframe = readl (&ehci->regs->frame_index)
+				% (ehci->periodic_size << 3);
+}
+
+static void disable_periodic (struct ehci_hcd *ehci)
+{
+	u32	cmd;
+
+	/* did setting PSE not take effect yet?
+	 * takes effect only at frame boundaries...
+	 */
+	while (!(readl (&ehci->regs->status) & STS_PSS))
+		udelay (20);
+
+	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
+	writel (cmd, &ehci->regs->command);
+	/* posted write ... */
+
+	ehci->next_uframe = -1;
+}
+
+/*-------------------------------------------------------------------------*/
+
 static void intr_deschedule (
 	struct ehci_hcd	*ehci,
 	unsigned	frame,
@@ -199,21 +233,9 @@
 	ehci->periodic_urbs--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs) {
-		u32	cmd = readl (&ehci->regs->command);
-
-		/* did setting PSE not take effect yet?
-		 * takes effect only at frame boundaries...
-		 */
-		while (!(readl (&ehci->regs->status) & STS_PSS))
-			udelay (20);
-
-		cmd &= ~CMD_PSE;
-		writel (cmd, &ehci->regs->command);
-		/* posted write ... */
-
-		ehci->next_frame = -1;
-	} else
+	if (!ehci->periodic_urbs)
+		disable_periodic (ehci);
+	else
 		vdbg ("periodic schedule still enabled");
 
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -242,7 +264,7 @@
 ) {
 	unsigned		epnum, period;
 	unsigned		temp;
-	unsigned short		mult, usecs;
+	unsigned short		usecs;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
 	struct hcd_dev		*dev;
@@ -255,12 +277,7 @@
 		epnum |= 0x10;
 	} else
 		temp = urb->dev->epmaxpacketout [epnum];
-	mult = 1;
-	if (urb->dev->speed == USB_SPEED_HIGH) {
-		/* high speed "high bandwidth" is coded in ep maxpacket */
-		mult += (temp >> 11) & 0x03;
-		temp &= 0x03ff;
-	} else {
+	if (urb->dev->speed != USB_SPEED_HIGH) {
 		dbg ("no intr/tt scheduling yet"); 
 		status = -ENOSYS;
 		goto done;
@@ -279,21 +296,12 @@
 
 	usecs = HS_USECS (urb->transfer_buffer_length);
 
-	/*
-	 * force a power-of-two (frames) sized polling interval
-	 *
-	 * NOTE: endpoint->bInterval for highspeed is measured in uframes,
-	 * while for full/low speeds it's in frames.  Here we "know" that
-	 * urb->interval doesn't give acccess to high interrupt rates.
-	 */
-	period = ehci->periodic_size;
-	temp = period;
-	if (unlikely (urb->interval < 1))
-		urb->interval = 1;
-	while (temp > urb->interval)
-		temp >>= 1;
-	period = urb->interval = temp;
-
+	/* FIXME handle HS periods of less than 1 frame. */
+	if (urb->interval < 8)
+		period = 1;
+	else
+		period = urb->interval >> 8;
+		
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/* get the qh (must be empty and idle) */
@@ -335,7 +343,6 @@
 		unsigned	frame = urb->interval;
 
 		qh->hw_next = EHCI_LIST_END;
-		qh->hw_info2 |= cpu_to_le32 (mult << 30);
 		qh->usecs = usecs;
 
 		urb->hcpriv = qh_put (qh);
@@ -378,7 +385,7 @@
 
 			/* stuff into the periodic schedule */
 			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+			vdbg ("qh %p usecs %d period %d starting %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
 				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
@@ -397,23 +404,8 @@
 			usb_claim_bandwidth (urb->dev, urb, usecs, 0);
 
 			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++) {
-				u32	cmd;
-
-				/* did clearing PSE did take effect yet?
-				 * takes effect only at frame boundaries...
-				 */
-				while (readl (&ehci->regs->status) & STS_PSS)
-					udelay (20);
-
-				cmd = readl (&ehci->regs->command) | CMD_PSE;
-				writel (cmd, &ehci->regs->command);
-				/* posted write ... PSS happens later */
-				ehci->hcd.state = USB_STATE_RUNNING;
-
-				/* make sure tasklet scans these */
-				ehci->next_frame = ehci_get_frame (&ehci->hcd);
-			}
+			if (!ehci->periodic_urbs++)
+				enable_periodic (ehci);
 			break;
 
 		} while (frame);
@@ -489,53 +481,56 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef	have_iso
-
-static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+static void
+itd_free_list (struct ehci_hcd *ehci, struct urb *urb)
 {
-	pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	struct ehci_itd *first_itd = urb->hcpriv;
+
+	pci_unmap_single (ehci->hcd.pdev,
+		first_itd->buf_dma, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	while (!list_empty (&first_itd->itd_list)) {
+		struct ehci_itd	*itd;
+
+		itd = list_entry (
+			first_itd->itd_list.next,
+			struct ehci_itd, itd_list);
+		list_del (&itd->itd_list);
+		pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+	}
+	pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma);
+	urb->hcpriv = 0;
 }
 
-/*
- * Create itd and allocate into uframes within specified frame.
- * Caller must update the resulting uframe links.
- */
-static struct ehci_itd *
-itd_make (
+static int
+itd_fill (
 	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
 	struct urb	*urb,
 	unsigned	index,		// urb->iso_frame_desc [index]
-	unsigned	frame,		// scheduled start
-	dma_addr_t	dma,		// mapped transfer buffer
-	int		mem_flags
+	dma_addr_t	dma		// mapped transfer buffer
 ) {
-	struct ehci_itd	*itd;
 	u64		temp;
 	u32		buf1;
-	unsigned	epnum, maxp, multi, usecs;
+	unsigned	i, epnum, maxp, multi;
 	unsigned	length;
-	unsigned	i, bufnum;
-
-	/* allocate itd, start to fill it */
-	itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
-	if (!itd)
-		return itd;
 
 	itd->hw_next = EHCI_LIST_END;
 	itd->urb = urb;
 	itd->index = index;
-	INIT_LIST_HEAD (&itd->itd_list);
-	itd->uframe = (frame * 8) % ehci->periodic_size;
 
-	/* tell itd about the buffer its transfers will consume */
+	/* tell itd about its transfer buffer, max 2 pages */
 	length = urb->iso_frame_desc [index].length;
 	dma += urb->iso_frame_desc [index].offset;
 	temp = dma & ~0x0fff;
-	for (i = 0; i < 7; i++) {
+	for (i = 0; i < 2; i++) {
 		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
 		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
-		temp += 0x0fff;
+		temp += 0x1000;
 	}
+	itd->buf_dma = dma;
 
 	/*
 	 * this might be a "high bandwidth" highspeed endpoint,
@@ -544,282 +539,407 @@
 	epnum = usb_pipeendpoint (urb->pipe);
 	if (usb_pipein (urb->pipe)) {
 		maxp = urb->dev->epmaxpacketin [epnum];
-		buf1 = (1 << 11) | maxp;
+		buf1 = (1 << 11);
 	} else {
 		maxp = urb->dev->epmaxpacketout [epnum];
-		buf1 = maxp;
+		buf1 = 0;
 	}
+	buf1 |= (maxp & 0x03ff);
 	multi = 1;
-	multi += (temp >> 11) & 0x03;
+	multi += (maxp >> 11) & 0x03;
 	maxp &= 0x03ff;
+	maxp *= multi;
+
+	/* transfer can't fit in any uframe? */ 
+	if (length < 0 || maxp < length) {
+		dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)",
+			length, maxp, urb, index,
+			urb->iso_frame_desc [index].length);
+		return -ENOSPC;
+	}
+	itd->usecs = HS_USECS_ISO (length);
 
 	/* "plus" info in low order bits of buffer pointers */
 	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
 	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
 	itd->hw_bufp [2] |= cpu_to_le32 (multi);
 
-	/* schedule as many uframes as needed */
-	maxp *= multi;
-	usecs = HS_USECS_ISO (maxp);
-	bufnum = 0;
-	for (i = 0; i < 8; i++) {
-		unsigned	t, offset, scratch;
+	/* figure hw_transaction[] value (it's scheduled later) */
+	itd->transaction = EHCI_ISOC_ACTIVE;
+	itd->transaction |= dma & 0x0fff;		/* offset; buffer=0 */
+	if ((index + 1) == urb->number_of_packets)
+		itd->transaction |= EHCI_ITD_IOC; 	/* end-of-urb irq */
+	itd->transaction |= length << 16;
+	cpu_to_le32s (&itd->transaction);
 
-		if (length <= 0) {
-			itd->hw_transaction [i] = 0;
-			continue;
-		}
+	return 0;
+}
 
-		/* don't commit more than 80% periodic == 100 usec */
-		if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
-			continue;
+static int
+itd_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	int			mem_flags
+) {
+	int			frame_index;
+	struct ehci_itd		*first_itd, *itd;
+	int			status;
+	dma_addr_t		buf_dma, itd_dma;
 
-		/* we'll use this uframe; figure hw_transaction */
-		t = EHCI_ISOC_ACTIVE;
-		t |= bufnum << 12;		// which buffer?
-		offset = temp & 0x0fff;		// offset therein
-		t |= offset;
-		if ((offset + maxp) >= 4096) 	// hc auto-wraps end-of-"page"
-			bufnum++;
-		if (length <= maxp) {
-			// interrupt only needed at end-of-urb
-			if ((index + 1) == urb->number_of_packets)
-				t |= EHCI_ITD_IOC;
-			scratch = length;
-		} else
-			scratch = maxp;
-		t |= scratch << 16;
-		t = cpu_to_le32 (t);
-
-		itd->hw_transaction [i] = itd->transaction [i] = t;
-		length -= scratch;
-	}
-	if (length > 0) {
-		dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
-			urb, index, length, urb->iso_frame_desc [index].length);
-		itd_free (ehci, itd);
-		itd = 0;
+	/* set up one dma mapping for this urb */
+	buf_dma = pci_map_single (ehci->hcd.pdev,
+		urb->transfer_buffer, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	if (buf_dma == 0)
+		return -ENOMEM;
+
+	/* allocate/init ITDs */
+	for (frame_index = 0, first_itd = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma);
+		if (!itd) {
+			status = -ENOMEM;
+			goto fail;
+		}
+		memset (itd, 0, sizeof *itd);
+		itd->itd_dma = itd_dma;
+
+		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+		if (status != 0)
+			goto fail;
+
+		if (first_itd)
+			list_add_tail (&itd->itd_list,
+					&first_itd->itd_list);
+		else {
+			INIT_LIST_HEAD (&itd->itd_list);
+			urb->hcpriv = first_itd = itd;
+		}
 	}
-	return itd;
+	urb->error_count = 0;
+	return 0;
+
+fail:
+	if (urb->hcpriv)
+		itd_free_list (ehci, urb);
+	return status;
 }
 
+/*-------------------------------------------------------------------------*/
+
 static inline void
 itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
 {
-	u32		ptr;
+	/* always prepend ITD/SITD ... only QH tree is order-sensitive */
+	itd->itd_next = ehci->pshadow [frame];
+	itd->hw_next = ehci->periodic [frame];
+	ehci->pshadow [frame].itd = itd;
+	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+}
 
-	ptr = cpu_to_le32 (itd->itd_dma);	// type 0 == itd
-	if (ehci->pshadow [frame].ptr) {
-		if (!itd->itd_next.ptr) {
-			itd->itd_next = ehci->pshadow [frame];
-			itd->hw_next = ehci->periodic [frame];
-		} else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
-			dbg ("frame %d itd link goof", frame);
-			BUG ();
+/*
+ * return zero on success, else -errno
+ * - start holds first uframe to start scheduling into
+ * - max is the first uframe it's NOT (!) OK to start scheduling into
+ * math to be done modulo "mod" (ehci->periodic_size << 3)
+ */
+static int get_iso_range (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	unsigned		*start,
+	unsigned		*max,
+	unsigned		mod
+) {
+	struct list_head	*lh;
+	struct hcd_dev		*dev = urb->dev->hcpriv;
+	int			last = -1;
+	unsigned		now, span, end;
+
+	span = urb->interval * urb->number_of_packets;
+
+	/* first see if we know when the next transfer SHOULD happen */
+	list_for_each (lh, &dev->urb_list) {
+		struct urb	*u;
+		struct ehci_itd	*itd;
+		unsigned	s;
+
+		u = list_entry (lh, struct urb, urb_list);
+		if (u == urb || u->pipe != urb->pipe)
+			continue;
+		if (u->interval != urb->interval) {	/* must not change! */ 
+			dbg ("urb %p interval %d ... != %p interval %d",
+				u, u->interval, urb, urb->interval);
+			return -EINVAL;
+		}
+		
+		/* URB for this endpoint... covers through when?  */
+		itd = urb->hcpriv;
+		s = itd->uframe + u->interval * u->number_of_packets;
+		if (last < 0)
+			last = s;
+		else {
+			/*
+			 * So far we can only queue two ISO URBs...
+			 *
+			 * FIXME do interval math, figure out whether
+			 * this URB is "before" or not ... also, handle
+			 * the case where the URB might have completed,
+			 * but hasn't yet been processed.
+			 */
+			dbg ("NYET: queue >2 URBs per ISO endpoint");
+			return -EDOM;
 		}
 	}
-	ehci->pshadow [frame].itd = itd;
-	ehci->periodic [frame] = ptr;
-}
 
-#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+	/* calculate the legal range [start,max) */
+	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
+	if (!ehci->periodic_urbs)
+		now += 8;				/* startup delay */
+	now %= mod;
+	end = now + mod;
+	if (last < 0) {
+		*start = now + ehci->i_thresh + /* paranoia */ 1;
+		*max = end - span;
+		if (*max < *start + 1)
+			*max = *start + 1;
+	} else {
+		*start = last % mod;
+		*max = (last + 1) % mod;
+	}
 
-static unsigned long
-itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+	/* explicit start frame? */
+	if (!(urb->transfer_flags & USB_ISO_ASAP)) {
+		unsigned	temp;
+
+		/* sanity check: must be in range */
+		urb->start_frame %= ehci->periodic_size;
+		temp = urb->start_frame << 3;
+		if (temp < *start)
+			temp += mod;
+		if (temp > *max)
+			return -EDOM;
+
+		/* use that explicit start frame */
+		*start = urb->start_frame << 3;
+		temp += 8;
+		if (temp < *max)
+			*max = temp;
+	}
+
+	// FIXME minimize wraparound to "now" ... insist max+span
+	// (and start+span) remains a few frames short of "end"
+
+	*max %= ehci->periodic_size;
+	if ((*start + span) < end)
+		return 0;
+	return -EFBIG;
+}
+
+static int
+itd_schedule (struct ehci_hcd *ehci, struct urb *urb)
 {
-	struct urb		*urb = itd->urb;
+	unsigned	start, max, i;
+	int		status;
+	unsigned	mod = ehci->periodic_size << 3;
 
-	/* if not unlinking: */
-	if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
-			&& ehci->hcd.state != USB_STATE_HALT) {
-		int			i;
-		struct usb_iso_packet_descriptor	*desc;
-		struct ehci_itd		*first_itd = urb->hcpriv;
+	for (i = 0; i < urb->number_of_packets; i++) {
+		urb->iso_frame_desc [i].status = -EINPROGRESS;
+		urb->iso_frame_desc [i].actual_length = 0;
+	}
 
-		/* update status for this frame's transfers */
-		desc = &urb->iso_frame_desc [itd->index];
-		desc->status = 0;
-		desc->actual_length = 0;
-		for (i = 0; i < 8; i++) {
-			u32	 t = itd->hw_transaction [i];
-			if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
-				if (t & EHCI_ISOC_ACTIVE)
-					desc->status = -EXDEV;
-				else if (t & EHCI_ISOC_BUF_ERR)
-					desc->status = usb_pipein (urb->pipe)
-						? -ENOSR  /* couldn't read */
-						: -ECOMM; /* couldn't write */
-				else if (t & EHCI_ISOC_BABBLE)
-					desc->status = -EOVERFLOW;
-				else /* (t & EHCI_ISOC_XACTERR) */
-					desc->status = -EPROTO;
+	if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0)
+		return status;
+
+	do {
+		unsigned	uframe;
+		unsigned	usecs;
+		struct ehci_itd	*itd;
+
+		/* check schedule: enough space? */
+		itd = urb->hcpriv;
+		uframe = start;
+		for (i = 0, uframe = start;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			/* can't commit more than 80% periodic == 100 usec */
+			if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
+					> (100 - itd->usecs)) {
+				itd = 0;
 				break;
 			}
-			desc->actual_length += EHCI_ITD_LENGTH (t);
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		}
+		if (!itd)
+			continue;
+		
+		/* that's where we'll schedule this! */
+		itd = urb->hcpriv;
+		urb->start_frame = start >> 3;
+		vdbg ("ISO urb %p (%d packets period %d) starting %d.%d",
+			urb, urb->number_of_packets, urb->interval,
+			urb->start_frame, start & 0x7);
+		for (i = 0, uframe = start, usecs = 0;
+				i < urb->number_of_packets;
+				i++, uframe += urb->interval) {
+			uframe %= mod;
+
+			itd->uframe = uframe;
+			itd->hw_transaction [uframe & 0x07] = itd->transaction;
+			itd_link (ehci, (uframe >> 3) % ehci->periodic_size,
+				itd);
+			usecs += itd->usecs;
+
+			itd = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
 		}
 
-		/* handle completion now? */
-		if ((itd->index + 1) != urb->number_of_packets)
-			return flags;
+		/* update bandwidth utilization records (for usbfs) */
+		/* FIXME usbcore expects per-frame average, which isn't
+		 * most accurate model... this provides the total claim,
+		 * and expects the average to be computed only display.
+		 */
+		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
 
-		i = usb_pipein (urb->pipe);
-		if (i)
-			pci_dma_sync_single (ehci->hcd.pdev,
-				first_itd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_FROMDEVICE);
+		/* maybe enable periodic schedule processing */
+		if (!ehci->periodic_urbs++)
+			enable_periodic (ehci);
 
-		/* call completion with no locks; it can unlink ... */
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		urb->complete (urb);
-		spin_lock_irqsave (&ehci->lock, flags);
-
-		/* re-activate this URB? or unlink? */
-		if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
-				&& ehci->hcd.state != USB_STATE_HALT) {
-			if (!i)
-				pci_dma_sync_single (ehci->hcd.pdev,
-					first_itd->buf_dma,
-					urb->transfer_buffer_length,
-					PCI_DMA_TODEVICE);
+		return 0;
 
-			itd = urb->hcpriv;
-			do {
-				for (i = 0; i < 8; i++)
-					itd->hw_transaction [i]
-						= itd->transaction [i];
-				itd = list_entry (itd->itd_list.next,
-						struct ehci_itd, itd_list);
-			} while (itd != urb->hcpriv);
-			return flags;
-		}
+	} while ((start = ++start % mod) != max);
+
+	/* no room in the schedule */
+	dbg ("urb %p, CAN'T SCHEDULE", urb);
+	return -ENOSPC;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
-	/* unlink done only on the last itd */
-	} else if ((itd->index + 1) != urb->number_of_packets)
+static unsigned long
+itd_complete (
+	struct ehci_hcd	*ehci,
+	struct ehci_itd	*itd,
+	unsigned	uframe,
+	unsigned long	flags
+) {
+	struct urb				*urb = itd->urb;
+	struct usb_iso_packet_descriptor	*desc;
+	u32					t;
+
+	/* update status for this uframe's transfers */
+	desc = &urb->iso_frame_desc [itd->index];
+
+	t = itd->hw_transaction [uframe];
+	itd->hw_transaction [uframe] = 0;
+	if (t & EHCI_ISOC_ACTIVE)
+		desc->status = -EXDEV;
+	else if (t & ISO_ERRS) {
+		urb->error_count++;
+		if (t & EHCI_ISOC_BUF_ERR)
+			desc->status = usb_pipein (urb->pipe)
+				? -ENOSR  /* couldn't read */
+				: -ECOMM; /* couldn't write */
+		else if (t & EHCI_ISOC_BABBLE)
+			desc->status = -EOVERFLOW;
+		else /* (t & EHCI_ISOC_XACTERR) */
+			desc->status = -EPROTO;
+
+		/* HC need not update length with this error */
+		if (!(t & EHCI_ISOC_BABBLE))
+			desc->actual_length += EHCI_ITD_LENGTH (t);
+	} else {
+		desc->status = 0;
+		desc->actual_length += EHCI_ITD_LENGTH (t);
+	}
+
+	vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d",
+		itd, urb, itd->index + 1, urb->number_of_packets,
+		t, desc->status, desc->actual_length);
+
+	/* handle completion now? */
+	if ((itd->index + 1) != urb->number_of_packets)
 		return flags;
 
-	/* we're unlinking ... */
+	/*
+	 * For now, always give the urb back to the driver ... expect it
+	 * to submit a new urb (or resubmit this), and to have another
+	 * already queued when un-interrupted transfers are needed.
+	 * No, that's not what OHCI or UHCI are now doing.
+	 *
+	 * FIXME Revisit the ISO URB model.  It's cleaner not to have all
+	 * the special case magic, but it'd be faster to reuse existing
+	 * ITD/DMA setup and schedule state.  Easy to dma_sync/complete(),
+	 * then either reschedule or, if unlinking, free and giveback().
+	 * But we can't overcommit like the full and low speed HCs do, and
+	 * there's no clean way to report an error when rescheduling...
+	 *
+	 * NOTE that for now we don't accelerate ISO unlinks; they just
+	 * happen according to the current schedule.  Means a delay of
+	 * up to about a second (max).
+	 */
+	itd_free_list (ehci, urb);
+	if (urb->status == -EINPROGRESS)
+		urb->status = 0;
 
-	/* decouple urb from the hcd */
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	if (ehci->hcd.state == USB_STATE_HALT)
-		urb->status = -ESHUTDOWN;
-	itd = urb->hcpriv;
-	urb->hcpriv = 0;
-	ehci_urb_done (ehci, itd->buf_dma, urb);
+	usb_hcd_giveback_urb (&ehci->hcd, urb);
 	spin_lock_irqsave (&ehci->lock, flags);
 
-	/* take itds out of the hc's periodic schedule */
-	list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
-		->itd_list.next = 0;
-	do {
-		struct ehci_itd	*next;
-
-		if (itd->itd_list.next)
-			next = list_entry (itd->itd_list.next,
-				struct ehci_itd, itd_list);
-		else
-			next = 0;
+	/* defer stopping schedule; completion can submit */
+	ehci->periodic_urbs--;
+	if (!ehci->periodic_urbs)
+		disable_periodic (ehci);
 
-		// FIXME:  hc WILL (!) lap us here, if we get behind
-		// by 128 msec (or less, with smaller periodic_size).
-		// Reading/caching these itds will cause trouble...
-
-		periodic_unlink (ehci, itd->uframe, itd);
-		itd_free (ehci, itd);
-		itd = next;
-	} while (itd);
 	return flags;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 {
-	struct ehci_itd		*first_itd = 0, *itd;
-	unsigned		frame_index;
-	dma_addr_t		dma;
-	unsigned long		flags;
+	int		status;
+	unsigned long	flags;
 
-	dbg ("itd_submit");
-
-	/* set up one dma mapping for this urb */
-	dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (dma == 0)
-		return -ENOMEM;
+	dbg ("itd_submit urb %p", urb);
 
+	/* NOTE DMA mapping assumes this ... */
+	if (urb->iso_frame_desc [0].offset != 0)
+		return -EINVAL;
+	
 	/*
-	 * Schedule as needed.  This is VERY optimistic about free
-	 * bandwidth!  But the API assumes drivers can pick frames
-	 * intelligently (how?), so there's no other good option.
-	 *
-	 * FIXME  this doesn't handle urb->next rings, or try to
-	 * use the iso periodicity.
+	 * NOTE doing this for now, anticipating periodic URB models
+	 * get updated to be "explicit resubmit".
 	 */
-	if (urb->transfer_flags & USB_ISO_ASAP) { 
-		urb->start_frame = ehci_get_frame (&ehci->hcd);
-		urb->start_frame++;
+	if (urb->next) {
+		dbg ("use explicit resubmit for ISO");
+		return -EINVAL;
 	}
-	urb->start_frame %= ehci->periodic_size;
 
-	/* create and populate itds (doing uframe scheduling) */
-	spin_lock_irqsave (&ehci->lock, flags);
-	for (frame_index = 0;
-			frame_index < urb->number_of_packets;
-			frame_index++) {
-		itd = itd_make (ehci, urb, frame_index,
-			urb->start_frame + frame_index,
-			dma, SLAB_ATOMIC);
-		if (itd) {
-			if (first_itd)
-				list_add_tail (&itd->itd_list,
-						&first_itd->itd_list);
-			else
-				first_itd = itd;
-		} else {
-			spin_unlock_irqrestore (&ehci->lock, flags);
-			if (first_itd) {
-				while (!list_empty (&first_itd->itd_list)) {
-					itd = list_entry (
-						first_itd->itd_list.next,
-						struct ehci_itd, itd_list);
-					list_del (&itd->itd_list);
-					itd_free (ehci, itd);
-				}
-				itd_free (ehci, first_itd);
-			}
-			pci_unmap_single (ehci->hcd.pdev,
-				dma, urb->transfer_buffer_length,
-				usb_pipein (urb->pipe)
-				    ? PCI_DMA_FROMDEVICE
-				    : PCI_DMA_TODEVICE);
-			return -ENOMEM;
-		}
-	}
-
-	/* stuff into the schedule */
-	itd = first_itd;
-	do {
-		unsigned	i;
-
-		for (i = 0; i < 8; i++) {
-			if (!itd->hw_transaction [i])
-				continue;
-			itd_link (ehci, itd->uframe + i, itd);
-		}
-		itd = list_entry (itd->itd_list.next,
-			struct ehci_itd, itd_list);
-	} while (itd != first_itd);
-	urb->hcpriv = first_itd;
+	/* allocate ITDs w/o locking anything */
+	status = itd_urb_transaction (ehci, urb, mem_flags);
+	if (status < 0)
+		return status;
 
+	/* schedule ... need to lock */
+	spin_lock_irqsave (&ehci->lock, flags);
+	status = itd_schedule (ehci, urb);
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	if (status < 0)
+		itd_free_list (ehci, urb);
+
+	return status;
 }
 
+#ifdef have_split_iso
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -827,7 +947,7 @@
  * the TTs in USB 2.0 hubs.
  */
 
-static inline void
+static void
 sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
 {
 	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
@@ -861,7 +981,7 @@
 
 }
 
-static inline void
+static void
 sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
 {
 	u32		ptr;
@@ -894,12 +1014,11 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
 {
 	// struct ehci_sitd	*first_sitd = 0;
 	unsigned		frame_index;
 	dma_addr_t		dma;
-	int			mem_flags;
 
 	dbg ("NYI -- sitd_submit");
 
@@ -908,8 +1027,6 @@
 	// FIXME:  setup one big dma mapping
 	dma = 0;
 
-	mem_flags = SLAB_ATOMIC;
-
 	for (frame_index = 0;
 			frame_index < urb->number_of_packets;
 			frame_index++) {
@@ -941,53 +1058,62 @@
 
 	return -ENOSYS;
 }
-
-#endif	/* have_iso */
+#endif /* have_split_iso */
 
 /*-------------------------------------------------------------------------*/
 
 static void scan_periodic (struct ehci_hcd *ehci)
 {
-	unsigned	frame;
-	unsigned	clock;
+	unsigned	frame, clock, now_uframe, mod;
 	unsigned long	flags;
 
+	mod = ehci->periodic_size << 3;
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	/*
 	 * When running, scan from last scan point up to "now"
+	 * else clean up by scanning everything that's left.
 	 * Touches as few pages as possible:  cache-friendly.
-	 * It's safe to scan entries more than once, though.
+	 * Don't scan ISO entries more than once, though.
 	 */
-	if (HCD_IS_RUNNING (ehci->hcd.state)) {
-		frame = ehci->next_frame;
-		clock = ehci_get_frame (&ehci->hcd);
+	frame = ehci->next_uframe >> 3;
+	if (HCD_IS_RUNNING (ehci->hcd.state))
+		now_uframe = readl (&ehci->regs->frame_index);
+	else
+		now_uframe = (frame << 3) - 1;
+	now_uframe %= mod;
+	clock = now_uframe >> 3;
 
-	/* when shutting down, scan everything for thoroughness */
-	} else {
-		frame = 0;
-		clock = ehci->periodic_size - 1;
-	}
 	for (;;) {
-		union ehci_shadow	 q;
-		u32	type;
+		union ehci_shadow	q, *q_p;
+		u32			type, *hw_p;
+		unsigned		uframes;
 
 restart:
-		q.ptr = ehci->pshadow [frame].ptr;
-		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+		/* scan schedule to _before_ current frame index */
+		if (frame == clock)
+			uframes = now_uframe & 0x07;
+		else
+			uframes = 8;
+
+		q_p = &ehci->pshadow [frame];
+		hw_p = &ehci->periodic [frame];
+		q.ptr = q_p->ptr;
+		type = Q_NEXT_TYPE (*hw_p);
 
 		/* scan each element in frame's queue for completions */
 		while (q.ptr != 0) {
 			int			last;
+			unsigned		uf;
 			union ehci_shadow	temp;
 
 			switch (type) {
 			case Q_TYPE_QH:
 				last = (q.qh->hw_next == EHCI_LIST_END);
+				temp = q.qh->qh_next;
+				type = Q_NEXT_TYPE (q.qh->hw_next);
 				flags = intr_complete (ehci, frame,
 						qh_put (q.qh), flags);
-				type = Q_NEXT_TYPE (q.qh->hw_next);
-				temp = q.qh->qh_next;
 				qh_unput (ehci, q.qh);
 				q = temp;
 				break;
@@ -1000,22 +1126,49 @@
 					dbg ("ignoring completions from FSTNs");
 				}
 				type = Q_NEXT_TYPE (q.fstn->hw_next);
-				temp = q.fstn->fstn_next;
+				q = q.fstn->fstn_next;
 				break;
-#ifdef have_iso
 			case Q_TYPE_ITD:
 				last = (q.itd->hw_next == EHCI_LIST_END);
-				flags = itd_complete (ehci, q.itd, flags);
-				type = Q_NEXT_TYPE (q.itd->hw_next);
-				q = q.itd->itd_next;
+
+				/* Unlink each (S)ITD we see, since the ISO
+				 * URB model forces constant rescheduling.
+				 * That complicates sharing uframes in ITDs,
+				 * and means we need to skip uframes the HC
+				 * hasn't yet processed.
+				 */
+				for (uf = 0; uf < uframes; uf++) {
+					if (q.itd->hw_transaction [uf] != 0) {
+						temp = q;
+						*q_p = q.itd->itd_next;
+						*hw_p = q.itd->hw_next;
+						type = Q_NEXT_TYPE (*hw_p);
+
+						/* might free q.itd ... */
+						flags = itd_complete (ehci,
+							temp.itd, uf, flags);
+						break;
+					}
+				}
+				/* we might skip this ITD's uframe ... */
+				if (uf == uframes) {
+					q_p = &q.itd->itd_next;
+					hw_p = &q.itd->hw_next;
+					type = Q_NEXT_TYPE (q.itd->hw_next);
+				}
+
+				q = *q_p;
 				break;
+#ifdef have_split_iso
 			case Q_TYPE_SITD:
 				last = (q.sitd->hw_next == EHCI_LIST_END);
 				flags = sitd_complete (ehci, q.sitd, flags);
 				type = Q_NEXT_TYPE (q.sitd->hw_next);
+
+				// FIXME unlink SITD after split completes
 				q = q.sitd->sitd_next;
 				break;
-#endif /* have_iso */
+#endif /* have_split_iso */
 			default:
 				dbg ("corrupt type %d frame %d shadow %p",
 					type, frame, q.ptr);
@@ -1044,13 +1197,16 @@
 
 			if (!HCD_IS_RUNNING (ehci->hcd.state))
 				break;
-			ehci->next_frame = clock;
-			now = ehci_get_frame (&ehci->hcd);
-			if (clock == now)
+			ehci->next_uframe = now_uframe;
+			now = readl (&ehci->regs->frame_index) % mod;
+			if (now_uframe == now)
 				break;
-			clock = now;
-		} else if (++frame >= ehci->periodic_size)
-			frame = 0;
+
+			/* rescan the rest of this frame, then ... */
+			now_uframe = now;
+			clock = now_uframe >> 3;
+		} else
+			frame = (frame + 1) % ehci->periodic_size;
 	} 
 	spin_unlock_irqrestore (&ehci->lock, flags);
- }
+}
diff -urN linux-2.5.6-pre3/drivers/usb/hcd/ehci.h linux-2.5.6/drivers/usb/hcd/ehci.h
--- linux-2.5.6-pre3/drivers/usb/hcd/ehci.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/drivers/usb/hcd/ehci.h	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -49,7 +49,7 @@
 	unsigned		i_thresh;	/* uframes HC might cache */
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
-	int			next_frame;	/* scan periodic, start here */
+	int			next_uframe;	/* scan periodic, start here */
 	unsigned		periodic_urbs;	/* how many urbs scheduled? */
 
 	/* deferred work from IRQ, etc */
@@ -62,6 +62,7 @@
 	struct usb_hcd		hcd;
 	struct ehci_caps	*caps;
 	struct ehci_regs	*regs;
+	u32			hcs_params;	/* cached register copy */
 
 	/* per-HC memory pools (could be per-PCI-bus, but ...) */
 	struct pci_pool		*qh_pool;	/* qh per active urb */
@@ -324,13 +325,14 @@
 	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
 
 	struct urb		*urb;
-	unsigned		index;		/* in urb->iso_frame_desc */
 	struct list_head	itd_list;	/* list of urb frames' itds */
 	dma_addr_t		buf_dma;	/* frame's buffer address */
 
-	unsigned		uframe;		/* in periodic schedule */
-	u32			transaction [8]; /* copy of hw_transaction */
-
+	/* for now, only one hw_transaction per itd */
+	u32			transaction;
+	u16			index;		/* in urb->iso_frame_desc */
+	u16			uframe;		/* in periodic schedule */
+	u16			usecs;
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff -urN linux-2.5.6-pre3/drivers/usb/hcd.c linux-2.5.6/drivers/usb/hcd.c
--- linux-2.5.6-pre3/drivers/usb/hcd.c	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd.c	Thu Mar  7 18:24:51 2002
@@ -224,12 +224,12 @@
  * helper routine for returning string descriptors in UTF-16LE
  * input can actually be ISO-8859-1; ASCII is its 7-bit subset
  */
-static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+static int ascii2utf (char *s, u8 *utf, int utfmax)
 {
 	int retval;
 
-	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
-		*utf++ = *ascii++ & 0x7f;
+	for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *s++;
 		*utf++ = 0;
 	}
 	return retval;
@@ -248,8 +248,7 @@
  */
 static int rh_string (
 	int		id,
-	struct pci_dev	*pci_desc,
-	char		*type,
+	struct usb_hcd	*hcd,
 	u8		*data,
 	int		len
 ) {
@@ -263,15 +262,16 @@
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, pci_desc->slot_name);
+		strcpy (buf, hcd->bus_name);
 
 	// product description
 	} else if (id == 2) {
-                strcpy (buf, pci_desc->name);
+                strcpy (buf, hcd->product_desc);
 
  	// id 3 == vendor description
 	} else if (id == 3) {
-                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
+			hcd->description);
 
 	// unsupported IDs --> "protocol stall"
 	} else
@@ -338,9 +338,7 @@
 			break;
 		case USB_DT_STRING << 8:
 			urb->actual_length = rh_string (
-				wValue & 0xff,
-				 hcd->pdev,
-				(char *) hcd->description,
+				wValue & 0xff, hcd,
 				ubuf, wLength);
 			break;
 		default:
@@ -1004,6 +1002,7 @@
 	hcd->self.hcpriv = (void *) hcd;
 	hcd->bus = &hcd->self;
 	hcd->bus_name = dev->slot_name;
+	hcd->product_desc = dev->name;
 
 	INIT_LIST_HEAD (&hcd->dev_list);
 
@@ -1266,7 +1265,7 @@
 	struct usb_hcd		*hcd;
 	struct hcd_dev		*dev;
 	unsigned long		flags;
-	int			pipe;
+	int			pipe, temp;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
@@ -1286,6 +1285,7 @@
 	if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
 		return -ESHUTDOWN;
 	pipe = urb->pipe;
+	temp = usb_pipetype (urb->pipe);
 	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
 			usb_pipeout (pipe)))
 		return -EPIPE;
@@ -1298,7 +1298,7 @@
 	/* enforce simple/standard policy */
 	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
 	allowed |= USB_NO_FSBR;		// only affects UHCI
-	switch (usb_pipetype (pipe)) {
+	switch (temp) {
 	case PIPE_CONTROL:
 		allowed |= USB_DISABLE_SPD;
 		break;
@@ -1317,15 +1317,55 @@
 
 	/* warn if submitter gave bogus flags */
 	if (urb->transfer_flags != orig_flags)
-		warn ("BOGUS urb flags, %x --> %x",
+		err ("BOGUS urb flags, %x --> %x",
 			orig_flags, urb->transfer_flags);
 	}
 #endif
 	/*
-	 * FIXME:  alloc periodic bandwidth here, for interrupt and iso?
-	 * Need to look at the ring submit mechanism for iso tds ... they
-	 * aren't actually "periodic" in 2.4 kernels.
+	 * Force periodic transfer intervals to be legal values that are
+	 * a power of two (so HCDs don't need to).
 	 *
+	 * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC
+	 * supports different values... this uses EHCI/UHCI defaults (and
+	 * EHCI can use smaller non-default values).
+	 */
+	switch (temp) {
+	case PIPE_ISOCHRONOUS:
+	case PIPE_INTERRUPT:
+		/* too small? */
+		if (urb->interval <= 0)
+			return -EINVAL;
+		/* too big? */
+		switch (urb->dev->speed) {
+		case USB_SPEED_HIGH:	/* units are microframes */
+			// NOTE usb handles 2^15
+			if (urb->interval > (1024 * 8))
+				urb->interval = 1024 * 8;
+			temp = 1024 * 8;
+			break;
+		case USB_SPEED_FULL:	/* units are frames/msec */
+		case USB_SPEED_LOW:
+			if (temp == PIPE_INTERRUPT) {
+				if (urb->interval > 255)
+					return -EINVAL;
+				// NOTE ohci only handles up to 32
+				temp = 128;
+			} else {
+				if (urb->interval > 1024)
+					urb->interval = 1024;
+				// NOTE usb and ohci handle up to 2^15
+				temp = 1024;
+			}
+		default:
+			return -EINVAL;
+		}
+		/* power of two? */
+		while (temp > urb->interval)
+			temp >>= 1;
+		urb->interval = temp;
+	}
+
+	/*
 	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
 	 * as simple as possible.
 	 */
@@ -1589,6 +1629,9 @@
 	struct usb_hcd		*hcd = __hcd;
 	int			start = hcd->state;
 
+	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
+		return;
+
 	hcd->driver->irq (hcd);
 	if (hcd->state != start && hcd->state == USB_STATE_HALT)
 		hc_died (hcd);
@@ -1642,7 +1685,8 @@
 	// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
 
 	if (urb->status)
-		dbg ("giveback urb %p status %d", urb, urb->status);
+		dbg ("giveback urb %p status %d len %d",
+			urb, urb->status, urb->actual_length);
 
 	/* if no error, make sure urb->next progresses */
 	else if (urb->next) {
diff -urN linux-2.5.6-pre3/drivers/usb/hcd.h linux-2.5.6/drivers/usb/hcd.h
--- linux-2.5.6-pre3/drivers/usb/hcd.h	Thu Mar  7 18:24:32 2002
+++ linux-2.5.6/drivers/usb/hcd.h	Thu Mar  7 18:24:51 2002
@@ -39,7 +39,7 @@
 	struct usb_bus		self;		/* hcd is-a bus */
 
 	const char		*bus_name;
-
+	const char		*product_desc;	/* product/vendor string */
 	const char		*description;	/* "ehci-hcd" etc */
 
 	struct timer_list	rh_timer;	/* drives root hub */
diff -urN linux-2.5.6-pre3/drivers/usb/pegasus.c linux-2.5.6/drivers/usb/pegasus.c
--- linux-2.5.6-pre3/drivers/usb/pegasus.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/usb/pegasus.c	Thu Mar  7 18:24:51 2002
@@ -1,7 +1,7 @@
 /*
 **	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
 **
-**	Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com)
+**	Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
 **	
 **
 **	ChangeLog:
@@ -21,6 +21,8 @@
 **			TODO: suppressing HCD warnings spewage on disconnect.
 **		v0.4.13	Ethernet address is now set at probe(), not at open()
 **			time as this seems to break dhcpd. 
+**		v0.5.0	branch to 2.5.x kernels
+**		v0.5.1	ethtool support added
 */
 
 /*
@@ -46,20 +48,25 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <linux/usb.h>
 #include <linux/module.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 #include "pegasus.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.23 (2002/02/01)"
-#define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
+#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
+#define	BMSR_MEDIA	(BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
+			BMSR_100FULL | BMSR_ANEGCAPABLE)
 
 static int loopback = 0;
 static int mii_mode = 0;
@@ -461,8 +468,8 @@
 	     usb_dev_id[pegasus->dev_index].vendor == VENDOR_DLINK ) {
 		__u16	auxmode;
 
-		read_mii_word( pegasus, 0, 0x1b, &auxmode );
-		write_mii_word( pegasus, 0, 0x1b, auxmode | 4 );
+		read_mii_word( pegasus, 0, MII_TPISTATUS, &auxmode );
+		write_mii_word( pegasus, 0, MII_TPISTATUS, auxmode | 4 );
 	}
 
 	return	0;
@@ -481,16 +488,16 @@
 	if ( !(bmsr & 0x20) && !loopback ) 
 		warn( "%s: link NOT established (0x%x) - check the cable.",
 			dev->name, bmsr );
-	if ( read_mii_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) )
+	if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
 		return 2;
 	if ( !(linkpart & 1) )
 		warn( "link partner stat %x", linkpart );
 
 	data[0] = 0xc9;
 	data[1] = 0;
-	if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) )
+	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_10FULL) )
 		data[1] |= 0x20; /* set full duplex */
-	if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) )
+	if ( linkpart & (ADVERTISE_100FULL | ADVERTISE_100HALF) )
 		data[1] |= 0x10; /* set 100 Mbps */
 	if ( mii_mode )
 		data[1] = 0;
@@ -710,15 +717,26 @@
 }
 
 
+static void set_carrier(struct net_device *net)
+{
+	pegasus_t	*pegasus;
+	short		tmp;
+
+	pegasus = net->priv;
+	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
+	if (tmp & BMSR_LSTATUS)
+		netif_carrier_on(net);
+	else
+		netif_carrier_off(net);
+	
+}
+
+
 static int pegasus_open(struct net_device *net)
 {
 	pegasus_t *pegasus = (pegasus_t *)net->priv;
 	int	res;
 
-	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
-		err("can't enable_net_traffic() - %d", res);
-		return -EIO;
-	}
 	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
@@ -735,6 +753,11 @@
 #endif
 	netif_start_queue( net );
 	pegasus->flags |= PEGASUS_RUNNING;
+	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
+		err("can't enable_net_traffic() - %d", res);
+		return -EIO;
+	}
+	set_carrier(net);
 
 	return 0;
 }
@@ -760,24 +783,103 @@
 }
 
 
+static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
+{
+	pegasus_t	*pegasus;
+	int		cmd;
+	char		tmp[128];
+
+	pegasus = net->priv;
+	if (get_user(cmd, (int *)uaddr))
+		return -EFAULT;
+	switch (cmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
+		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+		sprintf(tmp, "usb%d:%d", pegasus->usb->bus->busnum,
+		        pegasus->usb->devnum);
+		strncpy(info.bus_info, tmp, ETHTOOL_BUSINFO_LEN);
+		if (copy_to_user(uaddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd;
+		short	lpa, bmcr;
+
+		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
+			return -EFAULT;
+		ecmd.supported = (SUPPORTED_10baseT_Half |
+		                 SUPPORTED_10baseT_Full |
+		                 SUPPORTED_100baseT_Half |
+		                 SUPPORTED_100baseT_Full |
+		                 SUPPORTED_Autoneg |
+		                 SUPPORTED_TP |
+		                 SUPPORTED_MII);
+		ecmd.port = PORT_TP;
+		ecmd.transceiver = XCVR_INTERNAL;
+		ecmd.phy_address = pegasus->phy;
+		read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+		read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+		if (bmcr & BMCR_ANENABLE) {
+			ecmd.autoneg = AUTONEG_ENABLE;
+			ecmd.speed = lpa & (LPA_100HALF|LPA_100FULL) ?
+		                     SPEED_100 : SPEED_10;
+			if (ecmd.speed == SPEED_100)
+				ecmd.duplex = lpa & LPA_100FULL ?
+				              DUPLEX_FULL : DUPLEX_HALF;
+			else
+				ecmd.duplex = lpa & LPA_10FULL ?
+				              DUPLEX_FULL : DUPLEX_HALF;
+		} else {
+			ecmd.autoneg = AUTONEG_DISABLE;
+			ecmd.speed = bmcr & BMCR_SPEED100 ? 
+			             SPEED_100 : SPEED_10;
+			ecmd.duplex = bmcr & BMCR_FULLDPLX ?
+			              DUPLEX_FULL : DUPLEX_HALF;
+		}
+		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		return -EOPNOTSUPP;
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = netif_carrier_ok(net);
+		if (copy_to_user(uaddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
 static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
 {
 	__u16 *data = (__u16 *)&rq->ifr_data;
 	pegasus_t	*pegasus = net->priv;
 
 	switch(cmd) {
-		case SIOCDEVPRIVATE:
-			data[0] = pegasus->phy;
-		case SIOCDEVPRIVATE+1:
-			read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
-			return 0;
-		case SIOCDEVPRIVATE+2:
-			if ( !capable(CAP_NET_ADMIN) )
-				return -EPERM;
-			write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
-			return 0;
-		default:
-			return -EOPNOTSUPP;
+	case SIOCETHTOOL:
+		return pegasus_ethtool_ioctl(net, rq->ifr_data);
+	case SIOCDEVPRIVATE:
+		data[0] = pegasus->phy;
+	case SIOCDEVPRIVATE+1:
+		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
+		return 0;
+	case SIOCDEVPRIVATE+2:
+		if ( !capable(CAP_NET_ADMIN) )
+			return -EPERM;
+		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
 	}
 }
 
diff -urN linux-2.5.6-pre3/drivers/usb/pegasus.h linux-2.5.6/drivers/usb/pegasus.h
--- linux-2.5.6-pre3/drivers/usb/pegasus.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/usb/pegasus.h	Thu Mar  7 18:24:51 2002
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 1999,2000 Petko Manolov - Petkan (pmanolov@lnxw.com)
+ * Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,14 +31,6 @@
 #define	EPROM_WR_ENABLE		0x10
 #define	EPROM_LOAD		0x20
 
-#define	MII_BMCR		0x00
-#define	MII_BMSR		0x01
-#define	BMSR_MEDIA		0x7808
-#define	MII_ANLPA		0x05
-#define	ANLPA_100TX_FD		0x0100
-#define	ANLPA_100TX_HD		0x0080
-#define	ANLPA_10T_FD		0x0040
-#define	ANLPA_10T_HD		0x0020
 #define	PHY_DONE		0x80
 #define	PHY_READ		0x40
 #define	PHY_WRITE		0x20
@@ -184,6 +176,8 @@
 PEGASUS_DEV( "ADMtek AN986 \"Pegasus\" USB Ethernet (eval. board)",
 		VENDOR_ADMTEK, 0x0986,
 		DEFAULT_GPIO_RESET | HAS_HOME_PNA )
+PEGASUS_DEV( "AN986A USB MAC", VENDOR_ADMTEK, 1986,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
@@ -254,6 +248,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SMC 2206 USB Ethernet", VENDOR_SMC, 0x0201,
+		DEFAULT_GPIO_RESET | PEGASUS_II)
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
diff -urN linux-2.5.6-pre3/drivers/usb/printer.c linux-2.5.6/drivers/usb/printer.c
--- linux-2.5.6-pre3/drivers/usb/printer.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/drivers/usb/printer.c	Thu Mar  7 18:24:51 2002
@@ -91,7 +91,7 @@
 	struct usb_device 	*dev;			/* USB device */
 	devfs_handle_t		devfs;			/* devfs device */
 	struct semaphore	sem;			/* locks this struct, especially "dev" */
-	struct urb		readurb, writeurb;	/* The urbs */
+	struct urb		*readurb, *writeurb;	/* The urbs */
 	wait_queue_head_t	wait;			/* Zzzzz ... */
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
@@ -253,15 +253,15 @@
 	usblp->used = 1;
 	file->private_data = usblp;
 
-	usblp->writeurb.transfer_buffer_length = 0;
-	usblp->writeurb.status = 0;
+	usblp->writeurb->transfer_buffer_length = 0;
+	usblp->writeurb->status = 0;
 	usblp->wcomplete = 1; /* we begin writeable */
 	usblp->rcomplete = 0;
 
 	if (usblp->bidir) {
 		usblp->readcount = 0;
-		usblp->readurb.dev = usblp->dev;
-		if (usb_submit_urb(&usblp->readurb, GFP_KERNEL) < 0) {
+		usblp->readurb->dev = usblp->dev;
+		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
 			retval = -EIO;
 			usblp->used = 0;
 			file->private_data = NULL;
@@ -278,8 +278,10 @@
 	usblp_table [usblp->minor] = NULL;
 	info ("usblp%d: removed", usblp->minor);
 
-	kfree (usblp->writeurb.transfer_buffer);
+	kfree (usblp->writeurb->transfer_buffer);
 	kfree (usblp->device_id_string);
+	usb_free_urb(usblp->writeurb);
+	usb_free_urb(usblp->readurb);
 	kfree (usblp);
 }
 
@@ -292,8 +294,8 @@
 	usblp->used = 0;
 	if (usblp->dev) {
 		if (usblp->bidir)
-			usb_unlink_urb(&usblp->readurb);
-		usb_unlink_urb(&usblp->writeurb);
+			usb_unlink_urb(usblp->readurb);
+		usb_unlink_urb(usblp->writeurb);
 		up(&usblp->sem);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
@@ -306,8 +308,8 @@
 {
 	struct usblp *usblp = file->private_data;
 	poll_wait(file, &usblp->wait, wait);
- 	return ((!usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
- 			       | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
+ 	return ((!usblp->bidir || usblp->readurb->status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
+ 			       | (usblp->writeurb->status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
 }
 
 static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -423,12 +425,12 @@
 			return -ENODEV;
 		}
 
-		if (usblp->writeurb.status != 0) {
+		if (usblp->writeurb->status != 0) {
 			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
 				if (!usblp->wcomplete)
 					err("usblp%d: error %d writing to printer",
-						usblp->minor, usblp->writeurb.status);
-				err = usblp->writeurb.status;
+						usblp->minor, usblp->writeurb->status);
+				err = usblp->writeurb->status;
 			} else
 				err = usblp_check_status(usblp, err);
 			up (&usblp->sem);
@@ -440,23 +442,23 @@
 			continue;
 		}
 
-		writecount += usblp->writeurb.transfer_buffer_length;
-		usblp->writeurb.transfer_buffer_length = 0;
+		writecount += usblp->writeurb->transfer_buffer_length;
+		usblp->writeurb->transfer_buffer_length = 0;
 
 		if (writecount == count) {
 			up (&usblp->sem);
 			break;
 		}
 
-		usblp->writeurb.transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
-							 (count - writecount) : USBLP_BUF_SIZE;
+		usblp->writeurb->transfer_buffer_length = (count - writecount) < USBLP_BUF_SIZE ?
+							  (count - writecount) : USBLP_BUF_SIZE;
 
-		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
-				usblp->writeurb.transfer_buffer_length)) return -EFAULT;
+		if (copy_from_user(usblp->writeurb->transfer_buffer, buffer + writecount,
+				usblp->writeurb->transfer_buffer_length)) return -EFAULT;
 
-		usblp->writeurb.dev = usblp->dev;
+		usblp->writeurb->dev = usblp->dev;
 		usblp->wcomplete = 0;
-		if (usb_submit_urb(&usblp->writeurb, GFP_KERNEL)) {
+		if (usb_submit_urb(usblp->writeurb, GFP_KERNEL)) {
 			count = -EIO;
 			up (&usblp->sem);
 			break;
@@ -516,29 +518,29 @@
 		goto done;
 	}
 
-	if (usblp->readurb.status) {
+	if (usblp->readurb->status) {
 		err("usblp%d: error %d reading from printer",
-			usblp->minor, usblp->readurb.status);
-		usblp->readurb.dev = usblp->dev;
+			usblp->minor, usblp->readurb->status);
+		usblp->readurb->dev = usblp->dev;
  		usblp->readcount = 0;
-		usb_submit_urb(&usblp->readurb, GFP_KERNEL);
+		usb_submit_urb(usblp->readurb, GFP_KERNEL);
 		count = -EIO;
 		goto done;
 	}
 
-	count = count < usblp->readurb.actual_length - usblp->readcount ?
-		count :	usblp->readurb.actual_length - usblp->readcount;
+	count = count < usblp->readurb->actual_length - usblp->readcount ?
+		count :	usblp->readurb->actual_length - usblp->readcount;
 
-	if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count)) {
+	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
 		count = -EFAULT;
 		goto done;
 	}
 
-	if ((usblp->readcount += count) == usblp->readurb.actual_length) {
+	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
 		usblp->readcount = 0;
-		usblp->readurb.dev = usblp->dev;
+		usblp->readurb->dev = usblp->dev;
 		usblp->rcomplete = 0;
-		if (usb_submit_urb(&usblp->readurb, GFP_KERNEL)) {
+		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
 			count = -EIO;
 			goto done;
 		}
@@ -668,24 +670,42 @@
 
 	init_waitqueue_head(&usblp->wait);
 
+	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usblp->writeurb) {
+		err("out of memory");
+		kfree(usblp);
+		return NULL;
+	}
+	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!usblp->readurb) {
+		err("out of memory");
+		usb_free_urb(usblp->writeurb);
+		kfree(usblp);
+		return NULL;
+	}
+
 	if (!(buf = kmalloc(USBLP_BUF_SIZE * (bidir ? 2 : 1), GFP_KERNEL))) {
 		err("out of memory");
+		usb_free_urb(usblp->writeurb);
+		usb_free_urb(usblp->readurb);
 		kfree(usblp);
 		return NULL;
 	}
 
 	if (!(usblp->device_id_string = kmalloc(DEVICE_ID_SIZE, GFP_KERNEL))) {
 		err("out of memory");
+		usb_free_urb(usblp->writeurb);
+		usb_free_urb(usblp->readurb);
 		kfree(usblp);
 		kfree(buf);
 		return NULL;
 	}
 
-	FILL_BULK_URB(&usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+	FILL_BULK_URB(usblp->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
 		buf, 0, usblp_bulk_write, usblp);
 
 	if (bidir)
-		FILL_BULK_URB(&usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+		FILL_BULK_URB(usblp->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
 			buf + USBLP_BUF_SIZE, USBLP_BUF_SIZE, usblp_bulk_read, usblp);
 
 	/* Get the device_id string if possible. FIXME: Could make this kmalloc(length). */
@@ -737,9 +757,9 @@
 	lock_kernel();
 	usblp->dev = NULL;
 
-	usb_unlink_urb(&usblp->writeurb);
+	usb_unlink_urb(usblp->writeurb);
 	if (usblp->bidir)
-		usb_unlink_urb(&usblp->readurb);
+		usb_unlink_urb(usblp->readurb);
 
 	if (!usblp->used)
 		usblp_cleanup (usblp);
diff -urN linux-2.5.6-pre3/drivers/usb/serial/ir-usb.c linux-2.5.6/drivers/usb/serial/ir-usb.c
--- linux-2.5.6-pre3/drivers/usb/serial/ir-usb.c	Thu Mar  7 18:24:33 2002
+++ linux-2.5.6/drivers/usb/serial/ir-usb.c	Thu Mar  7 18:24:52 2002
@@ -1,8 +1,8 @@
 /*
  * USB IR Dongle driver
  *
- *	Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- *	Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.com)
+ *	Copyright (C) 2001-2002	Greg Kroah-Hartman (greg@kroah.com)
+ *	Copyright (C) 2002	Gary Brubaker (xavyer@ix.netcom.com)
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -21,6 +21,11 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Mar_07	greg kh
+ *	moved some needed structures and #define values from the
+ *	net/irda/irda-usb.h file into our file, as we don't want to depend on
+ *	that codebase compiling correctly :)
+ *
  * 2002_Jan_14  gb
  *	Added module parameter to force specific number of XBOFs.
  *	Added ir_xbof_change().
@@ -56,7 +61,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
-#include <net/irda/irda-usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
@@ -73,6 +77,33 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
+/* USB IrDA class spec information */
+#define USB_CLASS_IRDA		0x02
+#define USB_DT_IRDA		0x21
+#define IU_REQ_GET_CLASS_DESC	0x06
+#define SPEED_2400		0x01
+#define SPEED_9600		0x02
+#define SPEED_19200		0x03
+#define SPEED_38400		0x04
+#define SPEED_57600		0x05
+#define SPEED_115200		0x06
+#define SPEED_576000		0x07
+#define SPEED_1152000		0x08
+#define SPEED_4000000		0x09
+
+struct irda_class_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u16	bcdSpecRevision;
+	u8	bmDataSize;
+	u8	bmWindowSize;
+	u8	bmMinTurnaroundTime;
+	u16	wBaudRate;
+	u8	bmAdditionalBOFs;
+	u8	bIrdaRateSniff;
+	u8	bMaxUnicastList;
+} __attribute__ ((packed));
+
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
@@ -158,7 +189,7 @@
 	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev,0),
 			IU_REQ_GET_CLASS_DESC,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
+			0, ifnum, desc, sizeof(*desc), HZ);
 	
 	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
diff -urN linux-2.5.6-pre3/drivers/video/matrox/matroxfb_DAC1064.c linux-2.5.6/drivers/video/matrox/matroxfb_DAC1064.c
--- linux-2.5.6-pre3/drivers/video/matrox/matroxfb_DAC1064.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/drivers/video/matrox/matroxfb_DAC1064.c	Thu Mar  7 18:24:53 2002
@@ -473,9 +473,12 @@
 
 static int m1064_compute(void* outdev, struct my_timming* m) {
 #define minfo ((struct matrox_fb_info*)outdev)
+#ifdef CONFIG_FB_MATROX_G450
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
-	} else {
+	} else 
+#endif
+	{
 		int i;
 		int tmout;
 		CRITFLAGS
diff -urN linux-2.5.6-pre3/drivers/video/vesafb.c linux-2.5.6/drivers/video/vesafb.c
--- linux-2.5.6-pre3/drivers/video/vesafb.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/drivers/video/vesafb.c	Thu Mar  7 18:24:53 2002
@@ -550,7 +550,7 @@
 		ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
 
 	if (ypan || pmi_setpal) {
-		pmi_base  = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+		pmi_base  = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
 		pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
 		pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
 		printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
diff -urN linux-2.5.6-pre3/fs/cramfs/README linux-2.5.6/fs/cramfs/README
--- linux-2.5.6-pre3/fs/cramfs/README	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/fs/cramfs/README	Thu Mar  7 18:24:53 2002
@@ -6,8 +6,8 @@
 swapped around (though it does care that directory entries (inodes) in
 a given directory are contiguous, as this is used by readdir).
 
-All data is in host-endian format; neither mkcramfs nor the kernel
-ever do swabbing.  (See section `Block Size' below.)
+All data is currently in host-endian format; neither mkcramfs nor the
+kernel ever do swabbing.  (See section `Block Size' below.)
 
 <filesystem>:
 	<superblock>
@@ -29,6 +29,10 @@
 lines); put another way, the same order as `find -type d -exec
 ls -AU1 {} \;'.
 
+Beginning in 2.4.7, directory entries are sorted.  This optimization
+allows cramfs_lookup to return more quickly when a filename does not
+exist, speeds up user-space directory sorts, etc.
+
 <data>:
 	One <file_data> for each file that's either a symlink or a
 	 regular file of non-zero st_size.
@@ -63,17 +67,15 @@
 This kernel supports cramfs holes (i.e. [efficient representation of]
 blocks in uncompressed data consisting entirely of NUL bytes), but by
 default mkcramfs doesn't test for & create holes, since cramfs in
-kernels up to at least 2.3.39 didn't support holes.  Compile mkcramfs
-with -DDO_HOLES if you want it to create files that can have holes in
-them.
+kernels up to at least 2.3.39 didn't support holes.  Run mkcramfs
+with -z if you want it to create files that can have holes in them.
 
 
 Tools
 -----
 
-If you're hacking on cramfs, you might find useful some tools for
-testing cramfs at <http://cvs.bofh.asn.au/cramfs/>, including a
-rudimentary fsck for cramfs.
+The cramfs user-space tools, including mkcramfs and cramfsck, are
+located at <http://sourceforge.net/projects/cramfs/>.
 
 
 Future Development
@@ -103,8 +105,8 @@
 PAGE_CACHE_SIZE (4096)' to `#include <asm/page.h>'.  The disadvantage
 is that the generated cramfs cannot always be shared between different
 kernels, not even necessarily kernels of the same architecture if
-PAGE_CACHE_SIZE is subject to change between kernel versions.
-
+PAGE_CACHE_SIZE is subject to change between kernel versions
+(currently possible with arm and ia64).
 
 The remaining options try to make cramfs more sharable.
 
diff -urN linux-2.5.6-pre3/fs/cramfs/inode.c linux-2.5.6/fs/cramfs/inode.c
--- linux-2.5.6-pre3/fs/cramfs/inode.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/fs/cramfs/inode.c	Thu Mar  7 18:24:53 2002
@@ -117,7 +117,7 @@
 	unsigned i, blocknr, buffer, unread;
 	unsigned long devsize;
 	unsigned int major, minor;
-	
+
 	char *data;
 
 	if (!len)
@@ -187,7 +187,7 @@
 	}
 	return read_buffers[buffer] + offset;
 }
-			
+
 
 static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
 {
@@ -266,7 +266,7 @@
 	buf->f_bavail = 0;
 	buf->f_files = sb->CRAMFS_SB_FILES;
 	buf->f_ffree = 0;
-	buf->f_namelen = 255;
+	buf->f_namelen = CRAMFS_MAXPATHLEN;
 	return 0;
 }
 
@@ -476,4 +476,3 @@
 module_init(init_cramfs_fs)
 module_exit(exit_cramfs_fs)
 MODULE_LICENSE("GPL");
-
diff -urN linux-2.5.6-pre3/fs/exec.c linux-2.5.6/fs/exec.c
--- linux-2.5.6-pre3/fs/exec.c	Thu Mar  7 18:24:34 2002
+++ linux-2.5.6/fs/exec.c	Thu Mar  7 18:24:53 2002
@@ -509,23 +509,49 @@
 
 /*
  * An execve() will automatically "de-thread" the process.
- * Note: we don't have to hold the tasklist_lock to test
- * whether we migth need to do this. If we're not part of
- * a thread group, there is no way we can become one
- * dynamically. And if we are, we only need to protect the
- * unlink - even if we race with the last other thread exit,
- * at worst the list_del_init() might end up being a no-op.
+ * - if a master thread (PID==TGID) is doing this, then all subsidiary threads
+ *   will be killed (otherwise there will end up being two independent thread
+ *   groups with the same TGID).
+ * - if a subsidary thread is doing this, then it just leaves the thread group
  */
-static inline void de_thread(struct task_struct *tsk)
+static void de_thread(struct task_struct *tsk)
 {
-	if (!list_empty(&tsk->thread_group)) {
-		write_lock_irq(&tasklist_lock);
+	struct task_struct *sub;
+	struct list_head *head, *ptr;
+	struct siginfo info;
+	int pause;
+
+	write_lock_irq(&tasklist_lock);
+
+	if (tsk->tgid != tsk->pid) {
+		/* subsidiary thread - just escapes the group */
+		list_del_init(&tsk->thread_group);
+		tsk->tgid = tsk->pid;
+		pause = 0;
+	}
+	else {
+		/* master thread - kill all subsidiary threads */
+		info.si_signo = SIGKILL;
+		info.si_errno = 0;
+		info.si_code = SI_DETHREAD;
+		info.si_pid = current->pid;
+		info.si_uid = current->uid;
+
+		head = tsk->thread_group.next;
 		list_del_init(&tsk->thread_group);
-		write_unlock_irq(&tasklist_lock);
+
+		list_for_each(ptr,head) {
+			sub = list_entry(ptr,struct task_struct,thread_group);
+			send_sig_info(SIGKILL,&info,sub);
+		}
+
+		pause = 1;
 	}
 
-	/* Minor oddity: this might stay the same. */
-	tsk->tgid = tsk->pid;
+	write_unlock_irq(&tasklist_lock);
+
+	/* give the subsidiary threads a chance to clean themselves up */
+	if (pause) yield();
 }
 
 int flush_old_exec(struct linux_binprm * bprm)
@@ -566,7 +592,8 @@
 
 	flush_thread();
 
-	de_thread(current);
+	if (!list_empty(&current->thread_group))
+		de_thread(current);
 
 	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
 	    permission(bprm->file->f_dentry->d_inode,MAY_READ))
diff -urN linux-2.5.6-pre3/fs/ext2/ext2.h linux-2.5.6/fs/ext2/ext2.h
--- linux-2.5.6-pre3/fs/ext2/ext2.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/fs/ext2/ext2.h	Thu Mar  7 18:24:54 2002
@@ -63,7 +63,6 @@
 
 /* fsync.c */
 extern int ext2_sync_file (struct file *, struct dentry *, int);
-extern int ext2_fsync_inode (struct inode *, int);
 
 /* ialloc.c */
 extern struct inode * ext2_new_inode (struct inode *, int);
diff -urN linux-2.5.6-pre3/fs/ext2/fsync.c linux-2.5.6/fs/ext2/fsync.c
--- linux-2.5.6-pre3/fs/ext2/fsync.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/fs/ext2/fsync.c	Thu Mar  7 18:24:54 2002
@@ -35,11 +35,6 @@
 int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	struct inode *inode = dentry->d_inode;
-	return ext2_fsync_inode(inode, datasync);
-}
-
-int ext2_fsync_inode(struct inode *inode, int datasync)
-{
 	int err;
 	
 	err  = fsync_inode_buffers(inode);
diff -urN linux-2.5.6-pre3/fs/inode.c linux-2.5.6/fs/inode.c
--- linux-2.5.6-pre3/fs/inode.c	Thu Mar  7 18:24:35 2002
+++ linux-2.5.6/fs/inode.c	Thu Mar  7 18:24:54 2002
@@ -291,15 +291,15 @@
 
 static inline void sync_one(struct inode *inode, int sync)
 {
-	if (inode->i_state & I_LOCK) {
+	while (inode->i_state & I_LOCK) {
 		__iget(inode);
 		spin_unlock(&inode_lock);
 		__wait_on_inode(inode);
 		iput(inode);
 		spin_lock(&inode_lock);
-	} else {
-		__sync_one(inode, sync);
 	}
+
+	__sync_one(inode, sync);
 }
 
 static inline void sync_list(struct list_head *head)
diff -urN linux-2.5.6-pre3/fs/jfs/jfs_dtree.c linux-2.5.6/fs/jfs/jfs_dtree.c
--- linux-2.5.6-pre3/fs/jfs/jfs_dtree.c	Thu Mar  7 18:24:35 2002
+++ linux-2.5.6/fs/jfs/jfs_dtree.c	Thu Mar  7 18:24:54 2002
@@ -798,7 +798,7 @@
 	 *      insert entry for new key
 	 */
 	if (DO_INDEX(ip)) {
-		if (JFS_IP(ip)->next_index == -1) {
+		if (JFS_IP(ip)->next_index == DIREND) {
 			DT_PUTPAGE(mp);
 			return EMLINK;
 		}
@@ -1927,22 +1927,6 @@
 			release_metapage(mp);
 	}
 	/*
-	 * Update directory index table for entries now in right page
-	 */
-	if ((rp->header.flag & BT_LEAF) && DO_INDEX(ip)) {
-		metapage_t *mp = 0;
-		ldtentry_t *ldtentry;
-
-		stbl = DT_GETSTBL(rp);
-		for (n = 0; n < rp->header.nextindex; n++) {
-			ldtentry = (ldtentry_t *) & rp->slot[stbl[n]];
-			modify_index(tid, ip, le32_to_cpu(ldtentry->index),
-				     rbn, n, &mp);
-		}
-		if (mp)
-			release_metapage(mp);
-	}
-	/*
 	 * insert the new entry into the new right/child page
 	 * (skip index in the new right page will not change)
 	 */
@@ -2885,7 +2869,7 @@
 	int do_index = 0;
 	uint loop_count = 0;
 
-	if (filp->f_pos == -1)
+	if (filp->f_pos == DIREND)
 		return 0;
 
 	if (DO_INDEX(ip)) {
@@ -2904,25 +2888,25 @@
 			dir_table_slot_t dirtab_slot;
 
 			if (dtEmpty(ip)) {
-				filp->f_pos = -1;
+				filp->f_pos = DIREND;
 				return 0;
 			}
 		      repeat:
 			rc = get_index(ip, dir_index, &dirtab_slot);
 			if (rc) {
-				filp->f_pos = -1;
+				filp->f_pos = DIREND;
 				return rc;
 			}
 			if (dirtab_slot.flag == DIR_INDEX_FREE) {
 				if (loop_count++ > JFS_IP(ip)->next_index) {
 					jERROR(1, ("jfs_readdir detected "
 						   "infinite loop!\n"));
-					filp->f_pos = -1;
+					filp->f_pos = DIREND;
 					return 0;
 				}
 				dir_index = le32_to_cpu(dirtab_slot.addr2);
 				if (dir_index == -1) {
-					filp->f_pos = -1;
+					filp->f_pos = DIREND;
 					return 0;
 				}
 				goto repeat;
@@ -2931,13 +2915,7 @@
 			index = dirtab_slot.slot;
 			DT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 			if (rc) {
-				filp->f_pos = -1;
-				return 0;
-			}
-			if (p->header.flag & BT_INTERNAL) {
-				jERROR(1,("jfs_readdir: bad index table\n"));
-				DT_PUTPAGE(mp);
-				filp->f_pos = -1;
+				filp->f_pos = DIREND;
 				return 0;
 			}
 			if (p->header.flag & BT_INTERNAL) {
@@ -2968,7 +2946,7 @@
 			 * Find first entry of left-most leaf
 			 */
 			if (dtEmpty(ip)) {
-				filp->f_pos = -1;
+				filp->f_pos = DIREND;
 				return 0;
 			}
 
@@ -3013,7 +2991,7 @@
 		}
 
 		if (dtEmpty(ip)) {
-			filp->f_pos = -1;
+			filp->f_pos = DIREND;
 			return 0;
 		}
 
@@ -3021,7 +2999,7 @@
 			jERROR(1,
 			       ("jfs_readdir: unexpected rc = %d from dtReadNext\n",
 				rc));
-			filp->f_pos = -1;
+			filp->f_pos = DIREND;
 			return 0;
 		}
 		/* get start leaf page and index */
@@ -3029,7 +3007,7 @@
 
 		/* offset beyond directory eof ? */
 		if (bn < 0) {
-			filp->f_pos = -1;
+			filp->f_pos = DIREND;
 			return 0;
 		}
 	}
@@ -3038,7 +3016,7 @@
 	if (d_name == NULL) {
 		DT_PUTPAGE(mp);
 		jERROR(1, ("jfs_readdir: kmalloc failed!\n"));
-		filp->f_pos = -1;
+		filp->f_pos = DIREND;
 		return 0;
 	}
 	while (1) {
@@ -3087,13 +3065,13 @@
 		 */
 
 		if (p->header.flag & BT_ROOT) {
-			filp->f_pos = -1;
+			filp->f_pos = DIREND;
 			break;
 		}
 
 		bn = le64_to_cpu(p->header.next);
 		if (bn == 0) {
-			filp->f_pos = -1;
+			filp->f_pos = DIREND;
 			break;
 		}
 
diff -urN linux-2.5.6-pre3/fs/jfs/jfs_dtree.h linux-2.5.6/fs/jfs/jfs_dtree.h
--- linux-2.5.6-pre3/fs/jfs/jfs_dtree.h	Thu Mar  7 18:24:35 2002
+++ linux-2.5.6/fs/jfs/jfs_dtree.h	Thu Mar  7 18:24:54 2002
@@ -252,6 +252,10 @@
 #define DIRENTSIZ(namlen) \
     ( (sizeof(struct dirent) - 2*(JFS_NAME_MAX+1) + 2*((namlen)+1) + 3) &~ 3 )
 
+/*
+ * Maximum file offset for directories.
+ */
+#define DIREND	INT_MAX
 
 /*
  *	external declarations
diff -urN linux-2.5.6-pre3/fs/nfsd/nfsctl.c linux-2.5.6/fs/nfsd/nfsctl.c
--- linux-2.5.6-pre3/fs/nfsd/nfsctl.c	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/fs/nfsd/nfsctl.c	Thu Mar  7 18:24:55 2002
@@ -32,6 +32,7 @@
 #include <asm/uaccess.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 static int	nfsctl_svc(struct nfsctl_svc *data);
 static int	nfsctl_addclient(struct nfsctl_client *data);
diff -urN linux-2.5.6-pre3/fs/smbfs/ChangeLog linux-2.5.6/fs/smbfs/ChangeLog
--- linux-2.5.6-pre3/fs/smbfs/ChangeLog	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/fs/smbfs/ChangeLog	Thu Mar  7 18:24:55 2002
@@ -1,5 +1,18 @@
 ChangeLog for smbfs.
 
+2001-08-03 Urban Widmark <urban@teststation.com>
+
+	* *.c: Unicode support
+
+2001-08-23 Jochen Dolze <dolze@epcnet.de>
+
+	* proc.c: Correct rsize/wsize computation for readX/writeX
+
+2001-0?-?? Urban Widmark <urban@teststation.com>
+
+	* *.c: Add LFS
+	* *.c: Move to a "driver" style handling of different servertypes.
+	       (Not all operations are done this way. yet.)
 2001-12-31 René Scharfe <l.s.r@web.de>
 
 	* inode.c: added smb_show_options to show mount options in /proc/mounts
diff -urN linux-2.5.6-pre3/fs/smbfs/cache.c linux-2.5.6/fs/smbfs/cache.c
--- linux-2.5.6-pre3/fs/smbfs/cache.c	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/fs/smbfs/cache.c	Thu Mar  7 18:24:55 2002
@@ -84,7 +84,7 @@
 	struct list_head *next;
 
 	if (d_validate(dent, parent)) {
-		if (dent->d_name.len <= SMB_MAXPATHLEN &&
+		if (dent->d_name.len <= SMB_MAXNAMELEN &&
 		    (unsigned long)dent->d_fsdata == fpos) {
 			if (!dent->d_inode) {
 				dput(dent);
diff -urN linux-2.5.6-pre3/fs/smbfs/dir.c linux-2.5.6/fs/smbfs/dir.c
--- linux-2.5.6-pre3/fs/smbfs/dir.c	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/fs/smbfs/dir.c	Thu Mar  7 18:24:55 2002
@@ -187,7 +187,7 @@
 	ctl.filled = 0;
 	ctl.valid  = 1;
 read_really:
-	result = smb_proc_readdir(filp, dirent, filldir, &ctl);
+	result = server->ops->readdir(filp, dirent, filldir, &ctl);
 	if (ctl.idx == -1)
 		goto invalid_cache;	/* retry */
 	ctl.head.end = ctl.fpos - 1;
diff -urN linux-2.5.6-pre3/fs/smbfs/file.c linux-2.5.6/fs/smbfs/file.c
--- linux-2.5.6-pre3/fs/smbfs/file.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/fs/smbfs/file.c	Thu Mar  7 18:24:55 2002
@@ -55,12 +55,13 @@
 smb_readpage_sync(struct dentry *dentry, struct page *page)
 {
 	char *buffer = kmap(page);
-	unsigned long offset = page->index << PAGE_CACHE_SHIFT;
-	int rsize = smb_get_rsize(server_from_dentry(dentry));
+	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+	struct smb_sb_info *server = server_from_dentry(dentry);
+	unsigned int rsize = smb_get_rsize(server);
 	int count = PAGE_SIZE;
 	int result;
 
-	VERBOSE("file %s/%s, count=%d@%ld, rsize=%d\n",
+	VERBOSE("file %s/%s, count=%d@%Ld, rsize=%d\n",
 		DENTRY_PATH(dentry), count, offset, rsize);
 
 	result = smb_open(dentry, SMB_O_RDONLY);
@@ -74,7 +75,7 @@
 		if (count < rsize)
 			rsize = count;
 
-		result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
+		result = server->ops->read(dentry->d_inode,offset,rsize,buffer);
 		if (result < 0)
 			goto io_error;
 
@@ -118,21 +119,23 @@
  */
 static int
 smb_writepage_sync(struct inode *inode, struct page *page,
-		   unsigned long offset, unsigned int count)
+		   unsigned long pageoffset, unsigned int count)
 {
-	char *buffer = kmap(page) + offset;
-	int wsize = smb_get_wsize(server_from_inode(inode));
+	loff_t offset;
+	char *buffer = kmap(page) + pageoffset;
+	struct smb_sb_info *server = server_from_inode(inode);
+	unsigned int wsize = smb_get_wsize(server);
 	int result, written = 0;
 
-	offset += page->index << PAGE_CACHE_SHIFT;
-	VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
-		inode->i_ino, SMB_I(inode)->fileid, count, offset, wsize);
+	offset = ((loff_t)page->index << PAGE_CACHE_SHIFT) + pageoffset;
+	VERBOSE("file ino=%ld, fileid=%d, count=%d@%Ld, wsize=%d\n",
+		inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
 
 	do {
 		if (count < wsize)
 			wsize = count;
 
-		result = smb_proc_write(inode, offset, wsize, buffer);
+		result = server->ops->write(inode, offset, wsize, buffer);
 		if (result < 0) {
 			PARANOIA("failed write, wsize=%d, result=%d\n",
 				 wsize, result);
diff -urN linux-2.5.6-pre3/fs/smbfs/inode.c linux-2.5.6/fs/smbfs/inode.c
--- linux-2.5.6-pre3/fs/smbfs/inode.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/fs/smbfs/inode.c	Thu Mar  7 18:24:55 2002
@@ -445,8 +445,7 @@
 	if (server->conn_pid)
 	       kill_proc(server->conn_pid, SIGTERM, 1);
 
-	smb_kfree(server->mnt);
-	smb_kfree(server->temp_buf);
+	smb_kfree(server->ops);
 	if (server->packet)
 		smb_vfree(server->packet);
 
@@ -468,6 +467,7 @@
 	struct inode *root_inode;
 	struct smb_fattr root;
 	int ver;
+	void *mem;
 
 	if (!raw_data)
 		goto out_no_data;
@@ -494,22 +494,29 @@
 	if (!server->packet)
 		goto out_no_mem;
 
-	/* Allocate the global temp buffer */
-	server->temp_buf = smb_kmalloc(2*SMB_MAXPATHLEN+20, GFP_KERNEL);
-	if (!server->temp_buf)
+	/* Allocate the global temp buffer and some superblock helper structs */
+	VERBOSE("alloc chunk = %d\n", sizeof(struct smb_ops) +
+		sizeof(struct smb_mount_data_kernel) +
+		2*SMB_MAXPATHLEN + 20);
+	mem = smb_kmalloc(sizeof(struct smb_ops) +
+			  sizeof(struct smb_mount_data_kernel) +
+			  2*SMB_MAXPATHLEN + 20, GFP_KERNEL);
+	if (!mem)
 		goto out_no_temp;
 
+	server->ops = mem;
+	server->mnt = mem + sizeof(struct smb_ops);
+	server->name_buf = mem + sizeof(struct smb_ops) +
+		sizeof(struct smb_mount_data_kernel);
+	server->temp_buf = mem + sizeof(struct smb_ops) +
+		sizeof(struct smb_mount_data_kernel) +
+		SMB_MAXPATHLEN + 1;
+
 	/* Setup NLS stuff */
 	server->remote_nls = NULL;
 	server->local_nls = NULL;
-	server->name_buf = server->temp_buf + SMB_MAXPATHLEN + 20;
 
-	/* Allocate the mount data structure */
-	/* FIXME: merge this with the other malloc and get a whole page? */
-	mnt = smb_kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL);
-	if (!mnt)
-		goto out_no_mount;
-	server->mnt = mnt;
+	mnt = server->mnt;
 
 	memset(mnt, 0, sizeof(struct smb_mount_data_kernel));
 	strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT,
@@ -565,9 +572,7 @@
 out_no_root:
 	iput(root_inode);
 out_bad_option:
-	smb_kfree(server->mnt);
-out_no_mount:
-	smb_kfree(server->temp_buf);
+	smb_kfree(mem);
 out_no_temp:
 	smb_vfree(server->packet);
 out_no_mem:
@@ -630,8 +635,7 @@
 		error = smb_open(dentry, O_WRONLY);
 		if (error)
 			goto out;
-		error = smb_proc_trunc(server, SMB_I(inode)->fileid,
-				       attr->ia_size);
+		error = server->ops->truncate(inode, attr->ia_size);
 		if (error)
 			goto out;
 		error = vmtruncate(inode, attr->ia_size);
diff -urN linux-2.5.6-pre3/fs/smbfs/proc.c linux-2.5.6/fs/smbfs/proc.c
--- linux-2.5.6-pre3/fs/smbfs/proc.c	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/fs/smbfs/proc.c	Thu Mar  7 18:24:55 2002
@@ -48,16 +48,29 @@
 #define SMB_ST_BLKSIZE	(PAGE_SIZE)
 #define SMB_ST_BLKSHIFT	(PAGE_SHIFT)
 
+static struct smb_ops smb_ops_core;
+static struct smb_ops smb_ops_os2;
+static struct smb_ops smb_ops_win95;
+static struct smb_ops smb_ops_winNT;
+
+static void
+smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+static void
+smb_finish_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
+static int
+smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir,
+		      struct smb_fattr *fattr);
 static int
-smb_proc_setattr_ext(struct smb_sb_info *, struct inode *,
-		     struct smb_fattr *);
+smb_proc_getattr_ff(struct smb_sb_info *server, struct dentry *dentry,
+		    struct smb_fattr *fattr);
 static int
 smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry,
-                      __u16 attr);
+		      u16 attr);
 static int
-smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
-		    struct smb_fattr *fattr);
-
+smb_proc_setattr_ext(struct smb_sb_info *server,
+		     struct inode *inode, struct smb_fattr *fattr);
+static void
+install_ops(struct smb_ops *dst, struct smb_ops *src);
 
 
 static void
@@ -98,8 +111,8 @@
 }
 
 /* no conversion, just a wrapper for memcpy. */
-static int convert_memcpy(char *output, int olen,
-			  const char *input, int ilen,
+static int convert_memcpy(unsigned char *output, int olen,
+			  const unsigned char *input, int ilen,
 			  struct nls_table *nls_from,
 			  struct nls_table *nls_to)
 {
@@ -109,9 +122,25 @@
 	return ilen;
 }
 
+static inline int write_char(unsigned char ch, char *output, int olen)
+{
+	if (olen < 4)
+		return -ENAMETOOLONG;
+	sprintf(output, ":x%02x", ch);
+	return 4;
+}
+
+static inline int write_unichar(wchar_t ch, char *output, int olen)
+{
+	if (olen < 5)
+		return -ENAMETOOLONG;
+	sprintf(output, ":%04x", ch);
+	return 5;
+}
+
 /* convert from one "codepage" to another (possibly being utf8). */
-static int convert_cp(char *output, int olen,
-		      const char *input, int ilen,
+static int convert_cp(unsigned char *output, int olen,
+		      const unsigned char *input, int ilen,
 		      struct nls_table *nls_from,
 		      struct nls_table *nls_to)
 {
@@ -119,20 +148,26 @@
 	int n;
 	wchar_t ch;
 
-	if (!nls_from || !nls_to) {
-		PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to);
-		return convert_memcpy(output, olen, input, ilen, NULL, NULL);
-	}
-
 	while (ilen > 0) {
 		/* convert by changing to unicode and back to the new cp */
-		n = nls_from->char2uni((unsigned char *)input, ilen, &ch);
-		if (n < 0)
+		n = nls_from->char2uni(input, ilen, &ch);
+		if (n == -EINVAL) {
+			ilen--;
+			n = write_char(*input++, output, olen);
+			if (n < 0)
+				goto fail;
+			output += n;
+			olen -= n;
+			len += n;
+			continue;
+		} else if (n < 0)
 			goto fail;
 		input += n;
 		ilen -= n;
 
 		n = nls_to->uni2char(ch, output, olen);
+		if (n == -EINVAL)
+			n = write_unichar(ch, output, olen);
 		if (n < 0)
 			goto fail;
 		output += n;
@@ -145,6 +180,42 @@
 	return n;
 }
 
+/* ----------------------------------------------------------- */
+
+/*
+ * nls_unicode
+ *
+ * This encodes/decodes little endian unicode format
+ */
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+	if (boundlen < 2)
+		return -EINVAL;
+	*out++ = uni & 0xff;
+	*out++ = uni >> 8;
+	return 2;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+	if (boundlen < 2)
+		return -EINVAL;
+	*uni = (rawstring[1] << 8) | rawstring[0];
+	return 2;
+}
+
+static struct nls_table unicode_table = {
+	"unicode",
+	uni2char,
+	char2uni,
+	NULL,		/* not used by smbfs */
+	NULL,
+	NULL,		/* not a module */
+};
+
+/* ----------------------------------------------------------- */
+
 static int setcodepage(struct nls_table **p, char *name)
 {
 	struct nls_table *nls;
@@ -157,7 +228,7 @@
 	}
 
 	/* if already set, unload the previous one. */
-	if (*p)
+	if (*p && *p != &unicode_table)
 		unload_nls(*p);
 	*p = nls;
 
@@ -175,18 +246,25 @@
 	if (!*cp->remote_name)
 		goto out;
 
+	/* local */
 	n = setcodepage(&server->local_nls, cp->local_name);
 	if (n != 0)
 		goto out;
-	n = setcodepage(&server->remote_nls, cp->remote_name);
-	if (n != 0)
-		setcodepage(&server->local_nls, NULL);
+
+	/* remote */
+	if (!strcmp(cp->remote_name, "unicode")) {
+		server->remote_nls = &unicode_table;
+	} else {
+		n = setcodepage(&server->remote_nls, cp->remote_name);
+		if (n != 0)
+			setcodepage(&server->local_nls, NULL);
+	}
 
 out:
 	if (server->local_nls != NULL && server->remote_nls != NULL)
-		server->convert = convert_cp;
+		server->ops->convert = convert_cp;
 	else
-		server->convert = convert_memcpy;
+		server->ops->convert = convert_memcpy;
 
 	smb_unlock_server(server);
 	return n;
@@ -217,17 +295,19 @@
  * smb_build_path: build the path to entry and name storing it in buf.
  * The path returned will have the trailing '\0'.
  */
-static int smb_build_path(struct smb_sb_info *server, char * buf, int maxlen,
-			  struct dentry * entry, struct qstr * name)
+static int smb_build_path(struct smb_sb_info *server, unsigned char *buf,
+			  int maxlen,
+			  struct dentry *entry, struct qstr *name)
 {
-	char *path = buf;
+	unsigned char *path = buf;
 	int len;
+	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE) != 0;
 
-	if (maxlen < 2)
+	if (maxlen < (2<<unicode))
 		return -ENAMETOOLONG;
 
-	if (maxlen > SMB_MAXNAMELEN + 1)
-		maxlen = SMB_MAXNAMELEN + 1;
+	if (maxlen > SMB_MAXPATHLEN + 1)
+		maxlen = SMB_MAXPATHLEN + 1;
 
 	if (entry == NULL)
 		goto test_name_and_out;
@@ -237,8 +317,10 @@
 	 */
 	if (IS_ROOT(entry) && !name) {
 		*path++ = '\\';
+		if (unicode) *path++ = '\0';
 		*path++ = '\0';
-		return 2;
+		if (unicode) *path++ = '\0';
+		return path-buf;
 	}
 
 	/*
@@ -247,12 +329,12 @@
 	 */
 	read_lock(&dparent_lock);
 	while (!IS_ROOT(entry)) {
-		if (maxlen < 3) {
+		if (maxlen < (3<<unicode)) {
 			read_unlock(&dparent_lock);
 			return -ENAMETOOLONG;
 		}
 
-		len = server->convert(path, maxlen-2, 
+		len = server->ops->convert(path, maxlen-2, 
 				      entry->d_name.name, entry->d_name.len,
 				      server->local_nls, server->remote_nls);
 		if (len < 0) {
@@ -261,23 +343,30 @@
 		}
 		reverse_string(path, len);
 		path += len;
+		if (unicode) {
+			/* Note: reverse order */
+			*path++ = '\0';
+			maxlen--;
+		}
 		*path++ = '\\';
 		maxlen -= len+1;
 
 		entry = entry->d_parent;
-		if (IS_ROOT(entry))
-			break;
 	}
 	read_unlock(&dparent_lock);
 	reverse_string(buf, path-buf);
 
-	/* maxlen is at least 1 */
+	/* maxlen has space for at least one char */
 test_name_and_out:
 	if (name) {
-		if (maxlen < 3)
+		if (maxlen < (3<<unicode))
 			return -ENAMETOOLONG;
 		*path++ = '\\';
-		len = server->convert(path, maxlen-2, 
+		if (unicode) {
+			*path++ = '\0';
+			maxlen--;
+		}
+		len = server->ops->convert(path, maxlen-2, 
 				      name->name, name->len,
 				      server->local_nls, server->remote_nls);
 		if (len < 0)
@@ -285,8 +374,9 @@
 		path += len;
 		maxlen -= len+1;
 	}
-	/* maxlen is at least 1 */
+	/* maxlen has space for at least one char */
 	*path++ = '\0';
+	if (unicode) *path++ = '\0';
 	return path-buf;
 }
 
@@ -304,16 +394,31 @@
 	return result;
 }
 
+/* encode_path for non-trans2 request SMBs */
 static int smb_simple_encode_path(struct smb_sb_info *server, char **p,
 			  struct dentry * entry, struct qstr * name)
 {
 	char *s = *p;
 	int res;
 	int maxlen = ((char *)server->packet + server->packet_size) - s;
+	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
 
 	if (!maxlen)
 		return -ENAMETOOLONG;
-	*s++ = 4;
+	*s++ = 4;	/* ASCII data format */
+
+	/*
+	 * SMB Unicode strings must be 16bit aligned relative the start of the
+	 * packet. If they are not they must be padded with 0.
+	 */
+	if (unicode) {
+		int align = s - (char *)server->packet;
+		if (align & 1) {
+			*s++ = '\0';
+			maxlen--;
+		}
+	}
+
 	res = smb_encode_path(server, s, maxlen-1, entry, name);
 	if (res < 0)
 		return res;
@@ -505,7 +610,8 @@
 int
 smb_get_rsize(struct smb_sb_info *server)
 {
-	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+	/* readX has 12 parameters, read has 5 */
+	int overhead = SMB_HEADER_LEN + 12 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
 	VERBOSE("packet=%d, xmit=%d, size=%d\n",
@@ -520,7 +626,8 @@
 int
 smb_get_wsize(struct smb_sb_info *server)
 {
-	int overhead = SMB_HEADER_LEN + 5 * sizeof(__u16) + 2 + 1 + 2;
+	/* writeX has 14 parameters, write has 5 */
+	int overhead = SMB_HEADER_LEN + 14 * sizeof(__u16) + 2 + 1 + 2;
 	int size = smb_get_xmitsize(server, overhead);
 
 	VERBOSE("packet=%d, xmit=%d, size=%d\n",
@@ -836,13 +943,57 @@
 
 	/* now that we have an established connection we can detect the server
 	   type and enable bug workarounds */
-	if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
-	    (server->opt.max_xmit < 0x1000) &&
-	    !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
+	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2)
+		install_ops(server->ops, &smb_ops_core);
+	else if (server->opt.protocol == SMB_PROTOCOL_LANMAN2)
+		install_ops(server->ops, &smb_ops_os2);
+	else if (server->opt.protocol == SMB_PROTOCOL_NT1 &&
+		 (server->opt.max_xmit < 0x1000) &&
+		 !(server->opt.capabilities & SMB_CAP_NT_SMBS)) {
+		/* FIXME: can we kill the WIN95 flag now? */
 		server->mnt->flags |= SMB_MOUNT_WIN95;
-		VERBOSE("smb_newconn: detected WIN95 server\n");
+		VERBOSE("detected WIN95 server\n");
+		install_ops(server->ops, &smb_ops_win95);
+	} else {
+		/*
+		 * Samba has max_xmit 65535
+		 * NT4spX has max_xmit 4536 (or something like that)
+		 * win2k has ...
+		 */
+		VERBOSE("detected NT1 (Samba, NT4/5) server\n");
+		install_ops(server->ops, &smb_ops_winNT);
 	}
 
+	/* FIXME: the win9x code wants to modify these ... (seek/trunc bug) */
+	if (server->mnt->flags & SMB_MOUNT_OLDATTR) {
+		server->ops->getattr = smb_proc_getattr_core;
+	} else if (server->mnt->flags & SMB_MOUNT_DIRATTR) {
+		server->ops->getattr = smb_proc_getattr_ff;
+	}
+
+	/* Decode server capabilities */
+	if (server->opt.capabilities & SMB_CAP_LARGE_FILES) {
+		/* Should be ok to set this now, as no one can access the
+		   mount until the connection has been established. */
+		SB_of(server)->s_maxbytes = ~0ULL >> 1;
+		VERBOSE("LFS enabled\n");
+	}
+	if (server->opt.capabilities & SMB_CAP_UNICODE) {
+		server->mnt->flags |= SMB_MOUNT_UNICODE;
+		VERBOSE("Unicode enabled\n");
+	} else {
+		server->mnt->flags &= ~SMB_MOUNT_UNICODE;
+	}
+#if 0
+	/* flags we may test for other patches ... */
+	if (server->opt.capabilities & SMB_CAP_LARGE_READX) {
+		VERBOSE("Large reads enabled\n");
+	}
+	if (server->opt.capabilities & SMB_CAP_LARGE_WRITEX) {
+		VERBOSE("Large writes enabled\n");
+	}
+#endif
+
 	VERBOSE("protocol=%d, max_xmit=%d, pid=%d capabilities=0x%x\n",
 		server->opt.protocol, server->opt.max_xmit, server->conn_pid,
 		server->opt.capabilities);
@@ -919,10 +1070,15 @@
 	WSET(buf, smb_uid, server->opt.server_uid);
 	WSET(buf, smb_mid, 1);
 
-	if (server->opt.protocol > SMB_PROTOCOL_CORE)
-	{
-		*(buf+smb_flg) = 0x8;
-		WSET(buf, smb_flg2, 0x3);
+	if (server->opt.protocol > SMB_PROTOCOL_CORE) {
+		int flags = SMB_FLAGS_CASELESS_PATHNAMES;
+		int flags2 = SMB_FLAGS2_LONG_PATH_COMPONENTS |
+			SMB_FLAGS2_EXTENDED_ATTRIBUTES;	/* EA? not really ... */
+
+		*(buf+smb_flg) = flags;
+		if (server->mnt->flags & SMB_MOUNT_UNICODE)
+			flags2 |= SMB_FLAGS2_UNICODE_STRINGS;
+		WSET(buf, smb_flg2, flags2);
 	}
 	*p++ = wct;		/* wct */
 	p += 2 * wct;
@@ -1181,8 +1337,8 @@
 /* In smb_proc_read and smb_proc_write we do not retry, because the
    file-id would not be valid after a reconnection. */
 
-int
-smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
+static int
+smb_proc_read(struct inode *inode, loff_t offset, int count, char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
 	__u16 returned_count, data_len;
@@ -1230,15 +1386,15 @@
 	return result;
 }
 
-int
-smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
+static int
+smb_proc_write(struct inode *inode, loff_t offset, int count, const char *data)
 {
 	struct smb_sb_info *server = server_from_inode(inode);
 	int result;
 	__u8 *p;
 	__u16 fileid = SMB_I(inode)->fileid;
 
-	VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
 		inode->i_ino, SMB_I(inode)->fileid, count, offset,
 		server->packet_size);
 
@@ -1261,6 +1417,94 @@
 	return result;
 }
 
+/*
+ * In smb_proc_readX and smb_proc_writeX we do not retry, because the
+ * file-id would not be valid after a reconnection.
+ */
+static int
+smb_proc_readX(struct inode *inode, loff_t offset, int count, char *data)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	u16 data_len, data_off;
+	unsigned char *buf;
+	int result;
+
+	smb_lock_server(server);
+	smb_setup_header(server, SMBreadX, 12, 0);
+	buf = server->packet;
+	WSET(buf, smb_vwv0, 0x00ff);
+	WSET(buf, smb_vwv1, 0);
+	WSET(buf, smb_vwv2, SMB_I(inode)->fileid);
+	DSET(buf, smb_vwv3, (u32)offset);               /* low 32 bits */
+	WSET(buf, smb_vwv5, count);
+	WSET(buf, smb_vwv6, 0);
+	DSET(buf, smb_vwv7, 0);
+	WSET(buf, smb_vwv9, 0);
+	DSET(buf, smb_vwv10, (u32)(offset >> 32));      /* high 32 bits */
+	WSET(buf, smb_vwv11, 0);
+
+	result = smb_request_ok(server, SMBreadX, 12, -1);
+	if (result < 0)
+		goto out;
+	data_len = WVAL(server->packet, smb_vwv5);
+	data_off = WVAL(server->packet, smb_vwv6);
+	buf = smb_base(server->packet) + data_off;
+
+	/* we can NOT simply trust the info given by the server ... */
+	if (data_len > server->packet_size - (buf - server->packet)) {
+		printk(KERN_ERR "smb_proc_read: invalid data length!! "
+		       "%d > %d - (%p - %p)\n",
+		       data_len, server->packet_size, buf, server->packet);
+		result = -EIO;
+		goto out;
+	}
+
+	memcpy(data, buf, data_len);
+	result = data_len;
+
+out:
+	smb_unlock_server(server);
+	VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
+		inode->i_ino, SMB_I(inode)->fileid, count, result);
+	return result;
+}
+
+static int
+smb_proc_writeX(struct inode *inode, loff_t offset, int count, const char *data)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int result;
+	u8 *p;
+
+	VERBOSE("ino=%ld, fileid=%d, count=%d@%Ld, packet_size=%d\n",
+		inode->i_ino, SMB_I(inode)->fileid, count, offset,
+		server->packet_size);
+
+	smb_lock_server(server);
+	p = smb_setup_header(server, SMBwriteX, 14, count + 2);
+	WSET(server->packet, smb_vwv0, 0x00ff);
+	WSET(server->packet, smb_vwv1, 0);
+	WSET(server->packet, smb_vwv2, SMB_I(inode)->fileid);
+	DSET(server->packet, smb_vwv3, (u32)offset);    /* low 32 bits */
+	DSET(server->packet, smb_vwv5, 0);
+	WSET(server->packet, smb_vwv7, 0);              /* write mode */
+	WSET(server->packet, smb_vwv8, 0);
+	WSET(server->packet, smb_vwv9, 0);
+	WSET(server->packet, smb_vwv10, count);         /* data length */
+	WSET(server->packet, smb_vwv11, p + 2 - smb_base(server->packet));
+	DSET(server->packet, smb_vwv12, (u32)(offset >> 32));
+	*p++ = 0;    /* FIXME: pad to short or long ... change +2 above also */
+	*p++ = 0;
+	memcpy(p, data, count);
+
+	result = smb_request_ok(server, SMBwriteX, 6, 0);
+	if (result >= 0)
+		result = WVAL(server->packet, smb_vwv2);
+
+	smb_unlock_server(server);
+	return result;
+}
+
 int
 smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid)
 {
@@ -1380,7 +1624,9 @@
 	struct smb_fattr fattr;
 
 	/* first get current attribute */
-	result = smb_proc_do_getattr(server, dentry, &fattr);
+	smb_init_dirent(server, &fattr);
+	result = server->ops->getattr(server, dentry, &fattr);
+	smb_finish_dirent(server, &fattr);
 	if (result < 0)
 		return result;
 
@@ -1455,38 +1701,72 @@
 	return smb_request_ok(server, SMBflush, 0, 0);
 }
 
-int
-smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length)
+static int
+smb_proc_trunc32(struct inode *inode, loff_t length)
 {
-	char *p;
+	/*
+	 * Writing 0bytes is old-SMB magic for truncating files.
+	 * MAX_NON_LFS should prevent this from being called with a too
+	 * large offset.
+	 */
+	return smb_proc_write(inode, length, 0, NULL);
+}
+
+static int
+smb_proc_trunc64(struct inode *inode, loff_t length)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int command;
 	int result;
+	char *param = server->temp_buf;
+	char data[8];
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
 
 	smb_lock_server(server);
-
+	command = TRANSACT2_SETFILEINFO;
+ 
+	/* FIXME: must we also set allocation size? winNT seems to do that */
 retry:
-	p = smb_setup_header(server, SMBwrite, 5, 3);
-	WSET(server->packet, smb_vwv0, fid);
-	WSET(server->packet, smb_vwv1, 0);
-	DSET(server->packet, smb_vwv2, length);
-	WSET(server->packet, smb_vwv4, 0);
-	*p++ = 1;
-	WSET(p, 0, 0);
-
-	if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) {
+	WSET(param, 0, SMB_I(inode)->fileid);
+	WSET(param, 2, SMB_SET_FILE_END_OF_FILE_INFO);
+	WSET(param, 4, 0);
+	LSET(data, 0, length);
+	result = smb_trans2_request(server, command,
+				    8, data, 6, param,
+				    &resp_data_len, &resp_data,
+				    &resp_param_len, &resp_param);
+	if (result < 0) {
 		if (smb_retry(server))
 			goto retry;
 		goto out;
 	}
+	result = 0;
+	if (server->rcls != 0)
+		result = smb_errno(server);
+
+out:
+	smb_unlock_server(server);
+	return result;
+}
 
+static int
+smb_proc_trunc95(struct inode *inode, loff_t length)
+{
+	struct smb_sb_info *server = server_from_inode(inode);
+	int result = smb_proc_trunc32(inode, length);
+ 
 	/*
 	 * win9x doesn't appear to update the size immediately.
 	 * It will return the old file size after the truncate,
-	 * confusing smbfs.
-	 * NT and Samba return the new value immediately.
+	 * confusing smbfs. So we force an update.
+	 *
+	 * FIXME: is this still necessary?
 	 */
-	if (server->mnt->flags & SMB_MOUNT_WIN95)
-		smb_proc_flush(server, fid);
-out:
+	smb_lock_server(server);
+	smb_proc_flush(server, SMB_I(inode)->fileid);
 	smb_unlock_server(server);
 	return result;
 }
@@ -1567,7 +1847,6 @@
 	 */
 	while (len > 2 && qname->name[len-1] == ' ')
 		len--;
-	qname->len = len;
 
 	smb_finish_dirent(server, fattr);
 
@@ -1586,12 +1865,16 @@
 	}
 #endif
 
-	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     qname->name, len,
-				     server->remote_nls, server->local_nls);
-	qname->name = server->name_buf;
+	qname->len = 0;
+	len = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
+				   qname->name, len,
+				   server->remote_nls, server->local_nls);
+	if (len > 0) {
+		qname->len = len;
+		qname->name = server->name_buf;
+		DEBUG1("len=%d, name=%.*s\n",qname->len,qname->len,qname->name);
+	}
 
-	DEBUG1("len=%d, name=%.*s\n", qname->len, qname->len, qname->name);
 	return p + 22;
 }
 
@@ -1707,6 +1990,8 @@
 		for (i = 0; i < count; i++) {
 			p = smb_decode_short_dirent(server, p, 
 						    &qname, &fattr);
+			if (qname.len == 0)
+				continue;
 
 			if (entries_seen == 2 && qname.name[0] == '.') {
 				if (qname.len == 1)
@@ -1744,7 +2029,9 @@
 {
 	char *result;
 	unsigned int len = 0;
+	int n;
 	__u16 date, time;
+	int unicode = (server->mnt->flags & SMB_MOUNT_UNICODE);
 
 	/*
 	 * SMB doesn't have a concept of inode numbers ...
@@ -1780,16 +2067,16 @@
 		result = p + WVAL(p, 0);
 		len = DVAL(p, 60);
 		if (len > 255) len = 255;
-		/* NT4 null terminates */
+		/* NT4 null terminates, unless we are using unicode ... */
 		qname->name = p + 94;
-		if (len && qname->name[len-1] == '\0')
+		if (!unicode && len && qname->name[len-1] == '\0')
 			len--;
 
 		fattr->f_ctime = smb_ntutc2unixutc(LVAL(p, 8));
 		fattr->f_atime = smb_ntutc2unixutc(LVAL(p, 16));
 		fattr->f_mtime = smb_ntutc2unixutc(LVAL(p, 24));
 		/* change time (32) */
-		fattr->f_size = DVAL(p, 40);
+		fattr->f_size = LVAL(p, 40);
 		/* alloc size (48) */
 		fattr->attr = DVAL(p, 56);
 
@@ -1819,10 +2106,14 @@
 	}
 #endif
 
-	qname->len = server->convert(server->name_buf, SMB_MAXNAMELEN,
-				     qname->name, len,
-				     server->remote_nls, server->local_nls);
-	qname->name = server->name_buf;
+	qname->len = 0;
+	n = server->ops->convert(server->name_buf, SMB_MAXNAMELEN,
+				 qname->name, len,
+				 server->remote_nls, server->local_nls);
+	if (n > 0) {
+		qname->len = n;
+		qname->name = server->name_buf;
+	}
 
 out:
 	return result;
@@ -1888,7 +2179,7 @@
 	 */
 	mask = param + 12;
 
-	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dir, &star);
+	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dir, &star);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto unlock_return;
@@ -2063,18 +2354,6 @@
 	return result;
 }
 
-int
-smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir,
-		 struct smb_cache_control *ctl)
-{
-	struct smb_sb_info *server = server_from_dentry(filp->f_dentry);
-
-	if (server->opt.protocol >= SMB_PROTOCOL_LANMAN2)
-		return smb_proc_readdir_long(filp, dirent, filldir, ctl);
-	else
-		return smb_proc_readdir_short(filp, dirent, filldir, ctl);
-}
-
 /*
  * This version uses the trans2 TRANSACT2_FINDFIRST message 
  * to get the attribute data.
@@ -2095,7 +2374,7 @@
 	int mask_len, result;
 
 retry:
-	mask_len = smb_encode_path(server, mask, SMB_MAXNAMELEN+1, dentry, NULL);
+	mask_len = smb_encode_path(server, mask, SMB_MAXPATHLEN+1, dentry,NULL);
 	if (mask_len < 0) {
 		result = mask_len;
 		goto out;
@@ -2207,29 +2486,25 @@
  */
 static int
 smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir,
-			struct smb_fattr *attr)
+			int *lrdata, unsigned char **rdata,
+			int *lrparam, unsigned char **rparam,
+			int infolevel)
 {
 	char *p, *param = server->temp_buf;
-	__u16 date, time;
-	int off_date = 0, off_time = 2;
-	unsigned char *resp_data = NULL;
-	unsigned char *resp_param = NULL;
-	int resp_data_len = 0;
-	int resp_param_len = 0;
 	int result;
 
-      retry:
-	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
+retry:
+	WSET(param, 0, infolevel);
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;
 
 	result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
 				    0, NULL, p - param, param,
-				    &resp_data_len, &resp_data,
-				    &resp_param_len, &resp_param);
+				    lrdata, rdata,
+				    lrparam, rparam);
 	if (result < 0)
 	{
 		if (smb_retry(server))
@@ -2244,13 +2519,36 @@
 		goto out;
 	}
 	result = -ENOENT;
-	if (resp_data_len < 22)
+	if (*lrdata < 22)
 	{
 		PARANOIA("not enough data for %s, len=%d\n",
-			 &param[6], resp_data_len);
+			 &param[6], *lrdata);
 		goto out;
 	}
 
+	result = 0;
+out:
+	return result;
+}
+
+static int
+smb_proc_getattr_trans2_std(struct smb_sb_info *server, struct dentry *dir,
+			    struct smb_fattr *attr)
+{
+	u16 date, time;
+	int off_date = 0, off_time = 2;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+
+	int result = smb_proc_getattr_trans2(server, dir,
+					     &resp_data_len, &resp_data,
+					     &resp_param_len, &resp_param,
+					     SMB_INFO_STANDARD);
+	if (result < 0)
+		goto out;
+
 	/*
 	 * Kludge alert: Win 95 swaps the date and time field,
 	 * contrary to the CIFS docs and Win NT practice.
@@ -2276,37 +2574,51 @@
 #endif
 	attr->f_size = DVAL(resp_data, 12);
 	attr->attr = WVAL(resp_data, 20);
-	result = 0;
 
 out:
 	return result;
 }
 
-/*
- * Note: called with the server locked
- */
 static int
-smb_proc_do_getattr(struct smb_sb_info *server, struct dentry *dir,
-		    struct smb_fattr *fattr)
+smb_proc_getattr_trans2_all(struct smb_sb_info *server, struct dentry *dir,
+			    struct smb_fattr *attr)
 {
-	int result;
-	struct inode *inode = dir->d_inode;
+	unsigned char *resp_data = NULL;
+	unsigned char *resp_param = NULL;
+	int resp_data_len = 0;
+	int resp_param_len = 0;
+ 
+	int result = smb_proc_getattr_trans2(server, dir,
+					     &resp_data_len, &resp_data,
+					     &resp_param_len, &resp_param,
+					     SMB_QUERY_FILE_ALL_INFO);
+	if (result < 0)
+		goto out;
+ 
+	attr->f_ctime = smb_ntutc2unixutc(LVAL(resp_data, 0));
+	attr->f_atime = smb_ntutc2unixutc(LVAL(resp_data, 8));
+	attr->f_mtime = smb_ntutc2unixutc(LVAL(resp_data, 16));
+	/* change (24) */
+	attr->attr = WVAL(resp_data, 32);
+	/* pad? (34) */
+	/* allocated size (40) */
+	attr->f_size = LVAL(resp_data, 48);
 
-	smb_init_dirent(server, fattr);
+out:
+	return result;
+}
 
-	/*
-	 * Select whether to use core or trans2 getattr.
-	 * Win 95 appears to break with the trans2 getattr.
- 	 */
-	if (server->opt.protocol < SMB_PROTOCOL_LANMAN2 ||
-	    (server->mnt->flags & (SMB_MOUNT_OLDATTR|SMB_MOUNT_WIN95)) ) {
-		result = smb_proc_getattr_core(server, dir, fattr);
-	} else {
-		if (server->mnt->flags & SMB_MOUNT_DIRATTR)
-			result = smb_proc_getattr_ff(server, dir, fattr);
-		else
-			result = smb_proc_getattr_trans2(server, dir, fattr);
-	}
+static int
+smb_proc_getattr_95(struct smb_sb_info *server, struct dentry *dir,
+		    struct smb_fattr *attr)
+{
+	struct inode *inode = dir->d_inode;
+	int result;
+
+	/* FIXME: why not use the "all" version? */
+	result = smb_proc_getattr_trans2_std(server, dir, attr);
+	if (result < 0)
+		goto out;
 
 	/*
 	 * None of the getattr versions here can make win9x return the right
@@ -2314,16 +2626,14 @@
 	 * A seek-to-end does return the right size, but we only need to do
 	 * that on files we have written.
 	 */
-	if (server->mnt->flags & SMB_MOUNT_WIN95 &&
-	    inode &&
-	    SMB_I(inode)->flags & SMB_F_LOCALWRITE &&
+	if (inode && SMB_I(inode)->flags & SMB_F_LOCALWRITE &&
 	    smb_is_open(inode))
 	{
 		__u16 fileid = SMB_I(inode)->fileid;
-		fattr->f_size = smb_proc_seek(server, fileid, 2, 0);
+		attr->f_size = smb_proc_seek(server, fileid, 2, 0);
 	}
 
-	smb_finish_dirent(server, fattr);
+out:
 	return result;
 }
 
@@ -2334,7 +2644,11 @@
 	int result;
 
 	smb_lock_server(server);
-	result = smb_proc_do_getattr(server, dir, fattr);
+
+	smb_init_dirent(server, fattr);
+	result = server->ops->getattr(server, dir, fattr);
+	smb_finish_dirent(server, fattr);
+
 	smb_unlock_server(server);
 	return result;
 }
@@ -2471,7 +2785,7 @@
       retry:
 	WSET(param, 0, 1);	/* Info level SMB_INFO_STANDARD */
 	DSET(param, 2, 0);
-	result = smb_encode_path(server, param+6, SMB_MAXNAMELEN+1, dir, NULL);
+	result = smb_encode_path(server, param+6, SMB_MAXPATHLEN+1, dir, NULL);
 	if (result < 0)
 		goto out;
 	p = param + 6 + result;
@@ -2596,3 +2910,50 @@
 	smb_unlock_server(server);
 	return result;
 }
+
+
+static void
+install_ops(struct smb_ops *dst, struct smb_ops *src)
+{
+	memcpy(dst, src, sizeof(void *) * SMB_OPS_NUM_STATIC);
+}
+
+/* < LANMAN2 */
+static struct smb_ops smb_ops_core =
+{
+	read:		smb_proc_read,
+	write:		smb_proc_write,
+	readdir:	smb_proc_readdir_short,
+	getattr:	smb_proc_getattr_core,
+	truncate:	smb_proc_trunc32,
+};
+
+/* LANMAN2, OS/2, others? */
+static struct smb_ops smb_ops_os2 =
+{
+	read:		smb_proc_read,
+	write:		smb_proc_write,
+	readdir:	smb_proc_readdir_long,
+	getattr:	smb_proc_getattr_trans2_std,
+	truncate:	smb_proc_trunc32,
+};
+
+/* Win95, and possibly some NetApp versions too */
+static struct smb_ops smb_ops_win95 =
+{
+	read:		smb_proc_read,	/* does not support 12word readX */
+	write:		smb_proc_write,
+	readdir:	smb_proc_readdir_long,
+	getattr:	smb_proc_getattr_95,
+	truncate:	smb_proc_trunc95,
+};
+
+/* Samba, NT4 and NT5 */
+static struct smb_ops smb_ops_winNT =
+{
+	read:		smb_proc_readX,
+	write:		smb_proc_writeX,
+	readdir:	smb_proc_readdir_long,
+	getattr:	smb_proc_getattr_trans2_all,
+	truncate:	smb_proc_trunc64,
+};
diff -urN linux-2.5.6-pre3/fs/smbfs/proto.h linux-2.5.6/fs/smbfs/proto.h
--- linux-2.5.6-pre3/fs/smbfs/proto.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/fs/smbfs/proto.h	Thu Mar  7 18:24:55 2002
@@ -1,5 +1,5 @@
 /*
- *  Autogenerated with cproto on:  Tue Oct 2 20:40:54 CEST 2001
+ *  Autogenerated with cproto on:  Thu Nov 22 21:18:04 CET 2001
  */
 
 /* proc.c */
@@ -14,17 +14,13 @@
 extern int smb_open(struct dentry *dentry, int wish);
 extern int smb_close(struct inode *ino);
 extern int smb_close_fileid(struct dentry *dentry, __u16 fileid);
-extern int smb_proc_read(struct inode *inode, off_t offset, int count, char *data);
-extern int smb_proc_write(struct inode *inode, off_t offset, int count, const char *data);
 extern int smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid);
 extern int smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry);
 extern int smb_proc_mkdir(struct dentry *dentry);
 extern int smb_proc_rmdir(struct dentry *dentry);
 extern int smb_proc_unlink(struct dentry *dentry);
 extern int smb_proc_flush(struct smb_sb_info *server, __u16 fileid);
-extern int smb_proc_trunc(struct smb_sb_info *server, __u16 fid, __u32 length);
 extern void smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr);
-extern int smb_proc_readdir(struct file *filp, void *dirent, filldir_t filldir, struct smb_cache_control *ctl);
 extern int smb_proc_getattr(struct dentry *dir, struct smb_fattr *fattr);
 extern int smb_proc_setattr(struct dentry *dir, struct smb_fattr *fattr);
 extern int smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr);
diff -urN linux-2.5.6-pre3/include/asm-alpha/jensen.h linux-2.5.6/include/asm-alpha/jensen.h
--- linux-2.5.6-pre3/include/asm-alpha/jensen.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/include/asm-alpha/jensen.h	Thu Mar  7 18:24:55 2002
@@ -7,9 +7,6 @@
  * Defines for the AlphaPC EISA IO and memory address space.
  */
 
-/* The Jensen is strange */
-#define AUX_IRQ (9)
-
 /*
  * NOTE! The memory operations do not set any memory barriers, as it's
  * not needed for cases like a frame buffer that is essentially memory-like.
diff -urN linux-2.5.6-pre3/include/asm-alpha/keyboard.h linux-2.5.6/include/asm-alpha/keyboard.h
--- linux-2.5.6-pre3/include/asm-alpha/keyboard.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/include/asm-alpha/keyboard.h	Thu Mar  7 18:24:55 2002
@@ -60,7 +60,8 @@
  * Machine specific bits for the PS/2 driver
  */
 
-#define AUX_IRQ 12
+/* Jensen puts this at 9, everyone else at the standard 12.  */
+#define AUX_IRQ  (RTC_PORT(0) == 0x170 ? 9 : 12)
 
 #define aux_request_irq(hand, dev_id)                                  \
        request_irq(AUX_IRQ, hand, SA_SHIRQ, "PS/2 Mouse", dev_id)
diff -urN linux-2.5.6-pre3/include/asm-alpha/pgalloc.h linux-2.5.6/include/asm-alpha/pgalloc.h
--- linux-2.5.6-pre3/include/asm-alpha/pgalloc.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/include/asm-alpha/pgalloc.h	Thu Mar  7 18:24:55 2002
@@ -230,121 +230,66 @@
  * used to allocate a kernel page table - this turns on ASN bits
  * if any.
  */
-#ifndef CONFIG_SMP
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pmd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
-#else
-#include <asm/smp.h>
-#define quicklists cpu_data[smp_processor_id()]
-#endif
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pmd_quicklist (quicklists.pmd_cache)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-
-#define pmd_populate(mm, pmd, pte)	pmd_set(pmd, pte)
-#define pgd_populate(mm, pgd, pmd)	pgd_set(pgd, pmd)
-
-extern pgd_t *get_pgd_slow(void);
-
-static 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;
-}
-
-static inline void free_pgd_fast(pgd_t *pgd)
-{
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
-}
 
-static inline void free_pgd_slow(pgd_t *pgd)
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *pte)
 {
-	free_page((unsigned long)pgd);
+	pmd_set(pmd, (pte_t *)((pte - mem_map) << PAGE_SHIFT));
 }
 
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
-	if (ret)
-		clear_page(ret);
-	return ret;
+	pmd_set(pmd, pte);
 }
 
-static inline pmd_t *pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline void
+pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 {
-	unsigned long *ret;
-
-	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-	}
-	return (pmd_t *)ret;
+	pgd_set(pgd, pmd);
 }
 
-static inline void pmd_free_fast(pmd_t *pmd)
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+
+static inline void
+pgd_free(pgd_t *pgd)
 {
-	*(unsigned long *)pmd = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pmd;
-	pgtable_cache_size++;
+	free_page((unsigned long)pgd);
 }
 
-static inline void pmd_free_slow(pmd_t *pmd)
+static inline pmd_t *
+pmd_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-	free_page((unsigned long)pmd);
+	pmd_t *ret = (pmd_t *)__get_free_page(GFP_KERNEL);
+	if (ret)
+		clear_page(ret);
+	return ret;
 }
 
-static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+static inline void
+pmd_free(pmd_t *pmd)
 {
-	pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL);
-	if (pte)
-		clear_page(pte);
-	return pte;
+	free_page((unsigned long)pmd);
 }
 
-static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
-{
-	unsigned long *ret;
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
 
-	if ((ret = (unsigned long *)pte_quicklist) != NULL) {
-		pte_quicklist = (unsigned long *)(*ret);
-		ret[0] = 0;
-		pgtable_cache_size--;
-	}
-	return (pte_t *)ret;
+static inline void
+pte_free_kernel(pte_t *pte)
+{
+	free_page((unsigned long)pte);
 }
 
-static inline void pte_free_fast(pte_t *pte)
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-	*(unsigned long *)pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
+	return virt_to_page(pte_alloc_one_kernel(mm, addr));
 }
 
-static inline void pte_free_slow(pte_t *pte)
+static inline void
+pte_free(struct page *page)
 {
-	free_page((unsigned long)pte);
+	__free_page(page);
 }
 
-#define pte_free(pte)		pte_free_fast(pte)
-#define pmd_free(pmd)		pmd_free_fast(pmd)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc(mm)		get_pgd_fast()
-
-extern int do_check_pgt_cache(int, int);
-
 #endif /* _ALPHA_PGALLOC_H */
diff -urN linux-2.5.6-pre3/include/asm-alpha/pgtable.h linux-2.5.6/include/asm-alpha/pgtable.h
--- linux-2.5.6-pre3/include/asm-alpha/pgtable.h	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/include/asm-alpha/pgtable.h	Thu Mar  7 18:24:55 2002
@@ -248,8 +248,13 @@
 })
 #endif
 
-extern inline unsigned long pmd_page(pmd_t pmd)
-{ return PAGE_OFFSET + ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
+extern inline unsigned long
+pmd_page_kernel(pmd_t pmd)
+{
+	return ((pmd_val(pmd) & _PFN_MASK) >> (32-PAGE_SHIFT)) + PAGE_OFFSET;
+}
+
+#define pmd_page(pmd)	(mem_map + ((pmd_val(pmd) & _PFN_MASK) >> 32))
 
 extern inline unsigned long pgd_page(pgd_t pgd)
 { return PAGE_OFFSET + ((pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT)); }
@@ -306,11 +311,17 @@
 }
 
 /* Find an entry in the third-level page table.. */
-extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+extern inline pte_t * pte_offset_kernel(pmd_t * dir, unsigned long address)
 {
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1));
+	return (pte_t *) pmd_page_kernel(*dir)
+		+ ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1));
 }
 
+#define pte_offset_map(dir,addr)	pte_offset_kernel((dir),(addr))
+#define pte_offset_map_nested(dir,addr)	pte_offset_kernel((dir),(addr))
+#define pte_unmap(pte)			do { } while (0)
+#define pte_unmap_nested(pte)		do { } while (0)
+
 extern pgd_t swapper_pg_dir[1024];
 
 /*
diff -urN linux-2.5.6-pre3/include/asm-alpha/smp.h linux-2.5.6/include/asm-alpha/smp.h
--- linux-2.5.6-pre3/include/asm-alpha/smp.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/asm-alpha/smp.h	Thu Mar  7 18:24:55 2002
@@ -29,10 +29,6 @@
 	unsigned long last_asn;
 	int need_new_asn;
 	int asn_lock;
-	unsigned long *pgd_cache;
-	unsigned long *pmd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
 	unsigned long ipi_count;
 	unsigned long irq_attempt[NR_IRQS];
 	unsigned long prof_multiplier;
diff -urN linux-2.5.6-pre3/include/asm-alpha/system.h linux-2.5.6/include/asm-alpha/system.h
--- linux-2.5.6-pre3/include/asm-alpha/system.h	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/include/asm-alpha/system.h	Thu Mar  7 18:24:55 2002
@@ -137,6 +137,7 @@
 	check_mmu_context();						  \
 } while (0)
 
+struct task_struct;
 extern void alpha_switch_to(unsigned long, struct task_struct*);
 
 #define mb() \
diff -urN linux-2.5.6-pre3/include/asm-i386/io.h linux-2.5.6/include/asm-i386/io.h
--- linux-2.5.6-pre3/include/asm-i386/io.h	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/include/asm-i386/io.h	Thu Mar  7 18:24:55 2002
@@ -39,7 +39,8 @@
 #define IO_SPACE_LIMIT 0xffff
 
 #define XQUAD_PORTIO_BASE 0xfe400000
-#define XQUAD_PORTIO_LEN  0x40000   /* 256k per quad. Only remapping 1st */
+#define XQUAD_PORTIO_QUAD 0x40000  /* 256k per quad. */
+#define XQUAD_PORTIO_LEN  0x80000  /* Only remapping first 2 quads */
 
 #ifdef __KERNEL__
 
@@ -261,52 +262,65 @@
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
 
 #ifdef CONFIG_MULTIQUAD
-/* Make the default portio routines operate on quad 0 for now */
-#define __OUT(s,s1,x) \
-__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
-__OUTQ0(s,s,x) \
-__OUTQ0(s,s##_p,x) 
-#else
-#define __OUT(s,s1,x) \
-__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
-__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} 
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_MULTIQUAD
-#define __OUTQ0(s,ss,x)    /* Do the equivalent of the portio op on quad 0 */ \
+#define __OUTQ(s,ss,x)    /* Do the equivalent of the portio op on quads */ \
 static inline void out##ss(unsigned x value, unsigned short port) { \
 	if (xquad_portio) \
 		write##s(value, (unsigned long) xquad_portio + port); \
 	else               /* We're still in early boot, running on quad 0 */ \
 		out##ss##_local(value, port); \
-} 
+} \
+static inline void out##ss##_quad(unsigned x value, unsigned short port, int quad) { \
+	if (xquad_portio) \
+		write##s(value, (unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+			+ port); \
+}
 
-#define __INQ0(s,ss)       /* Do the equivalent of the portio op on quad 0 */ \
+#define __INQ(s,ss)       /* Do the equivalent of the portio op on quads */ \
 static inline RETURN_TYPE in##ss(unsigned short port) { \
 	if (xquad_portio) \
 		return read##s((unsigned long) xquad_portio + port); \
 	else               /* We're still in early boot, running on quad 0 */ \
 		return in##ss##_local(port); \
+} \
+static inline RETURN_TYPE in##ss##_quad(unsigned short port, int quad) { \
+	if (xquad_portio) \
+		return read##s((unsigned long) xquad_portio + (XQUAD_PORTIO_QUAD*quad)\
+			+ port); \
+	else\
+		return 0;\
 }
 #endif /* CONFIG_MULTIQUAD */
 
+#ifndef CONFIG_MULTIQUAD
+#define __OUT(s,s1,x) \
+__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} 
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __OUT(s,s1,x) \
+__OUT1(s##_local,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
+__OUT1(s##_p_local,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
+__OUTQ(s,s,x) \
+__OUTQ(s,s##_p,x) 
+#endif /* CONFIG_MULTIQUAD */
+
 #define __IN1(s) \
 static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
 
-#ifdef CONFIG_MULTIQUAD
-#define __IN(s,s1,i...) \
-__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
-__INQ0(s,s) \
-__INQ0(s,s##_p) 
-#else
+#ifndef CONFIG_MULTIQUAD
 #define __IN(s,s1,i...) \
 __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } 
+#else
+/* Make the default portio routines operate on quad 0 */
+#define __IN(s,s1,i...) \
+__IN1(s##_local) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__IN1(s##_p_local) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
+__INQ(s,s) \
+__INQ(s,s##_p) 
 #endif /* CONFIG_MULTIQUAD */
 
 #define __INS(s) \
diff -urN linux-2.5.6-pre3/include/asm-i386/mpspec.h linux-2.5.6/include/asm-i386/mpspec.h
--- linux-2.5.6-pre3/include/asm-i386/mpspec.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/include/asm-i386/mpspec.h	Thu Mar  7 18:24:55 2002
@@ -198,6 +198,9 @@
 	MP_BUS_MCA
 };
 extern int mp_bus_id_to_type [MAX_MP_BUSSES];
+extern int mp_bus_id_to_node [MAX_MP_BUSSES];
+extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
 extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
diff -urN linux-2.5.6-pre3/include/asm-i386/siginfo.h linux-2.5.6/include/asm-i386/siginfo.h
--- linux-2.5.6-pre3/include/asm-i386/siginfo.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/include/asm-i386/siginfo.h	Thu Mar  7 18:24:55 2002
@@ -108,6 +108,7 @@
 #define SI_ASYNCIO	-4		/* sent by AIO completion */
 #define SI_SIGIO	-5		/* sent by queued SIGIO */
 #define SI_TKILL	-6		/* sent by tkill system call */
+#define SI_DETHREAD	-7		/* sent by execve() killing subsidiary threads */
 
 #define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
 #define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
diff -urN linux-2.5.6-pre3/include/asm-x86_64/rwsem.h linux-2.5.6/include/asm-x86_64/rwsem.h
--- linux-2.5.6-pre3/include/asm-x86_64/rwsem.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/include/asm-x86_64/rwsem.h	Thu Mar  7 18:24:55 2002
@@ -157,9 +157,9 @@
 		"  jmp       1b\n"
 		".previous\n"
 		"# ending __up_read\n"
-		: "+m"(sem->count), "+d"(tmp)
+		: "+d"(tmp)
 		: "a"(sem)
-		: "memory", "cc");
+		: "memory");
 }
 
 /*
@@ -169,7 +169,7 @@
 {
 	__asm__ __volatile__(
 		"# beginning __up_write\n\t"
-		"  movl      %2,%%edx\n\t"
+		"  movl      %1,%%edx\n\t"
 LOCK_PREFIX	"  xaddl     %%edx,(%%rax)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
 		"  jnz       2f\n\t" /* jump if the lock is being waited upon */
 		"1:\n\t"
@@ -181,7 +181,7 @@
 		"  jmp       1b\n"
 		".previous\n"
 		"# ending __up_write\n"
-		: "+m"(sem->count)
+		: 
 		: "a"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS)
 		: "memory", "cc", "edx");
 }
diff -urN linux-2.5.6-pre3/include/linux/cramfs_fs.h linux-2.5.6/include/linux/cramfs_fs.h
--- linux-2.5.6-pre3/include/linux/cramfs_fs.h	Tue Feb 19 18:10:58 2002
+++ linux-2.5.6/include/linux/cramfs_fs.h	Thu Mar  7 18:24:55 2002
@@ -24,6 +24,12 @@
 #define CRAMFS_OFFSET_WIDTH 26
 
 /*
+ * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs
+ * path length is 63 << 2 = 252.
+ */
+#define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2)
+
+/*
  * Reasonably terse representation of the inode data.
  */
 struct cramfs_inode {
@@ -52,14 +58,14 @@
  * Superblock information at the beginning of the FS.
  */
 struct cramfs_super {
-	u32 magic;		/* 0x28cd3d45 - random number */
-	u32 size;		/* length in bytes */
-	u32 flags;		/* 0 */
-	u32 future;		/* 0 */
-	u8 signature[16];	/* "Compressed ROMFS" */
+	u32 magic;			/* 0x28cd3d45 - random number */
+	u32 size;			/* length in bytes */
+	u32 flags;			/* feature flags */
+	u32 future;			/* reserved for future use */
+	u8 signature[16];		/* "Compressed ROMFS" */
 	struct cramfs_info fsid;	/* unique filesystem info */
-	u8 name[16];		/* user-defined name */
-	struct cramfs_inode root;	/* Root inode data */
+	u8 name[16];			/* user-defined name */
+	struct cramfs_inode root;	/* root inode data */
 };
 
 /*
@@ -79,7 +85,10 @@
  * if (flags & ~CRAMFS_SUPPORTED_FLAGS).  Maybe that should be
  * changed to test super.future instead.
  */
-#define CRAMFS_SUPPORTED_FLAGS (0x7ff)
+#define CRAMFS_SUPPORTED_FLAGS	( 0x000000ff \
+				| CRAMFS_FLAG_HOLES \
+				| CRAMFS_FLAG_WRONG_SIGNATURE \
+				| CRAMFS_FLAG_SHIFTED_ROOT_OFFSET )
 
 /* Uncompression interfaces to the underlying zlib */
 int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
diff -urN linux-2.5.6-pre3/include/linux/hdlc/ioctl.h linux-2.5.6/include/linux/hdlc/ioctl.h
--- linux-2.5.6-pre3/include/linux/hdlc/ioctl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/include/linux/hdlc/ioctl.h	Thu Mar  7 18:24:55 2002
@@ -0,0 +1,55 @@
+#ifndef __HDLC_IOCTL_H__
+#define __HDLC_IOCTL_H__
+
+typedef struct { 
+	unsigned int clock_rate; /* bits per second */
+	unsigned int clock_type; /* internal, external, TX-internal etc. */
+	unsigned short loopback;
+} sync_serial_settings;          /* V.35, V.24, X.21 */
+
+typedef struct { 
+	unsigned int clock_rate; /* bits per second */
+	unsigned int clock_type; /* internal, external, TX-internal etc. */
+	unsigned short loopback;
+	unsigned int slot_map;
+} te1_settings;                  /* T1, E1 */
+
+typedef struct {
+	unsigned short encoding;
+	unsigned short parity;
+} raw_hdlc_proto;
+
+typedef struct {
+	unsigned int t391;
+	unsigned int t392;
+	unsigned int n391;
+	unsigned int n392;
+	unsigned int n393;
+	unsigned short lmi;
+	unsigned short dce; /* 1 for DCE (network side) operation */
+} fr_proto;
+
+typedef struct {
+	unsigned int dlci;
+} fr_proto_pvc;          /* for creating/deleting FR PVCs */
+
+typedef struct {
+    unsigned int interval;
+    unsigned int timeout;
+} cisco_proto;
+
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
+
+union hdlc_settings {
+	raw_hdlc_proto		raw_hdlc;
+	cisco_proto		cisco;
+	fr_proto		fr;
+	fr_proto_pvc		fr_pvc;
+};
+
+union line_settings {
+	sync_serial_settings	sync;
+	te1_settings		te1;
+};
+
+#endif /* __HDLC_IOCTL_H__ */
diff -urN linux-2.5.6-pre3/include/linux/hdlc.h linux-2.5.6/include/linux/hdlc.h
--- linux-2.5.6-pre3/include/linux/hdlc.h	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/include/linux/hdlc.h	Thu Mar  7 18:24:55 2002
@@ -1,7 +1,7 @@
 /*
  * Generic HDLC support routines for Linux
  *
- * Copyright (C) 1999, 2000 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -12,64 +12,49 @@
 #ifndef __HDLC_H
 #define __HDLC_H
 
-/* Ioctls - to be changed */
-#define HDLCGSLOTMAP	(0x89F4) /* E1/T1 slot bitmap */
-#define HDLCGCLOCK	(0x89F5) /* clock sources */
-#define HDLCGCLOCKRATE	(0x89F6) /* clock rate */
-#define HDLCGMODE	(0x89F7) /* internal to hdlc.c - protocol used */
-#define HDLCGLINE	(0x89F8) /* physical interface */
-#define HDLCSSLOTMAP	(0x89F9)
-#define HDLCSCLOCK	(0x89FA)
-#define HDLCSCLOCKRATE	(0x89FB)
-#define HDLCSMODE	(0x89FC) /* internal to hdlc.c - select protocol */
-#define HDLCPVC		(0x89FD) /* internal to hdlc.c - create/delete PVC */
-#define HDLCSLINE	(0x89FE)
-#define HDLCRUN		(0x89FF) /* Download firmware and run board */
-
-/* Modes */
-#define MODE_NONE	0x00000000 /* Not initialized */
-#define MODE_DCE	0x00000080 /* DCE */
-#define MODE_HDLC	0x00000100 /* Raw HDLC frames */
-#define MODE_CISCO	0x00000200
-#define MODE_PPP	0x00000400
-#define MODE_FR		0x00000800 /* Any LMI */
-#define MODE_FR_ANSI	0x00000801
-#define MODE_FR_CCITT	0x00000802
-#define MODE_X25	0x00001000
-#define MODE_MASK	0x0000FF00
-#define MODE_SOFT	0x80000000 /* Driver modes, using hardware HDLC */
-
-/* Lines */
-#define LINE_DEFAULT	0x00000000
-#define LINE_V35	0x00000001
-#define LINE_RS232	0x00000002
-#define LINE_X21	0x00000003
-#define LINE_T1		0x00000004
-#define LINE_E1		0x00000005
-#define LINE_MASK	0x000000FF
-#define LINE_LOOPBACK	0x80000000 /* On-card loopback */
-
-#define CLOCK_EXT	0	/* External TX and RX clock - DTE */
-#define CLOCK_INT	1	/* Internal TX and RX clock - DCE */
-#define CLOCK_TXINT	2	/* Internal TX and external RX clock */
-#define CLOCK_TXFROMRX	3	/* TX clock derived from external RX clock */
+#define CLOCK_DEFAULT   0	/* Default (current) setting */
+#define CLOCK_EXT	1	/* External TX and RX clock - DTE */
+#define CLOCK_INT	2	/* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT	3	/* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX	4	/* TX clock derived from external RX clock */
+
+
+#define ENCODING_DEFAULT	0 /* Default (current) setting */
+#define ENCODING_NRZ		1
+#define ENCODING_NRZI		2
+#define ENCODING_FM_MARK	3
+#define ENCODING_FM_SPACE	4
+#define ENCODING_MANCHESTER	5
+
+
+#define PARITY_DEFAULT		0 /* Default (current) setting */
+#define PARITY_NONE		1 /* No parity */
+#define PARITY_CRC16_PR0	2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1	3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT	4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT	5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT	6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT	7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT		0 /* Default (current) setting */
+#define LMI_NONE		1 /* No LMI, all PVCs are static */
+#define LMI_ANSI		2 /* ANSI Annex D */
+#define LMI_CCITT		3 /* ITU-T Annex A */
 
+/* PPP doesn't need any info now - supply length = 0 to ioctl */
 
-#define HDLC_MAX_MTU 1500	/* Ethernet 1500 bytes */
-#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
 
 #ifdef __KERNEL__
 
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <net/syncppp.h>
+#include <linux/hdlc/ioctl.h>
 
-#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
+#define HDLC_MAX_MTU 1500	/* Ethernet 1500 bytes */
+#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10) /* max 10 bytes for FR */
 
-#define LINK_STATE_RELIABLE 0x01
-#define LINK_STATE_REQUEST  0x02 /* full stat sent (DCE) / req pending (DTE) */
-#define LINK_STATE_CHANGED  0x04 /* change in PVCs state, send full report */
-#define LINK_STATE_FULLREP_SENT 0x08 /* full report sent */
+#define MAXLEN_LMISTAT  20	/* max size of status enquiry frame */
 
 #define PVC_STATE_NEW       0x01
 #define PVC_STATE_ACTIVE    0x02
@@ -112,6 +97,7 @@
 
 
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned ea1  : 1;
 	unsigned cr   : 1;
 	unsigned dlcih: 6;
@@ -121,6 +107,19 @@
 	unsigned becn : 1;
 	unsigned fecn : 1;
 	unsigned dlcil: 4;
+#elif defined (__BIG_ENDIAN_BITFIELD)
+	unsigned dlcih: 6;
+	unsigned cr   : 1;
+	unsigned ea1  : 1;
+  
+	unsigned dlcil: 4;
+	unsigned fecn : 1;
+	unsigned becn : 1;
+	unsigned de   : 1;
+	unsigned ea2  : 1;
+#else
+#error  "Please fix <asm/byteorder.h>"
+#endif
 }__attribute__ ((packed)) fr_hdr;
 
 
@@ -151,63 +150,96 @@
 	struct hdlc_device_struct *master;
 	struct pvc_device_struct *next;
 
-	u8 state;
-	u8 newstate;
+	struct {
+		int active;
+		int new;
+		int deleted;
+		int fecn;
+		int becn;
+	}state;
 }pvc_device;
 
 
 
-typedef struct {
-	u32 last_errors;	/* last errors bit list */
-	int last_poll;		/* ! */
-	u8 T391;		/* ! link integrity verification polling timer */
-	u8 T392;		/* ! polling verification timer */
-	u8 N391;		/* full status polling counter */
-	u8 N392;		/* error threshold */
-	u8 N393;		/* monitored events count */
-	u8 N391cnt;
-
-	u8 state;		/* ! */
-	u32 txseq;		/* ! TX sequence number - Cisco uses 4 bytes */
-	u32 rxseq;		/* ! RX sequence number */
-}fr_lmi;			/* ! means used in Cisco HDLC as well */
-
-
 typedef struct hdlc_device_struct {
-	/* to be initialized by hardware driver: */
+	/* To be initialized by hardware driver */
 	struct net_device netdev; /* master net device - must be first */
 	struct net_device_stats stats;
 
-	struct ppp_device pppdev;
-	struct ppp_device *syncppp_ptr;
+	/* used by HDLC layer to take control over HDLC device from hw driver*/
+	int (*attach)(struct hdlc_device_struct *hdlc,
+		      unsigned short encoding, unsigned short parity);
 
-	/* set_mode may be NULL if HDLC-only board */
-	int (*set_mode)(struct hdlc_device_struct *hdlc, int mode);
-	int (*open)(struct hdlc_device_struct *hdlc);
-	void (*close)(struct hdlc_device_struct *hdlc);
-	int (*xmit)(struct hdlc_device_struct *hdlc, struct sk_buff *skb);
-	int (*ioctl)(struct hdlc_device_struct *hdlc, struct ifreq *ifr,
-		     int cmd);
-  
-	/* Only in "hardware" FR modes etc. - may be NULL */
-	int (*create_pvc)(pvc_device *pvc);
-	void (*destroy_pvc)(pvc_device *pvc);
-	int (*open_pvc)(pvc_device *pvc);
-	void (*close_pvc)(pvc_device *pvc);
-
-	/* for hdlc.c internal use only */
-	pvc_device *first_pvc;
-	u16 pvc_count;
-	int mode;
+	/* hardware driver must handle this instead of dev->hard_start_xmit */
+	int (*xmit)(struct sk_buff *skb, struct net_device *dev);
 
-	struct timer_list timer;
-	fr_lmi lmi;
+
+	/* Things below are for HDLC layer internal use only */
+	int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
+	int (*open)(struct hdlc_device_struct *hdlc);
+	void (*stop)(struct hdlc_device_struct *hdlc);
+	void (*detach)(struct hdlc_device_struct *hdlc);
+	void (*netif_rx)(struct sk_buff *skb);
+	int proto;		/* IF_PROTO_HDLC/CISCO/FR/etc. */
+
+	union {
+		struct {
+			fr_proto settings;
+			pvc_device *first_pvc;
+			int pvc_count;
+
+			struct timer_list timer;
+			int last_poll;
+			int reliable;
+			int changed;
+			int request;
+			int fullrep_sent;
+			u32 last_errors; /* last errors bit list */
+			u8 n391cnt;
+			u8 txseq; /* TX sequence number */
+			u8 rxseq; /* RX sequence number */
+		}fr;
+
+		struct {
+			cisco_proto settings;
+
+			struct timer_list timer;
+			int last_poll;
+			int up;
+			u32 txseq; /* TX sequence number */
+			u32 rxseq; /* RX sequence number */
+		}cisco;
+
+		struct {
+			raw_hdlc_proto settings;
+		}raw_hdlc;
+
+		struct {
+			struct ppp_device pppdev;
+			struct ppp_device *syncppp_ptr;
+			int (*old_change_mtu)(struct net_device *dev,
+					      int new_mtu);
+		}ppp;
+	}state;
 }hdlc_device;
 
 
+
+int hdlc_raw_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_cisco_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_ppp_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+int hdlc_x25_ioctl(hdlc_device *hdlc, struct ifreq *ifr);
+
+
+/* Exported from hdlc.o */
+
+/* Called by hardware driver when a user requests HDLC service */
+int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+
+/* Must be used by hardware driver on module startup/exit */
 int register_hdlc_device(hdlc_device *hdlc);
 void unregister_hdlc_device(hdlc_device *hdlc);
-void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
 
 
 static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
@@ -246,33 +278,6 @@
 }
 
 
-static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
-{
-	*state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
-	if (status[2] & 0x08)
-		*state |= PVC_STATE_NEW;
-	else if (status[2] & 0x02)
-		*state |= PVC_STATE_ACTIVE;
-
-	return ((status[0] & 0x3F)<<4) | ((status[1] & 0x78)>>3);
-}
-
-
-static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
-				      u8 state)
-{
-	status[0] = (dlci>>4) & 0x3F;
-	status[1] = ((dlci<<3) & 0x78) | 0x80;
-	status[2] = 0x80;
-
-	if (state & PVC_STATE_NEW)
-		status[2] |= 0x08;
-	else if (state & PVC_STATE_ACTIVE)
-		status[2] |= 0x02;
-}
-
-
-
 static __inline__ u16 netdev_dlci(struct net_device *dev)
 {
 	return ntohs(*(u16*)dev->dev_addr);
@@ -282,37 +287,15 @@
 
 static __inline__ u16 q922_to_dlci(u8 *hdr)
 {
-	return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
+	return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
 }
 
 
 
 static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
 {
-	hdr[0] = (dlci>>2) & 0xFC;
-	hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
-}
-
-
-
-static __inline__ int mode_is(hdlc_device *hdlc, int mask)
-{
-	return (hdlc->mode & mask) == mask;
-}
-
-
-
-static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
-{
-	pvc_device *pvc=hdlc->first_pvc;
-	
-	while (pvc) {
-		if (netdev_dlci(&pvc->netdev) == dlci)
-			return pvc;
-		pvc=pvc->next;
-	}
-
-	return NULL;
+	hdr[0] = (dlci >> 2) & 0xFC;
+	hdr[1] = ((dlci << 4) & 0xF0) | 0x01;
 }
 
 
@@ -332,5 +315,35 @@
 }
 
 
+
+/* Must be called by hardware driver when HDLC device is being opened */
+static __inline__ int hdlc_open(hdlc_device *hdlc)
+{
+	if (hdlc->proto == -1)
+		return -ENOSYS;		/* no protocol attached */
+
+	if (hdlc->open)
+		return hdlc->open(hdlc);
+	return 0;
+}
+
+
+/* Must be called by hardware driver when HDLC device is being closed */
+static __inline__ void hdlc_close(hdlc_device *hdlc)
+{
+	if (hdlc->stop)
+		hdlc->stop(hdlc);
+}
+
+
+/* May be used by hardware driver to gain control over HDLC device */
+static __inline__ void hdlc_detach(hdlc_device *hdlc)
+{
+	if (hdlc->detach)
+		hdlc->detach(hdlc);
+	hdlc->detach = NULL;
+}
+
+
 #endif /* __KERNEL */
 #endif /* __HDLC_H */
diff -urN linux-2.5.6-pre3/include/linux/if.h linux-2.5.6/include/linux/if.h
--- linux-2.5.6-pre3/include/linux/if.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/include/linux/if.h	Thu Mar  7 18:24:55 2002
@@ -21,6 +21,7 @@
 
 #include <linux/types.h>		/* for "__kernel_caddr_t" et al	*/
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
+#include <linux/hdlc/ioctl.h>
 
 /* Standard interface flags (netdevice->flags). */
 #define	IFF_UP		0x1		/* interface is up		*/
@@ -48,6 +49,29 @@
 /* Private (from user) interface flags (netdevice->priv_flags). */
 #define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
 
+
+#define IF_GET_IFACE	0x0001		/* for querying only */
+#define IF_GET_PROTO	0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35	0x1000		/* V.35 serial interface	*/
+#define IF_IFACE_V24	0x1001		/* V.24 serial interface	*/
+#define IF_IFACE_X21	0x1002		/* X.21 serial interface	*/
+#define IF_IFACE_T1	0x1003		/* T1 telco serial interface	*/
+#define IF_IFACE_E1	0x1004		/* E1 telco serial interface	*/
+#define IF_IFACE_SYNC_SERIAL 0x1005	/* cant'b be set by software	*/
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC	0x2000		/* raw HDLC protocol		*/
+#define IF_PROTO_PPP	0x2001		/* PPP protocol			*/
+#define IF_PROTO_CISCO	0x2002		/* Cisco HDLC protocol		*/
+#define IF_PROTO_FR	0x2003		/* Frame Relay protocol		*/
+#define IF_PROTO_FR_ADD_PVC 0x2004	/*    Create FR PVC		*/
+#define IF_PROTO_FR_DEL_PVC 0x2005	/*    Delete FR PVC		*/
+#define IF_PROTO_X25	0x2006		/* X.25				*/
+
+
+
 /*
  *	Device mapping structure. I'd just gone off and designed a 
  *	beautiful scheme using only loadable modules with arguments
@@ -69,6 +93,19 @@
 	/* 3 bytes spare */
 };
 
+struct if_settings
+{
+	unsigned int type;	/* Type of physical device or protocol */
+	union {
+		/* {atm/eth/dsl}_settings anyone ? */
+		union hdlc_settings ifsu_hdlc;
+		union line_settings ifsu_line;
+	} ifs_ifsu;
+};
+
+#define ifs_hdlc	ifs_ifsu.ifsu_hdlc
+#define ifs_line	ifs_ifsu.ifsu_line
+
 /*
  * Interface request structure used for socket
  * ioctl's.  All interface ioctl's must have parameter
@@ -98,6 +135,7 @@
 		char	ifru_slave[IFNAMSIZ];	/* Just fits the size */
 		char	ifru_newname[IFNAMSIZ];
 		char *	ifru_data;
+		struct	if_settings *ifru_settings;
 	} ifr_ifru;
 };
 
@@ -117,6 +155,7 @@
 #define ifr_bandwidth	ifr_ifru.ifru_ivalue    /* link bandwidth	*/
 #define ifr_qlen	ifr_ifru.ifru_ivalue	/* Queue length 	*/
 #define ifr_newname	ifr_ifru.ifru_newname	/* New name		*/
+#define ifr_settings	ifr_ifru.ifru_settings	/* Device/proto settings*/
 
 /*
  * Structure used in SIOCGIFCONF request.
diff -urN linux-2.5.6-pre3/include/linux/if_ether.h linux-2.5.6/include/linux/if_ether.h
--- linux-2.5.6-pre3/include/linux/if_ether.h	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/include/linux/if_ether.h	Thu Mar  7 18:24:55 2002
@@ -85,6 +85,7 @@
 #define ETH_P_CONTROL	0x0016		/* Card specific control frames */
 #define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
 #define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
+#define ETH_P_HDLC	0x0019		/* HDLC frames			*/
 
 /*
  *	This is an Ethernet frame header.
diff -urN linux-2.5.6-pre3/include/linux/pci.h linux-2.5.6/include/linux/pci.h
--- linux-2.5.6-pre3/include/linux/pci.h	Thu Mar  7 18:24:37 2002
+++ linux-2.5.6/include/linux/pci.h	Thu Mar  7 18:24:55 2002
@@ -564,6 +564,10 @@
 int pci_enable_device(struct pci_dev *dev);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
+#define HAVE_PCI_SET_MWI
+int pci_set_mwi(struct pci_dev *dev);
+void pci_clear_mwi(struct pci_dev *dev);
+int pdev_set_mwi(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
diff -urN linux-2.5.6-pre3/include/linux/pci_ids.h linux-2.5.6/include/linux/pci_ids.h
--- linux-2.5.6-pre3/include/linux/pci_ids.h	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/include/linux/pci_ids.h	Thu Mar  7 18:24:55 2002
@@ -1494,7 +1494,11 @@
 #define PCI_VENDOR_ID_BROADCOM		0x14e4
 #define PCI_DEVICE_ID_TIGON3_5700	0x1644
 #define PCI_DEVICE_ID_TIGON3_5701	0x1645
+#define PCI_DEVICE_ID_TIGON3_5702	0x1646
 #define PCI_DEVICE_ID_TIGON3_5703	0x1647
+#define PCI_DEVICE_ID_TIGON3_5702FE	0x164d
+#define PCI_DEVICE_ID_TIGON3_5702X	0x16a6
+#define PCI_DEVICE_ID_TIGON3_5703X	0x16a7
 
 #define PCI_VENDOR_ID_SYBA		0x1592
 #define PCI_DEVICE_ID_SYBA_2P_EPP	0x0782
@@ -1517,6 +1521,9 @@
 #define PCI_DEVICE_ID_MACROLINK_MCCR8	0x2000
 #define PCI_DEVICE_ID_MACROLINK_MCCR	0x2001
 
+#define PCI_VENDOR_ID_ALTIMA		0x173b
+#define PCI_DEVICE_ID_ALTIMA_AC1000	0x03e8
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
diff -urN linux-2.5.6-pre3/include/linux/pnpbios.h linux-2.5.6/include/linux/pnpbios.h
--- linux-2.5.6-pre3/include/linux/pnpbios.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/linux/pnpbios.h	Thu Mar  7 18:24:55 2002
@@ -142,7 +142,7 @@
 
 extern int  pnpbios_dont_use_current_config;
 extern void *pnpbios_kmalloc(size_t size, int f);
-extern void pnpbios_init (void);
+extern int pnpbios_init (void);
 extern void pnpbios_proc_init (void);
 
 extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
diff -urN linux-2.5.6-pre3/include/linux/smb.h linux-2.5.6/include/linux/smb.h
--- linux-2.5.6-pre3/include/linux/smb.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/include/linux/smb.h	Thu Mar  7 18:24:55 2002
@@ -86,7 +86,7 @@
 	uid_t		f_uid;
 	gid_t		f_gid;
 	kdev_t		f_rdev;
-	off_t		f_size;
+	loff_t		f_size;
 	time_t		f_atime;
 	time_t		f_mtime;
 	time_t		f_ctime;
diff -urN linux-2.5.6-pre3/include/linux/smb_fs.h linux-2.5.6/include/linux/smb_fs.h
--- linux-2.5.6-pre3/include/linux/smb_fs.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/include/linux/smb_fs.h	Thu Mar  7 18:24:55 2002
@@ -117,6 +117,7 @@
 #define SMB_CAP_NT_FIND          0x0200
 #define SMB_CAP_DFS              0x1000
 #define SMB_CAP_LARGE_READX      0x4000
+#define SMB_CAP_LARGE_WRITEX     0x8000
 
 
 /*
@@ -159,6 +160,30 @@
 	int				filled, valid, idx;
 };
 
+#define SMB_OPS_NUM_STATIC	5
+struct smb_ops {
+	int (*read)(struct inode *inode, loff_t offset, int count,
+		    char *data);
+	int (*write)(struct inode *inode, loff_t offset, int count, const
+		     char *data);
+	int (*readdir)(struct file *filp, void *dirent, filldir_t filldir,
+		       struct smb_cache_control *ctl);
+
+	int (*getattr)(struct smb_sb_info *server, struct dentry *dir,
+		       struct smb_fattr *fattr);
+	/* int (*setattr)(...); */      /* setattr is really icky! */
+
+	int (*truncate)(struct inode *inode, loff_t length);
+
+
+	/* --- --- --- end of "static" entries --- --- --- */
+
+	int (*convert)(unsigned char *output, int olen,
+		       const unsigned char *input, int ilen,
+		       struct nls_table *nls_from,
+		       struct nls_table *nls_to);
+};
+
 static inline int
 smb_is_open(struct inode *i)
 {
diff -urN linux-2.5.6-pre3/include/linux/smb_fs_sb.h linux-2.5.6/include/linux/smb_fs_sb.h
--- linux-2.5.6-pre3/include/linux/smb_fs_sb.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/linux/smb_fs_sb.h	Thu Mar  7 18:24:55 2002
@@ -54,8 +54,7 @@
 	   to put it on the stack. This points to temp_buf space. */
 	char *name_buf;
 
-	int (*convert)(char *, int, const char *, int,
-		       struct nls_table *, struct nls_table *);
+	struct smb_ops *ops;
 };
 
 
diff -urN linux-2.5.6-pre3/include/linux/smb_mount.h linux-2.5.6/include/linux/smb_mount.h
--- linux-2.5.6-pre3/include/linux/smb_mount.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/include/linux/smb_mount.h	Thu Mar  7 18:24:55 2002
@@ -37,6 +37,7 @@
 #define SMB_MOUNT_OLDATTR	0x0002	/* Use core getattr (Win 95 speedup) */
 #define SMB_MOUNT_DIRATTR	0x0004	/* Use find_first for getattr */
 #define SMB_MOUNT_CASE		0x0008	/* Be case sensitive */
+#define SMB_MOUNT_UNICODE	0x0010	/* Server talks unicode */
 
 
 struct smb_mount_data_kernel {
diff -urN linux-2.5.6-pre3/include/linux/smbno.h linux-2.5.6/include/linux/smbno.h
--- linux-2.5.6-pre3/include/linux/smbno.h	Tue Feb 19 18:11:04 2002
+++ linux-2.5.6/include/linux/smbno.h	Thu Mar  7 18:24:55 2002
@@ -281,4 +281,51 @@
 #define TRANSACT2_FINDNOTIFYNEXT  12
 #define TRANSACT2_MKDIR           13
 
+/* Information Levels -  Shared? */
+#define SMB_INFO_STANDARD		1
+#define SMB_INFO_QUERY_EA_SIZE		2
+#define SMB_INFO_QUERY_EAS_FROM_LIST	3
+#define SMB_INFO_QUERY_ALL_EAS		4
+#define SMB_INFO_IS_NAME_VALID		6
+
+/* Information Levels -  TRANSACT2_FINDFIRST */
+#define SMB_FIND_FILE_DIRECTORY_INFO		0x101
+#define SMB_FIND_FILE_FULL_DIRECTORY_INFO	0x102
+#define SMB_FIND_FILE_NAMES_INFO		0x103
+#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO	0x104
+
+/* Information Levels -  TRANSACT2_QPATHINFO */
+#define SMB_QUERY_FILE_BASIC_INFO	0x101
+#define SMB_QUERY_FILE_STANDARD_INFO	0x102
+#define SMB_QUERY_FILE_EA_INFO		0x103
+#define SMB_QUERY_FILE_NAME_INFO	0x104
+#define SMB_QUERY_FILE_ALL_INFO		0x107
+#define SMB_QUERY_FILE_ALT_NAME_INFO	0x108
+#define SMB_QUERY_FILE_STREAM_INFO	0x109
+#define SMB_QUERY_FILE_COMPRESSION_INFO	0x10b
+
+/* Information Levels - TRANSACT2_SETFILEINFO */
+#define SMB_SET_FILE_BASIC_INFO		0x101
+#define SMB_SET_FILE_DISPOSITION_INFO	0x102
+#define SMB_SET_FILE_ALLOCATION_INFO	0x103
+#define SMB_SET_FILE_END_OF_FILE_INFO	0x104
+
+/* smb_flg field flags */
+#define SMB_FLAGS_SUPPORT_LOCKREAD	0x01
+#define SMB_FLAGS_CLIENT_BUF_AVAIL	0x02
+#define SMB_FLAGS_RESERVED		0x04
+#define SMB_FLAGS_CASELESS_PATHNAMES	0x08
+#define SMB_FLAGS_CANONICAL_PATHNAMES	0x10
+#define SMB_FLAGS_REQUEST_OPLOCK	0x20
+#define SMB_FLAGS_REQUEST_BATCH_OPLOCK	0x40
+#define SMB_FLAGS_REPLY			0x80
+
+/* smb_flg2 field flags (samba-2.2.0/source/include/smb.h) */
+#define SMB_FLAGS2_LONG_PATH_COMPONENTS		0x0001
+#define SMB_FLAGS2_EXTENDED_ATTRIBUTES		0x0002
+#define SMB_FLAGS2_DFS_PATHNAMES		0x1000
+#define SMB_FLAGS2_READ_PERMIT_NO_EXECUTE	0x2000
+#define SMB_FLAGS2_32_BIT_ERROR_CODES		0x4000 
+#define SMB_FLAGS2_UNICODE_STRINGS		0x8000
+
 #endif /* _SMBNO_H_ */
diff -urN linux-2.5.6-pre3/include/linux/sockios.h linux-2.5.6/include/linux/sockios.h
--- linux-2.5.6-pre3/include/linux/sockios.h	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/include/linux/sockios.h	Thu Mar  7 18:24:55 2002
@@ -81,6 +81,8 @@
 #define SIOCGMIIREG	0x8948		/* Read MII PHY register.	*/
 #define SIOCSMIIREG	0x8949		/* Write MII PHY register.	*/
 
+#define SIOCWANDEV	0x894A		/* get/set netdev parameters	*/
+
 /* ARP cache control calls. */
 		    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
 #define SIOCDARP	0x8953		/* delete ARP table entry	*/
diff -urN linux-2.5.6-pre3/include/linux/spinlock.h linux-2.5.6/include/linux/spinlock.h
--- linux-2.5.6-pre3/include/linux/spinlock.h	Tue Feb 19 18:11:03 2002
+++ linux-2.5.6/include/linux/spinlock.h	Thu Mar  7 18:24:55 2002
@@ -84,12 +84,12 @@
   #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #endif
 
-#define spin_lock_init(lock)	do { } while(0)
+#define spin_lock_init(lock)	do { (void)(lock); } while(0)
 #define _raw_spin_lock(lock)	(void)(lock) /* Not "unused variable". */
-#define spin_is_locked(lock)	(0)
-#define _raw_spin_trylock(lock)	({1; })
-#define spin_unlock_wait(lock)	do { } while(0)
-#define _raw_spin_unlock(lock)	do { } while(0)
+#define spin_is_locked(lock)	((void)(lock), 0)
+#define _raw_spin_trylock(lock)	((void)(lock), 1)
+#define spin_unlock_wait(lock)	do { (void)(lock); } while(0)
+#define _raw_spin_unlock(lock)	do { (void)(lock); } while(0)
 
 #elif (DEBUG_SPINLOCKS < 2)
 
diff -urN linux-2.5.6-pre3/include/net/irda/irda.h linux-2.5.6/include/net/irda/irda.h
--- linux-2.5.6-pre3/include/net/irda/irda.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/net/irda/irda.h	Thu Mar  7 18:24:55 2002
@@ -54,8 +54,8 @@
 #define IRDA_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#ifndef ALIGN
-#  define ALIGN __attribute__((aligned))
+#ifndef IRDA_ALIGN
+#  define IRDA_ALIGN __attribute__((aligned))
 #endif
 #ifndef PACK
 #  define PACK __attribute__((packed))
diff -urN linux-2.5.6-pre3/include/net/irda/irqueue.h linux-2.5.6/include/net/irda/irqueue.h
--- linux-2.5.6-pre3/include/net/irda/irqueue.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/net/irda/irqueue.h	Thu Mar  7 18:24:55 2002
@@ -49,8 +49,8 @@
 #define HASHBIN_SIZE   8
 #define HASHBIN_MASK   0x7
 
-#ifndef ALIGN 
-#define ALIGN __attribute__((aligned))
+#ifndef IRDA_ALIGN 
+#define IRDA_ALIGN __attribute__((aligned))
 #endif
 
 #define Q_NULL { NULL, NULL, "", 0 }
@@ -75,8 +75,8 @@
 	__u32      magic;
 	int        hb_type;
 	int        hb_size;
-	spinlock_t hb_mutex[HASHBIN_SIZE] ALIGN;
-	irda_queue_t   *hb_queue[HASHBIN_SIZE] ALIGN;
+	spinlock_t hb_mutex[HASHBIN_SIZE] IRDA_ALIGN;
+	irda_queue_t   *hb_queue[HASHBIN_SIZE] IRDA_ALIGN;
 
 	irda_queue_t* hb_current;
 } hashbin_t;
diff -urN linux-2.5.6-pre3/include/sound/core.h linux-2.5.6/include/sound/core.h
--- linux-2.5.6-pre3/include/sound/core.h	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/include/sound/core.h	Thu Mar  7 18:24:55 2002
@@ -22,6 +22,10 @@
  *
  */
 
+#ifdef CONFIG_PM
+#include <linux/sched.h>		/* wake_up() and struct semaphore */
+#endif
+
 /* Typedef's */
 typedef struct timeval snd_timestamp_t;
 typedef struct sndrv_interval snd_interval_t;
diff -urN linux-2.5.6-pre3/include/sound/driver.h linux-2.5.6/include/sound/driver.h
--- linux-2.5.6-pre3/include/sound/driver.h	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/include/sound/driver.h	Thu Mar  7 18:24:55 2002
@@ -78,12 +78,4 @@
 
 #include "sndmagic.h"
 
-/*
- * Temporary hack, until linux/init.h is fixed.
- */
-#include <linux/init.h>
-#ifndef __devexit_p
-#define __devexit_p(x) x
-#endif
-
 #endif /* __SOUND_DRIVER_H */
diff -urN linux-2.5.6-pre3/include/sound/info.h linux-2.5.6/include/sound/info.h
--- linux-2.5.6-pre3/include/sound/info.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/include/sound/info.h	Thu Mar  7 18:24:55 2002
@@ -104,6 +104,11 @@
 #ifdef CONFIG_PROC_FS
 
 extern snd_info_entry_t *snd_seq_root;
+#ifdef CONFIG_SND_OSSEMUL
+extern snd_info_entry_t *snd_oss_root;
+#else
+#define snd_oss_root NULL
+#endif
 
 int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) __attribute__ ((format (printf, 2, 3)));
 int snd_info_init(void);
@@ -138,6 +143,7 @@
 #else
 
 #define snd_seq_root NULL
+#define snd_oss_root NULL
 
 static inline int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...) { return 0; }
 static inline int snd_info_init(void) { return 0; }
diff -urN linux-2.5.6-pre3/include/sound/pcm.h linux-2.5.6/include/sound/pcm.h
--- linux-2.5.6-pre3/include/sound/pcm.h	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/include/sound/pcm.h	Thu Mar  7 18:24:55 2002
@@ -25,6 +25,7 @@
 
 #include <sound/asound.h>
 #include <linux/poll.h>
+#include <linux/bitops.h>
 
 typedef sndrv_pcm_uframes_t snd_pcm_uframes_t;
 typedef sndrv_pcm_sframes_t snd_pcm_sframes_t;
diff -urN linux-2.5.6-pre3/include/sound/pcm_params.h linux-2.5.6/include/sound/pcm_params.h
--- linux-2.5.6-pre3/include/sound/pcm_params.h	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/include/sound/pcm_params.h	Thu Mar  7 18:24:55 2002
@@ -22,8 +22,6 @@
  *
  */
 
-#include <linux/bitops.h>
-
 extern int snd_pcm_hw_param_mask(snd_pcm_substream_t *pcm, snd_pcm_hw_params_t *params,
 				 snd_pcm_hw_param_t var, const snd_mask_t *val);
 extern unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params,
diff -urN linux-2.5.6-pre3/include/sound/version.h linux-2.5.6/include/sound/version.h
--- linux-2.5.6-pre3/include/sound/version.h	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/include/sound/version.h	Thu Mar  7 18:24:55 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0beta12"
-#define CONFIG_SND_DATE " (Tue Feb 26 09:34:24 2002 UTC)"
+#define CONFIG_SND_DATE " (Wed Mar 06 07:56:20 2002 UTC)"
diff -urN linux-2.5.6-pre3/init/do_mounts.c linux-2.5.6/init/do_mounts.c
--- linux-2.5.6-pre3/init/do_mounts.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/init/do_mounts.c	Thu Mar  7 18:24:55 2002
@@ -840,7 +840,7 @@
 	mount_devfs_fs ();
 }
 
-#ifdef BUILD_CRAMDISK
+#if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
 
 /*
  * gzip declarations
@@ -985,4 +985,4 @@
 	return result;
 }
 
-#endif  /* BUILD_CRAMDISK */
+#endif  /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */
diff -urN linux-2.5.6-pre3/kernel/sched.c linux-2.5.6/kernel/sched.c
--- linux-2.5.6-pre3/kernel/sched.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/kernel/sched.c	Thu Mar  7 18:24:55 2002
@@ -1438,10 +1438,12 @@
 	idle->prio = MAX_PRIO;
 	idle->state = TASK_RUNNING;
 	idle->thread_info->cpu = cpu;
-	idle->thread_info->preempt_count = (idle->lock_depth >= 0);
 	double_rq_unlock(idle_rq, rq);
 	set_tsk_need_resched(idle);
 	__restore_flags(flags);
+
+	/* Set the preempt count _outside_ the spinlocks! */
+	idle->thread_info->preempt_count = (idle->lock_depth >= 0);
 }
 
 extern void init_timervecs(void);
diff -urN linux-2.5.6-pre3/net/core/dev.c linux-2.5.6/net/core/dev.c
--- linux-2.5.6-pre3/net/core/dev.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/net/core/dev.c	Thu Mar  7 18:24:56 2002
@@ -2110,7 +2110,8 @@
 			    cmd == SIOCETHTOOL ||
 			    cmd == SIOCGMIIPHY ||
 			    cmd == SIOCGMIIREG ||
-			    cmd == SIOCSMIIREG) {
+			    cmd == SIOCSMIIREG ||
+			    cmd == SIOCWANDEV) {
 				if (dev->do_ioctl) {
 					if (!netif_device_present(dev))
 						return -ENODEV;
@@ -2276,8 +2277,9 @@
 		 */	
 		 
 		default:
-			if (cmd >= SIOCDEVPRIVATE &&
-			    cmd <= SIOCDEVPRIVATE + 15) {
+			if (cmd == SIOCWANDEV ||
+			    (cmd >= SIOCDEVPRIVATE &&
+			     cmd <= SIOCDEVPRIVATE + 15)) {
 				dev_load(ifr.ifr_name);
 				dev_probe_lock();
 				rtnl_lock();
diff -urN linux-2.5.6-pre3/scripts/cramfs/GNUmakefile linux-2.5.6/scripts/cramfs/GNUmakefile
--- linux-2.5.6-pre3/scripts/cramfs/GNUmakefile	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/scripts/cramfs/GNUmakefile	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-CC = gcc
-CFLAGS = -W -Wall -O2 -g
-CPPFLAGS = -I../../include
-LDLIBS = -lz
-PROGS = mkcramfs cramfsck
-
-all: $(PROGS)
-
-distclean clean:
-	rm -f $(PROGS)
-
-.PHONY: all clean
diff -urN linux-2.5.6-pre3/scripts/cramfs/cramfsck.c linux-2.5.6/scripts/cramfs/cramfsck.c
--- linux-2.5.6-pre3/scripts/cramfs/cramfsck.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/scripts/cramfs/cramfsck.c	Wed Dec 31 16:00:00 1969
@@ -1,588 +0,0 @@
-/*
- * cramfsck - check a cramfs file system
- *
- * Copyright (C) 2000-2001 Transmeta Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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
- *
- * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program)
- * 2000/06/03: Daniel Quinlan (CRC and length checking program)
- * 2000/06/04: Daniel Quinlan (merged programs, added options, support
- *                            for special files, preserve permissions and
- *                            ownership, cramfs superblock v2, bogus mode
- *                            test, pathname length test, etc.)
- * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing,
- *                            symlink size test)
- * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512,
- *                            fsck-compatible exit codes)
- * 2000/07/15: Daniel Quinlan (initial support for block devices)
- */
-
-/* compile-time options */
-#define INCLUDE_FS_TESTS	/* include cramfs checking and extraction */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/fcntl.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-#include <getopt.h>
-#include <sys/sysmacros.h>
-#include <utime.h>
-#include <sys/ioctl.h>
-#define _LINUX_STRING_H_
-#include <linux/fs.h>
-#include <linux/cramfs_fs.h>
-#include <zlib.h>
-
-static const char *progname = "cramfsck";
-
-static int fd;			/* ROM image file descriptor */
-static char *filename;		/* ROM image filename */
-struct cramfs_super *super;	/* just find the cramfs superblock once */
-static int opt_verbose = 0;	/* 1 = verbose (-v), 2+ = very verbose (-vv) */
-#ifdef INCLUDE_FS_TESTS
-static int opt_extract = 0;	/* extract cramfs (-x) */
-char *extract_dir = NULL;	/* extraction directory (-x) */
-
-unsigned long start_inode = 1 << 28;	/* start of first non-root inode */
-unsigned long end_inode = 0;		/* end of the directory structure */
-unsigned long start_data = 1 << 28;	/* start of the data (256 MB = max) */
-unsigned long end_data = 0;		/* end of the data */
-/* true?  cramfs_super < start_inode < end_inode <= start_data <= end_data */
-static uid_t euid;			/* effective UID */
-
-#define PAD_SIZE 512
-#define PAGE_CACHE_SIZE (4096)
-
-/* Guarantee access to at least 8kB at a time */
-#define ROMBUFFER_BITS	13
-#define ROMBUFFERSIZE	(1 << ROMBUFFER_BITS)
-#define ROMBUFFERMASK	(ROMBUFFERSIZE-1)
-static char read_buffer[ROMBUFFERSIZE * 2];
-static unsigned long read_buffer_block = ~0UL;
-
-/* Uncompressing data structures... */
-static char outbuffer[PAGE_CACHE_SIZE*2];
-z_stream stream;
-
-#endif /* INCLUDE_FS_TESTS */
-
-/* Input status of 0 to print help and exit without an error. */
-static void usage(int status)
-{
-	FILE *stream = status ? stderr : stdout;
-
-	fprintf(stream, "usage: %s [-hv] [-x dir] file\n"
-		" -h         print this help\n"
-		" -x dir     extract into dir\n"
-		" -v         be more verbose\n"
-		" file       file to test\n", progname);
-
-	exit(status);
-}
-
-#ifdef INCLUDE_FS_TESTS
-void print_node(char type, struct cramfs_inode *i, char *name)
-{
-	char info[10];
-
-	if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) {
-		/* major/minor numbers can be as high as 2^12 or 4096 */
-		snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size));
-	}
-	else {
-		/* size be as high as 2^24 or 16777216 */
-		snprintf(info, 10, "%9d", i->size);
-	}
-
-	printf("%c %04o %s %5d:%-3d %s\n",
-	       type, i->mode & ~S_IFMT, info, i->uid, i->gid, name);
-}
-
-/*
- * Create a fake "blocked" access
- */
-static void *romfs_read(unsigned long offset)
-{
-	unsigned int block = offset >> ROMBUFFER_BITS;
-	if (block != read_buffer_block) {
-		read_buffer_block = block;
-		lseek(fd, block << ROMBUFFER_BITS, SEEK_SET);
-		read(fd, read_buffer, ROMBUFFERSIZE * 2);
-	}
-	return read_buffer + (offset & ROMBUFFERMASK);
-}
-
-static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i)
-{
-	struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode));
-	*inode = *i;
-	return inode;
-}
-
-static struct cramfs_inode *iget(unsigned int ino)
-{
-	return cramfs_iget(romfs_read(ino));
-}
-
-void iput(struct cramfs_inode *inode)
-{
-	free(inode);
-}
-
-/*
- * Return the offset of the root directory,
- * or 0 if none.
- */
-static struct cramfs_inode *read_super(void)
-{
-	unsigned long offset;
-
-	offset = super->root.offset << 2;
-	if (super->magic != CRAMFS_MAGIC)
-		return NULL;
-	if (memcmp(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)) != 0)
-		return NULL;
-	if (offset < sizeof(super))
-		return NULL;
-	return cramfs_iget(&super->root);
-}
-
-static int uncompress_block(void *src, int len)
-{
-	int err;
-
-	stream.next_in = src;
-	stream.avail_in = len;
-
-	stream.next_out = (unsigned char *) outbuffer;
-	stream.avail_out = PAGE_CACHE_SIZE*2;
-
-	inflateReset(&stream);
-
-	err = inflate(&stream, Z_FINISH);
-	if (err != Z_STREAM_END) {
-		fprintf(stderr, "%s: error %d while decompressing! %p(%d)\n",
-			filename, err, src, len);
-		exit(4);
-	}
-	return stream.total_out;
-}
-
-static void change_file_status(char *path, struct cramfs_inode *i)
-{
-	struct utimbuf epoch = { 0, 0 };
-
-	if (euid == 0) {
-		if (lchown(path, i->uid, i->gid) < 0) {
-			perror(path);
-			exit(8);
-		}
-		if (S_ISLNK(i->mode))
-			return;
-		if ((S_ISUID | S_ISGID) & i->mode) {
-			if (chmod(path, i->mode) < 0) {
-				perror(path);
-				exit(8);
-			}
-		}
-	}
-	if (S_ISLNK(i->mode))
-		return;
-	if (utime(path, &epoch) < 0) {
-		perror(path);
-		exit(8);
-	}
-}
-
-static void do_symlink(char *path, struct cramfs_inode *i)
-{
-	unsigned long offset = i->offset << 2;
-	unsigned long curr = offset + 4;
-	unsigned long next = *(u32 *) romfs_read(offset);
-	unsigned long size;
-
-	if (next > end_data) {
-		end_data = next;
-	}
-
-	size = uncompress_block(romfs_read(curr), next - curr);
-	if (size != i->size) {
-		fprintf(stderr, "%s: size error in symlink `%s'\n",
-			filename, path);
-		exit(4);
-	}
-	outbuffer[size] = 0;
-	if (opt_verbose) {
-		char *str;
-
-		str = malloc(strlen(outbuffer) + strlen(path) + 5);
-		strcpy(str, path);
-		strncat(str, " -> ", 4);
-		strncat(str, outbuffer, size);
-
-		print_node('l', i, str);
-		if (opt_verbose > 1) {
-			printf("  uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
-		}
-	}
-	if (opt_extract) {
-		symlink(outbuffer, path);
-		change_file_status(path, i);
-	}
-}
-
-static void do_special_inode(char *path, struct cramfs_inode *i)
-{
-	dev_t devtype = 0;
-	char type;
-
-	if (S_ISCHR(i->mode)) {
-		devtype = i->size;
-		type = 'c';
-	}
-	else if (S_ISBLK(i->mode)) {
-		devtype = i->size;
-		type = 'b';
-	}
-	else if (S_ISFIFO(i->mode))
-		type = 'p';
-	else if (S_ISSOCK(i->mode))
-		type = 's';
-	else {
-		fprintf(stderr, "%s: bogus mode on `%s' (%o)\n", filename, path, i->mode);
-		exit(4);
-	}
-
-	if (opt_verbose) {
-		print_node(type, i, path);
-	}
-
-	if (opt_extract) {
-		if (mknod(path, i->mode, devtype) < 0) {
-			perror(path);
-			exit(8);
-		}
-		change_file_status(path, i);
-	}
-}
-
-static void do_uncompress(int fd, unsigned long offset, unsigned long size)
-{
-	unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE);
-
-	do {
-		unsigned long out = PAGE_CACHE_SIZE;
-		unsigned long next = *(u32 *) romfs_read(offset);
-
-		if (next > end_data) {
-			end_data = next;
-		}
-
-		offset += 4;
-		if (curr == next) {
-			if (opt_verbose > 1) {
-				printf("  hole at %ld (%d)\n", curr, PAGE_CACHE_SIZE);
-			}
-			if (size < PAGE_CACHE_SIZE)
-				out = size;
-			memset(outbuffer, 0x00, out);
-		}
-		else {
-			if (opt_verbose > 1) {
-				printf("  uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr);
-			}
-			out = uncompress_block(romfs_read(curr), next - curr);
-		}
-		if (size >= PAGE_CACHE_SIZE) {
-			if (out != PAGE_CACHE_SIZE) {
-				fprintf(stderr, "%s: Non-block (%ld) bytes\n", filename, out);
-				exit(4);
-			}
-		} else {
-			if (out != size) {
-				fprintf(stderr, "%s: Non-size (%ld vs %ld) bytes\n", filename, out, size);
-				exit(4);
-			}
-		}
-		size -= out;
-		if (opt_extract) {
-			write(fd, outbuffer, out);
-		}
-		curr = next;
-	} while (size);
-}
-
-static void expand_fs(int pathlen, char *path, struct cramfs_inode *inode)
-{
-	if (S_ISDIR(inode->mode)) {
-		int count = inode->size;
-		unsigned long offset = inode->offset << 2;
-		char *newpath = malloc(pathlen + 256);
-
-		if (count > 0 && offset < start_inode) {
-			start_inode = offset;
-		}
-		/* XXX - need to check end_inode for empty case? */
-		memcpy(newpath, path, pathlen);
-		newpath[pathlen] = '/';
-		pathlen++;
-		if (opt_verbose) {
-			print_node('d', inode, path);
-		}
-		if (opt_extract) {
-			mkdir(path, inode->mode);
-			change_file_status(path, inode);
-		}
-		while (count > 0) {
-			struct cramfs_inode *child = iget(offset);
-			int size;
-			int newlen = child->namelen << 2;
-
-			size = sizeof(struct cramfs_inode) + newlen;
-			count -= size;
-
-			offset += sizeof(struct cramfs_inode);
-
-			memcpy(newpath + pathlen, romfs_read(offset), newlen);
-			newpath[pathlen + newlen] = 0;
-			if ((pathlen + newlen) - strlen(newpath) > 3) {
-				fprintf(stderr, "%s: invalid cramfs--bad path length\n", filename);
-				exit(4);
-			}
-			expand_fs(strlen(newpath), newpath, child);
-
-			offset += newlen;
-
-			if (offset > end_inode) {
-				end_inode = offset;
-			}
-		}
-		return;
-	}
-	if (S_ISREG(inode->mode)) {
-		int fd = 0;
-		unsigned long offset = inode->offset << 2;
-
-		if (offset > 0 && offset < start_data) {
-			start_data = offset;
-		}
-		if (opt_verbose) {
-			print_node('f', inode, path);
-		}
-		if (opt_extract) {
-			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, inode->mode);
-		}
-		if (inode->size) {
-			do_uncompress(fd, offset, inode->size);
-		}
-		if (opt_extract) {
-			close(fd);
-			change_file_status(path, inode);
-		}
-		return;
-	}
-	if (S_ISLNK(inode->mode)) {
-		unsigned long offset = inode->offset << 2;
-
-		if (offset < start_data) {
-			start_data = offset;
-		}
-		do_symlink(path, inode);
-		return;
-	}
-	else {
-		do_special_inode(path, inode);
-		return;
-	}
-}
-#endif /* INCLUDE_FS_TESTS */
-
-int main(int argc, char **argv)
-{
-	void *buf;
-	size_t length;
-	struct stat st;
-	u32 crc_old, crc_new;
-#ifdef INCLUDE_FS_TESTS
-	struct cramfs_inode *root;
-#endif /* INCLUDE_FS_TESTS */
-	int c;			/* for getopt */
-	int start = 0;
-
-	if (argc)
-		progname = argv[0];
-
-	/* command line options */
-	while ((c = getopt(argc, argv, "hx:v")) != EOF) {
-		switch (c) {
-		case 'h':
-			usage(0);
-		case 'x':
-#ifdef INCLUDE_FS_TESTS
-			opt_extract = 1;
-			extract_dir = malloc(strlen(optarg) + 1);
-			strcpy(extract_dir, optarg);
-			break;
-#else /*  not INCLUDE_FS_TESTS */
-			fprintf(stderr, "%s: compiled without -x support\n",
-				progname);
-			exit(16);
-#endif /* not INCLUDE_FS_TESTS */
-		case 'v':
-			opt_verbose++;
-			break;
-		}
-	}
-
-	if ((argc - optind) != 1)
-		usage(16);
-	filename = argv[optind];
-
-	/* find the physical size of the file or block device */
-	if (lstat(filename, &st) < 0) {
-		perror(filename);
-		exit(8);
-	}
-	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		exit(8);
-	}
-	if (S_ISBLK(st.st_mode)) {
-		if (ioctl(fd, BLKGETSIZE, &length) < 0) {
-			fprintf(stderr, "%s: warning--unable to determine filesystem size \n", filename);
-			exit(4);
-		}
-		length = length * 512;
-	}
-	else if (S_ISREG(st.st_mode)) {
-		length = st.st_size;
-	}
-	else {
-		fprintf(stderr, "%s is not a block device or file\n", filename);
-		exit(8);
-	}
-
-	if (length < sizeof(struct cramfs_super)) {
-		fprintf(stderr, "%s: invalid cramfs--file length too short\n", filename);
-		exit(4);
-	}
-
-	if (S_ISBLK(st.st_mode)) {
-		/* nasty because mmap of block devices fails */
-		buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-		read(fd, buf, length);
-	}
-	else {
-		/* nice and easy */
-		buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-	}
-
-	/* XXX - this could be cleaner... */
-	if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) {
-		start = 0;
-		super = (struct cramfs_super *) buf;
-	}
-	else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) &&
-		 ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC)))
-	{
-		start = PAD_SIZE;
-		super = (struct cramfs_super *) (buf + PAD_SIZE);
-	}
-	else {
-		fprintf(stderr, "%s: invalid cramfs--wrong magic\n", filename);
-		exit(4);
-	}
-
-	if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) {
-		/* length test */
-		if (length < super->size) {
-			fprintf(stderr, "%s: invalid cramfs--file length too short\n", filename);
-			exit(4);
-		}
-		else if (length > super->size) {
-			fprintf(stderr, "%s: warning--file length too long, padded image?\n", filename);
-		}
-
-		/* CRC test */
-		crc_old = super->fsid.crc;
-		super->fsid.crc = crc32(0L, Z_NULL, 0);
-		crc_new = crc32(0L, Z_NULL, 0);
-		crc_new = crc32(crc_new, (unsigned char *) buf+start, super->size - start);
-		if (crc_new != crc_old) {
-			fprintf(stderr, "%s: invalid cramfs--crc error\n", filename);
-			exit(4);
-		}
-	}
-	else {
-		fprintf(stderr, "%s: warning--old cramfs image, no CRC\n",
-			filename);
-	}
-
-#ifdef INCLUDE_FS_TESTS
-	super = (struct cramfs_super *) malloc(sizeof(struct cramfs_super));
-	if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) {
-		memcpy(super, buf, sizeof(struct cramfs_super));
-	}
-	else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) &&
-		 ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC)))
-	{
-		memcpy(super, (buf + PAD_SIZE), sizeof(struct cramfs_super));
-	}
-
-	munmap(buf, length);
-
-	/* file format test, uses fake "blocked" accesses */
-	root = read_super();
-	umask(0);
-	euid = geteuid();
-	if (!root) {
-		fprintf(stderr, "%s: invalid cramfs--bad superblock\n",
-			filename);
-		exit(4);
-	}
-	stream.next_in = NULL;
-	stream.avail_in = 0;
-	inflateInit(&stream);
-
-	if (!extract_dir) {
-		extract_dir = "root";
-	}
-
-	expand_fs(strlen(extract_dir), extract_dir, root);
-	inflateEnd(&stream);
-
-	if (start_data != 1 << 28  && end_inode != start_data) {
-		fprintf(stderr, "%s: invalid cramfs--directory data end (%ld) != file data start (%ld)\n", filename, end_inode, start_data);
-		exit(4);
-	}
-	if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) {
-		if (end_data > super->size) {
-			fprintf(stderr, "%s: invalid cramfs--invalid file data offset\n", filename);
-			exit(4);
-		}
-	}
-#endif /* INCLUDE_FS_TESTS */
-
-	exit(0);
-}
diff -urN linux-2.5.6-pre3/scripts/cramfs/mkcramfs.c linux-2.5.6/scripts/cramfs/mkcramfs.c
--- linux-2.5.6-pre3/scripts/cramfs/mkcramfs.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/scripts/cramfs/mkcramfs.c	Wed Dec 31 16:00:00 1969
@@ -1,776 +0,0 @@
-/*
- * mkcramfs - make a cramfs file system
- *
- * Copyright (C) 1999-2001 Transmeta Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/fcntl.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-#include <getopt.h>
-#include <linux/cramfs_fs.h>
-#include <zlib.h>
-
-#define PAD_SIZE 512		/* only 0 and 512 supported by kernel */
-
-static const char *progname = "mkcramfs";
-
-/* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */
-
-/* Input status of 0 to print help and exit without an error. */
-static void usage(int status)
-{
-	FILE *stream = status ? stderr : stdout;
-
-	fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
-		" -h         print this help\n"
-		" -E         make all warnings errors (non-zero exit status)\n"
-		" -e edition set edition number (part of fsid)\n"
-		" -i file    insert a file image into the filesystem (requires >= 2.4.0)\n"
-		" -n name    set name of cramfs filesystem\n"
-		" -p         pad by %d bytes for boot code\n"
-		" -s         sort directory entries (old option, ignored)\n"
-		" -z         make explicit holes (requires >= 2.3.39)\n"
-		" dirname    root of the filesystem to be compressed\n"
-		" outfile    output file\n", progname, PAD_SIZE);
-
-	exit(status);
-}
-
-#define PAGE_CACHE_SIZE (4096)
-/* The kernel assumes PAGE_CACHE_SIZE as block size. */
-static unsigned int blksize = PAGE_CACHE_SIZE;
-static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
-static int image_length = 0;
-
-/*
- * If opt_holes is set, then mkcramfs can create explicit holes in the
- * data, which saves 26 bytes per hole (which is a lot smaller a
- * saving than most most filesystems).
- *
- * Note that kernels up to at least 2.3.39 don't support cramfs holes,
- * which is why this is turned off by default.
- */
-static int opt_edition = 0;
-static int opt_errors = 0;
-static int opt_holes = 0;
-static int opt_pad = 0;
-static char *opt_image = NULL;
-static char *opt_name = NULL;
-
-static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
-
-#ifndef MIN
-# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
-#endif
-
-/* In-core version of inode / directory entry. */
-struct entry {
-	/* stats */
-	char *name;
-	unsigned int mode, size, uid, gid;
-
-	/* FS data */
-	void *uncompressed;
-        /* points to other identical file */
-        struct entry *same;
-        unsigned int offset;            /* pointer to compressed data in archive */
-	unsigned int dir_offset;	/* Where in the archive is the directory entry? */
-
-	/* organization */
-	struct entry *child; /* null for non-directories and empty directories */
-	struct entry *next;
-};
-
-/*
- * The longest file name component to allow for in the input directory tree.
- * Ext2fs (and many others) allow up to 255 bytes.  A couple of filesystems
- * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
- * >255-byte names in the input directory tree given that such names get
- * truncated to 255 bytes when written to cramfs.
- */
-#define MAX_INPUT_NAMELEN 255
-
-static int find_identical_file(struct entry *orig,struct entry *newfile)
-{
-        if(orig==newfile) return 1;
-        if(!orig) return 0;
-        if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) {
-                newfile->same=orig;
-                return 1;
-        }
-        return find_identical_file(orig->child,newfile) ||
-                   find_identical_file(orig->next,newfile);
-}
-
-static void eliminate_doubles(struct entry *root,struct entry *orig) {
-        if(orig) {
-                if(orig->size && orig->uncompressed)
-			find_identical_file(root,orig);
-                eliminate_doubles(root,orig->child);
-                eliminate_doubles(root,orig->next);
-        }
-}
-
-/*
- * We define our own sorting function instead of using alphasort which
- * uses strcoll and changes ordering based on locale information.
- */
-static int cramsort (const void *a, const void *b)
-{
-	return strcmp ((*(const struct dirent **) a)->d_name,
-		       (*(const struct dirent **) b)->d_name);
-}
-
-static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
-{
-	struct dirent **dirlist;
-	int totalsize = 0, dircount, dirindex;
-	char *path, *endpath;
-	size_t len = strlen(name);
-
-	/* Set up the path. */
-	/* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
-	path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
-	if (!path) {
-		perror(NULL);
-		exit(8);
-	}
-	memcpy(path, name, len);
-	endpath = path + len;
-	*endpath = '/';
-	endpath++;
-
-        /* read in the directory and sort */
-        dircount = scandir(name, &dirlist, 0, cramsort);
-
-	if (dircount < 0) {
-		perror(name);
-		exit(8);
-	}
-
-	/* process directory */
-	for (dirindex = 0; dirindex < dircount; dirindex++) {
-		struct dirent *dirent;
-		struct entry *entry;
-		struct stat st;
-		int size;
-		size_t namelen;
-
-		dirent = dirlist[dirindex];
-
-		/* Ignore "." and ".." - we won't be adding them to the archive */
-		if (dirent->d_name[0] == '.') {
-			if (dirent->d_name[1] == '\0')
-				continue;
-			if (dirent->d_name[1] == '.') {
-				if (dirent->d_name[2] == '\0')
-					continue;
-			}
-		}
-		namelen = strlen(dirent->d_name);
-		if (namelen > MAX_INPUT_NAMELEN) {
-			fprintf(stderr,
-				"Very long (%u bytes) filename `%s' found.\n"
-				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
-				namelen, dirent->d_name);
-			exit(8);
-		}
-		memcpy(endpath, dirent->d_name, namelen + 1);
-
-		if (lstat(path, &st) < 0) {
-			perror(endpath);
-			warn_skip = 1;
-			continue;
-		}
-		entry = calloc(1, sizeof(struct entry));
-		if (!entry) {
-			perror(NULL);
-			exit(8);
-		}
-		entry->name = strdup(dirent->d_name);
-		if (!entry->name) {
-			perror(NULL);
-			exit(8);
-		}
-		if (namelen > 255) {
-			/* Can't happen when reading from ext2fs. */
-
-			/* TODO: we ought to avoid chopping in half
-			   multi-byte UTF8 characters. */
-			entry->name[namelen = 255] = '\0';
-			warn_namelen = 1;
-		}
-		entry->mode = st.st_mode;
-		entry->size = st.st_size;
-		entry->uid = st.st_uid;
-		if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
-			warn_uid = 1;
-		entry->gid = st.st_gid;
-		if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
-			/* TODO: We ought to replace with a default
-                           gid instead of truncating; otherwise there
-                           are security problems.  Maybe mode should
-                           be &= ~070.  Same goes for uid once Linux
-                           supports >16-bit uids. */
-			warn_gid = 1;
-		size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
-		*fslen_ub += size;
-		if (S_ISDIR(st.st_mode)) {
-			entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
-		} else if (S_ISREG(st.st_mode)) {
-			/* TODO: We ought to open files in do_compress, one
-			   at a time, instead of amassing all these memory
-			   maps during parse_directory (which don't get used
-			   until do_compress anyway).  As it is, we tend to
-			   get EMFILE errors (especially if mkcramfs is run
-			   by non-root).
-
-			   While we're at it, do analagously for symlinks
-			   (which would just save a little memory). */
-			int fd = open(path, O_RDONLY);
-			if (fd < 0) {
-				perror(path);
-				warn_skip = 1;
-				continue;
-			}
-			if (entry->size) {
-				if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
-					warn_size = 1;
-					entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
-				}
-
-				entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0);
-				if (-1 == (int) (long) entry->uncompressed) {
-					perror("mmap");
-					exit(8);
-				}
-			}
-			close(fd);
-		} else if (S_ISLNK(st.st_mode)) {
-			entry->uncompressed = malloc(entry->size);
-			if (!entry->uncompressed) {
-				perror(NULL);
-				exit(8);
-			}
-			if (readlink(path, entry->uncompressed, entry->size) < 0) {
-				perror(path);
-				warn_skip = 1;
-				continue;
-			}
-		} else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
-			/* maybe we should skip sockets */
-			entry->size = 0;
-		} else {
-			entry->size = st.st_rdev;
-			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
-				warn_dev = 1;
-		}
-
-		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
-			int blocks = ((entry->size - 1) / blksize + 1);
-
-			/* block pointers & data expansion allowance + data */
-			if(entry->size)
-				*fslen_ub += (4+26)*blocks + entry->size + 3;
-                }
-
-		/* Link it into the list */
-		*prev = entry;
-		prev = &entry->next;
-		totalsize += size;
-	}
-	free(path);
-	free(dirlist);		/* allocated by scandir() with malloc() */
-	return totalsize;
-}
-
-/* Returns sizeof(struct cramfs_super), which includes the root inode. */
-static unsigned int write_superblock(struct entry *root, char *base, int size)
-{
-	struct cramfs_super *super = (struct cramfs_super *) base;
-	unsigned int offset = sizeof(struct cramfs_super) + image_length;
-
-	if (opt_pad) {
-		offset += opt_pad;
-	}
-
-	super->magic = CRAMFS_MAGIC;
-	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
-	if (opt_holes)
-		super->flags |= CRAMFS_FLAG_HOLES;
-	if (image_length > 0)
-		super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
-	super->size = size;
-	memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
-
-	super->fsid.crc = crc32(0L, Z_NULL, 0);
-	super->fsid.edition = opt_edition;
-	super->fsid.blocks = total_blocks;
-	super->fsid.files = total_nodes;
-
-	memset(super->name, 0x00, sizeof(super->name));
-	if (opt_name)
-		strncpy(super->name, opt_name, sizeof(super->name));
-	else
-		strncpy(super->name, "Compressed", sizeof(super->name));
-
-	super->root.mode = root->mode;
-	super->root.uid = root->uid;
-	super->root.gid = root->gid;
-	super->root.size = root->size;
-	super->root.offset = offset >> 2;
-
-	return offset;
-}
-
-static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
-{
-	struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
-#ifdef DEBUG
-	assert ((offset & 3) == 0);
-#endif /* DEBUG */
-	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
-		fprintf(stderr, "filesystem too big.  Exiting.\n");
-		exit(8);
-	}
-	inode->offset = (offset >> 2);
-}
-
-
-/*
- * We do a width-first printout of the directory
- * entries, using a stack to remember the directories
- * we've seen.
- */
-#define MAXENTRIES (100)
-static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
-{
-	int stack_entries = 0;
-	struct entry *entry_stack[MAXENTRIES];
-
-	for (;;) {
-		int dir_start = stack_entries;
-		while (entry) {
-			struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
-			size_t len = strlen(entry->name);
-
-			entry->dir_offset = offset;
-
-			inode->mode = entry->mode;
-			inode->uid = entry->uid;
-			inode->gid = entry->gid;
-			inode->size = entry->size;
-			inode->offset = 0;
-			/* Non-empty directories, regfiles and symlinks will
-			   write over inode->offset later. */
-
-			offset += sizeof(struct cramfs_inode);
-			total_nodes++;	/* another node */
-			memcpy(base + offset, entry->name, len);
-			/* Pad up the name to a 4-byte boundary */
-			while (len & 3) {
-				*(base + offset + len) = '\0';
-				len++;
-			}
-			inode->namelen = len >> 2;
-			offset += len;
-
-			/* TODO: this may get it wrong for chars >= 0x80.
-			   Most filesystems use UTF8 encoding for filenames,
-			   whereas the console is a single-byte character
-			   set like iso-latin-1. */
-			printf("  %s\n", entry->name);
-			if (entry->child) {
-				if (stack_entries >= MAXENTRIES) {
-					fprintf(stderr, "Exceeded MAXENTRIES.  Raise this value in mkcramfs.c and recompile.  Exiting.\n");
-					exit(8);
-				}
-				entry_stack[stack_entries] = entry;
-				stack_entries++;
-			}
-			entry = entry->next;
-		}
-
-		/*
-		 * Reverse the order the stack entries pushed during
-                 * this directory, for a small optimization of disk
-                 * access in the created fs.  This change makes things
-                 * `ls -UR' order.
-		 */
-		{
-			struct entry **lo = entry_stack + dir_start;
-			struct entry **hi = entry_stack + stack_entries;
-			struct entry *tmp;
-
-			while (lo < --hi) {
-				tmp = *lo;
-				*lo++ = *hi;
-				*hi = tmp;
-			}
-		}
-
-		/* Pop a subdirectory entry from the stack, and recurse. */
-		if (!stack_entries)
-			break;
-		stack_entries--;
-		entry = entry_stack[stack_entries];
-
-		set_data_offset(entry, base, offset);
-		printf("'%s':\n", entry->name);
-		entry = entry->child;
-	}
-	return offset;
-}
-
-static int is_zero(char const *begin, unsigned len)
-{
-	if (opt_holes)
-		/* Returns non-zero iff the first LEN bytes from BEGIN are
-		   all NULs. */
-		return (len-- == 0 ||
-			(begin[0] == '\0' &&
-			 (len-- == 0 ||
-			  (begin[1] == '\0' &&
-			   (len-- == 0 ||
-			    (begin[2] == '\0' &&
-			     (len-- == 0 ||
-			      (begin[3] == '\0' &&
-			       memcmp(begin, begin + 4, len) == 0))))))));
-	else
-		/* Never create holes. */
-		return 0;
-}
-
-/*
- * One 4-byte pointer per block and then the actual blocked
- * output. The first block does not need an offset pointer,
- * as it will start immediately after the pointer block;
- * so the i'th pointer points to the end of the i'th block
- * (i.e. the start of the (i+1)'th block or past EOF).
- *
- * Note that size > 0, as a zero-sized file wouldn't ever
- * have gotten here in the first place.
- */
-static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
-{
-	unsigned long original_size = size;
-	unsigned long original_offset = offset;
-	unsigned long new_size;
-	unsigned long blocks = (size - 1) / blksize + 1;
-	unsigned long curr = offset + 4 * blocks;
-	int change;
-
-	total_blocks += blocks;
-
-	do {
-		unsigned long len = 2 * blksize;
-		unsigned int input = size;
-		if (input > blksize)
-			input = blksize;
-		size -= input;
-		if (!is_zero (uncompressed, input)) {
-			compress(base + curr, &len, uncompressed, input);
-			curr += len;
-		}
-		uncompressed += input;
-
-		if (len > blksize*2) {
-			/* (I don't think this can happen with zlib.) */
-			printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
-			exit(8);
-		}
-
-		*(u32 *) (base + offset) = curr;
-		offset += 4;
-	} while (size);
-
-	curr = (curr + 3) & ~3;
-	new_size = curr - original_offset;
-	/* TODO: Arguably, original_size in these 2 lines should be
-	   st_blocks * 512.  But if you say that then perhaps
-	   administrative data should also be included in both. */
-	change = new_size - original_size;
-	printf("%6.2f%% (%+d bytes)\t%s\n",
-	       (change * 100) / (double) original_size, change, name);
-
-	return curr;
-}
-
-
-/*
- * Traverse the entry tree, writing data for every item that has
- * non-null entry->compressed (i.e. every symlink and non-empty
- * regfile).
- */
-static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
-{
-	do {
-		if (entry->uncompressed) {
-                        if(entry->same) {
-                                set_data_offset(entry, base, entry->same->offset);
-                                entry->offset=entry->same->offset;
-                        } else {
-                                set_data_offset(entry, base, offset);
-                                entry->offset=offset;
-                                offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
-                        }
-		}
-		else if (entry->child)
-			offset = write_data(entry->child, base, offset);
-                entry=entry->next;
-	} while (entry);
-	return offset;
-}
-
-static unsigned int write_file(char *file, char *base, unsigned int offset)
-{
-	int fd;
-	char *buf;
-
-	fd = open(file, O_RDONLY);
-	if (fd < 0) {
-		perror(file);
-		exit(8);
-	}
-	buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
-	memcpy(base + offset, buf, image_length);
-	munmap(buf, image_length);
-	close (fd);
-	/* Pad up the image_length to a 4-byte boundary */
-	while (image_length & 3) {
-		*(base + offset + image_length) = '\0';
-		image_length++;
-	}
-	return (offset + image_length);
-}
-
-/*
- * Maximum size fs you can create is roughly 256MB.  (The last file's
- * data must begin within 256MB boundary but can extend beyond that.)
- *
- * Note that if you want it to fit in a ROM then you're limited to what the
- * hardware and kernel can support (64MB?).
- */
-#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \
-		  + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
-		  + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
-
-
-/*
- * Usage:
- *
- *      mkcramfs directory-name outfile
- *
- * where "directory-name" is simply the root of the directory
- * tree that we want to generate a compressed filesystem out
- * of.
- */
-int main(int argc, char **argv)
-{
-	struct stat st;		/* used twice... */
-	struct entry *root_entry;
-	char *rom_image;
-	ssize_t offset, written;
-	int fd;
-	/* initial guess (upper-bound) of required filesystem size */
-	loff_t fslen_ub = sizeof(struct cramfs_super);
-	char const *dirname, *outfile;
-	u32 crc = crc32(0L, Z_NULL, 0);
-	int c;			/* for getopt */
-
-	total_blocks = 0;
-
-	if (argc)
-		progname = argv[0];
-
-	/* command line options */
-	while ((c = getopt(argc, argv, "hEe:i:n:psz")) != EOF) {
-		switch (c) {
-		case 'h':
-			usage(0);
-		case 'E':
-			opt_errors = 1;
-			break;
-		case 'e':
-			opt_edition = atoi(optarg);
-			break;
-		case 'i':
-			opt_image = optarg;
-			if (lstat(opt_image, &st) < 0) {
-				perror(opt_image);
-				exit(16);
-			}
-			image_length = st.st_size; /* may be padded later */
-			fslen_ub += (image_length + 3); /* 3 is for padding */
-			break;
-		case 'n':
-			opt_name = optarg;
-			break;
-		case 'p':
-			opt_pad = PAD_SIZE;
-			fslen_ub += PAD_SIZE;
-			break;
-		case 's':
-			/* old option, ignored */
-			break;
-		case 'z':
-			opt_holes = 1;
-			break;
-		}
-	}
-
-	if ((argc - optind) != 2)
-		usage(16);
-	dirname = argv[optind];
-	outfile = argv[optind + 1];
-
-	if (stat(dirname, &st) < 0) {
-		perror(dirname);
-		exit(16);
-	}
-	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-
-	root_entry = calloc(1, sizeof(struct entry));
-	if (!root_entry) {
-		perror(NULL);
-		exit(8);
-	}
-	root_entry->mode = st.st_mode;
-	root_entry->uid = st.st_uid;
-	root_entry->gid = st.st_gid;
-
-	root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
-
-	/* always allocate a multiple of blksize bytes because that's
-           what we're going to write later on */
-	fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
-
-	if (fslen_ub > MAXFSLEN) {
-		fprintf(stderr,
-			"warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB.  We might die prematurely.\n",
-			fslen_ub >> 20,
-			MAXFSLEN >> 20);
-		fslen_ub = MAXFSLEN;
-	}
-
-        /* find duplicate files. TODO: uses the most inefficient algorithm
-           possible. */
-        eliminate_doubles(root_entry,root_entry);
-
-	/* TODO: Why do we use a private/anonymous mapping here
-           followed by a write below, instead of just a shared mapping
-           and a couple of ftruncate calls?  Is it just to save us
-           having to deal with removing the file afterwards?  If we
-           really need this huge anonymous mapping, we ought to mmap
-           in smaller chunks, so that the user doesn't need nn MB of
-           RAM free.  If the reason is to be able to write to
-           un-mmappable block devices, then we could try shared mmap
-           and revert to anonymous mmap if the shared mmap fails. */
-	rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
-	if (-1 == (int) (long) rom_image) {
-		perror("ROM image map");
-		exit(8);
-	}
-
-	/* Skip the first opt_pad bytes for boot loader code */
-	offset = opt_pad;
-	memset(rom_image, 0x00, opt_pad);
-
-	/* Skip the superblock and come back to write it later. */
-	offset += sizeof(struct cramfs_super);
-
-	/* Insert a file image. */
-	if (opt_image) {
-		printf("Including: %s\n", opt_image);
-		offset = write_file(opt_image, rom_image, offset);
-	}
-
-	offset = write_directory_structure(root_entry->child, rom_image, offset);
-	printf("Directory data: %d bytes\n", offset);
-
-	offset = write_data(root_entry, rom_image, offset);
-
-	/* We always write a multiple of blksize bytes, so that
-           losetup works. */
-	offset = ((offset - 1) | (blksize - 1)) + 1;
-	printf("Everything: %d kilobytes\n", offset >> 10);
-
-	/* Write the superblock now that we can fill in all of the fields. */
-	write_superblock(root_entry, rom_image+opt_pad, offset);
-	printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
-
-	/* Put the checksum in. */
-	crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
-	((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
-	printf("CRC: %x\n", crc);
-
-	/* Check to make sure we allocated enough space. */
-	if (fslen_ub < offset) {
-		fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n",
-			fslen_ub, offset);
-		exit(8);
-	}
-
-	written = write(fd, rom_image, offset);
-	if (written < 0) {
-		perror("ROM image");
-		exit(8);
-	}
-	if (offset != written) {
-		fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
-		exit(8);
-	}
-
-	/* (These warnings used to come at the start, but they scroll off the
-           screen too quickly.) */
-	if (warn_namelen) /* (can't happen when reading from ext2fs) */
-		fprintf(stderr, /* bytes, not chars: think UTF8. */
-			"warning: filenames truncated to 255 bytes.\n");
-	if (warn_skip)
-		fprintf(stderr, "warning: files were skipped due to errors.\n");
-	if (warn_size)
-		fprintf(stderr,
-			"warning: file sizes truncated to %luMB (minus 1 byte).\n",
-			1L << (CRAMFS_SIZE_WIDTH - 20));
-	if (warn_uid) /* (not possible with current Linux versions) */
-		fprintf(stderr,
-			"warning: uids truncated to %u bits.  (This may be a security concern.)\n",
-			CRAMFS_UID_WIDTH);
-	if (warn_gid)
-		fprintf(stderr,
-			"warning: gids truncated to %u bits.  (This may be a security concern.)\n",
-			CRAMFS_GID_WIDTH);
-	if (warn_dev)
-		fprintf(stderr,
-			"WARNING: device numbers truncated to %u bits.  This almost certainly means\n"
-			"that some device files will be wrong.\n",
-			CRAMFS_OFFSET_WIDTH);
-	if (opt_errors &&
-	    (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev))
-		exit(8);
-	return 0;
-}
diff -urN linux-2.5.6-pre3/sound/Config.help linux-2.5.6/sound/Config.help
--- linux-2.5.6-pre3/sound/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/Config.help	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,7 @@
+CONFIG_SOUND_PRIME
+  Say 'Y' or 'M' to enable Open Sound System drivers.
+
+CONFIG_SOUND_SND
+  Say 'Y' or 'M' to enable Advanced Linux Sound Architecture (ALSA) drivers.
+  You need to install also alsa-lib and alsa-utils packages available on
+  the ALSA website at <http://www.alsa-project.org>.
diff -urN linux-2.5.6-pre3/sound/core/Config.help linux-2.5.6/sound/core/Config.help
--- linux-2.5.6-pre3/sound/core/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/Config.help	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,40 @@
+CONFIG_SND_SEQUENCER
+  Say 'Y' or 'M' to enable MIDI sequencer and router support. This feature
+  allows routing and enqueing MIDI events. Events can be processed at given
+  time.
+
+CONFIG_SND_SEQ_DUMMY
+  Say 'Y' or 'M' to enable dummy sequencer client. This client is a simple
+  midi-through client. All normal input events are redirected to output port
+  immediately.
+
+CONFIG_SND_OSSEMUL
+  Say 'Y' to enable OSS (Open Sound System) API emulation code.
+
+CONFIG_SND_MIXER_OSS
+  Say 'Y' or 'M' to enable mixer OSS API emulation (/dev/mixer*).
+
+CONFIG_SND_PCM_OSS
+  Say 'Y' or 'M' to enable digital audio (PCM) OSS API emulation (/dev/dsp*).
+
+CONFIG_SND_SEQUENCER_OSS
+  Say 'Y' or 'M' to enable OSS sequencer emulation (both /dev/sequencer and
+  /dev/music interfaces).
+
+CONFIG_SND_RTCTIMER
+  Say 'Y' or 'M' to enable RTC timer support for ALSA. ALSA code uses RTC
+  timer as precise timing source and maps the RTC timer to the ALSA's timer
+  interface. ALSA sequencer code can also use this timing source.
+
+CONFIG_SND_VERBOSE_PRINTK
+  Say 'Y' to enable verbose log messages. These messages will help to
+  identify source file and position containing printed messages.
+
+CONFIG_SND_DEBUG
+  Say 'Y' to enable ALSA debug code.
+
+CONFIG_SND_DEBUG_MEMORY
+  Say 'Y' to enable debugging of memory allocation.
+
+CONFIG_SND_DEBUG_DETECTION
+  Say 'Y' to enable debugging of hardware detection.
diff -urN linux-2.5.6-pre3/sound/core/Config.in linux-2.5.6/sound/core/Config.in
--- linux-2.5.6-pre3/sound/core/Config.in	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/Config.in	Thu Mar  7 18:24:56 2002
@@ -1,5 +1,14 @@
 # ALSA soundcard-configuration
 
+if [ "$CONFIG_X86_64" = "y" -a "$CONFIG_IA32_EMULATION" = "y" ]; then
+  dep_tristate '  Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
+if [ "$CONFIG_PPC64" = "y" ]; then
+  dep_tristate '  Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
+if [ "$CONFIG_SPARC64" = "y" ]; then
+  dep_tristate '  Emulation for 32-bit applications' CONFIG_SND_BIT32_EMUL
+fi
 dep_tristate '  Sequencer support' CONFIG_SND_SEQUENCER $CONFIG_SND
 if [ "$CONFIG_SND_SEQUENCER" != "n" ]; then
   dep_tristate '  Sequencer dummy client' CONFIG_SND_SEQ_DUMMY $CONFIG_SND_SEQUENCER
diff -urN linux-2.5.6-pre3/sound/core/Makefile linux-2.5.6/sound/core/Makefile
--- linux-2.5.6-pre3/sound/core/Makefile	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/Makefile	Thu Mar  7 18:24:56 2002
@@ -45,6 +45,11 @@
 
 obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o
 
+subdir-$(CONFIG_SND_BIT32_EMUL) += ioctl32
+ifeq ($(CONFIG_SND_BIT32_EMUL),y)
+  obj-y += ioctl32/_ioctl32.o
+endif
+
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd.o
 obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o
@@ -72,8 +77,8 @@
 obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
-obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
-obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-hwdep.o snd-rawmidi.o
+obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
+obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
@@ -85,7 +90,7 @@
 obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
-obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
 obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
@@ -100,6 +105,10 @@
 obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
 obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
 obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd.o
+ifeq ($(CONFIG_SND_SB16_CSP),y)
+  obj-$(CONFIG_SND_SB16) += snd-hwdep.o
+  obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o
+endif
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.5.6-pre3/sound/core/info.c linux-2.5.6/sound/core/info.c
--- linux-2.5.6-pre3/sound/core/info.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/info.c	Thu Mar  7 18:24:56 2002
@@ -24,12 +24,12 @@
 #include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/time.h>
+#include <linux/smp_lock.h>
 #include <sound/core.h>
 #include <sound/minors.h>
 #include <sound/info.h>
 #include <sound/version.h>
 #include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
 #endif
@@ -55,7 +55,7 @@
 		"memdebug",
 		"detect",
 		"devices",
-		"oss-devices",
+		"oss",
 		"cards",
 		"timers",
 		"synth",
@@ -124,6 +124,9 @@
 struct proc_dir_entry *snd_proc_root = NULL;
 struct proc_dir_entry *snd_proc_dev = NULL;
 snd_info_entry_t *snd_seq_root = NULL;
+#ifdef CONFIG_SND_OSSEMUL
+snd_info_entry_t *snd_oss_root = NULL;
+#endif
 
 #ifdef LINUX_2_2
 static void snd_info_fill_inode(struct inode *inode, int fill)
@@ -163,11 +166,13 @@
 {
 	snd_info_private_data_t *data;
 	struct snd_info_entry *entry;
-	int ret = -EINVAL;
+	loff_t ret;
 
 	data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO);
 	entry = data->entry;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
 	lock_kernel();
+#endif
 	switch (entry->content) {
 	case SNDRV_INFO_CONTENT_TEXT:
 		switch (orig) {
@@ -181,6 +186,7 @@
 			goto out;
 		case 2:	/* SEEK_END */
 		default:
+			ret = -EINVAL;
 			goto out;
 		}
 		break;
@@ -195,7 +201,9 @@
 	}
 	ret = -ENXIO;
 out:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3)
 	unlock_kernel();
+#endif
 	return ret;
 }
 
@@ -623,6 +631,19 @@
 	if (p == NULL)
 		return -ENOMEM;
 	snd_proc_dev = p;
+#ifdef CONFIG_SND_OSSEMUL
+	{
+		snd_info_entry_t *entry;
+		if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
+			return -ENOMEM;
+		entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		if (snd_info_register(entry) < 0) {
+			snd_info_free_entry(entry);
+			return -ENOMEM;
+		}
+		snd_oss_root = entry;
+	}
+#endif
 #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 	{
 		snd_info_entry_t *entry;
@@ -664,6 +685,10 @@
 		if (snd_seq_root)
 			snd_info_unregister(snd_seq_root);
 #endif
+#ifdef CONFIG_SND_OSSEMUL
+		if (snd_oss_root)
+			snd_info_unregister(snd_oss_root);
+#endif
 		snd_remove_proc_entry(snd_proc_root, snd_proc_dev);
 		snd_remove_proc_entry(&proc_root, snd_proc_root);
 	}
diff -urN linux-2.5.6-pre3/sound/core/info_oss.c linux-2.5.6/sound/core/info_oss.c
--- linux-2.5.6-pre3/sound/core/info_oss.c	Tue Feb 19 18:10:56 2002
+++ linux-2.5.6/sound/core/info_oss.c	Thu Mar  7 18:24:56 2002
@@ -114,7 +114,7 @@
 	snd_info_entry_t *entry;
 
 	memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
-	if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", NULL)) != NULL) {
+	if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
 		entry->content = SNDRV_INFO_CONTENT_TEXT;
 		entry->c.text.read_size = 2048;
 		entry->c.text.read = snd_sndstat_proc_read;
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/Makefile linux-2.5.6/sound/core/ioctl32/Makefile
--- linux-2.5.6-pre3/sound/core/ioctl32/Makefile	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/Makefile	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,17 @@
+#
+# Makefile for ALSA
+# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+#
+
+O_TARGET     := _ioctl32.o
+
+list-multi   := snd-ioctl32.o
+
+snd-ioctl32-objs := ioctl32.o pcm32.o rawmidi32.o timer32.o hwdep32.o
+
+obj-$(CONFIG_SND_BIT32_EMUL) += snd-ioctl32.o
+
+include $(TOPDIR)/Rules.make
+
+snd-ioctl32.o: $(snd-ioctl32-objs)
+	$(LD) $(LD_RFLAG) -r -o $@ $(snd-ioctl32-objs)
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/hwdep32.c linux-2.5.6/sound/core/ioctl32/hwdep32.c
--- linux-2.5.6-pre3/sound/core/ioctl32/hwdep32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/hwdep32.c	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,37 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for timer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper hwdep_mappers[] = {
+	{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
+	{ SNDRV_HWDEP_IOCTL_INFO, NULL },
+	{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
+	{ 0 },
+};
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/ioctl32.c linux-2.5.6/sound/core/ioctl32/ioctl32.c
--- linux-2.5.6-pre3/sound/core/ioctl32/ioctl32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/ioctl32.c	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,357 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for control API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/smp_lock.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+/*
+ * register/unregister mappers
+ * exported for other modules
+ */
+
+int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
+int unregister_ioctl32_conversion(unsigned int cmd);
+
+
+int snd_ioctl32_register(struct ioctl32_mapper *mappers)
+{
+	int err;
+	struct ioctl32_mapper *m;
+
+	lock_kernel();
+	for (m = mappers; m->cmd; m++) {
+		err = register_ioctl32_conversion(m->cmd, m->handler);
+		if (err < 0) {
+			unlock_kernel();
+			return err;
+		}
+		m->registered++;
+	}
+	return 0;
+}
+
+void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
+{
+	struct ioctl32_mapper *m;
+
+	lock_kernel();
+	for (m = mappers; m->cmd; m++) {
+		if (m->registered) {
+			unregister_ioctl32_conversion(m->cmd);
+			m->registered = 0;
+		}
+	}
+	unlock_kernel();
+}
+
+
+/*
+ * Controls
+ */
+
+struct sndrv_ctl_elem_list32 {
+	u32 offset;
+	u32 space;
+	u32 used;
+	u32 count;
+	u32 pids;
+	unsigned char reserved[50];
+};
+
+#define CVT_sndrv_ctl_elem_list()\
+{\
+	COPY(offset);\
+	COPY(space);\
+	COPY(used);\
+	COPY(count);\
+	CPTR(pids);\
+}
+
+DEFINE_ALSA_IOCTL(ctl_elem_list);
+
+
+/*
+ * control element info
+ * it uses union, so the things are not easy..
+ */
+
+struct sndrv_ctl_elem_info32 {
+	struct sndrv_ctl_elem_id id; // the size of struct is same
+	s32 type;
+	u32 access;
+	u32 count;
+	s32 owner;
+	union {
+		struct {
+			s32 min;
+			s32 max;
+			s32 step;
+		} integer;
+		struct {
+			u32 items;
+			u32 item;
+			char name[64];
+		} enumerated;
+		unsigned char reserved[128];
+	} value;
+	unsigned char reserved[64];
+};
+
+static int snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+	struct sndrv_ctl_elem_info data;
+	struct sndrv_ctl_elem_info32 data32;
+	int err;
+
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
+	memset(&data, 0, sizeof(data));
+	data.id = data32.id;
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+	if (err < 0)
+		return err;
+	/* restore info to 32bit */
+	data32.type = data.type;
+	data32.access = data.access;
+	data32.count = data.count;
+	data32.owner = data.owner;
+	switch (data.type) {
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		data32.value.integer.min = data.value.integer.min;
+		data32.value.integer.max = data.value.integer.min;
+		data32.value.integer.step = data.value.integer.step;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+		data32.value.enumerated.items = data.value.enumerated.items;
+		data32.value.enumerated.item = data.value.enumerated.item;
+		memcpy(data32.value.enumerated.name, data.value.enumerated.name,
+		       sizeof(data.value.enumerated.name));
+		break;
+	default:
+		break;
+	}
+	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+		return -EFAULT;
+	return err;
+}
+
+
+struct sndrv_ctl_elem_value32 {
+	struct sndrv_ctl_elem_id id;
+	unsigned int indirect: 1;
+        union {
+		union {
+			s32 value[128];
+			u32 value_ptr;
+		} integer;
+		union {
+			u32 item[128];
+			u32 item_ptr;
+		} enumerated;
+		union {
+			unsigned char data[512];
+			u32 data_ptr;
+		} bytes;
+		struct sndrv_aes_iec958 iec958;
+        } value;
+        unsigned char reserved[128];
+};
+
+
+/* hmm, it's so hard to retrieve the value type from the control id.. */
+static int get_ctl_type(struct file *file, snd_ctl_elem_id_t *id)
+{
+	snd_ctl_file_t *ctl;
+	snd_kcontrol_t *kctl;
+	snd_ctl_elem_info_t info;
+	int err;
+
+	ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+
+	read_lock(&ctl->card->control_rwlock);
+	kctl = snd_ctl_find_id(ctl->card, id);
+	if (! kctl) {
+		read_unlock(&ctl->card->control_rwlock);
+		return -ENXIO;
+	}
+	info.id = *id;
+	err = kctl->info(kctl, &info);
+	if (err >= 0)
+		err = info.type;
+	read_unlock(&ctl->card->control_rwlock);
+	return err;
+}
+
+
+static int snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+	// too big?
+	struct sndrv_ctl_elem_value data;
+	struct sndrv_ctl_elem_value32 data32;
+	int err, i;
+	int type;
+	/* FIXME: check the sane ioctl.. */
+
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
+		return -EFAULT;
+	memset(&data, 0, sizeof(data));
+	data.id = data32.id;
+	data.indirect = data32.indirect;
+	if (data.indirect) /* FIXME: this is not correct for long arrays */
+		data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
+	type = get_ctl_type(file, &data.id);
+	if (type < 0)
+		return type;
+	if (! data.indirect) {
+		switch (type) {
+		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+		case SNDRV_CTL_ELEM_TYPE_INTEGER:
+			for (i = 0; i < 128; i++)
+				data.value.integer.value[i] = data32.value.integer.value[i];
+			break;
+		case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+			for (i = 0; i < 128; i++)
+				data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+			break;
+		case SNDRV_CTL_ELEM_TYPE_BYTES:
+			memcpy(data.value.bytes.data, data32.value.bytes.data,
+			       sizeof(data.value.bytes.data));
+			break;
+		case SNDRV_CTL_ELEM_TYPE_IEC958:
+			data.value.iec958 = data32.value.iec958;
+			break;
+		default:
+			break;
+		}
+	}
+
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);
+	if (err < 0)
+		return err;
+	/* restore info to 32bit */
+	if (! data.indirect) {
+		switch (type) {
+		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+		case SNDRV_CTL_ELEM_TYPE_INTEGER:
+			for (i = 0; i < 128; i++)
+				data.value.integer.value[i] = data32.value.integer.value[i];
+			break;
+		case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
+			for (i = 0; i < 128; i++)
+				data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+			break;
+		case SNDRV_CTL_ELEM_TYPE_BYTES:
+			memcpy(data.value.bytes.data, data32.value.bytes.data,
+			       sizeof(data.value.bytes.data));
+			break;
+		case SNDRV_CTL_ELEM_TYPE_IEC958:
+			data.value.iec958 = data32.value.iec958;
+			break;
+		default:
+			break;
+		}
+	}
+	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
+		return -EFAULT;
+	return err;
+}
+
+
+/*
+ */
+
+#define AP(x) snd_ioctl32_##x
+
+static struct ioctl32_mapper control_mappers[] = {
+	/* controls (without rawmidi, hwdep, timer releated ones) */
+	{ SNDRV_CTL_IOCTL_PVERSION, NULL },
+	{ SNDRV_CTL_IOCTL_CARD_INFO , NULL },
+	{ SNDRV_CTL_IOCTL_ELEM_LIST, AP(ctl_elem_list) },
+	{ SNDRV_CTL_IOCTL_ELEM_INFO, AP(ctl_elem_info) },
+	{ SNDRV_CTL_IOCTL_ELEM_READ, AP(ctl_elem_value) },
+	{ SNDRV_CTL_IOCTL_ELEM_WRITE, AP(ctl_elem_value) },
+	{ SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
+	{ SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
+	{ SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
+	{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
+	{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_POWER, NULL },
+	{ SNDRV_CTL_IOCTL_POWER_STATE, NULL },
+	{ 0 }
+};
+
+
+/*
+ */
+
+extern struct ioctl32_mapper pcm_mappers[];
+extern struct ioctl32_mapper rawmidi_mappers[];
+extern struct ioctl32_mapper timer_mappers[];
+extern struct ioctl32_mapper hwdep_mappers[];
+
+static void snd_ioctl32_done(void)
+{
+	snd_ioctl32_unregister(hwdep_mappers);
+	snd_ioctl32_unregister(timer_mappers);
+	snd_ioctl32_unregister(rawmidi_mappers);
+	snd_ioctl32_unregister(pcm_mappers);
+	snd_ioctl32_unregister(control_mappers);
+}
+
+static int __init snd_ioctl32_init(void)
+{
+	int err;
+	
+	err = snd_ioctl32_register(control_mappers);
+	if (err < 0)
+		return err;
+	err = snd_ioctl32_register(pcm_mappers);
+	if (err < 0) {
+		snd_ioctl32_done();
+		return err;
+	}
+	err = snd_ioctl32_register(rawmidi_mappers);
+	if (err < 0) {
+		snd_ioctl32_done();
+		return err;
+	}
+	err = snd_ioctl32_register(timer_mappers);
+	if (err < 0) {
+		snd_ioctl32_done();
+		return err;
+	}
+	err = snd_ioctl32_register(hwdep_mappers);
+	if (err < 0) {
+		snd_ioctl32_done();
+		return err;
+	}
+}
+
+module_init(snd_ioctl32_init)
+module_exit(snd_ioctl32_done)
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/ioctl32.h linux-2.5.6/sound/core/ioctl32/ioctl32.h
--- linux-2.5.6-pre3/sound/core/ioctl32/ioctl32.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/ioctl32.h	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,79 @@
+/*
+ *   32bit -> 64bit ioctl helpers
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *
+ * This file registers the converters from 32-bit ioctls to 64-bit ones.
+ * The converter assumes that a 32-bit user-pointer can be casted by A(x)
+ * macro to a valid 64-bit pointer which is accessible via copy_from/to_user.
+ *
+ */
+
+#ifndef __ALSA_IOCTL32_H
+#define __ALSA_IOCTL32_H
+
+#define TO_PTR(x)  A(x)
+
+#define COPY(x)  (dst->x = src->x)
+#define CPTR(x)	 (dst->x = (typeof(dst->x))A(src->x))
+
+#define convert_from_32(type, dstp, srcp)\
+{\
+	struct sndrv_##type *dst = dstp;\
+	struct sndrv_##type##32 *src = srcp;\
+	CVT_##sndrv_##type();\
+}
+
+#define convert_to_32(type, dstp, srcp)\
+{\
+	struct sndrv_##type *src = srcp;\
+	struct sndrv_##type##32 *dst = dstp;\
+	CVT_##sndrv_##type();\
+}
+
+
+#define DEFINE_ALSA_IOCTL(type) \
+static int snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)\
+{\
+	struct sndrv_##type##32 data32;\
+	struct sndrv_##type data;\
+	int err;\
+	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
+		return -EFAULT;\
+	memset(&data, 0, sizeof(data));\
+	convert_from_32(type, &data, &data32);\
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, (unsigned long)&data);\
+	if (err < 0)\
+		return err;\
+	if (cmd & (_IOC_READ << _IOC_DIRSHIFT)) {\
+		convert_to_32(type, &data32, &data);\
+		if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
+			return -EFAULT;\
+	}\
+	return err;\
+}
+
+struct ioctl32_mapper {
+	unsigned int cmd;
+	int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp);
+	int registered;
+};
+
+int snd_ioctl32_register(struct ioctl32_mapper *mappers);
+void snd_ioctl32_unregister(struct ioctl32_mapper *mappers);
+
+#endif /* __ALSA_IOCTL32_H */
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/pcm32.c linux-2.5.6/sound/core/ioctl32/pcm32.c
--- linux-2.5.6-pre3/sound/core/ioctl32/pcm32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/pcm32.c	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,296 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for PCM API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include "ioctl32.h"
+
+
+/* wrapper for sndrv_pcm_[us]frames */
+struct sndrv_pcm_sframes_str {
+	sndrv_pcm_sframes_t val;
+};
+struct sndrv_pcm_sframes_str32 {
+	s32 val;
+};
+struct sndrv_pcm_uframes_str {
+	sndrv_pcm_uframes_t val;
+};
+struct sndrv_pcm_uframes_str32 {
+	u32 val;
+};
+
+#define CVT_sndrv_pcm_sframes_str() { COPY(val); }
+#define CVT_sndrv_pcm_uframes_str() { COPY(val); }
+
+
+struct sndrv_interval32 {
+	u32 min, max;
+	unsigned int openmin:1,
+		     openmax:1,
+		     integer:1,
+		     empty:1;
+};
+
+struct sndrv_pcm_hw_params32 {
+	u32 flags;
+	u32 masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
+	struct sndrv_interval32 intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
+	u32 rmask;
+	u32 cmask;
+	u32 info;
+	u32 msbits;
+	u32 rate_num;
+	u32 rate_den;
+	u32 fifo_size;
+	unsigned char reserved[64];
+};
+
+#define numberof(array)  (sizeof(array)/sizeof(array[0]))
+
+#define CVT_sndrv_pcm_hw_params()\
+{\
+	int i;\
+	COPY(flags);\
+	for (i = 0; i < numberof(dst->masks); i++)\
+		COPY(masks[i]);\
+	for (i = 0; i < numberof(dst->intervals); i++) {\
+		COPY(intervals[i].min);\
+		COPY(intervals[i].max);\
+		COPY(intervals[i].openmin);\
+		COPY(intervals[i].openmax);\
+		COPY(intervals[i].integer);\
+		COPY(intervals[i].empty);\
+	}\
+	COPY(rmask);\
+	COPY(cmask);\
+	COPY(info);\
+	COPY(msbits);\
+	COPY(rate_num);\
+	COPY(rate_den);\
+	COPY(fifo_size);\
+}
+
+struct sndrv_pcm_sw_params32 {
+	s32 tstamp_mode;
+	u32 period_step;
+	u32 sleep_min;
+	u32 avail_min;
+	u32 xfer_align;
+	u32 start_threshold;
+	u32 stop_threshold;
+	u32 silence_threshold;
+	u32 silence_size;
+	u32 boundary;
+	unsigned char reserved[64];
+};
+
+#define CVT_sndrv_pcm_sw_params()\
+{\
+	COPY(tstamp_mode);\
+	COPY(period_step);\
+	COPY(sleep_min);\
+	COPY(avail_min);\
+	COPY(xfer_align);\
+	COPY(start_threshold);\
+	COPY(stop_threshold);\
+	COPY(silence_threshold);\
+	COPY(silence_size);\
+	COPY(boundary);\
+}
+
+struct sndrv_pcm_channel_info32 {
+	u32 channel;
+	u32 offset;
+	u32 first;
+	u32 step;
+};
+
+#define CVT_sndrv_pcm_channel_info()\
+{\
+	COPY(channel);\
+	COPY(offset);\
+	COPY(first);\
+	COPY(step);\
+}
+
+struct timeval32 {
+	s32 tv_sec;
+	s32 tv_usec;
+};
+
+struct sndrv_pcm_status32 {
+	s32 state;
+	struct timeval32 trigger_tstamp;
+	struct timeval32 tstamp;
+	u32 appl_ptr;
+	u32 hw_ptr;
+	s32 delay;
+	u32 avail;
+	u32 avail_max;
+	u32 overrange;
+	s32 suspended_state;
+	unsigned char reserved[60];
+};
+
+#define CVT_sndrv_pcm_status()\
+{\
+	COPY(state);\
+	COPY(trigger_tstamp.tv_sec);\
+	COPY(trigger_tstamp.tv_usec);\
+	COPY(tstamp.tv_sec);\
+	COPY(tstamp.tv_usec);\
+	COPY(appl_ptr);\
+	COPY(hw_ptr);\
+	COPY(delay);\
+	COPY(avail);\
+	COPY(avail_max);\
+	COPY(overrange);\
+	COPY(suspended_state);\
+}
+
+struct sndrv_xferi32 {
+	s32 result;
+	u32 buf;
+	u32 frames;
+};
+
+#define CVT_sndrv_xferi()\
+{\
+	COPY(result);\
+	CPTR(buf);\
+	COPY(frames);\
+}
+
+DEFINE_ALSA_IOCTL(pcm_uframes_str);
+DEFINE_ALSA_IOCTL(pcm_sframes_str);
+DEFINE_ALSA_IOCTL(pcm_hw_params);
+DEFINE_ALSA_IOCTL(pcm_sw_params);
+DEFINE_ALSA_IOCTL(pcm_channel_info);
+DEFINE_ALSA_IOCTL(pcm_status);
+DEFINE_ALSA_IOCTL(xferi);
+
+/* snd_xfern needs remapping of bufs */
+struct sndrv_xfern32 {
+	s32 result;
+	u32 bufs;  /* this is void **; */
+	u32 frames;
+};
+
+/*
+ * xfern ioctl nees to copy (up to) 128 pointers on stack.
+ * although we may pass the copied pointers through f_op->ioctl, but the ioctl
+ * handler there expands again the same 128 pointers on stack, so it is better
+ * to handle the function (calling pcm_readv/writev) directly in this handler.
+ */
+static int snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file)
+{
+	snd_pcm_file_t *pcm_file;
+	snd_pcm_substream_t *substream;
+	struct sndrv_xfern32 data32, *srcptr = (struct sndrv_xfern32*)arg;
+	void *bufs[128];
+	int err = 0, ch, i;
+	u32 *bufptr;
+
+	/* FIXME: need to check whether fop->ioctl is sane */
+
+	pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO);
+	substream = pcm_file->substream;
+	snd_assert(substream != NULL && substream->runtime, return -ENXIO);
+
+	/* check validty of the command */
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
+		if (substream->stream  != SNDRV_PCM_STREAM_PLAYBACK)
+			return -EINVAL;
+		if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
+			return -EBADFD;
+	case SNDRV_PCM_IOCTL_READN_FRAMES:
+		if (substream->stream  != SNDRV_PCM_STREAM_CAPTURE)
+			return -EINVAL;
+		break;
+	}
+	if ((ch = substream->runtime->channels) > 128)
+		return -EINVAL;
+	if (get_user(data32.frames, &srcptr->frames))
+		return -EFAULT;
+	__get_user(data32.bufs, &srcptr->bufs);
+	bufptr = (u32*)TO_PTR(data32.bufs);
+	for (i = 0; i < ch; i++) {
+		u32 ptr;
+		if (get_user(ptr, bufptr))
+			return -EFAULT;
+		bufs[ch] = (void*)TO_PTR(ptr);
+		bufptr++;
+	}
+	switch (cmd) {
+	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
+		err = snd_pcm_lib_writev(substream, bufs, data32.frames);
+		break;
+	case SNDRV_PCM_IOCTL_READN_FRAMES:
+		err = snd_pcm_lib_readv(substream, bufs, data32.frames);
+		break;
+	}
+	
+	if (err < 0)
+		return err;
+	if (put_user(err, &srcptr->result))
+		return -EFAULT;
+	return err < 0 ? err : 0;
+}
+
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper pcm_mappers[] = {
+	{ SNDRV_PCM_IOCTL_PVERSION, NULL },
+	{ SNDRV_PCM_IOCTL_INFO, NULL },
+	{ SNDRV_PCM_IOCTL_HW_REFINE, AP(pcm_hw_params) },
+	{ SNDRV_PCM_IOCTL_HW_PARAMS, AP(pcm_hw_params) },
+	{ SNDRV_PCM_IOCTL_HW_FREE, NULL },
+	{ SNDRV_PCM_IOCTL_SW_PARAMS, AP(pcm_sw_params) },
+	{ SNDRV_PCM_IOCTL_STATUS, AP(pcm_status) },
+	{ SNDRV_PCM_IOCTL_DELAY, AP(pcm_sframes_str) },
+	{ SNDRV_PCM_IOCTL_CHANNEL_INFO, AP(pcm_channel_info) },
+	{ SNDRV_PCM_IOCTL_PREPARE, NULL },
+	{ SNDRV_PCM_IOCTL_RESET, NULL },
+	{ SNDRV_PCM_IOCTL_START, NULL },
+	{ SNDRV_PCM_IOCTL_DROP, NULL },
+	{ SNDRV_PCM_IOCTL_DRAIN, NULL },
+	{ SNDRV_PCM_IOCTL_PAUSE, NULL },
+	{ SNDRV_PCM_IOCTL_REWIND, AP(pcm_uframes_str) },
+	{ SNDRV_PCM_IOCTL_RESUME, NULL },
+	{ SNDRV_PCM_IOCTL_XRUN, NULL },
+	{ SNDRV_PCM_IOCTL_WRITEI_FRAMES, AP(xferi) },
+	{ SNDRV_PCM_IOCTL_READI_FRAMES, AP(xferi) },
+	{ SNDRV_PCM_IOCTL_WRITEN_FRAMES, AP(xfern) },
+	{ SNDRV_PCM_IOCTL_READN_FRAMES, AP(xfern) },
+	{ SNDRV_PCM_IOCTL_LINK, NULL },
+	{ SNDRV_PCM_IOCTL_UNLINK, NULL },
+
+	{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
+	{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
+
+	{ 0 },
+};
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/rawmidi32.c linux-2.5.6/sound/core/ioctl32/rawmidi32.c
--- linux-2.5.6-pre3/sound/core/ioctl32/rawmidi32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/rawmidi32.c	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,86 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for raw MIDI API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/rawmidi.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+struct sndrv_rawmidi_params32 {
+	s32 stream;
+	u32 buffer_size;
+	u32 avail_min;
+	unsigned int no_active_sensing: 1;
+	unsigned char reserved[16];
+};
+
+#define CVT_sndrv_rawmidi_params()\
+{\
+	COPY(stream);\
+	COPY(buffer_size);\
+	COPY(avail_min);\
+	COPY(no_active_sensing);\
+}
+
+struct timeval32 {
+	s32 tv_sec;
+	s32 tv_usec;
+};
+
+struct sndrv_rawmidi_status32 {
+	s32 stream;
+	struct timeval32 tstamp;
+	u32 avail;
+	u32 xruns;
+	unsigned char reserved[16];
+};
+
+#define CVT_sndrv_rawmidi_status()\
+{\
+	COPY(stream);\
+	COPY(tstamp.tv_sec);\
+	COPY(tstamp.tv_usec);\
+	COPY(avail);\
+	COPY(xruns);\
+}
+
+DEFINE_ALSA_IOCTL(rawmidi_params);
+DEFINE_ALSA_IOCTL(rawmidi_status);
+
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper rawmidi_mappers[] = {
+	{ SNDRV_RAWMIDI_IOCTL_PVERSION, NULL },
+	{ SNDRV_RAWMIDI_IOCTL_INFO, NULL },
+	{ SNDRV_RAWMIDI_IOCTL_PARAMS, AP(rawmidi_params) },
+	{ SNDRV_RAWMIDI_IOCTL_STATUS, AP(rawmidi_status) },
+	{ SNDRV_RAWMIDI_IOCTL_DROP, NULL },
+	{ SNDRV_RAWMIDI_IOCTL_DRAIN, NULL },
+
+	{ SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE, NULL },
+	{ SNDRV_CTL_IOCTL_RAWMIDI_INFO, NULL },
+	{ SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, NULL },
+
+	{ 0 },
+};
diff -urN linux-2.5.6-pre3/sound/core/ioctl32/timer32.c linux-2.5.6/sound/core/ioctl32/timer32.c
--- linux-2.5.6-pre3/sound/core/ioctl32/timer32.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/core/ioctl32/timer32.c	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,93 @@
+/*
+ *   32bit -> 64bit ioctl wrapper for timer API
+ *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+#define __NO_VERSION__
+#include <sound/driver.h>
+#include <linux/time.h>
+#include <sound/core.h>
+#include <sound/timer.h>
+#include <asm/uaccess.h>
+#include "ioctl32.h"
+
+struct sndrv_timer_info32 {
+	u32 flags;
+	s32 card;
+	unsigned char id[64];
+	unsigned char name[80];
+	u32 ticks;
+	u32 resolution;
+	unsigned char reserved[64];
+};
+
+#define CVT_sndrv_timer_info()\
+{\
+	COPY(flags);\
+	COPY(card);\
+	memcpy(dst->id, src->id, sizeof(src->id));\
+	memcpy(dst->name, src->name, sizeof(src->name));\
+	COPY(ticks);\
+	COPY(resolution);\
+}
+
+struct timeval32 {
+	s32 tv_sec;
+	s32 tv_usec;
+};
+
+struct sndrv_timer_status32 {
+	struct timeval32 tstamp;
+	u32 resolution;
+	u32 lost;
+	u32 overrun;
+	u32 queue;
+	unsigned char reserved[64];
+};
+
+#define CVT_sndrv_timer_status()\
+{\
+	COPY(tstamp.tv_sec);\
+	COPY(tstamp.tv_usec);\
+	COPY(resolution);\
+	COPY(lost);\
+	COPY(overrun);\
+	COPY(queue);\
+}
+
+DEFINE_ALSA_IOCTL(timer_info);
+DEFINE_ALSA_IOCTL(timer_status);
+
+
+/*
+ */
+
+#define AP(x) snd_ioctl32_##x
+
+struct ioctl32_mapper timer_mappers[] = {
+	{ SNDRV_TIMER_IOCTL_PVERSION, NULL },
+	{ SNDRV_TIMER_IOCTL_NEXT_DEVICE, NULL },
+	{ SNDRV_TIMER_IOCTL_SELECT, NULL },
+	{ SNDRV_TIMER_IOCTL_INFO, AP(timer_info) },
+	{ SNDRV_TIMER_IOCTL_PARAMS, NULL },
+	{ SNDRV_TIMER_IOCTL_STATUS, AP(timer_status) },
+	{ SNDRV_TIMER_IOCTL_START, NULL },
+	{ SNDRV_TIMER_IOCTL_STOP, NULL },
+	{ SNDRV_TIMER_IOCTL_CONTINUE, NULL },
+	{ 0 },
+};
diff -urN linux-2.5.6-pre3/sound/core/oss/pcm_oss.c linux-2.5.6/sound/core/oss/pcm_oss.c
--- linux-2.5.6-pre3/sound/core/oss/pcm_oss.c	Tue Feb 19 18:10:59 2002
+++ linux-2.5.6/sound/core/oss/pcm_oss.c	Thu Mar  7 18:24:56 2002
@@ -516,7 +516,6 @@
 snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	mm_segment_t fs;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -525,11 +524,14 @@
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel)
+		if (in_kernel) {
+			mm_segment_t fs;
 			fs = snd_enter_user();
-		ret = snd_pcm_lib_write(substream, ptr, frames);
-		if (in_kernel)
+			ret = snd_pcm_lib_write(substream, ptr, frames);
 			snd_leave_user(fs);
+		} else {
+			ret = snd_pcm_lib_write(substream, ptr, frames);
+		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 		/* test, if we can't store new data, because the stream */
@@ -543,7 +545,6 @@
 snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	mm_segment_t fs;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -556,11 +557,15 @@
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel)
-			fs = snd_enter_user();
 		ret = snd_pcm_lib_read(substream, ptr, frames);
-		if (in_kernel)
+		if (in_kernel) {
+			mm_segment_t fs;
+			fs = snd_enter_user();
+			ret = snd_pcm_lib_read(substream, ptr, frames);
 			snd_leave_user(fs);
+		} else {
+			ret = snd_pcm_lib_read(substream, ptr, frames);
+		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 	}
@@ -570,7 +575,6 @@
 snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	mm_segment_t fs;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -579,13 +583,17 @@
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel)
+		if (in_kernel) {
+			mm_segment_t fs;
 			fs = snd_enter_user();
-		ret = snd_pcm_lib_writev(substream, bufs, frames);
-		if (in_kernel)
+			ret = snd_pcm_lib_writev(substream, bufs, frames);
 			snd_leave_user(fs);
+		} else {
+			ret = snd_pcm_lib_writev(substream, bufs, frames);
+		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
+
 		/* test, if we can't store new data, because the stream */
 		/* has not been started */
 		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
@@ -597,7 +605,6 @@
 snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	mm_segment_t fs;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -610,11 +617,14 @@
 			if (ret < 0)
 				break;
 		}
-		if (in_kernel)
+		if (in_kernel) {
+			mm_segment_t fs;
 			fs = snd_enter_user();
-		ret = snd_pcm_lib_readv(substream, bufs, frames);
-		if (in_kernel)
+			ret = snd_pcm_lib_readv(substream, bufs, frames);
 			snd_leave_user(fs);
+		} else {
+			ret = snd_pcm_lib_readv(substream, bufs, frames);
+		}
 		if (ret != -EPIPE && ret != -ESTRPIPE)
 			break;
 	}
diff -urN linux-2.5.6-pre3/sound/core/rtctimer.c linux-2.5.6/sound/core/rtctimer.c
--- linux-2.5.6-pre3/sound/core/rtctimer.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/rtctimer.c	Thu Mar  7 18:24:56 2002
@@ -18,19 +18,12 @@
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
- * 
- *================================================================
- * For enabling this timer, apply the patch file to your kernel.
- * The configure script checks the patch automatically.
- * The patches, rtc-xxx.dif, are found under utils/patches, where
- * xxx is the kernel version.
- *================================================================
- *
  */
 
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/time.h>
+#include <linux/interrupt.h>
 #include <sound/core.h>
 #include <sound/timer.h>
 #include <sound/info.h>
@@ -59,7 +52,7 @@
 
 
 /*
- * The harware depenant description for this timer.
+ * The hardware dependent description for this timer.
  */
 static struct _snd_timer_hardware rtc_hw = {
 	flags:		SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
@@ -72,7 +65,7 @@
 
 int rtctimer_freq = RTC_FREQ;		/* frequency */
 static snd_timer_t *rtctimer;
-static volatile int rtc_inc = 0;
+static atomic_t rtc_inc = ATOMIC_INIT(0);
 static rtc_task_t rtc_task;
 
 /* tasklet */
@@ -83,6 +76,10 @@
 static int
 rtctimer_open(snd_timer_t *t)
 {
+	err = rtc_register(&rtc_task);
+	if (err < 0)
+		return err;
+	t->private_data = &rtc_task;
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -90,6 +87,11 @@
 static int
 rtctimer_close(snd_timer_t *t)
 {
+	rtc_task_t *rtc = t->private_data;
+	if (rtc) {
+		rtc_unregister(rtc);
+		t->private_data = NULL;
+	}
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -101,7 +103,7 @@
 	snd_assert(rtc != NULL, return -EINVAL);
 	rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
 	rtc_control(rtc, RTC_PIE_ON, 0);
-	rtc_inc = 0;
+	atomic_set(&rtc_inc, 0);
 	return 0;
 }
 
@@ -119,12 +121,15 @@
  */
 static void rtctimer_interrupt(void *private_data)
 {
-	rtc_inc++;
+	atomic_inc(&rtc_inc);
 #ifdef USE_TASKLET
 	tasklet_hi_schedule(&rtc_tq);
 #else
-	snd_timer_interrupt((snd_timer_t*)private_data, rtc_inc);
-	rtc_inc = 0;
+	{
+		int ticks = atomic_read(&rtc_inc);
+		snd_timer_interrupt((snd_timer_t*)private_data, ticks);
+		atomic_sub(ticks, &rtc_inc);
+	}
 #endif /* USE_TASKLET */
 }
 
@@ -132,20 +137,16 @@
 static void rtctimer_interrupt2(unsigned long private_data)
 {
 	snd_timer_t *timer = (snd_timer_t *)private_data;
+	int ticks;
+
 	snd_assert(timer != NULL, return);
 	do {
-		snd_timer_interrupt(timer, 1);
-	} while (--rtc_inc > 0);
+		ticks = atomic_read(&rtc_inc);
+		snd_timer_interrupt(timer, ticks);
+	} while (!atomic_sub_and_test(ticks, &rtc_inc));
 }
 #endif /* USE_TASKLET */
 
-static void rtctimer_private_free(snd_timer_t *timer)
-{
-	rtc_task_t *rtc = timer->private_data;
-	if (rtc)
-		rtc_unregister(rtc);
-}
-
 
 /*
  *  ENTRY functions
@@ -179,23 +180,16 @@
 	timer->hw = rtc_hw;
 	timer->hw.resolution = NANO_SEC / rtctimer_freq;
 
-	/* register RTC callback */
+	/* set up RTC callback */
 	rtc_task.func = rtctimer_interrupt;
 	rtc_task.private_data = timer;
-	err = rtc_register(&rtc_task);
-	if (err < 0) {
-		snd_timer_global_free(timer);
-		return err;
-	}
-	timer->private_data = &rtc_task;
-	timer->private_free = rtctimer_private_free;
 
 	err = snd_timer_global_register(timer);
 	if (err < 0) {
 		snd_timer_global_free(timer);
 		return err;
 	}
-	rtctimer = timer;
+	rtctimer = timer; /* remember this */
 
 	return 0;
 }
@@ -210,7 +204,7 @@
 
 
 /*
- * exported stuffs
+ * exported stuff
  */
 module_init(rtctimer_init)
 module_exit(rtctimer_exit)
diff -urN linux-2.5.6-pre3/sound/core/seq/Makefile linux-2.5.6/sound/core/seq/Makefile
--- linux-2.5.6-pre3/sound/core/seq/Makefile	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/seq/Makefile	Thu Mar  7 18:24:56 2002
@@ -72,6 +72,7 @@
 obj-$(CONFIG_SND_ES1968) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
 obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
 obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
diff -urN linux-2.5.6-pre3/sound/core/seq/seq_midi_event.c linux-2.5.6/sound/core/seq/seq_midi_event.c
--- linux-2.5.6-pre3/sound/core/seq/seq_midi_event.c	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/sound/core/seq/seq_midi_event.c	Thu Mar  7 18:24:56 2002
@@ -68,8 +68,8 @@
 	event_decode_t decode;
 } status_event[] = {
 	/* 0x80 - 0xf0 */
-	{SNDRV_SEQ_EVENT_NOTEOFF,		2, note_event, note_decode},
-	{SNDRV_SEQ_EVENT_NOTEON,		2, note_event, note_decode},
+	{SNDRV_SEQ_EVENT_NOTEOFF,	2, note_event, note_decode},
+	{SNDRV_SEQ_EVENT_NOTEON,	2, note_event, note_decode},
 	{SNDRV_SEQ_EVENT_KEYPRESS,	2, note_event, note_decode},
 	{SNDRV_SEQ_EVENT_CONTROLLER,	2, two_param_ctrl_event, two_param_decode},
 	{SNDRV_SEQ_EVENT_PGMCHANGE,	1, one_param_ctrl_event, one_param_decode},
@@ -78,9 +78,9 @@
 	{SNDRV_SEQ_EVENT_NONE,		0, NULL, NULL}, /* 0xf0 */
 	/* 0xf0 - 0xff */
 	{SNDRV_SEQ_EVENT_SYSEX,		1, NULL, NULL}, /* sysex: 0xf0 */
-	{SNDRV_SEQ_EVENT_QFRAME,		1, one_param_event, one_param_decode}, /* 0xf1 */
-	{SNDRV_SEQ_EVENT_SONGPOS,		2, songpos_event, songpos_decode}, /* 0xf2 */
-	{SNDRV_SEQ_EVENT_SONGSEL,		1, one_param_event, one_param_decode}, /* 0xf3 */
+	{SNDRV_SEQ_EVENT_QFRAME,	1, one_param_event, one_param_decode}, /* 0xf1 */
+	{SNDRV_SEQ_EVENT_SONGPOS,	2, songpos_event, songpos_decode}, /* 0xf2 */
+	{SNDRV_SEQ_EVENT_SONGSEL,	1, one_param_event, one_param_decode}, /* 0xf3 */
 	{SNDRV_SEQ_EVENT_NONE,		0, NULL, NULL}, /* 0xf4 */
 	{SNDRV_SEQ_EVENT_NONE,		0, NULL, NULL}, /* 0xf5 */
 	{SNDRV_SEQ_EVENT_TUNE_REQUEST,	0, NULL, NULL},	/* 0xf6 */
@@ -92,7 +92,7 @@
 	{SNDRV_SEQ_EVENT_STOP, 		0, NULL, NULL}, /* 0xfc */
 	{SNDRV_SEQ_EVENT_NONE, 		0, NULL, NULL}, /* 0xfd */
 	{SNDRV_SEQ_EVENT_SENSING, 	0, NULL, NULL}, /* 0xfe */
-	{SNDRV_SEQ_EVENT_RESET, 		0, NULL, NULL}, /* 0xff */
+	{SNDRV_SEQ_EVENT_RESET, 	0, NULL, NULL}, /* 0xff */
 };
 
 static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
@@ -128,6 +128,7 @@
 		}
 	}
 	dev->bufsize = bufsize;
+	dev->lastcmd = 0xff;
 	spin_lock_init(&dev->lock);
 	*rdev = dev;
 	return 0;
diff -urN linux-2.5.6-pre3/sound/core/seq/seq_virmidi.c linux-2.5.6/sound/core/seq/seq_virmidi.c
--- linux-2.5.6-pre3/sound/core/seq/seq_virmidi.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/core/seq/seq_virmidi.c	Thu Mar  7 18:24:56 2002
@@ -233,8 +233,7 @@
 	}
 	vmidi->seq_mode = rdev->seq_mode;
 	vmidi->client = rdev->client;
-	vmidi->port = rdev->port;	
-	snd_midi_event_init(vmidi->parser);
+	vmidi->port = rdev->port;
 	snd_virmidi_init_event(vmidi, &vmidi->event);
 	vmidi->rdev = rdev;
 	runtime->private_data = vmidi;
diff -urN linux-2.5.6-pre3/sound/core/sound_oss.c linux-2.5.6/sound/core/sound_oss.c
--- linux-2.5.6-pre3/sound/core/sound_oss.c	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/sound/core/sound_oss.c	Thu Mar  7 18:24:56 2002
@@ -212,7 +212,7 @@
 {
 	snd_info_entry_t *entry;
 
-	entry = snd_info_create_module_entry(THIS_MODULE, "oss-devices", NULL);
+	entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
 	if (entry) {
 		entry->content = SNDRV_INFO_CONTENT_TEXT;
 		entry->c.text.read_size = PAGE_SIZE;
diff -urN linux-2.5.6-pre3/sound/drivers/Config.help linux-2.5.6/sound/drivers/Config.help
--- linux-2.5.6-pre3/sound/drivers/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/drivers/Config.help	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,18 @@
+CONFIG_SND_DUMMY
+  Say 'Y' or 'M' to include dummy driver. This driver does nothing, but
+  emulates various mixer controls and PCM devices.
+  
+CONFIG_SND_VIRMIDI
+  Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to
+  connect applications using raw MIDI devices to sequencer.
+
+CONFIG_SND_MTPAV
+  Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport
+  MIDI adapter.
+
+CONFIG_SND_SERIAL_U16550
+  Say 'Y' or 'M' to include support for MIDI serial port driver. It works
+  with serial UARTs 16550 and better.
+
+CONFIG_SND_MPU401
+  Say 'Y' or 'M' to include support for MPU401 hardware using UART access.
diff -urN linux-2.5.6-pre3/sound/drivers/mpu401/Makefile linux-2.5.6/sound/drivers/mpu401/Makefile
--- linux-2.5.6-pre3/sound/drivers/mpu401/Makefile	Tue Feb 19 18:11:05 2002
+++ linux-2.5.6/sound/drivers/mpu401/Makefile	Thu Mar  7 18:24:56 2002
@@ -37,6 +37,7 @@
 obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
+obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o
 obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
diff -urN linux-2.5.6-pre3/sound/drivers/mpu401/mpu401_uart.c linux-2.5.6/sound/drivers/mpu401/mpu401_uart.c
--- linux-2.5.6-pre3/sound/drivers/mpu401/mpu401_uart.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/sound/drivers/mpu401/mpu401_uart.c	Thu Mar  7 18:24:56 2002
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/mpu401.h>
 
diff -urN linux-2.5.6-pre3/sound/drivers/mtpav.c linux-2.5.6/sound/drivers/mtpav.c
--- linux-2.5.6-pre3/sound/drivers/mtpav.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/drivers/mtpav.c	Thu Mar  7 18:24:56 2002
@@ -54,6 +54,7 @@
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
diff -urN linux-2.5.6-pre3/sound/drivers/opl3/Makefile linux-2.5.6/sound/drivers/opl3/Makefile
--- linux-2.5.6-pre3/sound/drivers/opl3/Makefile	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/sound/drivers/opl3/Makefile	Thu Mar  7 18:24:56 2002
@@ -29,7 +29,7 @@
 obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-lib.o
 obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-lib.o
 obj-$(CONFIG_SND_OPTI93X) += snd-opl3-lib.o
-obj-$(CONFIG_SND_SB) += snd-opl3-lib.o
+obj-$(CONFIG_SND_SB8) += snd-opl3-lib.o
 obj-$(CONFIG_SND_SB16) += snd-opl3-lib.o
 obj-$(CONFIG_SND_SBAWE) += snd-opl3-lib.o
 obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-lib.o
@@ -54,7 +54,7 @@
   obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-opl3-synth.o
   obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-opl3-synth.o
   obj-$(CONFIG_SND_OPTI93X) += snd-opl3-synth.o
-  obj-$(CONFIG_SND_SB) += snd-opl3-synth.o
+  obj-$(CONFIG_SND_SB8) += snd-opl3-synth.o
   obj-$(CONFIG_SND_SB16) += snd-opl3-synth.o
   obj-$(CONFIG_SND_SBAWE) += snd-opl3-synth.o
   obj-$(CONFIG_SND_WAVEFRONT) += snd-opl3-synth.o
diff -urN linux-2.5.6-pre3/sound/drivers/opl3/opl3_lib.c linux-2.5.6/sound/drivers/opl3/opl3_lib.c
--- linux-2.5.6-pre3/sound/drivers/opl3/opl3_lib.c	Tue Feb 19 18:10:57 2002
+++ linux-2.5.6/sound/drivers/opl3/opl3_lib.c	Thu Mar  7 18:24:56 2002
@@ -28,6 +28,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/minors.h>
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Hannu Savolainen 1993-1996, Rob Hooft");
diff -urN linux-2.5.6-pre3/sound/drivers/serial-u16550.c linux-2.5.6/sound/drivers/serial-u16550.c
--- linux-2.5.6-pre3/sound/drivers/serial-u16550.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/drivers/serial-u16550.c	Thu Mar  7 18:24:56 2002
@@ -39,7 +39,7 @@
  * 
  *      Usage example for MS-124T, with A-B switch in A position:
  *        setserial /dev/ttyS0 uart none
- *        /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ *        /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
  *            snd_adaptor=1 snd_speed=19200
  *
  *      - In MS-124W S/A mode, one raw MIDI substream is supported
@@ -49,7 +49,7 @@
  * 
  *      Usage example for S/A mode:
  *        setserial /dev/ttyS0 uart none
- *        /sbin/modprobe snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ *        /sbin/modprobe snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
  *            snd_adaptor=2
  *
  *      - In MS-124W M/B mode, the driver supports 16 ALSA raw MIDI
@@ -67,7 +67,7 @@
  * 
  *      Usage example for M/B mode:
  *        setserial /dev/ttyS0 uart none
- *        /sbin/insmod snd-card-serial snd_port=0x3f8 snd_irq=4 \
+ *        /sbin/insmod snd-serial-u16550 snd_port=0x3f8 snd_irq=4 \
  *            snd_adaptor=3
  *
  *      - The MS-124W hardware's M/A mode is currently not supported.
@@ -106,6 +106,7 @@
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 #define SNDRV_GET_ID
diff -urN linux-2.5.6-pre3/sound/i2c/Makefile linux-2.5.6/sound/i2c/Makefile
--- linux-2.5.6-pre3/sound/i2c/Makefile	Tue Feb 19 18:10:53 2002
+++ linux-2.5.6/sound/i2c/Makefile	Thu Mar  7 18:24:56 2002
@@ -13,7 +13,7 @@
 snd-cs8427-objs := cs8427.o
 snd-tea6330t-objs := tea6330t.o
 
-# Module Dependency
+# Toplevel Module Dependency
 obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o
 obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o
 
diff -urN linux-2.5.6-pre3/sound/isa/Config.help linux-2.5.6/sound/isa/Config.help
--- linux-2.5.6-pre3/sound/isa/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/isa/Config.help	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,99 @@
+CONFIG_SND_AD1816A
+  Say 'Y' or 'M' to include support for Analog Devices SoundPort AD1816A or
+  compatible sound chips.
+
+CONFIG_SND_AD1848
+  Say 'Y' or 'M' to include support for AD1848 (Analog Devices) or CS4248 
+  (Cirrus Logic - Crystal Semiconductors) chips. Please, for newer chips
+  from Cirrus Logic, use CS4231, CS4232 or CS4236+ driver.
+
+CONFIG_SND_CS4231
+  Say 'Y' or 'M' to include support for CS4231 chips from Cirrus Logic -
+  Crystal Semiconductors.
+
+CONFIG_SND_CS4232
+  Say 'Y' or 'M' to include support for CS4232 chips from Cirrus Logic -
+  Crystal Semiconductors.
+
+CONFIG_SND_CS4236
+  Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239
+  chips from Cirrus Logic - Crystal Semiconductors.
+
+CONFIG_SND_ES968
+  Say 'Y' or 'M' to include support for ESS AudioDrive ES968 chip.
+
+CONFIG_SND_ES1688
+  Say 'Y' or 'M' to include support for ESS AudioDrive ES688 or ES1688 chips.
+
+CONFIG_SND_ES18XX
+  Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips.
+
+CONFIG_SND_GUSCLASSIC
+  Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard.
+
+CONFIG_SND_GUSEXTREME
+  Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard.
+
+CONFIG_SND_GUSMAX
+  Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard.
+
+CONFIG_SND_INTERWAVE
+  Say 'Y' or 'M' to include support for AMD InterWave based soundcards
+  (Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro,
+  Panasonic PCA761AW).
+
+CONFIG_SND_INTERWAVE_STB
+  Say 'Y' or 'M' to include support for AMD InterWave based soundcards
+  with TEA6330T bass and treble regulator (UltraSound 32-Pro).
+
+CONFIG_SND_OPTI92X_AD1848
+  Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
+  AD1848 codec.
+
+CONFIG_SND_OPTI92X_CS4231
+  Say 'Y' or 'M' to include support for Opti92x soundcards equiped with
+  CS4231 codec.
+
+CONFIG_SND_OPTI93X
+  Say 'Y' or 'M' to include support for Opti93x soundcards.
+
+CONFIG_SND_SB8
+  Say 'Y' or 'M' to include support for Sound Blaster 1.0/2.0/Pro (8-bit)
+  soundcards or 100% compatible from Creative.
+
+CONFIG_SND_SB16
+  Say 'Y' or 'M' to include support for Sound Blaster 16 (including
+  Plug and Play version).
+
+CONFIG_SND_SBAWE
+  Say 'Y' or 'M' to include support for Sound Blaster AWE (including
+  Plug and Play version).
+
+CONFIG_SND_SB16_CSP
+  Say 'Y' to include support for CSP core. This special coprocessor
+  can do variable tasks like various compression and decompression
+  algorithms.
+
+CONFIG_SND_WAVEFRONT
+  Say 'Y' or 'M' to include support for Turtle Beach Maui, Tropez
+  and Tropez+ soundcards based on Wavefront chip.
+
+CONFIG_SND_ALS100
+  Say 'Y' or 'M' to include support for Avance Logic ALS100, ALS110,
+  ALS120 and ALS200 soundcards.
+
+CONFIG_SND_AZT2320
+  Say 'Y' or 'M' to include support for Aztech Systems AZT2320 soundcard.
+
+CONFIG_SND_CMI8330
+  Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards.
+
+CONFIG_SND_DT0197H
+  Say 'Y' or 'M' to include support for Diamond Technologies DT-0197H
+  soundcards.
+
+CONFIG_SND_OPL3SA2
+  Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips.
+
+CONFIG_SND_SGALAXY
+  Say 'Y' or 'M' to include support for Aztech Sound Galaxy.
diff -urN linux-2.5.6-pre3/sound/isa/ad1816a/ad1816a_lib.c linux-2.5.6/sound/isa/ad1816a/ad1816a_lib.c
--- linux-2.5.6-pre3/sound/isa/ad1816a/ad1816a_lib.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/sound/isa/ad1816a/ad1816a_lib.c	Thu Mar  7 18:24:56 2002
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/ad1816a.h>
 
diff -urN linux-2.5.6-pre3/sound/isa/ad1848/ad1848_lib.c linux-2.5.6/sound/isa/ad1848/ad1848_lib.c
--- linux-2.5.6-pre3/sound/isa/ad1848/ad1848_lib.c	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/sound/isa/ad1848/ad1848_lib.c	Thu Mar  7 18:24:56 2002
@@ -25,6 +25,7 @@
 #include <asm/dma.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/ad1848.h>
 
diff -urN linux-2.5.6-pre3/sound/isa/azt2320.c linux-2.5.6/sound/isa/azt2320.c
--- linux-2.5.6-pre3/sound/isa/azt2320.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/isa/azt2320.c	Thu Mar  7 18:24:56 2002
@@ -134,7 +134,7 @@
 static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
 	/* PRO16V */
 	ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001),
-	/* --- */
+	/* Aztech Sound Galaxy 16 */
 	ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002),
 	/* Packard Bell Sound III 336 AM/SP */
 	ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001),
diff -urN linux-2.5.6-pre3/sound/isa/cs423x/cs4231_lib.c linux-2.5.6/sound/isa/cs423x/cs4231_lib.c
--- linux-2.5.6-pre3/sound/isa/cs423x/cs4231_lib.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/isa/cs423x/cs4231_lib.c	Thu Mar  7 18:24:56 2002
@@ -32,6 +32,7 @@
 #include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/cs4231.h>
 
diff -urN linux-2.5.6-pre3/sound/isa/es1688/es1688_lib.c linux-2.5.6/sound/isa/es1688/es1688_lib.c
--- linux-2.5.6-pre3/sound/isa/es1688/es1688_lib.c	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/sound/isa/es1688/es1688_lib.c	Thu Mar  7 18:24:56 2002
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/es1688.h>
 #include <sound/initval.h>
diff -urN linux-2.5.6-pre3/sound/isa/gus/gus_main.c linux-2.5.6/sound/isa/gus/gus_main.c
--- linux-2.5.6-pre3/sound/isa/gus/gus_main.c	Tue Feb 19 18:10:55 2002
+++ linux-2.5.6/sound/isa/gus/gus_main.c	Thu Mar  7 18:24:56 2002
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/gus.h>
 #include <sound/control.h>
diff -urN linux-2.5.6-pre3/sound/isa/opl3sa2.c linux-2.5.6/sound/isa/opl3sa2.c
--- linux-2.5.6-pre3/sound/isa/opl3sa2.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/isa/opl3sa2.c	Thu Mar  7 18:24:56 2002
@@ -177,7 +177,7 @@
 	ISAPNP_OPL3SA2('Y','M','H',0x0020,0x0021),
 	/* Yamaha OPL3-SA3 (integrated on Intel's Pentium II AL440LX motherboard) */
 	ISAPNP_OPL3SA2('Y','M','H',0x0030,0x0021),
-	/* ??? */
+	/* Yamaha OPL3-SA2 */
 	ISAPNP_OPL3SA2('Y','M','H',0x0800,0x0021),
 	/* NeoMagic MagicWave 3DX */
 	ISAPNP_OPL3SA2('N','M','X',0x2200,0x2210),
diff -urN linux-2.5.6-pre3/sound/isa/sb/Makefile linux-2.5.6/sound/isa/sb/Makefile
--- linux-2.5.6-pre3/sound/isa/sb/Makefile	Tue Feb 19 18:11:01 2002
+++ linux-2.5.6/sound/isa/sb/Makefile	Thu Mar  7 18:24:56 2002
@@ -27,12 +27,12 @@
 obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
 obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
+obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
 ifeq ($(CONFIG_SND_SB16_CSP),y)
   obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
   obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
 endif
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
 ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
   obj-$(CONFIG_SND_SBAWE) += snd-emu8000-synth.o
 endif
diff -urN linux-2.5.6-pre3/sound/isa/sb/emu8000.c linux-2.5.6/sound/isa/sb/emu8000.c
--- linux-2.5.6-pre3/sound/isa/sb/emu8000.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/sound/isa/sb/emu8000.c	Thu Mar  7 18:24:56 2002
@@ -25,6 +25,7 @@
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/emu8000.h>
 #include <sound/emu8000_reg.h>
diff -urN linux-2.5.6-pre3/sound/isa/sb/sb16_main.c linux-2.5.6/sound/isa/sb/sb16_main.c
--- linux-2.5.6-pre3/sound/isa/sb/sb16_main.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/sound/isa/sb/sb16_main.c	Thu Mar  7 18:24:56 2002
@@ -209,11 +209,11 @@
 #else
 #define snd_sb16_csp_playback_prepare(chip, runtime)	/*nop*/
 #define snd_sb16_csp_capture_prepare(chip, runtime)	/*nop*/
-#define snd_sb16_csp_update(chip)		/*nop*/
+#define snd_sb16_csp_update(chip)			/*nop*/
 #define snd_sb16_csp_playback_open(chip, runtime)	/*nop*/
-#define snd_sb16_csp_playback_close(chip)	/*nop*/
+#define snd_sb16_csp_playback_close(chip)		/*nop*/
 #define snd_sb16_csp_capture_open(chip, runtime)	/*nop*/
-#define snd_sb16_csp_capture_close(chip)       	/*nop*/
+#define snd_sb16_csp_capture_close(chip)      	 	/*nop*/
 #endif
 
 
diff -urN linux-2.5.6-pre3/sound/isa/sb/sb8.c linux-2.5.6/sound/isa/sb/sb8.c
--- linux-2.5.6-pre3/sound/isa/sb/sb8.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/isa/sb/sb8.c	Thu Mar  7 18:24:56 2002
@@ -22,6 +22,7 @@
 #include <sound/driver.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/opl3.h>
diff -urN linux-2.5.6-pre3/sound/isa/sb/sb_common.c linux-2.5.6/sound/isa/sb/sb_common.c
--- linux-2.5.6-pre3/sound/isa/sb/sb_common.c	Tue Feb 19 18:11:02 2002
+++ linux-2.5.6/sound/isa/sb/sb_common.c	Thu Mar  7 18:24:56 2002
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/ioport.h>
 #include <sound/core.h>
 #include <sound/sb.h>
 #include <sound/initval.h>
diff -urN linux-2.5.6-pre3/sound/isa/sgalaxy.c linux-2.5.6/sound/isa/sgalaxy.c
--- linux-2.5.6-pre3/sound/isa/sgalaxy.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/isa/sgalaxy.c	Thu Mar  7 18:24:56 2002
@@ -119,7 +119,7 @@
 	static int dma_bits[] = {1, 2, 0, 3};
 	int tmp, tmp1;
 
-	unsigned int flags;
+	unsigned long flags;
 
 	if ((tmp = inb(port + 3)) == 0xff)
 	{
diff -urN linux-2.5.6-pre3/sound/isa/wavefront/wavefront_synth.c linux-2.5.6/sound/isa/wavefront/wavefront_synth.c
--- linux-2.5.6-pre3/sound/isa/wavefront/wavefront_synth.c	Tue Feb 19 18:11:00 2002
+++ linux-2.5.6/sound/isa/wavefront/wavefront_synth.c	Thu Mar  7 18:24:56 2002
@@ -111,30 +111,6 @@
 MODULE_PARM(osrun_time,"i");
 MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
 
-/*
- *	This sucks, hopefully it'll get standardised
- */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,18) && LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-#define loops_per_sec loops_per_jiffy*HZ
-#elif LINUX_VERSION_CODE == KERNEL_VERSION(2,4,0) && defined(I_DIRTY_PAGES) /* linux/fs.h */
-#define loops_per_sec loops_per_jiffy*HZ
-#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
-#define loops_per_sec loops_per_jiffy*HZ
-#endif
- 
-#if defined(__alpha__) || defined(__powerpc__)
-#ifdef __SMP__
-#define LOOPS_PER_SEC	(cpu_data[smp_processor_id()].loops_per_sec)
-#else
-#define LOOPS_PER_SEC	(loops_per_sec)
-#endif
-#endif
-
-#if defined(__i386__)
-#define LOOPS_PER_SEC	(current_cpu_data.loops_per_sec)
-#endif
- 
 /* 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 
@@ -323,26 +299,16 @@
 
 {
 	int             i;
-	static int      short_loop_cnt = 0;
-
-	/* Compute the loop count that lets us sleep for about the
-	   right amount of time, cache issues, bus speeds and all
-	   other issues being unequal but largely irrelevant.
-	*/
-
-	if (short_loop_cnt == 0) {
-		short_loop_cnt = wait_usecs *
-			(LOOPS_PER_SEC / 1000000);
-	}
 
 	/* Spin for a short period of time, because >99% of all
 	   requests to the WaveFront can be serviced inline like this.
 	*/
 
-	for (i = 0; i < short_loop_cnt; i++) {
+	for (i = 0; i < wait_usecs; i += 5) {
 		if (wavefront_status (dev) & mask) {
 			return 1;
 		}
+		udelay(5);
 	}
 
 	for (i = 0; i < sleep_tries; i++) {
@@ -1316,18 +1282,21 @@
     
 	for (i = 0; i < num_samples; i++) {
 		char d[2];
+		int val;
 	
-		if ((d[0] = wavefront_read (dev)) == -1) {
+		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
 			return -(EIO);
 		}
+		d[0] = val;
 
-		if ((d[1] = wavefront_read (dev)) == -1) {
+		if ((val = wavefront_read (dev)) == -1) {
 			snd_printk ("upload multisample failed "
 				    "during sample loop.\n");
 			return -(EIO);
 		}
+		d[1] = val;
 	
 		header->hdr.ms.SampleNumber[i] =
 			demunge_int32 ((unsigned char *) d, 2);
diff -urN linux-2.5.6-pre3/sound/oss/via82cxxx_audio.c linux-2.5.6/sound/oss/via82cxxx_audio.c
--- linux-2.5.6-pre3/sound/oss/via82cxxx_audio.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/oss/via82cxxx_audio.c	Thu Mar  7 18:24:56 2002
@@ -354,8 +354,6 @@
 static struct pci_device_id via_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5,
 	  PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5,
-	  PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci,via_pci_tbl);
diff -urN linux-2.5.6-pre3/sound/pci/Config.help linux-2.5.6/sound/pci/Config.help
--- linux-2.5.6-pre3/sound/pci/Config.help	Wed Dec 31 16:00:00 1969
+++ linux-2.5.6/sound/pci/Config.help	Thu Mar  7 18:24:56 2002
@@ -0,0 +1,75 @@
+CONFIG_SND_ALI5451
+  Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core.
+
+CONFIG_SND_CS46XX
+  Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 /
+  CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips.
+
+CONFIG_SND_CS46XX_ACCEPT_VALID
+  Say 'Y' to allow sample resolution for mmap() transfers.
+
+CONFIG_SND_EMU10K1
+  Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!,
+  Audigy and E-mu APS (partially supported).
+
+CONFIG_SND_KORG1212
+  Say 'Y' or 'M' to include support for Korg 1212IO.
+
+CONFIG_SND_NM256
+  Say 'Y' or 'M' to include support for NeoMagic NM256AV/ZX chips.
+
+CONFIG_SND_RME96
+  Say 'Y' or 'M' to include support for RME Digi96, Digi96/8 and
+  Digi96/8 PRO/PAD/PST.
+
+CONFIG_SND_RME9652
+  Say 'Y' or 'M' to include support for RME Hammerfall (RME Digi9652 /
+  Digi9636) soundcards.
+
+CONFIG_SND_TRIDENT
+
+CONFIG_SND_YMFPCI
+  Say 'Y' or 'M' to include support for Yamaha PCI audio chips - 
+  YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754.
+
+CONFIG_SND_ALS4000
+  Say 'Y' or 'M' to include support for Avance Logic ALS4000.
+
+CONFIG_SND_CMIPCI
+  Say 'Y' or 'M' to include support for C-Media CMI8338 and 8738 PCI
+  soundcards.
+
+CONFIG_SND_ENS1370
+  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370.
+
+CONFIG_SND_ENS1371
+  Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and
+  Sound Blaster PCI 64 or 128 soundcards.
+
+CONFIG_SND_ES1938
+  Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946)
+  soundcard.
+
+CONFIG_SND_ES1968
+  Say 'Y' or 'M' to include support for ESS Maestro 1/2/2E.
+
+CONFIG_SND_MAESTRO3
+  Say 'Y' or 'M' to include support for ESS Maestro 3 (Allegro) soundcard.
+
+CONFIG_SND_FM801
+  Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards.
+
+CONFIG_SND_ICE1712
+  Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards.
+
+CONFIG_SND_INTEL8X0
+  Say 'Y' or 'M' to include support for Intel8x0 based soundcards.
+
+CONFIG_SND_SONICVIBES
+  Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
+
+CONFIG_SND_VIA686
+  Say 'Y' or 'M' to include support for VIA VT82C686A/B South Bridge.
+
+CONFIG_SND_VIA8233
+  Say 'Y' or 'M' to include support for VIA VT8233 South Bridge.
diff -urN linux-2.5.6-pre3/sound/pci/ymfpci/ymfpci.c linux-2.5.6/sound/pci/ymfpci/ymfpci.c
--- linux-2.5.6-pre3/sound/pci/ymfpci/ymfpci.c	Thu Mar  7 18:24:38 2002
+++ linux-2.5.6/sound/pci/ymfpci/ymfpci.c	Thu Mar  7 18:24:57 2002
@@ -109,7 +109,7 @@
 	}
 
 	legacy_ctrl = 0;
-	legacy_ctrl2 = 0;
+	legacy_ctrl2 = 0x0800;	/* SMOD = 01 */
 
 	if (id->device >= 0x0010) { /* YMF 744/754 */
 		if (snd_fm_port[dev] < 0)
diff -urN linux-2.5.6-pre3/sound/synth/Makefile linux-2.5.6/sound/synth/Makefile
--- linux-2.5.6-pre3/sound/synth/Makefile	Tue Feb 19 18:10:54 2002
+++ linux-2.5.6/sound/synth/Makefile	Thu Mar  7 18:24:57 2002
@@ -15,8 +15,8 @@
 snd-util-mem-objs := util_mem.o
 
 # Toplevel Module Dependency
-obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
 obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o
+obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o
 ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y)
   obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o
 endif
