diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Wed Apr  3 17:11:14 2002
+++ b/CREDITS	Wed Apr  3 17:11:14 2002
@@ -1916,6 +1916,7 @@
 N: Petko Manolov
 E: petkan@users.sourceforge.net
 D: USB ethernet pegasus/pegasus-II driver
+D: USB ethernet rtl8150 driver
 D: optimizing i[45]86 string routines
 D: i386 task switching hacks
 S: 482 Shadowgraph Dr.
@@ -2132,7 +2133,7 @@
 S: Germany
 
 N: Thomas Molina
-E: tmolina@home.com
+E: tmolina@cox.net
 D: bug fixes, documentation, minor hackery
 
 N: David Mosberger-Tang
@@ -2536,6 +2537,7 @@
 
 N: Thiago Berlitz Rondon
 E: maluco@mileniumnet.com.br
+W: http://vivaldi.linuxms.com.br/~maluco
 D: Miscellaneous kernel hacker
 S: R. Anhanguera, 1487 - Ipiranga
 S: 79080-740 - Campo Grande - Mato Grosso do Sul
@@ -3288,9 +3290,10 @@
 S: USA
 
 N: Richard Zidlicky
-E: rdzidlic@geocities.com,rdzidlic@cip.informatik.uni-erlangen.de
-W: http://www.geocities.com/SiliconValley/Bay/2602/
+E: rz@linux-m68k.org, rdzidlic@geocities.com
+W: http://www.geocities.com/rdzidlic
 D: Q40 port - see arch/m68k/q40/README
+D: various m68k hacks
 S: Germany
 
 N: Werner Zimmermann
diff -Nru a/Documentation/00-INDEX b/Documentation/00-INDEX
--- a/Documentation/00-INDEX	Wed Apr  3 17:11:14 2002
+++ b/Documentation/00-INDEX	Wed Apr  3 17:11:14 2002
@@ -12,14 +12,14 @@
 
 00-INDEX
 	- this file.
+BK-usage/
+	- directory with info on BitKeeper.
 BUG-HUNTING
 	- brute force method of doing binary search of patches to find bug.
 Changes
 	- list of changes that break older software packages.
 CodingStyle
 	- how the boss likes the C code in the kernel to look.
-Configure.help
-	- text file that is used for help when you run "make config"
 DMA-mapping.txt
 	- info for PCI drivers using DMA portably across all platforms.
 DocBook/
@@ -34,6 +34,10 @@
 	- info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux
 README.moxa
 	- release notes for Moxa mutiport serial card.
+README.nsp_cs.eng
+	- info on WorkBiT NinjaSCSI-3/32Bi driver.
+SAK.txt
+	- info on Secure Attention Keys.
 SubmittingDrivers
 	- procedure to get a new driver source included into the kernel tree.
 SubmittingPatches
@@ -44,6 +48,8 @@
 	- directory with info about Linux on the ARM architecture.
 binfmt_misc.txt
 	- info on the kernel support for extra binary formats.
+block/
+	- info on the Block I/O (BIO) layer.
 cachetlb.txt
 	- describes the cache/TLB flushing interfaces Linux uses.
 cciss.txt
@@ -54,6 +60,8 @@
 	- info on Computone Intelliport II/Plus Multiport Serial Driver
 cpqarray.txt
 	- info on using Compaq's SMART2 Intelligent Disk Array Controllers.
+cris/
+	- directory with info about Linux on CRIS architecture.
 devices.txt
 	- plain ASCII listing of all the nodes in /dev/ with major minor #'s
 digiboard.txt
@@ -62,6 +70,8 @@
 	- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 dnotify.txt
 	- info about directory notification in Linux.
+driver-model.txt
+	- info about Linux driver model.
 exception.txt
 	- how Linux v2.2 handles exceptions without verify_area etc.
 fb/
@@ -80,12 +90,16 @@
 	- directory with info about the I2C bus/protocol (2 wire, kHz speed)
 i386/
 	- directory with info about Linux on intel 32 bit architecture.
+i810_rng.txt
+	- info on Linux support for random number generator in i8xx chipsets.
 ia64/
 	- directory with info about Linux on intel 64 bit architecture.
 ide.txt
 	- important info for users of ATA devices (IDE/EIDE disks and CD-ROMS)
 initrd.txt
 	- how to use the RAM disk as an initial/temporary root filesystem.
+input/
+	- info on Linux input device support.
 ioctl-number.txt
 	- how to implement and register device/driver ioctl calls.
 isapnp.txt
@@ -94,12 +108,6 @@
 	- directory with info on the Linux ISDN support, and supported cards.
 java.txt
 	- info on the in-kernel binary support for Java(tm)
-joystick-api.txt
-	- API specification for applications that will be using the joystick.
-joystick-parport.txt 
-	- info on how to hook joysticks/gamepads to the parallel port.
-joystick.txt
-	- info on using joystick devices (and driver) with Linux.
 kbuild/
 	- directory with info about the kernel build process
 kernel-doc-nano-HOWTO.txt
@@ -128,6 +136,8 @@
 	- info on boot arguments for the multiple devices driver
 memory.txt
 	- info on typical Linux memory problems.
+mips/
+	- directory with info about Linux on MIPS architecture.
 mkdev.cciss
 	- script to make /dev entries for SMART controllers (see cciss.txt)
 mkdev.ida
@@ -161,9 +171,13 @@
 pcwd-watchdog.txt
 	- info and sample code for using with the PC Watchdog reset card.
 pm.txt
-	- info on Linux power management support
+	- info on Linux power management support.
+power/
+	- directory with info on Linux PCI power management.
 powerpc/
 	- directory with info on using Linux with the PowerPC.
+preempt-locking.txt
+	- info on locking under a preemptive kernel.
 ramdisk.txt
 	- short guide on how to set up and use the RAM disk.
 riscom8.txt
@@ -172,6 +186,8 @@
 	- notes on how to use the Real Time Clock (aka CMOS clock) driver.
 s390/
 	- directory with info on using Linux on the IBM S390.
+sh/
+	- directory with info on porting Linux to a new architecture.
 scsi-generic.txt
 	- info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
 scsi.txt
@@ -186,6 +202,8 @@
 	- LaTeX document describing implementation of Multiprocessor Linux
 smp.txt
 	- a few more notes on symmetric multi-processing
+sonypi.txt
+	- info on Linux Sony Programmable I/O Device support.
 sound/
 	- directory with info on sound card support
 sparc/
@@ -216,6 +234,8 @@
 	- directory with info on the Linux vm code.
 watchdog.txt
 	- how to auto-reboot Linux if it has "fallen and can't get up". ;-)
+x86_64/
+	- directory with info on Linux support for AMD x86-64 (Hammer) machines.
 xterm-linux.xpm
 	- XPM image of penguin logo (see logo.txt) sitting on an xterm.
 zorro.txt
diff -Nru a/Documentation/BK-usage/bksend b/Documentation/BK-usage/bksend
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/BK-usage/bksend	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,36 @@
+#!/bin/sh
+# A script to format BK changeset output in a manner that is easy to read.
+# Andreas Dilger <adilger@turbolabs.com>  13/02/2002
+#
+# Add diffstat output after Changelog <adilger@turbolabs.com>   21/02/2002
+
+PROG=bksend
+
+usage() {
+	echo "usage: $PROG -r<rev>"
+	echo -e "\twhere <rev> is of the form '1.23', '1.23..', '1.23..1.27',"
+	echo -e "\tor '+' to indicate the most recent revision"
+
+	exit 1
+}
+
+case $1 in
+-r) REV=$2; shift ;;
+-r*) REV=`echo $1 | sed 's/^-r//'` ;;
+*) echo "$PROG: no revision given, you probably don't want that";;
+esac
+
+[ -z "$REV" ] && usage
+
+echo "You can import this changeset into BK by piping this whole message to:"
+echo "'| bk receive [path to repository]' or apply the patch as usual."
+
+SEP="\n===================================================================\n\n"
+echo -e $SEP
+bk changes -r$REV
+echo
+bk export -tpatch -du -h -r$REV | diffstat
+echo; echo
+bk export -tpatch -du -h -r$REV
+echo -e $SEP
+bk send -wgzip_uu -r$REV -
diff -Nru a/Documentation/BK-usage/bz64wrap b/Documentation/BK-usage/bz64wrap
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/BK-usage/bz64wrap	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# bz64wrap - the sending side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com>   Jan 2002
+
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+# A program to generate base64 encoding on stdout
+BASE64_ENCODE="uuencode -m /dev/stdout"
+BASE64_BEGIN=
+BASE64_END=
+
+BZIP=NO
+BASE64=NO
+
+# Test if we have the bzip program installed
+bzip2 -c /dev/null > /dev/null 2>&1 && BZIP=YES
+
+# Test if uuencode can handle the -m (MIME) encoding option
+$BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+
+if [ $BASE64 = NO ]; then
+	BASE64_ENCODE=mimencode
+	BASE64_BEGIN="begin-base64 644 -"
+	BASE64_END="===="
+
+	$BASE64_ENCODE < /dev/null > /dev/null 2>&1 && BASE64=YES
+fi
+
+if [ $BZIP = NO -o $BASE64 = NO ]; then
+	echo "$0: can't use bz64 encoding: bzip2=$BZIP, $BASE64_ENCODE=$BASE64"
+	exit 1
+fi
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this internally.
+echo "$BASE64_BEGIN"
+bzip2 -9 | $BASE64_ENCODE
+echo "$BASE64_END"
diff -Nru a/Documentation/BK-usage/cset-to-linus b/Documentation/BK-usage/cset-to-linus
--- a/Documentation/BK-usage/cset-to-linus	Wed Apr  3 17:11:14 2002
+++ b/Documentation/BK-usage/cset-to-linus	Wed Apr  3 17:11:14 2002
@@ -1,4 +1,4 @@
-#!/usr/bin/perl5.6.1 -w
+#!/usr/bin/perl -w
 
 use strict;
 
diff -Nru a/Documentation/BK-usage/csets-to-patches b/Documentation/BK-usage/csets-to-patches
--- a/Documentation/BK-usage/csets-to-patches	Wed Apr  3 17:11:16 2002
+++ b/Documentation/BK-usage/csets-to-patches	Wed Apr  3 17:11:16 2002
@@ -1,4 +1,4 @@
-#!/usr/bin/perl5.6.1 -w
+#!/usr/bin/perl -w
 
 use strict;
 
diff -Nru a/Documentation/BK-usage/unbz64wrap b/Documentation/BK-usage/unbz64wrap
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/BK-usage/unbz64wrap	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# unbz64wrap - the receiving side of a bzip2 | base64 stream
+# Andreas Dilger <adilger@clusterfs.com>   Jan 2002
+
+# Sadly, mimencode does not appear to have good "begin" and "end" markers
+# like uuencode does, and it is picky about getting the right start/end of
+# the base64 stream, so we handle this explicitly here.
+
+PATH=$PATH:/usr/bin:/usr/local/bin:/usr/freeware/bin
+
+if mimencode -u < /dev/null > /dev/null 2>&1 ; then
+	SHOW=
+	while read LINE; do
+		case $LINE in
+		begin-base64*) SHOW=YES ;;
+		====) SHOW= ;;
+		*) [ "$SHOW" ] && echo $LINE ;;
+		esac
+	done | mimencode -u | bunzip2
+	exit $?
+else
+	cat - | uudecode -o /dev/stdout | bunzip2
+	exit $?
+fi
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Wed Apr  3 17:11:16 2002
+++ b/Documentation/Changes	Wed Apr  3 17:11:16 2002
@@ -55,7 +55,7 @@
 o  modutils               2.4.2                   # insmod -V
 o  e2fsprogs              1.25                    # tune2fs
 o  jfsutils               1.0.14                  # fsck.jfs -V
-o  reiserfsprogs          3.x.0j                  # reiserfsck 2>&1|grep reiserfsprogs
+o  reiserfsprogs          3.x.1b                  # reiserfsck 2>&1|grep reiserfsprogs
 o  pcmcia-cs              3.1.21                  # cardmgr -V
 o  PPP                    2.4.0                   # pppd --version
 o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
@@ -107,8 +107,8 @@
 your kernel.  This change does, however, mean that you need a recent
 release of binutils.
 
-System utililities
-==================
+System utilities
+================
 
 Architectural changes
 ---------------------
@@ -320,7 +320,7 @@
 
 Reiserfsprogs
 -------------
-o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0j.tar.gz>
+o  <ftp://ftp.namesys.com/pub/reiserfsprogs/reiserfsprogs-3.x.0b.tar.gz>
 
 LVM toolset
 -----------
diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
--- a/Documentation/DMA-mapping.txt	Wed Apr  3 17:11:15 2002
+++ b/Documentation/DMA-mapping.txt	Wed Apr  3 17:11:15 2002
@@ -759,13 +759,10 @@
    Struct scatterlist must contain, at a minimum, the following
    members:
 
-	char *address;
 	struct page *page;
 	unsigned int offset;
 	unsigned int length;
 
-   The "address" member will disappear in 2.5.x
-
    This means that your pci_{map,unmap}_sg() and all other
    interfaces dealing with scatterlists must be able to cope
    properly with page being non NULL.
@@ -774,9 +771,6 @@
    either specified by "address" or by a "page+offset" pair.
    If "address" is NULL, then "page+offset" is being used.
    If "page" is NULL, then "address" is being used.
-
-   In 2.5.x, all scatterlists will use "page+offset".  But during
-   2.4.x we still have to support the old method.
 
 2) More to come...
 
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Wed Apr  3 17:11:15 2002
+++ b/Documentation/DocBook/Makefile	Wed Apr  3 17:11:15 2002
@@ -59,8 +59,8 @@
 	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/net/wan/z85230.c \
 		<z8530book.tmpl >z8530book.sgml
 
-via-audio.sgml: via-audio.tmpl $(TOPDIR)/drivers/sound/via82cxxx_audio.c
-	$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/sound/via82cxxx_audio.c \
+via-audio.sgml: via-audio.tmpl $(TOPDIR)/sound/oss/via82cxxx_audio.c
+	$(TOPDIR)/scripts/docgen $(TOPDIR)/sound/oss/via82cxxx_audio.c \
 		<via-audio.tmpl >via-audio.sgml
 
 tulip-user.sgml: tulip-user.tmpl
@@ -100,8 +100,8 @@
 		$(TOPDIR)/drivers/hotplug/pci_hotplug_core.c \
 		$(TOPDIR)/drivers/hotplug/pci_hotplug_util.c \
 		$(TOPDIR)/drivers/block/ll_rw_blk.c \
-		$(TOPDIR)/drivers/sound/sound_core.c \
-		$(TOPDIR)/drivers/sound/sound_firmware.c \
+		$(TOPDIR)/sound/sound_core.c \
+		$(TOPDIR)/sound/sound_firmware.c \
 		$(TOPDIR)/drivers/net/wan/syncppp.c \
 		$(TOPDIR)/drivers/net/wan/z85230.c \
 		$(TOPDIR)/drivers/usb/hcd.c \
diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
--- a/Documentation/DocBook/kernel-api.tmpl	Wed Apr  3 17:11:13 2002
+++ b/Documentation/DocBook/kernel-api.tmpl	Wed Apr  3 17:11:13 2002
@@ -203,8 +203,8 @@
 
   <chapter id="snddev">
      <title>Sound Devices</title>
-!Edrivers/sound/sound_core.c
-!Idrivers/sound/sound_firmware.c
+!Esound/sound_core.c
+!Isound/sound_firmware.c
   </chapter>
 
   <chapter id="usb">
diff -Nru a/Documentation/DocBook/via-audio.tmpl b/Documentation/DocBook/via-audio.tmpl
--- a/Documentation/DocBook/via-audio.tmpl	Wed Apr  3 17:11:15 2002
+++ b/Documentation/DocBook/via-audio.tmpl	Wed Apr  3 17:11:15 2002
@@ -537,7 +537,7 @@
    </listitem>
    <listitem>
     <para>
- Optimize included headers to eliminate headers found in linux/drivers/sound
+ Optimize included headers to eliminate headers found in linux/sound
 	</para>
    </listitem>
   </itemizedlist>
@@ -587,7 +587,9 @@
   
   <chapter id="intfunctions">
      <title>Internal Functions</title>
-!Idrivers/sound/via82cxxx_audio.c
+!Isound/oss/via82cxxx_audio.c
   </chapter>
 
 </book>
+
+
diff -Nru a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
--- a/Documentation/SubmittingDrivers	Wed Apr  3 17:11:15 2002
+++ b/Documentation/SubmittingDrivers	Wed Apr  3 17:11:15 2002
@@ -3,7 +3,7 @@
 
 This document is intended to explain how to submit device drivers to the
 Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) 
+card drivers you should probably talk to XFree86 (http://www.xfree86.org) 
 instead.
 
 Also read the Documentation/SubmittingPatches document.
diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Wed Apr  3 17:11:14 2002
+++ b/Documentation/filesystems/Locking	Wed Apr  3 17:11:14 2002
@@ -140,6 +140,10 @@
 	int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
 	int (*bmap)(struct address_space *, long);
+	int (*flushpage) (struct page *, unsigned long);
+	int (*releasepage) (struct page *, int);
+	int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+
 locking rules:
 	All may block
 		BKL	PageLocked(page)
@@ -149,6 +153,8 @@
 prepare_write:	no	yes
 commit_write:	no	yes
 bmap:		yes
+flushpage:	no	yes
+releasepage:	no	yes
 
 	->prepare_write(), ->commit_write(), ->sync_page() and ->readpage()
 may be called from the request handler (/dev/loop).
@@ -161,6 +167,15 @@
 filesystems and by the swapper. The latter will eventually go away. All
 instances do not actually need the BKL. Please, keep it that way and don't
 breed new callers.
+	->flushpage() is called when the filesystem must attempt to drop
+some or all of the buffers from the page when it is being truncated.  It
+returns zero on success.  If ->flushpage is zero, the kernel uses
+block_flushpage() instead.
+	->releasepage() is called when the kernel is about to try to drop the
+buffers from the page in preparation for freeing it.  It returns zero to
+indicate that the buffers are (or may be) freeable.  If ->releasepage is zero,
+the kernel assumes that the fs has no private interest in the buffers.
+
 	Note: currently almost all instances of address_space methods are
 using BKL for internal serialization and that's one of the worst sources
 of contention. Normally they are calling library functions (in fs/buffer.c)
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Wed Apr  3 17:11:15 2002
+++ b/Documentation/kernel-parameters.txt	Wed Apr  3 17:11:15 2002
@@ -17,6 +17,7 @@
 	CD	Appropriate CD support is enabled.
 	DEVFS   devfs support is enabled. 
 	DRM	Direct Rendering Management support is enabled. 
+	EFI	EFI Partitioning (GPT) is enabled
 	EIDE	EIDE/ATAPI support is enabled.
 	FB	The frame buffer device is enabled.
 	HW	Appropriate hardware is enabled.
@@ -218,6 +219,9 @@
 	gc_3=		[HW,JOY]
  
 	gdth=		[HW,SCSI]
+
+	gpt             [EFI] Forces disk with valid GPT signature but
+			invalid Protective MBR to be treated as GPT.
 
 	gscd=		[HW,CD]
 
diff -Nru a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
--- a/Documentation/networking/dl2k.txt	Wed Apr  3 17:11:14 2002
+++ b/Documentation/networking/dl2k.txt	Wed Apr  3 17:11:14 2002
@@ -1,7 +1,7 @@
 
     D-Link DL2000-based Gigabit Ethernet Adapter Installation
     for Linux
-    Jan 02, 2002
+    Jan 29, 2002
 
 Contents
 ========
@@ -199,8 +199,8 @@
 				  6          	1000Mbps full duplex.
 
 				  By default, the NIC operates at autosense.
-				  Note that only 1000mbps_fd and 1000mbps_hd
-				  types are available for fiber adapter.
+				  1000mbps_fd and 1000mbps_hd types are only
+				  available for fiber adapter.
 
 vlan=[0|1]			- Specifies the VLAN ID. If vlan=0, the
 				  Virtual Local Area Network (VLAN) function is
diff -Nru a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
--- a/Documentation/networking/ip-sysctl.txt	Wed Apr  3 17:11:15 2002
+++ b/Documentation/networking/ip-sysctl.txt	Wed Apr  3 17:11:15 2002
@@ -126,7 +126,13 @@
 	if network conditions require more than default value.
 
 tcp_tw_recycle - BOOLEAN
-	Enable fast recycling TIME-WAIT sockets. Default value is 1.
+	Enable fast recycling TIME-WAIT sockets. Default value is 0.
+	It should not be changed without advice/request of technical
+	experts.
+
+tcp_tw_reuse - BOOLEAN
+	Allow to reuse TIME-WAIT sockets for new connections when it is
+	safe from protocol viewpoint. Default value is 0.
 	It should not be changed without advice/request of technical
 	experts.
 
@@ -182,10 +188,7 @@
 	still did not receive an acknowledgement from connecting client.
 	Default value is 1024 for systems with more than 128Mb of memory,
 	and 128 for low memory machines. If server suffers of overload,
-	try to increase this number. Warning! If you make it greater
-	than 1024, it would be better to change TCP_SYNQ_HSIZE in
-	include/net/tcp.h to keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog
-	and to recompile kernel.
+	try to increase this number.
 
 tcp_window_scaling - BOOLEAN
 	Enable window scaling as defined in RFC1323.
@@ -357,6 +360,17 @@
 mc_forwarding - BOOLEAN
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
+
+medium_id - INTEGER
+	Integer value used to differentiate the devices by the medium they
+	are attached to. Two devices can have different id values when
+	the broadcast packets are received only on one of them.
+	The default value 0 means that the device is the only interface
+	to its medium, value of -1 means that medium is not known.
+	
+	Currently, it is used to change the proxy_arp behavior:
+	the proxy_arp feature is enabled for packets forwarded between
+	two devices attached to different media.
 
 proxy_arp - BOOLEAN
 	Do proxy arp.
diff -Nru a/Documentation/networking/ppp_generic.txt b/Documentation/networking/ppp_generic.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/networking/ppp_generic.txt	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,432 @@
+		PPP Generic Driver and Channel Interface
+		----------------------------------------
+
+			    Paul Mackerras
+			   paulus@samba.org
+			      7 Feb 2002
+
+The generic PPP driver in linux-2.4 provides an implementation of the
+functionality which is of use in any PPP implementation, including:
+
+* the network interface unit (ppp0 etc.)
+* the interface to the networking code
+* PPP multilink: splitting datagrams between multiple links, and
+  ordering and combining received fragments
+* the interface to pppd, via a /dev/ppp character device
+* packet compression and decompression
+* TCP/IP header compression and decompression
+* detecting network traffic for demand dialling and for idle timeouts
+* simple packet filtering
+
+For sending and receiving PPP frames, the generic PPP driver calls on
+the services of PPP `channels'.  A PPP channel encapsulates a
+mechanism for transporting PPP frames from one machine to another.  A
+PPP channel implementation can be arbitrarily complex internally but
+has a very simple interface with the generic PPP code: it merely has
+to be able to send PPP frames, receive PPP frames, and optionally
+handle ioctl requests.  Currently there are PPP channel
+implementations for asynchronous serial ports, synchronous serial
+ports, and for PPP over ethernet.
+
+This architecture makes it possible to implement PPP multilink in a
+natural and straightforward way, by allowing more than one channel to
+be linked to each ppp network interface unit.  The generic layer is
+responsible for splitting datagrams on transmit and recombining them
+on receive.
+
+
+PPP channel API
+---------------
+
+See include/linux/ppp_channel.h for the declaration of the types and
+functions used to communicate between the generic PPP layer and PPP
+channels.
+
+Each channel has to provide two functions to the generic PPP layer,
+via the ppp_channel.ops pointer:
+
+* start_xmit() is called by the generic layer when it has a frame to
+  send.  The channel has the option of rejecting the frame for
+  flow-control reasons.  In this case, start_xmit() should return 0
+  and the channel should call the ppp_output_wakeup() function at a
+  later time when it can accept frames again, and the generic layer
+  will then attempt to retransmit the rejected frame(s).  If the frame
+  is accepted, the start_xmit() function should return 1.
+
+* ioctl() provides an interface which can be used by a user-space
+  program to control aspects of the channel's behaviour.  This
+  procedure will be called when a user-space program does an ioctl
+  system call on an instance of /dev/ppp which is bound to the
+  channel.  (Usually it would only be pppd which would do this.)
+
+The generic PPP layer provides seven functions to channels:
+
+* ppp_register_channel() is called when a channel has been created, to
+  notify the PPP generic layer of its presence.  For example, setting
+  a serial port to the PPPDISC line discipline causes the ppp_async
+  channel code to call this function.
+
+* ppp_unregister_channel() is called when a channel is to be
+  destroyed.  For example, the ppp_async channel code calls this when
+  a hangup is detected on the serial port.
+
+* ppp_output_wakeup() is called by a channel when it has previously
+  rejected a call to its start_xmit function, and can now accept more
+  packets.
+
+* ppp_input() is called by a channel when it has received a complete
+  PPP frame.
+
+* ppp_input_error() is called by a channel when it has detected that a
+  frame has been lost or dropped (for example, because of a FCS (frame
+  check sequence) error).
+
+* ppp_channel_index() returns the channel index assigned by the PPP
+  generic layer to this channel.  The channel should provide some way
+  (e.g. an ioctl) to transmit this back to user-space, as user-space
+  will need it to attach an instance of /dev/ppp to this channel.
+
+* ppp_unit_number() returns the unit number of the ppp network
+  interface to which this channel is connected, or -1 if the channel
+  is not connected.
+
+Connecting a channel to the ppp generic layer is initiated from the
+channel code, rather than from the generic layer.  The channel is
+expected to have some way for a user-level process to control it
+independently of the ppp generic layer.  For example, with the
+ppp_async channel, this is provided by the file descriptor to the
+serial port.
+
+Generally a user-level process will initialize the underlying
+communications medium and prepare it to do PPP.  For example, with an
+async tty, this can involve setting the tty speed and modes, issuing
+modem commands, and then going through some sort of dialog with the
+remote system to invoke PPP service there.  We refer to this process
+as `discovery'.  Then the user-level process tells the medium to
+become a PPP channel and register itself with the generic PPP layer.
+The channel then has to report the channel number assigned to it back
+to the user-level process.  From that point, the PPP negotiation code
+in the PPP daemon (pppd) can take over and perform the PPP
+negotiation, accessing the channel through the /dev/ppp interface.
+
+At the interface to the PPP generic layer, PPP frames are stored in
+skbuff structures and start with the two-byte PPP protocol number.
+The frame does *not* include the 0xff `address' byte or the 0x03
+`control' byte that are optionally used in async PPP.  Nor is there
+any escaping of control characters, nor are there any FCS or framing
+characters included.  That is all the responsibility of the channel
+code, if it is needed for the particular medium.  That is, the skbuffs
+presented to the start_xmit() function contain only the 2-byte
+protocol number and the data, and the skbuffs presented to ppp_input()
+must be in the same format.
+
+The channel must provide an instance of a ppp_channel struct to
+represent the channel.  The channel is free to use the `private' field
+however it wishes.  The channel should initialize the `mtu' and
+`hdrlen' fields before calling ppp_register_channel() and not change
+them until after ppp_unregister_channel() returns.  The `mtu' field
+represents the maximum size of the data part of the PPP frames, that
+is, it does not include the 2-byte protocol number.
+
+If the channel needs some headroom in the skbuffs presented to it for
+transmission (i.e., some space free in the skbuff data area before the
+start of the PPP frame), it should set the `hdrlen' field of the
+ppp_channel struct to the amount of headroom required.  The generic
+PPP layer will attempt to provide that much headroom but the channel
+should still check if there is sufficient headroom and copy the skbuff
+if there isn't.
+
+On the input side, channels should ideally provide at least 2 bytes of
+headroom in the skbuffs presented to ppp_input().  The generic PPP
+code does not require this but will be more efficient if this is done.
+
+
+Buffering and flow control
+--------------------------
+
+The generic PPP layer has been designed to minimize the amount of data
+that it buffers in the transmit direction.  It maintains a queue of
+transmit packets for the PPP unit (network interface device) plus a
+queue of transmit packets for each attached channel.  Normally the
+transmit queue for the unit will contain at most one packet; the
+exceptions are when pppd sends packets by writing to /dev/ppp, and
+when the core networking code calls the generic layer's start_xmit()
+function with the queue stopped, i.e. when the generic layer has
+called netif_stop_queue(), which only happens on a transmit timeout.
+The start_xmit function always accepts and queues the packet which it
+is asked to transmit.
+
+Transmit packets are dequeued from the PPP unit transmit queue and
+then subjected to TCP/IP header compression and packet compression
+(Deflate or BSD-Compress compression), as appropriate.  After this
+point the packets can no longer be reordered, as the decompression
+algorithms rely on receiving compressed packets in the same order that
+they were generated.
+
+If multilink is not in use, this packet is then passed to the attached
+channel's start_xmit() function.  If the channel refuses to take
+the packet, the generic layer saves it for later transmission.  The
+generic layer will call the channel's start_xmit() function again
+when the channel calls  ppp_output_wakeup() or when the core
+networking code calls the generic layer's start_xmit() function
+again.  The generic layer contains no timeout and retransmission
+logic; it relies on the core networking code for that.
+
+If multilink is in use, the generic layer divides the packet into one
+or more fragments and puts a multilink header on each fragment.  It
+decides how many fragments to use based on the length of the packet
+and the number of channels which are potentially able to accept a
+fragment at the moment.  A channel is potentially able to accept a
+fragment if it doesn't have any fragments currently queued up for it
+to transmit.  The channel may still refuse a fragment; in this case
+the fragment is queued up for the channel to transmit later.  This
+scheme has the effect that more fragments are given to higher-
+bandwidth channels.  It also means that under light load, the generic
+layer will tend to fragment large packets across all the channels,
+thus reducing latency, while under heavy load, packets will tend to be
+transmitted as single fragments, thus reducing the overhead of
+fragmentation.
+
+
+SMP safety
+----------
+
+The PPP generic layer has been designed to be SMP-safe.  Locks are
+used around accesses to the internal data structures where necessary
+to ensure their integrity.  As part of this, the generic layer
+requires that the channels adhere to certain requirements and in turn
+provides certain guarantees to the channels.  Essentially the channels
+are required to provide the appropriate locking on the ppp_channel
+structures that form the basis of the communication between the
+channel and the generic layer.  This is because the channel provides
+the storage for the ppp_channel structure, and so the channel is
+required to provide the guarantee that this storage exists and is
+valid at the appropriate times.
+
+The generic layer requires these guarantees from the channel:
+
+* The ppp_channel object must exist from the time that
+  ppp_register_channel() is called until after the call to
+  ppp_unregister_channel() returns.
+
+* No thread may be in a call to any of ppp_input(), ppp_input_error(),
+  ppp_output_wakeup(), ppp_channel_index() or ppp_unit_number() for a
+  channel at the time that ppp_unregister_channel() is called for that
+  channel.
+
+* ppp_register_channel() and ppp_unregister_channel() must be called
+  from process context, not interrupt or softirq/BH context.
+
+* The remaining generic layer functions may be called at softirq/BH
+  level but must not be called from a hardware interrupt handler.
+
+* The generic layer may call the channel start_xmit() function at
+  softirq/BH level but will not call it at interrupt level.  Thus the
+  start_xmit() function may not block.
+
+* The generic layer will only call the channel ioctl() function in
+  process context.
+
+The generic layer provides these guarantees to the channels:
+
+* The generic layer will not call the start_xmit() function for a
+  channel while any thread is already executing in that function for
+  that channel.
+
+* The generic layer will not call the ioctl() function for a channel
+  while any thread is already executing in that function for that
+  channel.
+
+* By the time a call to ppp_unregister_channel() returns, no thread
+  will be executing in a call from the generic layer to that channel's
+  start_xmit() or ioctl() function, and the generic layer will not
+  call either of those functions subsequently.
+
+
+Interface to pppd
+-----------------
+
+The PPP generic layer exports a character device interface called
+/dev/ppp.  This is used by pppd to control PPP interface units and
+channels.  Although there is only one /dev/ppp, each open instance of
+/dev/ppp acts independently and can be attached either to a PPP unit
+or a PPP channel.  This is achieved using the file->private_data field
+to point to a separate object for each open instance of /dev/ppp.  In
+this way an effect similar to Solaris' clone open is obtained,
+allowing us to control an arbitrary number of PPP interfaces and
+channels without having to fill up /dev with hundreds of device names.
+
+When /dev/ppp is opened, a new instance is created which is initially
+unattached.  Using an ioctl call, it can then be attached to an
+existing unit, attached to a newly-created unit, or attached to an
+existing channel.  An instance attached to a unit can be used to send
+and receive PPP control frames, using the read() and write() system
+calls, along with poll() if necessary.  Similarly, an instance
+attached to a channel can be used to send and receive PPP frames on
+that channel.
+
+In multilink terms, the unit represents the bundle, while the channels
+represent the individual physical links.  Thus, a PPP frame sent by a
+write to the unit (i.e., to an instance of /dev/ppp attached to the
+unit) will be subject to bundle-level compression and to fragmentation
+across the individual links (if multilink is in use).  In contrast, a
+PPP frame sent by a write to the channel will be sent as-is on that
+channel, without any multilink header.
+
+A channel is not initially attached to any unit.  In this state it can
+be used for PPP negotiation but not for the transfer of data packets.
+It can then be connected to a PPP unit with an ioctl call, which
+makes it available to send and receive data packets for that unit.
+
+The ioctl calls which are available on an instance of /dev/ppp depend
+on whether it is unattached, attached to a PPP interface, or attached
+to a PPP channel.  The ioctl calls which are available on an
+unattached instance are:
+
+* PPPIOCNEWUNIT creates a new PPP interface and makes this /dev/ppp
+  instance the "owner" of the interface.  The argument should point to
+  an int which is the desired unit number if >= 0, or -1 to assign the
+  lowest unused unit number.  Being the owner of the interface means
+  that the interface will be shut down if this instance of /dev/ppp is
+  closed.
+
+* PPPIOCATTACH attaches this instance to an existing PPP interface.
+  The argument should point to an int containing the unit number.
+  This does not make this instance the owner of the PPP interface.
+
+* PPPIOCATTCHAN attaches this instance to an existing PPP channel.
+  The argument should point to an int containing the channel number.
+
+The ioctl calls available on an instance of /dev/ppp attached to a
+channel are:
+
+* PPPIOCDETACH detaches the instance from the channel.  This ioctl is
+  deprecated since the same effect can be achieved by closing the
+  instance.  In order to prevent possible races this ioctl will fail
+  with an EINVAL error if more than one file descriptor refers to this
+  instance (i.e. as a result of dup(), dup2() or fork()).
+
+* PPPIOCCONNECT connects this channel to a PPP interface.  The
+  argument should point to an int containing the interface unit
+  number.  It will return an EINVAL error if the channel is already
+  connected to an interface, or ENXIO if the requested interface does
+  not exist.
+
+* PPPIOCDISCONN disconnects this channel from the PPP interface that
+  it is connected to.  It will return an EINVAL error if the channel
+  is not connected to an interface.
+
+* All other ioctl commands are passed to the channel ioctl() function.
+
+The ioctl calls that are available on an instance that is attached to
+an interface unit are:
+
+* PPPIOCSMRU sets the MRU (maximum receive unit) for the interface.
+  The argument should point to an int containing the new MRU value.
+
+* PPPIOCSFLAGS sets flags which control the operation of the
+  interface.  The argument should be a pointer to an int containing
+  the new flags value.  The bits in the flags value that can be set
+  are:
+	SC_COMP_TCP		enable transmit TCP header compression
+	SC_NO_TCP_CCID		disable connection-id compression for
+				TCP header compression
+	SC_REJ_COMP_TCP		disable receive TCP header decompression
+	SC_CCP_OPEN		Compression Control Protocol (CCP) is
+				open, so inspect CCP packets
+	SC_CCP_UP		CCP is up, may (de)compress packets
+	SC_LOOP_TRAFFIC		send IP traffic to pppd
+	SC_MULTILINK		enable PPP multilink fragmentation on
+				transmitted packets
+	SC_MP_SHORTSEQ		expect short multilink sequence
+				numbers on received multilink fragments
+	SC_MP_XSHORTSEQ		transmit short multilink sequence nos.
+
+  The values of these flags are defined in <linux/if_ppp.h>.  Note
+  that the values of the SC_MULTILINK, SC_MP_SHORTSEQ and
+  SC_MP_XSHORTSEQ bits are ignored if the CONFIG_PPP_MULTILINK option
+  is not selected.
+
+* PPPIOCGFLAGS returns the value of the status/control flags for the
+  interface unit.  The argument should point to an int where the ioctl
+  will store the flags value.  As well as the values listed above for
+  PPPIOCSFLAGS, the following bits may be set in the returned value:
+	SC_COMP_RUN		CCP compressor is running
+	SC_DECOMP_RUN		CCP decompressor is running
+	SC_DC_ERROR		CCP decompressor detected non-fatal error
+	SC_DC_FERROR		CCP decompressor detected fatal error
+
+* PPPIOCSCOMPRESS sets the parameters for packet compression or
+  decompression.  The argument should point to a ppp_option_data
+  structure (defined in <linux/if_ppp.h>), which contains a
+  pointer/length pair which should describe a block of memory
+  containing a CCP option specifying a compression method and its
+  parameters.  The ppp_option_data struct also contains a `transmit'
+  field.  If this is 0, the ioctl will affect the receive path,
+  otherwise the transmit path.
+
+* PPPIOCGUNIT returns, in the int pointed to by the argument, the unit
+  number of this interface unit.
+
+* PPPIOCSDEBUG sets the debug flags for the interface to the value in
+  the int pointed to by the argument.  Only the least significant bit
+  is used; if this is 1 the generic layer will print some debug
+  messages during its operation.  This is only intended for debugging
+  the generic PPP layer code; it is generally not helpful for working
+  out why a PPP connection is failing.
+
+* PPPIOCGDEBUG returns the debug flags for the interface in the int
+  pointed to by the argument.
+
+* PPPIOCGIDLE returns the time, in seconds, since the last data
+  packets were sent and received.  The argument should point to a
+  ppp_idle structure (defined in <linux/ppp_defs.h>).  If the
+  CONFIG_PPP_FILTER option is enabled, the set of packets which reset
+  the transmit and receive idle timers is restricted to those which
+  pass the `active' packet filter.
+
+* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
+  number of connection slots) for the TCP header compressor and
+  decompressor.  The lower 16 bits of the int pointed to by the
+  argument specify the maximum connection-ID for the compressor.  If
+  the upper 16 bits of that int are non-zero, they specify the maximum
+  connection-ID for the decompressor, otherwise the decompressor's
+  maximum connection-ID is set to 15.
+
+* PPPIOCSNPMODE sets the network-protocol mode for a given network
+  protocol.  The argument should point to an npioctl struct (defined
+  in <linux/if_ppp.h>).  The `protocol' field gives the PPP protocol
+  number for the protocol to be affected, and the `mode' field
+  specifies what to do with packets for that protocol:
+
+	NPMODE_PASS	normal operation, transmit and receive packets
+	NPMODE_DROP	silently drop packets for this protocol
+	NPMODE_ERROR	drop packets and return an error on transmit
+	NPMODE_QUEUE	queue up packets for transmit, drop received
+			packets
+
+  At present NPMODE_ERROR and NPMODE_QUEUE have the same effect as
+  NPMODE_DROP.
+
+* PPPIOCGNPMODE returns the network-protocol mode for a given
+  protocol.  The argument should point to an npioctl struct with the
+  `protocol' field set to the PPP protocol number for the protocol of
+  interest.  On return the `mode' field will be set to the network-
+  protocol mode for that protocol.
+
+* PPPIOCSPASS and PPPIOCSACTIVE set the `pass' and `active' packet
+  filters.  These ioctls are only available if the CONFIG_PPP_FILTER
+  option is selected.  The argument should point to a sock_fprog
+  structure (defined in <linux/filter.h>) containing the compiled BPF
+  instructions for the filter.  Packets are dropped if they fail the
+  `pass' filter; otherwise, if they fail the `active' filter they are
+  passed but they do not reset the transmit or receive idle timer.
+
+* PPPIOCSMRRU enables or disables multilink processing for received
+  packets and sets the multilink MRRU (maximum reconstructed receive
+  unit).  The argument should point to an int containing the new MRRU
+  value.  If the MRRU value is 0, processing of received multilink
+  fragments is disabled.  This ioctl is only available if the
+  CONFIG_PPP_MULTILINK option is selected.
+
+Last modified: 7-feb-2002
diff -Nru a/Documentation/sonypi.txt b/Documentation/sonypi.txt
--- a/Documentation/sonypi.txt	Wed Apr  3 17:11:13 2002
+++ b/Documentation/sonypi.txt	Wed Apr  3 17:11:13 2002
@@ -25,7 +25,8 @@
 can be downloaded at: <http://www.alcove-labs.org/en/software/sonypi/>
 
 This driver supports also some ioctl commands for setting the LCD screen
-brightness (some more commands may be added in the future).
+brightness and querying the batteries charge information (some more 
+commands may be added in the future).
 
 This driver can also be used to set the camera controls on Picturebook series
 (brightness, contrast etc), and is used by the video4linux driver for the 
diff -Nru a/Documentation/sound/oss/AudioExcelDSP16 b/Documentation/sound/oss/AudioExcelDSP16
--- a/Documentation/sound/oss/AudioExcelDSP16	Wed Apr  3 17:11:13 2002
+++ b/Documentation/sound/oss/AudioExcelDSP16	Wed Apr  3 17:11:13 2002
@@ -2,7 +2,7 @@
 ------
 
 Informations about Audio Excel DSP 16 driver can be found in the source
-file lowlevel/aedsp16.c
+file aedsp16.c
 Please, read the head of the source before using it. It contain useful
 informations.
 
diff -Nru a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt
--- a/Documentation/usb/hiddev.txt	Wed Apr  3 17:11:14 2002
+++ b/Documentation/usb/hiddev.txt	Wed Apr  3 17:11:14 2002
@@ -18,10 +18,10 @@
 The data flow for a HID event produced by a device is something like
 the following :
 
- usb.c ---> hid.c  ----> input.c ----> [keyboard/mouse/joystick/event]
-                    |
-                    |
-                    --> hiddev.c ----> POWER / MONITOR CONTROL 
+ usb.c ---> hid-core.c  ----> input.c ----> [keyboard/mouse/joystick/event]
+                         |
+                         |
+                          --> hiddev.c ----> POWER / MONITOR CONTROL 
 
 In addition, other subsystems (apart from USB) can potentially feed
 events into the input subsystem, but these have no effect on the hid
@@ -63,12 +63,18 @@
 
 The hiddev API uses a read() interface, and a set of ioctl() calls.
 
+HID devices exchange data with the host computer using data
+bundles called "reports".  Each report is divided into "fields",
+each of which can have one or more "usages".  In the hid-core,
+each one of these usages has a single signed 32 bit value.
 
 read():
-This is the event interface. When the HID device performs an
-interrupt transfer, indicating a change of state, data will be made
-available at the associated hiddev device with the content of a struct
-hiddev_event: 
+This is the event interface.  When the HID device's state changes,
+it performs an interrupt transfer containing a report which contains
+the changed value.  The hid-core.c module parses the report, and
+returns to hiddev.c the individual usages that have changed within
+the report.  In its basic mode, the hiddev will make these individual
+usage changes available to the reader using a struct hiddev_event:
 
        struct hiddev_event {
            unsigned hid;
@@ -78,7 +84,10 @@
 containing the HID usage identifier for the status that changed, and
 the value that it was changed to. Note that the structure is defined
 within <linux/hiddev.h>, along with some other useful #defines and
-structures. 
+structures.  The HID usage identifier is a composite of the HID usage
+page shifted to the 16 high order bits ORed with the usage code.  The
+behavior of the read() function can be modified using the HIDIOCSFLAG
+ioctl() described below.
 
 
 ioctl(): 
@@ -108,7 +117,9 @@
 Instructs the kernel to retrieve all input and feature report values
 from the device. At this point, all the usage structures will contain
 current values for the device, and will maintain it as the device
-changes.
+changes.  Note that the use of this ioctl is unnecessary in general,
+since later kernels automatically initialize the reports from the
+device at attach time.
 
 HIDIOCGNAME - string (variable length)
 Gets the device name
@@ -116,12 +127,12 @@
 HIDIOCGREPORT - struct hiddev_report_info (write)
 Instructs the kernel to get a feature or input report from the device,
 in order to selectively update the usage structures (in contrast to
-INITREPORT). 
+INITREPORT).
 
 HIDIOCSREPORT - struct hiddev_report_info (write)
 Instructs the kernel to send a report to the device. This report can
 be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
-individual usage values in the report beforesending the report in full
+individual usage values in the report before sending the report in full
 to the device. 
 
 HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
@@ -157,6 +168,25 @@
 usage if it is found. 
 
 HIDIOCSUSAGE - struct hiddev_usage_ref (write)
-Sets the value of a usage in an output report.
-
-
+Sets the value of a usage in an output report.  The user fills in
+the hiddev_usage_ref structure as above, but additionally fills in
+the value field.
+
+HIDIOCGFLAG - int (read)
+HIDIOCSFLAG - int (write)
+These operations respectively inspect and replace the mode flags
+that influence the read() call above.  The flags are as follows:
+
+    HIDDEV_FLAG_UREF - read() calls will now return 
+        struct hiddev_usage_ref instead of struct hiddev_event.
+        This is a larger structure, but in situations where the
+        device has more than one usage in its reports with the
+        same usage code, this mode serves to resolve such
+        ambiguity.
+
+    HIDDEV_FLAG_REPORT - This flag can only be used in conjunction
+        with HIDDEV_FLAG_UREF.  With this flag set, when the device
+        sends a report, a struct hiddev_usage_ref will be returned
+        to read() filled in with the report_type and report_id, but 
+        with field_index set to FIELD_INDEX_NONE.  This serves as
+        additional notification when the device has sent a report.
diff -Nru a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
--- a/Documentation/usb/proc_usb_info.txt	Wed Apr  3 17:11:14 2002
+++ b/Documentation/usb/proc_usb_info.txt	Wed Apr  3 17:11:14 2002
@@ -1,32 +1,99 @@
 /proc/bus/usb filesystem output
 ===============================
-(version 2000.08.15)
+(version 2002.03.19)
 
 
-The /proc filesystem for USB devices generates
-/proc/bus/usb/drivers and /proc/bus/usb/devices.
+The /proc filesystem for USB devices provides /proc/bus/usb/drivers
+and /proc/bus/usb/devices, as well as /proc/bus/usb/BBB/DDD files.
 
-/proc/bus/usb/drivers lists the registered drivers,
-one per line, with each driver's USB minor dev node
-number range if applicable.
 
-**NOTE**: If /proc/bus/usb appears empty, you need
-          to mount the filesystem, issue the command (as root):
+**NOTE**: If /proc/bus/usb appears empty, and a host controller
+	  driver has been linked, then you need to mount the
+	  filesystem.  Issue the command (as root):
 
-      mount -t usbdevfs none /proc/bus/usb
+      mount -t usbfs none /proc/bus/usb
 
 	  An alternative and more permanent method would be to add
 
-      none  /proc/bus/usb  usbdevfs  defaults  0  0
+      none  /proc/bus/usb  usbfs  defaults  0  0
 
-	  to /etc/fstab.  This will mount usbdevfs at each reboot.
+	  to /etc/fstab.  This will mount usbfs at each reboot.
 	  You can then issue `cat /proc/bus/usb/devices` to extract
-	  USB device information.
+	  USB device information, and user mode drivers can use usbfs 
+	  to interact with USB devices.
 
-For more information on mounting the usbdevfs file system, see the
+	  There are a number of mount options supported by usbfs.
+	  Consult the source code (linux/drivers/usb/inode.c) for
+	  information about those options.
+
+**NOTE**: The filesystem has been renamed from "usbdevfs" to
+	  "usbfs", to reduce confusion with "devfs".  You may
+	  still see references to the older "usbdevfs" name.
+
+For more information on mounting the usbfs file system, see the
 "USB Device Filesystem" section of the USB Guide. The latest copy 
 of the USB Guide can be found at http://www.linux-usb.org/
 
+
+THE /proc/bus/usb/BBB/DDD FILES:
+--------------------------------
+Each connected USB device has one file.  The BBB indicates the bus
+number.  The DDD indicates the device address on that bus.  Both
+of these numbers are assigned sequentially, and can be reused, so
+you can't rely on them for stable access to devices.  For example,
+it's relatively common for devices to re-enumerate while they are
+still connected (perhaps someone jostled their power supply, hub,
+or USB cable), so a device might be 002/027 when you first connect
+it and 002/048 sometime later.
+
+These files can be read as binary data.  The binary data consists
+of first the device descriptor, then the descriptors for each
+configuration of the device.  That information is also shown in
+text form by the /proc/bus/usb/devices file, described later.
+
+These files may also be used to write user-level drivers for the USB
+devices.  You would open the /proc/bus/usb/BBB/DDD file read/write,
+read its descriptors to make sure it's the device you expect, and then
+bind to an interface (or perhaps several) using an ioctl call.  You
+would issue more ioctls to the device to communicate to it using
+control, bulk, or other kinds of USB transfers.  The IOCTLs are
+listed in the <linux/usbdevice_fs.h> file, and at this writing the
+source code (linux/drivers/usb/devio.c) is the primary reference
+for how to access devices through those files.
+
+Note that since by default these BBB/DDD files are writable only by
+root, only root can write such user mode drivers.  You can selectively
+grant read/write permissions to other users by using "chmod".  Also,
+usbfs mount options such as "devmode=0666" may be helpful.
+
+
+
+THE /proc/bus/usb/drivers FILE:
+-------------------------------
+Each of the USB device drivers linked into your kernel (statically,
+or dynamically using "modprobe") is listed in the "drivers" file.
+Here's an example from one system:
+
+         usbdevfs
+         hub
+  0- 15: usblp
+         usbnet
+         serial
+         usb-storage
+         pegasus
+
+If you see this file, "usbdevfs" and "hub" will always be listed,
+since those are part of the "usbcore" framework.
+
+Drivers that use the USB major number (180) to provide character devices
+will include a range of minor numbers, as shown above for the "usblp"
+(actually "printer.o") module.  USB device drivers can of course use any
+major number, but it's easy to use the USB range since there's explicit
+support for subdividing it in the USB device driver framework.
+
+
+THE /proc/bus/usb/devices FILE:
+-------------------------------
 In /proc/bus/usb/devices, each device's output has multiple
 lines of ASCII output.
 I made it ASCII instead of binary on purpose, so that someone
@@ -34,8 +101,6 @@
 auxiliary program.  However, with an auxiliary program, the numbers
 in the first 4 columns of each "T:" line (topology info:
 Lev, Prnt, Port, Cnt) can be used to build a USB topology diagram.
-(I think.  I haven't proved this, but I have tested it with 3
-different topo/connections and it looked possible.)
 
 Each line is tagged with a one-character ID for that line:
 
@@ -73,14 +138,30 @@
 |   |__Bus number
 |__Topology info tag
 
+    Speed may be:
+    	1.5	Mbit/s for low speed USB
+	12	Mbit/s for full speed USB
+	480	Mbit/s for high speed USB (added for USB 2.0)
+
 
 Bandwidth info:
 B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
-|   |                       |         |__Number if isochronous requests
+|   |                       |         |__Number of isochronous requests
 |   |                       |__Number of interrupt requests
 |   |__Total Bandwidth allocated to this bus
 |__Bandwidth info tag
 
+    Bandwidth allocation is an approximation of how much of one frame
+    (millisecond) is in use.  It reflects only periodic transfers, which
+    are the only transfers that reserve bandwidth.  Control and bulk
+    transfers use all other bandwidth, including reserved bandwidth that
+    is not used for transfers (such as for short packets).
+    
+    The percentage is how much of the "reserved" bandwidth is scheduled by
+    those transfers.  For a low or full speed bus (loosely, "USB 1.1"),
+    90% of the bus bandwidth is reserved.  For a high speed bus (loosely,
+    "USB 2.0") 80% is reserved.
+
 
 Device descriptor info & Product ID info:
 
@@ -109,37 +190,55 @@
 
 S:  Manufacturer=ssss
 |   |__Manufacturer of this device as read from the device.
+|      For USB host controller drivers (virtual root hubs) this may
+|      be omitted, or (for newer drivers) will identify the kernel
+|      version and the driver which provides this hub emulation.
 |__String info tag
 
 S:  Product=ssss
-|   |__Product description of this device as read from the device,
-|      except that it is a generated string for USB host controllers
-|      (virtual root hubs), in the form "USB *HCI Root Hub".
+|   |__Product description of this device as read from the device.
+|      For older USB host controller drivers (virtual root hubs) this
+|      indicates the driver; for newer ones, it's a product (and vendor)
+|      description that often comes from the kernel's PCI ID database.
 |__String info tag
 
 S:  SerialNumber=ssss
-|   |__Serial Number of this device as read from the device,
-|      except that it is a generated string for USB host controllers
-|      (virtual root hubs), and represents the host controller's
-|      unique identification in the system (currently I/O or
-|      memory-mapped base address).
+|   |__Serial Number of this device as read from the device.
+|      For USB host controller drivers (virtual root hubs) this is
+|      some unique ID, normally a bus ID (address or slot name) that
+|      can't be shared with any other device.
 |__String info tag
 
 
+
 Configuration descriptor info:
 
-C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
-|   |       |       |      |__MaxPower in mA
-|   |       |       |__Attributes
-|   |       |__ConfiguratioNumber
-|   |__NumberOfInterfaces
+C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
+| | |       |       |      |__MaxPower in mA
+| | |       |       |__Attributes
+| | |       |__ConfiguratioNumber
+| | |__NumberOfInterfaces
+| |__ "*" indicates the active configuration (others are " ")
 |__Config info tag
+    
+    USB devices may have multiple configurations, each of which act
+    rather differently.  For example, a bus-powered configuration
+    might be much less capable than one that is self-powered.  Only
+    one device configuration can be active at a time; most devices
+    have only one configuration.
+
+    Each configuration consists of one or more interfaces.  Each
+    interface serves a distinct "function", which is typically bound
+    to a different USB device driver.  One common example is a USB
+    speaker with an audio interface for playback, and a HID interface
+    for use with software volume control.
 
 
 Interface descriptor info (can be multiple per Config):
 
 I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
 |   |      |      |       |             |      |       |__Driver name
+|   |      |      |       |             |      |          or "(none)"
 |   |      |      |       |             |      |__InterfaceProtocol
 |   |      |      |       |             |__InterfaceSubClass
 |   |      |      |       |__InterfaceClass
@@ -148,16 +247,38 @@
 |   |__InterfaceNumber
 |__Interface info tag
 
+    A given interface may have one or more "alternate" settings.
+    For example, default settings may not use more than a small
+    amount of periodic bandwidth.  To use significant fractions
+    of bus bandwidth, drivers must select a non-default altsetting.
+    
+    Only one setting for an interface may be active at a time, and
+    only one driver may bind to an interface at a time.  Most devices
+    have only one alternate setting per interface.
+
 
 Endpoint descriptor info (can be multiple per Interface):
 
-E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
-|   |        |            |         |__Interval
+E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddss
+|   |        |            |         |__Interval (max) between transfers
 |   |        |            |__EndpointMaxPacketSize
 |   |        |__Attributes(EndpointType)
 |   |__EndpointAddress(I=In,O=Out)
 |__Endpoint info tag
+
+    The interval is nonzero for all periodic (interrupt or isochronous)
+    endpoints.  For high speed endpoints the transfer interval may be
+    measured in microseconds rather than milliseconds.
+
+    For high speed periodic endpoints, the "MaxPacketSize" reflects
+    the per-microframe data transfer size.  For "high bandwidth"
+    endpoints, that can reflect two or three packets (for up to
+    3KBytes every 125 usec) per endpoint.
+
+    With the Linux-USB stack, periodic bandwidth reservations use the
+    transfer intervals and sizes provided by URBs, which can be less
+    than those found in endpoint descriptor.
+
 
 =======================================================================
 
diff -Nru a/Documentation/usb/se401.txt b/Documentation/usb/se401.txt
--- a/Documentation/usb/se401.txt	Wed Apr  3 17:11:13 2002
+++ b/Documentation/usb/se401.txt	Wed Apr  3 17:11:13 2002
@@ -40,7 +40,7 @@
 KNOWN PROBLEMS:
 
 The driver works fine with the usb-ohci and uhci host controller drivers,
-the default settings also work with usb-uhci. But sending more then one bulk
+the default settings also work with usb-uhci. But sending more than one bulk
 transfer at a time with usb-uhci doesn't work yet.
 Users of usb-ohci and uhci can safely enlarge SE401_NUMSBUF in se401.h in
 order to increase the throughput (and thus framerate).
diff -Nru a/Documentation/usb/silverlink.txt b/Documentation/usb/silverlink.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/usb/silverlink.txt	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,76 @@
+-------------------------------------------------------------------------
+Readme for Linux device driver for the Texas Instruments SilverLink cable
+-------------------------------------------------------------------------
+
+Author: Romain Liévin & Julien Blache
+Homepage: http://lpg.ticalc.org/prj_usb
+
+INTRODUCTION:
+
+This is a driver for the TI-GRAPH LINK USB (aka SilverLink) cable, a cable 
+designed by TI for connecting their TI8x/9x calculators to a computer 
+(PC or Mac usually).
+
+If you need more information, please visit the 'SilverLink drivers' homepage 
+at the above URL.
+
+WHAT YOU NEED:
+
+A TI calculator of course and a program capable to communicate with your 
+calculator.
+TiLP will work for sure (since I am his developer !). yal92 may be able to use
+it by changing tidev for tiglusb (may require some hacking...).
+
+HOW TO USE IT:
+
+You must have first compiled USB support, support for your specific USB host
+controller (UHCI or OHCI).
+
+Next, (as root) from your appropriate modules directory (lib/modules/2.5.XX):
+
+       insmod usb/usbcore.o
+       insmod usb/usb-uhci.o  <OR>  insmod usb/ohci-hcd.o
+       insmod tiglusb.o
+
+If it is not already there (it usually is), create the device:
+
+       mknod /dev/tiglusb0 c 115 16
+
+You will have to set permissions on this device to allow you to read/write
+from it:
+
+       chmod 666 /dev/tiglusb0
+       
+Now you are ready to run a linking program such as TiLP. Be sure to configure 
+it properly (RTFM).
+       
+MODULE PARAMETERS:
+
+  You can set these with:  insmod tiglusb NAME=VALUE
+  There is currently no way to set these on a per-cable basis.
+
+  NAME: timeout
+  TYPE: integer
+  DEFAULT: 15
+  DESC: Timeout value in tenth of seconds. If no data is available once this 
+       time has expired then the driver will return with a timeout error.
+
+QUIRKS:
+
+The following problem seems to be specific to the link cable since it appears 
+on all platforms (Linux, Windows, Mac OS-X). 
+
+In some very particular cases, the driver returns with success but
+without any data. The application should retry a read operation at least once.
+
+HOW TO CONTACT US:
+
+You can email me at roms@lpg.ticalc.org. Please prefix the subject line
+with "TIGLUSB: " so that I am certain to notice your message.
+You can also mail JB at jb@jblache.org: he has written the first release of 
+this driver but he better knows the Mac OS-X driver.
+
+CREDITS:
+
+The code is based on dabusb.c, printer.c and scanner.c !
+The driver has been developed independantly of Texas Instruments.
diff -Nru a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
--- a/Documentation/video4linux/Zoran	Wed Apr  3 17:11:15 2002
+++ b/Documentation/video4linux/Zoran	Wed Apr  3 17:11:15 2002
@@ -160,9 +160,9 @@
   set aside the necessary memory during boot time. There seem to be
   several versions of this patch against various kernel versions
   floating around in the net, you may obtain one e.g. from:
-  http://www.polyware.nl/~middelin/patch/bigphysarea-2.2.1.tar.gz You
-  also have to compile your driver AFTER installing that patch in order
-  to get it working
+  http://www.polyware.nl/~middelin/hob-v4l.html#bigphysarea
+  You also have to compile your driver AFTER installing that patch in
+  order to get it working
 
   or
 
diff -Nru a/Documentation/video4linux/bttv/README.freeze b/Documentation/video4linux/bttv/README.freeze
--- a/Documentation/video4linux/bttv/README.freeze	Wed Apr  3 17:11:13 2002
+++ b/Documentation/video4linux/bttv/README.freeze	Wed Apr  3 17:11:13 2002
@@ -46,10 +46,6 @@
 the PCI bus. The bt848/878 chips have a few workarounds for known
 incompatibilities, see README.quirks.
 
-Some folks report that increasing the pci latency helps too,
-althrought I'm not sure whenever this really fixes the problems or
-only makes it less likely to happen.
-
 Some mainboard have problems to deal correctly with multiple devices
 doing DMA at the same time.  bttv + ide seems to cause this sometimes,
 if this is the case you likely see freezes only with video and hard disk
diff -Nru a/Documentation/video4linux/w9966.txt b/Documentation/video4linux/w9966.txt
--- a/Documentation/video4linux/w9966.txt	Wed Apr  3 17:11:15 2002
+++ b/Documentation/video4linux/w9966.txt	Wed Apr  3 17:11:15 2002
@@ -1,37 +1,33 @@
+W9966 Camera driver, written by Jakob Kemi (jakob.kemi@telia.com)
 
-W9966 Camera driver, written by Jakob Kemi (jakob.kemi@post.utfors.se)
+After a lot of work in softice & wdasm, reading .pdf-files and tiresome
+trial-and-error work I've finally got everything to work. I needed vision for a
+robotics project so I borrowed this camera from a friend and started hacking.
+Anyway I've converted my original code from the AVR 8bit RISC C/ASM code into
+a working Linux driver.
 
-Ok, after a lot of work in softice, wdasm, reading pdf-files
-and trial-and-error work I've finally got everything to work.
-Since I needed some vision for a robotics project I borrowed
-this camera from a friend and started hacking. Anyway I've
-converted my original code from the AVR 8bit RISC C/asm
-into a working linux driver. I would really appreciate _any_
-kind of feedback regarding this driver.
-
-To get it working quickly configure your kernel
-to support parport, ieee1284, video4linux, experimental drivers
-and w9966
+To get it working simply configure your kernel to support
+parport, ieee1284, video4linux and w9966
 
-If w9966 is statically linked it will perform aggressive probing
-for the camera. If built as a module you'll have more configuration options.
+If w9966 is statically linked it will always perform aggressive probing for
+the camera. If built as a module you'll have more configuration options.
 
 Options:
-modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
- 
+ modprobe w9966.o pardev=parport0(or whatever) parmode=0 (0=auto, 1=ecp, 2=epp)
 voila!
 
 you can also type 'modinfo -p w9966.o' for option usage
 (or checkout w9966.c)
 
-I've only tested it with custom built testprograms
-(http://hem.fyristorg.com/mogul/w9966.html) and with gqcam.
-(you'll need to tweak the code to qcam a bit to make it work,
-dimensions and such)
+The only thing to keep in mind is that the image format is in Y-U-Y-V format
+where every two pixels take 4 bytes. In SDL (www.libsdl.org) this format
+is called VIDEO_PALETTE_YUV422 (16 bpp).
+
+A minimal test application (with source) is available from:
+  http://hem.fyristorg.com/mogul/w9966.html
 
 The slow framerate is due to missing DMA ECP read support in the 
 parport drivers. I might add working EPP support later.
 
 Good luck!
-
-    /Jakob
+    /Jakob Kemi
diff -Nru a/Documentation/watchdog-api.txt b/Documentation/watchdog-api.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/watchdog-api.txt	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,390 @@
+The Linux Watchdog driver API.
+
+Copyright 2002 Christer Weingel <wingel@nano-system.com>
+
+Some parts of this document are copied verbatim from the sbc60xxwdt
+driver which is (c) Copyright 2000 Jakob Oestergaard <jakob@ostenfeld.dk>
+
+This document describes the state of the Linux 2.4.18 kernel.
+
+Introduction:
+
+A Watchdog Timer (WDT) is a hardware circuit that can reset the
+computer system in case of a software fault.  You probably knew that
+already.
+
+Usually a userspace daemon will notify the kernel watchdog driver via the
+/dev/watchdog special device file that userspace is still alive, at
+regular intervals.  When such a notification occurs, the driver will
+usually tell the hardware watchdog that everything is in order, and
+that the watchdog should wait for yet another little while to reset
+the system.  If userspace fails (RAM error, kernel bug, whatever), the
+notifications cease to occur, and the hardware watchdog will reset the
+system (causing a reboot) after the timeout occurs.
+
+The Linux watchdog API is a rather AD hoc construction and different
+drivers implement different, and sometimes incompatible, parts of it.
+This file is an attempt to document the existing usage and allow
+future driver writers to use it as a reference.
+
+The simplest API:
+
+All drivers support the basic mode of operation, where the watchdog
+activates as soon as /dev/watchdog is opened and will reboot unless
+the watchdog is pinged within a certain time, this time is called the
+timeout or margin.  The simplest way to ping the watchdog is to write
+some data to the device.  So a very simple watchdog daemon would look
+like this:
+
+int main(int argc, const char *argv[]) {
+	int fd=open("/dev/watchdog",O_WRONLY);
+	if (fd==-1) {
+		perror("watchdog");
+		exit(1);
+	}
+	while(1) {
+		write(fd, "\0", 1);
+		sleep(10);
+	}
+}
+
+A more advanced driver could for example check that a HTTP server is
+still responding before doing the write call to ping the watchdog.
+
+When the device is closed, the watchdog is disabled.  This is not
+always such a good idea, since if there is a bug in the watchdog
+daemon and it crashes the system will not reboot.  Because of this,
+some of the drivers support the configuration option "Disable watchdog
+shutdown on close", CONFIG_WATCHDOG_NOWAYOUT.  If it is set to Y when
+compiling the kernel, there is no way of disabling the watchdog once
+it has been started.  So, if the watchdog dameon crashes, the system
+will reboot after the timeout has passed.
+
+Some other drivers will not disable the watchdog, unless a specific
+magic character 'V' has been sent /dev/watchdog just before closing
+the file.  If the userspace daemon closes the file without sending
+this special character, the driver will assume that the daemon (and
+userspace in general) died, and will stop pinging the watchdog without
+disabling it first.  This will then cause a reboot.
+
+The ioctl API:
+
+All conforming drivers also support an ioctl API.
+
+Pinging the watchdog using an ioctl:
+
+All drivers that have an ioctl interface support at least one ioctl,
+KEEPALIVE.  This ioctl does exactly the same thing as a write to the
+watchdog device, so the main loop in the above program could be
+replaced with:
+
+	while (1) {
+		ioctl(fd, WDIOC_KEEPALIVE, 0);
+		sleep(10);
+	}
+
+the argument to the ioctl is ignored.
+
+Setting and getting the timeout:
+
+For some drivers it is possible to modify the watchdog timeout on the
+fly with the SETTIMEOUT ioctl, those drivers have the WDIOF_SETTIMEOUT
+flag set in their option field.  The argument is an integer
+representing the timeout in seconds.  The driver returns the real
+timeout used in the same variable, and this timeout might differ from
+the requested one due to limitation of the hardware.
+
+    int timeout = 45;
+    ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
+    printf("The timeout was set to %d seconds\n", timeout);
+
+This example might actually print "The timeout was set to 60 seconds"
+if the device has a granularity of minutes for its timeout.
+
+Starting with the Linux 2.4.18 kernel, it is possible to query the
+current timeout using the GETTIMEOUT ioctl.
+
+    ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
+    printf("The timeout was is %d seconds\n", timeout);
+
+Envinronmental monitoring:
+
+All watchdog drivers are required return more information about the system,
+some do temperature, fan and power level monitoring, some can tell you
+the reason for the last reboot of the system.  The GETSUPPORT ioctl is
+available to ask what the device can do:
+
+	struct watchdog_info ident;
+	ioctl(fd, WDIOC_GETSUPPORT, &ident);
+
+the fields returned in the ident struct are:
+
+        identity		a string identifying the watchdog driver
+	firmware_version	the firmware version of the card if available
+	options			a flags describing what the device supports
+
+the options field can have the following bits set, and describes what
+kind of information that the GET_STATUS and GET_BOOT_STATUS ioctls can
+return.   [FIXME -- Is this correct?]
+
+	WDIOF_OVERHEAT		Reset due to CPU overheat
+
+The machine was last rebooted by the watchdog because the thermal limit was
+exceeded
+
+	WDIOF_FANFAULT		Fan failed
+
+A system fan monitored by the watchdog card has failed
+
+	WDIOF_EXTERN1		External relay 1
+
+External monitoring relay/source 1 was triggered. Controllers intended for
+real world applications include external monitoring pins that will trigger
+a reset.
+
+	WDIOF_EXTERN2		External relay 2
+
+External monitoring relay/source 2 was triggered
+
+	WDIOF_POWERUNDER	Power bad/power fault
+
+The machine is showing an undervoltage status
+
+	WDIOF_CARDRESET		Card previously reset the CPU
+
+The last reboot was caused by the watchdog card
+
+	WDIOF_POWEROVER		Power over voltage
+
+The machine is showing an overvoltage status. Note that if one level is
+under and one over both bits will be set - this may seem odd but makes
+sense.
+
+	WDIOF_KEEPALIVEPING	Keep alive ping reply
+
+The watchdog saw a keepalive ping since it was last queried.
+
+	WDIOF_SETTIMEOUT	Can set/get the timeout
+
+
+For those drivers that return any bits set in the option field, the
+GETSTATUS and GETBOOTSTATUS ioctls can be used to ask for the current
+status, and the status at the last reboot, respectively.  
+
+    int flags;
+    ioctl(fd, WDIOC_GETSTATUS, &flags);
+
+    or
+
+    ioctl(fd, WDIOC_GETBOOTSTATUS, &flags);
+
+Note that not all devices support these two calls, and some only
+support the GETBOOTSTATUS call.
+
+Some drivers can measure the temperature using the GETTEMP ioctl.  The
+returned value is the temperature in degrees farenheit.
+
+    int temperature;
+    ioctl(fd, WDIOC_GETTEMP, &temperature);
+
+Finally the SETOPTIONS ioctl can be used to control some aspects of
+the cards operation; right now the pcwd driver is the only one
+supporting thiss ioctl.
+
+    int options = 0;
+    ioctl(fd, WDIOC_SETOPTIONS, options);
+
+The following options are available:
+
+	WDIOS_DISABLECARD	Turn off the watchdog timer
+	WDIOS_ENABLECARD	Turn on the watchdog timer
+	WDIOS_TEMPPANIC		Kernel panic on temperature trip
+
+[FIXME -- better explanations]
+
+Implementations in the current drivers in the kernel tree:
+
+Here I have tried to summarize what the different drivers support and
+where they do strange things compared to the other drivers.
+
+acquirewdt.c -- Acquire Single Board Computer
+
+	This driver has a hardcoded timeout of 1 minute
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns KEEPALIVEPING.  GETSTATUS will return 1 if
+	the device is open, 0 if not.  [FIXME -- isn't this rather
+	silly?  To be able to use the ioctl, the device must be open
+	and so GETSTATUS will always return 1].
+
+advantechwdt.c -- Advantech Single Board Computer
+
+	Timeout that defaults to 60 seconds, supports SETTIMEOUT.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT.
+	The GETSTATUS call returns if the device is open or not.
+	[FIXME -- silliness again?]
+	
+eurotechwdt.c -- Eurotech CPU-1220/1410
+
+	The timeout can be set using the SETTIMEOUT ioctl and defaults
+	to 60 seconds.
+
+	Also has a module parameter "ev", event type which controls
+	what should happen on a timeout, the string "int" or anything
+	else that causes a reboot.  [FIXME -- better description]
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns CARDRESET and WDIOF_SETTIMEOUT but
+	GETSTATUS is not supported and GETBOOTSTATUS just returns 0.
+
+i810-tco.c -- Intel 810 chipset
+
+	Also has support for a lot of other i8x0 stuff, but the
+	watchdog is one of the things.
+
+	The timeout is set using the module parameter "i810_margin",
+	which is in steps of 0.6 seconds where 2<i810_margin<64.  The
+	driver supports the SETTIMEOUT ioctl.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT.
+
+	GETSUPPORT returns WDIOF_SETTIMEOUT.  The GETSTATUS call
+	returns some kind of timer value which ist not compatible with
+	the other drivers.  GETBOOT status returns some kind of
+	hardware specific boot status.  [FIXME -- describe this]
+
+ib700wdt.c -- IB700 Single Board Computer
+
+	Default timeout of 30 seconds and the timeout is settable
+	using the SETTIMEOUT ioctl.  Note that only a few timeout
+	values are supported.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns WDIOF_KEEPALIVEPING and WDIOF_SETTIMEOUT.
+	The GETSTATUS call returns if the device is open or not.
+	[FIXME -- silliness again?]
+
+machzwd.c -- MachZ ZF-Logic
+
+	Hardcoded timeout of 10 seconds
+
+	Has a module parameter "action" that controls what happens
+	when the timeout runs out which can be 0 = RESET (default), 
+	1 = SMI, 2 = NMI, 3 = SCI.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT and the the magic character
+	'V' close handling.
+
+	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
+	returns if the device is open or not.  [FIXME -- silliness
+	again?]
+
+mixcomwd.c -- MixCom Watchdog
+
+	[FIXME -- I'm unable to tell what the timeout is]
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns WDIOF_KEEPALIVEPING, GETSTATUS returns if
+	the device is opened or not [FIXME -- I'm not really sure how
+	this works, there seems to be some magic connected to
+	CONFIG_WATCHDOG_NOWAYOUT]
+
+pcwd.c -- Berkshire PC Watchdog
+
+	Hardcoded timeout of 1.5 seconds
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns WDIOF_OVERHEAT|WDIOF_CARDRESET and both
+	GETSTATUS and GETBOOTSTATUS return something useful.
+
+	The SETOPTIONS call can be used to enable and disable the card
+	and to ask the driver to call panic if the system overheats.
+
+sbc60xxwdt.c -- 60xx Single Board Computer
+
+	Hardcoded timeout of 10 seconds
+
+	Does not support CONFIG_WATCHDOG_NOWAYOUT, but has the magic
+	character 'V' close handling.
+
+	No bits set in GETSUPPORT
+
+scx200.c -- National SCx200 CPUs
+
+	Not in the kernel yet.
+
+	The timeout is set using a module parameter "margin" which
+	defaults to 60 seconds.  The timeout can also be set using
+	SETTIMEOUT and read using GETTIMEOUT.
+
+	Supports a module parameter "nowayout" that is initialized
+	with the value of CONFIG_WATCHDOG_NOWAYOUT.  Also supports the
+	magic character 'V' handling.
+
+shwdt.c -- SuperH 3/4 processors
+
+	[FIXME -- I'm unable to tell what the timeout is]
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns WDIOF_KEEPALIVEPING, and the GETSTATUS call
+	returns if the device is open or not.  [FIXME -- silliness
+	again?]
+
+softdog.c -- Software watchdog
+
+	The timeout is set with the module parameter "soft_margin"
+	which defaults to 60 seconds, the timeout is also settable
+	using the SETTIMEOUT ioctl.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	WDIOF_SETTIMEOUT bit set in GETSUPPORT
+
+w83877f_wdt.c -- W83877F Computer
+
+	Hardcoded timeout of 30 seconds
+
+	Does not support CONFIG_WATCHDOG_NOWAYOUT, but has the magic
+	character 'V' close handling.
+
+	No bits set in GETSUPPORT
+
+wdt.c -- ICS WDT500/501 ISA and
+wdt_pci.c -- ICS WDT500/501 PCI
+
+	Default timeout of 60 seconds.  The timeout is also settable
+        using the SETTIMEOUT ioctl.
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	GETSUPPORT returns with bits set depending on the actual
+	card. The WDT501 supports a lot of external monitoring, the
+	WDT500 much less.
+
+wdt285.c -- Footbridge watchdog
+
+	The timeout is set with the module parameter "soft_margin"
+	which defaults to 60 seconds.  The timeout is also settable
+	using the SETTIMEOUT ioctl.
+
+	Does not support CONFIG_WATCHDOG_NOWAYOUT
+
+	WDIOF_SETTIMEOUT bit set in GETSUPPORT
+
+wdt977.c -- Netwinder W83977AF chip
+
+	Hardcoded timeout of 3 minutes
+
+	Supports CONFIG_WATCHDOG_NOWAYOUT
+
+	Does not support any ioctls at all.
+
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Wed Apr  3 17:11:14 2002
+++ b/MAINTAINERS	Wed Apr  3 17:11:14 2002
@@ -1437,8 +1437,6 @@
 M:	anton@samba.org
 L:	sparclinux@vger.kernel.org
 L:	ultralinux@vger.kernel.org
-W:	http://ultra.linux.cz
-W:	http://www.geog.ubc.ca/s_linux.html
 S:	Maintained
 
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
@@ -1502,6 +1500,13 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TI GRAPH LINK USB (SilverLink) CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+P:     Julien Blache
+M:     jb@technologeek.org
+S:     Maintained
+
 TLAN NETWORK DRIVER
 P:	Torben Mathiasen
 M:	torben.mathiasen@compaq.com
@@ -1660,6 +1665,7 @@
 M:	petkan@users.sourceforge.net
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
+W:	http://pegasus2.sourceforge.net/
 S:	Maintained
 
 USB PRINTER DRIVER
@@ -1667,6 +1673,14 @@
 M:	vojtech@suse.cz
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
+S:	Maintained
+
+USB RTL8150 DRIVER
+P:	Petko Manolov
+M:	petkan@users.sourceforge.net
+L:	linux-usb-users@lists.sourceforge.net
+L:	linux-usb-devel@lists.sourceforge.net
+W:	http://pegasus2.sourceforge.net/
 S:	Maintained
 
 USB SE401 DRIVER
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Wed Apr  3 17:11:14 2002
+++ b/Makefile	Wed Apr  3 17:11:14 2002
@@ -1,12 +1,12 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 7
-EXTRAVERSION =
+SUBLEVEL = 8
+EXTRAVERSION =-pre1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//")
+KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
 
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
 	  else if [ -x /bin/bash ]; then echo /bin/bash; \
@@ -341,7 +341,7 @@
 	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $<
 
 init/do_mounts.o: init/do_mounts.c include/config/MARKER
-	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -c -o $*.o $<
+	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $*.o $<
 
 fs lib mm ipc kernel drivers net sound: dummy
 	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Wed Apr  3 17:11:15 2002
+++ b/Rules.make	Wed Apr  3 17:11:15 2002
@@ -50,10 +50,10 @@
 #
 
 %.s: %.c
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -S $< -o $@
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@
 
 %.i: %.c
-	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) $< > $@
+	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@
 
 %.o: %.c
 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $<
diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/alpha/kernel/alpha_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -103,7 +103,6 @@
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c	Wed Apr  3 17:11:14 2002
+++ b/arch/alpha/kernel/setup.c	Wed Apr  3 17:11:14 2002
@@ -472,6 +472,7 @@
 	struct percpu_struct *cpu;
 	char *type_name, *var_name, *p;
 	void *kernel_end = _end; /* end of kernel */
+	char *args = command_line;
 
 	hwrpb = (struct hwrpb_struct*) __va(INIT_HWRPB->phys_addr);
 	boot_cpuid = hard_smp_processor_id();
@@ -509,7 +510,8 @@
 	/* 
 	 * Process command-line arguments.
 	 */
-	for (p = strtok(command_line, " \t"); p ; p = strtok(NULL, " \t")) {
+	while ((p = strsep(&args, " \t")) != NULL) {
+		if (!*p) continue;
 		if (strncmp(p, "alpha_mv=", 9) == 0) {
 			vec = get_sysvec_byname(p+9);
 			continue;
@@ -528,7 +530,7 @@
 		}
 	}
 
-	/* Replace the command line, now that we've killed it with strtok.  */
+	/* Replace the command line, now that we've killed it with strsep.  */
 	strcpy(command_line, saved_command_line);
 
 	/* If we want SRM console printk echoing early, do it now. */
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c	Wed Apr  3 17:11:15 2002
+++ b/arch/arm/kernel/armksyms.c	Wed Apr  3 17:11:15 2002
@@ -180,7 +180,7 @@
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strpbrk);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
 EXPORT_SYMBOL_NOVERS(memset);
diff -Nru a/arch/arm/mach-arc/dma.c b/arch/arm/mach-arc/dma.c
--- a/arch/arm/mach-arc/dma.c	Wed Apr  3 17:11:15 2002
+++ b/arch/arm/mach-arc/dma.c	Wed Apr  3 17:11:15 2002
@@ -100,7 +100,7 @@
 	/* 10/1/1999 DAG - Presume whether there is an outstanding command? */
 	extern unsigned int fdc1772_fdc_int_done;
 
-	* Explicit! If the int done is 0 then 1 int to go */
+	/* Explicit! If the int done is 0 then 1 int to go */
 	return (fdc1772_fdc_int_done==0)?1:0;
 }
 
diff -Nru a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c
--- a/arch/cris/drivers/ethernet.c	Wed Apr  3 17:11:15 2002
+++ b/arch/cris/drivers/ethernet.c	Wed Apr  3 17:11:15 2002
@@ -996,7 +996,7 @@
 	int i;
 #endif
 
-	if (!led_active && jiffies > led_next_time) {
+	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
 
@@ -1288,7 +1288,7 @@
 {
 	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
 
-	if (!led_active && jiffies > led_next_time) {
+	if (!led_active && time_after(jiffies, led_next_time)) {
 		/* light the network leds depending on the current speed. */
 		e100_set_network_leds(NETWORK_ACTIVITY);
 
@@ -1313,7 +1313,7 @@
 static void
 e100_clear_network_leds(unsigned long dummy)
 {
-	if (led_active && jiffies > led_next_time) {
+	if (led_active && jiffies > time_after(jiffies, led_next_time)) {
 		e100_set_network_leds(NO_NETWORK_ACTIVITY);
 
 		/* Set the earliest time we may set the LED */
diff -Nru a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c
--- a/arch/cris/drivers/gpio.c	Wed Apr  3 17:11:13 2002
+++ b/arch/cris/drivers/gpio.c	Wed Apr  3 17:11:13 2002
@@ -217,7 +217,7 @@
 gpio_open(struct inode *inode, struct file *filp)
 {
 	struct gpio_private *priv;
-	int p = MINOR(inode->i_rdev);
+	int p = minor(inode->i_rdev);
 
 	if (p >= NUM_PORTS && p != LEDS)
 		return -EINVAL;
diff -Nru a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c
--- a/arch/cris/drivers/ide.c	Wed Apr  3 17:11:14 2002
+++ b/arch/cris/drivers/ide.c	Wed Apr  3 17:11:14 2002
@@ -271,10 +271,10 @@
 
 	printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
 
-	/* first fill in some stuff in the ide_hwifs fields */
+	/* first initialize the channel interface data */
 	
 	for(h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
+		struct ata_channel *hwif = &ide_hwifs[h];
 		hwif->chipset = ide_etrax100;
 		hwif->tuneproc = &tune_e100_ide;
 		hwif->dmaproc = &e100_dmaproc;
@@ -355,7 +355,7 @@
 	printk("ide: waiting %d seconds for drives to regain consciousness\n", CONFIG_ETRAX_IDE_DELAY);
 
 	h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
-	while(jiffies < h) ;
+	while(time_before(jiffies, h)) ;
 
   /* reset the dma channels we will use */
 
@@ -717,7 +717,7 @@
 	LED_DISK_READ(0);
 	LED_DISK_WRITE(0);
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
@@ -798,7 +798,7 @@
 	 * not a diskdrive.
 	 */
 
-        if (drive->media != ide_disk)
+        if (drive->type != ATA_DISK)
                 return 0;
 
  dma_begin:
@@ -809,7 +809,7 @@
 		WAIT_DMA(ATA_RX_DMA_NBR);
 
 		/* set up the Etrax DMA descriptors */
-		
+
 		if(e100_ide_build_dmatable (drive))
 			return 1;
 
@@ -902,7 +902,7 @@
  * --- Marcin Dalecki
  */
 
-void ide_release_dma (ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
 {
 	/* empty */
 }
diff -Nru a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c
--- a/arch/cris/kernel/ksyms.c	Wed Apr  3 17:11:16 2002
+++ b/arch/cris/kernel/ksyms.c	Wed Apr  3 17:11:16 2002
@@ -38,9 +38,7 @@
 /* String functions */
 EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strchr);
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
--- a/arch/i386/Config.help	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/Config.help	Wed Apr  3 17:11:14 2002
@@ -128,6 +128,12 @@
 
   If unsure, say "off".
 
+CONFIG_HIGHPTE
+  The VM uses one page table entry for each page of physical memory.
+  For systems with a lot of RAM, this can be wasteful of precious
+  low memory.  Setting this option will put user-space page table
+  entries in high memory.
+
 CONFIG_HIGHMEM4G
   Select this if you have a 32-bit processor and between 1 and 4
   gigabytes of physical RAM.
@@ -797,6 +803,30 @@
   a work-around for a number of buggy BIOSes. Switch this option on if
   your computer crashes instead of powering off properly.
 
+CONFIG_X86_MCE
+  Machine Check Exception support allows the processor to notify the
+  kernel if it detects a problem (e.g. overheating, component failure).
+  The action the kernel takes depends on the severity of the problem,
+  ranging from a warning message on the console, to halting the machine.
+  Your processor must be a Pentium or newer to support this - check the
+  flags in /proc/cpuinfo for mce.  Note that some older Pentium systems
+  have a design flaw which leads to false MCE events - hence MCE is
+  disabled on all P5 processors, unless explicitly enabled with "mce"
+  as a boot argument.  Similarly, if MCE is built in and creates a
+  problem on some new non-standard machine, you can boot with "nomce"
+  to disable it.  MCE support simply ignores non-MCE processors like
+  the 386 and 486, so nearly everyone can say Y here.
+
+CONFIG_X86_MCE_NONFATAL
+  Enabling this feature starts a timer that triggers every 5 seconds which
+  will look at the machine check registers to see if anything happened.
+  Non-fatal problems automatically get corrected (but still logged).
+  Disable this if you don't want to see these messages.
+  Seeing the messages this option prints out may be indicative of dying hardware,
+  or out-of-spec (ie, overclocked) hardware.
+  This option only does something on hardware with Intel P6 style MCE.
+  (Pentium Pro and above, AMD Athlon/Duron)
+				 
 CONFIG_TOSHIBA
   This adds a driver to safely access the System Management Mode of
   the CPU on Toshiba portables with a genuine Toshiba BIOS. It does
@@ -903,3 +933,6 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+CONFIG_DEBUG_OBSOLETE
+  Say Y here if you want to reduce the chances of the tree compiling,
+  and are prepared to dig into driver internals to fix compile errors.
diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S	Wed Apr  3 17:11:13 2002
+++ b/arch/i386/boot/setup.S	Wed Apr  3 17:11:13 2002
@@ -544,7 +544,7 @@
 	cmpw	$0, %cs:realmode_swtch
 	jz	rmodeswtch_normal
 
-	lcall	*%cs:realmode_swtch
+	lcall	%cs:realmode_swtch
 
 	jmp	rmodeswtch_end
 
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/config.in	Wed Apr  3 17:11:14 2002
@@ -25,6 +25,7 @@
 	 Pentium-4				CONFIG_MPENTIUM4 \
 	 K6/K6-II/K6-III			CONFIG_MK6 \
 	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Elan					CONFIG_MELAN \
 	 Crusoe					CONFIG_MCRUSOE \
 	 Winchip-C6				CONFIG_MWINCHIPC6 \
 	 Winchip-2				CONFIG_MWINCHIP2 \
@@ -119,6 +120,11 @@
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
+if [ "$CONFIG_MELAN" = "y" ]; then
+   define_int  CONFIG_X86_L1_CACHE_SHIFT 4
+   define_bool CONFIG_X86_USE_STRING_486 y
+   define_bool CONFIG_X86_ALIGNMENT_16 y
+fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_TSC y
@@ -150,6 +156,10 @@
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
 fi
+
+bool 'Machine Check Exception' CONFIG_X86_MCE
+dep_bool 'Check for non-fatal errors' CONFIG_X86_MCE_NONFATAL $CONFIG_X86_MCE
+
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 tristate 'Dell laptop support' CONFIG_I8K
 
@@ -160,23 +170,18 @@
 choice 'High Memory Support' \
 	"off           CONFIG_NOHIGHMEM \
 	 4GB           CONFIG_HIGHMEM4G \
-	 4GB-highpte   CONFIG_HIGHMEM4G_HIGHPTE \
-	 64GB          CONFIG_HIGHMEM64G \
-	 64GB-highpte  CONFIG_HIGHMEM64G_HIGHPTE" off
-if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
-   define_bool CONFIG_HIGHMEM y
+	 64GB          CONFIG_HIGHMEM64G" off
+
+if [ "$CONFIG_HIGHMEM4G" = "y" -o "$CONFIG_HIGHMEM64G" = "y" ]; then
+   bool 'Use high memory pte support' CONFIG_HIGHPTE
 fi
-if [ "$CONFIG_HIGHMEM4G_HIGHPTE" = "y" ]; then
+
+if [ "$CONFIG_HIGHMEM4G" = "y" ]; then
    define_bool CONFIG_HIGHMEM y
-   define_bool CONFIG_HIGHPTE y
 fi
+
 if [ "$CONFIG_HIGHMEM64G" = "y" ]; then
    define_bool CONFIG_HIGHMEM y
-   define_bool CONFIG_X86_PAE y
-fi
-if [ "$CONFIG_HIGHMEM64G_HIGHPTE" = "y" ]; then
-   define_bool CONFIG_HIGHMEM y
-   define_bool CONFIG_HIGHPTE y
    define_bool CONFIG_X86_PAE y
 fi
 
diff -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/defconfig	Wed Apr  3 17:11:14 2002
@@ -39,6 +39,7 @@
 # CONFIG_MPENTIUM4 is not set
 # CONFIG_MK6 is not set
 # CONFIG_MK7 is not set
+# CONFIG_MELAN is not set
 # CONFIG_MCRUSOE is not set
 # CONFIG_MWINCHIPC6 is not set
 # CONFIG_MWINCHIP2 is not set
@@ -57,6 +58,8 @@
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_PGE=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_MCE=y
+# CONFIG_X86_MCE_NONFATAL is not set
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
 # CONFIG_MICROCODE is not set
@@ -64,9 +67,7 @@
 # CONFIG_X86_CPUID is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
-# CONFIG_HIGHMEM4G_HIGHPTE is not set
 # CONFIG_HIGHMEM64G is not set
-# CONFIG_HIGHMEM64G_HIGHPTE is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_MTRR is not set
 CONFIG_SMP=y
@@ -103,7 +104,6 @@
 # CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
-# CONFIG_PCMCIA_SA1100 is not set
 
 #
 # PCI Hotplug Support
@@ -268,7 +268,6 @@
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
@@ -276,7 +275,6 @@
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_PIIX=y
-CONFIG_PIIX_TUNING=y
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC_ADMA is not set
@@ -291,7 +289,6 @@
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/Makefile	Wed Apr  3 17:11:14 2002
@@ -18,7 +18,8 @@
 
 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 \
-		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o
+		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
+		bootflag.o
 
 
 ifdef CONFIG_PCI
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/apic.c	Wed Apr  3 17:11:15 2002
@@ -90,7 +90,7 @@
 		apic_write_around(APIC_LVTPC, APIC_LVT_MASKED);
 	v = GET_APIC_VERSION(apic_read(APIC_LVR));
 	if (APIC_INTEGRATED(v)) {	/* !82489DX */
-		if (maxlvt > 3)
+		if (maxlvt > 3)		/* Due to Pentium errata 3AP and 11AP. */
 			apic_write(APIC_ESR, 0);
 		apic_read(APIC_ESR);
 	}
@@ -449,6 +449,7 @@
 	unsigned int apic_lvterr;
 	unsigned int apic_tmict;
 	unsigned int apic_tdcr;
+	unsigned int apic_thmr;
 } apic_pm_state;
 
 static void apic_pm_suspend(void *data)
@@ -470,6 +471,7 @@
 	apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
 	apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
 	apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
+	apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
 	__save_flags(flags);
 	__cli();
 	disable_local_APIC();
@@ -498,6 +500,7 @@
 	apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
 	apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
 	apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
+	apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
 	apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
 	apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
 	apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/bluesmoke.c	Wed Apr  3 17:11:14 2002
@@ -3,16 +3,128 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/config.h>
+#include <linux/irq.h>
 #include <asm/processor.h> 
+#include <asm/system.h>
 #include <asm/msr.h>
+#include <asm/apic.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_X86_MCE
 
 static int mce_disabled __initdata = 0;
 
+static int banks;
+
 /*
- *	Machine Check Handler For PII/PIII
+ * If we get an MCE, we don't know what state the caches/TLB's are
+ * going to be in, so we throw them all away.
  */
+static void inline flush_all (void)
+{   
+	__asm__ __volatile__ ("invd": : );
+	__flush_tlb();
+}
 
-static int banks;
+/*
+ *	P4/Xeon Thermal transition interrupt handler
+ */
+
+static void intel_thermal_interrupt(struct pt_regs *regs)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	u32 l, h;
+	unsigned int cpu = smp_processor_id();
+
+	ack_APIC_irq();
+
+	rdmsr(MSR_IA32_THERM_STATUS, l, h);
+	if (l & 1) {
+		printk(KERN_EMERG "CPU#%d: Temperature above threshold\n", cpu);
+		printk(KERN_EMERG "CPU#%d: Running in modulated clock mode\n", cpu);
+	} else {
+		printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
+	}
+#endif
+}
+
+static void unexpected_thermal_interrupt(struct pt_regs *regs)
+{	
+	printk(KERN_ERR "CPU#%d: Unexpected LVT TMR interrupt!\n", smp_processor_id());
+}
+
+/*
+ *	Thermal interrupt handler for this CPU setup
+ */
+
+static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
+
+asmlinkage void smp_thermal_interrupt(struct pt_regs regs)
+{
+	vendor_thermal_interrupt(&regs);
+}
+
+/* P4/Xeon Thermal regulation detect and init */
+
+static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	u32 l, h;
+	unsigned int cpu = smp_processor_id();
+
+	/* Thermal monitoring */
+	if (!test_bit(X86_FEATURE_ACPI, &c->x86_capability))
+		return;	/* -ENODEV */
+	
+	/* Clock modulation */
+	if (!test_bit(X86_FEATURE_ACC, &c->x86_capability))
+		return;	/* -ENODEV */
+
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	/* first check if its enabled already, in which case there might
+	 * be some SMM goo which handles it, so we can't even put a handler
+	 * since it might be delivered via SMI already -zwanem.
+	 */
+
+	if (l & (1<<3)) {
+		printk(KERN_DEBUG "CPU#%d: Thermal monitoring already enabled\n", cpu);
+	} else {
+		wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+		printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+	}
+
+	/* check wether a vector already exists */	
+	l = apic_read(APIC_LVTTHMR);
+	if (l & 0xff) {
+		printk(KERN_DEBUG "CPU#%d: Thermal LVT already handled\n", cpu);
+		return; /* -EBUSY */
+	}
+	
+	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+	
+	/* The temperature transition interrupt handler setup */
+	l = THERMAL_APIC_VECTOR;		/* our delivery vector */
+	l |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
+	apic_write_around(APIC_LVTTHMR, l);
+
+	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
+	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x3 , h);
+
+	/* ok we're good to go... */
+	vendor_thermal_interrupt = intel_thermal_interrupt;
+	l = apic_read(APIC_LVTTHMR);
+	apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+
+	return;
+#endif
+}
+
+/*
+ *	Machine Check Handler For PII/PIII
+ */
 
 static void intel_machine_check(struct pt_regs * regs, long error_code)
 {
@@ -20,7 +132,9 @@
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
 	int i;
-	
+
+	flush_all();
+
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 	if(mcgstl&(1<<0))	/* Recoverable ? */
 		recover=0;
@@ -41,13 +155,12 @@
 			if(high&(1<<27))
 			{
 				rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
-				printk("[%08x%08x]", alow, ahigh);
+				printk("[%08x%08x]", ahigh, alow);
 			}
 			if(high&(1<<26))
 			{
 				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
-				printk(" at %08x%08x", 
-					ahigh, alow);
+				printk(" at %08x%08x", ahigh, alow);
 			}
 			printk("\n");
 			/* Clear it */
@@ -109,8 +222,55 @@
 	machine_check_vector(regs, error_code);
 }
 
+
+#ifdef CONFIG_X86_MCE_NONFATAL
+struct timer_list mce_timer;
+
+static void mce_checkregs (unsigned int cpu)
+{
+	u32 low, high;
+	int i;
+
+	if (cpu!=smp_processor_id())
+		BUG();
+
+	for (i=0; i<banks; i++) {
+		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
+
+		if ((low | high) != 0) {
+			flush_all();
+			printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occured on CPU %d.\n", smp_processor_id());
+			printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
+
+			/* Scrub the error so we don't pick it up in 5 seconds time. */
+			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+
+			/* Serialize */
+			wmb();
+		}
+	}
+
+	/* Refresh the timer. */
+	mce_timer.expires = jiffies + 5 * HZ;
+	add_timer (&mce_timer);
+}
+
+static void mce_timerfunc (unsigned long data)
+{
+	int i;
+
+	for (i=0; i<smp_num_cpus; i++) {
+		if (i == smp_processor_id())
+			mce_checkregs(i);
+		else
+			smp_call_function (mce_checkregs, i, 1, 1);
+	}
+}
+#endif
+
+
 /*
- *	Set up machine check reporting for Intel processors
+ *	Set up machine check reporting for processors with Intel style MCE
  */
 
 static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
@@ -164,19 +324,27 @@
 	if(done==0)
 		printk(KERN_INFO "Intel machine check architecture supported.\n");
 	rdmsr(MSR_IA32_MCG_CAP, l, h);
-	if(l&(1<<8))
+	if(l&(1<<8))	/* Control register present ? */
 		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 	banks = l&0xff;
-	for(i=1;i<banks;i++)
-	{
-		wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+
+	/* Don't enable bank 0 on intel P6 cores, it goes bang quickly. */
+	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6) {
+		for(i=1; i<banks; i++)
+			wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+	} else {
+		for(i=0; i<banks; i++)
+			wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
 	}
-	for(i=0;i<banks;i++)
-	{
+
+	for(i=0; i<banks; i++)
 		wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
-	}
+
 	set_in_cr4(X86_CR4_MCE);
 	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+	
+	intel_init_thermal(c);
+
 	done=1;
 }
 
@@ -206,28 +374,36 @@
  *	This has to be run for each processor
  */
 
-
-
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
 	if(mce_disabled==1)
 		return;
-		
+
 	switch(c->x86_vendor)
 	{
 		case X86_VENDOR_AMD:
-			/*
-			 *	AMD K7 machine check is Intel like
-			 */
-			if(c->x86 == 6)
+			/* AMD K7 machine check is Intel like */
+			if(c->x86 == 6) {
 				intel_mcheck_init(c);
+#ifdef CONFIG_X86_MCE_NONFATAL
+				/* Set the timer to check for non-fatal errors every 5 seconds */
+				init_timer (&mce_timer);
+				mce_timer.expires = jiffies + 5 * HZ;
+				mce_timer.data = 0;
+				mce_timer.function = &mce_timerfunc;
+				add_timer (&mce_timer);
+#endif
+			}
 			break;
+
 		case X86_VENDOR_INTEL:
 			intel_mcheck_init(c);
 			break;
+
 		case X86_VENDOR_CENTAUR:
 			winchip_mcheck_init(c);
 			break;
+
 		default:
 			break;
 	}
@@ -247,3 +423,9 @@
 
 __setup("nomce", mcheck_disable);
 __setup("mce", mcheck_enable);
+
+#else
+asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {}
+asmlinkage void smp_thermal_interrupt(struct pt_regs regs) {}
+void __init mcheck_init(struct cpuinfo_x86 *c) {}
+#endif
diff -Nru a/arch/i386/kernel/bootflag.c b/arch/i386/kernel/bootflag.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/bootflag.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,253 @@
+/*
+ *	Implement 'Simple Boot Flag Specification 1.0'
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include <linux/mc146818rtc.h>
+
+
+#define SBF_RESERVED (0x78)
+#define SBF_PNPOS    (1<<0)
+#define SBF_BOOTING  (1<<1)
+#define SBF_DIAG     (1<<2)
+#define SBF_PARITY   (1<<7)
+
+
+struct sbf_boot
+{
+	u8 sbf_signature[4];
+	u32 sbf_len;
+	u8 sbf_revision __attribute((packed));
+	u8 sbf_csum __attribute((packed));
+	u8 sbf_oemid[6] __attribute((packed));
+	u8 sbf_oemtable[8] __attribute((packed));
+	u8 sbf_revdata[4] __attribute((packed));
+	u8 sbf_creator[4] __attribute((packed));
+	u8 sbf_crearev[4] __attribute((packed));
+	u8 sbf_cmos __attribute((packed));
+	u8 sbf_spare[3] __attribute((packed));
+};
+
+
+static int sbf_port __initdata = -1;
+
+static int __init sbf_struct_valid(unsigned long tptr)
+{
+	u8 *ap;
+	u8 v;
+	unsigned int i;
+	struct sbf_boot sb;
+	
+	memcpy_fromio(&sb, tptr, sizeof(sb));
+
+	if(sb.sbf_len != 40 && sb.sbf_len != 39)
+		// 39 on IBM ThinkPad A21m, BIOS version 1.02b (KXET24WW; 2000-12-19).
+		return 0;
+
+	ap = (u8 *)&sb;
+	v= 0;
+	
+	for(i=0;i<sb.sbf_len;i++)
+		v+=*ap++;
+		
+	if(v)
+		return 0;
+
+	if(memcmp(sb.sbf_signature, "BOOT", 4))
+		return 0;
+
+	if (sb.sbf_len == 39)
+		printk (KERN_WARNING "SBF: ACPI BOOT descriptor is wrong length (%d)\n",
+			sb.sbf_len);
+
+	sbf_port = sb.sbf_cmos;	/* Save CMOS port */
+	return 1;
+}
+
+static int __init parity(u8 v)
+{
+	int x = 0;
+	int i;
+	
+	for(i=0;i<8;i++)
+	{
+		x^=(v&1);
+		v>>=1;
+	}
+	return x;
+}
+
+static void __init sbf_write(u8 v)
+{
+	unsigned long flags;
+	if(sbf_port != -1)
+	{
+		v &= ~SBF_PARITY;
+		if(!parity(v))
+			v|=SBF_PARITY;
+
+		printk(KERN_INFO "SBF: Setting boot flags 0x%x\n",v);
+
+		spin_lock_irqsave(&rtc_lock, flags);
+		CMOS_WRITE(v, sbf_port);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+	}
+}
+
+static u8 __init sbf_read(void)
+{
+	u8 v;
+	unsigned long flags;
+	if(sbf_port == -1)
+		return 0;
+	spin_lock_irqsave(&rtc_lock, flags);
+	v = CMOS_READ(sbf_port);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return v;
+}
+
+static int __init sbf_value_valid(u8 v)
+{
+	if(v&SBF_RESERVED)		/* Reserved bits */
+		return 0;
+	if(!parity(v))
+		return 0;
+	return 1;
+}
+
+
+static void __init sbf_bootup(void)
+{
+	u8 v;
+	if(sbf_port == -1)
+		return;
+	v = sbf_read();
+	if(!sbf_value_valid(v))
+		printk(KERN_WARNING "SBF: Simple boot flag value 0x%x read from CMOS RAM was invalid\n",v);
+	v &= ~SBF_RESERVED;
+	v &= ~SBF_BOOTING;
+	v &= ~SBF_DIAG;
+#if defined(CONFIG_ISAPNP)
+	v |= SBF_PNPOS;
+#endif
+	sbf_write(v);
+}
+
+static int __init sbf_init(void)
+{
+	unsigned int i;
+	void *rsdt;
+	u32 rsdtlen = 0;
+	u32 rsdtbase = 0;
+	u8 sum = 0;
+	int n;
+	
+	u8 *p;
+	
+	for(i=0xE0000; i <= 0xFFFE0; i+=16)
+	{
+		p = phys_to_virt(i);
+		
+		if(memcmp(p, "RSD PTR ", 8))
+			continue;
+		
+		sum = 0;
+		for(n=0; n<20; n++)
+			sum+=p[n];
+			
+		if(sum != 0)
+			continue;
+			
+		/* So it says RSD PTR and it checksums... */
+
+		/*
+		 *	Process the RDSP pointer
+		 */
+	 
+		rsdtbase = *(u32 *)(p+16);
+		
+		/*
+		 *	RSDT length is ACPI 2 only, for ACPI 1 we must map
+		 *	and remap.
+		 */
+		 
+		if(p[15]>1)
+			rsdtlen = *(u32 *)(p+20);
+		else
+			rsdtlen = 36;
+
+		if(rsdtlen < 36 || rsdtlen > 1024)
+			continue;
+		break;
+	}
+	if(i>0xFFFE0)
+		return 0;
+		
+		
+	rsdt = ioremap(rsdtbase, rsdtlen);
+	if(rsdt == 0)
+		return 0;
+		
+	i = readl(rsdt + 4);
+	
+	/*
+	 *	Remap if needed
+	 */
+	 
+	if(i > rsdtlen)
+	{
+		rsdtlen = i;
+		iounmap(rsdt);
+		rsdt = ioremap(rsdtbase, rsdtlen);
+		if(rsdt == 0)
+			return 0;
+	}
+	
+	for(n = 0; n < i; n++)
+		sum += readb(rsdt + n);
+		
+	if(sum)
+	{
+		iounmap(rsdt);
+		return 0;
+	}
+	
+	/* Ok the RSDT checksums too */
+	
+	for(n = 36; n+3 < i; n += 4)
+	{
+		unsigned long rp = readl(rsdt+n);
+		int len = 4096;
+
+		if(rp > 0xFFFFFFFFUL - len)
+			len = 0xFFFFFFFFUL - rp;
+			
+		/* Too close to the end!! */
+		if(len < 20)
+			continue;
+		rp = (unsigned long)ioremap(rp, 4096);
+		if(rp == 0)
+			continue;
+		if(sbf_struct_valid(rp))
+		{
+			/* Found the BOOT table and processed it */
+			printk(KERN_INFO "SBF: Simple Boot Flag extension found and enabled.\n");
+		}
+		iounmap((void *)rp);
+	}
+	iounmap(rsdt);
+	sbf_bootup();
+	return 0;
+}
+
+module_init(sbf_init);
diff -Nru a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
--- a/arch/i386/kernel/cpuid.c	Wed Apr  3 17:11:13 2002
+++ b/arch/i386/kernel/cpuid.c	Wed Apr  3 17:11:13 2002
@@ -35,6 +35,7 @@
 #include <linux/poll.h>
 #include <linux/smp.h>
 #include <linux/major.h>
+#include <linux/fs.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/dmi_scan.c	Wed Apr  3 17:11:15 2002
@@ -295,6 +295,22 @@
 	return 0;
 }
 
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int broken_hp_bios_irq9;
+	if (broken_hp_bios_irq9 == 0)
+	{
+		broken_hp_bios_irq9 = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
 
 /*
  *  Check for clue free BIOS implementations who use
@@ -438,6 +454,25 @@
 }
 
 /*
+ * The Microstar 6163-2 (a.k.a Pro) mainboard will hang shortly after
+ * resumes, and also at what appears to be asynchronous APM events,
+ * if the local APIC is enabled.
+ */
+static int __init apm_kills_local_apic(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	extern int dont_enable_local_apic;
+	if (apm_info.bios.version && !dont_enable_local_apic) {
+		dont_enable_local_apic = 1;
+		printk(KERN_WARNING "%s with broken BIOS detected. "
+		       "Refusing to enable the local APIC.\n",
+		       d->ident);
+	}
+#endif
+	return 0;
+}
+
+/*
  * The Intel AL440LX mainboard will hang randomly if the local APIC
  * timer is running and the APM BIOS hasn't been disabled.
  */
@@ -483,10 +518,10 @@
 			} },
 #endif			
 	{ broken_ps2_resume, "Dell Latitude C600", {	/* Handle problems with APM on the C600 */
-		        MATCH(DMI_SYS_VENDOR, "Dell"),
+			MATCH(DMI_SYS_VENDOR, "Dell"),
 			MATCH(DMI_PRODUCT_NAME, "Latitude C600"),
 			NO_MATCH, NO_MATCH
-	                } },
+			} },
 	{ broken_apm_power, "Dell Inspiron 5000e", {	/* Handle problems with APM on Inspiron 5000e */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "A04"),
@@ -512,6 +547,11 @@
 			MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
 			NO_MATCH, NO_MATCH
 			} },
+	{ set_bios_reboot, "Dell PowerEdge 2400", {  /* Handle problems with rebooting on Dell 300/800's */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
+			NO_MATCH, NO_MATCH
+			} },
 	{ set_apm_ints, "Dell Inspiron", {	/* Allow interrupts during suspend on Dell Inspiron laptops*/
 			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 			MATCH(DMI_PRODUCT_NAME, "Inspiron 4000"),
@@ -533,12 +573,23 @@
 			MATCH(DMI_PRODUCT_NAME, "Delhi3"),
 			NO_MATCH, NO_MATCH,
 			} },
+	{ apm_is_horked, "Fujitsu-Siemens", { /* APM crashes */
+			MATCH(DMI_BIOS_VENDOR, "hoenix/FUJITSU SIEMENS"),
+			MATCH(DMI_BIOS_VERSION, "Version1.01"),
+			NO_MATCH, NO_MATCH,
+			} },
 	{ apm_is_horked, "Sharp PC-PJ/AX", { /* APM crashes */
 			MATCH(DMI_SYS_VENDOR, "SHARP"),
 			MATCH(DMI_PRODUCT_NAME, "PC-PJ/AX"),
 			MATCH(DMI_BIOS_VENDOR,"SystemSoft"),
 			MATCH(DMI_BIOS_VERSION,"Version R2.08")
 			} },
+	{ apm_is_horked, "Dell Inspiron 2500", { /* APM crashes */
+			MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			MATCH(DMI_PRODUCT_NAME, "Inspiron 2500"),
+			MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION,"A11")
+			} },
 	{ sony_vaio_laptop, "Sony Vaio", { /* This is a Sony Vaio laptop */
 			MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 			MATCH(DMI_PRODUCT_NAME, "PCG-"),
@@ -548,7 +599,7 @@
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0206H"),
 			MATCH(DMI_BIOS_DATE, "08/23/99"), NO_MATCH
-	} },
+			} },
 
 	{ swab_apm_power_in_minutes, "Sony VAIO", { /* Handle problems with APM on Sony Vaio PCG-N505VX */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
@@ -574,6 +625,12 @@
 			MATCH(DMI_BIOS_DATE, "08/11/00"), NO_MATCH
 			} },
 
+	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z600LEK(DE) */
+			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
+			MATCH(DMI_BIOS_VERSION, "R0206Z3"),
+			MATCH(DMI_BIOS_DATE, "12/25/00"), NO_MATCH
+			} },
+
 	{ swab_apm_power_in_minutes, "Sony VAIO", {	/* Handle problems with APM on Sony Vaio PCG-Z505LS */
 			MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"),
 			MATCH(DMI_BIOS_VERSION, "R0203D0"),
@@ -617,6 +674,17 @@
 			NO_MATCH, NO_MATCH
 			} },
 
+	{ local_apic_kills_bios, "IBM Thinkpad T20", {
+			MATCH(DMI_BOARD_VENDOR, "IBM"),
+			MATCH(DMI_BOARD_NAME, "264741U"),
+			NO_MATCH, NO_MATCH
+			} },
+
+	{ apm_kills_local_apic, "Microstar 6163", {
+			MATCH(DMI_BOARD_VENDOR, "MICRO-STAR INTERNATIONAL CO., LTD"),
+			MATCH(DMI_BOARD_NAME, "MS-6163"),
+			NO_MATCH, NO_MATCH } },
+
 	{ apm_kills_local_apic_timer, "Intel AL440LX", {
 			MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
 			MATCH(DMI_BOARD_NAME, "AL440LX"),
@@ -678,7 +746,14 @@
 			NO_MATCH, NO_MATCH
 			} },
 	 
-			
+	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+			} },
+ 
+
 	/*
 	 *	Generic per vendor APM settings
 	 */
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Wed Apr  3 17:11:15 2002
@@ -93,7 +93,6 @@
 EXPORT_SYMBOL_NOVERS(__get_user_2);
 EXPORT_SYMBOL_NOVERS(__get_user_4);
 
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
--- a/arch/i386/kernel/microcode.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/microcode.c	Wed Apr  3 17:11:14 2002
@@ -51,6 +51,12 @@
  *		Bugfix for HT (Hyper-Threading) enabled processors
  *		whereby processor resources are shared by all logical processors
  *		in a single CPU package.
+ *	1.10	28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *		Tigran Aivazian <tigran@veritas.com>,
+ *		Serialize updates as required on HT processors due to speculative
+ *		nature of implementation.
+ *	1.11	22 Mar 2001 Tigran Aivazian <tigran@veritas.com>
+ *		Fix the panic when writing zero-length microcode chunk.
  */
 
 #include <linux/init.h>
@@ -60,12 +66,16 @@
 #include <linux/vmalloc.h>
 #include <linux/miscdevice.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/spinlock.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_VERSION 	"1.09"
+
+static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
+
+#define MICROCODE_VERSION 	"1.11"
 
 MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
@@ -195,7 +205,8 @@
 	struct cpuinfo_x86 *c = cpu_data + cpu_num;
 	struct update_req *req = update_req + cpu_num;
 	unsigned int pf = 0, val[2], rev, sig;
-	int i,found=0;
+	unsigned long flags;
+	int i;
 
 	req->err = 1; /* assume update will fail on this cpu */
 
@@ -216,8 +227,9 @@
 	for (i=0; i<microcode_num; i++)
 		if (microcode[i].sig == sig && microcode[i].pf == pf &&
 		    microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
-
-			found=1;
+			int sum = 0;
+			struct microcode *m = &microcode[i];
+			unsigned int *sump = (unsigned int *)(m+1);
 
 			printf("Microcode\n");
 			printf("   Header Revision %d\n",microcode[i].hdrver);
@@ -234,54 +246,69 @@
 			printf("   Loader Revision %x\n",microcode[i].ldrver);
 			printf("   Processor Flags %x\n\n",microcode[i].pf);
 
+			req->slot = i;
+
+			/* serialize access to update decision */
+			spin_lock_irqsave(&microcode_update_lock, flags);          
+
 			/* trick, to work even if there was no prior update by the BIOS */
 			wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 			__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
 
 			/* get current (on-cpu) revision into rev (ignore val[0]) */
 			rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
+			
 			if (microcode[i].rev < rev) {
+				spin_unlock_irqrestore(&microcode_update_lock, flags);
 				printk(KERN_ERR 
-					"microcode: CPU%d not 'upgrading' to earlier revision"
+				       "microcode: CPU%d not 'upgrading' to earlier revision"
+				       " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
+				return;
+			} else if (microcode[i].rev == rev) {
+				/* notify the caller of success on this cpu */
+				req->err = 0;
+				spin_unlock_irqrestore(&microcode_update_lock, flags);
+				printk(KERN_ERR 
+					"microcode: CPU%d already at revision"
 					" %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
-			} else {
-				int sum = 0;
-				struct microcode *m = &microcode[i];
-				unsigned int *sump = (unsigned int *)(m+1);
-
-				while (--sump >= (unsigned int *)m)
-					sum += *sump;
-				if (sum != 0) {
-					printk(KERN_ERR "microcode: CPU%d aborting, "
-							"bad checksum\n", cpu_num);
-					break;
-				}
-
-				/* write microcode via MSR 0x79 */
-				wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
+				return;
+			}
 
-				/* serialize */
-				__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+			/* Verify the checksum */
+			while (--sump >= (unsigned int *)m)
+				sum += *sump;
+			if (sum != 0) {
+				req->err = 1;
+				spin_unlock_irqrestore(&microcode_update_lock, flags);
+				printk(KERN_ERR "microcode: CPU%d aborting, "
+				       "bad checksum\n", cpu_num);
+				return;
+			}
+			
+			/* write microcode via MSR 0x79 */
+			wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
 
-				/* get the current revision from MSR 0x8B */
-				rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+			/* serialize */
+			__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
 
-				/* notify the caller of success on this cpu */
-				req->err = 0;
-				req->slot = i;
+			/* get the current revision from MSR 0x8B */
+			rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 
-				printk(KERN_INFO "microcode: CPU%d updated from revision "
-						"%d to %d, date=%08x\n", 
-						cpu_num, rev, val[1], m->date);
-			}
-			break;
+			/* notify the caller of success on this cpu */
+			req->err = 0;
+			spin_unlock_irqrestore(&microcode_update_lock, flags);
+			printk(KERN_INFO "microcode: CPU%d updated from revision "
+			       "%d to %d, date=%08x\n", 
+			       cpu_num, rev, val[1], microcode[i].date);
+			return;
 		}
-
-	if(!found)
-		printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
-				cpu_num, sig, pf);
+	
+	printk(KERN_ERR
+	       "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", 
+	       cpu_num, sig, pf);
 }
 
+
 static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
 {
 	ssize_t ret = 0;
@@ -305,9 +332,13 @@
 {
 	ssize_t ret;
 
-	if (len % sizeof(struct microcode) != 0) {
+	if (!len || len % sizeof(struct microcode) != 0) {
 		printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", 
 			sizeof(struct microcode));
+		return -EINVAL;
+	}
+	if ((len >> PAGE_SHIFT) > num_physpages) {
+		printk(KERN_ERR "microcode: too much data (max %d pages)\n", num_physpages);
 		return -EINVAL;
 	}
 	down_write(&microcode_rwsem);
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/mpparse.c	Wed Apr  3 17:11:14 2002
@@ -232,6 +232,7 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
@@ -816,11 +817,13 @@
 	 * trustworthy, simply because the SMP table may have been
 	 * stomped on during early boot. These loaders are buggy and
 	 * should be fixed.
+	 *
+	 * MP1.4 SPEC states to only scan first 1K of 4K EBDA.
 	 */
 
 	address = *(unsigned short *)phys_to_virt(0x40E);
 	address <<= 4;
-	smp_scan_config(address, 0x1000);
+	smp_scan_config(address, 0x400);
 	if (smp_found_config)
 		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
diff -Nru a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c
--- a/arch/i386/kernel/mtrr.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/mtrr.c	Wed Apr  3 17:11:14 2002
@@ -498,7 +498,6 @@
     case MTRR_IF_INTEL:
 	rdmsr (MTRRcap_MSR, config, dummy);
 	return (config & (1<<10));
-	return 1;
     case MTRR_IF_AMD_K6:
     case MTRR_IF_CENTAUR_MCR:
     case MTRR_IF_CYRIX_ARR:
diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
--- a/arch/i386/kernel/nmi.c	Wed Apr  3 17:11:13 2002
+++ b/arch/i386/kernel/nmi.c	Wed Apr  3 17:11:13 2002
@@ -8,6 +8,7 @@
  *  Fixes:
  *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
  *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
+ *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
  */
 
 #include <linux/config.h>
@@ -43,6 +44,32 @@
 #define P6_EVENT_CPU_CLOCKS_NOT_HALTED	0x79
 #define P6_NMI_EVENT		P6_EVENT_CPU_CLOCKS_NOT_HALTED
 
+#define MSR_P4_MISC_ENABLE	0x1A0
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL	(1<<7)
+#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL	(1<<12)
+#define MSR_P4_PERFCTR0		0x300
+#define MSR_P4_CCCR0		0x360
+#define P4_ESCR_EVENT_SELECT(N)	((N)<<25)
+#define P4_ESCR_OS		(1<<3)
+#define P4_ESCR_USR		(1<<2)
+#define P4_CCCR_OVF_PMI		(1<<26)
+#define P4_CCCR_THRESHOLD(N)	((N)<<20)
+#define P4_CCCR_COMPLEMENT	(1<<19)
+#define P4_CCCR_COMPARE		(1<<18)
+#define P4_CCCR_REQUIRED	(3<<16)
+#define P4_CCCR_ESCR_SELECT(N)	((N)<<13)
+#define P4_CCCR_ENABLE		(1<<12)
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+   CRU_ESCR0 (with any non-null event selector) through a complemented
+   max threshold. [IA32-Vol3, Section 14.9.9] */
+#define MSR_P4_IQ_COUNTER0	0x30C
+#define MSR_P4_IQ_CCCR0		0x36C
+#define MSR_P4_CRU_ESCR0	0x3B8
+#define P4_NMI_CRU_ESCR0	(P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
+#define P4_NMI_IQ_CCCR0	\
+	(P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|	\
+	 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
+
 int __init check_nmi_watchdog (void)
 {
 	irq_cpustat_t tmp[NR_CPUS];
@@ -84,11 +111,11 @@
 	/*
 	 * If any other x86 CPU has a local APIC, then
 	 * please test the NMI stuff there and send me the
-	 * missing bits. Right now Intel P6 and AMD K7 only.
+	 * missing bits. Right now Intel P6/P4 and AMD K7 only.
 	 */
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-			(boot_cpu_data.x86 == 6))
+			(boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
 		nmi_watchdog = nmi;
 	if ((nmi == NMI_LOCAL_APIC) &&
 			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
@@ -118,7 +145,15 @@
 		wrmsr(MSR_K7_EVNTSEL0, 0, 0);
 		break;
 	case X86_VENDOR_INTEL:
-		wrmsr(MSR_IA32_EVNTSEL0, 0, 0);
+		switch (boot_cpu_data.x86) {
+		case 6:
+			wrmsr(MSR_P6_EVNTSEL0, 0, 0);
+			break;
+		case 15:
+			wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
+			wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
+			break;
+		}
 		break;
 	}
 }
@@ -157,17 +192,22 @@
  * Original code written by Keith Owens.
  */
 
+static void __pminit clear_msr_range(unsigned int base, unsigned int n)
+{
+	unsigned int i;
+
+	for(i = 0; i < n; ++i)
+		wrmsr(base+i, 0, 0);
+}
+
 static void __pminit setup_k7_watchdog(void)
 {
-	int i;
 	unsigned int evntsel;
 
 	nmi_perfctr_msr = MSR_K7_PERFCTR0;
 
-	for(i = 0; i < 4; ++i) {
-		wrmsr(MSR_K7_EVNTSEL0+i, 0, 0);
-		wrmsr(MSR_K7_PERFCTR0+i, 0, 0);
-	}
+	clear_msr_range(MSR_K7_EVNTSEL0, 4);
+	clear_msr_range(MSR_K7_PERFCTR0, 4);
 
 	evntsel = K7_EVNTSEL_INT
 		| K7_EVNTSEL_OS
@@ -184,27 +224,54 @@
 
 static void __pminit setup_p6_watchdog(void)
 {
-	int i;
 	unsigned int evntsel;
 
-	nmi_perfctr_msr = MSR_IA32_PERFCTR0;
+	nmi_perfctr_msr = MSR_P6_PERFCTR0;
 
-	for(i = 0; i < 2; ++i) {
-		wrmsr(MSR_IA32_EVNTSEL0+i, 0, 0);
-		wrmsr(MSR_IA32_PERFCTR0+i, 0, 0);
-	}
+	clear_msr_range(MSR_P6_EVNTSEL0, 2);
+	clear_msr_range(MSR_P6_PERFCTR0, 2);
 
 	evntsel = P6_EVNTSEL_INT
 		| P6_EVNTSEL_OS
 		| P6_EVNTSEL_USR
 		| P6_NMI_EVENT;
 
-	wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
-	Dprintk("setting IA32_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
-	wrmsr(MSR_IA32_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+	Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= P6_EVNTSEL0_ENABLE;
-	wrmsr(MSR_IA32_EVNTSEL0, evntsel, 0);
+	wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
+}
+
+static int __pminit setup_p4_watchdog(void)
+{
+	unsigned int misc_enable, dummy;
+
+	rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+		return 0;
+
+	nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
+
+	if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+		clear_msr_range(0x3F1, 2);
+	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
+	   docs doesn't fully define it, so leave it alone for now. */
+	clear_msr_range(0x3A0, 31);
+	clear_msr_range(0x3C0, 6);
+	clear_msr_range(0x3C8, 6);
+	clear_msr_range(0x3E0, 2);
+	clear_msr_range(MSR_P4_CCCR0, 18);
+	clear_msr_range(MSR_P4_PERFCTR0, 18);
+
+	wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
+	Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
+	wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+	wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+	return 1;
 }
 
 void __pminit setup_apic_nmi_watchdog (void)
@@ -216,9 +283,17 @@
 		setup_k7_watchdog();
 		break;
 	case X86_VENDOR_INTEL:
-		if (boot_cpu_data.x86 != 6)
+		switch (boot_cpu_data.x86) {
+		case 6:
+			setup_p6_watchdog();
+			break;
+		case 15:
+			if (!setup_p4_watchdog())
+				return;
+			break;
+		default:
 			return;
-		setup_p6_watchdog();
+		}
 		break;
 	default:
 		return;
@@ -296,6 +371,18 @@
 		last_irq_sums[cpu] = sum;
 		alert_counter[cpu] = 0;
 	}
-	if (nmi_perfctr_msr)
+	if (nmi_perfctr_msr) {
+		if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
+			/*
+			 * P4 quirks:
+			 * - An overflown perfctr will assert its interrupt
+			 *   until the OVF flag in its CCCR is cleared.
+			 * - LVTPC is masked on interrupt and must be
+			 *   unmasked by the LVTPC handler.
+			 */
+			wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
+			apic_write(APIC_LVTPC, APIC_DM_NMI);
+		}
 		wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
+	}
 }
diff -Nru a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
--- a/arch/i386/kernel/pci-dma.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/pci-dma.c	Wed Apr  3 17:11:14 2002
@@ -19,7 +19,7 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || hwdev->dma_mask != 0xffffffff)
+	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
 		gfp |= GFP_DMA;
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
diff -Nru a/arch/i386/kernel/pci-irq.c b/arch/i386/kernel/pci-irq.c
--- a/arch/i386/kernel/pci-irq.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/pci-irq.c	Wed Apr  3 17:11:15 2002
@@ -23,6 +23,7 @@
 #define PIRQ_VERSION 0x0100
 
 int pci_use_acpi_routing = 0;
+int broken_hp_bios_irq9;
 
 static struct irq_routing_table *pirq_table;
 
@@ -208,6 +209,24 @@
 }
 
 /*
+ * ITE 8330G pirq rules are nibble-based
+ * FIXME: pirqmap may be { 1, 0, 3, 2 },
+ * 	  2+3 are both mapped to irq 9 on my system
+ */
+static int pirq_ite_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	return read_config_nybble(router,0x43, pirqmap[pirq-1]);
+}
+
+static int pirq_ite_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
+{
+	static unsigned char pirqmap[4] = { 1, 0, 2, 3 };
+	write_config_nybble(router, 0x43, pirqmap[pirq-1], irq);
+	return 1;
+}
+
+/*
  * OPTI: high four bits are nibble pointer..
  * I wonder what the low bits do?
  */
@@ -227,12 +246,12 @@
  */
 static int pirq_cyrix_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
 {
-	return read_config_nybble(router, 0x5C, pirq-1);
+	return read_config_nybble(router, 0x5C, (pirq-1)^1);
 }
 
 static int pirq_cyrix_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
 {
-	write_config_nybble(router, 0x5C, pirq-1, irq);
+	write_config_nybble(router, 0x5C, (pirq-1)^1, irq);
 	return 1;
 }
 
@@ -445,10 +464,17 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, pirq_piix_get, pirq_piix_set },
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
+	{ "ITE", PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8330G_0, pirq_ite_get, pirq_ite_set },
+
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, pirq_via_get, pirq_via_set },
 	{ "VIA", PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, pirq_via_get, pirq_via_set },
@@ -588,6 +614,15 @@
 	}
 	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
 	mask &= pcibios_irq_mask;
+
+	/* Work around broken HP Pavilion Notebooks which assign USB to
+	   IRQ 9 even though it is actually wired to IRQ 11 */
+
+	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+		r->set(pirq_router_dev, dev, pirq, 11);
+	}
 
 	/*
 	 * Find the best IRQ to assign: use the one
diff -Nru a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c
--- a/arch/i386/kernel/pci-pc.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/pci-pc.c	Wed Apr  3 17:11:15 2002
@@ -1205,7 +1205,8 @@
 
         pci_read_config_byte(d, where, &v);
 	if (v & 0xe0) {
-		printk("Disabling broken memory write queue.\n");
+		printk("Disabling broken memory write queue: [%02x] %02x->%02x\n",
+			where, v, v & 0x1f);
 		v &= 0x1f; /* clear bits 5, 6, 7 */
 		pci_write_config_byte(d, where, v);
 	}
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Wed Apr  3 17:11:15 2002
+++ b/arch/i386/kernel/setup.c	Wed Apr  3 17:11:15 2002
@@ -99,6 +99,8 @@
 #endif
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
 #include <asm/processor.h>
@@ -127,9 +129,6 @@
 /*
  * Bus types ..
  */
-#ifdef CONFIG_EISA
-int EISA_bus;
-#endif
 int MCA_bus;
 
 /* for MCA, but anyone else can use it if they want */
@@ -210,6 +209,10 @@
 	{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
 	{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
 };
+#ifdef CONFIG_MELAN
+standard_io_resources[1] = { "pic1", 0x20, 0x21, IORESOURCE_BUSY };
+standard_io_resources[5] = { "pic2", 0xa0, 0xa1, IORESOURCE_BUSY };
+#endif
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
 
@@ -1240,7 +1243,7 @@
 }
 
 /*
- * Read Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
  */
 static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
 {
@@ -1315,7 +1318,7 @@
 static void __init check_cx686_slop(struct cpuinfo_x86 *c)
 {
 	unsigned long flags;
-	
+
 	if (Cx86_dir0_msb == 3) {
 		unsigned char ccr3, ccr5;
 
@@ -1325,7 +1328,7 @@
 		ccr5 = getCx86(CX86_CCR5);
 		if (ccr5 & 2)
 			setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
-		setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
+		setCx86(CX86_CCR3, ccr3);		  /* disable MAPEN */
 		local_irq_restore(flags);
 
 		if (ccr5 & 2) { /* possible wrong calibration done */
@@ -1336,6 +1339,7 @@
 	}
 }
 
+
 static void __init init_cyrix(struct cpuinfo_x86 *c)
 {
 	unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
@@ -1402,17 +1406,12 @@
 		break;
 
 	case 4: /* MediaGX/GXm */
-		/*
-		 *	Life sometimes gets weiiiiiiiird if we use this
-		 *	on the MediaGX. So we turn it off for now. 
-		 */
-		
 #ifdef CONFIG_PCI
-		/* It isnt really a PCI quirk directly, but the cure is the
+		/* It isn't really a PCI quirk directly, but the cure is the
 		   same. The MediaGX has deep magic SMM stuff that handles the
 		   SB emulation. It thows away the fifo on disable_dma() which
 		   is wrong and ruins the audio. 
-                   
+
 		   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
 		   causes bad things. According to NatSemi VSA2 has another
 		   bug to do with 'hlt'. I've not seen any boards using VSA2
@@ -1427,15 +1426,26 @@
 
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
+			/* Enable Natsemi MMX extensions */
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+
 			get_model_name(c);  /* get CPU marketing name */
-			clear_bit(X86_FEATURE_TSC, c->x86_capability);
+			/*
+			 *  The 5510/5520 companion chips have a funky PIT
+			 *  that breaks the TSC synchronizing, so turn it off
+			 */
+			if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+				pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+				clear_bit(X86_FEATURE_TSC, c->x86_capability);
 			return;
 		}
 		else {  /* MediaGX */
 			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
 			p = Cx86_cb+2;
 			c->x86_model = (dir1 & 0x20) ? 1 : 2;
+#ifndef CONFIG_CS5520
 			clear_bit(X86_FEATURE_TSC, &c->x86_capability);
+#endif
 		}
 		break;
 
@@ -1453,7 +1463,7 @@
 		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
 		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
 		p = Cx86_cb+tmp;
-        	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+	 	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
 			(c->x86_model)++;
 		/* Emulate MTRRs using Cyrix's ARRs. */
 		set_bit(X86_FEATURE_CYRIX_ARR, &c->x86_capability);
@@ -2096,7 +2106,7 @@
 		}
 		if ( l1i || l1d )
 			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			       l1i, l1d);
+			      l1i, l1d);
 		if ( l2 )
 			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
 		if ( l3 )
@@ -2203,6 +2213,8 @@
 		c->x86_vendor = X86_VENDOR_AMD;
 	else if (!strcmp(v, "CyrixInstead"))
 		c->x86_vendor = X86_VENDOR_CYRIX;
+	else if (!strcmp(v, "Geode by NSC"))
+		c->x86_vendor = X86_VENDOR_NSC;
 	else if (!strcmp(v, "UMC UMC UMC "))
 		c->x86_vendor = X86_VENDOR_UMC;
 	else if (!strcmp(v, "CentaurHauls"))
@@ -2528,24 +2540,6 @@
 	 * indicate the features this CPU genuinely supports!
 	 */
 	switch ( c->x86_vendor ) {
-	case X86_VENDOR_UNKNOWN:
-	default:
-		/* Not much we can do here... */
-		/* Check if at least it has cpuid */
-		if (c->cpuid_level == -1)
-		{
-			/* No cpuid. It must be an ancient CPU */
-			if (c->x86 == 4)
-				strcpy(c->x86_model_id, "486");
-			else if (c->x86 == 3)
-				strcpy(c->x86_model_id, "386");
-		}
-		break;
-
-	case X86_VENDOR_CYRIX:
-		init_cyrix(c);
-		break;
-
 	case X86_VENDOR_AMD:
 		init_amd(c);
 		break;
@@ -2554,6 +2548,10 @@
 		init_centaur(c);
 		break;
 
+	case X86_VENDOR_CYRIX:
+		init_cyrix(c);
+		break;
+
 	case X86_VENDOR_INTEL:
 		init_intel(c);
 		break;
@@ -2562,13 +2560,32 @@
 		c->x86_cache_size = 256; /* A few had 1 MB... */
 		break;
 
-	case X86_VENDOR_TRANSMETA:
-		init_transmeta(c);
+	case X86_VENDOR_NSC:
+        init_cyrix(c);
 		break;
 
 	case X86_VENDOR_RISE:
 		init_rise(c);
 		break;
+
+	case X86_VENDOR_TRANSMETA:
+		init_transmeta(c);
+		break;
+
+	case X86_VENDOR_UNKNOWN:
+	default:
+		/* Not much we can do here... */
+		/* Check if at least it has cpuid */
+		if (c->cpuid_level == -1)
+		{
+			/* No cpuid. It must be an ancient CPU */
+			if (c->x86 == 4)
+				strcpy(c->x86_model_id, "486");
+			else if (c->x86 == 3)
+				strcpy(c->x86_model_id, "386");
+		}
+		break;
+
 	}
 
 	printk(KERN_DEBUG "CPU: After vendor init, caps: %08x %08x %08x %08x\n",
@@ -2646,14 +2663,15 @@
 {
 	get_cpu_vendor(&boot_cpu_data);
 
-	if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX )
+	if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
+	    ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC   ))
 		init_cyrix(&boot_cpu_data);
 }
 
 
 /* These need to match <asm/processor.h> */
 static char *cpu_vendor_names[] __initdata = {
-	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
+	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" };
 
 
 void __init print_cpu_info(struct cpuinfo_x86 *c)
@@ -2694,10 +2712,10 @@
 	 */
 	static char *x86_cap_flags[] = {
 		/* Intel-defined */
-	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
+		"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+		"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+		"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+		"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
 
 		/* AMD-defined */
 		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/kernel/traps.c	Wed Apr  3 17:11:14 2002
@@ -25,6 +25,10 @@
 #include <linux/interrupt.h>
 #include <linux/highmem.h>
 
+#ifdef CONFIG_EISA
+#include <linux/ioport.h>
+#endif
+
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
 #include <asm/processor.h>
@@ -951,11 +955,20 @@
 	printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
 }
 #endif
+
+#ifdef CONFIG_EISA
+int EISA_bus;
+static struct resource eisa_id = { "EISA ID", 0xc80, 0xc83, IORESOURCE_BUSY };
+#endif
+
 void __init trap_init(void)
 {
 #ifdef CONFIG_EISA
-	if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24))
+	if (isa_readl(0x0FFFD9) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
 		EISA_bus = 1;
+		if (request_resource(&ioport_resource, &eisa_id) == -EBUSY)
+			printk ("EISA port was EBUSY :-(\n");
+	}
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c	Wed Apr  3 17:11:14 2002
+++ b/arch/i386/mm/ioremap.c	Wed Apr  3 17:11:14 2002
@@ -11,6 +11,7 @@
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/pgalloc.h>
+#include <asm/fixmap.h>
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
@@ -162,7 +163,6 @@
 		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
 }
 
-#include <asm/fixmap.h>
 void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
 {
 	unsigned long offset, last_addr;
diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
--- a/arch/ia64/kernel/ia64_ksyms.c	Wed Apr  3 17:11:15 2002
+++ b/arch/ia64/kernel/ia64_ksyms.c	Wed Apr  3 17:11:15 2002
@@ -23,7 +23,6 @@
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 
 #include <linux/irq.h>
diff -Nru a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
--- a/arch/m68k/atari/config.c	Wed Apr  3 17:11:14 2002
+++ b/arch/m68k/atari/config.c	Wed Apr  3 17:11:14 2002
@@ -205,14 +205,16 @@
     char switches[len+1];
     char *p;
     int ovsc_shift;
+    char *args = switches;
 
-    /* copy string to local array, strtok works destructively... */
+    /* copy string to local array, strsep works destructively... */
     strncpy( switches, str, len );
     switches[len] = 0;
     atari_switches = 0;
 
     /* parse the options */
-    for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) {
+    while ((p = strsep(&args, ",")) != NULL) {
+	if (!*p) continue;
 	ovsc_shift = 0;
 	if (strncmp( p, "ov_", 3 ) == 0) {
 	    p += 3;
diff -Nru a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
--- a/arch/m68k/kernel/m68k_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/m68k/kernel/m68k_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -54,7 +54,6 @@
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(kernel_thread);
diff -Nru a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
--- a/arch/m68k/mac/baboon.c	Wed Apr  3 17:11:14 2002
+++ b/arch/m68k/mac/baboon.c	Wed Apr  3 17:11:14 2002
@@ -27,7 +27,7 @@
 
 void baboon_irq(int, void *, struct pt_regs *);
 
-extern int macide_ack_intr(ide_hwif_t *);
+extern int macide_ack_intr(struct ata_channel *);
 
 /*
  * Baboon initialization.
diff -Nru a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
--- a/arch/mips/kernel/mips_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/mips/kernel/mips_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -51,7 +51,6 @@
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL_NOVERS(strcat);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strlen);
@@ -60,7 +59,7 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
 
 EXPORT_SYMBOL(_clear_page);
 EXPORT_SYMBOL(enable_irq);
diff -Nru a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
--- a/arch/mips/kernel/signal.c	Wed Apr  3 17:11:16 2002
+++ b/arch/mips/kernel/signal.c	Wed Apr  3 17:11:16 2002
@@ -204,7 +204,7 @@
 #define restore_gp_reg(i) do {						\
 	err |= __get_user(reg, &sc->sc_regs[i]);			\
 	regs->regs[i] = reg;						\
-} while(0);
+} while(0)
 	restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
 	restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
 	restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
diff -Nru a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
--- a/arch/mips/kernel/smp.c	Wed Apr  3 17:11:14 2002
+++ b/arch/mips/kernel/smp.c	Wed Apr  3 17:11:14 2002
@@ -156,7 +156,7 @@
 		sprintf(p->comm, "%s%d", "Idle", i);
 		init_tasks[i] = p;
 		p->processor = i;
-		p->cpus_runnable = 1 << i; /* we schedule the first task manually *
+		p->cpus_runnable = 1 << i; /* we schedule the first task manually */
 		del_from_runqueue(p);
 		unhash_process(p);
 		/* Attach to the address space of init_task. */
diff -Nru a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
--- a/arch/mips/sni/pci.c	Wed Apr  3 17:11:15 2002
+++ b/arch/mips/sni/pci.c	Wed Apr  3 17:11:15 2002
@@ -25,7 +25,7 @@
 		 ((dev->bus->number    & 0xff) << 0x10) |                    \
 	         ((dev->devfn & 0xff) << 0x08) |                             \
 	         (where  & 0xfc);                                            \
-} while(0);
+} while(0)
 
 #if 0
 /* To do:  Bring this uptodate ...  */
diff -Nru a/arch/mips64/kernel/mips64_ksyms.c b/arch/mips64/kernel/mips64_ksyms.c
--- a/arch/mips64/kernel/mips64_ksyms.c	Wed Apr  3 17:11:15 2002
+++ b/arch/mips64/kernel/mips64_ksyms.c	Wed Apr  3 17:11:15 2002
@@ -48,14 +48,13 @@
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL(simple_strtol);
 EXPORT_SYMBOL_NOVERS(strcat);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strncat);
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
 EXPORT_SYMBOL(_clear_page);
diff -Nru a/arch/mips64/math-emu/cp1emu.c b/arch/mips64/math-emu/cp1emu.c
--- a/arch/mips64/math-emu/cp1emu.c	Wed Apr  3 17:11:14 2002
+++ b/arch/mips64/math-emu/cp1emu.c	Wed Apr  3 17:11:14 2002
@@ -29,7 +29,7 @@
  * Notes: 
  *  1) the IEEE754 library (-le) performs the actual arithmetic;
  *  2) if you know that you won't have an fpu, then you'll get much 
- *     better performance by compiling with -msoft-float!  */
+ *     better performance by compiling with -msoft-float!
  *
  *  Nov 7, 2000
  *  Massive changes to integrate with Linux kernel.
diff -Nru a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
--- a/arch/parisc/kernel/parisc_ksyms.c	Wed Apr  3 17:11:16 2002
+++ b/arch/parisc/kernel/parisc_ksyms.c	Wed Apr  3 17:11:16 2002
@@ -20,7 +20,6 @@
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strncpy);
-EXPORT_SYMBOL(strtok);
 
 #include <linux/pci.h>
 EXPORT_SYMBOL(hppa_dma_ops);
diff -Nru a/arch/ppc/4xx_io/stb_kb.c b/arch/ppc/4xx_io/stb_kb.c
--- a/arch/ppc/4xx_io/stb_kb.c	Wed Apr  3 17:11:13 2002
+++ b/arch/ppc/4xx_io/stb_kb.c	Wed Apr  3 17:11:13 2002
@@ -19,7 +19,7 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/kbd_kern.h>
 
 /* the following are borrowed from pc_keyb.c, thanks to those involved! */
diff -Nru a/arch/ppc/iSeries/iSeries_irq.c b/arch/ppc/iSeries/iSeries_irq.c
--- a/arch/ppc/iSeries/iSeries_irq.c	Wed Apr  3 17:11:15 2002
+++ b/arch/ppc/iSeries/iSeries_irq.c	Wed Apr  3 17:11:15 2002
@@ -36,7 +36,7 @@
 
 #include <linux/irq.h>
 #include <linux/spinlock.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 
 #include <asm/iSeries/HvCallPci.h>
 #include <asm/iSeries/HvCallXm.h>
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Wed Apr  3 17:11:16 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Wed Apr  3 17:11:16 2002
@@ -123,7 +123,6 @@
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
diff -Nru a/arch/ppc/math-emu/op-4.h b/arch/ppc/math-emu/op-4.h
--- a/arch/ppc/math-emu/op-4.h	Wed Apr  3 17:11:15 2002
+++ b/arch/ppc/math-emu/op-4.h	Wed Apr  3 17:11:15 2002
@@ -279,7 +279,7 @@
     X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE);   \
     X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
     X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
-  } while (0);
+  } while (0)
 
 #define _FP_FRAC_CONV_4_1(dfs, sfs, D, S)                               \
    do {                                                                 \
diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
--- a/arch/s390/kernel/s390_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/s390/kernel/s390_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -44,7 +44,7 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
 /*
diff -Nru a/arch/s390x/kernel/s390_ksyms.c b/arch/s390x/kernel/s390_ksyms.c
--- a/arch/s390x/kernel/s390_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/s390x/kernel/s390_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -47,7 +47,7 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
 /*
diff -Nru a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
--- a/arch/sh/kernel/sh_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sh/kernel/sh_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -39,9 +39,6 @@
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
 
-EXPORT_SYMBOL(simple_strtol);
-
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(strlen);
diff -Nru a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
--- a/arch/sparc/kernel/ioport.c	Wed Apr  3 17:11:16 2002
+++ b/arch/sparc/kernel/ioport.c	Wed Apr  3 17:11:16 2002
@@ -161,7 +161,7 @@
 static void *_sparc_alloc_io(unsigned int busno, unsigned long phys,
     unsigned long size, char *name)
 {
-	static int printed_full = 0;
+	static int printed_full;
 	struct xresource *xres;
 	struct resource *res;
 	char *tack;
diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
--- a/arch/sparc/kernel/irq.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/kernel/irq.c	Wed Apr  3 17:11:14 2002
@@ -91,7 +91,7 @@
  */
 #define MAX_STATIC_ALLOC	4
 struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count = 0;
+int static_irq_count;
 
 struct irqaction *irq_action[NR_IRQS+1] = {
 	  NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
--- a/arch/sparc/kernel/pcic.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc/kernel/pcic.c	Wed Apr  3 17:11:13 2002
@@ -185,7 +185,7 @@
  * Only one PCIC per IIep,
  * and since we have no SMP IIep, only one per system.
  */
-static int pcic0_up = 0;
+static int pcic0_up;
 static struct linux_pcic pcic0;
 
 unsigned int pcic_regs;
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/kernel/process.c	Wed Apr  3 17:11:14 2002
@@ -63,9 +63,9 @@
 	for (;;) {
 		if (ARCH_SUN4C_SUN4) {
 			static int count = HZ;
-			static unsigned long last_jiffies = 0;
-			static unsigned long last_faults = 0;
-			static unsigned long fps = 0;
+			static unsigned long last_jiffies;
+			static unsigned long last_faults;
+			static unsigned long fps;
 			unsigned long now;
 			unsigned long faults;
 			unsigned long flags;
@@ -83,7 +83,7 @@
 				fps = (fps + (faults - last_faults)) >> 1;
 				last_faults = faults;
 #if 0
-				printk("kernel faults / second = %d\n", fps);
+				printk("kernel faults / second = %ld\n", fps);
 #endif
 				if (fps >= SUN4C_FAULT_HIGH) {
 					sun4c_grow_kernel_ring();
diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
--- a/arch/sparc/kernel/ptrace.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/kernel/ptrace.c	Wed Apr  3 17:11:15 2002
@@ -278,6 +278,7 @@
 	unsigned long data = regs->u_regs[UREG_I3];
 	unsigned long addr2 = regs->u_regs[UREG_I4];
 	struct task_struct *child;
+	int ret;
 
 	lock_kernel();
 #ifdef DEBUG_PTRACE
@@ -335,20 +336,13 @@
 		pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
-	if (!(child->ptrace & PT_PTRACED)) {
-		pt_error_return(regs, ESRCH);
-		goto out_tsk;
-	}
-	if(child->state != TASK_STOPPED) {
-		if(request != PTRACE_KILL) {
-			pt_error_return(regs, ESRCH);
-			goto out_tsk;
-		}
-	}
-	if(child->p_pptr != current) {
-		pt_error_return(regs, ESRCH);
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0) {
+		pt_error_return(regs, -ret);
 		goto out_tsk;
 	}
+
 	switch(request) {
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: {
diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc/kernel/setup.c	Wed Apr  3 17:11:13 2002
@@ -47,8 +47,6 @@
 #include <asm/hardirq.h>
 #include <asm/machines.h>
 
-#undef PROM_DEBUG_CONSOLE
-
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -134,6 +132,19 @@
 	}
 }
 
+static void
+prom_console_write(struct console *con, const char *s, unsigned n)
+{
+	prom_printf("%s", s);
+}
+
+static struct console prom_debug_console = {
+	name:		"debug",
+	write:		prom_console_write,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
 int obp_system_intr(void)
 {
 	if (boot_flags & BOOTME_KGDB) {
@@ -166,6 +177,10 @@
 		prom_printf("boot_flags_init: Halt!\n");
 		prom_halt();
 		break;
+	case 'p':
+		/* Use PROM debug console. */
+		register_console(&prom_debug_console);
+		break;
 	default:
 		printk("Unknown boot switch (-%c)\n", c);
 		break;
@@ -280,21 +295,6 @@
 
 struct pt_regs fake_swapper_regs;
 
-#ifdef PROM_DEBUG_CONSOLE
-static void
-prom_console_write(struct console *con, const char *s, unsigned n)
-{
-	prom_printf("%s", s);
-}
-
-static struct console prom_console = {
-	name:		"debug",
-	write:		prom_console_write,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
-};
-#endif
-
 extern void paging_init(void);
 
 void __init setup_arch(char **cmdline_p)
@@ -348,9 +348,6 @@
 		printk("UNKNOWN!\n");
 		break;
 	};
-#ifdef PROM_DEBUG_CONSOLE
-	register_console(&prom_console);
-#endif
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -381,7 +378,7 @@
 	if (!root_flags)
 		root_mountflags &= ~MS_RDONLY;
 	ROOT_DEV = to_kdev_t(root_dev);
-#ifdef CONFIG_BLK_DEV_RAM
+#ifdef CONFIG_BLK_DEV_INITRD
 	rd_image_start = ram_flags & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((ram_flags & RAMDISK_PROMPT_FLAG) != 0);
 	rd_doload = ((ram_flags & RAMDISK_LOAD_FLAG) != 0);	
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/kernel/signal.c	Wed Apr  3 17:11:15 2002
@@ -1195,8 +1195,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -1245,7 +1245,7 @@
 				current->exit_code = signr;
 
 				/* notify_parent() is SMP safe */
-				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags &
+				if(!(current->parent->sig->action[SIGCHLD-1].sa.sa_flags &
 				     SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
@@ -1280,7 +1280,10 @@
 #endif
 				/* fall through */
 			default:
-				sig_exit(signr, exit_code, &info);
+				sigaddset(&current->pending.signal, signr);
+				recalc_sigpending(current);
+				current->flags |= PF_SIGNALED;
+				do_exit(exit_code);
 				/* NOT REACHED */
 			}
 		}
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/kernel/sparc_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -250,7 +250,6 @@
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strstr);
 EXPORT_SYMBOL(page_kernel);
 
diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
--- a/arch/sparc/kernel/sun4d_smp.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/kernel/sun4d_smp.c	Wed Apr  3 17:11:14 2002
@@ -47,7 +47,7 @@
 extern volatile int smp_processors_ready;
 extern unsigned long cpu_present_map;
 extern int smp_num_cpus;
-static int smp_highest_cpu = 0;
+static int smp_highest_cpu;
 extern int smp_threads_ready;
 extern unsigned char mid_xlate[NR_CPUS];
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
--- a/arch/sparc/kernel/time.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/kernel/time.c	Wed Apr  3 17:11:15 2002
@@ -115,7 +115,7 @@
 void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
+	static long last_rtc_update;
 
 #ifndef CONFIG_SMP
 	if(!user_mode(regs))
diff -Nru a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
--- a/arch/sparc/kernel/traps.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/kernel/traps.c	Wed Apr  3 17:11:15 2002
@@ -272,7 +272,7 @@
 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		 unsigned long psr)
 {
-	static int calls = 0;
+	static int calls;
 	siginfo_t info;
 	unsigned long fsr;
 	int ret = 0;
diff -Nru a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c
--- a/arch/sparc/mm/iommu.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/mm/iommu.c	Wed Apr  3 17:11:15 2002
@@ -25,7 +25,7 @@
 BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long)
 #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page)
 extern int flush_page_for_dma_global;
-static int viking_flush = 0;
+static int viking_flush;
 /* viking.S */
 extern void viking_flush_page(unsigned long page);
 extern void viking_mxcc_flush_page(unsigned long page);
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc/mm/srmmu.c	Wed Apr  3 17:11:13 2002
@@ -1739,7 +1739,7 @@
 static void __init poke_viking(void)
 {
 	unsigned long mreg = srmmu_get_mmureg();
-	static int smp_catch = 0;
+	static int smp_catch;
 
 	if(viking_mxcc_present) {
 		unsigned long mxcc_control = mxcc_get_creg();
@@ -1963,7 +1963,7 @@
 		iaddr = &(insn); \
 		daddr = &(dest); \
 		*iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
-	} while(0);
+	} while(0)
 
 static void __init patch_window_trap_handlers(void)
 {
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/mm/sun4c.c	Wed Apr  3 17:11:14 2002
@@ -425,7 +425,7 @@
 		daddr = &(dst);		\
 		iaddr = &(src);		\
 		*daddr = *iaddr;	\
-	} while (0);
+	} while (0)
 
 static void patch_kernel_fault_handler(void)
 {
diff -Nru a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S
--- a/arch/sparc/mm/swift.S	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc/mm/swift.S	Wed Apr  3 17:11:15 2002
@@ -53,11 +53,9 @@
 
 	.globl	swift_flush_cache_mm
 swift_flush_cache_mm:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_mm_out
-#endif
 	WINDOW_FLUSH(%g4, %g5)
 	rd	%psr, %g1
 	andn	%g1, PSR_ET, %g3
@@ -121,11 +119,9 @@
 swift_flush_cache_page:
 	ld	[%o0 + 0x0], %o0		/* XXX vma->vm_mm, GROSS XXX */
 70:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_cache_page_out
-#endif
 	WINDOW_FLUSH(%g4, %g5)
 	rd	%psr, %g1
 	andn	%g1, PSR_ET, %g3
@@ -226,11 +222,9 @@
 swift_flush_tlb_range:
 	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 swift_flush_tlb_mm:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	swift_flush_tlb_all_out
-#endif
 swift_flush_tlb_all:
 	mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
@@ -244,11 +238,9 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	swift_flush_tlb_page_out
 	 nop
-#endif
 #if 1
 	mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE	
diff -Nru a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
--- a/arch/sparc/mm/tsunami.S	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc/mm/tsunami.S	Wed Apr  3 17:11:14 2002
@@ -27,10 +27,8 @@
 	ld	[%o0 + 0x0], %o0	/* XXX vma->vm_mm, GROSS XXX */
 tsunami_flush_cache_mm:
 	ld	[%o0 + AOFF_mm_context], %g2
-#ifndef CONFIG_SMP
 	cmp	%g2, -1
 	be	tsunami_flush_cache_out
-#endif
 tsunami_flush_cache_all:
 	WINDOW_FLUSH(%g4, %g5)
 tsunami_flush_page_for_dma:
@@ -50,11 +48,9 @@
 tsunami_flush_tlb_range:
 	ld	[%o0 + 0x00], %o0	/* XXX vma->vm_mm GROSS XXX */
 tsunami_flush_tlb_mm:
-#ifndef CONFIG_SMP
 	ld	[%o0 + AOFF_mm_context], %g2
 	cmp	%g2, -1
 	be	tsunami_flush_tlb_out
-#endif
 tsunami_flush_tlb_all:
 	 mov	0x400, %o1
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
@@ -73,10 +69,8 @@
 	mov	SRMMU_CTX_REG, %g1
 	ld	[%o0 + AOFF_mm_context], %o3
 	andn	%o1, (PAGE_SIZE - 1), %o1
-#ifndef CONFIG_SMP
 	cmp	%o3, -1
 	be	tsunami_flush_tlb_page_out
-#endif
 	 lda	[%g1] ASI_M_MMUREGS, %g5
 	sta	%o3, [%g1] ASI_M_MMUREGS
 	sta	%g0, [%o1] ASI_M_FLUSH_PROBE
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/defconfig	Wed Apr  3 17:11:14 2002
@@ -248,7 +248,7 @@
 CONFIG_IDE=y
 
 #
-# IDE, ATA and ATAPI Block devices
+# ATA and ATAPI Block devices
 #
 CONFIG_BLK_DEV_IDE=y
 
@@ -283,9 +283,9 @@
 # CONFIG_BLK_DEV_ISAPNP is not set
 # CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -296,13 +296,13 @@
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC_ADMA is not set
@@ -314,10 +314,9 @@
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
 # CONFIG_DMA_NONPCI is not set
-CONFIG_BLK_DEV_IDE_MODES=y
 # CONFIG_BLK_DEV_ATARAID is not set
 # CONFIG_BLK_DEV_ATARAID_PDC is not set
 # CONFIG_BLK_DEV_ATARAID_HPT is not set
@@ -789,6 +788,7 @@
 # USB Device Class drivers
 #
 # CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
 CONFIG_USB_BLUETOOTH=m
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -909,6 +909,7 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_DEBUG_DCFLUSH is not set
+# CONFIG_STACK_DEBUG is not set
 
 #
 # Library routines
diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c
--- a/arch/sparc64/kernel/binfmt_elf32.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/binfmt_elf32.c	Wed Apr  3 17:11:14 2002
@@ -43,7 +43,7 @@
 	dest[34] = (unsigned int) src->tnpc;		\
 	dest[35] = src->y;				\
 	dest[36] = dest[37] = 0; /* XXX */		\
-} while(0);
+} while(0)
 
 typedef struct {
 	union {
diff -Nru a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
--- a/arch/sparc64/kernel/ebus.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/ebus.c	Wed Apr  3 17:11:14 2002
@@ -275,6 +275,25 @@
 	printk("]");
 }
 
+static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
+{
+	struct pci_dev *pdev = start;
+
+	do {
+		pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev);
+		if (pdev &&
+		    (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
+		     pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+			break;
+	} while (pdev != NULL);
+
+	if (pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS))
+		*is_rio_p = 1;
+	else
+		*is_rio_p = 0;
+
+	return pdev;
+}
 
 void __init ebus_init(void)
 {
@@ -289,12 +308,7 @@
 	if (!pci_present())
 		return;
 
-	is_rio = 0;
-	pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
-	if (!pdev) {
-		pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_EBUS, 0);
-		is_rio = 1;
-	}
+	pdev = find_next_ebus(NULL, &is_rio);
 	if (!pdev) {
 		printk("ebus: No EBus's found.\n");
 		return;
@@ -315,16 +329,7 @@
 		   we'd have to tweak with the ebus_chain
 		   in the runtime after initialization. -jj */
 		if (!prom_getchild (ebusnd)) {
-			struct pci_dev *orig_pdev = pdev;
-
-			is_rio = 0;
-			pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
-					       PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
-			if (!pdev) {
-				pdev = pci_find_device(PCI_VENDOR_ID_SUN, 
-						       PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
-				is_rio = 1;
-			}
+			pdev = find_next_ebus(pdev, &is_rio);
 			if (!pdev) {
 				if (ebus == ebus_chain) {
 					ebus_chain = NULL;
@@ -374,20 +379,9 @@
 	next_ebus:
 		printk("\n");
 
-		{
-			struct pci_dev *orig_pdev = pdev;
-
-			is_rio = 0;
-			pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-					       PCI_DEVICE_ID_SUN_EBUS, orig_pdev);
-			if (!pdev) {
-				pdev = pci_find_device(PCI_VENDOR_ID_SUN,
-						       PCI_DEVICE_ID_SUN_RIO_EBUS, orig_pdev);
-				is_rio = 1;
-			}
-			if (!pdev)
-				break;
-		}
+		pdev = find_next_ebus(pdev, &is_rio);
+		if (!pdev)
+			break;
 
 		cookie = pdev->sysdata;
 		ebusnd = cookie->prom_node;
diff -Nru a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
--- a/arch/sparc64/kernel/head.S	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/head.S	Wed Apr  3 17:11:15 2002
@@ -565,13 +565,6 @@
 #define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 	mov	TSB_REG, %g1
 	stxa	%g0, [%g1] ASI_DMMU
 	membar	#Sync
@@ -602,8 +595,6 @@
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 	/* Setup Interrupt globals */
 	wrpr	%o1, (PSTATE_IG|PSTATE_IE), %pstate
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/ioctl32.c	Wed Apr  3 17:11:15 2002
@@ -1061,7 +1061,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("%s: Unknown fb ioctl cmd fd(%d) "
 				       "cmd(%08x) arg(%08lx)\n",
@@ -1714,7 +1714,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("ppp_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1824,7 +1824,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("mt_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -1942,7 +1942,7 @@
 		break;
 	default:
 		do {
-			static int count = 0;
+			static int count;
 			if (++count <= 20)
 				printk("cdrom_ioctl: Unknown cmd fd(%d) "
 				       "cmd(%08x) arg(%08x)\n",
@@ -2029,7 +2029,7 @@
 		}
 		break;
 	default: {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("%s: Unknown loop ioctl cmd, fd(%d) "
 			       "cmd(%08x) arg(%08lx)\n",
@@ -4882,7 +4882,7 @@
 		handler = (void *)(long)t->handler;
 		error = handler(fd, cmd, arg, filp);
 	} else {
-		static int count = 0;
+		static int count;
 		if (++count <= 20)
 			printk("sys32_ioctl(%s:%d): Unknown cmd fd(%d) "
 			       "cmd(%08x) arg(%08x)\n",
diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
--- a/arch/sparc64/kernel/irq.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/irq.c	Wed Apr  3 17:11:15 2002
@@ -82,7 +82,7 @@
  */
 #define MAX_STATIC_ALLOC	4
 static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count = 0;
+static int static_irq_count;
 
 /* This is exported so that fast IRQ handlers can get at it... -DaveM */
 struct irqaction *irq_action[NR_IRQS+1] = {
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc64/kernel/pci.c	Wed Apr  3 17:11:13 2002
@@ -234,33 +234,63 @@
 	return request_resource(root, res);
 }
 
+/*
+ * Given the PCI bus a device resides on, try to
+ * find an acceptable resource allocation for a
+ * specific device resource..
+ */
+static int pci_assign_bus_resource(const struct pci_bus *bus,
+	struct pci_dev *dev,
+	struct resource *res,
+	unsigned long size,
+	unsigned long min,
+	int resno)
+{
+	unsigned int type_mask;
+	int i;
+
+	type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+	for (i = 0 ; i < 4; i++) {
+		struct resource *r = bus->resource[i];
+		if (!r)
+			continue;
+
+		/* type_mask must match */
+		if ((res->flags ^ r->flags) & type_mask)
+			continue;
+
+		/* Ok, try it out.. */
+		if (allocate_resource(r, res, size, min, -1, size, NULL, NULL) < 0)
+			continue;
+
+		/* PCI config space updated by caller.  */
+		return 0;
+	}
+	return -EBUSY;
+}
+
 int pci_assign_resource(struct pci_dev *pdev, int resource)
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm = pcp->pbm;
 	struct resource *res = &pdev->resource[resource];
-	struct resource *root;
-	unsigned long min, max, size, align;
+	unsigned long min, size;
 	int err;
 
-	if (res->flags & IORESOURCE_IO) {
-		root = &pbm->io_space;
-		min = root->start + 0x400UL;
-		max = root->end;
-	} else {
-		root = &pbm->mem_space;
-		min = root->start;
-		max = min + 0x80000000UL;
-	}
+	if (res->flags & IORESOURCE_IO)
+		min = pbm->io_space.start + 0x400UL;
+	else
+		min = pbm->mem_space.start;
+
+	size = res->end - res->start + 1;
 
-	size = res->end - res->start;
-	align = size + 1;
+	err = pci_assign_bus_resource(pdev->bus, pdev, res, size, min, resource);
 
-	err = allocate_resource(root, res, size + 1, min, max, align, NULL, NULL);
 	if (err < 0) {
 		printk("PCI: Failed to allocate resource %d for %s\n",
 		       resource, pdev->name);
 	} else {
+		/* Update PCI config space. */
 		pbm->parent->base_address_update(pdev, resource);
 	}
 
diff -Nru a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
--- a/arch/sparc64/kernel/pci_common.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/pci_common.c	Wed Apr  3 17:11:14 2002
@@ -571,14 +571,12 @@
 	struct pci_pbm_info *pbm = dev_pcp->pbm;
 	struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs;
 	unsigned int hi, mid, lo, irq;
-	int i, num_intmap;
-
-	if (pbm->num_pbm_intmap == 0)
-		return 0;
+	int i, num_intmap, map_slot;
 
 	intmap = &pbm->pbm_intmap[0];
 	intmask = &pbm->pbm_intmask;
 	num_intmap = pbm->num_pbm_intmap;
+	map_slot = 0;
 
 	/* If we are underneath a PCI bridge, use PROM register
 	 * property of the parent bridge which is closest to
@@ -639,11 +637,21 @@
 				printk("pci_intmap_match: Trying to recover.\n");
 				return 0;
 			}
+
+			if (pdev->bus->self != bus_dev)
+				map_slot = 1;
 		} else {
 			pregs = bus_pcp->prom_regs;
+			map_slot = 1;
 		}
 	}
 
+	if (map_slot) {
+		*interrupt = ((*interrupt
+			       - 1
+			       + PCI_SLOT(pdev->devfn)) & 0x3) + 1;
+	}
+
 	hi   = pregs->phys_hi & intmask->phys_hi;
 	mid  = pregs->phys_mid & intmask->phys_mid;
 	lo   = pregs->phys_lo & intmask->phys_lo;
@@ -655,24 +663,33 @@
 		    intmap[i].phys_lo  == lo	&&
 		    intmap[i].interrupt == irq) {
 			*interrupt = intmap[i].cinterrupt;
+			printk("PCI-IRQ: Routing bus[%2x] slot[%2x] map[%d] to INO[%02x]\n",
+			       pdev->bus->number, PCI_SLOT(pdev->devfn),
+			       map_slot, *interrupt);
 			return 1;
 		}
 	}
 
-	/* Print it both to OBP console and kernel one so that if bootup
-	 * hangs here the user has the information to report.
+	/* We will run this code even if pbm->num_pbm_intmap is zero, just so
+	 * we can apply the slot mapping to the PROM interrupt property value.
+	 * So do not spit out these warnings in that case.
 	 */
-	prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
-		    pdev->bus->number, pdev->devfn);
-	prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-		    pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-	prom_printf("Please email this information to davem@redhat.com\n");
-
-	printk("pci_intmap_match: bus %02x, devfn %02x: ",
-	       pdev->bus->number, pdev->devfn);
-	printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
-	       pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
-	printk("Please email this information to davem@redhat.com\n");
+	if (num_intmap != 0) {
+		/* Print it both to OBP console and kernel one so that if bootup
+		 * hangs here the user has the information to report.
+		 */
+		prom_printf("pci_intmap_match: bus %02x, devfn %02x: ",
+			    pdev->bus->number, pdev->devfn);
+		prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+			    pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+		prom_printf("Please email this information to davem@redhat.com\n");
+
+		printk("pci_intmap_match: bus %02x, devfn %02x: ",
+		       pdev->bus->number, pdev->devfn);
+		printk("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n",
+		       pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt);
+		printk("Please email this information to davem@redhat.com\n");
+	}
 
 	return 0;
 }
@@ -718,20 +735,6 @@
 	if ((prom_irq & PCI_IRQ_INO) & 0x20) {
 		pdev->irq = p->irq_build(pbm, pdev, (portid << 6 | prom_irq));
 		goto have_irq;
-	}
-
-	/* Firmware gets quad-hme interrupts property totally
-	 * wrong.  It is 4 EBUS+HME devices behind a Digital bridge.
-	 * For each of the 4 instances the EBUS has interrupt property
-	 * '1' and the HME has interrupt property '2'.  So we have to
-	 * fix this up.
-	 */
-	if (!strcmp(pcp->prom_name, "SUNW,qfe") ||
-	    !strcmp(pcp->prom_name, "qfe")) {
-		if (PCI_SLOT(pdev->devfn) & ~3)
-			BUG();
-
-		prom_irq = PCI_SLOT(pdev->devfn) + 1;
 	}
 
 	/* Can we find a matching entry in the interrupt-map? */
diff -Nru a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
--- a/arch/sparc64/kernel/pci_psycho.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/pci_psycho.c	Wed Apr  3 17:11:15 2002
@@ -1101,7 +1101,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1117,6 +1124,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - root->start)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
diff -Nru a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
--- a/arch/sparc64/kernel/pci_sabre.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/pci_sabre.c	Wed Apr  3 17:11:15 2002
@@ -1067,7 +1067,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1083,6 +1090,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - base)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
@@ -1148,7 +1159,7 @@
 
 static void __init sabre_scan_bus(struct pci_controller_info *p)
 {
-	static int once = 0;
+	static int once;
 	struct pci_bus *sabre_bus;
 	struct pci_pbm_info *pbm;
 	struct pcidev_cookie *cookie;
diff -Nru a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
--- a/arch/sparc64/kernel/pci_schizo.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/pci_schizo.c	Wed Apr  3 17:11:14 2002
@@ -383,7 +383,7 @@
 	struct ino_bucket *bucket;
 	unsigned long imap, iclr, pbm_off;
 	unsigned long imap_off, iclr_off;
-	int pil, inofixup = 0;
+	int pil;
 
 	if (pbm == &p->pbm_A)
 		pbm_off = SCHIZO_PBM_A_REGS_OFF;
@@ -406,10 +406,13 @@
 	iclr = p->controller_regs + pbm_off + iclr_off;
 	iclr += 4;
 
-	if (ino < 0x18)
-		inofixup = ino & 0x03;
-
-	bucket = __bucket(build_irq(pil, inofixup, iclr, imap));
+	/* On Schizo, no inofixup occurs.  This is because each
+	 * INO has it's own IMAP register.  On Psycho and Sabre
+	 * there is only one IMAP register for each PCI slot even
+	 * though four different INOs can be generated by each
+	 * PCI slot.
+	 */
+	bucket = __bucket(build_irq(pil, 0, iclr, imap));
 	bucket->flags |= IBF_PCI;
 
 	return __irq(bucket);
@@ -1423,7 +1426,14 @@
 	int where, size, is_64bit;
 
 	res = &pdev->resource[resource];
-	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	if (resource < 6) {
+		where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	} else if (resource == PCI_ROM_RESOURCE) {
+		where = pdev->rom_base_reg;
+	} else {
+		/* Somebody might have asked allocation of a non-standard resource */
+		return;
+	}
 
 	is_64bit = 0;
 	if (res->flags & IORESOURCE_IO)
@@ -1439,6 +1449,10 @@
 	pci_read_config_dword(pdev, where, &reg);
 	reg = ((reg & size) |
 	       (((u32)(res->start - root->start)) & ~size));
+	if (resource == PCI_ROM_RESOURCE) {
+		reg |= PCI_ROM_ADDRESS_ENABLE;
+		res->flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
 	pci_write_config_dword(pdev, where, reg);
 
 	/* This knows that the upper 32-bits of the address
@@ -1469,24 +1483,12 @@
 #define SCHIZO_PCI_B_IO_MATCH		0x00070UL
 #define SCHIZO_PCI_B_IO_MASK		0x00078UL
 
-/* VAL must be non-zero. */
-static unsigned long strip_to_lowest_bit_set(unsigned long val)
-{
-	unsigned long tmp;
-
-	tmp = 1UL;
-	while (!(tmp & val))
-		tmp <<= 1UL;
-
-	return tmp;
-}
-
 static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm,
 					  int is_pbm_a, unsigned long reg_base)
 {
 	u64 mem_match, mem_mask;
 	u64 io_match;
-	u64 long a, b;
+	u64 a;
 
 	if (is_pbm_a) {
 		mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH;
@@ -1498,11 +1500,12 @@
 	mem_mask = mem_match + 0x8UL;
 
 	a = schizo_read(mem_match) & ~0x8000000000000000UL;
-	b = strip_to_lowest_bit_set(schizo_read(mem_mask));
 
-	/* It should be 2GB in size. */
+	/* It should be 2GB in size but the decode is set for the full
+	 * 4GB so we have to add the 2G by hand.
+	 */
 	pbm->mem_space.start = a;
-	pbm->mem_space.end = a + (b - 1UL);
+	pbm->mem_space.end = a + 0x80000000;
 	pbm->mem_space.flags = IORESOURCE_MEM;
 
 	/* This 32MB area is divided into two pieces.  The first
diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
--- a/arch/sparc64/kernel/power.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/power.c	Wed Apr  3 17:11:15 2002
@@ -22,7 +22,7 @@
 #define POWER_COURTESY_OFF (1 << 1)
 
 static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed = 0;
+static int button_pressed;
 
 static void power_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -81,7 +81,7 @@
 {
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
-	static int invoked = 0;
+	static int invoked;
 
 	if (invoked)
 		return;
diff -Nru a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
--- a/arch/sparc64/kernel/ptrace.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/ptrace.c	Wed Apr  3 17:11:15 2002
@@ -122,6 +122,7 @@
 	unsigned long data = regs->u_regs[UREG_I3];
 	unsigned long addr2 = regs->u_regs[UREG_I4];
 	struct task_struct *child;
+	int ret;
 
 	if (test_thread_flag(TIF_32BIT)) {
 		addr &= 0xffffffffUL;
@@ -184,18 +185,10 @@
 		pt_succ_return(regs, 0);
 		goto out_tsk;
 	}
-	if (!(child->ptrace & PT_PTRACED)) {
-		pt_error_return(regs, ESRCH);
-		goto out_tsk;
-	}
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL) {
-			pt_error_return(regs, ESRCH);
-			goto out_tsk;
-		}
-	}
-	if (child->p_pptr != current) {
-		pt_error_return(regs, ESRCH);
+
+	ret = ptrace_check_attach(child, request == PTRACE_KILL);
+	if (ret < 0) {
+		pt_error_return(regs, -ret);
 		goto out_tsk;
 	}
 
diff -Nru a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
--- a/arch/sparc64/kernel/signal.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/signal.c	Wed Apr  3 17:11:15 2002
@@ -729,8 +729,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -772,7 +772,7 @@
 				struct signal_struct *sig;
 
 				current->exit_code = signr;
-				sig = current->p_pptr->sig;
+				sig = current->parent->sig;
 				preempt_disable();
 				current->state = TASK_STOPPED;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc64/kernel/signal32.c	Wed Apr  3 17:11:13 2002
@@ -1403,8 +1403,8 @@
 				info.si_signo = signr;
 				info.si_errno = 0;
 				info.si_code = SI_USER;
-				info.si_pid = current->p_pptr->pid;
-				info.si_uid = current->p_pptr->uid;
+				info.si_pid = current->parent->pid;
+				info.si_uid = current->parent->uid;
 			}
 
 			/* If the (new) signal is now blocked, requeue it.  */
@@ -1446,7 +1446,7 @@
 				struct signal_struct *sig;
 
 				current->exit_code = signr;
-				sig = current->p_pptr->sig;
+				sig = current->parent->sig;
 				preempt_disable();
 				current->state = TASK_STOPPED;
 				if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags &
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc64/kernel/smp.c	Wed Apr  3 17:11:13 2002
@@ -46,8 +46,8 @@
 volatile int __cpu_logical_map[NR_CPUS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
 
 /* Please don't make this stuff initdata!!!  --DaveM */
-static unsigned char boot_cpu_id = 0;
-static int smp_activated = 0;
+static unsigned char boot_cpu_id;
+static int smp_activated;
 
 /* Kernel spinlock */
 spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
@@ -898,7 +898,7 @@
 
 static atomic_t smp_capture_depth = ATOMIC_INIT(0);
 static atomic_t smp_capture_registry = ATOMIC_INIT(0);
-static unsigned long penguins_are_doing_time = 0;
+static unsigned long penguins_are_doing_time;
 
 void smp_capture(void)
 {
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -303,7 +303,6 @@
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strstr);
 
 #ifdef CONFIG_SOLARIS_EMUL_MODULE
diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
--- a/arch/sparc64/kernel/sys_sparc.c	Wed Apr  3 17:11:13 2002
+++ b/arch/sparc64/kernel/sys_sparc.c	Wed Apr  3 17:11:13 2002
@@ -380,7 +380,7 @@
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
 {
-	static int count=0;
+	static int count;
 	
 	/* Don't make the system unusable, if someone goes stuck */
 	if (count++ > 5)
@@ -450,7 +450,7 @@
 
 asmlinkage int solaris_syscall(struct pt_regs *regs)
 {
-	static int count = 0;
+	static int count;
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
@@ -470,7 +470,7 @@
 #ifndef CONFIG_SUNOS_EMUL
 asmlinkage int sunos_syscall(struct pt_regs *regs)
 {
-	static int count = 0;
+	static int count;
 
 	regs->tpc = regs->tnpc;
 	regs->tnpc += 4;
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/kernel/sys_sunos32.c	Wed Apr  3 17:11:14 2002
@@ -210,7 +210,7 @@
 
 asmlinkage void sunos_vadvise(u32 strategy)
 {
-	static int count = 0;
+	static int count;
 
 	/* I wanna see who uses this... */
 	if (count++ < 5)
diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
--- a/arch/sparc64/kernel/time.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/time.c	Wed Apr  3 17:11:15 2002
@@ -62,7 +62,7 @@
 static __inline__ void timer_check_rtc(void)
 {
 	/* last time the cmos clock got updated */
-	static long last_rtc_update=0;
+	static long last_rtc_update;
 
 	/* Determine when to update the Mostek clock. */
 	if ((time_status & STA_UNSYNC) == 0 &&
@@ -410,7 +410,7 @@
 	struct linux_ebus *ebus = NULL;
 	struct isa_bridge *isa_br = NULL;
 #endif
-	static int invoked = 0;
+	static int invoked;
 
 	if (invoked)
 		return;
diff -Nru a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
--- a/arch/sparc64/kernel/trampoline.S	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/kernel/trampoline.S	Wed Apr  3 17:11:15 2002
@@ -215,13 +215,6 @@
 #define KERN_HIGHBITS		((_PAGE_VALID|_PAGE_SZ4MB)^0xfffff80000000000)
 #define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 	mov		TSB_REG, %g1
 	stxa		%g0, [%g1] ASI_DMMU
 	membar		#Sync
@@ -252,8 +245,6 @@
 	clr	%g7
 #undef KERN_HIGHBITS
 #undef KERN_LOWBITS
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 	wrpr		%o1, 0x0, %pstate
 	ldx		[%g6 + TI_TASK], %g4
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/mm/init.c	Wed Apr  3 17:11:15 2002
@@ -699,7 +699,7 @@
 	}
 }
 
-static int prom_ditlb_set = 0;
+static int prom_ditlb_set;
 struct prom_tlb_entry {
 	int		tlb_ent;
 	unsigned long	tlb_tag;
diff -Nru a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c
--- a/arch/sparc64/prom/bootstr.c	Wed Apr  3 17:11:14 2002
+++ b/arch/sparc64/prom/bootstr.c	Wed Apr  3 17:11:14 2002
@@ -9,6 +9,11 @@
 #include <linux/init.h>
 #include <asm/oplib.h>
 
+/* WARNING: The boot loader knows that these next three variables come one right
+ *          after another in the .data section.  Do not move this stuff into
+ *          the .bss section or it will break things.
+ */
+
 #define BARG_LEN  256
 int bootstr_len = BARG_LEN;
 static int bootstr_valid = 0;
diff -Nru a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
--- a/arch/sparc64/prom/misc.c	Wed Apr  3 17:11:16 2002
+++ b/arch/sparc64/prom/misc.c	Wed Apr  3 17:11:16 2002
@@ -171,7 +171,7 @@
 
 static int prom_get_memory_ihandle(void)
 {
-	static int memory_ihandle_cache = 0;
+	static int memory_ihandle_cache;
 	int node, ret;
 
 	if (memory_ihandle_cache != 0)
diff -Nru a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
--- a/arch/sparc64/solaris/misc.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/solaris/misc.c	Wed Apr  3 17:11:15 2002
@@ -57,7 +57,7 @@
 	/* Do we need it here? */
 	set_personality(PER_SVR4);
 	if (flags & MAP_NORESERVE) {
-		static int cnt = 0;
+		static int cnt;
 		
 		if (cnt < 5) {
 			printk("%s:  unimplemented Solaris MAP_NORESERVE mmap() flag\n",
diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
--- a/arch/sparc64/solaris/timod.c	Wed Apr  3 17:11:15 2002
+++ b/arch/sparc64/solaris/timod.c	Wed Apr  3 17:11:15 2002
@@ -46,7 +46,7 @@
 void * mykmalloc(size_t s, int gfp)
 {
 	static char * page;
-	static size_t free = 0;
+	static size_t free;
 	void * r;
 	s = ((s + 63) & ~63);
 	if( s > PAGE_SIZE ) {
diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
--- a/arch/x86_64/kernel/x8664_ksyms.c	Wed Apr  3 17:11:14 2002
+++ b/arch/x86_64/kernel/x8664_ksyms.c	Wed Apr  3 17:11:14 2002
@@ -87,7 +87,6 @@
 EXPORT_SYMBOL_NOVERS(__put_user_2);
 EXPORT_SYMBOL_NOVERS(__put_user_4);
 
-EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strpbrk);
 EXPORT_SYMBOL(strstr);
 
diff -Nru a/drivers/acpi/acpi_tables.c b/drivers/acpi/acpi_tables.c
--- a/drivers/acpi/acpi_tables.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/acpi/acpi_tables.c	Wed Apr  3 17:11:15 2002
@@ -32,6 +32,7 @@
 #include <linux/types.h>
 #include <linux/irq.h>
 #include <linux/acpi.h>
+#include <linux/err.h>
 
 #define PREFIX			"ACPI: "
 
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/atm/eni.c	Wed Apr  3 17:11:14 2002
@@ -14,7 +14,6 @@
 #include <linux/sonet.h>
 #include <linux/skbuff.h>
 #include <linux/time.h>
-#include <linux/sched.h> /* for xtime */
 #include <linux/delay.h>
 #include <linux/uio.h>
 #include <linux/init.h>
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/block/DAC960.c	Wed Apr  3 17:11:16 2002
@@ -5295,7 +5295,7 @@
       DAC960_ComputeGenericDiskInfo(Controller);
       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
-  if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
+  if (Controller->GenericDiskInfo.sizes[minor(Inode->i_rdev)] == 0)
     return -ENXIO;
   /*
     Increment Controller and Logical Drive Usage Counts.
@@ -6902,3 +6902,5 @@
 
 module_init(DAC960_Initialize);
 module_exit(DAC960_Finalize);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/block/blkpg.c	Wed Apr  3 17:11:14 2002
@@ -247,8 +247,8 @@
 		case BLKFLSBUF:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			fsync_dev(dev);
-			invalidate_buffers(dev);
+			fsync_bdev(bdev);
+			invalidate_bdev(bdev, 0);
 			return 0;
 
 		case BLKSSZGET:
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/block/cciss.c	Wed Apr  3 17:11:16 2002
@@ -42,6 +42,7 @@
 #include <linux/blk.h>
 #include <linux/blkdev.h>
 #include <linux/genhd.h>
+#include <linux/completion.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 #define DRIVER_NAME "Compaq CISS Driver (v 2.5.0)"
diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
--- a/drivers/block/cciss_scsi.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/block/cciss_scsi.c	Wed Apr  3 17:11:14 2002
@@ -32,6 +32,7 @@
 #include "../scsi/hosts.h" 
 #include <asm/atomic.h>
 #include <linux/timer.h>
+#include <linux/completion.h>
 
 #include "cciss_scsi.h"
 
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/block/genhd.c	Wed Apr  3 17:11:15 2002
@@ -22,6 +22,7 @@
 #include <linux/blk.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/seq_file.h>
 
 
 static rwlock_t gendisk_lock;
@@ -142,39 +143,58 @@
 }
 
 #ifdef CONFIG_PROC_FS
-int
-get_partition_list(char *page, char **start, off_t offset, int count)
+/* iterator */
+static void *part_start(struct seq_file *part, loff_t *pos)
 {
-	struct gendisk *gp;
-	char buf[64];
-	int len, n;
+	loff_t k = *pos;
+	struct gendisk *sgp;
 
-	len = sprintf(page, "major minor  #blocks  name\n\n");
 	read_lock(&gendisk_lock);
-	for (gp = gendisk_head; gp; gp = gp->next) {
-		for (n = 0; n < (gp->nr_real << gp->minor_shift); n++) {
-			if (gp->part[n].nr_sects == 0)
-				continue;
-
-			len += snprintf(page + len, 63,
-					"%4d  %4d %10d %s\n",
-					gp->major, n, gp->sizes[n],
-					disk_name(gp, n, buf));
-			if (len < offset)
-				offset -= len, len = 0;
-			else if (len >= offset + count)
-				goto out;
-		}
+	for (sgp = gendisk_head; sgp; sgp = sgp->next) {
+		if (!k--)
+			return sgp;
 	}
+	return NULL;
+}
 
-out:
+static void *part_next(struct seq_file *part, void *v, loff_t *pos)
+{
+	++*pos;
+	return ((struct gendisk *)v)->next;
+}
+
+static void part_stop(struct seq_file *part, void *v)
+{
 	read_unlock(&gendisk_lock);
-	*start = page + offset;
-	len -= offset;
-	if (len < 0)
-		len = 0;
-	return len > count ? count : len;
 }
+
+static int show_partition(struct seq_file *part, void *v)
+{
+	struct gendisk *sgp = v;
+	int n;
+	char buf[64];
+
+	if (sgp == gendisk_head)
+		seq_puts(part, "major minor  #blocks  name\n\n");
+
+	/* show all non-0 size partitions of this disk */
+	for (n = 0; n < (sgp->nr_real << sgp->minor_shift); n++) {
+		if (sgp->part[n].nr_sects == 0)
+			continue;
+		seq_printf(part, "%4d  %4d %10d %s\n",
+			sgp->major, n, sgp->sizes[n],
+			disk_name(sgp, n, buf));
+	}
+
+	return 0;
+}
+
+struct seq_operations partitions_op = {
+	start:	part_start,
+	next:	part_next,
+	stop:	part_stop,
+	show:	show_partition
+};
 #endif
 
 
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/block/loop.c	Wed Apr  3 17:11:13 2002
@@ -36,6 +36,9 @@
  * Al Viro too.
  * Jens Axboe <axboe@suse.de>, Nov 2000
  *
+ * Support up to 256 loop devices
+ * Heinz Mauelshagen <mge@sistina.com>, Feb 2002
+ *
  * Still To Fix:
  * - Advisory locking is ignored here. 
  * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 
@@ -927,7 +930,7 @@
  * And now the modules code and kernel interface.
  */
 MODULE_PARM(max_loop, "i");
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
 MODULE_LICENSE("GPL");
 
 int loop_register_transfer(struct loop_func_table *funcs)
@@ -963,9 +966,9 @@
 {
 	int	i;
 
-	if ((max_loop < 1) || (max_loop > 255)) {
+	if ((max_loop < 1) || (max_loop > 256)) {
 		printk(KERN_WARNING "loop: invalid max_loop (must be between"
-				    " 1 and 255), using default (8)\n");
+				    " 1 and 256), using default (8)\n");
 		max_loop = 8;
 	}
 
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/block/nbd.c	Wed Apr  3 17:11:14 2002
@@ -327,7 +327,7 @@
 		req = CURRENT;
 #ifdef PARANOIA
 		if (!req)
-			FAIL("que not empty but no request?");
+			FAIL("queue not empty but no request?");
 #endif
 		dev = minor(req->rq_dev);
 #ifdef PARANOIA
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/block/rd.c	Wed Apr  3 17:11:14 2002
@@ -405,9 +405,10 @@
 	for (i = 0 ; i < NUM_RAMDISKS; i++) {
 		struct block_device *bdev = rd_bdev[i];
 		rd_bdev[i] = NULL;
-		if (bdev)
+		if (bdev) {
+			invalidate_bdev(bdev, 1);
 			blkdev_put(bdev, BDEV_FILE);
-		destroy_buffers(mk_kdev(MAJOR_NR, i));
+		}
 	}
 
 	devfs_unregister (devfs_handle);
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/cdrom/cdrom.c	Wed Apr  3 17:11:14 2002
@@ -1107,6 +1107,7 @@
 
 	/* Misc */
 	case DVD_INVALIDATE_AGID:
+		cgc.quiet = 1;
 		cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 
 		setup_report_key(&cgc, ai->lsa.agid, 0x3f);
 		if ((ret = cdo->generic_packet(cdi, &cgc)))
diff -Nru a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
--- a/drivers/char/acquirewdt.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/acquirewdt.c	Wed Apr  3 17:11:14 2002
@@ -17,6 +17,9 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *          Can't add timeout - driver doesn't allow changing value
  */
 
 #include <linux/config.h>
@@ -50,8 +53,14 @@
 #define WDT_STOP 0x43
 #define WDT_START 0x443
 
-#define WD_TIMO (100*60)		/* 1 minute */
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
  *	Kernel methods.
@@ -126,10 +135,13 @@
 				spin_unlock(&acq_lock);
 				return -EBUSY;
 			}
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
-	 
+
 			acq_is_open=1;
 			inb_p(WDT_START);      
 			spin_unlock(&acq_lock);
@@ -144,9 +156,9 @@
 	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 		spin_lock(&acq_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_STOP);
-#endif		
+		if (!nowayout) {
+			inb_p(WDT_STOP);
+		}
 		acq_is_open=0;
 		spin_unlock(&acq_lock);
 	}
diff -Nru a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
--- a/drivers/char/advantechwdt.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/advantechwdt.c	Wed Apr  3 17:11:15 2002
@@ -20,6 +20,9 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *          Added timeout module option to override default
  */
 
 #include <linux/config.h>
@@ -56,8 +59,7 @@
  *	the manual says WDT_STOP is 0x43, not 0x443).
  *	(0x43 is also a write-only control register for the 8254 timer!)
  *
- *	TODO: module parameters to set the I/O port addresses and NOWAYOUT
- *	option at load time.
+ *	TODO: module parameters to set the I/O port addresses
  */
  
 #define WDT_STOP 0x443
@@ -65,6 +67,19 @@
 
 #define WD_TIMO 60		/* 1 minute */
 
+static int timeout = WD_TIMO;	/* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)"); 
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Kernel methods.
  */
@@ -73,7 +88,7 @@
 advwdt_ping(void)
 {
 	/* Write a watchdog value */
-	outb_p(WD_TIMO, WDT_START);
+	outb_p(timeout, WDT_START);
 }
 
 static ssize_t
@@ -135,6 +150,9 @@
 				spin_unlock(&advwdt_lock);
 				return -EBUSY;
 			}
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
@@ -153,9 +171,9 @@
 {
 	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&advwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_STOP);
-#endif		
+		if (!nowayout) {
+			inb_p(WDT_STOP);
+		}
 		advwdt_is_open = 0;
 		spin_unlock(&advwdt_lock);
 	}
@@ -207,11 +225,21 @@
 	0
 };
 
+static void __init
+advwdt_validate_timeout(void)
+{
+	if (timeout < 1 || timeout > 63) {
+		timeout = WD_TIMO;
+		printk(KERN_INFO "advantechwdt: timeout value must be 1 <= x <= 63, using %d\n", timeout);
+	}
+}
+
 static int __init
 advwdt_init(void)
 {
 	printk("WDT driver for Advantech single board computer initialising.\n");
 
+	advwdt_validate_timeout();
 	spin_lock_init(&advwdt_lock);
 	misc_register(&advwdt_miscdev);
 #if WDT_START != WDT_STOP
diff -Nru a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
--- a/drivers/char/agp/agpgart_be.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/agp/agpgart_be.c	Wed Apr  3 17:11:14 2002
@@ -397,7 +397,7 @@
 static void agp_generic_agp_enable(u32 mode)
 {
 	struct pci_dev *device = NULL;
-	u32 command, scratch, cap_id;
+	u32 command, scratch; 
 	u8 cap_ptr;
 
 	pci_read_config_dword(agp_bridge.dev,
@@ -410,34 +410,8 @@
 	 */
 
 
-	pci_for_each_dev(device)
-	{
-		/*
-		 *	Enable AGP devices. Most will be VGA display but
-		 *	some may be coprocessors on non VGA devices too
-		 */
-		 
-		if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
-			(device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
-			continue;
-
-		pci_read_config_dword(device, 0x04, &scratch);
-
-		if (!(scratch & 0x00100000))
-			continue;
-
-		pci_read_config_byte(device, 0x34, &cap_ptr);
-
-		if (cap_ptr != 0x00) {
-			do {
-				pci_read_config_dword(device,
-						      cap_ptr, &cap_id);
-
-				if ((cap_id & 0xff) != 0x02)
-					cap_ptr = (cap_id >> 8) & 0xff;
-			}
-			while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
-		}
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
 		if (cap_ptr != 0x00) {
 			/*
 			 * Ok, here we have a AGP device. Disable impossible 
@@ -506,25 +480,8 @@
 	 *        command registers.
 	 */
 
-	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
-					device)) != NULL) {
-		pci_read_config_dword(device, 0x04, &scratch);
-
-		if (!(scratch & 0x00100000))
-			continue;
-
-		pci_read_config_byte(device, 0x34, &cap_ptr);
-
-		if (cap_ptr != 0x00) {
-			do {
-				pci_read_config_dword(device,
-						      cap_ptr, &cap_id);
-
-				if ((cap_id & 0xff) != 0x02)
-					cap_ptr = (cap_id >> 8) & 0xff;
-			}
-			while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
-		}
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
 		if (cap_ptr != 0x00)
 			pci_write_config_dword(device, cap_ptr + 8, command);
 	}
@@ -809,9 +766,9 @@
 	struct page * page;
 	
 	page = alloc_page(GFP_KERNEL);
-	if (page == NULL) {
+	if (page == NULL)
 		return 0;
-	}
+
 	get_page(page);
 	LockPage(page);
 	atomic_inc(&agp_bridge.current_memory_agp);
@@ -823,10 +780,9 @@
 	void *pt = (void *) addr;
 	struct page *page;
 
-	if (pt == NULL) {
+	if (pt == NULL)
 		return;
-	}
-	
+
 	page = virt_to_page(pt);
 	put_page(page);
 	UnlockPage(page);
@@ -3318,24 +3274,8 @@
 	 */
 
 
-	pci_for_each_dev(device)
-	{
-		/*
-		 *	Enable AGP devices. Most will be VGA display but
-		 *	some may be coprocessors on non VGA devices too
-		 */
-		 
-		if((((device->class >> 16) & 0xFF) != PCI_BASE_CLASS_DISPLAY) &&
-			(device->class != (PCI_CLASS_PROCESSOR_CO << 8)))
-			continue;
-
-		pci_read_config_dword(device, 0x04, &scratch);
-
-		if (!(scratch & 0x00100000))
-			continue;
-
-		pci_read_config_byte(device, 0x34, &cap_ptr);
-
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
 		if (cap_ptr != 0x00) {
 			do {
 				pci_read_config_dword(device,
@@ -3413,25 +3353,8 @@
 	 *        command registers.
 	 */
 
-	while ((device = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8,
-					device)) != NULL) {
-		pci_read_config_dword(device, 0x04, &scratch);
-
-		if (!(scratch & 0x00100000))
-			continue;
-
-		pci_read_config_byte(device, 0x34, &cap_ptr);
-
-		if (cap_ptr != 0x00) {
-			do {
-				pci_read_config_dword(device,
-						      cap_ptr, &cap_id);
-
-				if ((cap_id & 0xff) != 0x02)
-					cap_ptr = (cap_id >> 8) & 0xff;
-			}
-			while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
-		}
+	pci_for_each_dev(device) {
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
 		if (cap_ptr != 0x00)
 			pci_write_config_dword(device, cap_ptr + 8, command);
 	}
@@ -3881,7 +3804,6 @@
 {
 	struct pci_dev *dev = NULL;
 	u8 cap_ptr = 0x00;
-	u32 cap_id, scratch;
 
 	if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) == NULL)
 		return -ENODEV;
@@ -4022,20 +3944,7 @@
 #endif	/* CONFIG_AGP_SWORKS */
 
 	/* find capndx */
-	pci_read_config_dword(dev, 0x04, &scratch);
-	if (!(scratch & 0x00100000))
-		return -ENODEV;
-
-	pci_read_config_byte(dev, 0x34, &cap_ptr);
-	if (cap_ptr != 0x00) {
-		do {
-			pci_read_config_dword(dev, cap_ptr, &cap_id);
-
-			if ((cap_id & 0xff) != 0x02)
-				cap_ptr = (cap_id >> 8) & 0xff;
-		}
-		while (((cap_id & 0xff) != 0x02) && (cap_ptr != 0x00));
-	}
+	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
 	if (cap_ptr == 0x00)
 		return -ENODEV;
 	agp_bridge.capndx = cap_ptr;
diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c
--- a/drivers/char/applicom.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/char/applicom.c	Wed Apr  3 17:11:16 2002
@@ -36,7 +36,7 @@
 
 #if LINUX_VERSION_CODE < 0x20300 
 /* These probably want adding to <linux/compatmac.h> */
-#define init_waitqueue_head(x) do { *(x) = NULL; } while (0);
+#define init_waitqueue_head(x) do { *(x) = NULL; } while (0)
 #define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
 #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x
 #define __setup(x,y) /* */
diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/cyclades.c	Wed Apr  3 17:11:14 2002
@@ -4965,6 +4965,8 @@
   uclong		Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0;
   uclong		Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
   unsigned char         Ze_irq[NR_CARDS];
+  struct resource *resource;
+  unsigned long res_start, res_len;
 
         for (i = 0; i < NR_CARDS; i++) {
                 /* look for a Cyclades card by vendor and device id */
@@ -5012,7 +5014,15 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
+		resource = request_region(cy_pci_phys1,
+					CyPCI_Yctl, "Cyclom-Y");
+		if (resource == NULL) {
+			printk(KERN_ERR "cyclades: failed to allocate IO "
+					"resource at 0x%lx\n", cy_pci_phys1);
+			continue;
+		}
+		res_start = cy_pci_phys1;
+		res_len = CyPCI_Yctl;
 
 #if defined(__alpha__)
                 if (device_id  == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
@@ -5083,7 +5093,11 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = cy_pci_nchan/4;
-
+		cy_card[j].resource = resource;
+		cy_card[j].res_start = res_start;
+		cy_card[j].res_len = res_len;
+		resource = NULL;	/* For next card */
+	
                 /* enable interrupts in the PCI interface */
 		plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
 		switch (plx_ver) {
@@ -5162,8 +5176,16 @@
 		/* Although we don't use this I/O region, we should
 		   request it from the kernel anyway, to avoid problems
 		   with other drivers accessing it. */
-		request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
-
+		resource = request_region(cy_pci_phys1,
+				CyPCI_Zctl, "Cyclades-Z");
+		if (resource == NULL) {
+			printk(KERN_ERR "cyclades: failed ot allocate IO resource "
+					"at 0x%lx\n", cy_pci_phys1);
+			continue;
+		}
+		res_start = cy_pci_phys1;
+		res_len = CyPCI_Zctl;
+	
 		if (mailbox == ZE_V1) {
 		    cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
 		    if (ZeIndex == NR_CARDS) {
@@ -5261,6 +5283,10 @@
                 cy_card[j].bus_index = 1;
                 cy_card[j].first_line = cy_next_channel;
                 cy_card[j].num_chips = -1;
+		cy_card[j].resource = resource;
+		cy_card[j].res_start = res_start;
+		cy_card[j].res_len = res_len;
+		resource = NULL;	/* For next card */
 
                 /* print message */
 #ifdef CONFIG_CYZ_INTR
@@ -5279,7 +5305,7 @@
                 printk("%d channels starting from port %d.\n",
 		    cy_pci_nchan,cy_next_channel);
                 cy_next_channel += cy_pci_nchan;
-    }
+	    }
         }
 
         for (; ZeIndex != 0 && i < NR_CARDS; i++) {
@@ -5787,6 +5813,8 @@
 #endif /* CONFIG_CYZ_INTR */
 	    )
 		free_irq(cy_card[i].irq, &cy_card[i]);
+		if (cy_card[i].resource)
+			release_region(cy_card[i].res_start, cy_card[i].res_len);
         }
     }
     if (tmp_buf) {
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/drm/i810_dma.c	Wed Apr  3 17:11:15 2002
@@ -73,7 +73,7 @@
 	*(volatile unsigned int *)(virt + outring) = n;			\
 	outring += 4;							\
 	outring &= ringmask;						\
-} while (0);
+} while (0)
 
 static inline void i810_print_status_page(drm_device_t *dev)
 {
diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c
--- a/drivers/char/esp.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/char/esp.c	Wed Apr  3 17:11:13 2002
@@ -2161,7 +2161,7 @@
 		if (signal_pending(current))
 			break;
 
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 
 		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
diff -Nru a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c
--- a/drivers/char/eurotechwdt.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/eurotechwdt.c	Wed Apr  3 17:11:14 2002
@@ -20,6 +20,10 @@
  *      "AS-IS" and at no charge.
  *
  *      (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>*
+ *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *          Added timeout module option to override default
  */
 
 #include <linux/config.h>
@@ -45,7 +49,6 @@
 #include <linux/smp_lock.h>
 
 static int eurwdt_is_open;
-static int eurwdt_timeout; 
 static spinlock_t eurwdt_lock;
  
 /*
@@ -58,6 +61,18 @@
 static char *ev = "int";
  
 #define WDT_TIMEOUT		60                /* 1 minute */
+static int timeout = WDT_TIMEOUT;
+
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Eurotech WDT timeout in seconds (default=60)"); 
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 
 /*
@@ -116,6 +131,15 @@
  *      Programming support
  */
 
+static void __init eurwdt_validate_timeout(void)
+{
+	if (timeout < 0 || timeout > 255) {
+		timeout = WDT_TIMEOUT;
+		printk(KERN_INFO "eurwdt: timeout must be 0 < x < 255, using %d\n",
+		       timeout);
+	}
+}
+
 static inline void eurwdt_write_reg(u8 index, u8 data)
 {
    outb(index, io);
@@ -189,7 +213,7 @@
 static void eurwdt_ping(void)
 {
    /* Write the watchdog default value */
-   eurwdt_set_timeout(eurwdt_timeout);
+   eurwdt_set_timeout(timeout);
 }
  
 /**
@@ -263,7 +287,7 @@
          if (time < 0 || time > 255)
             return -EINVAL;
 
-         eurwdt_timeout = time; 
+         timeout = time; 
          eurwdt_set_timeout(time); 
          return 0;
    }
@@ -287,9 +311,11 @@
             spin_unlock(&eurwdt_lock);
             return -EBUSY;
          }
+	 if (nowayout) {
+		 MOD_INC_USE_COUNT;
+	 }
 
          eurwdt_is_open = 1;
-         eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
 
          /* Activate the WDT */
          eurwdt_activate_timer(); 
@@ -323,12 +349,12 @@
 static int eurwdt_release(struct inode *inode, struct file *file)
 {
    if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-      eurwdt_disable_timer();
-#endif
-      eurwdt_is_open = 0;
+	   if (!nowayout) {
+		   eurwdt_disable_timer();
+	   }
+	   eurwdt_is_open = 0;
 
-      MOD_DEC_USE_COUNT;
+	   MOD_DEC_USE_COUNT;
    }
 
    return 0;
@@ -422,7 +448,8 @@
 static int __init eurwdt_init(void)
 {
    int ret;
- 
+
+   eurwdt_validate_timeout();
    ret = misc_register(&eurwdt_miscdev);
    if (ret) {
       printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
diff -Nru a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
--- a/drivers/char/i810-tco.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/char/i810-tco.c	Wed Apr  3 17:11:13 2002
@@ -1,5 +1,5 @@
 /*
- *	i810-tco 0.02:	TCO timer driver for i810 chipsets
+ *	i810-tco 0.03:	TCO timer driver for i810 chipsets
  *
  *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
  *				http://www.kernelconcepts.de
@@ -28,6 +28,9 @@
  *	Initial Version 0.01
  *  20000728 Nils Faerber
  *      0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ *  20011214 Matt Domsch <Matt_Domsch@dell.com>
+ *      0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *           Didn't add timeout option as i810_margin already exists.
  */
  
 #include <linux/module.h>
@@ -60,6 +63,18 @@
 static int i810_margin = TIMER_MARGIN;	/* steps of 0.6sec */
 
 MODULE_PARM (i810_margin, "i");
+MODULE_PARM_DESC(i810_margin, "Watchdog timeout in steps of 0.6sec, 2<n<64. Default = 50 (30 seconds)");
+
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 
 /*
  *	Timer active flag
@@ -167,6 +182,9 @@
 	if (timer_alive)
 		return -EBUSY;
 
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *      Reload and activate timer
 	 */
@@ -181,10 +199,10 @@
 	/*
 	 *      Shut off the timer.
 	 */
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	tco_timer_stop ();
-	timer_alive = 0;
-#endif	
+	if (nowayout) {
+		tco_timer_stop ();
+		timer_alive = 0;
+	}
 	return 0;
 }
 
@@ -342,8 +360,8 @@
 	tco_timer_reload ();
 
 	printk (KERN_INFO
-		"i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
-		(int) (i810_margin * 6 / 10), TCOBASE);
+		"i810 TCO timer: V0.03, timer margin: %d sec (0x%04x), nowayout: %d\n",
+		(int) (i810_margin * 6 / 10), TCOBASE, nowayout);
 	return 0;
 }
 
diff -Nru a/drivers/char/ib700wdt.c b/drivers/char/ib700wdt.c
--- a/drivers/char/ib700wdt.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/ib700wdt.c	Wed Apr  3 17:11:15 2002
@@ -25,6 +25,10 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *           Added timeout module option to override default
+ * 
  */
 
 #include <linux/config.h>
@@ -92,15 +96,36 @@
 
 #define WD_TIMO 0		/* 30 seconds +/- 20%, from table */
 
+static int timeout_val = WD_TIMO;	/* value in table */
+static int timeout = 30;	        /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, 0 < n < 30, must be even (default=30)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Kernel methods.
  */
 
+static void __init
+ibwdt_validate_timeout(void)
+{
+	timeout_val = (30 - timeout) / 2;
+	if (timeout_val < 0 || timeout_val > 0xF) timeout_val = WD_TIMO;
+}
+
 static void
 ibwdt_ping(void)
 {
 	/* Write a watchdog value */
-	outb_p(WD_TIMO, WDT_START);
+	outb_p(timeout_val, WDT_START);
 }
 
 static ssize_t
@@ -162,6 +187,9 @@
 				spin_unlock(&ibwdt_lock);
 				return -EBUSY;
 			}
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate
 			 */
@@ -181,9 +209,9 @@
 	lock_kernel();
 	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&ibwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		outb_p(WD_TIMO, WDT_STOP);
-#endif
+		if (!nowayout) {
+			outb_p(timeout_val, WDT_STOP);
+		}
 		ibwdt_is_open = 0;
 		spin_unlock(&ibwdt_lock);
 	}
@@ -201,7 +229,7 @@
 {
 	if (code == SYS_DOWN || code == SYS_HALT) {
 		/* Turn the WDT off */
-		outb_p(WD_TIMO, WDT_STOP);
+		outb_p(timeout_val, WDT_STOP);
 	}
 	return NOTIFY_DONE;
 }
@@ -241,6 +269,7 @@
 {
 	printk("WDT driver for IB700 single board computer initialising.\n");
 
+	ibwdt_validate_timeout();
 	spin_lock_init(&ibwdt_lock);
 	misc_register(&ibwdt_miscdev);
 #if WDT_START != WDT_STOP
diff -Nru a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
--- a/drivers/char/ip2/i2lib.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/ip2/i2lib.c	Wed Apr  3 17:11:15 2002
@@ -1330,7 +1330,7 @@
 
 	// if expires == 0 then timer poped, then do not need to del_timer
 	if ((timeout > 0) && pCh->BookmarkTimer.expires && 
-				(pCh->BookmarkTimer.expires > jiffies)) {
+	                     time_before(jiffies, pCh->BookmarkTimer.expires)) {
 		del_timer( &(pCh->BookmarkTimer) );
 		pCh->BookmarkTimer.expires = 0;
 
diff -Nru a/drivers/char/machzwd.c b/drivers/char/machzwd.c
--- a/drivers/char/machzwd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/machzwd.c	Wed Apr  3 17:11:14 2002
@@ -24,6 +24,8 @@
  *  a system RESET and it starts wd#2 that unconditionaly will RESET 
  *  the system when the counter reaches zero.
  *
+ *  14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *      Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
@@ -103,6 +105,15 @@
 MODULE_PARM(action, "i");
 MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 #define PFX "machzwd"
 
 static struct watchdog_info zf_info = {
@@ -307,23 +318,23 @@
  * no need to check for close confirmation
  * no way to disable watchdog ;)
  */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t ofs;
-
-		/* 
-		 * note: just in case someone wrote the magic character
-		 * five months ago...
-		 */
-		zf_expect_close = 0;
-
-		/* now scan */
-		for(ofs = 0; ofs != count; ofs++){
-			if(buf[ofs] == 'V'){
-				zf_expect_close = 1;
-				dprintk("zf_expect_close 1\n");
+		if (!nowayout) {
+			size_t ofs;
+			
+			/* 
+			 * note: just in case someone wrote the magic character
+			 * five months ago...
+			 */
+			zf_expect_close = 0;
+			
+			/* now scan */
+			for(ofs = 0; ofs != count; ofs++){
+				if(buf[ofs] == 'V'){
+					zf_expect_close = 1;
+					dprintk("zf_expect_close 1\n");
+				}
 			}
 		}
-#endif
 		/*
 		 * Well, anyhow someone wrote to us,
 		 * we should return that favour
@@ -386,9 +397,9 @@
 				return -EBUSY;
 			}
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			zf_is_open = 1;
 
 			spin_unlock(&zf_lock);
diff -Nru a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
--- a/drivers/char/mixcomwd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/mixcomwd.c	Wed Apr  3 17:11:14 2002
@@ -27,10 +27,13 @@
  *
  * Version 0.4 (99/11/15):
  *		- support for one more type board
+ *
+ * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
+ *              - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  *	
  */
 
-#define VERSION "0.4" 
+#define VERSION "0.5" 
   
 #include <linux/module.h>
 #include <linux/config.h>
@@ -57,26 +60,30 @@
 static long mixcomwd_opened; /* long req'd for setbit --RR */
 
 static int watchdog_port;
-
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static int mixcomwd_timer_alive;
 static struct timer_list mixcomwd_timer;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
 #endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static void mixcomwd_ping(void)
 {
 	outb_p(55,watchdog_port);
 	return;
 }
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static void mixcomwd_timerfun(unsigned long d)
 {
 	mixcomwd_ping();
 	
 	mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
 }
-#endif
 
 /*
  *	Allow only one person to hold it open
@@ -89,31 +96,32 @@
 	}
 	mixcomwd_ping();
 	
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		del_timer(&mixcomwd_timer);
-		mixcomwd_timer_alive=0;
-	} 
-#endif
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	} else {
+		if(mixcomwd_timer_alive) {
+			del_timer(&mixcomwd_timer);
+			mixcomwd_timer_alive=0;
+		}
+	}
 	return 0;
 }
 
 static int mixcomwd_release(struct inode *inode, struct file *file)
 {
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_ERR "mixcomwd: release called while internal timer alive");
-		return -EBUSY;
+	if (!nowayout) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+			return -EBUSY;
+		}
+		init_timer(&mixcomwd_timer);
+		mixcomwd_timer.expires=jiffies + 5 * HZ;
+		mixcomwd_timer.function=mixcomwd_timerfun;
+		mixcomwd_timer.data=0;
+		mixcomwd_timer_alive=1;
+		add_timer(&mixcomwd_timer);
 	}
-	init_timer(&mixcomwd_timer);
-	mixcomwd_timer.expires=jiffies + 5 * HZ;
-	mixcomwd_timer.function=mixcomwd_timerfun;
-	mixcomwd_timer.data=0;
-	mixcomwd_timer_alive=1;
-	add_timer(&mixcomwd_timer);
-#endif
-
 	clear_bit(0,&mixcomwd_opened);
 	return 0;
 }
@@ -145,9 +153,9 @@
 	{
 		case WDIOC_GETSTATUS:
 			status=mixcomwd_opened;
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-			status|=mixcomwd_timer_alive;
-#endif
+			if (!nowayout) {
+				status|=mixcomwd_timer_alive;
+			}
 			if (copy_to_user((int *)arg, &status, sizeof(int))) {
 				return -EFAULT;
 			}
@@ -252,14 +260,14 @@
 
 static void __exit mixcomwd_exit(void)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
-			" probably reboot!\n");
-		del_timer(&mixcomwd_timer);
-		mixcomwd_timer_alive=0;
+	if (!nowayout) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+			       " probably reboot!\n");
+			del_timer(&mixcomwd_timer);
+			mixcomwd_timer_alive=0;
+		}
 	}
-#endif
 	release_region(watchdog_port,1);
 	misc_deregister(&mixcomwd_miscdev);
 }
diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/mxser.c	Wed Apr  3 17:11:15 2002
@@ -32,6 +32,9 @@
  *      version         : 1.2 
  *      
  *    Fixes for C104H/PCI by Tim Hockin <thockin@sun.com>
+ *    Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards
+ *                        by Damian Wrobel <dwrobel@ertel.com.pl>
+ *
  */
 
 #include <linux/config.h>
@@ -61,7 +64,7 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
-#define		MXSER_VERSION			"1.2"
+#define		MXSER_VERSION			"1.2.1"
 
 #define		MXSERMAJOR	 	174
 #define		MXSERCUMAJOR		175
@@ -114,10 +117,22 @@
 #ifndef PCI_DEVICE_ID_C104
 #define PCI_DEVICE_ID_C104	0x1040
 #endif
+#ifndef PCI_DEVICE_ID_CP132
+#define PCI_DEVICE_ID_CP132	0x1320
+#endif
+#ifndef PCI_DEVICE_ID_CP114
+#define PCI_DEVICE_ID_CP114	0x1141
+#endif
+#ifndef PCI_DEVICE_ID_CT114
+#define PCI_DEVICE_ID_CT114	0x1140
+#endif
 
 #define C168_ASIC_ID    1
 #define C104_ASIC_ID    2
+#define CI134_ASIC_ID   3
+#define CI132_ASIC_ID   4
 #define CI104J_ASIC_ID  5
+#define C102_ASIC_ID	0xB
 
 enum {
 	MXSER_BOARD_C168_ISA = 0,
@@ -125,6 +140,12 @@
 	MXSER_BOARD_CI104J,
 	MXSER_BOARD_C168_PCI,
 	MXSER_BOARD_C104_PCI,
+	MXSER_BOARD_C102_ISA,
+	MXSER_BOARD_CI132,
+	MXSER_BOARD_CI134,
+	MXSER_BOARD_CP132_PCI,
+	MXSER_BOARD_CP114_PCI,
+	MXSER_BOARD_CT114_PCI
 };
 
 static char *mxser_brdname[] =
@@ -134,6 +155,12 @@
 	"CI-104J series",
 	"C168H/PCI series",
 	"C104H/PCI series",
+	"C102 series",
+	"CI-132 series",
+	"CI-134 series",
+	"CP-132 series",
+	"CP-114 series",
+	"CT-114 series"
 };
 
 static int mxser_numports[] =
@@ -143,6 +170,12 @@
 	4,
 	8,
 	4,
+	2,
+	2,
+	4,
+	2,
+	4,
+	4
 };
 
 /*
@@ -163,6 +196,12 @@
 	  MXSER_BOARD_C168_PCI },
 	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
 	  MXSER_BOARD_C104_PCI },
+	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  MXSER_BOARD_CP132_PCI },
+	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  MXSER_BOARD_CP114_PCI },
+	{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CT114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  MXSER_BOARD_CT114_PCI },
 	{ 0 }
 };
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -613,38 +652,35 @@
 		n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
 		index = 0;
 		for (b = 0; b < n; b++) {
-			pdev = pci_find_device(mxser_pcibrds[b].vendor,
-					       mxser_pcibrds[b].device, pdev);
-			if (!pdev || pci_enable_device(pdev))
-				continue;
-			hwconf.pdev = pdev;
-			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
-				mxser_brdname[mxser_pcibrds[b].driver_data],
-				pdev->bus->number, PCI_SLOT(pdev->devfn));
-			if (m >= MXSER_BOARDS) {
-				printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
-			} else {
-				retval = mxser_get_PCI_conf(pdev,
-				   mxser_pcibrds[b].driver_data, &hwconf);
-				if (retval < 0) {
-					if (retval == MXSER_ERR_IRQ)
-						printk("Invalid interrupt number,board not configured\n");
-					else if (retval == MXSER_ERR_IRQ_CONFLIT)
-						printk("Invalid interrupt number,board not configured\n");
-					else if (retval == MXSER_ERR_VECTOR)
-						printk("Invalid interrupt vector,board not configured\n");
-					else if (retval == MXSER_ERR_IOADDR)
-						printk("Invalid I/O address,board not configured\n");
+			while (pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)) 
+			{
+				if (pci_enable_device(pdev))
 					continue;
-
+				hwconf.pdev = pdev;
+				printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+					mxser_brdname[mxser_pcibrds[b].driver_data],
+				pdev->bus->number, PCI_SLOT(pdev->devfn));
+				if (m >= MXSER_BOARDS) {
+					printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
+				} else {
+					retval = mxser_get_PCI_conf(pdev, mxser_pcibrds[b].driver_data, &hwconf);
+					if (retval < 0) {
+						if (retval == MXSER_ERR_IRQ)
+							printk("Invalid interrupt number,board not configured\n");
+						else if (retval == MXSER_ERR_IRQ_CONFLIT)
+							printk("Invalid interrupt number,board not configured\n");	
+						else if (retval == MXSER_ERR_VECTOR)
+							printk("Invalid interrupt vector,board not configured\n");
+						else if (retval == MXSER_ERR_IOADDR)
+							printk("Invalid I/O address,board not configured\n");
+						continue;
+					}
+					if (mxser_initbrd(m, &hwconf) < 0)
+						continue;
+					mxser_getcfg(m, &hwconf);
+					m++;
 				}
-				if (mxser_initbrd(m, &hwconf) < 0)
-					continue;
-				mxser_getcfg(m, &hwconf);
-				m++;
-
 			}
-
 		}
 	}
 #endif
@@ -2306,6 +2342,12 @@
 		hwconf->board_type = MXSER_BOARD_C168_ISA;
 	else if (id == C104_ASIC_ID)
 		hwconf->board_type = MXSER_BOARD_C104_ISA;
+	else if (id == C102_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_C102_ISA;
+	else if (id == CI132_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_CI132;
+	else if (id == CI134_ASIC_ID)
+		hwconf->board_type = MXSER_BOARD_CI134;
 	else if (id == CI104J_ASIC_ID)
 		hwconf->board_type = MXSER_BOARD_CI104J;
 	else
@@ -2417,7 +2459,8 @@
 	(void) inb(port);
 	restore_flags(flags);
 	id = inb(port + 1) & 0x1F;
-	if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID))
+	if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != CI104J_ASIC_ID) &&
+		(id != C102_ASIC_ID) &&	(id != CI132_ASIC_ID) && (id != CI134_ASIC_ID))
 		return (-1);
 	for (i = 0, j = 0; i < 4; i++) {
 		n = inb(port + 2);
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/raw.c	Wed Apr  3 17:11:14 2002
@@ -322,7 +322,7 @@
 		if (err)
 			break;
 
-		err = brw_kiovec(rw, 1, &iobuf, dev, &blocknr, sector_size);
+		err = brw_kiovec(rw, 1, &iobuf, raw_devices[minor].binding, &blocknr, sector_size);
 
 		if (rw == READ && err > 0)
 			mark_dirty_kiobuf(iobuf, err);
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/rocket.c	Wed Apr  3 17:11:14 2002
@@ -42,10 +42,6 @@
 #include <linux/config.h>
 #include <linux/version.h>
 
-#ifdef CONFIG_PCI
-#define ENABLE_PCI
-#endif
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/major.h>
@@ -63,15 +59,8 @@
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
-#ifdef ENABLE_PCI
 #include <linux/pci.h>
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-#include <linux/bios32.h>
-#endif
-#endif
-#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
 #include <linux/init.h>
-#endif
 	
 #include "rocket_int.h"
 #ifdef LOCAL_ROCKET_H
@@ -154,7 +143,6 @@
 static unsigned long time_counter;
 #endif
 
-#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
 MODULE_AUTHOR("Theodore Ts'o");
 MODULE_DESCRIPTION("Comtrol Rocketport driver");
 MODULE_LICENSE("GPL");
@@ -170,39 +158,8 @@
 MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
 MODULE_PARM(support_low_speed, "i");
 MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");	
-#endif
-
-#if (LINUX_VERSION_CODE < 131336)
-int copy_from_user(void *to, const void *from_user, unsigned long len)
-{
-	int	error;
-
-	error = verify_area(VERIFY_READ, from_user, len);
-	if (error)
-		return len;
-	memcpy_fromfs(to, from_user, len);
-	return 0;
-}
-
-int copy_to_user(void *to_user, const void *from, unsigned long len)
-{
-	int	error;
-	
-	error = verify_area(VERIFY_WRITE, to_user, len);
-	if (error)
-		return len;
-	memcpy_tofs(to_user, from, len);
-	return 0;
-}
-
-static inline int signal_pending(struct task_struct *p)
-{
-	return (p->signal & ~p->blocked) != 0;
-}
 
-#else
 #include <asm/uaccess.h>
-#endif
 
 /*
  * tmp_buf is used as a temporary buffer by rp_write.  We need to
@@ -497,7 +454,7 @@
 			continue;
 		ctlp= sCtlNumToCtlPtr(ctrl);
 
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
 		if(ctlp->BusType == isPCI)
 			CtlMask= sPCIGetControllerIntStatus(ctlp);
 		else
@@ -611,12 +568,6 @@
 	rp_table[line] = info;
 }
 
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300,
-	600, 1200, 1800, 2400, 4800, 9600, 19200,
-	38400, 57600, 115200, 230400, 460800, 0 };
-#endif
 
 /*
  * This routine configures a rocketport port so according to its
@@ -627,9 +578,6 @@
 	unsigned cflag;
 	unsigned long 	flags;
 	int	bits, baud;
-#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */
-	int i;
-#endif
 	CHANNEL_t	*cp;
 	
 	if (!info->tty || !info->tty->termios)
@@ -665,31 +613,9 @@
 	}
 	
 	/* baud rate */
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 4) 
-			info->tty->termios->c_cflag &= ~CBAUDEX;
-		else
-			i += 15;
-	}
-	if (i == 15) {
-		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
-			i += 1;
-		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
-			i += 2;
-		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)
-			i += 3;
-		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
-			i += 4;
-	}
-	baud = baud_table[i] ? baud_table[i] : 9600;
-#else
 	baud = tty_get_baud_rate(info->tty);
 	if (!baud)
 		baud = 9600;
-#endif
 	info->cps = baud / bits;
 	sSetBaud(cp, (rp_baud_base/baud) - 1);
 	
@@ -990,7 +916,6 @@
 
 	info->flags |= ROCKET_INITIALIZED;
 
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
@@ -1002,7 +927,6 @@
 		info->tty->alt_speed = 230400;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
 		info->tty->alt_speed = 460800;
-#endif
 
 	configure_r_port(info);
 	if (tty->termios->c_cflag & CBAUD) {
@@ -1094,10 +1018,8 @@
 	 * If transmission was throttled by the application request,
 	 * just flush the xmit buffer.
 	 */
-#if (LINUX_VERSION_CODE >= 131343)
 	if (tty->flow_stopped)
 		rp_flush_buffer(tty);
-#endif
 
 	/*
 	 * Wait for the transmit buffer to clear
@@ -1218,17 +1140,6 @@
 /*
  * Here are the routines used by rp_ioctl
  */
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-static void send_break(	struct r_port * info, int duration)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	cli();
-	sSendBreak(&info->channel);
-	schedule_timeout(duration);
-	sClrBreak(&info->channel);
-	sti();
-}
-#else
 static void rp_break(struct tty_struct *tty, int break_state)
 {
 	struct r_port * info = (struct r_port *)tty->driver_data;
@@ -1245,7 +1156,6 @@
 	}
 	restore_flags(flags);
 }
-#endif
 
 static int get_modem_info(struct r_port * info, unsigned int *value)
 {
@@ -1348,7 +1258,6 @@
 	info->close_delay = new_serial.close_delay;
 	info->closing_wait = new_serial.closing_wait;
 
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)
 		info->tty->alt_speed = 57600;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)
@@ -1357,7 +1266,6 @@
 		info->tty->alt_speed = 230400;
 	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)
 		info->tty->alt_speed = 460800;
-#endif
 	
 	configure_r_port(info);
 	return 0;
@@ -1389,54 +1297,13 @@
 		    unsigned int cmd, unsigned long arg)
 {
 	struct r_port * info = (struct r_port *)tty->driver_data;
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-	int retval, tmp;
-#endif
 
 	if (cmd != RCKP_GET_PORTS &&
 	    rocket_paranoia_check(info, tty->device, "rp_ioctl"))
 		return -ENODEV;
 
 	switch (cmd) {
-#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
-		case TCSBRK:	/* SVID version: non-zero arg --> no break */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-			if (!arg) {
-				send_break(info, HZ/4);	/* 1/4 second */
-				if (signal_pending(current))
-					return -EINTR;
-			}
-			return 0;
-		case TCSBRKP:	/* support for POSIX tcsendbreak() */
-			retval = tty_check_change(tty);
-			if (retval)
-				return retval;
-			tty_wait_until_sent(tty, 0);
-			if (signal_pending(current))
-				return -EINTR;
-			send_break(info, arg ? arg*(HZ/10) : HZ/4);
-			if (signal_pending(current))
-				return -EINTR;
-			return 0;
-		case TIOCGSOFTCAR:
-			tmp = C_CLOCAL(tty) ? 1 : 0;
-			if (copy_to_user((void *)arg, &tmp, sizeof(int)))
-				return -EFAULT;
-			return 0;
-		case TIOCSSOFTCAR:
-			if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
-				return -EFAULT;
 
-			tty->termios->c_cflag =
-				((tty->termios->c_cflag & ~CLOCAL) |
-				 (tmp ? CLOCAL : 0));
-			return 0;
-#endif
 		case TIOCMGET:
 			return get_modem_info(info, (unsigned int *) arg);
 		case TIOCMBIS:
@@ -1877,36 +1744,7 @@
 	sFlushTxFIFO(cp);
 }
 
-#ifdef ENABLE_PCI
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-/* For compatibility */
-static struct pci_dev *pci_find_slot(unsigned char bus,
-				     unsigned char device_fn)
-{
-	unsigned short		vendor_id, device_id;
-	int			ret, error;
-	static struct pci_dev	ret_struct;
-	
-	error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
-		&vendor_id);
-	ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
-		&device_id);
-	if (error == 0)
-		error = ret;
-
-	if (error) {
-		printk("PCI RocketPort error: %s not initializing due to error"
-		       "reading configuration space\n",
-		       pcibios_strerror(error));
-		return(0);
-	}
-
-	memset(&ret_struct, 0, sizeof(ret_struct));
-	ret_struct.device = device_id;
-
-	return &ret_struct;
-}
-#endif
+#ifdef CONFIG_PCI
      
 int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
 {
@@ -1915,10 +1753,6 @@
 	char *str;
 	CONTROLLER_t	*ctlp;
 	struct pci_dev *dev = pci_find_slot(bus, device_fn);
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
-	int	ret;
-	unsigned int port;
-#endif
 
 	if (!dev)
 		return 0;
@@ -2161,7 +1995,7 @@
 		if(init_ISA(i, &reserved_controller))
 			isa_boards_found++;
 	}
-#ifdef ENABLE_PCI
+#ifdef CONFIG_PCI
 	if (pcibios_present()) {
 		if(isa_boards_found < NUM_BOARDS)
 			pci_boards_found = init_PCI(isa_boards_found);
@@ -2219,13 +2053,9 @@
 	rocket_driver.stop = rp_stop;
 	rocket_driver.start = rp_start;
 	rocket_driver.hangup = rp_hangup;
-#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 	rocket_driver.break_ctl = rp_break;
-#endif
-#if (LINUX_VERSION_CODE >= 131343)
 	rocket_driver.send_xchar = rp_send_xchar;
 	rocket_driver.wait_until_sent = rp_wait_until_sent;
-#endif
 
 	/*
 	 * The callout device is just like normal device except for
diff -Nru a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
--- a/drivers/char/sbc60xxwdt.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/sbc60xxwdt.c	Wed Apr  3 17:11:14 2002
@@ -109,6 +109,15 @@
 static int wdt_is_open;
 static int wdt_expect_close;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Whack the dog
  */
@@ -202,6 +211,9 @@
 			/* Just in case we're already talking to someone... */
 			if(wdt_is_open)
 				return -EBUSY;
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/* Good, fire up the show */
 			wdt_is_open = 1;
 			wdt_startup();
@@ -216,7 +228,7 @@
 {
 	if(minor(inode->i_rdev) == WATCHDOG_MINOR) 
 	{
-		if(wdt_expect_close)
+		if(wdt_expect_close && !nowayout)
 			wdt_turnoff();
 		else {
 			del_timer(&timer);
diff -Nru a/drivers/char/shwdt.c b/drivers/char/shwdt.c
--- a/drivers/char/shwdt.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/shwdt.c	Wed Apr  3 17:11:14 2002
@@ -9,6 +9,9 @@
  * 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.
+ *
+ * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *     Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -88,6 +91,15 @@
 static struct timer_list timer;
 static unsigned long next_heartbeat;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /**
  *	sh_wdt_write_cnt - Write to Counter
  *
@@ -175,6 +187,10 @@
 			if (test_and_set_bit(0, &sh_is_open))
 				return -EBUSY;
 
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
+
 			sh_wdt_start();
 
 			break;
@@ -196,9 +212,9 @@
 static int sh_wdt_close(struct inode *inode, struct file *file)
 {
 	if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		sh_wdt_stop();
-#endif
+		if (!nowayout) {
+			sh_wdt_stop();
+		}
 		clear_bit(0, &sh_is_open);
 	}
 	
diff -Nru a/drivers/char/softdog.c b/drivers/char/softdog.c
--- a/drivers/char/softdog.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/softdog.c	Wed Apr  3 17:11:15 2002
@@ -1,5 +1,5 @@
 /*
- *	SoftDog	0.05:	A Software Watchdog Device
+ *	SoftDog	0.06:	A Software Watchdog Device
  *
  *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
  *				http://www.redhat.com
@@ -26,6 +26,10 @@
  *
  *  19980911 Alan Cox
  *	Made SMP safe for 2.3.x
+ *
+ *  20011214 Matt Domsch <Matt_Domsch@dell.com>
+ *      Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *      Didn't add timeout option, as soft_margin option already exists.
  */
  
 #include <linux/module.h>
@@ -46,6 +50,15 @@
 static int soft_margin = TIMER_MARGIN;	/* in seconds */
 
 MODULE_PARM(soft_margin,"i");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 MODULE_LICENSE("GPL");
 
 /*
@@ -83,9 +96,9 @@
 {
 	if(timer_alive)
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	 
-	MOD_INC_USE_COUNT;
-#endif	
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *	Activate timer
 	 */
@@ -98,11 +111,11 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	 
-	del_timer(&watchdog_ticktock);
-#endif	
+	if(!nowayout) {
+		del_timer(&watchdog_ticktock);
+	}
 	timer_alive=0;
 	return 0;
 }
@@ -159,7 +172,7 @@
 	fops:		&softdog_fops,
 };
 
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.05, timer margin: %d sec\n";
+static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n";
 
 static int __init watchdog_init(void)
 {
@@ -170,7 +183,7 @@
 	if (ret)
 		return ret;
 
-	printk(banner, soft_margin);
+	printk(banner, soft_margin, nowayout);
 
 	return 0;
 }
diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/sonypi.c	Wed Apr  3 17:11:14 2002
@@ -109,25 +109,29 @@
         return result;
 }
 
-static void sonypi_ecrset(u16 addr, u16 value) {
+static void sonypi_ecrset(u8 addr, u8 value) {
 
-	wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
-	outw_p(0x81, SONYPI_CST_IOPORT);
-	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
-	outw_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
-	outw_p(value, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
-}
-
-static u16 sonypi_ecrget(u16 addr) {
-
-	wait_on_command(1, inw_p(SONYPI_CST_IOPORT) & 3);
-	outw_p(0x80, SONYPI_CST_IOPORT);
-	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
-	outw_p(addr, SONYPI_DATA_IOPORT);
-	wait_on_command(0, inw_p(SONYPI_CST_IOPORT) & 2);
-	return inw_p(SONYPI_DATA_IOPORT);
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+	outb_p(0x81, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+	outb_p(value, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+}
+
+static u8 sonypi_ecrget(u8 addr) {
+
+	wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3);
+	outb_p(0x80, SONYPI_CST_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+	outb_p(addr, SONYPI_DATA_IOPORT);
+	wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2);
+	return inb_p(SONYPI_DATA_IOPORT);
+}
+
+static u16 sonypi_ecrget16(u8 addr) {
+	return sonypi_ecrget(addr) | (sonypi_ecrget(addr + 1) << 8);
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
@@ -286,19 +290,38 @@
 	sonypi_device.camera_power = 1;
 }
 
+/* sets the bluetooth subsystem power state */
+static void sonypi_setbluetoothpower(u8 state) {
+
+	state = (state != 0);
+	if (sonypi_device.bluetooth_power && state) 
+		return;
+	if (!sonypi_device.bluetooth_power && !state) 
+		return;
+	
+	sonypi_call2(0x96, state);
+	sonypi_call1(0x93);
+	sonypi_device.bluetooth_power = state;
+}
+
 /* Interrupt handler: some event is available */
 void sonypi_irq(int irq, void *dev_id, struct pt_regs *regs) {
 	u8 v1, v2, event = 0;
 	int i;
 	u8 sonypi_jogger_ev, sonypi_fnkey_ev;
+	u8 sonypi_capture_ev, sonypi_bluetooth_ev;
 
 	if (sonypi_device.model == SONYPI_DEVICE_MODEL_TYPE2) {
 		sonypi_jogger_ev = SONYPI_TYPE2_JOGGER_EV;
 		sonypi_fnkey_ev = SONYPI_TYPE2_FNKEY_EV;
+		sonypi_capture_ev = SONYPI_TYPE2_CAPTURE_EV;
+		sonypi_bluetooth_ev = SONYPI_TYPE2_BLUETOOTH_EV;
 	}
 	else {
 		sonypi_jogger_ev = SONYPI_TYPE1_JOGGER_EV;
 		sonypi_fnkey_ev = SONYPI_TYPE1_FNKEY_EV;
+		sonypi_capture_ev = SONYPI_TYPE1_CAPTURE_EV;
+		sonypi_bluetooth_ev = SONYPI_TYPE1_BLUETOOTH_EV;
 	}
 
 	v1 = inb_p(sonypi_device.ioport1);
@@ -318,7 +341,7 @@
 				goto found;
 			}
 	}
-	if ((v2 & SONYPI_CAPTURE_EV) == SONYPI_CAPTURE_EV) {
+	if ((v2 & sonypi_capture_ev) == sonypi_capture_ev) {
 		for (i = 0; sonypi_captureev[i].event; i++)
 			if (sonypi_captureev[i].data == v1) {
 				event = sonypi_captureev[i].event;
@@ -332,7 +355,7 @@
 				goto found;
 			}
 	}
-	if ((v2 & SONYPI_BLUETOOTH_EV) == SONYPI_BLUETOOTH_EV) {
+	if ((v2 & sonypi_bluetooth_ev) == sonypi_bluetooth_ev) {
 		for (i = 0; sonypi_blueev[i].event; i++)
 			if (sonypi_blueev[i].data == v1) {
 				event = sonypi_blueev[i].event;
@@ -510,24 +533,74 @@
 static int sonypi_misc_ioctl(struct inode *ip, struct file *fp, 
 			     unsigned int cmd, unsigned long arg) {
 	int ret = 0;
-	u8 val;
+	u8 val8;
+	u16 val16;
 
 	down(&sonypi_device.lock);
 	switch (cmd) {
-		case SONYPI_IOCGBRT:
-			val = sonypi_ecrget(0x96) & 0xff;
-			if (copy_to_user((u8 *)arg, &val, sizeof(val))) {
-				ret = -EFAULT;
-				goto out;
-			}
-			break;
-		case SONYPI_IOCSBRT:
-			if (copy_from_user(&val, (u8 *)arg, sizeof(val))) {
-				ret = -EFAULT;
-				goto out;
-			}
-			sonypi_ecrset(0x96, val);
-			break;
+	case SONYPI_IOCGBRT:
+		val8 = sonypi_ecrget(0x96);
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCSBRT:
+		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		sonypi_ecrset(0x96, val8);
+		break;
+	case SONYPI_IOCGBAT1CAP:
+		val16 = sonypi_ecrget16(0xb2);
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCGBAT1REM:
+		val16 = sonypi_ecrget16(0xa2);
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCGBAT2CAP:
+		val16 = sonypi_ecrget16(0xba);
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCGBAT2REM:
+		val16 = sonypi_ecrget16(0xaa);
+		if (copy_to_user((u16 *)arg, &val16, sizeof(val16))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCGBATFLAGS:
+		val8 = sonypi_ecrget(0x81) & 0x07;
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCGBLUE:
+		val8 = sonypi_device.bluetooth_power;
+		if (copy_to_user((u8 *)arg, &val8, sizeof(val8))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		break;
+	case SONYPI_IOCSBLUE:
+		if (copy_from_user(&val8, (u8 *)arg, sizeof(val8))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		sonypi_setbluetoothpower(val8);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -562,6 +635,7 @@
 		sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
 	sonypi_initq();
 	init_MUTEX(&sonypi_device.lock);
+	sonypi_device.bluetooth_power = 0;
 	
 	if (pcidev && pci_enable_device(pcidev)) {
 		printk(KERN_ERR "sonypi: pci_enable_device failed\n");
diff -Nru a/drivers/char/sonypi.h b/drivers/char/sonypi.h
--- a/drivers/char/sonypi.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/char/sonypi.h	Wed Apr  3 17:11:13 2002
@@ -34,8 +34,8 @@
 
 #ifdef __KERNEL__
 
-#define SONYPI_DRIVER_MAJORVERSION	1
-#define SONYPI_DRIVER_MINORVERSION	8
+#define SONYPI_DRIVER_MAJORVERSION	 1
+#define SONYPI_DRIVER_MINORVERSION	10
 
 #include <linux/types.h>
 #include <linux/pci.h>
@@ -132,15 +132,17 @@
 #define SONYPI_CAMERA_ROMVERSION 		9
 
 /* key press event data (ioport2) */
-#define SONYPI_TYPE1_JOGGER_EV	0x10
-#define SONYPI_TYPE2_JOGGER_EV	0x08
-#define SONYPI_CAPTURE_EV	0x60
-#define SONYPI_TYPE1_FNKEY_EV	0x20
-#define SONYPI_TYPE2_FNKEY_EV	0x08
-#define SONYPI_BLUETOOTH_EV	0x30
-#define SONYPI_TYPE1_PKEY_EV	0x40
-#define SONYPI_BACK_EV		0x08
-#define SONYPI_LID_EV		0x38
+#define SONYPI_TYPE1_JOGGER_EV		0x10
+#define SONYPI_TYPE2_JOGGER_EV		0x08
+#define SONYPI_TYPE1_CAPTURE_EV		0x60
+#define SONYPI_TYPE2_CAPTURE_EV		0x08
+#define SONYPI_TYPE1_FNKEY_EV		0x20
+#define SONYPI_TYPE2_FNKEY_EV		0x08
+#define SONYPI_TYPE1_BLUETOOTH_EV	0x30
+#define SONYPI_TYPE2_BLUETOOTH_EV	0x08
+#define SONYPI_TYPE1_PKEY_EV		0x40
+#define SONYPI_BACK_EV			0x08
+#define SONYPI_LID_EV			0x38
 
 struct sonypi_event {
 	u8	data;
@@ -203,6 +205,8 @@
 /* The set of possible bluetooth events */
 static struct sonypi_event sonypi_blueev[] = {
 	{ 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+	{ 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+	{ 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
 	{ 0x00, 0x00 }
 };
 
@@ -241,6 +245,7 @@
 	u16 ioport2;
 	u16 region_size;
 	int camera_power;
+	int bluetooth_power;
 	struct semaphore lock;
 	struct sonypi_queue queue;
 	int open_count;
diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/stallion.c	Wed Apr  3 17:11:14 2002
@@ -2458,7 +2458,7 @@
 	}
 
 /*
- *	We have verfied that the board is actually present, so now we
+ *	We have verified that the board is actually present, so now we
  *	can complete the setup.
  */
 
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/synclink.c	Wed Apr  3 17:11:15 2002
@@ -925,9 +925,9 @@
 static char *driver_name = "SyncLink serial driver";
 static char *driver_version = "$Revision: 3.12 $";
 
-static int __init synclink_init_one (struct pci_dev *dev,
+static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
-static void __exit synclink_remove_one (struct pci_dev *dev);
+static void synclink_remove_one (struct pci_dev *dev);
 
 static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
diff -Nru a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
--- a/drivers/char/tpqic02.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/tpqic02.c	Wed Apr  3 17:11:15 2002
@@ -2748,7 +2748,9 @@
 	 * the config parameters have been set using MTSETCONFIG.
 	 */
 
-	if (check_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE)) {
+	/* Grab the IO region. */
+	if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
+			   TPQIC02_NAME)) {
 		printk(TPQIC02_NAME
 		       ": IO space at 0x%x [%d ports] already reserved\n",
 		       QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
@@ -2762,6 +2764,7 @@
 		printk(TPQIC02_NAME
 		       ": can't allocate IRQ%d for QIC-02 tape\n",
 		       QIC02_TAPE_IRQ);
+		release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
 		return -EBUSY;
 	}
 
@@ -2771,12 +2774,9 @@
 		       ": can't allocate DMA%d for QIC-02 tape\n",
 		       QIC02_TAPE_DMA);
 		free_irq(QIC02_TAPE_IRQ, NULL);
+		release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
 		return -EBUSY;
 	}
-
-	/* Grab the IO region. We already made sure it's available. */
-	request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE,
-		       TPQIC02_NAME);
 
 	/* Setup the page-address for the dma transfer. */
 	buffaddr =
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/tty_io.c	Wed Apr  3 17:11:15 2002
@@ -569,6 +569,8 @@
 	struct task_struct *p;
 	int tty_pgrp = -1;
 
+	lock_kernel();
+
 	if (tty) {
 		tty_pgrp = tty->pgrp;
 		if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY)
@@ -578,6 +580,7 @@
 			kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
 			kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
 		}
+		unlock_kernel();	
 		return;
 	}
 	if (tty_pgrp > 0) {
@@ -595,6 +598,7 @@
 	  	if (p->session == current->session)
 			p->tty = NULL;
 	read_unlock(&tasklist_lock);
+	unlock_kernel();
 }
 
 void stop_tty(struct tty_struct *tty)
diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
--- a/drivers/char/vme_scc.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/char/vme_scc.c	Wed Apr  3 17:11:13 2002
@@ -214,7 +214,7 @@
 {
 	struct scc_port *port;
 
-	printk("SCC: MVME147 Serial Driver\n");
+	printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
 	/* Init channel A */
 	port = &scc_ports[0];
 	port->channel = CHANNEL_A;
@@ -284,7 +284,7 @@
 	if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
 		return (-ENODEV);
 
-	printk("SCC: MVME162 Serial Driver\n");
+	printk(KERN_INFO "SCC: MVME162 Serial Driver\n");
 	/* Init channel A */
 	port = &scc_ports[0];
 	port->channel = CHANNEL_A;
@@ -352,7 +352,7 @@
 {
 	struct scc_port *port;
 
-	printk("SCC: BVME6000 Serial Driver\n");
+	printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
 	/* Init channel A */
 	port = &scc_ports[0];
 	port->channel = CHANNEL_A;
@@ -449,7 +449,7 @@
 
 	ch = SCCread_NB(RX_DATA_REG);
 	if (!tty) {
-		printk ("scc_rx_int with NULL tty!\n");
+		printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
 		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
 		return;
 	}
@@ -487,7 +487,7 @@
 	SCC_ACCESS_INIT(port);
 	
 	if (!tty) {
-		printk ("scc_spcond_int with NULL tty!\n");
+		printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
 		SCCwrite(COMMAND_REG, CR_ERROR_RESET);
 		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
 		return;
@@ -533,7 +533,7 @@
 	SCC_ACCESS_INIT(port);
 
 	if (!port->gs.tty) {
-		printk ("scc_tx_int with NULL tty!\n");
+		printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
 		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
 		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
 		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
@@ -719,7 +719,7 @@
 	else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
 		 (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
 		 (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
-		printk("SCC: Bad speed requested, %d\n", baud);
+		printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
 		return 0;
 	}
 
diff -Nru a/drivers/char/wdt.c b/drivers/char/wdt.c
--- a/drivers/char/wdt.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/char/wdt.c	Wed Apr  3 17:11:15 2002
@@ -15,7 +15,7 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *	Release 0.08.
+ *	Release 0.09.
  *
  *	Fixes
  *		Dave Gregorich	:	Modularisation and minor bugs
@@ -27,6 +27,7 @@
  *		Tim Hockin	:	Added insmod parameters, comment cleanup
  *					Parameterized timeout
  *		Tigran Aivazian	:	Restructured wdt_init() to handle failures
+ *		Matt Domsch	:	added nowayout and timeout module options
  */
 
 #include <linux/config.h>
@@ -62,6 +63,26 @@
 
 #define WD_TIMO (100*60)		/* 1 minute */
 
+static int timeout_val = WD_TIMO;	/* value passed to card */
+static int timeout = 60;	        /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdt_validate_timeout(void)
+{
+	timeout_val = timeout * 100;
+}
+
 #ifndef MODULE
 
 /**
@@ -216,7 +237,7 @@
 	/* Write a watchdog value */
 	inb_p(WDT_DC);
 	wdt_ctr_mode(1,2);
-	wdt_ctr_load(1,WD_TIMO);		/* Timeout */
+	wdt_ctr_load(1,timeout_val);		/* Timeout */
 	outb_p(0, WDT_DC);
 }
 
@@ -339,6 +360,9 @@
 		case WATCHDOG_MINOR:
 			if(test_and_set_bit(0, &wdt_is_open))
 				return -EBUSY;
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
@@ -348,7 +372,7 @@
 			wdt_ctr_mode(1,2);
 			wdt_ctr_mode(2,0);
 			wdt_ctr_load(0, 8948);		/* count at 100Hz */
-			wdt_ctr_load(1,WD_TIMO);	/* Timeout 120 seconds */
+			wdt_ctr_load(1,timeout_val);	/* Timeout */
 			wdt_ctr_load(2,65535);
 			outb_p(0, WDT_DC);	/* Enable */
 			return 0;
@@ -375,10 +399,10 @@
 {
 	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_DC);		/* Disable counters */
-		wdt_ctr_load(2,0);	/* 0 length reset pulses now */
-#endif		
+		if (!nowayout) {
+			inb_p(WDT_DC);		/* Disable counters */
+			wdt_ctr_load(2,0);	/* 0 length reset pulses now */
+		}
 		clear_bit(0, &wdt_is_open);
 	}
 	return 0;
@@ -484,6 +508,7 @@
 {
 	int ret;
 
+	wdt_validate_timeout();
 	ret = misc_register(&wdt_miscdev);
 	if (ret) {
 		printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
diff -Nru a/drivers/char/wdt977.c b/drivers/char/wdt977.c
--- a/drivers/char/wdt977.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/wdt977.c	Wed Apr  3 17:11:14 2002
@@ -1,5 +1,5 @@
 /*
- *	Wdt977	0.01:	A Watchdog Device for Netwinder W83977AF chip
+ *	Wdt977	0.02:	A Watchdog Device for Netwinder W83977AF chip
  *
  *	(c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
  *
@@ -11,8 +11,13 @@
  *	2 of the License, or (at your option) any later version.
  *
  *			-----------------------
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *	19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
+ *	06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
+ *				    from minutes to seconds.
  */
- 
+
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/types.h>
@@ -21,56 +26,123 @@
 #include <linux/miscdevice.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/watchdog.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
+#include <asm/uaccess.h>
 
 #define WATCHDOG_MINOR	130
 
-static	int timeout = 3;
+#define	DEFAULT_TIMEOUT	1	/* default timeout = 1 minute */
+
+static	int timeout = DEFAULT_TIMEOUT*60;	/* TO in seconds from user */
+static	int timeoutM = DEFAULT_TIMEOUT;		/* timeout in minutes */
 static	int timer_alive;
 static	int testmode;
 
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60");
+MODULE_PARM(testmode, "i");
+MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */
+int kick_wdog(void)
+{
+	/*
+	 *	Refresh the timer.
+	 */
+
+	/* unlock the SuperIO chip */
+	outb(0x87,0x370);
+	outb(0x87,0x370);
+
+	/* select device Aux2 (device=8) and kicks watchdog reg F2 */
+	/* F2 has the timeout in minutes */
+
+	outb(0x07,0x370);
+	outb(0x08,0x371);
+	outb(0xF2,0x370);
+	outb(timeoutM,0x371);
+
+	/* lock the SuperIO chip */
+	outb(0xAA,0x370);
+
+	return 0;
+}
+
+
 /*
  *	Allow only one person to hold it open
  */
- 
+
 static int wdt977_open(struct inode *inode, struct file *file)
 {
+
 	if(timer_alive)
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	MOD_INC_USE_COUNT;
-#endif
+
+	/* convert seconds to minutes, rounding up */
+	timeoutM = timeout + 59;
+	timeoutM /= 60;
+
+	if (nowayout)
+	{
+		MOD_INC_USE_COUNT;
+
+		/* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */
+		if (!timeoutM) timeoutM = DEFAULT_TIMEOUT;
+	}
 	timer_alive++;
 
-	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
-	if (timeout>255)
-	    timeout = 255;
-
-	printk(KERN_INFO "Watchdog: active, current timeout %d min.\n",timeout);
-
-	// unlock the SuperIO chip
-	outb(0x87,0x370); 
-	outb(0x87,0x370); 
-	
-	//select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
-	//F2 has the timeout in minutes
-	//F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
-	//   at timeout, and to reset timer on kbd/mouse activity (not now)
-	//F4 is used to just clear the TIMEOUT'ed state (bit 0)
-	
+	if (machine_is_netwinder())
+	{
+		/* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+		 *  this limits the max timeout to half of device max of 255 minutes...
+		 */
+		timeoutM += timeoutM;
+	}
+
+	/* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */
+	if (timeoutM > 255) timeoutM = 255;
+
+	/* convert seconds to minutes */
+	printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n",
+		machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60,
+		nowayout, testmode);
+
+	/* unlock the SuperIO chip */
+	outb(0x87,0x370);
+	outb(0x87,0x370);
+
+	/* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
+	 * F2 has the timeout in minutes
+	 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
+	 *   at timeout, and to reset timer on kbd/mouse activity (not impl.)
+	 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
+	 */
 	outb(0x07,0x370);
 	outb(0x08,0x371);
 	outb(0xF2,0x370);
-	outb(timeout,0x371);
+	outb(timeoutM,0x371);
 	outb(0xF3,0x370);
-	outb(0x00,0x371);	//another setting is 0E for kbd/mouse/LED
+	outb(0x00,0x371);	/* another setting is 0E for kbd/mouse/LED */
 	outb(0xF4,0x370);
 	outb(0x00,0x371);
-	
-	//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+
+	/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+	/* in test mode watch the bit 1 on F4 to indicate "triggered" */
 	if (!testmode)
 	{
 		outb(0x07,0x370);
@@ -78,9 +150,9 @@
 		outb(0xE6,0x370);
 		outb(0x08,0x371);
 	}
-		
-	// lock the SuperIO chip
-	outb(0xAA,0x370); 
+
+	/* lock the SuperIO chip */
+	outb(0xAA,0x370);
 
 	return 0;
 }
@@ -89,84 +161,163 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (!nowayout)
+	{
+		lock_kernel();
 
-	// unlock the SuperIO chip
-	outb(0x87,0x370); 
-	outb(0x87,0x370); 
-	
-	//select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
-	//F3 is reset to its default state
-	//F4 can clear the TIMEOUT'ed state (bit 0) - back to default
-	//We can not use GP17 as a PowerLed, as we use its usage as a RedLed
-	
-	outb(0x07,0x370);
-	outb(0x08,0x371);
-	outb(0xF2,0x370);
-	outb(0xFF,0x371);
-	outb(0xF3,0x370);
-	outb(0x00,0x371);
-	outb(0xF4,0x370);
-	outb(0x00,0x371);
-	outb(0xF2,0x370);
-	outb(0x00,0x371);
-	
-	//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
-	outb(0x07,0x370);
-	outb(0x07,0x371);
-	outb(0xE6,0x370);
-	outb(0x08,0x371);
-	
-	// lock the SuperIO chip
-	outb(0xAA,0x370);
+		/* unlock the SuperIO chip */
+		outb(0x87,0x370);
+		outb(0x87,0x370);
+
+		/* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+		* F3 is reset to its default state
+		* F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+		* We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+		*/
+		outb(0x07,0x370);
+		outb(0x08,0x371);
+		outb(0xF2,0x370);
+		outb(0xFF,0x371);
+		outb(0xF3,0x370);
+		outb(0x00,0x371);
+		outb(0xF4,0x370);
+		outb(0x00,0x371);
+		outb(0xF2,0x370);
+		outb(0x00,0x371);
 
-	timer_alive=0;
+		/* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
+		outb(0x07,0x370);
+		outb(0x07,0x371);
+		outb(0xE6,0x370);
+		outb(0x08,0x371);
 
-	printk(KERN_INFO "Watchdog: shutdown.\n");
-#endif
+		/* lock the SuperIO chip */
+		outb(0xAA,0x370);
+
+		timer_alive=0;
+		unlock_kernel();
+
+		printk(KERN_INFO "Wdt977 Watchdog: shutdown\n");
+	}
 	return 0;
 }
 
-static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+
+/*
+ *      wdt977_write:
+ *      @file: file handle to the watchdog
+ *      @buf: buffer to write (unused as data does not matter here
+ *      @count: count of bytes
+ *      @ppos: pointer to the position to write. No seeks allowed
+ *
+ *      A write to a watchdog device is defined as a keepalive signal. Any
+ *      write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t wdt977_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
 
-	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
-	if (timeout>255)
-	    timeout = 255;
+	if(count)
+	{
+		kick_wdog();
+		return 1;
+	}
+	return 0;
+}
 
-	/*
-	 *	Refresh the timer.
-	 */
-		
-	//we have a hw bug somewhere, so each 977 minute is actually only 30sec
-	//as such limit the max timeout to half of max of 255 minutes...
-//	if (timeout>126)
-//	    timeout = 126;
-	
-	// unlock the SuperIO chip
-	outb(0x87,0x370); 
-	outb(0x87,0x370); 
-	
-	//select device Aux2 (device=8) and kicks watchdog reg F2
-	//F2 has the timeout in minutes
-	
-	outb(0x07,0x370);
-	outb(0x08,0x371);
-	outb(0xF2,0x370);
-	outb(timeout,0x371);
-	
-	// lock the SuperIO chip
-	outb(0xAA,0x370); 
-	
-	return 1;
+/*
+ *      wdt977_ioctl:
+ *      @inode: inode of the device
+ *      @file: file handle to the device
+ *      @cmd: watchdog command
+ *      @arg: argument pointer
+ *
+ *      The watchdog API defines a common set of functions for all watchdogs
+ *      according to their available features.
+ */
+
+static int wdt977_ioctl(struct inode *inode, struct file *file,
+         unsigned int cmd, unsigned long arg)
+{
+static struct watchdog_info ident = {
+	identity	: "Winbond 83977"
+};
+
+int temp;
+
+	switch(cmd)
+	{
+	default:
+		return -ENOTTY;
+
+	case WDIOC_GETSUPPORT:
+	    return copy_to_user((struct watchdog_info *)arg, &ident,
+			sizeof(ident)) ? -EFAULT : 0;
+
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, (int *) arg);
+
+	case WDIOC_GETSTATUS:
+		/* unlock the SuperIO chip */
+		outb(0x87,0x370);
+		outb(0x87,0x370);
+
+		/* select device Aux2 (device=8) and read watchdog reg F4 */
+		outb(0x07,0x370);
+		outb(0x08,0x371);
+		outb(0xF4,0x370);
+		temp = inb(0x371);
+
+		/* lock the SuperIO chip */
+		outb(0xAA,0x370);
+
+		/* return info if "expired" in test mode */
+		return put_user(temp & 1, (int *) arg);
+
+	case WDIOC_KEEPALIVE:
+		kick_wdog();
+		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (copy_from_user(&temp, (int *) arg, sizeof(int)))
+			return -EFAULT;
+
+		/* convert seconds to minutes, rounding up */
+		temp += 59;
+		temp /= 60;
+
+		/* we have a hw bug somewhere, so each 977 minute is actually only 30sec
+		*  this limits the max timeout to half of device max of 255 minutes...
+		*/
+		if (machine_is_netwinder())
+		{
+		    temp += temp;
+		}
+
+		/* Sanity check */
+		if (temp < 0 || temp > 255)
+			return -EINVAL;
+
+		if (!temp && nowayout)
+			return -EINVAL;
+
+		timeoutM = temp;
+		kick_wdog();
+		return 0;
+	}
 }
 
+
 static struct file_operations wdt977_fops=
 {
 	owner:		THIS_MODULE,
 	write:		wdt977_write,
+	ioctl:		wdt977_ioctl,
 	open:		wdt977_open,
 	release:	wdt977_release,
 };
@@ -184,9 +335,9 @@
 		return -ENODEV;
 
 	misc_register(&wdt977_miscdev);
-	printk(KERN_INFO "NetWinder Watchdog sleeping.\n");
+	printk(KERN_INFO "Wdt977 Watchdog sleeping.\n");
 	return 0;
-}	
+}
 
 static void __exit nwwatchdog_exit(void)
 {
diff -Nru a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
--- a/drivers/char/wdt_pci.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/char/wdt_pci.c	Wed Apr  3 17:11:14 2002
@@ -15,7 +15,7 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *	Release 0.08.
+ *	Release 0.09.
  *
  *	Fixes
  *		Dave Gregorich	:	Modularisation and minor bugs
@@ -30,6 +30,7 @@
  *		Alan Cox	:	Split ISA and PCI cards into two drivers
  *		Jeff Garzik	:	PCI cleanups
  *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle failures
+ *		Matt Domsch	:	added nowayout and timeout module options
  */
 
 #include <linux/config.h>
@@ -83,6 +84,26 @@
 
 #define WD_TIMO (100*60)		/* 1 minute */
 
+static int timeout_val = WD_TIMO;	/* value passed to card */
+static int timeout = 60;	        /* in seconds */
+MODULE_PARM(timeout,"i");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=60)");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static void __init
+wdtpci_validate_timeout(void)
+{
+	timeout_val = timeout * 100;
+}
+
 #ifndef MODULE
 
 /**
@@ -232,7 +253,7 @@
 	/* Write a watchdog value */
 	inb_p(WDT_DC);
 	wdtpci_ctr_mode(1,2);
-	wdtpci_ctr_load(1,WD_TIMO);		/* Timeout */
+	wdtpci_ctr_load(1,timeout_val);		/* Timeout */
 	outb_p(0, WDT_DC);
 }
 
@@ -357,9 +378,9 @@
 			{
 				return -EBUSY;
 			}
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
@@ -385,7 +406,7 @@
 			wdtpci_ctr_mode(1,2);
 			wdtpci_ctr_mode(2,1);
 			wdtpci_ctr_load(0,20833);	/* count at 100Hz */
-			wdtpci_ctr_load(1,WD_TIMO);/* Timeout 60 seconds */
+			wdtpci_ctr_load(1,timeout_val); /* Timeout */
 			/* DO NOT LOAD CTR2 on PCI card! -- JPN */
 			outb_p(0, WDT_DC);	/* Enable */
 			return 0;
@@ -412,10 +433,10 @@
 {
 	if(minor(inode->i_rdev)==WATCHDOG_MINOR)
 	{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_DC);		/* Disable counters */
-		wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
-#endif		
+		if (!nowayout) {
+			inb_p(WDT_DC);		/* Disable counters */
+			wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
+		}
 		clear_bit(0, &wdt_is_open );
 	}
 	return 0;
@@ -617,6 +638,8 @@
 	
 	if (rc < 1)
 		return -ENODEV;
+
+	wdtpci_validate_timeout();
 	
 	return 0;
 }
diff -Nru a/drivers/fc4/soc.c b/drivers/fc4/soc.c
--- a/drivers/fc4/soc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/fc4/soc.c	Wed Apr  3 17:11:14 2002
@@ -742,7 +742,6 @@
 	
 	for_each_soc(s) {
 		irq = s->port[0].fc.irq;
-		disable_irq (irq);
 		free_irq (irq, s);
 
 		fcp_release(&(s->port[0].fc), 2);
diff -Nru a/drivers/fc4/socal.c b/drivers/fc4/socal.c
--- a/drivers/fc4/socal.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/fc4/socal.c	Wed Apr  3 17:11:15 2002
@@ -881,7 +881,6 @@
 	
 	for_each_socal(s) {
 		irq = s->port[0].fc.irq;
-		disable_irq (irq);
 		free_irq (irq, s);
 
 		fcp_release(&(s->port[0].fc), 2);
diff -Nru a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c
--- a/drivers/i2c/i2c-algo-bit.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/i2c/i2c-algo-bit.c	Wed Apr  3 17:11:13 2002
@@ -49,7 +49,7 @@
 /* respectively. This makes sure that the algorithm works. Some chips   */
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
-#define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
+#define SLO_IO      jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\
                         cond_resched();
 */
 
@@ -117,7 +117,7 @@
  		 * while they are processing data internally. 
  		 */
 		setscl(adap,1);
-		if (start+adap->timeout <= jiffies) {
+		if (time_after_eq(jiffies, start+adap->timeout)) {
 			return -ETIMEDOUT;
 		}
 		cond_resched();
diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/i2c/i2c-dev.c	Wed Apr  3 17:11:16 2002
@@ -141,7 +141,7 @@
 #ifdef DEBUG
 	struct inode *inode = file->f_dentry->d_inode;
 	printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
-	       MINOR(inode->i_rdev),(long) offset,origin);
+	       minor(inode->i_rdev),(long) offset,origin);
 #endif /* DEBUG */
 	return -ESPIPE;
 }
@@ -165,7 +165,7 @@
 		return -ENOMEM;
 
 #ifdef DEBUG
-	printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+	printk("i2c-dev.o: i2c-%d reading %d bytes.\n",minor(inode->i_rdev),
 	       count);
 #endif
 
@@ -197,7 +197,7 @@
 	}
 
 #ifdef DEBUG
-	printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+	printk("i2c-dev.o: i2c-%d writing %d bytes.\n",minor(inode->i_rdev),
 	       count);
 #endif
 	ret = i2c_master_send(client,tmp,count);
@@ -218,7 +218,7 @@
 
 #ifdef DEBUG
 	printk("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
-	       MINOR(inode->i_rdev),cmd, arg);
+	       minor(inode->i_rdev),cmd, arg);
 #endif /* DEBUG */
 
 	switch ( cmd ) {
diff -Nru a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c
--- a/drivers/i2c/i2c-proc.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/i2c/i2c-proc.c	Wed Apr  3 17:11:15 2002
@@ -119,6 +119,10 @@
 		sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr);
 	}
 	*name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL);
+	if (!*name) {
+		printk (KERN_WARNING "i2c_create_name: not enough memory\n");
+		return -ENOMEM;
+	}
 	strcpy(*name, name_buffer);
 	return 0;
 }
diff -Nru a/drivers/ide/aec62xx.c b/drivers/ide/aec62xx.c
--- a/drivers/ide/aec62xx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/aec62xx.c	Wed Apr  3 17:11:15 2002
@@ -220,7 +220,7 @@
 
 static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	int err			= 0;
 	unsigned short d_conf	= 0x0000;
@@ -256,10 +256,10 @@
 
 static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	byte unit		= (drive->select.b.unit & 0x01);
-	byte ultra_pci		= hwif->channel ? 0x45 : 0x44;
+	byte ultra_pci		= hwif->unit ? 0x45 : 0x44;
 	int err			= 0;
 	byte drive_conf		= 0x00;
 	byte ultra_conf		= 0x00;
@@ -293,7 +293,7 @@
 
 static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
+	if (drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
 		return ((int) aec6210_tune_chipset(drive, speed));
 	} else {
 		return ((int) aec6260_tune_chipset(drive, speed));
@@ -304,7 +304,7 @@
 static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	byte unit		= (drive->select.b.unit & 0x01);
 	unsigned long dma_base	= hwif->dma_base;
 	byte speed		= -1;
@@ -349,7 +349,7 @@
 static int config_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	byte unit		= (drive->select.b.unit & 0x01);
 	unsigned long dma_base	= hwif->dma_base;
 	byte speed		= -1;
@@ -396,7 +396,7 @@
 
 static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
-	switch(HWIF(drive)->pci_dev->device) {	
+	switch(drive->channel->pci_dev->device) {
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 			return config_aec6210_chipset_for_dma(drive, ultra);
 		case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -418,7 +418,7 @@
 	else
 		speed = XFER_PIO_0 + min_t(byte, pio, 4);
 
-	switch(HWIF(drive)->pci_dev->device) {
+	switch(drive->channel->pci_dev->device) {
 		case PCI_DEVICE_ID_ARTOP_ATP850UF:
 			(void) aec6210_tune_chipset(drive, speed);
 		case PCI_DEVICE_ID_ARTOP_ATP860:
@@ -435,7 +435,7 @@
 	struct hd_driveid *id = drive->id;
 	ide_dma_action_t dma_func = ide_dma_on;
 
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -476,7 +476,7 @@
 no_dma_set:
 		aec62xx_tune_drive(drive, 5);
 	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 /*
@@ -489,16 +489,16 @@
 			return config_drive_xfer_rate(drive);
 		case ide_dma_lostirq:
 		case ide_dma_timeout:
-			switch(HWIF(drive)->pci_dev->device) {
+			switch(drive->channel->pci_dev->device) {
 				case PCI_DEVICE_ID_ARTOP_ATP860:
 				case PCI_DEVICE_ID_ARTOP_ATP860R:
 //					{
 //						int i = 0;
 //						byte reg49h = 0;
-//						pci_read_config_byte(HWIF(drive)->pci_dev, 0x49, &reg49h);
+//						pci_read_config_byte(drive->channel->pci_dev, 0x49, &reg49h);
 //						for (i=0;i<256;i++)
-//							pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h|0x10);
-//						pci_write_config_byte(HWIF(drive)->pci_dev, 0x49, reg49h & ~0x10);
+//							pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h|0x10);
+//						pci_write_config_byte(drive->channel->pci_dev, 0x49, reg49h & ~0x10);
 //					}
 //					return 0;
 				default:
@@ -530,16 +530,16 @@
 	return dev->irq;
 }
 
-unsigned int __init ata66_aec62xx (ide_hwif_t *hwif)
+unsigned int __init ata66_aec62xx(struct ata_channel *hwif)
 {
-	byte mask	= hwif->channel ? 0x02 : 0x01;
+	byte mask	= hwif->unit ? 0x02 : 0x01;
 	byte ata66	= 0;
 
 	pci_read_config_byte(hwif->pci_dev, 0x49, &ata66);
 	return ((ata66 & mask) ? 0 : 1);
 }
 
-void __init ide_init_aec62xx (ide_hwif_t *hwif)
+void __init ide_init_aec62xx(struct ata_channel *hwif)
 {
 #ifdef CONFIG_AEC62XX_TUNING
 	hwif->tuneproc = &aec62xx_tune_drive;
@@ -555,7 +555,7 @@
 #endif /* CONFIG_AEC62XX_TUNING */
 }
 
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_aec62xx(struct ata_channel *hwif, unsigned long dmabase)
 {
 #ifdef CONFIG_AEC62XX_TUNING
 	unsigned long flags;
@@ -565,7 +565,7 @@
 	__cli();		/* local CPU only */
 
 	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->unit ? 0xF0 : 0x0F));
 
 	__restore_flags(flags);	/* local CPU only */
 #endif /* CONFIG_AEC62XX_TUNING */
diff -Nru a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
--- a/drivers/ide/ali14xx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ali14xx.c	Wed Apr  3 17:11:15 2002
@@ -134,7 +134,7 @@
 		drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4);
 
 	/* stuff timing parameters into controller registers */
-	driveNum = (HWIF(drive)->index << 1) + drive->select.b.unit;
+	driveNum = (drive->channel->index << 1) + drive->select.b.unit;
 	save_flags(flags);	/* all CPUs */
 	cli();			/* all CPUs */
 	outb_p(regOn, basePort);
@@ -214,7 +214,7 @@
 	ide_hwifs[1].tuneproc = &ali14xx_tune_drive;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
+	ide_hwifs[1].unit = 1;
 
 	/* initialize controller registers */
 	if (!initRegisters()) {
diff -Nru a/drivers/ide/alim15x3.c b/drivers/ide/alim15x3.c
--- a/drivers/ide/alim15x3.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/alim15x3.c	Wed Apr  3 17:11:14 2002
@@ -242,13 +242,13 @@
 static void ali15x3_tune_drive (ide_drive_t *drive, byte pio)
 {
 	struct ata_timing *t;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev = hwif->pci_dev;
 	int s_time, a_time, c_time;
 	byte s_clc, a_clc, r_clc;
 	unsigned long flags;
-	int port = hwif->index ? 0x5c : 0x58;
-	int portFIFO = hwif->channel ? 0x55 : 0x54;
+	int port = hwif->unit ? 0x5c : 0x58;
+	int portFIFO = hwif->unit ? 0x55 : 0x54;
 	byte cd_dma_fifo = 0;
 
 	if (pio == 255)
@@ -305,11 +305,11 @@
 
 static int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	byte unit		= (drive->select.b.unit & 0x01);
 	byte tmpbyte		= 0x00;
-	int m5229_udma		= hwif->channel? 0x57 : 0x56;
+	int m5229_udma		= hwif->unit ? 0x57 : 0x56;
 	int err			= 0;
 
 	if (speed < XFER_UDMA_0) {
@@ -431,10 +431,10 @@
 
 static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
 {
-	struct hd_driveid *id		= drive->id;
-	ide_hwif_t *hwif		= HWIF(drive);
-	ide_dma_action_t dma_func	= ide_dma_on;
-	byte can_ultra_dma		= ali15x3_can_ultra(drive);
+	struct hd_driveid *id = drive->id;
+	struct ata_channel *hwif = drive->channel;
+	ide_dma_action_t dma_func = ide_dma_on;
+	byte can_ultra_dma = ali15x3_can_ultra(drive);
 
 	if ((m5229_revision<=0x20) && (drive->type != ATA_DISK))
 		return hwif->dmaproc(ide_dma_off_quietly, drive);
@@ -537,7 +537,7 @@
  * of UDMA66 transfers. It doesn't check the drives.
  * But see note 2 below!
  */
-unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+unsigned int __init ata66_ali15x3(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int ata66	= 0;
@@ -597,7 +597,7 @@
 		/*
 		 * Allow ata66 if cable of current channel has 80 pins
 		 */
-		ata66 = (hwif->channel)?cable_80_pin[1]:cable_80_pin[0];
+		ata66 = (hwif->unit)?cable_80_pin[1]:cable_80_pin[0];
 	} else {
 		/*
 		 * revision 0x20 (1543-E, 1543-F)
@@ -632,14 +632,14 @@
 	return(ata66);
 }
 
-void __init ide_init_ali15x3 (ide_hwif_t *hwif)
+void __init ide_init_ali15x3(struct ata_channel *hwif)
 {
 #ifndef CONFIG_SPARC64
 	byte ideic, inmir;
 	byte irq_routing_table[] = { -1,  9, 3, 10, 4,  5, 7,  6,
 				      1, 11, 0, 12, 0, 14, 0, 15 };
 
-	hwif->irq = hwif->channel ? 15 : 14;
+	hwif->irq = hwif->unit ? 15 : 14;
 
 	if (isa_dev) {
 		/*
@@ -651,14 +651,14 @@
 		ideic = ideic & 0x03;
 
 		/* get IRQ for IDE Controller */
-		if ((hwif->channel && ideic == 0x03) || (!hwif->channel && !ideic)) {
+		if ((hwif->unit && ideic == 0x03) || (!hwif->unit && !ideic)) {
 			/*
 			 * get SIRQ1 routing table
 			 */
 			pci_read_config_byte(isa_dev, 0x44, &inmir);
 			inmir = inmir & 0x0f;
 			hwif->irq = irq_routing_table[inmir];
-		} else if (hwif->channel && !(ideic & 0x01)) {
+		} else if (hwif->unit && !(ideic & 0x01)) {
 			/*
 			 * get SIRQ2 routing table
 			 */
@@ -690,7 +690,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-void __init ide_dmacapable_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_ali15x3(struct ata_channel *hwif, unsigned long dmabase)
 {
 	if ((dmabase) && (m5229_revision < 0x20)) {
 		return;
diff -Nru a/drivers/ide/amd74xx.c b/drivers/ide/amd74xx.c
--- a/drivers/ide/amd74xx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/amd74xx.c	Wed Apr  3 17:11:15 2002
@@ -226,7 +226,7 @@
 
 static int amd_set_drive(ide_drive_t *drive, unsigned char speed)
 {
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
 	struct ata_timing t, p;
 	int T, UT;
 
@@ -247,7 +247,7 @@
 
 	if (speed == XFER_UDMA_5 && amd_clock <= 33333) t.udma = 1;
 
-	amd_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+	amd_set_speed(drive->channel->pci_dev, drive->dn, &t);
 
 	if (!drive->init_speed)	
 		drive->init_speed = speed;
@@ -263,7 +263,7 @@
 
 static void amd74xx_tune_drive(ide_drive_t *drive, unsigned char pio)
 {
-	if (!((amd_enabled >> HWIF(drive)->channel) & 1))
+	if (!((amd_enabled >> drive->channel->unit) & 1))
 		return;
 
 	if (pio == 255) {
@@ -287,7 +287,7 @@
 
 	if (func == ide_dma_check) {
 
-		short w80 = HWIF(drive)->udma_four;
+		short w80 = drive->channel->udma_four;
 
 		short speed = ata_timing_mode(drive,
 			XFER_PIO | XFER_EPIO | XFER_MWDMA | XFER_UDMA |
@@ -297,7 +297,7 @@
 
 		amd_set_drive(drive, speed);
 
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+		func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
 			? ide_dma_on : ide_dma_off_quietly;
 	}
 
@@ -409,12 +409,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_amd74xx(ide_hwif_t *hwif)
+unsigned int __init ata66_amd74xx(struct ata_channel *hwif)
 {
-	return ((amd_enabled & amd_80w) >> hwif->channel) & 1;
+	return ((amd_enabled & amd_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_amd74xx(ide_hwif_t *hwif)
+void __init ide_init_amd74xx(struct ata_channel *hwif)
 {
 	int i;
 
@@ -426,7 +426,7 @@
 		hwif->drives[i].io_32bit = 1;
 		hwif->drives[i].unmask = 1;
 		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
+		hwif->drives[i].dn = hwif->unit * 2 + i;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -445,8 +445,8 @@
  * We allow the BM-DMA driver only work on enabled interfaces.
  */
 
-void __init ide_dmacapable_amd74xx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_amd74xx(struct ata_channel *hwif, unsigned long dmabase)
 {
-	if ((amd_enabled >> hwif->channel) & 1)
+	if ((amd_enabled >> hwif->unit) & 1)
 		ide_setup_dma(hwif, dmabase, 8);
 }
diff -Nru a/drivers/ide/buddha.c b/drivers/ide/buddha.c
--- a/drivers/ide/buddha.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/buddha.c	Wed Apr  3 17:11:15 2002
@@ -116,7 +116,7 @@
      *  Check and acknowledge the interrupt status
      */
 
-static int buddha_ack_intr(ide_hwif_t *hwif)
+static int buddha_ack_intr(struct ata_channel *hwif)
 {
     unsigned char ch;
 
@@ -126,7 +126,7 @@
     return 1;
 }
 
-static int xsurf_ack_intr(ide_hwif_t *hwif)
+static int xsurf_ack_intr(struct ata_channel *hwif)
 {
     unsigned char ch;
 
diff -Nru a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c
--- a/drivers/ide/cmd640.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/cmd640.c	Wed Apr  3 17:11:15 2002
@@ -187,7 +187,7 @@
 /*
  * These are initialized to point at the devices we control
  */
-static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
+static struct ata_channel *cmd_hwif0, *cmd_hwif1;
 static ide_drive_t *cmd_drives[4];
 
 /*
@@ -429,7 +429,7 @@
 	cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
 	cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
 	for (i = 0; i < MAX_HWIFS; i++) {
-		ide_hwif_t *hwif = &ide_hwifs[i];
+		struct ata_channel *hwif = &ide_hwifs[i];
 		if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
 			if (hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0)
 				cmd_hwif0 = hwif;
@@ -795,7 +795,7 @@
 		cmd_hwif1->chipset = ide_cmd640;
 		cmd_hwif0->mate = cmd_hwif1;
 		cmd_hwif1->mate = cmd_hwif0;
-		cmd_hwif1->channel = 1;
+		cmd_hwif1->unit = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
 		cmd_hwif1->tuneproc = &cmd640_tune_drive;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
diff -Nru a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c
--- a/drivers/ide/cmd64x.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/cmd64x.c	Wed Apr  3 17:11:15 2002
@@ -211,7 +211,7 @@
 static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
 {
 	unsigned long flags;
-	ide_drive_t *drives = HWIF(drive)->drives;
+	ide_drive_t *drives = drive->channel->drives;
 	byte temp_b;
 	static const byte setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
 	static const byte recovery_counts[] =
@@ -224,7 +224,7 @@
 			{ DRWTIM0, DRWTIM1 },
 			{ DRWTIM2, DRWTIM3 }
 		};
-	int channel = (int) HWIF(drive)->channel;
+	int channel = drive->channel->unit;
 	int slave = (drives != drive);  /* Is this really the best way to determine this?? */
 
 	cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n", setup_count,
@@ -260,10 +260,10 @@
 	 * Program the address_setup clocks into ARTTIM reg,
 	 * and then the active/recovery counts into the DRWTIM reg
 	 */
-	(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
+	(void) pci_read_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave], &temp_b);
+	(void) pci_write_config_byte(drive->channel->pci_dev, arttim_regs[channel][slave],
 		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, drwtim_regs[channel][slave],
+	(void) pci_write_config_byte(drive->channel->pci_dev, drwtim_regs[channel][slave],
 		(byte) ((active_count << 4) | recovery_count));
 	cmdprintk ("Write %x to %x\n", ((byte) setup_count) | (temp_b & 0x3f), arttim_regs[channel][slave]);
 	cmdprintk ("Write %x to %x\n", (byte) ((active_count << 4) | recovery_count), drwtim_regs[channel][slave]);
@@ -333,10 +333,10 @@
 		setup_count, active_count, recovery_count);
 }
 
-static byte cmd680_taskfile_timing (ide_hwif_t *hwif)
+static byte cmd680_taskfile_timing(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
-	byte addr_mask		= (hwif->channel) ? 0xB2 : 0xA2;
+	byte addr_mask		= (hwif->unit) ? 0xB2 : 0xA2;
 	unsigned short		timing;
 
 	pci_read_config_word(dev, addr_mask, &timing);
@@ -353,7 +353,7 @@
 
 static void cmd680_tuneproc (ide_drive_t *drive, byte mode_wanted)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	byte			drive_pci;
 	unsigned short		speedt;
@@ -394,10 +394,10 @@
 
 static void config_cmd680_chipset_for_pio (ide_drive_t *drive, byte set_speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 addr_mask		= (hwif->unit) ? 0x84 : 0x80;
 	u8 speed		= 0x00;
 	u8 mode_pci		= 0x00;
 	u8 channel_timings	= cmd680_taskfile_timing(hwif);
@@ -420,7 +420,7 @@
 
 static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
 {
-        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
+        if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
 		config_cmd680_chipset_for_pio(drive, set_speed);
 	} else {
 		config_cmd64x_chipset_for_pio(drive, set_speed);
@@ -430,13 +430,13 @@
 static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
 {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	int err			= 0;
 
 	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 pciU			= (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
-	u8 pciD			= (hwif->channel) ? BMIDESR1 : BMIDESR0;
+	u8 pciU			= (hwif->unit) ? UDIDETCR1 : UDIDETCR0;
+	u8 pciD			= (hwif->unit) ? BMIDESR1 : BMIDESR0;
 	u8 regU			= 0;
 	u8 regD			= 0;
 
@@ -498,9 +498,9 @@
 
 static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 addr_mask		= (hwif->channel) ? 0x84 : 0x80;
+	u8 addr_mask		= (hwif->unit) ? 0x84 : 0x80;
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 dma_pci		= 0;
 	u8 udma_pci		= 0;
@@ -615,7 +615,7 @@
 static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
 	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 
 	byte speed		= 0x00;
@@ -741,7 +741,7 @@
 
 static int config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
 {
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
+	if (drive->channel->pci_dev->device == PCI_DEVICE_ID_CMD_680)
 		return (config_cmd680_chipset_for_dma(drive));
 	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
 }
@@ -749,7 +749,7 @@
 static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int class_rev	= 0;
 	byte can_ultra_33	= 0;
@@ -822,7 +822,7 @@
 no_dma_set:
 		config_chipset_for_pio(drive, 1);
 	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 static int cmd680_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
@@ -841,9 +841,9 @@
 {
 	byte dma_stat		= 0;
 	byte dma_alt_stat	= 0;
-	byte mask		= (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	byte mask		= (drive->channel->unit) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
+	unsigned long dma_base	= drive->channel->dma_base;
+	struct pci_dev *dev	= drive->channel->pci_dev;
 	byte jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
 
 	switch (func) {
@@ -856,8 +856,8 @@
 			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
 			if (jack_slap) {
 				byte dma_intr	= 0;
-				byte dma_mask	= (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (HWIF(drive)->channel) ? ARTTIM2 : CFR;
+				byte dma_mask	= (drive->channel->unit) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+				byte dma_reg	= (drive->channel->unit) ? ARTTIM2 : CFR;
 				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
 				/*
 				 * DAMN BMIDE is not connected to PCI space!
@@ -891,7 +891,7 @@
  */
 static int cmd646_1_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
 	byte dma_stat;
 
@@ -917,8 +917,8 @@
 static int cmd680_busproc (ide_drive_t * drive, int state)
 {
 #if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	struct ata_channel *hwif	= drive->channel;
+	u8 addr_mask		= (hwif->unit) ? 0xB0 : 0xA0;
 	u32 stat_config		= 0;
 
         pci_read_config_dword(hwif->pci_dev, addr_mask, &stat_config);
@@ -950,8 +950,8 @@
 static void cmd680_reset (ide_drive_t *drive)
 {
 #if 0
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 addr_mask		= (hwif->channel) ? 0xB0 : 0xA0;
+	struct ata_channel *hwif = drive->channel;
+	u8 addr_mask		= (hwif->unit) ? 0xB0 : 0xA0;
 	byte reset		= 0;
 
 	pci_read_config_byte(hwif->pci_dev, addr_mask, &reset);
@@ -1081,25 +1081,25 @@
 	return cmd64x_pci_init (dev);
 }
 
-unsigned int cmd680_ata66 (ide_hwif_t *hwif)
+unsigned int cmd680_ata66(struct ata_channel *hwif)
 {
 	byte ata66	= 0;
-	byte addr_mask	= (hwif->channel) ? 0xB0 : 0xA0;
+	byte addr_mask	= (hwif->unit) ? 0xB0 : 0xA0;
 
 	pci_read_config_byte(hwif->pci_dev, addr_mask, &ata66);
 	return (ata66 & 0x01) ? 1 : 0;
 }
 
-unsigned int cmd64x_ata66 (ide_hwif_t *hwif)
+unsigned int cmd64x_ata66(struct ata_channel *hwif)
 {
 	byte ata66 = 0;
-	byte mask = (hwif->channel) ? 0x02 : 0x01;
+	byte mask = (hwif->unit) ? 0x02 : 0x01;
 
 	pci_read_config_byte(hwif->pci_dev, BMIDECSR, &ata66);
 	return (ata66 & mask) ? 1 : 0;
 }
 
-unsigned int __init ata66_cmd64x (ide_hwif_t *hwif)
+unsigned int __init ata66_cmd64x(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	if (dev->device == PCI_DEVICE_ID_CMD_680)
@@ -1107,7 +1107,7 @@
 	return cmd64x_ata66(hwif);
 }
 
-void __init ide_init_cmd64x (ide_hwif_t *hwif)
+void __init ide_init_cmd64x(struct ata_channel *hwif)
 {
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned int class_rev;
diff -Nru a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c
--- a/drivers/ide/cs5530.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/cs5530.c	Wed Apr  3 17:11:15 2002
@@ -101,7 +101,7 @@
  * After chip reset, the PIO timings are set to 0x0000e132, which is not valid.
  */
 #define CS5530_BAD_PIO(timings) (((timings)&~0x80000000)==0x0000e132)
-#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->channel ? 0x30 : 0x20))
+#define CS5530_BASEREG(hwif)	(((hwif)->dma_base & ~0xf) + ((hwif)->unit ? 0x30 : 0x20))
 
 /*
  * cs5530_tuneproc() handles selection/setting of PIO modes
@@ -112,7 +112,7 @@
  */
 static void cs5530_tuneproc (ide_drive_t *drive, byte pio)	/* pio=255 means "autotune" */
 {
-	ide_hwif_t	*hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned int	format, basereg = CS5530_BASEREG(hwif);
 
 	if (pio == 255)
@@ -134,7 +134,7 @@
 static int cs5530_config_dma (ide_drive_t *drive)
 {
 	int			udma_ok = 1, mode = 0;
-	ide_hwif_t		*hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	int			unit = drive->select.b.unit;
 	ide_drive_t		*mate = &hwif->drives[unit^1];
 	struct hd_driveid	*id = drive->id;
@@ -344,7 +344,7 @@
  * This gets invoked by the IDE driver once for each channel,
  * and performs channel-specific pre-initialization before drive probing.
  */
-void __init ide_init_cs5530 (ide_hwif_t *hwif)
+void __init ide_init_cs5530(struct ata_channel *hwif)
 {
 	if (hwif->mate)
 		hwif->serialized = hwif->mate->serialized = 1;
diff -Nru a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c
--- a/drivers/ide/cy82c693.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/cy82c693.c	Wed Apr  3 17:11:14 2002
@@ -192,7 +192,7 @@
 	if (mode > drive->id->tDMA)  /* to be absolutly sure we have a valid mode */
 		mode = drive->id->tDMA;
 	
-        index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
+        index = (drive->channel->unit == 0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1;
 
 #if CY82C693_DEBUG_LOGS
        	/* for debug let's show the previous values */
@@ -200,7 +200,7 @@
 	OUT_BYTE(index, CY82_INDEX_PORT);
 	data = IN_BYTE(CY82_DATA_PORT);
 
-	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, (data&0x3), ((data>>2)&1));
+	printk (KERN_INFO "%s (ch=%d, dev=%d): DMA mode is %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, (data&0x3), ((data>>2)&1));
 #endif /* CY82C693_DEBUG_LOGS */
 
 	data = (byte)mode|(byte)(single<<2);
@@ -209,7 +209,7 @@
 	OUT_BYTE(data, CY82_DATA_PORT);
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, mode, single);
+	printk (KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, drive->channel->unit, drive->select.b.unit, mode, single);
 #endif /* CY82C693_DEBUG_INFO */
 
 	/* 
@@ -271,7 +271,7 @@
  */
 static void cy82c693_tune_drive (ide_drive_t *drive, byte pio)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev = hwif->pci_dev;
 	pio_clocks_t pclk;
 	unsigned int addrCtrl;
@@ -318,7 +318,7 @@
 		pci_read_config_byte(dev, CY82_IDE_SLAVE_8BIT, &pclk.time_8);
 	}
 
-	printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+	printk (KERN_INFO "%s (ch=%d, dev=%d): PIO timing is (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_LOGS */
 
         /* first let's calc the pio modes */
@@ -371,7 +371,7 @@
 	}	
 
 #if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->channel, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
+	printk (KERN_INFO "%s (ch=%d, dev=%d): set PIO timing to (addr=0x%X, ior=0x%X, iow=0x%X, 8bit=0x%X)\n", drive->name, hwif->unit, drive->select.b.unit, addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_INFO */
 }
 
@@ -431,7 +431,7 @@
 /*
  * the init function - called for each ide channel once
  */
-void __init ide_init_cy82c693(ide_hwif_t *hwif)
+void __init ide_init_cy82c693(struct ata_channel *hwif)
 {
 	hwif->chipset = ide_cy82c693;
 	hwif->tuneproc = cy82c693_tune_drive;
diff -Nru a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c
--- a/drivers/ide/dtc2278.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/dtc2278.c	Wed Apr  3 17:11:15 2002
@@ -89,7 +89,7 @@
 	 * 32bit I/O has to be enabled for *both* drives at the same time.
 	 */
 	drive->io_32bit = 1;
-	HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1;
+	drive->channel->drives[!drive->select.b.unit].io_32bit = 1;
 }
 
 void __init init_dtc2278 (void)
@@ -126,5 +126,5 @@
 	ide_hwifs[1].drives[1].no_unmask = 1;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
+	ide_hwifs[1].unit = 1;
 }
diff -Nru a/drivers/ide/gayle.c b/drivers/ide/gayle.c
--- a/drivers/ide/gayle.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/gayle.c	Wed Apr  3 17:11:14 2002
@@ -84,7 +84,7 @@
      *  Check and acknowledge the interrupt status
      */
 
-static int gayle_ack_intr_a4000(ide_hwif_t *hwif)
+static int gayle_ack_intr_a4000(struct ata_channel *hwif)
 {
     unsigned char ch;
 
@@ -94,7 +94,7 @@
     return 1;
 }
 
-static int gayle_ack_intr_a1200(ide_hwif_t *hwif)
+static int gayle_ack_intr_a1200(struct ata_channel *hwif)
 {
     unsigned char ch;
 
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/hpt34x.c	Wed Apr  3 17:11:14 2002
@@ -98,12 +98,12 @@
 	unsigned int reg1	= 0, tmp1 = 0;
 	unsigned int reg2	= 0, tmp2 = 0;
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
+	pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+	pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
+	tmp1 = ((0x00 << (3 * drive->dn)) | (reg1 & ~(7 << (3 * drive->dn))));
 	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+	pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+	pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
 }
 
 static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
@@ -122,13 +122,13 @@
 		lo_speed >>= 5;
 	}
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
+	pci_read_config_dword(drive->channel->pci_dev, 0x44, &reg1);
+	pci_read_config_dword(drive->channel->pci_dev, 0x48, &reg2);
 	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
 	tmp2 = ((hi_speed << drive->dn) | reg2);
 	err = ide_config_drive_speed(drive, speed);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
+	pci_write_config_dword(drive->channel->pci_dev, 0x44, tmp1);
+	pci_write_config_dword(drive->channel->pci_dev, 0x48, tmp2);
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
@@ -254,7 +254,7 @@
 	struct hd_driveid *id = drive->id;
 	ide_dma_action_t dma_func = ide_dma_on;
 
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -301,7 +301,7 @@
 		dma_func = ide_dma_off;
 #endif /* CONFIG_HPT34X_AUTODMA */
 
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 /*
@@ -314,7 +314,7 @@
 
 int hpt34x_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
 	unsigned int count, reading = 0;
 	byte dma_stat;
@@ -334,6 +334,7 @@
 			drive->waiting_for_dma = 1;
 			if (drive->type != ATA_DISK)
 				return 0;
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
 			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
@@ -408,7 +409,7 @@
 	return dev->irq;
 }
 
-void __init ide_init_hpt34x (ide_hwif_t *hwif)
+void __init ide_init_hpt34x(struct ata_channel *hwif)
 {
 	hwif->tuneproc = &hpt34x_tune_drive;
 	hwif->speedproc = &hpt34x_tune_chipset;
diff -Nru a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c
--- a/drivers/ide/hpt366.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/hpt366.c	Wed Apr  3 17:11:14 2002
@@ -485,7 +485,7 @@
 static void hpt366_tune_chipset (ide_drive_t *drive, byte speed)
 {
 	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	byte regfast		= (drive->channel->unit) ? 0x55 : 0x51;
 			/*
 			 * since the channel is always 0 it does not matter.
 			 */
@@ -497,11 +497,11 @@
 	/*
 	 * Disable the "fast interrupt" prediction. 
 	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
+	pci_read_config_byte(drive->channel->pci_dev, regfast, &drive_fast);
 	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
+		pci_write_config_byte(drive->channel->pci_dev, regfast, drive_fast & ~0x20);
 
-	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
+	pci_read_config_dword(drive->channel->pci_dev, regtime, &reg1);
 	/* detect bus speed by looking at control reg timing: */
 	switch((reg1 >> 8) & 7) {
 		case 5:
@@ -531,18 +531,18 @@
 	}	
 	reg2 &= ~0x80000000;
 
-	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
+	pci_write_config_dword(drive->channel->pci_dev, regtime, reg2);
 }
 
 static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
+	byte regfast		= (drive->channel->unit) ? 0x55 : 0x51;
 	unsigned int list_conf	= 0;
 	unsigned int drive_conf = 0;
 	unsigned int conf_mask	= (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
 	byte drive_pci		= 0x40 + (drive->dn * 4);
 	byte new_fast, drive_fast		= 0;
-	struct pci_dev *dev 	= HWIF(drive)->pci_dev;
+	struct pci_dev *dev	= drive->channel->pci_dev;
 
 	/*
 	 * Disable the "fast interrupt" prediction.
@@ -561,7 +561,7 @@
 		new_fast |= 0x01;
 #endif
 	if (new_fast != drive_fast)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, new_fast);
+		pci_write_config_byte(drive->channel->pci_dev, regfast, new_fast);
 
 	list_conf = pci_bus_clock_list(speed, 
 				       (struct chipset_bus_clock_list_entry *)
@@ -585,7 +585,7 @@
 	if (!drive->init_speed)
 		drive->init_speed = speed;
 
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+	if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
 		hpt370_tune_chipset(drive, speed);
         } else {
                 hpt366_tune_chipset(drive, speed);
@@ -670,7 +670,7 @@
 	if ((id->dma_ultra & 0x0020) &&
 	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
 	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
+	    (pci_rev_check_hpt3xx(drive->channel->pci_dev)) &&
 	    (ultra66)) {
 		speed = XFER_UDMA_5;
 	} else if ((id->dma_ultra & 0x0010) &&
@@ -720,23 +720,23 @@
 	if (drive->quirk_list) {
 		/* drives in the quirk_list may not like intr setups/cleanups */
 	} else {
-		OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
+		OUT_BYTE((drive)->ctl|2, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
 	}
 }
 
 void hpt3xx_maskproc (ide_drive_t *drive, int mask)
 {
 	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
+		if (pci_rev_check_hpt3xx(drive->channel->pci_dev)) {
 			byte reg5a = 0;
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
+			pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5a);
 			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+				pci_write_config_byte(drive->channel->pci_dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
 		} else {
 			if (mask) {
-				disable_irq(HWIF(drive)->irq);
+				disable_irq(drive->channel->irq);
 			} else {
-				enable_irq(HWIF(drive)->irq);
+				enable_irq(drive->channel->irq);
 			}
 		}
 	} else {
@@ -750,7 +750,7 @@
 	struct hd_driveid *id = drive->id;
 	ide_dma_action_t dma_func = ide_dma_on;
 
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -791,7 +791,7 @@
 
 		config_chipset_for_pio(drive);
 	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 /*
@@ -803,7 +803,7 @@
 int hpt366_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
 	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-	unsigned long dma_base = HWIF(drive)->dma_base;
+	unsigned long dma_base = drive->channel->dma_base;
 
 	switch (func) {
 		case ide_dma_check:
@@ -812,21 +812,21 @@
 			dma_stat = inb(dma_base+2);
 			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
 		case ide_dma_lostirq:
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5ah);
+			pci_read_config_byte(drive->channel->pci_dev, 0x50, &reg50h);
+			pci_read_config_byte(drive->channel->pci_dev, 0x52, &reg52h);
+			pci_read_config_byte(drive->channel->pci_dev, 0x5a, &reg5ah);
 			printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
 				drive->name,
 				ide_dmafunc_verbose(func),
 				reg50h, reg52h, reg5ah);
 			if (reg5ah & 0x10)
-				pci_write_config_byte(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
+				pci_write_config_byte(drive->channel->pci_dev, 0x5a, reg5ah & ~0x10);
 			/* fall through to a reset */
 #if 0
 		case ide_dma_begin:
 		case ide_dma_end:
 			/* reset the chips state over and over.. */
-			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
+			pci_write_config_byte(drive->channel->pci_dev, 0x51, 0x13);
 #endif
 			break;
 		case ide_dma_timeout:
@@ -838,10 +838,10 @@
 
 int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
-	byte regstate = hwif->channel ? 0x54 : 0x50;
-	byte reginfo = hwif->channel ? 0x56 : 0x52;
+	byte regstate = hwif->unit ? 0x54 : 0x50;
+	byte reginfo = hwif->unit ? 0x56 : 0x52;
 	byte dma_stat;
 
 	switch (func) {
@@ -899,23 +899,23 @@
 void hpt3xx_reset (ide_drive_t *drive)
 {
 #if 0
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
-	byte reset		= (HWIF(drive)->channel) ? 0x80 : 0x40;
+	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
+	byte reset		= (drive->channel->unit) ? 0x80 : 0x40;
 	byte reg59h		= 0;
 
-	pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
-	pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
+	pci_read_config_byte(drive->channel->pci_dev, 0x59, &reg59h);
+	pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h|reset);
+	pci_write_config_byte(drive->channel->pci_dev, 0x59, reg59h);
 #endif
 }
 
 #if 0
 static int hpt3xx_tristate (ide_drive_t * drive, int state)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif	= drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
-	byte reset		= (hwif->channel) ? 0x80 : 0x40;
-	byte state_reg		= (hwif->channel) ? 0x57 : 0x53;
+	byte reset		= (hwif->unit) ? 0x80 : 0x40;
+	byte state_reg		= (hwif->unit) ? 0x57 : 0x53;
 	byte reg59h		= 0;
 	byte regXXh		= 0;
 
@@ -951,7 +951,7 @@
 #define TRISTATE_BIT  0x8000
 static int hpt370_busproc(ide_drive_t * drive, int state)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	byte tristate, resetmask, bus_reg;
 	u16 tri_reg;
 
@@ -960,7 +960,7 @@
 
 	hwif->bus_state = state;
 
-	if (hwif->channel) { 
+	if (hwif->unit) { 
 		/* secondary channel */
 		tristate = 0x56;
 		resetmask = 0x80; 
@@ -1136,10 +1136,10 @@
 	return dev->irq;
 }
 
-unsigned int __init ata66_hpt366 (ide_hwif_t *hwif)
+unsigned int __init ata66_hpt366(struct ata_channel *hwif)
 {
 	byte ata66	= 0;
-	byte regmask	= (hwif->channel) ? 0x01 : 0x02;
+	byte regmask	= (hwif->unit) ? 0x01 : 0x02;
 
 	pci_read_config_byte(hwif->pci_dev, 0x5a, &ata66);
 #ifdef DEBUG
@@ -1150,7 +1150,7 @@
 	return ((ata66 & regmask) ? 0 : 1);
 }
 
-void __init ide_init_hpt366 (ide_hwif_t *hwif)
+void __init ide_init_hpt366(struct ata_channel *hwif)
 {
 	int hpt_rev;
 
@@ -1210,12 +1210,12 @@
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-void __init ide_dmacapable_hpt366 (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_hpt366(struct ata_channel *hwif, unsigned long dmabase)
 {
 	byte masterdma = 0, slavedma = 0;
 	byte dma_new = 0, dma_old = inb(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
+	byte primary	= hwif->unit ? 0x4b : 0x43;
+	byte secondary	= hwif->unit ? 0x4f : 0x47;
 	unsigned long flags;
 
 	__save_flags(flags);	/* local CPU only */
diff -Nru a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c
--- a/drivers/ide/ht6560b.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ht6560b.c	Wed Apr  3 17:11:14 2002
@@ -321,7 +321,7 @@
 			ide_hwifs[1].serialized = 1;  /* is this needed? */
 			ide_hwifs[0].mate = &ide_hwifs[1];
 			ide_hwifs[1].mate = &ide_hwifs[0];
-			ide_hwifs[1].channel = 1;
+			ide_hwifs[1].unit = 1;
 			
 			/*
 			 * Setting default configurations for drives
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/icside.c	Wed Apr  3 17:11:14 2002
@@ -224,7 +224,7 @@
 #define NR_ENTRIES 256
 #define TABLE_SIZE (NR_ENTRIES * 8)
 
-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
 {
 	request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
 	struct scatterlist *sg = hwif->sg_table;
@@ -245,16 +245,16 @@
 static int
 icside_build_dmatable(ide_drive_t *drive, int reading)
 {
-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	return drive->channel->sg_nents = ide_build_sglist(drive->channel, HWGROUP(drive)->rq);
 }
 
 /* Teardown mappings after DMA has completed.  */
 static void icside_destroy_dmatable(ide_drive_t *drive)
 {
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
+	struct scatterlist *sg = drive->channel->sg_table;
+	int nents = drive->channel->sg_nents;
 
-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
+	pci_unmap_sg(NULL, sg, nents, drive->channel->sg_dma_direction);
 }
 
 /*
@@ -333,7 +333,7 @@
 	int i;
 	byte stat, dma_stat;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
@@ -356,7 +356,7 @@
 icside_dma_check(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	int autodma = hwif->autodma;
 	int xfer_mode = XFER_PIO_2;
 	int func = ide_dma_off_quietly;
@@ -397,7 +397,7 @@
 static int
 icside_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	int count, reading = 0;
 
 	switch (func) {
@@ -436,14 +436,15 @@
 		 */
 		set_dma_speed(hwif->hw.dma, drive->drive_data);
 
-		set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+		set_dma_sg(hwif->hw.dma, drive->channel->sg_table, count);
 		set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ
 			     : DMA_MODE_WRITE);
 
 		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
+		if (drive->type != ATA_DISK)
 			return 0;
 
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
 		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
 			 IDE_COMMAND_REG);
@@ -473,7 +474,7 @@
 }
 
 static int
-icside_setup_dma(ide_hwif_t *hwif, int autodma)
+icside_setup_dma(struct ata_channel *hwif, int autodma)
 {
 	printk("    %s: SG-DMA", hwif->name);
 
@@ -498,7 +499,7 @@
 	return 0;
 }
 
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
 {
 	if (hwif->sg_table) {
 		kfree(hwif->sg_table);
@@ -507,10 +508,10 @@
 }
 #endif
 
-static ide_hwif_t *
+static struct ata_channel *
 icside_find_hwif(unsigned long dataport)
 {
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	int index;
 
 	for (index = 0; index < MAX_HWIFS; ++index) {
@@ -530,11 +531,11 @@
 	return hwif;
 }
 
-static ide_hwif_t *
+static struct ata_channel *
 icside_setup(unsigned long base, struct cardinfo *info, int irq)
 {
 	unsigned long port = base + info->dataoffset;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 
 	hwif = icside_find_hwif(base);
 	if (hwif) {
@@ -562,7 +563,7 @@
 static int __init icside_register_v5(struct expansion_card *ec, int autodma)
 {
 	unsigned long slot_port;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 
 	slot_port = ecard_address(ec, ECARD_MEMC, 0);
 
@@ -584,7 +585,8 @@
 static int __init icside_register_v6(struct expansion_card *ec, int autodma)
 {
 	unsigned long slot_port, port;
-	ide_hwif_t *hwif, *mate;
+	struct ata_channel *hwif;
+	struct ata_channel *mate;
 	int sel = 0;
 
 	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
@@ -620,7 +622,7 @@
 			hwif->hw.dma  = ec->dma;
 			hwif->hw.priv = (void *)
 					(port + ICS_ARCIN_V6_INTRSTAT_1);
-			hwif->channel = 0;
+			hwif->unit = 0;
 			icside_setup_dma(hwif, autodma);
 		}
 		if (mate) {
@@ -629,7 +631,7 @@
 			mate->hw.dma  = ec->dma;
 			mate->hw.priv = (void *)
 					(port + ICS_ARCIN_V6_INTRSTAT_2);
-			mate->channel = 1;
+			mate->unit = 1;
 			icside_setup_dma(mate, autodma);
 		}
 	}
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ide-cd.c	Wed Apr  3 17:11:15 2002
@@ -723,9 +723,9 @@
 
 	if (info->dma) {
 		if (info->cmd == READ) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);
+			info->dma = !drive->channel->dmaproc(ide_dma_read, drive);
 		} else if (info->cmd == WRITE) {
-			info->dma = !HWIF(drive)->dmaproc(ide_dma_write, drive);
+			info->dma = !drive->channel->dmaproc(ide_dma_write, drive);
 		} else {
 			printk("ide-cd: DMA set, but not allowed\n");
 		}
@@ -740,11 +740,12 @@
 	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
- 
+
 	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		(void) drive->channel->dmaproc(ide_dma_begin, drive);
 
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
 		return ide_started;
@@ -787,6 +788,7 @@
 	}
 
 	/* Arm the interrupt handler. */
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler (drive, handler, timeout, cdrom_timer_expiry);
 
 	/* Send the command to the device. */
@@ -899,8 +901,8 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+		if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive)))
+			drive->channel->dmaproc(ide_dma_off, drive);
 	}
 
 	if (cdrom_decode_status (&startstop, drive, 0, &stat))
@@ -1005,7 +1007,9 @@
 
 	/* Done moving data!
 	   Wait for another interrupt. */
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
+
 	return ide_started;
 }
 
@@ -1335,6 +1339,8 @@
 	}
 
 	/* Now we wait for another interrupt. */
+
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);
 	return ide_started;
 }
@@ -1476,9 +1482,9 @@
 	/* Check for errors. */
 	if (dma) {
 		info->dma = 0;
-		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {
+		if ((dma_error = drive->channel->dmaproc(ide_dma_end, drive))) {
 			printk("ide-cd: write dma error\n");
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			drive->channel->dmaproc(ide_dma_off, drive);
 		}
 	}
 
@@ -1559,6 +1565,7 @@
 	}
 
 	/* re-arm handler */
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -2021,14 +2028,14 @@
 
 	/* Now try to get the total cdrom capacity. */
 	minor = (drive->select.b.unit) << PARTN_BITS;
-	dev = mk_kdev(HWIF(drive)->major, minor);
+	dev = mk_kdev(drive->channel->major, minor);
 	stat = cdrom_get_last_written(dev, &toc->capacity);
 	if (stat)
 		stat = cdrom_read_capacity(drive, &toc->capacity, sense);
 	if (stat)
 		toc->capacity = 0x1fffff;
 
-	HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
+	drive->channel->gd->sizes[drive->select.b.unit << PARTN_BITS] = (toc->capacity * SECTORS_PER_FRAME) >> (BLOCK_SIZE_BITS - 9);
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
 
 	/* Remember that we've read this stuff. */
@@ -2487,7 +2494,7 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
+	devinfo->dev = mk_kdev(drive->channel->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
 	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2519,7 +2526,7 @@
 	 */
 
 	devinfo->de = devfs_register(drive->de, "cd", DEVFS_FL_DEFAULT,
-				     HWIF(drive)->major, minor,
+				     drive->channel->major, minor,
 				     S_IFBLK | S_IRUGO | S_IWUGO,
 				     ide_fops, NULL);
 
@@ -2661,7 +2668,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) drive->channel->dmaproc(ide_dma_verbose, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -2684,8 +2691,8 @@
 	/*
 	 * default to read-only always and fix latter at the bottom
 	 */
-	set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
-	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	set_device_ro(mk_kdev(drive->channel->major, minor), 1);
+	set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
 	blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
 	blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2807,7 +2814,7 @@
 	nslots = ide_cdrom_probe_capabilities (drive);
 
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-		set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
+		set_device_ro(mk_kdev(drive->channel->major, minor), 0);
 
 	if (ide_cdrom_register (drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2854,7 +2861,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
+	return cdrom_media_changed(mk_kdev (drive->channel->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2875,14 +2882,14 @@
 
 	/* for general /dev/cdrom like mounting, one big disc */
 	drive->part[0].nr_sects = toc->capacity * SECTORS_PER_FRAME;
-	HWIF(drive)->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
+	drive->channel->gd->sizes[minor] = toc->capacity * BLOCKS_PER_FRAME;
 
 	/*
 	 * reset block size, ide_revalidate_disk incorrectly sets it to
 	 * 1024 even for CDROM's
 	 */
-	blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
-	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	blk_size[drive->channel->major] = drive->channel->gd->sizes;
+	set_blocksize(mk_kdev(drive->channel->major, minor), CD_FRAMESIZE);
 }
 
 static
@@ -2984,15 +2991,14 @@
 		memset (info, 0, sizeof (struct cdrom_info));
 		drive->driver_data = info;
 
-		/* ATA-PATTERN */
-		ata_ops(drive)->busy++;
+		MOD_INC_USE_COUNT;
 		if (ide_cdrom_setup (drive)) {
-			ata_ops(drive)->busy--;
+			MOD_DEC_USE_COUNT;
 			if (ide_cdrom_cleanup (drive))
 				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
 			continue;
 		}
-		ata_ops(drive)->busy--;
+		MOD_DEC_USE_COUNT;
 
 		failed--;
 	}
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/ide/ide-disk.c	Wed Apr  3 17:11:13 2002
@@ -51,7 +51,7 @@
 #include <asm/io.h>
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-#define IS_PDC4030_DRIVE (HWIF(drive)->chipset == ide_pdc4030)
+#define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030)
 #else
 #define IS_PDC4030_DRIVE (0)	/* auto-NULLs out pdc4030 code */
 #endif
@@ -106,51 +106,7 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-static ide_startstop_t chs_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block);
-static ide_startstop_t lba48_do_request(ide_drive_t *drive, struct request *rq, unsigned long long block);
-
-/*
- * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
- * otherwise, to address sectors.  It also takes care of issuing special
- * DRIVE_CMDs.
- */
-static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	/*
-	 * Wait until all request have bin finished.
-	 */
-
-	while (drive->blocked) {
-		yield();
-		// panic("ide: Request while drive blocked?");
-	}
-
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
-		ide_end_request(drive, 0);
-		return ide_stopped;
-	}
-
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
-
-		return promise_rw_disk(drive, rq, block);
-	}
-
-	/* 48-bit LBA */
-	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
-		return lba48_do_request(drive, rq, block);
-
-	/* 28-bit LBA */
-	if (drive->select.b.lba)
-		return lba28_do_request(drive, rq, block);
-
-	/* 28-bit CHS */
-	return chs_do_request(drive, rq, block);
-}
-
-static task_ioreg_t get_command(ide_drive_t *drive, int cmd)
+static u8 get_command(ide_drive_t *drive, int cmd)
 {
 	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
@@ -158,20 +114,38 @@
 	lba48bit = drive->addressing;
 #endif
 
-	if (cmd == READ) {
-		if (drive->using_dma)
-			return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
-		else if (drive->mult_count)
-			return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-		else
-			return (lba48bit) ? WIN_READ_EXT : WIN_READ;
-	} else if (cmd == WRITE) {
-		if (drive->using_dma)
-			return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-		else if (drive->mult_count)
-			return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-		else
-			return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	if (lba48bit) {
+		if (cmd == READ) {
+			if (drive->using_dma)
+				return WIN_READDMA_EXT;
+			else if (drive->mult_count)
+				return WIN_MULTREAD_EXT;
+			else
+				return WIN_READ_EXT;
+		} else if (cmd == WRITE) {
+			if (drive->using_dma)
+				return WIN_WRITEDMA_EXT;
+			else if (drive->mult_count)
+				return WIN_MULTWRITE_EXT;
+			else
+				return WIN_WRITE_EXT;
+		}
+	} else {
+		if (cmd == READ) {
+			if (drive->using_dma)
+				return WIN_READDMA;
+			else if (drive->mult_count)
+				return WIN_MULTREAD;
+			else
+				return WIN_READ;
+		} else if (cmd == WRITE) {
+			if (drive->using_dma)
+				return WIN_WRITEDMA;
+			else if (drive->mult_count)
+				return WIN_MULTWRITE;
+			else
+				return WIN_WRITE;
+		}
 	}
 	return WIN_NOP;
 }
@@ -183,27 +157,27 @@
 	ide_task_t			args;
 	int				sectors;
 
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
-
 	unsigned int track	= (block / drive->sect);
 	unsigned int sect	= (block % drive->sect) + 1;
 	unsigned int head	= (track % drive->head);
 	unsigned int cyl	= (track / drive->head);
 
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 
 	sectors = rq->nr_sectors;
 	if (sectors == 256)
 		sectors = 0;
 
 	taskfile.sector_count	= sectors;
+
 	taskfile.sector_number	= sect;
 	taskfile.low_cylinder	= cyl;
 	taskfile.high_cylinder	= (cyl>>8);
+
 	taskfile.device_head	= head;
 	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
+	taskfile.command	=  get_command(drive, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -214,14 +188,17 @@
 	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
 
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.taskfile = taskfile;
+	args.hobfile = hobfile;
 	ide_cmd_type_parser(&args);
-	args.rq	= rq;
-	args.block = block;
 	rq->special = &args;
 
-	return do_rw_taskfile(drive, &args);
+	return ata_taskfile(drive,
+			&args.taskfile,
+			&args.hobfile,
+			args.handler,
+			args.prehandler,
+			rq);
 }
 
 static ide_startstop_t lba28_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
@@ -231,22 +208,22 @@
 	ide_task_t			args;
 	int				sectors;
 
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
-
 	sectors = rq->nr_sectors;
 	if (sectors == 256)
 		sectors = 0;
 
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 
 	taskfile.sector_count	= sectors;
 	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f);
+	taskfile.low_cylinder	= (block >>= 8);
+
+	taskfile.high_cylinder	= (block >>= 8);
+
+	taskfile.device_head	= ((block >> 8) & 0x0f);
 	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
+	taskfile.command	= get_command(drive, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -257,14 +234,17 @@
 	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
 
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.taskfile = taskfile;
+	args.hobfile = hobfile;
 	ide_cmd_type_parser(&args);
-	args.rq = rq;
-	args.block = block;
 	rq->special = &args;
 
-	return do_rw_taskfile(drive, &args);
+	return ata_taskfile(drive,
+			&args.taskfile,
+			&args.hobfile,
+			args.handler,
+			args.prehandler,
+			rq);
 }
 
 /*
@@ -280,10 +260,8 @@
 	ide_task_t			args;
 	int				sectors;
 
-	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
+	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
+	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 
 	sectors = rq->nr_sectors;
 	if (sectors == 65536)
@@ -297,16 +275,18 @@
 		hobfile.sector_count	= 0x00;
 	}
 
-	taskfile.sector_number	= block;	/* low lba */
-	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
-	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	hobfile.sector_number	= (block>>=8);	/* low lba */
-	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
-	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
+	taskfile.sector_number	= block;		/* low lba */
+	taskfile.low_cylinder	= (block >>= 8);	/* mid lba */
+	taskfile.high_cylinder	= (block >>= 8);	/* hi  lba */
+
+	hobfile.sector_number	= (block >>= 8);	/* low lba */
+	hobfile.low_cylinder	= (block >>= 8);	/* mid lba */
+	hobfile.high_cylinder	= (block >>= 8);	/* hi  lba */
+
 	taskfile.device_head	= drive->select.all;
 	hobfile.device_head	= taskfile.device_head;
 	hobfile.control		= (drive->ctl|0x80);
-	taskfile.command	= command;
+	taskfile.command	= get_command(drive, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -317,14 +297,57 @@
 	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
 #endif
 
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
+	args.taskfile = taskfile;
+	args.hobfile = hobfile;
 	ide_cmd_type_parser(&args);
-	args.rq = rq;
-	args.block = block;
 	rq->special = &args;
 
-	return do_rw_taskfile(drive, &args);
+	return ata_taskfile(drive,
+			&args.taskfile,
+			&args.hobfile,
+			args.handler,
+			args.prehandler,
+			rq);
+}
+
+/*
+ * Issue a READ or WRITE command to a disk, using LBA if supported, or CHS
+ * otherwise, to address sectors.  It also takes care of issuing special
+ * DRIVE_CMDs.
+ */
+static ide_startstop_t idedisk_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	/*
+	 * Wait until all request have bin finished.
+	 */
+
+	while (drive->blocked) {
+		yield();
+		printk("ide: Request while drive blocked?");
+	}
+
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "idedisk_do_request - bad command");
+		ide_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	if (IS_PDC4030_DRIVE) {
+		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+
+		return promise_rw_disk(drive, rq, block);
+	}
+
+	/* 48-bit LBA */
+	if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing))
+		return lba48_do_request(drive, rq, block);
+
+	/* 28-bit LBA */
+	if (drive->select.b.lba)
+		return lba28_do_request(drive, rq, block);
+
+	/* 28-bit CHS */
+	return chs_do_request(drive, rq, block);
 }
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
@@ -333,10 +356,14 @@
 	if (drive->removable && drive->usage == 1) {
 		struct hd_drive_task_hdr taskfile;
 		struct hd_drive_hob_hdr hobfile;
+
 		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
 		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
 		check_disk_change(inode->i_rdev);
+
 		taskfile.command = WIN_DOORLOCK;
+
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
@@ -353,13 +380,14 @@
 {
 	struct hd_drive_task_hdr taskfile;
 	struct hd_drive_hob_hdr hobfile;
+
 	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
 	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	if (drive->id->cfs_enable_2 & 0x2400) {
-		taskfile.command	= WIN_FLUSH_CACHE_EXT;
-	} else {
-		taskfile.command	= WIN_FLUSH_CACHE;
-	}
+	if (drive->id->cfs_enable_2 & 0x2400)
+		taskfile.command = WIN_FLUSH_CACHE_EXT;
+	else
+		taskfile.command = WIN_FLUSH_CACHE;
+
 	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
 }
 
@@ -368,9 +396,12 @@
 	if (drive->removable && !drive->usage) {
 		struct hd_drive_task_hdr taskfile;
 		struct hd_drive_hob_hdr hobfile;
+
 		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
 		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
 		invalidate_bdev(inode->i_bdev, 0);
+
 		taskfile.command = WIN_DOORUNLOCK;
 		if (drive->doorlocking &&
 		    ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
@@ -404,21 +435,23 @@
 
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.handler				= task_no_data_intr;
+	args.taskfile.device_head = 0x40;
+	args.taskfile.command = WIN_READ_NATIVE_MAX;
+	args.handler = task_no_data_intr;
 
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-		     | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-		     | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-		     | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	if ((args.taskfile.command & 0x01) == 0) {
+		addr = ((args.taskfile.device_head & 0x0f) << 24)
+		     | (args.taskfile.high_cylinder << 16)
+		     | (args.taskfile.low_cylinder <<  8)
+		     | args.taskfile.sector_number;
 	}
+
 	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+
 	return addr;
 }
 
@@ -430,24 +463,26 @@
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 
-	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.handler				= task_no_data_intr;
+	args.taskfile.device_head = 0x40;
+	args.taskfile.command = WIN_READ_NATIVE_MAX_EXT;
+	args.handler = task_no_data_intr;
 
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
 	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
-			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
-			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+	if ((args.taskfile.command & 0x01) == 0) {
+		u32 high = (args.hobfile.high_cylinder << 16) |
+			   (args.hobfile.low_cylinder << 8) |
+			    args.hobfile.sector_number;
+		u32 low  = (args.taskfile.high_cylinder << 16) |
+			   (args.taskfile.low_cylinder << 8) |
+			    args.taskfile.sector_number;
 		addr = ((__u64)high << 24) | low;
 	}
+
 	addr++;	/* since the return value is (maxlba - 1), we add 1 */
+
 	return addr;
 }
 
@@ -464,20 +499,22 @@
 	addr_req--;
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>  8) & 0xff);
-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
-	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.handler				= task_no_data_intr;
+
+	args.taskfile.sector_number = (addr_req >> 0);
+	args.taskfile.low_cylinder = (addr_req >> 8);
+	args.taskfile.high_cylinder = (addr_req >> 16);
+
+	args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
+	args.taskfile.command = WIN_SET_MAX;
+	args.handler = task_no_data_intr;
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24)
-			 | ((args.tfRegister[  IDE_HCYL_OFFSET]       ) << 16)
-			 | ((args.tfRegister[  IDE_LCYL_OFFSET]       ) <<  8)
-			 | ((args.tfRegister[IDE_SECTOR_OFFSET]       ));
+	if ((args.taskfile.command & 0x01) == 0) {
+		addr_set = ((args.taskfile.device_head & 0x0f) << 24)
+			 | (args.taskfile.high_cylinder << 16)
+			 | (args.taskfile.low_cylinder <<  8)
+			 | args.taskfile.sector_number;
 	}
 	addr_set++;
 	return addr_set;
@@ -491,27 +528,31 @@
 	addr_req--;
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
-	args.tfRegister[IDE_SECTOR_OFFSET]	= ((addr_req >>  0) & 0xff);
-	args.tfRegister[IDE_LCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
-	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >>= 8) & 0xff);
-	args.tfRegister[IDE_SELECT_OFFSET]      = 0x40;
-	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX_EXT;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-        args.handler				= task_no_data_intr;
+
+	args.taskfile.sector_number = (addr_req >>  0);
+	args.taskfile.low_cylinder = (addr_req >>= 8);
+	args.taskfile.high_cylinder = (addr_req >>= 8);
+	args.taskfile.device_head = 0x40;
+	args.taskfile.command = WIN_SET_MAX_EXT;
+
+	args.hobfile.sector_number = (addr_req >>= 8);
+	args.hobfile.low_cylinder = (addr_req >>= 8);
+	args.hobfile.high_cylinder = (addr_req >>= 8);
+
+	args.hobfile.device_head = 0x40;
+	args.hobfile.control = (drive->ctl | 0x80);
+
+        args.handler = task_no_data_intr;
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
-	if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) {
-		u32 high = ((args.hobRegister[IDE_HCYL_OFFSET_HOB])<<16) |
-			   ((args.hobRegister[IDE_LCYL_OFFSET_HOB])<<8) |
-			    (args.hobRegister[IDE_SECTOR_OFFSET_HOB]);
-		u32 low  = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) |
-			   ((args.tfRegister[IDE_LCYL_OFFSET])<<8) |
-			    (args.tfRegister[IDE_SECTOR_OFFSET]);
+	if ((args.taskfile.command & 0x01) == 0) {
+		u32 high = (args.hobfile.high_cylinder << 16) |
+			   (args.hobfile.low_cylinder << 8) |
+			    args.hobfile.sector_number;
+		u32 low  = (args.taskfile.high_cylinder << 16) |
+			   (args.taskfile.low_cylinder << 8) |
+			    args.taskfile.sector_number;
 		addr_set = ((__u64)high << 24) | low;
 	}
 	return addr_set;
@@ -572,10 +613,10 @@
 				drive->select.b.lba = 1;
 				drive->id->lba_capacity_2 = capacity_2;
                         }
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
 			printk("%s: setmax_ext LBA %llu, native  %llu\n",
 				drive->name, set_max_ext, capacity_2);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
 		}
 		drive->bios_cyl		= drive->cyl;
 		drive->capacity48	= capacity_2;
@@ -598,10 +639,10 @@
 			drive->select.b.lba = 1;
 			drive->id->lba_capacity = capacity;
 		}
-#else /* !CONFIG_IDEDISK_STROKE */
+#else
 		printk("%s: setmax LBA %lu, native  %lu\n",
 			drive->name, set_max, capacity);
-#endif /* CONFIG_IDEDISK_STROKE */
+#endif
 	}
 
 	drive->capacity = capacity;
@@ -643,7 +684,7 @@
 			taskfile.command = WIN_SPECIFY;
 			handler	= set_geometry_intr;;
 		}
-		do_taskfile(drive, &taskfile, &hobfile, handler);
+		ata_taskfile(drive, &taskfile, &hobfile, handler, NULL, NULL);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
 		if (!IS_PDC4030_DRIVE) {
@@ -653,7 +694,7 @@
 			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 			taskfile.sector_count	= drive->sect;
 			taskfile.command	= WIN_RESTORE;
-			do_taskfile(drive, &taskfile, &hobfile, recal_intr);
+			ata_taskfile(drive, &taskfile, &hobfile, recal_intr, NULL, NULL);
 		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
@@ -666,7 +707,7 @@
 			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 			taskfile.sector_count	= drive->mult_req;
 			taskfile.command	= WIN_SETMULT;
-			do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
+			ata_taskfile(drive, &taskfile, &hobfile, set_multmode_intr, NULL, NULL);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -915,6 +956,9 @@
 	 * already been done...
 	 */
 
+	if (level != SUSPEND_SAVE_STATE)
+		return 0;
+
 	/* wait until all commands are finished */
 	printk("ide_disk_suspend()\n");
 	while (HWGROUP(drive)->handler)
@@ -934,6 +978,9 @@
 static int idedisk_resume(struct device *dev, u32 level)
 {
 	ide_drive_t *drive = dev->driver_data;
+
+	if (level != RESUME_RESTORE_STATE)
+		return 0;
 	if (!drive->blocked)
 		panic("ide: Resume but not suspended?\n");
 
@@ -979,7 +1026,7 @@
 		}
 	}
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		ide_hwif_t *hwif = HWIF(drive);
+		struct ata_channel *hwif = drive->channel;
 
 		if (drive != &hwif->drives[i])
 		    continue;
@@ -997,7 +1044,7 @@
 	    sprintf(drive->device.bus_id, "%d", drvid);
 	    sprintf(drive->device.name, "ide-disk");
 	    drive->device.driver = &idedisk_devdrv;
-	    drive->device.parent = &HWIF(drive)->device;
+	    drive->device.parent = &drive->channel->dev;
 	    drive->device.driver_data = drive;
 	    device_register(&drive->device);
 	}
@@ -1045,11 +1092,11 @@
 	if (id->buf_size)
 		printk (" w/%dKiB Cache", id->buf_size/2);
 
-	printk(", CHS=%d/%d/%d", 
+	printk(", CHS=%d/%d/%d",
 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (drive->using_dma)
-		(void) HWIF(drive)->dmaproc(ide_dma_verbose, drive);
+		(void) drive->channel->dmaproc(ide_dma_verbose, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	printk("\n");
 
@@ -1074,8 +1121,11 @@
 	(void) probe_lba_addressing(drive, 1);
 }
 
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
 {
+	if (!drive)
+	    return 0;
+
 	put_device(&drive->device);
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (idedisk_flushcache(drive))
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ide-dma.c	Wed Apr  3 17:11:14 2002
@@ -204,7 +204,7 @@
 {
 	byte stat, dma_stat;
 
-	dma_stat = HWIF(drive)->dmaproc(ide_dma_end, drive);
+	dma_stat = drive->channel->dmaproc(ide_dma_end, drive);
 	stat = GET_STAT();			/* get drive status */
 	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
 		if (!dma_stat) {
@@ -219,7 +219,7 @@
 	return ide_error(drive, "dma_intr", stat);
 }
 
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_build_sglist(struct ata_channel *hwif, struct request *rq)
 {
 	request_queue_t *q = &hwif->drives[DEVICE_NR(rq->rq_dev) & 1].queue;
 	struct scatterlist *sg = hwif->sg_table;
@@ -238,7 +238,7 @@
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
-static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
+static int ide_raw_build_sglist(struct ata_channel *hwif, struct request *rq)
 {
 	struct scatterlist *sg = hwif->sg_table;
 	int nents = 0;
@@ -285,7 +285,7 @@
  */
 int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned int *table = hwif->dmatable_cpu;
 #ifdef CONFIG_BLK_DEV_TRM290
 	unsigned int is_trm290_chipset = (hwif->chipset == ide_trm290);
@@ -371,11 +371,11 @@
 /* Teardown mappings after DMA has completed.  */
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
-	struct pci_dev *dev = HWIF(drive)->pci_dev;
-	struct scatterlist *sg = HWIF(drive)->sg_table;
-	int nents = HWIF(drive)->sg_nents;
+	struct pci_dev *dev = drive->channel->pci_dev;
+	struct scatterlist *sg = drive->channel->sg_table;
+	int nents = drive->channel->sg_nents;
 
-	pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);
+	pci_unmap_sg(dev, sg, nents, drive->channel->sg_dma_direction);
 }
 
 /*
@@ -462,7 +462,7 @@
 {
 	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 
 #ifdef CONFIG_IDEDMA_ONLYDISK
 	if (drive->type != ATA_DISK)
@@ -502,7 +502,7 @@
  */
 static int dma_timer_expiry(ide_drive_t *drive)
 {
-	byte dma_stat = inb(HWIF(drive)->dma_base+2);
+	byte dma_stat = inb(drive->channel->dma_base+2);
 
 #ifdef DEBUG
 	printk("%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat);
@@ -525,11 +525,11 @@
 {
 	u64 addr = BLK_BOUNCE_HIGH;
 
-	if (on && drive->type == ATA_DISK && HWIF(drive)->highmem) {
+	if (on && drive->type == ATA_DISK && drive->channel->highmem) {
 		if (!PCI_DMA_BUS_IS_PHYS)
 			addr = BLK_BOUNCE_ANY;
 		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+			addr = drive->channel->pci_dev->dma_mask;
 	}
 
 	blk_queue_bounce_limit(&drive->queue, addr);
@@ -553,7 +553,7 @@
  */
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned long dma_base = hwif->dma_base;
 	byte unit = (drive->select.b.unit & 0x01);
 	unsigned int count, reading = 0, set_high = 1;
@@ -588,17 +588,19 @@
 			drive->waiting_for_dma = 1;
 			if (drive->type != ATA_DISK)
 				return 0;
+
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
 			if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) &&
 			    (drive->addressing == 1)) {
 				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
+				OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
 			} else if (drive->addressing) {
 				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 			} else {
 				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			}
-			return HWIF(drive)->dmaproc(ide_dma_begin, drive);
+			return drive->channel->dmaproc(ide_dma_begin, drive);
 		case ide_dma_begin:
 			/* Note that this is done *after* the cmd has
 			 * been issued to the drive, as per the BM-IDE spec.
@@ -644,7 +646,7 @@
 /*
  * Needed for allowing full modular support of ide-driver
  */
-void ide_release_dma(ide_hwif_t *hwif)
+void ide_release_dma(struct ata_channel *hwif)
 {
 	if (!hwif->dma_base)
 		return;
@@ -660,7 +662,7 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
-	if ((hwif->dma_extra) && (hwif->channel == 0))
+	if ((hwif->dma_extra) && (hwif->unit == 0))
 		release_region((hwif->dma_base + 16), hwif->dma_extra);
 	release_region(hwif->dma_base, 8);
 	hwif->dma_base = 0;
@@ -669,7 +671,7 @@
 /*
  * This can be called for a dynamically installed interface. Don't __init it
  */
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)
+void ide_setup_dma(struct ata_channel *hwif, unsigned long dma_base, unsigned int num_ports)
 {
 	printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
 	if (check_region(dma_base, num_ports)) {
diff -Nru a/drivers/ide/ide-features.c b/drivers/ide/ide-features.c
--- a/drivers/ide/ide-features.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ide-features.c	Wed Apr  3 17:11:15 2002
@@ -2,7 +2,7 @@
  * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
  *
  *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *  
+ *
  *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
  *
  *  Extracts if ide.c to address the evolving transfer rate code for
@@ -134,7 +134,7 @@
 	struct hd_driveid *id;
 	unsigned long timeout, flags;
 
-	SELECT_MASK(HWIF(drive), drive, 1);
+	SELECT_MASK(drive->channel, drive, 1);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
 	ide_delay_50ms();
@@ -142,20 +142,20 @@
 	timeout = jiffies + WAIT_WORSTCASE;
 	do {
 		if (0 < (signed long)(jiffies - timeout)) {
-			SELECT_MASK(HWIF(drive), drive, 0);
+			SELECT_MASK(drive->channel, drive, 0);
 			return 0;	/* drive timed-out */
 		}
 		ide_delay_50ms();	/* give drive a breather */
 	} while (IN_BYTE(IDE_ALTSTATUS_REG) & BUSY_STAT);
 	ide_delay_50ms();	/* wait for IRQ and DRQ_STAT */
 	if (!OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) {
-		SELECT_MASK(HWIF(drive), drive, 0);
+		SELECT_MASK(drive->channel, drive, 0);
 		printk("%s: CHECK for good STATUS\n", drive->name);
 		return 0;
 	}
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_MASK(drive->channel, drive, 0);
 	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
 	if (!id) {
 		__restore_flags(flags);	/* local CPU only */
@@ -186,11 +186,11 @@
  */
 int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) {
-		if (!HWIF(drive)->udma_four) {
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
+	if ((args->taskfile.command == WIN_SETFEATURES) &&
+	    (args->taskfile.sector_number > XFER_UDMA_2) &&
+	    (args->taskfile.feature == SETFEATURES_XFER)) {
+		if (!drive->channel->udma_four) {
+			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", drive->channel->name);
 			return 1;
 		}
 #ifndef CONFIG_IDEDMA_IVB
@@ -213,9 +213,9 @@
  */
 int set_transfer (ide_drive_t *drive, ide_task_t *args)
 {
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
-	    (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) &&
-	    (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) &&
+	if ((args->taskfile.command == WIN_SETFEATURES) &&
+	    (args->taskfile.sector_number >= XFER_SW_DMA_0) &&
+	    (args->taskfile.feature == SETFEATURES_XFER) &&
 	    (drive->id->dma_ultra ||
 	     drive->id->dma_mword ||
 	     drive->id->dma_1word))
@@ -229,7 +229,7 @@
  */
 byte eighty_ninty_three (ide_drive_t *drive)
 {
-	return ((byte) ((HWIF(drive)->udma_four) &&
+	return ((byte) ((drive->channel->udma_four) &&
 #ifndef CONFIG_IDEDMA_IVB
 			(drive->id->hw_config & 0x4000) &&
 #endif /* CONFIG_IDEDMA_IVB */
@@ -249,8 +249,9 @@
  */
 int ide_config_drive_speed (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif = HWIF(drive);
-	int	i, error = 1;
+	struct ata_channel *hwif = drive->channel;
+	int i;
+	int error = 1;
 	byte stat;
 
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
@@ -269,8 +270,8 @@
          */
 	disable_irq(hwif->irq);	/* disable_irq_nosync ?? */
 	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_DRIVE(drive->channel, drive);
+	SELECT_MASK(drive->channel, drive, 0);
 	udelay(1);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG);
@@ -310,7 +311,7 @@
 		}
 	}
 
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_MASK(drive->channel, drive, 0);
 
 	enable_irq(hwif->irq);
 
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ide-floppy.c	Wed Apr  3 17:11:14 2002
@@ -902,7 +902,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+		if (drive->channel->dmaproc(ide_dma_end, drive)) {
 			set_bit (PC_DMA_ERROR, &pc->flags);
 		} else {
 			pc->actually_transferred=pc->request_transfer;
@@ -945,7 +945,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-floppy: The floppy wants to issue more interrupts in DMA mode\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		drive->channel->dmaproc(ide_dma_off, drive);
 		return ide_stopped;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -968,6 +968,7 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n");
 				idefloppy_discard_data (drive,bcount.all);
+				BUG_ON(HWGROUP(drive)->handler);
 				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -990,7 +991,9 @@
 	pc->actually_transferred+=bcount.all;				/* Update the current position */
 	pc->current_position+=bcount.all;
 
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	BUG_ON(HWGROUP(drive)->handler);
+	ide_set_handler(drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+
 	return ide_started;
 }
 
@@ -1014,8 +1017,11 @@
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
 		return ide_stopped;
 	}
+
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */
+
 	return ide_started;
 }
 
@@ -1055,17 +1061,19 @@
 		printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n");
 		return ide_stopped;
 	}
-	/* 
+	/*
 	 * The following delay solves a problem with ATAPI Zip 100 drives where the
 	 * Busy flag was apparently being deasserted before the unit was ready to
 	 * receive data. This was happening on a 1200 MHz Athlon system. 10/26/01
-	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will 
+	 * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will
 	 * not be actually used until after the packet is moved in about 50 msec.
 	 */
-	ide_set_handler (drive, 
-	  &idefloppy_pc_intr, 		/* service routine for packet command */
+	BUG_ON(HWGROUP(drive)->handler);
+	ide_set_handler (drive,
+	  &idefloppy_pc_intr,		/* service routine for packet command */
 	  floppy->ticks,			/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
+
 	return ide_started;
 }
 
@@ -1117,10 +1125,10 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) drive->channel->dmaproc(ide_dma_off, drive);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok=!drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
@@ -1133,7 +1141,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {							/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		(void) drive->channel->dmaproc(ide_dma_begin, drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1143,8 +1151,9 @@
 	} else {
 		pkt_xfer_routine = &idefloppy_transfer_pc;	/* immediate */
 	}
-	
+
 	if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) {
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
 		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
 		return ide_started;
@@ -1156,7 +1165,7 @@
 
 static void idefloppy_rw_callback (ide_drive_t *drive)
 {
-#if IDEFLOPPY_DEBUG_LOG	
+#if IDEFLOPPY_DEBUG_LOG
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
@@ -2004,7 +2013,7 @@
 	(void) idefloppy_get_capacity (drive);
 	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		ide_hwif_t *hwif = HWIF(drive);
+		struct ata_channel *hwif = drive->channel;
 
 		if (drive != &hwif->drives[i]) continue;
 		hwif->gd->de_arr[i] = drive->de;
@@ -2109,10 +2118,9 @@
 			kfree (floppy);
 			continue;
 		}
-		/* ATA-PATTERN */
-		ata_ops(drive)->busy++;
+		MOD_INC_USE_COUNT;
 		idefloppy_setup (drive, floppy);
-		ata_ops(drive)->busy--;
+		MOD_DEC_USE_COUNT;
 
 		failed--;
 	}
diff -Nru a/drivers/ide/ide-geometry.c b/drivers/ide/ide-geometry.c
--- a/drivers/ide/ide-geometry.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/ide/ide-geometry.c	Wed Apr  3 17:11:13 2002
@@ -7,6 +7,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/ide.h>
 #include <linux/mc146818rtc.h>
 #include <asm/io.h>
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/ide/ide-pci.c	Wed Apr  3 17:11:16 2002
@@ -39,45 +39,45 @@
 
 #ifdef CONFIG_BLK_DEV_AEC62XX
 extern unsigned int pci_init_aec62xx(struct pci_dev *);
-extern unsigned int ata66_aec62xx(ide_hwif_t *);
-extern void ide_init_aec62xx(ide_hwif_t *);
-extern void ide_dmacapable_aec62xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_aec62xx(struct ata_channel *);
+extern void ide_init_aec62xx(struct ata_channel *);
+extern void ide_dmacapable_aec62xx(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_ALI15X3
 extern unsigned int pci_init_ali15x3(struct pci_dev *);
-extern unsigned int ata66_ali15x3(ide_hwif_t *);
-extern void ide_init_ali15x3(ide_hwif_t *);
-extern void ide_dmacapable_ali15x3(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_ali15x3(struct ata_channel *);
+extern void ide_init_ali15x3(struct ata_channel *);
+extern void ide_dmacapable_ali15x3(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_AMD74XX
 extern unsigned int pci_init_amd74xx(struct pci_dev *);
-extern unsigned int ata66_amd74xx(ide_hwif_t *);
-extern void ide_init_amd74xx(ide_hwif_t *);
-extern void ide_dmacapable_amd74xx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_amd74xx(struct ata_channel *);
+extern void ide_init_amd74xx(struct ata_channel *);
+extern void ide_dmacapable_amd74xx(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_CMD64X
 extern unsigned int pci_init_cmd64x(struct pci_dev *);
-extern unsigned int ata66_cmd64x(ide_hwif_t *);
-extern void ide_init_cmd64x(ide_hwif_t *);
-extern void ide_dmacapable_cmd64x(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_cmd64x(struct ata_channel *);
+extern void ide_init_cmd64x(struct ata_channel *);
+extern void ide_dmacapable_cmd64x(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_CY82C693
 extern unsigned int pci_init_cy82c693(struct pci_dev *);
-extern void ide_init_cy82c693(ide_hwif_t *);
+extern void ide_init_cy82c693(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_CS5530
 extern unsigned int pci_init_cs5530(struct pci_dev *);
-extern void ide_init_cs5530(ide_hwif_t *);
+extern void ide_init_cs5530(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT34X
 extern unsigned int pci_init_hpt34x(struct pci_dev *);
-extern void ide_init_hpt34x(ide_hwif_t *);
+extern void ide_init_hpt34x(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_HPT366
@@ -85,9 +85,9 @@
 extern byte hpt363_shared_pin;
 
 extern unsigned int pci_init_hpt366(struct pci_dev *);
-extern unsigned int ata66_hpt366(ide_hwif_t *);
-extern void ide_init_hpt366(ide_hwif_t *);
-extern void ide_dmacapable_hpt366(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_hpt366(struct ata_channel *);
+extern void ide_init_hpt366(struct ata_channel *);
+extern void ide_dmacapable_hpt366(struct ata_channel *, unsigned long);
 #else
 /* FIXME: those have to be killed */
 static byte hpt363_shared_irq;
@@ -95,69 +95,69 @@
 #endif
 
 #ifdef CONFIG_BLK_DEV_NS87415
-extern void ide_init_ns87415(ide_hwif_t *);
+extern void ide_init_ns87415(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_OPTI621
-extern void ide_init_opti621(ide_hwif_t *);
+extern void ide_init_opti621(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC_ADMA
 extern unsigned int pci_init_pdcadma(struct pci_dev *);
-extern unsigned int ata66_pdcadma(ide_hwif_t *);
-extern void ide_init_pdcadma(ide_hwif_t *);
-extern void ide_dmacapable_pdcadma(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_pdcadma(struct ata_channel *);
+extern void ide_init_pdcadma(struct ata_channel *);
+extern void ide_dmacapable_pdcadma(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_PDC202XX
 extern unsigned int pci_init_pdc202xx(struct pci_dev *);
-extern unsigned int ata66_pdc202xx(ide_hwif_t *);
-extern void ide_init_pdc202xx(ide_hwif_t *);
+extern unsigned int ata66_pdc202xx(struct ata_channel *);
+extern void ide_init_pdc202xx(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_PIIX
 extern unsigned int pci_init_piix(struct pci_dev *);
-extern unsigned int ata66_piix(ide_hwif_t *);
-extern void ide_init_piix(ide_hwif_t *);
-extern void ide_dmacapable_piix(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_piix(struct ata_channel *);
+extern void ide_init_piix(struct ata_channel *);
+extern void ide_dmacapable_piix(struct ata_channel *, unsigned long);
 #endif
 
 #ifdef CONFIG_BLK_DEV_IT8172
 extern unsigned int pci_init_it8172(struct pci_dev *);
-extern void ide_init_it8172(ide_hwif_t *);
+extern void ide_init_it8172(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_RZ1000
-extern void ide_init_rz1000(ide_hwif_t *);
+extern void ide_init_rz1000(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_SVWKS
 extern unsigned int pci_init_svwks(struct pci_dev *);
-extern unsigned int ata66_svwks(ide_hwif_t *);
-extern void ide_init_svwks(ide_hwif_t *);
+extern unsigned int ata66_svwks(struct ata_channel *);
+extern void ide_init_svwks(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_SIS5513
 extern unsigned int pci_init_sis5513(struct pci_dev *);
-extern unsigned int ata66_sis5513(ide_hwif_t *);
-extern void ide_init_sis5513(ide_hwif_t *);
+extern unsigned int ata66_sis5513(struct ata_channel *);
+extern void ide_init_sis5513(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_SL82C105
 extern unsigned int pci_init_sl82c105(struct pci_dev *);
-extern void dma_init_sl82c105(ide_hwif_t *, unsigned long);
-extern void ide_init_sl82c105(ide_hwif_t *);
+extern void dma_init_sl82c105(struct ata_channel *, unsigned long);
+extern void ide_init_sl82c105(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_TRM290
-extern void ide_init_trm290(ide_hwif_t *);
+extern void ide_init_trm290(struct ata_channel *);
 #endif
 
 #ifdef CONFIG_BLK_DEV_VIA82CXXX
 extern unsigned int pci_init_via82cxxx(struct pci_dev *);
-extern unsigned int ata66_via82cxxx(ide_hwif_t *);
-extern void ide_init_via82cxxx(ide_hwif_t *);
-extern void ide_dmacapable_via82cxxx(ide_hwif_t *, unsigned long);
+extern unsigned int ata66_via82cxxx(struct ata_channel *);
+extern void ide_init_via82cxxx(struct ata_channel *);
+extern void ide_dmacapable_via82cxxx(struct ata_channel *, unsigned long);
 #endif
 
 typedef struct ide_pci_enablebit_s {
@@ -181,9 +181,9 @@
 	unsigned short		vendor;
 	unsigned short		device;
 	unsigned int		(*init_chipset)(struct pci_dev *dev);
-	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void			(*init_hwif)(ide_hwif_t *hwif);
-	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
+	unsigned int		(*ata66_check)(struct ata_channel *hwif);
+	void			(*init_hwif)(struct ata_channel *hwif);
+	void			(*dma_init)(struct ata_channel *hwif, unsigned long dmabase);
 	ide_pci_enablebit_t	enablebits[2];
 	unsigned int		bootable;
 	unsigned int		extra;
@@ -229,6 +229,7 @@
 	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268R, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ  | ATA_F_DMA },
 	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, pci_init_pdc202xx, ata66_pdc202xx, ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
 	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, pci_init_pdc202xx, ata66_pdc202xx,	ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
+	{PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, pci_init_pdc202xx, ata66_pdc202xx,	ide_init_pdc202xx, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, OFF_BOARD, 0, ATA_F_IRQ | ATA_F_DMA },
 #endif
 #ifdef CONFIG_BLK_DEV_RZ1000
 	{PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, NULL, NULL,	ide_init_rz1000, NULL, {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, ON_BOARD, 0, 0 },
@@ -328,10 +329,10 @@
  * Match a PCI IDE port against an entry in ide_hwifs[],
  * based on io_base port if possible.
  */
-static ide_hwif_t __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
+static struct ata_channel __init *lookup_hwif (unsigned long io_base, int bootable, const char *name)
 {
 	int h;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 
 	/*
 	 * Look for a hwif with matching io_base specified using
@@ -430,7 +431,7 @@
 /*
  * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
  */
-static unsigned long __init get_dma_base(ide_hwif_t *hwif, int extra, const char *name)
+static unsigned long __init get_dma_base(struct ata_channel *hwif, int extra, const char *name)
 {
 	unsigned long	dma_base = 0;
 	struct pci_dev	*dev = hwif->pci_dev;
@@ -441,7 +442,7 @@
 	 */
 
 	if (hwif->mate && hwif->mate->dma_base)
-		dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
+		dma_base = hwif->mate->dma_base - (hwif->unit ? 0 : 8);
 	else
 		dma_base = pci_resource_start(dev, 4);
 
@@ -451,7 +452,7 @@
 	if (extra) /* PDC20246, PDC20262, HPT343, & HPT366 */
 		request_region(dma_base + 16, extra, name);
 
-	dma_base += hwif->channel ? 8 : 0;
+	dma_base += hwif->unit ? 8 : 0;
 	hwif->dma_extra = extra;
 
 	if ((dev->vendor == PCI_VENDOR_ID_AL && dev->device == PCI_DEVICE_ID_AL_M5219) ||
@@ -484,11 +485,11 @@
 /*
  * Setup DMA transfers on a channel.
  */
-static void __init setup_channel_dma(ide_hwif_t *hwif, struct pci_dev *dev,
+static void __init setup_channel_dma(struct ata_channel *hwif, struct pci_dev *dev,
 		ide_pci_device_t *d,
 		int port,
 		u8 class_rev,
-		int pciirq, ide_hwif_t **mate,
+		int pciirq, struct ata_channel **mate,
 		int autodma, unsigned short *pcicmd)
 {
 	unsigned long dma_base;
@@ -535,14 +536,15 @@
 		ide_pci_device_t *d,
 		int port,
 		u8 class_rev,
-		int pciirq, ide_hwif_t **mate,
+		int pciirq,
+		struct ata_channel **mate,
 		int autodma,
 		unsigned short *pcicmd)
 {
 	unsigned long base = 0;
 	unsigned long ctl = 0;
 	ide_pci_enablebit_t *e = &(d->enablebits[port]);
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 
 	u8 tmp;
 	if (port == 1) {
@@ -608,7 +610,7 @@
 
 	hwif->chipset = ide_pci;
 	hwif->pci_dev = dev;
-	hwif->channel = port;
+	hwif->unit = port;
 	if (!hwif->irq)
 		hwif->irq = pciirq;
 
@@ -669,7 +671,7 @@
 	int pciirq = 0;
 	unsigned short pcicmd = 0;
 	unsigned short tried_config = 0;
-	ide_hwif_t *mate = NULL;
+	struct ata_channel *mate = NULL;
 	unsigned int class_rev;
 
 #ifdef CONFIG_IDEDMA_AUTO
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ide-pmac.c	Wed Apr  3 17:11:15 2002
@@ -71,6 +71,9 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
+# define BAD_DMA_DRIVE		0
+# define GOOD_DMA_DRIVE		1
+
 typedef struct {
 	int	accessTime;
 	int	cycleTime;
@@ -124,10 +127,10 @@
 static int
 pmac_ide_find(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	ide_ioreg_t base;
 	int i;
-	
+
 	for (i=0; i<pmac_ide_count; i++) {
 		base = pmac_ide[i].regbase;
 		if (base && base == hwif->io_ports[0])
@@ -258,8 +261,8 @@
 	save_flags(flags);
 	cli();
 	udelay(1);
-	SELECT_DRIVE(HWIF(drive), drive);
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_DRIVE(drive->channel, drive);
+	SELECT_MASK(drive->channel, drive, 0);
 	udelay(1);
 	if(wait_for_ready(drive)) {
 		printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
@@ -507,7 +510,7 @@
 	struct device_node *p, **pp, *removables, **rp;
 	unsigned long base;
 	int irq, big_delay;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 
 	if (_machine != _MACH_Pmac)
 		return;
@@ -928,12 +931,12 @@
 	int enable = 1;
 
 	drive->using_dma = 0;
-	
+
 	idx = pmac_ide_find(drive);
 	if (idx < 0)
 		return 0;
-		
-	if (drive->media == ide_floppy)
+
+	if (drive->type == ATA_FLOPPY)
 		enable = 0;
 	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))
 		enable = 0;
@@ -942,9 +945,9 @@
 
 	udma = 0;
 	ata4 = (pmac_ide[idx].kind == controller_kl_ata4);
-			
+
 	if(enable) {
-		if (ata4 && (drive->media == ide_disk) &&
+		if (ata4 && (drive->type == ATA_DISK) &&
 		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {
 			/* UltraDMA modes. */
 			drive->using_dma = pmac_ide_udma_enable(drive, idx);
@@ -991,8 +994,9 @@
 		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))
 			return 1;
 		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
+		if (drive->type != ATA_DISK)
 			return 0;
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,
 			 IDE_COMMAND_REG);
@@ -1051,12 +1055,12 @@
 static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
 {
 	int j;
-	
+
 	/* FIXME: We only handle the master IDE disk, we shoud
 	 *        try to fix CD-ROMs here
 	 */
-	switch (drive->media) {
-	case ide_disk:
+	switch (drive->type) {
+	case ATA_DISK:
 		/* Spin down the drive */
 		outb(0xa0, base+0x60);
 		outb(0x0, base+0x30);
@@ -1064,7 +1068,7 @@
 		outb(0x0, base+0x40);
 		outb(0x0, base+0x50);
 		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);   
+		outb(0x2, base+0x160);
 		for (j = 0; j < 10; j++) {
 			int status;
 			mdelay(100);
@@ -1073,10 +1077,10 @@
 				break;
 		}
 		break;
-	case ide_cdrom:
+	case ATA_ROM:
 		// todo
 		break;
-	case ide_floppy:
+	case ATA_FLOPPY:
 		// todo
 		break;
 	}
@@ -1094,7 +1098,7 @@
 		DRIVER(drive)->media_change(drive);
 
 	/* We kick the VFS too (see fix in ide.c revalidate) */
-	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+	check_disk_change(MKDEV(drive->channel->major, (drive->select.b.unit) << PARTN_BITS));
 	
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* We re-enable DMA on the drive if it was active. */
@@ -1198,7 +1202,7 @@
 		break;
 	case PBOOK_SLEEP_NOW:
 		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
+			struct ata_channel *hwif;
 			ide_drive_t *drive;
 			int unlock = 0;
 
@@ -1258,8 +1262,8 @@
 			mdelay(IDE_WAKEUP_DELAY_MS);
 	
 		for (i = 0; i < pmac_ide_count; ++i) {
-			ide_hwif_t *hwif;
-			ide_drive_t *drive;			
+			struct ata_channel *hwif;
+			ide_drive_t *drive;
 			int j, used_dma;
 			
 			if ((base = pmac_ide[i].regbase) == 0)
diff -Nru a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
--- a/drivers/ide/ide-pnp.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ide-pnp.c	Wed Apr  3 17:11:14 2002
@@ -13,7 +13,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/ide.h>
@@ -57,7 +57,7 @@
 static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
 {
 	hw_regs_t hw;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	int index;
 
 	if (!enable)
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/ide/ide-probe.c	Wed Apr  3 17:11:13 2002
@@ -118,7 +118,7 @@
 		byte type = (id->config >> 8) & 0x1f;
 		printk("ATAPI ");
 #ifdef CONFIG_BLK_DEV_PDC4030
-		if (HWIF(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+		if (drive->channel->unit == 1 && drive->channel->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
@@ -167,12 +167,16 @@
 	 */
 	if (id->config & (1<<7))
 		drive->removable = 1;
+
 	/*
-	 * Prevent long system lockup probing later for non-existant
-	 * slave drive if the hwif is actually a flash memory card of some variety:
+	 * FIXME: This is just plain ugly or plain unnecessary.
+	 *
+	 * Prevent long system lockup probing later for non-existant slave
+	 * drive if the hwif is actually a flash memory card of some variety:
 	 */
+
 	if (drive_is_flashcard(drive)) {
-		ide_drive_t *mate = &HWIF(drive)->drives[1^drive->select.b.unit];
+		ide_drive_t *mate = &drive->channel->drives[1 ^ drive->select.b.unit];
 		if (!mate->ata_flash) {
 			mate->present = 0;
 			mate->noprobe = 1;
@@ -182,8 +186,8 @@
 	printk("ATA DISK drive\n");
 
 	/* Initialize our quirk list. */
-	if (HWIF(drive)->quirkproc)
-		drive->quirk_list = HWIF(drive)->quirkproc(drive);
+	if (drive->channel->quirkproc)
+		drive->quirk_list = drive->channel->quirkproc(drive);
 
 	return;
 
@@ -232,7 +236,7 @@
 		OUT_BYTE(0,IDE_FEATURE_REG);	/* disable dma & overlap */
 
 #if CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030) {
+	if (drive->channel->chipset == ide_pdc4030) {
 		/* DC4030 hosted drives need their own identify... */
 		extern int pdc4030_identify(ide_drive_t *);
 		if (pdc4030_identify(drive)) {
@@ -270,7 +274,7 @@
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 
-	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+	if (IDE_CONTROL_REG && !drive->channel->irq) {
 		autoprobe = 1;
 		cookie = probe_irq_on();
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* enable device irq */
@@ -284,9 +288,9 @@
 		GET_STAT();			/* clear drive IRQ */
 		udelay(5);
 		irq = probe_irq_off(cookie);
-		if (!HWIF(drive)->irq) {
+		if (!drive->channel->irq) {
 			if (irq > 0)
-				HWIF(drive)->irq = irq;
+				drive->channel->irq = irq;
 			else	/* Mmmm.. multiple IRQs.. don't know which was ours */
 				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
 		}
@@ -314,7 +318,7 @@
 static int do_probe (ide_drive_t *drive, byte cmd)
 {
 	int rc;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	if (drive->present) {	/* avoid waiting for inappropriate probes */
 		if ((drive->type != ATA_DISK) && (cmd == WIN_IDENTIFY))
 			return 4;
@@ -369,12 +373,12 @@
 /*
  *
  */
-static void enable_nest (ide_drive_t *drive)
+static void enable_nest(ide_drive_t *drive)
 {
 	unsigned long timeout;
 
-	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
-	SELECT_DRIVE(HWIF(drive), drive);
+	printk("%s: enabling %s -- ", drive->channel->name, drive->id->model);
+	SELECT_DRIVE(drive->channel, drive);
 	ide_delay_50ms();
 	OUT_BYTE(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG);
 	timeout = jiffies + WAIT_WORSTCASE;
@@ -427,7 +431,7 @@
  * ordered sanely.  We deal with the CONTROL register
  * separately.
  */
-static int hwif_check_regions (ide_hwif_t *hwif)
+static int hwif_check_regions(struct ata_channel *hwif)
 {
 	int region_errors = 0;
 
@@ -453,20 +457,20 @@
 	return(region_errors);
 }
 
-static void hwif_register (ide_hwif_t *hwif)
+static void hwif_register(struct ata_channel *hwif)
 {
 	/* Register this hardware interface within the global device tree.
 	 */
-	sprintf(hwif->device.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
-	sprintf(hwif->device.name, "ide");
-	hwif->device.driver_data = hwif;
+	sprintf(hwif->dev.bus_id, "%04x", hwif->io_ports[IDE_DATA_OFFSET]);
+	sprintf(hwif->dev.name, "ide");
+	hwif->dev.driver_data = hwif;
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	if (hwif->pci_dev)
-		hwif->device.parent = &hwif->pci_dev->dev;
+		hwif->dev.parent = &hwif->pci_dev->dev;
 	else
 #endif
-		hwif->device.parent = NULL; /* Would like to do = &device_legacy */
-	device_register(&hwif->device);
+		hwif->dev.parent = NULL; /* Would like to do = &device_legacy */
+	device_register(&hwif->dev);
 
 	if (((unsigned long)hwif->io_ports[IDE_DATA_OFFSET] | 7) ==
 	    ((unsigned long)hwif->io_ports[IDE_STATUS_OFFSET])) {
@@ -503,7 +507,7 @@
  * This routine only knows how to look for drive units 0 and 1
  * on an interface, so any setting of MAX_DRIVES > 2 won't work here.
  */
-static void probe_hwif (ide_hwif_t *hwif)
+static void probe_hwif(struct ata_channel *hwif)
 {
 	unsigned int unit;
 	unsigned long flags;
@@ -513,7 +517,7 @@
 
 	if (
 #if CONFIG_BLK_DEV_PDC4030
-	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
+	    (hwif->chipset != ide_pdc4030 || hwif->unit == 0) &&
 #endif
 	    hwif_check_regions(hwif)) {
 		int msgout = 0;
@@ -562,7 +566,7 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 		if (drive->present) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+			ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
 			if (tuneproc != NULL && drive->autotune == 1)
 				tuneproc(drive, 255);	/* auto-tune PIO mode */
 		}
@@ -583,7 +587,7 @@
 
 	/* IDE can do up to 128K per request, pdc4030 needs smaller limit */
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030)
+	if (drive->channel->chipset == ide_pdc4030)
 		max_sectors = 127;
 #endif
 	blk_queue_max_sectors(q, max_sectors);
@@ -608,9 +612,10 @@
  *
  * This routine detects and reports such situations, but does not fix them.
  */
-static void save_match(ide_hwif_t *hwif, ide_hwif_t *new, ide_hwif_t **match)
+static void save_match(struct ata_channel *hwif, struct ata_channel *new,
+		struct ata_channel **match)
 {
-	ide_hwif_t *m = *match;
+	struct ata_channel *m = *match;
 
 	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
 		if (!new->hwgroup)
@@ -635,12 +640,12 @@
  * but anything else has led to problems on some machines.  We re-enable
  * interrupts as much as we can safely do in most places.
  */
-static int init_irq (ide_hwif_t *hwif)
+static int init_irq(struct ata_channel *hwif)
 {
 	unsigned long flags;
 	unsigned int index;
 	ide_hwgroup_t *hwgroup, *new_hwgroup;
-	ide_hwif_t *match = NULL;
+	struct ata_channel *match = NULL;
 
 
 	/* Allocate the buffer and potentially sleep first */
@@ -655,7 +660,7 @@
 	 * Group up with any other hwifs that share our irq(s).
 	 */
 	for (index = 0; index < MAX_HWIFS; index++) {
-		ide_hwif_t *h = &ide_hwifs[index];
+		struct ata_channel *h = &ide_hwifs[index];
 		if (h->hwgroup) {  /* scan only initialized hwif's */
 			if (hwif->irq == h->irq) {
 				hwif->sharing_irq = h->sharing_irq = 1;
@@ -736,7 +741,7 @@
 		ide_init_queue(drive);
 	}
 	if (!hwgroup->hwif) {
-		hwgroup->hwif = HWIF(hwgroup->drive);
+		hwgroup->hwif = hwgroup->drive->channel;
 #ifdef DEBUG
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
@@ -770,7 +775,7 @@
  * structures needed for the routines in genhd.c.  ide_geninit() gets called
  * somewhat later, during the partition check.
  */
-static void init_gendisk (ide_hwif_t *hwif)
+static void init_gendisk(struct ata_channel *hwif)
 {
 	struct gendisk *gd;
 	unsigned int unit, minors, i;
@@ -819,11 +824,11 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		char name[80];
 		ide_add_generic_settings(hwif->drives + unit);
-		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+		hwif->drives[unit].dn = ((hwif->unit ? 2 : 0) + unit);
 		sprintf (name, "host%d/bus%d/target%d/lun%d",
-			(hwif->channel && hwif->mate) ?
+			(hwif->unit && hwif->mate) ?
 			hwif->mate->index : hwif->index,
-			hwif->channel, unit, hwif->drives[unit].lun);
+			hwif->unit, unit, hwif->drives[unit].lun);
 		if (hwif->drives[unit].present)
 			hwif->drives[unit].de = devfs_mk_dir(ide_devfs_handle, name, NULL);
 	}
@@ -840,7 +845,7 @@
 	return;
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+static int hwif_init(struct ata_channel *hwif)
 {
 	if (!hwif->present)
 		return 0;
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ide-proc.c	Wed Apr  3 17:11:14 2002
@@ -138,7 +138,7 @@
 static int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_hwif_t	*hwif = data;
+	struct ata_channel *hwif = data;
 	int		len;
 	const char	*name;
 
@@ -167,7 +167,7 @@
 static int proc_ide_read_mate
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_hwif_t	*hwif = data;
+	struct ata_channel *hwif = data;
 	int		len;
 
 	if (hwif && hwif->mate && hwif->mate->present)
@@ -180,10 +180,10 @@
 static int proc_ide_read_channel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
-	ide_hwif_t	*hwif = data;
+	struct ata_channel *hwif = data;
 	int		len;
 
-	page[0] = hwif->channel ? '1' : '0';
+	page[0] = hwif->unit ? '1' : '0';
 	page[1] = '\n';
 	len = 2;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
@@ -435,7 +435,7 @@
 	}
 }
 
-static void create_proc_ide_drives(ide_hwif_t *hwif)
+static void create_proc_ide_drives(struct ata_channel *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
@@ -465,7 +465,7 @@
 	}
 }
 
-static void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive)
+static void destroy_proc_ide_device(struct ata_channel *hwif, ide_drive_t *drive)
 {
 	struct ata_operations *driver = drive->driver;
 
@@ -479,7 +479,7 @@
 	}
 }
 
-void destroy_proc_ide_drives(ide_hwif_t *hwif)
+void destroy_proc_ide_drives(struct ata_channel *hwif)
 {
 	int	d;
 
@@ -503,7 +503,7 @@
 	int	h;
 
 	for (h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
+		struct ata_channel *hwif = &ide_hwifs[h];
 
 		if (!hwif->present)
 			continue;
@@ -522,7 +522,7 @@
 	int	h;
 
 	for (h = 0; h < MAX_HWIFS; h++) {
-		ide_hwif_t *hwif = &ide_hwifs[h];
+		struct ata_channel *hwif = &ide_hwifs[h];
 		int exist = (hwif->proc != NULL);
 #if 0
 		if (!hwif->present)
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/ide-tape.c	Wed Apr  3 17:11:14 2002
@@ -2058,7 +2058,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		if (HWIF(drive)->dmaproc(ide_dma_end, drive)) {
+		if (drive->channel->dmaproc(ide_dma_end, drive)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2132,7 +2132,7 @@
 	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
 		printk (KERN_ERR "ide-tape: The tape wants to issue more interrupts in DMA mode\n");
 		printk (KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
-		HWIF(drive)->dmaproc(ide_dma_off, drive);
+		drive->channel->dmaproc(ide_dma_off, drive);
 		return ide_stopped;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -2155,7 +2155,8 @@
 			if (temp > pc->buffer_size) {
 				printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n");
 				idetape_discard_data (drive, bcount.all);
-				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				BUG_ON(HWGROUP(drive)->handler);
+				ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
@@ -2181,7 +2182,8 @@
 	if (tape->debug_level >= 2)
 		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	BUG_ON(HWGROUP(drive)->handler);
+	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -2255,6 +2257,7 @@
 		return ide_stopped;
 	}
 	tape->cmd_start_time = jiffies;
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* Set the interrupt routine */
 	atapi_output_bytes (drive,pc->c,12);			/* Send the actual packet */
 	return ide_started;
@@ -2309,10 +2312,10 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
 		printk (KERN_WARNING "ide-tape: DMA disabled, reverting to PIO\n");
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+		(void) drive->channel->dmaproc(ide_dma_off, drive);
 	}
 	if (test_bit (PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma)
-		dma_ok = !HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (IDE_CONTROL_REG)
@@ -2324,10 +2327,11 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (dma_ok) {						/* Begin DMA, if necessary */
 		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		(void) drive->channel->dmaproc(ide_dma_begin, drive);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) {
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL);
 		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
@@ -3103,10 +3107,10 @@
 	idetape_tape_t *tape = drive->driver_data;
 	idetape_read_position_result_t *result;
 	
-//#if IDETAPE_DEBUG_LOG
-//	if (tape->debug_level >= 4)
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
 		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
@@ -3280,10 +3284,10 @@
 	idetape_pc_t pc;
 	int position;
 
-//#if IDETAPE_DEBUG_LOG
-//        if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
-//#endif /* IDETAPE_DEBUG_LOG */
+#if IDETAPE_DEBUG_LOG
+	if (tape->debug_level >= 4)
+	    printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+#endif /* IDETAPE_DEBUG_LOG */
 
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
@@ -5997,13 +6001,13 @@
 		tape->onstream = 1;
 	drive->dsc_overlap = 1;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
+	if (!tape->onstream && drive->channel->pci_dev != NULL) {
 		/*
 		 * These two ide-pci host adapters appear to need DSC overlap disabled.
 		 * This probably needs further analysis.
 		 */
-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
+		if ((drive->channel->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
+		    (drive->channel->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
 			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
 		    	drive->dsc_overlap = 0;
 		}
@@ -6099,8 +6103,7 @@
 	idetape_chrdevs[minor].drive = NULL;
 	restore_flags (flags);	/* all CPUs (overkill?) */
 
-	/* FIXME: this appears to be totally wrong! */
-	ata_ops(drive)->busy = 0;
+	MOD_DEC_USE_COUNT;
 
 	ide_unregister_subdriver (drive);
 	drive->driver_data = NULL;
@@ -6255,12 +6258,12 @@
 		idetape_chrdevs[minor].drive = drive;
 		tape->de_r =
 		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
-				    HWIF(drive)->major, minor,
+				    drive->channel->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
 		tape->de_n =
 		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
-				    HWIF(drive)->major, minor + 128,
+				    drive->channel->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
 		devfs_register_tape (tape->de_r);
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ide-taskfile.c	Wed Apr  3 17:11:15 2002
@@ -33,7 +33,7 @@
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
@@ -48,14 +48,14 @@
 	if (rq->bio)
 		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
 	else
-		return rq->buffer + task_rq_offset(rq);
+		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
 }
 
 static inline void ide_unmap_rq(struct request *rq, char *to,
 				unsigned long *flags)
 {
 	if (rq->bio)
-	    bio_kunmap_irq(to, flags);
+		bio_kunmap_irq(to, flags);
 }
 
 static void bswap_data (void *buffer, int wcount)
@@ -98,8 +98,8 @@
 	 * for handling polled ide transfers
 	 */
 
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
+	if (drive->channel->ideproc) {
+		drive->channel->ideproc(ideproc_ide_input_data, drive, buffer, wcount);
 		return;
 	}
 
@@ -138,8 +138,8 @@
 {
 	byte io_32bit;
 
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
+	if (drive->channel->ideproc) {
+		drive->channel->ideproc(ideproc_ide_output_data, drive, buffer, wcount);
 		return;
 	}
 
@@ -180,8 +180,8 @@
  */
 void atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
+	if (drive->channel->ideproc) {
+		drive->channel->ideproc(ideproc_atapi_input_bytes, drive, buffer, bytecount);
 		return;
 	}
 
@@ -200,8 +200,8 @@
 
 void atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
 {
-	if (HWIF(drive)->ideproc) {
-		HWIF(drive)->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
+	if (drive->channel->ideproc) {
+		drive->channel->ideproc(ideproc_atapi_output_bytes, drive, buffer, bytecount);
 		return;
 	}
 
@@ -243,7 +243,7 @@
 {
 	byte stat = 0;
 	if (drive->waiting_for_dma)
-		return HWIF(drive)->dmaproc(ide_dma_test_irq, drive);
+		return drive->channel->dmaproc(ide_dma_test_irq, drive);
 #if 0
 	/* need to guarantee 400ns since last command was issued */
 	udelay(1);
@@ -288,83 +288,124 @@
 			break;
 	}
 }
-static ide_startstop_t bio_mulout_intr(ide_drive_t *drive);
 
-/*
- * Handler for command write multiple
- * Called directly from execute_drive_cmd for the first bunch of sectors,
- * afterwards only by the ISR
- */
-static ide_startstop_t task_mulout_intr(ide_drive_t *drive)
+static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+	ide_startstop_t startstop;
+
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+
+	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
+		return startstop;
+
+	ata_poll_drive_ready(drive);
+	return args->handler(drive);
+}
+
+static ide_startstop_t task_mulout_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
 	byte stat		= GET_STAT();
 	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
+	struct request *rq	= &HWGROUP(drive)->wrq;
 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
-	unsigned long flags;
+	int mcount		= drive->mult_count;
+	ide_startstop_t startstop;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
 	 * occurs after all data was sent in this chunk
 	 */
-	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
-			return ide_error(drive, "task_mulout_intr", stat);
+	if (!rq->nr_sectors) {
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			startstop = ide_error(drive, "task_mulout_intr", stat);
+			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+			return startstop;
+		}
 
-		/*
-		 * there may be more, ide_do_request will restart it if
-		 * necessary
-		 */
-		ide_end_request(drive, 1);
+		__ide_end_request(drive, 1, rq->hard_nr_sectors);
+		rq->bio = NULL;
 
 		return ide_stopped;
 	}
 
-	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
+	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+		if (stat & (ERR_STAT | DRQ_STAT)) {
+			startstop = ide_error(drive, "task_mulout_intr", stat);
+			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
+			return startstop;
 		}
+
 		/* no data yet, so wait for another interrupt */
 		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+			ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
 		return ide_started;
 	}
 
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-	nsect = rq->current_nr_sectors;
-	if (nsect > msect)
-		nsect = msect;
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bio after this? */
+		if (!rq->current_nr_sectors) {
+			/* remember to fix this up /jens */
+			struct bio *bio = rq->bio->bi_next;
+
+			/* end early if we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt
+		 * re-entering us on the last transfer.
+		 */
+		taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
+		bio_kunmap_irq(buffer, &flags);
+	} while (mcount);
 
-	pBuf = ide_map_rq(rq, &flags);
-	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	ide_unmap_rq(rq, pBuf, &flags);
 	drive->io_32bit = io_32bit;
 	rq->errors = 0;
-	/* Are we sure that this as all been already transfered? */
-	rq->current_nr_sectors -= nsect;
 	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
 	return ide_started;
 }
 
-ide_startstop_t do_rw_taskfile(ide_drive_t *drive, ide_task_t *task)
+ide_startstop_t ata_taskfile(ide_drive_t *drive,
+		struct hd_drive_task_hdr *taskfile,
+		struct hd_drive_hob_hdr *hobfile,
+		ide_handler_t *handler,
+		ide_pre_handler_t *prehandler,
+		struct request *rq
+		)
 {
-	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
-	hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister;
 	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
+	u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;
 
 	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) {
+	if (handler != task_mulout_intr) {
 		if (IDE_CONTROL_REG)
 			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
+		SELECT_MASK(drive->channel, drive, 0);
 	}
 
 	if ((id->command_set_2 & 0x0400) &&
@@ -386,67 +427,24 @@
 	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
 
 	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (task->handler != NULL) {
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
+	if (handler != NULL) {
+		ide_set_handler(drive, handler, WAIT_CMD, NULL);
 		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
 		/*
 		 * Warning check for race between handler and prehandler for
 		 * writing first block of data.  however since we are well
 		 * inside the boundaries of the seek, we should be okay.
 		 */
-		if (task->prehandler != NULL) {
-			return task->prehandler(drive, task->rq);
-		}
+		if (prehandler != NULL)
+			return prehandler(drive, rq);
 	} else {
 		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
+		if (drive->using_dma && !(drive->channel->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
 	}
 
 	return ide_started;
 }
 
-void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile,
-		struct hd_drive_hob_hdr *hobfile,
-		ide_handler_t *handler)
-{
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr && handler != bio_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	if ((id->command_set_2 & 0x0400) &&
-	    (id->cfs_enable_2 & 0x0400) &&
-	    (drive->addressing == 1)) {
-		OUT_BYTE(hobfile->feature, IDE_FEATURE_REG);
-		OUT_BYTE(hobfile->sector_count, IDE_NSECTOR_REG);
-		OUT_BYTE(hobfile->sector_number, IDE_SECTOR_REG);
-		OUT_BYTE(hobfile->low_cylinder, IDE_LCYL_REG);
-		OUT_BYTE(hobfile->high_cylinder, IDE_HCYL_REG);
-	}
-
-	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
-	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
-	/* refers to number of sectors to transfer */
-	OUT_BYTE(taskfile->sector_number, IDE_SECTOR_REG);
-	/* refers to sector offset or start sector */
-	OUT_BYTE(taskfile->low_cylinder, IDE_LCYL_REG);
-	OUT_BYTE(taskfile->high_cylinder, IDE_HCYL_REG);
-
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (handler != NULL) {
-		ide_set_handler (drive, handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-	} else {
-		/* for dma commands we down set the handler */
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(((taskfile->command == WIN_WRITEDMA) || (taskfile->command == WIN_WRITEDMA_EXT)) ? ide_dma_write : ide_dma_read, drive)));
-	}
-}
-
 /*
  * This is invoked on completion of a WIN_SETMULT cmd.
  */
@@ -567,8 +565,8 @@
 	}
 
 	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+	if ((args->taskfile.command != WIN_MULTWRITE) &&
+	    (args->taskfile.command != WIN_MULTWRITE_EXT)) {
 		unsigned long flags;
 		char *buf = ide_map_rq(rq, &flags);
 		/* For Write_sectors we need to stuff the first sector */
@@ -616,107 +614,6 @@
 	return ide_started;
 }
 
-static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq)
-{
-	ide_task_t *args = rq->special;
-	ide_startstop_t startstop;
-
-	/*
-	 * assign private copy for multi-write
-	 */
-	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
-
-	if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ))
-		return startstop;
-
-	ata_poll_drive_ready(drive);
-	return args->handler(drive);
-}
-
-
-static ide_startstop_t bio_mulout_intr (ide_drive_t *drive)
-{
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= &HWGROUP(drive)->wrq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	int mcount		= drive->mult_count;
-	ide_startstop_t startstop;
-
-	/*
-	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent in this chunk
-	 */
-	if (!rq->nr_sectors) {
-		if (stat & (ERR_STAT|DRQ_STAT)) {
-			startstop = ide_error(drive, "bio_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
-			return startstop;
-		}
-
-		__ide_end_request(drive, 1, rq->hard_nr_sectors);
-		HWGROUP(drive)->wrq.bio = NULL;
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
-		if (stat & (ERR_STAT | DRQ_STAT)) {
-			startstop = ide_error(drive, "bio_mulout_intr", stat);
-			memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request));
-			return startstop;
-		}
-
-		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
-		return ide_started;
-	}
-
-	do {
-		char *buffer;
-		int nsect = rq->current_nr_sectors;
-		unsigned long flags;
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-
-		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
-		rq->sector += nsect;
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bio after this? */
-		if (!rq->current_nr_sectors) {
-			/* remember to fix this up /jens */
-			struct bio *bio = rq->bio->bi_next;
-
-			/* end early early we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
-			}
-		}
-
-		/*
-		 * Ok, we're all setup for the interrupt
-		 * re-entering us on the last transfer.
-		 */
-		taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS);
-		bio_kunmap_irq(buffer, &flags);
-	} while (mcount);
-
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL);
-
-	return ide_started;
-}
-
 /*
  * Handler for command with Read Multiple
  */
@@ -774,12 +671,12 @@
 /* Called by ioctl to feature out type of command being called */
 void ide_cmd_type_parser(ide_task_t *args)
 {
-	struct hd_drive_task_hdr *taskfile = (struct hd_drive_task_hdr *) args->tfRegister;
+	struct hd_drive_task_hdr *taskfile = &args->taskfile;
 
 	args->prehandler = NULL;
 	args->handler = NULL;
 
-	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
+	switch(args->taskfile.command) {
 		case WIN_IDENTIFY:
 		case WIN_PIDENTIFY:
 			args->handler = task_in_intr;
@@ -814,8 +711,8 @@
 		case CFA_WRITE_MULTI_WO_ERASE:
 		case WIN_MULTWRITE:
 		case WIN_MULTWRITE_EXT:
-			args->prehandler = pre_bio_out_intr;
-			args->handler = bio_mulout_intr;
+			args->prehandler = pre_task_mulout_intr;
+			args->handler = task_mulout_intr;
 			args->command_type = IDE_DRIVE_TASK_RAW_WRITE;
 			return;
 
@@ -830,9 +727,11 @@
 		case WIN_SMART:
 			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
 				args->prehandler = pre_task_out_intr;
-			args->tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS;
-			args->tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS;
-			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+
+			args->taskfile.low_cylinder = SMART_LCYL_PASS;
+			args->taskfile.high_cylinder = SMART_HCYL_PASS;
+
+			switch(args->taskfile.feature) {
 				case SMART_READ_VALUES:
 				case SMART_READ_THRESHOLDS:
 				case SMART_READ_LOG_SECTOR:
@@ -870,7 +769,7 @@
 #endif
 		case WIN_SETFEATURES:
 			args->handler = task_no_data_intr;
-			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+			switch(args->taskfile.feature) {
 				case SETFEATURES_XFER:
 					args->command_type = IDE_DRIVE_TASK_SET_XFER;
 					return;
@@ -960,7 +859,7 @@
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
-static void ide_init_drive_taskfile (struct request *rq)
+static void init_taskfile_request(struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
 	rq->flags = REQ_DRIVE_TASKFILE;
@@ -968,37 +867,25 @@
 
 /*
  * This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
+ * This is an internal call and nobody in user-space has a
  * reason to call this taskfile.
  *
  * ide_raw_taskfile is the one that user-space executes.
  */
+
 int ide_wait_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
 {
 	struct request rq;
+	/* FIXME: This is on stack! */
 	ide_task_t args;
 
 	memset(&args, 0, sizeof(ide_task_t));
 
-	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
-	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
-	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
-	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
-	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
-	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
-	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
-	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
-
-	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
-	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
-	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+	args.taskfile = *taskfile;
+	args.hobfile = *hobfile;
+
+	init_taskfile_request(&rq);
 
-	ide_init_drive_taskfile(&rq);
 	/* This is kept for internal use only !!! */
 	ide_cmd_type_parser(&args);
 	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
@@ -1006,64 +893,33 @@
 
 	rq.buffer = buf;
 	rq.special = &args;
+
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *args, byte *buf)
 {
 	struct request rq;
-	ide_init_drive_taskfile(&rq);
+	init_taskfile_request(&rq);
 	rq.buffer = buf;
 
 	if (args->command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		rq.current_nr_sectors = rq.nr_sectors
+			= (args->hobfile.sector_count << 8)
+			| args->taskfile.sector_count;
 
 	rq.special = args;
+
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
- *  The taskfile glue table
- *
- *  reqtask.data_phase	reqtask.req_cmd
- *			args.command_type		args.handler
- *
- *  TASKFILE_P_OUT_DMAQ	??				??
- *  TASKFILE_P_IN_DMAQ	??				??
- *  TASKFILE_P_OUT_DMA	??				??
- *  TASKFILE_P_IN_DMA	??				??
- *  TASKFILE_P_OUT	??				??
- *  TASKFILE_P_IN	??				??
- *
- *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_IN_OUT	??				??
- *
- *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
- *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
- *
- *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
- *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
- *
- *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
- *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
- *
- *			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
- *			IDE_DRIVE_TASK_INVALID
- *
- */
-
-/*
- * Issue ATA command and wait for completion. use for implementing commands in
+ * Issue ATA command and wait for completion. Use for implementing commands in
  * kernel.
  *
  * The caller has to make sure buf is never NULL!
  */
-static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf)
+static int ide_wait_cmd(ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *argbuf)
 {
 	struct request rq;
 
@@ -1072,10 +928,10 @@
 	memset(argbuf, 0, 4 + SECTOR_WORDS * 4 * sectors);
 	ide_init_drive_cmd(&rq);
 	rq.buffer = argbuf;
-	*argbuf++ = cmd;
-	*argbuf++ = nsect;
-	*argbuf++ = feature;
-	*argbuf++ = sectors;
+	argbuf[0] = cmd;
+	argbuf[1] = nsect;
+	argbuf[2] = feature;
+	argbuf[3] = sectors;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -1083,7 +939,8 @@
 int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	int err = 0;
-	byte args[4], *argbuf = args;
+	u8 args[4];
+	u8 *argbuf = args;
 	byte xfer_rate = 0;
 	int argsize = 4;
 	ide_task_t tfargs;
@@ -1096,13 +953,13 @@
 	if (copy_from_user(args, (void *)arg, 4))
 		return -EFAULT;
 
-	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+	tfargs.taskfile.feature = args[2];
+	tfargs.taskfile.sector_count = args[3];
+	tfargs.taskfile.sector_number = args[1];
+	tfargs.taskfile.low_cylinder = 0x00;
+	tfargs.taskfile.high_cylinder = 0x00;
+	tfargs.taskfile.device_head = 0x00;
+	tfargs.taskfile.command = args[0];
 
 	if (args[3]) {
 		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
@@ -1121,8 +978,8 @@
 
 	if (!err && xfer_rate) {
 		/* active-retuning-calls future */
-		if ((HWIF(drive)->speedproc) != NULL)
-			HWIF(drive)->speedproc(drive, xfer_rate);
+		if ((drive->channel->speedproc) != NULL)
+			drive->channel->speedproc(drive, xfer_rate);
 		ide_driveid_update(drive);
 	}
 abort:
@@ -1162,8 +1019,7 @@
 EXPORT_SYMBOL(atapi_output_bytes);
 EXPORT_SYMBOL(taskfile_input_data);
 EXPORT_SYMBOL(taskfile_output_data);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
+EXPORT_SYMBOL(ata_taskfile);
 
 EXPORT_SYMBOL(recal_intr);
 EXPORT_SYMBOL(set_geometry_intr);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ide.c	Wed Apr  3 17:11:15 2002
@@ -223,7 +223,7 @@
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
-ide_hwif_t ide_hwifs[MAX_HWIFS];	/* master data repository */
+struct ata_channel ide_hwifs[MAX_HWIFS];	/* master data repository */
 
 #if (DISK_RECOVERY_TIME > 0)
 /*
@@ -244,19 +244,19 @@
 	__restore_flags(flags);	/* local CPU only */
 	return (t - i);
 }
-#endif /* DISK_RECOVERY_TIME */
+#endif
 
-static inline void set_recovery_timer (ide_hwif_t *hwif)
+static inline void set_recovery_timer(struct ata_channel *channel)
 {
 #if (DISK_RECOVERY_TIME > 0)
-	hwif->last_time = read_timer();
-#endif /* DISK_RECOVERY_TIME */
+	channel->last_time = read_timer();
+#endif
 }
 
 /*
  * Do not even *think* about calling this!
  */
-static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
+static void init_hwif_data(struct ata_channel *hwif, unsigned int index)
 {
 	static const byte ide_major[] = {
 		IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, IDE4_MAJOR,
@@ -267,7 +267,7 @@
 	hw_regs_t hw;
 
 	/* bulk initialize hwif & drive info with zeros */
-	memset(hwif, 0, sizeof(ide_hwif_t));
+	memset(hwif, 0, sizeof(struct ata_channel));
 	memset(&hw, 0, sizeof(hw_regs_t));
 
 	/* fill in any non-zero initial values */
@@ -288,7 +288,7 @@
 
 		drive->type			= ATA_DISK;
 		drive->select.all		= (unit<<4)|0xa0;
-		drive->hwif			= hwif;
+		drive->channel			= hwif;
 		drive->ctl			= 0x08;
 		drive->ready_stat		= READY_STAT;
 		drive->bad_wstat		= BAD_W_STAT;
@@ -445,13 +445,13 @@
 	if (drive->using_dma) {
 		/* check the DMA crc count */
 		if (drive->crc_count) {
-			HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-			if ((HWIF(drive)->speedproc) != NULL)
-				HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive));
+			drive->channel->dmaproc(ide_dma_off_quietly, drive);
+			if ((drive->channel->speedproc) != NULL)
+				drive->channel->speedproc(drive, ide_auto_reduce_xfer(drive));
 			if (drive->current_speed >= XFER_SW_DMA_0)
-				HWIF(drive)->dmaproc(ide_dma_on, drive);
+				drive->channel->dmaproc(ide_dma_on, drive);
 		} else
-			HWIF(drive)->dmaproc(ide_dma_off, drive);
+			drive->channel->dmaproc(ide_dma_off, drive);
 	}
 }
 
@@ -483,7 +483,7 @@
 	printk("%s: ata_special: 0x%02x\n", drive->name, s->all);
 #endif
 	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
+		ide_tuneproc_t *tuneproc = drive->channel->tuneproc;
 		s->b.set_tune = 0;
 		if (tuneproc != NULL)
 			tuneproc(drive, drive->tune_req);
@@ -507,9 +507,9 @@
 extern struct block_device_operations ide_fops[];
 
 /*
- * ide_geninit() is called exactly *once* for each interface.
+ * This is called exactly *once* for each channel.
  */
-void ide_geninit (ide_hwif_t *hwif)
+void ide_geninit(struct ata_channel *hwif)
 {
 	unsigned int unit;
 	struct gendisk *gd = hwif->gd;
@@ -542,13 +542,14 @@
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	byte stat;
 
-	SELECT_DRIVE(HWIF(drive),drive);
+	SELECT_DRIVE(drive->channel,drive);
 	udelay (10);
 
 	if (OK_STAT(stat=GET_STAT(), 0, BUSY_STAT)) {
 		printk("%s: ATAPI reset complete\n", drive->name);
 	} else {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
@@ -569,11 +570,12 @@
 static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
 {
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	byte tmp;
 
 	if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) {
-		if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
 			return ide_started;	/* continue polling */
 		}
@@ -632,7 +634,7 @@
 {
 	unsigned int unit;
 	unsigned long flags;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 
 	__save_flags(flags);	/* local CPU only */
@@ -645,6 +647,7 @@
 		udelay (20);
 		OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
 		__restore_flags (flags);	/* local CPU only */
 		return ide_started;
@@ -679,7 +682,8 @@
 	}
 	udelay(10);			/* more than enough time */
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL);
+	BUG_ON(HWGROUP(drive)->handler);
+	ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
 
 	/*
 	 * Some weird controller like resetting themselves to a strange
@@ -737,27 +741,25 @@
 		ide_task_t *args = (ide_task_t *) rq->special;
 		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 		if (args) {
-			if (args->tf_in_flags.b.data) {
-				unsigned short data			= IN_WORD(IDE_DATA_REG);
-				args->tfRegister[IDE_DATA_OFFSET]	= (data) & 0xFF;
-				args->hobRegister[IDE_DATA_OFFSET_HOB]	= (data >> 8) & 0xFF;
-			}
-			args->tfRegister[IDE_ERROR_OFFSET]   = err;
-			args->tfRegister[IDE_NSECTOR_OFFSET] = IN_BYTE(IDE_NSECTOR_REG);
-			args->tfRegister[IDE_SECTOR_OFFSET]  = IN_BYTE(IDE_SECTOR_REG);
-			args->tfRegister[IDE_LCYL_OFFSET]    = IN_BYTE(IDE_LCYL_REG);
-			args->tfRegister[IDE_HCYL_OFFSET]    = IN_BYTE(IDE_HCYL_REG);
-			args->tfRegister[IDE_SELECT_OFFSET]  = IN_BYTE(IDE_SELECT_REG);
-			args->tfRegister[IDE_STATUS_OFFSET]  = stat;
+			args->taskfile.feature = err;
+			args->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+			args->taskfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+			args->taskfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+			args->taskfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
+			args->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
+			args->taskfile.command = stat;
 			if ((drive->id->command_set_2 & 0x0400) &&
 			    (drive->id->cfs_enable_2 & 0x0400) &&
 			    (drive->addressing == 1)) {
-				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG_HOB);
-				args->hobRegister[IDE_FEATURE_OFFSET_HOB] = IN_BYTE(IDE_FEATURE_REG);
-				args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = IN_BYTE(IDE_NSECTOR_REG);
-				args->hobRegister[IDE_SECTOR_OFFSET_HOB]  = IN_BYTE(IDE_SECTOR_REG);
-				args->hobRegister[IDE_LCYL_OFFSET_HOB]    = IN_BYTE(IDE_LCYL_REG);
-				args->hobRegister[IDE_HCYL_OFFSET_HOB]    = IN_BYTE(IDE_HCYL_REG);
+				/* The following command goes to the hob file! */
+
+				OUT_BYTE(drive->ctl|0x80, IDE_CONTROL_REG);
+				args->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
+				args->hobfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
+
+				args->hobfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
+				args->hobfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
+				args->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
 			}
 		}
 	}
@@ -933,10 +935,11 @@
  */
 void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler)
 {
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler (drive, handler, WAIT_CMD, NULL);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive),drive,0);
+	SELECT_MASK(drive->channel, drive, 0);
 	OUT_BYTE(nsect,IDE_NSECTOR_REG);
 	OUT_BYTE(cmd,IDE_COMMAND_REG);
 }
@@ -978,7 +981,7 @@
  * setting a timer to wake up at half second intervals thereafter,
  * until timeout is achieved, before timing out.
  */
-int ide_wait_stat (ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
+int ide_wait_stat(ide_startstop_t *startstop, ide_drive_t *drive, byte good, byte bad, unsigned long timeout) {
 	byte stat;
 	int i;
 	unsigned long flags;
@@ -1020,90 +1023,6 @@
 }
 
 /*
- * execute_drive_cmd() issues a special drive command,
- * usually initiated by ioctl() from the external hdparm program.
- */
-static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq)
-{
-	if (rq->flags & REQ_DRIVE_TASKFILE) {
-		ide_task_t *args = rq->special;
-
-		if (!(args))
-			goto args_error;
-
-		do_taskfile(drive,
-				(struct hd_drive_task_hdr *)&args->tfRegister,
-				(struct hd_drive_hob_hdr *)&args->hobRegister,
-				args->handler);
-
-		if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
-		     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
-		      args->prehandler && args->handler)
-			return args->prehandler(drive, rq);
-		return ide_started;
-
-	} else if (rq->flags & REQ_DRIVE_TASK) {
-		byte *args = rq->buffer;
-		byte sel;
-
-		if (!(args)) goto args_error;
-#ifdef DEBUG
-			printk("%s: DRIVE_TASK_CMD ", drive->name);
-			printk("cmd=0x%02x ", args[0]);
-			printk("fr=0x%02x ", args[1]);
-			printk("ns=0x%02x ", args[2]);
-			printk("sc=0x%02x ", args[3]);
-			printk("lcyl=0x%02x ", args[4]);
-			printk("hcyl=0x%02x ", args[5]);
-			printk("sel=0x%02x\n", args[6]);
-#endif
-		OUT_BYTE(args[1], IDE_FEATURE_REG);
-		OUT_BYTE(args[3], IDE_SECTOR_REG);
-		OUT_BYTE(args[4], IDE_LCYL_REG);
-		OUT_BYTE(args[5], IDE_HCYL_REG);
-		sel = (args[6] & ~0x10);
-		if (drive->select.b.unit)
-			sel |= 0x10;
-		OUT_BYTE(sel, IDE_SELECT_REG);
-		ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
-		return ide_started;
-	} else if (rq->flags & REQ_DRIVE_CMD) {
-
-		byte *args = rq->buffer;
-		if (!(args)) goto args_error;
-#ifdef DEBUG
-		printk("%s: DRIVE_CMD ", drive->name);
-		printk("cmd=0x%02x ", args[0]);
-		printk("sc=0x%02x ", args[1]);
-		printk("fr=0x%02x ", args[2]);
-		printk("xx=0x%02x\n", args[3]);
-#endif
-		if (args[0] == WIN_SMART) {
-			OUT_BYTE(0x4f, IDE_LCYL_REG);
-			OUT_BYTE(0xc2, IDE_HCYL_REG);
-			OUT_BYTE(args[2],IDE_FEATURE_REG);
-			OUT_BYTE(args[1],IDE_SECTOR_REG);
-			ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
-			return ide_started;
-		}
-		OUT_BYTE(args[2],IDE_FEATURE_REG);
-		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
-		return ide_started;
-	}
-
-args_error:
-	/*
-	 * NULL is actually a valid way of waiting for
-	 * all current requests to be flushed from the queue.
-	 */
-#ifdef DEBUG
-	printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
-	ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
-	return ide_stopped;
-}
-
-/*
  * start_request() initiates handling of a new I/O request
  */
 static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
@@ -1111,7 +1030,7 @@
 	ide_startstop_t startstop;
 	unsigned long block;
 	unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
 
@@ -1150,9 +1069,100 @@
 		printk(KERN_WARNING "%s: drive not ready for command\n", drive->name);
 		return startstop;
 	}
+
+	/* FIXME: We can see nicely here that all commands should be submitted
+	 * through the request queue and that the special field in drive should
+	 * go as soon as possible!
+	 */
+
 	if (!drive->special.all) {
-		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE))
-			return execute_drive_cmd(drive, rq);
+		if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+			/* This issues a special drive command, usually
+			 * initiated by ioctl() from the external hdparm
+			 * program.
+			 */
+
+			if (rq->flags & REQ_DRIVE_TASKFILE) {
+				ide_task_t *args = rq->special;
+
+				if (!(args))
+					goto args_error;
+
+				ata_taskfile(drive,
+						&args->taskfile,
+						&args->hobfile,
+						args->handler, NULL, NULL);
+
+				if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
+					(args->command_type == IDE_DRIVE_TASK_OUT)) &&
+						args->prehandler && args->handler)
+					return args->prehandler(drive, rq);
+				return ide_started;
+
+			} else if (rq->flags & REQ_DRIVE_TASK) {
+				byte *args = rq->buffer;
+				byte sel;
+
+				if (!(args)) goto args_error;
+#ifdef DEBUG
+				printk("%s: DRIVE_TASK_CMD ", drive->name);
+				printk("cmd=0x%02x ", args[0]);
+				printk("fr=0x%02x ", args[1]);
+				printk("ns=0x%02x ", args[2]);
+				printk("sc=0x%02x ", args[3]);
+				printk("lcyl=0x%02x ", args[4]);
+				printk("hcyl=0x%02x ", args[5]);
+				printk("sel=0x%02x\n", args[6]);
+#endif
+				OUT_BYTE(args[1], IDE_FEATURE_REG);
+				OUT_BYTE(args[3], IDE_SECTOR_REG);
+				OUT_BYTE(args[4], IDE_LCYL_REG);
+				OUT_BYTE(args[5], IDE_HCYL_REG);
+				sel = (args[6] & ~0x10);
+				if (drive->select.b.unit)
+					sel |= 0x10;
+				OUT_BYTE(sel, IDE_SELECT_REG);
+				ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
+				return ide_started;
+			} else if (rq->flags & REQ_DRIVE_CMD) {
+				byte *args = rq->buffer;
+				if (!(args)) goto args_error;
+#ifdef DEBUG
+				printk("%s: DRIVE_CMD ", drive->name);
+				printk("cmd=0x%02x ", args[0]);
+				printk("sc=0x%02x ", args[1]);
+				printk("fr=0x%02x ", args[2]);
+				printk("xx=0x%02x\n", args[3]);
+#endif
+				if (args[0] == WIN_SMART) {
+					OUT_BYTE(0x4f, IDE_LCYL_REG);
+					OUT_BYTE(0xc2, IDE_HCYL_REG);
+					OUT_BYTE(args[2],IDE_FEATURE_REG);
+					OUT_BYTE(args[1],IDE_SECTOR_REG);
+					ide_cmd(drive, args[0], args[3], &drive_cmd_intr);
+
+					return ide_started;
+				}
+				OUT_BYTE(args[2],IDE_FEATURE_REG);
+				ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
+				return ide_started;
+			}
+
+args_error:
+			/*
+			 * NULL is actually a valid way of waiting for all
+			 * current requests to be flushed from the queue.
+			 */
+#ifdef DEBUG
+			printk("%s: DRIVE_CMD (null)\n", drive->name);
+#endif
+			ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());
+			return ide_stopped;
+		}
+
+		/* The normal way of execution is to pass execute the request
+		 * handler.
+		 */
 
 		if (ata_ops(drive)) {
 			if (ata_ops(drive)->do_request)
@@ -1194,55 +1204,34 @@
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
  * to the hwgroup by sleeping for timeout jiffies.
  */
-void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
+void ide_stall_queue(ide_drive_t *drive, unsigned long timeout)
 {
 	if (timeout > WAIT_WORSTCASE)
 		timeout = WAIT_WORSTCASE;
-	drive->sleep = timeout + jiffies;
+	drive->PADAM_sleep = timeout + jiffies;
 }
 
-#define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
-
 /*
  * choose_drive() selects the next drive which will be serviced.
  */
-static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
+static inline ide_drive_t *choose_drive(ide_hwgroup_t *hwgroup)
 {
 	ide_drive_t *drive, *best;
 
-repeat:
 	best = NULL;
 	drive = hwgroup->drive;
 	do {
-		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+		if (!list_empty(&drive->queue.queue_head)
+		&& (!drive->PADAM_sleep	|| time_after_eq(drive->PADAM_sleep, jiffies))) {
 			if (!best
-			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
-			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
+			 || (drive->PADAM_sleep && (!best->PADAM_sleep || time_after(best->PADAM_sleep, drive->PADAM_sleep)))
+			 || (!best->PADAM_sleep && time_after(best->PADAM_service_start + 2 * best->PADAM_service_time, drive->PADAM_service_start + 2 * drive->PADAM_service_time)))
 			{
 				if (!blk_queue_plugged(&drive->queue))
 					best = drive;
 			}
 		}
 	} while ((drive = drive->next) != hwgroup->drive);
-	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
-		long t = (signed long)(WAKEUP(best) - jiffies);
-		if (t >= WAIT_MIN_SLEEP) {
-			/*
-			 * We *may* have some time to spare, but first let's see if
-			 * someone can potentially benefit from our nice mood today..
-			 */
-			drive = best->next;
-			do {
-				if (!drive->sleep
-				 && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time))
-				 && 0 < (signed long)((jiffies + t) - WAKEUP(drive)))
-				{
-					ide_stall_queue(best, min(t, 10L * WAIT_MIN_SLEEP));
-					goto repeat;
-				}
-			} while ((drive = drive->next) != best);
-		}
-	}
 	return best;
 }
 
@@ -1278,8 +1267,8 @@
  */
 static void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq)
 {
-	ide_drive_t	*drive;
-	ide_hwif_t	*hwif;
+	ide_drive_t *drive;
+	struct ata_channel *hwif;
 	ide_startstop_t	startstop;
 	struct request	*rq;
 
@@ -1294,8 +1283,8 @@
 			hwgroup->rq = NULL;
 			drive = hwgroup->drive;
 			do {
-				if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep)))
-					sleep = drive->sleep;
+				if (drive->PADAM_sleep && (!sleep || time_after(sleep, drive->PADAM_sleep)))
+					sleep = drive->PADAM_sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
 			if (sleep) {
 				/*
@@ -1304,7 +1293,7 @@
 				 * play fairly with us, just in case there are big differences
 				 * in relative throughputs.. don't want to hog the cpu too much.
 				 */
-				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
+				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep))
 					sleep = jiffies + WAIT_MIN_SLEEP;
 #if 1
 				if (timer_pending(&hwgroup->timer))
@@ -1320,7 +1309,7 @@
 			}
 			return;		/* no more work for this hwgroup (for now) */
 		}
-		hwif = HWIF(drive);
+		hwif = drive->channel;
 		if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif && hwif->io_ports[IDE_CONTROL_OFFSET]) {
 			/* set nIEN for previous hwif */
 
@@ -1331,8 +1320,8 @@
 		}
 		hwgroup->hwif = hwif;
 		hwgroup->drive = drive;
-		drive->sleep = 0;
-		drive->service_start = jiffies;
+		drive->PADAM_sleep = 0;
+		drive->PADAM_service_start = jiffies;
 
 		if (blk_queue_plugged(&drive->queue))
 			BUG();
@@ -1366,11 +1355,12 @@
 /*
  * Returns the queue which corresponds to a given device.
  */
-request_queue_t *ide_get_queue (kdev_t dev)
+request_queue_t *ide_get_queue(kdev_t dev)
 {
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
+	struct ata_channel *channel = (struct ata_channel *)blk_dev[major(dev)].data;
 
-	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+	/* FIXME: ALLERT: This discriminates between master and slave! */
+	return &channel->drives[DEVICE_NR(dev) & 1].queue;
 }
 
 /*
@@ -1388,7 +1378,7 @@
  */
 void ide_dma_timeout_retry(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct request *rq;
 
 	/*
@@ -1461,7 +1451,7 @@
 			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
 			hwgroup->handler = NULL;
 		} else {
-			ide_hwif_t *hwif;
+			struct ata_channel *hwif;
 			ide_startstop_t startstop;
 			/* paranoia */
 			if (!test_and_set_bit(IDE_BUSY, &hwgroup->flags))
@@ -1483,7 +1473,7 @@
 			 * mask the specific IRQ:
 			 */
 			spin_unlock(&ide_lock);
-			hwif  = HWIF(drive);
+			hwif  = drive->channel;
 #if DISABLE_IRQ_NOSYNC
 			disable_irq_nosync(hwif->irq);
 #else
@@ -1506,7 +1496,7 @@
 					startstop = ide_error(drive, "irq timeout", GET_STAT());
 			}
 			set_recovery_timer(hwif);
-			drive->service_time = jiffies - drive->service_start;
+			drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
 			enable_irq(hwif->irq);
 			spin_lock_irq(&ide_lock);
 			if (startstop == ide_stopped)
@@ -1540,10 +1530,10 @@
  * accidentally invoked as a result of any valid command completion interrupt.
  *
  */
-static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
+static void unexpected_intr(int irq, ide_hwgroup_t *hwgroup)
 {
 	byte stat;
-	ide_hwif_t *hwif = hwgroup->hwif;
+	struct ata_channel *hwif = hwgroup->hwif;
 
 	/*
 	 * handle the unexpected interrupt
@@ -1568,11 +1558,11 @@
 /*
  * entry point for all interrupts, caller does __cli() for us
  */
-void ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+void ide_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	ide_drive_t *drive;
 	ide_handler_t *handler;
 	ide_startstop_t startstop;
@@ -1611,7 +1601,7 @@
 			 * Whack the status register, just in case we have a leftover pending IRQ.
 			 */
 			IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+#endif
 		}
 		goto out_lock;
 	}
@@ -1650,8 +1640,8 @@
 	 * same irq as is currently being serviced here, and Linux
 	 * won't allow another of the same (on any CPU) until we return.
 	 */
-	set_recovery_timer(HWIF(drive));
-	drive->service_time = jiffies - drive->service_start;
+	set_recovery_timer(drive->channel);
+	drive->PADAM_service_time = jiffies - drive->PADAM_service_start;
 	if (startstop == ide_stopped) {
 		if (hwgroup->handler == NULL) {	/* paranoia */
 			clear_bit(IDE_BUSY, &hwgroup->flags);
@@ -1675,7 +1665,7 @@
 	int h;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_hwif_t  *hwif = &ide_hwifs[h];
+		struct ata_channel *hwif = &ide_hwifs[h];
 		if (hwif->present && major == hwif->major) {
 			int unit = DEVICE_NR(i_rdev);
 			if (unit < MAX_DRIVES) {
@@ -1699,41 +1689,39 @@
 }
 
 /*
- * This function issues a special IDE device request
- * onto the request queue.
+ * This function issues a special IDE device request onto the request queue.
  *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
+ * If action is ide_wait, then the rq is queued at the end of the request
+ * queue, and the function sleeps until it has been processed.  This is for use
+ * when invoked from an ioctl handler.
+ *
+ * If action is ide_preempt, then the rq is queued at the head of the request
+ * queue, displacing the currently-being-processed request and this function
+ * returns immediately without waiting for the new rq to be completed.  This is
+ * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom
+ * driver code.
+ *
+ * If action is ide_next, then the rq is queued immediately after the
+ * currently-being-processed-request (if any), and the function returns without
+ * waiting for the new rq to be completed.  As above, This is VERY DANGEROUS,
+ * and is intended for careful use by the ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the request queue,
+ * and the function returns immediately without waiting for the new rq to be
+ * completed. This is again intended for careful use by the ATAPI tape/cdrom
+ * driver code.
  */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
+int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned int major = HWIF(drive)->major;
+	unsigned int major = drive->channel->major;
 	request_queue_t *q = &drive->queue;
 	struct list_head *queue_head = &q->queue_head;
 	DECLARE_COMPLETION(wait);
 
 #ifdef CONFIG_BLK_DEV_PDC4030
-	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)
+	if (drive->channel->chipset == ide_pdc4030 && rq->buffer != NULL)
 		return -ENOSYS;  /* special drive cmds not supported */
 #endif
 	rq->errors = 0;
@@ -1812,7 +1800,7 @@
  */
 void revalidate_drives(void)
 {
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	ide_drive_t *drive;
 	int h;
 
@@ -1935,29 +1923,28 @@
  * Note that we only release the standard ports, and do not even try to handle
  * any extra ports allocated for weird IDE interface chipsets.
  */
-static void hwif_unregister(ide_hwif_t *hwif)
+static void hwif_unregister(struct ata_channel *hwif)
 {
 	if (hwif->straight8) {
 		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
-		goto jump_eight;
+	} else {
+		if (hwif->io_ports[IDE_DATA_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
+		if (hwif->io_ports[IDE_ERROR_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
+		if (hwif->io_ports[IDE_NSECTOR_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
+		if (hwif->io_ports[IDE_SECTOR_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
+		if (hwif->io_ports[IDE_LCYL_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
+		if (hwif->io_ports[IDE_HCYL_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
+		if (hwif->io_ports[IDE_SELECT_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
+		if (hwif->io_ports[IDE_STATUS_OFFSET])
+			ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
 	}
-	if (hwif->io_ports[IDE_DATA_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);
-	if (hwif->io_ports[IDE_ERROR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);
-	if (hwif->io_ports[IDE_NSECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_SECTOR_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);
-	if (hwif->io_ports[IDE_LCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_HCYL_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);
-	if (hwif->io_ports[IDE_SELECT_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);
-	if (hwif->io_ports[IDE_STATUS_OFFSET])
-		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);
-jump_eight:
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
 		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
@@ -1966,23 +1953,22 @@
 #endif
 }
 
-void ide_unregister(ide_hwif_t *hwif)
+void ide_unregister(struct ata_channel *channel)
 {
 	struct gendisk *gd;
 	ide_drive_t *drive, *d;
-	ide_hwif_t *g;
 	ide_hwgroup_t *hwgroup;
-	int irq_count = 0, unit, i;
+	int unit, i;
 	unsigned long flags;
 	unsigned int p, minor;
-	ide_hwif_t old_hwif;
+	struct ata_channel old_hwif;
 
 	spin_lock_irqsave(&ide_lock, flags);
-	if (!hwif->present)
+	if (!channel->present)
 		goto abort;
-	put_device(&hwif->device);
+	put_device(&channel->dev);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		drive = &hwif->drives[unit];
+		drive = &channel->drives[unit];
 		if (!drive->present)
 			continue;
 		if (drive->busy || drive->usage)
@@ -1995,43 +1981,47 @@
 				ide_unregister_subdriver(drive);
 		}
 	}
-	hwif->present = 0;
+	channel->present = 0;
 
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
 	spin_unlock_irqrestore(&ide_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		drive = &hwif->drives[unit];
+		drive = &channel->drives[unit];
 		if (!drive->present)
 			continue;
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
-				kdev_t devp = mk_kdev(hwif->major, minor+p);
+				kdev_t devp = mk_kdev(channel->major, minor+p);
 				invalidate_device(devp, 0);
 			}
 		}
 	}
 #ifdef CONFIG_PROC_FS
-	destroy_proc_ide_drives(hwif);
+	destroy_proc_ide_drives(channel);
 #endif
 	spin_lock_irqsave(&ide_lock, flags);
-	hwgroup = hwif->hwgroup;
+	hwgroup = channel->hwgroup;
 
 	/*
 	 * free the irq if we were the only hwif using it
 	 */
-	g = hwgroup->hwif;
-	do {
-		if (g->irq == hwif->irq)
-			++irq_count;
-		g = g->next;
-	} while (g != hwgroup->hwif);
-	if (irq_count == 1)
-		free_irq(hwif->irq, hwgroup);
-
-	hwif_unregister(hwif);
+	{
+		struct ata_channel *g;
+		int irq_count = 0;
+
+		g = hwgroup->hwif;
+		do {
+			if (g->irq == channel->irq)
+				++irq_count;
+			g = g->next;
+		} while (g != hwgroup->hwif);
+		if (irq_count == 1)
+			free_irq(channel->irq, hwgroup);
+	}
+	hwif_unregister(channel);
 
 	/*
 	 * Remove us from the hwgroup, and free
@@ -2039,7 +2029,7 @@
 	 */
 	d = hwgroup->drive;
 	for (i = 0; i < MAX_DRIVES; ++i) {
-		drive = &hwif->drives[i];
+		drive = &channel->drives[i];
 		if (drive->de) {
 			devfs_unregister (drive->de);
 			drive->de = NULL;
@@ -2060,27 +2050,27 @@
 	}
 	if (d->present)
 		hwgroup->drive = d;
-	while (hwgroup->hwif->next != hwif)
+	while (hwgroup->hwif->next != channel)
 		hwgroup->hwif = hwgroup->hwif->next;
-	hwgroup->hwif->next = hwif->next;
-	if (hwgroup->hwif == hwif)
+	hwgroup->hwif->next = channel->next;
+	if (hwgroup->hwif == channel)
 		kfree(hwgroup);
 	else
-		hwgroup->hwif = HWIF(hwgroup->drive);
+		hwgroup->hwif = hwgroup->drive->channel;
 
 #if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	ide_release_dma(hwif);
+	ide_release_dma(channel);
 #endif
 
 	/*
 	 * Remove us from the kernel's knowledge
 	 */
-	unregister_blkdev(hwif->major, hwif->name);
-	kfree(blksize_size[hwif->major]);
-	blk_dev[hwif->major].data = NULL;
-	blk_dev[hwif->major].queue = NULL;
-	blk_clear(hwif->major);
-	gd = hwif->gd;
+	unregister_blkdev(channel->major, channel->name);
+	kfree(blksize_size[channel->major]);
+	blk_dev[channel->major].data = NULL;
+	blk_dev[channel->major].queue = NULL;
+	blk_clear(channel->major);
+	gd = channel->gd;
 	if (gd) {
 		del_gendisk(gd);
 		kfree(gd->sizes);
@@ -2090,45 +2080,45 @@
 		if (gd->flags)
 			kfree (gd->flags);
 		kfree(gd);
-		hwif->gd = NULL;
+		channel->gd = NULL;
 	}
 
 	/*
-	 * Reinitialize the hwif handler, but preserve any special methods for
+	 * Reinitialize the channel handler, but preserve any special methods for
 	 * it.
 	 */
 
-	old_hwif		= *hwif;
-	init_hwif_data(hwif, hwif->index);
-	hwif->hwgroup		= old_hwif.hwgroup;
-	hwif->tuneproc		= old_hwif.tuneproc;
-	hwif->speedproc		= old_hwif.speedproc;
-	hwif->selectproc	= old_hwif.selectproc;
-	hwif->resetproc		= old_hwif.resetproc;
-	hwif->intrproc		= old_hwif.intrproc;
-	hwif->maskproc		= old_hwif.maskproc;
-	hwif->quirkproc		= old_hwif.quirkproc;
-	hwif->rwproc		= old_hwif.rwproc;
-	hwif->ideproc		= old_hwif.ideproc;
-	hwif->dmaproc		= old_hwif.dmaproc;
-	hwif->busproc		= old_hwif.busproc;
-	hwif->bus_state		= old_hwif.bus_state;
-	hwif->dma_base		= old_hwif.dma_base;
-	hwif->dma_extra		= old_hwif.dma_extra;
-	hwif->config_data	= old_hwif.config_data;
-	hwif->select_data	= old_hwif.select_data;
-	hwif->proc		= old_hwif.proc;
+	old_hwif		= *channel;
+	init_hwif_data(channel, channel->index);
+	channel->hwgroup = old_hwif.hwgroup;
+	channel->tuneproc = old_hwif.tuneproc;
+	channel->speedproc = old_hwif.speedproc;
+	channel->selectproc = old_hwif.selectproc;
+	channel->resetproc = old_hwif.resetproc;
+	channel->intrproc = old_hwif.intrproc;
+	channel->maskproc = old_hwif.maskproc;
+	channel->quirkproc = old_hwif.quirkproc;
+	channel->rwproc	= old_hwif.rwproc;
+	channel->ideproc = old_hwif.ideproc;
+	channel->dmaproc = old_hwif.dmaproc;
+	channel->busproc = old_hwif.busproc;
+	channel->bus_state = old_hwif.bus_state;
+	channel->dma_base = old_hwif.dma_base;
+	channel->dma_extra = old_hwif.dma_extra;
+	channel->config_data = old_hwif.config_data;
+	channel->select_data = old_hwif.select_data;
+	channel->proc = old_hwif.proc;
 #ifndef CONFIG_BLK_DEV_IDECS
-	hwif->irq		= old_hwif.irq;
+	channel->irq = old_hwif.irq;
 #endif
-	hwif->major		= old_hwif.major;
-	hwif->chipset		= old_hwif.chipset;
-	hwif->autodma		= old_hwif.autodma;
-	hwif->udma_four		= old_hwif.udma_four;
+	channel->major = old_hwif.major;
+	channel->chipset = old_hwif.chipset;
+	channel->autodma = old_hwif.autodma;
+	channel->udma_four = old_hwif.udma_four;
 #ifdef CONFIG_BLK_DEV_IDEPCI
-	hwif->pci_dev		= old_hwif.pci_dev;
+	channel->pci_dev = old_hwif.pci_dev;
 #endif
-	hwif->straight8		= old_hwif.straight8;
+	channel->straight8 = old_hwif.straight8;
 abort:
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
@@ -2173,10 +2163,11 @@
  * Register an IDE interface, specifing exactly the registers etc
  * Set init=1 iff calling before probes have taken place.
  */
-int ide_register_hw(hw_regs_t *hw, ide_hwif_t **hwifp)
+int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp)
 {
-	int h, retry = 1;
-	ide_hwif_t *hwif;
+	int h;
+	int retry = 1;
+	struct ata_channel *hwif;
 
 	do {
 		for (h = 0; h < MAX_HWIFS; ++h) {
@@ -2193,7 +2184,9 @@
 		for (h = 0; h < MAX_HWIFS; ++h)
 			ide_unregister(&ide_hwifs[h]);
 	} while (retry--);
+
 	return -1;
+
 found:
 	ide_unregister(hwif);
 	if (hwif->present)
@@ -2375,8 +2368,8 @@
 {
 	drive->io_32bit = arg;
 #ifdef CONFIG_BLK_DEV_DTC2278
-	if (HWIF(drive)->chipset == ide_dtc2278)
-		HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
+	if (drive->channel->chipset == ide_dtc2278)
+		drive->channel->drives[!drive->select.b.unit].io_32bit = arg;
 #endif /* CONFIG_BLK_DEV_DTC2278 */
 	return 0;
 }
@@ -2385,9 +2378,9 @@
 {
 	if (!drive->driver)
 		return -EPERM;
-	if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
+	if (!drive->id || !(drive->id->capability & 1) || !drive->channel->dmaproc)
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
+	if (drive->channel->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
 		return -EIO;
 	return 0;
 }
@@ -2396,14 +2389,14 @@
 {
 	struct request rq;
 
-	if (!HWIF(drive)->tuneproc)
+	if (!drive->channel->tuneproc)
 		return -ENOSYS;
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
 	drive->tune_req = (byte) arg;
 	drive->special.b.set_tune = 1;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	ide_do_drive_cmd(drive, &rq, ide_wait);
 	return 0;
 }
 
@@ -2414,7 +2407,6 @@
  */
 	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
 	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
-	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
 	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
 	ide_add_setting(drive,	"slow",			SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->slow,			NULL);
 	ide_add_setting(drive,	"unmaskirq",		drive->no_unmask ? SETTING_READ : SETTING_RW,	HDIO_GET_UNMASKINTR,	HDIO_SET_UNMASKINTR,	TYPE_BYTE,	0,	1,				1,		1,		&drive->unmask,			NULL);
@@ -2540,10 +2532,7 @@
 
 		case HDIO_GET_NICE:
 			return put_user(drive->dsc_overlap	<<	IDE_NICE_DSC_OVERLAP	|
-					drive->atapi_overlap	<<	IDE_NICE_ATAPI_OVERLAP	|
-					drive->nice0		<< 	IDE_NICE_0		|
-					drive->nice1		<<	IDE_NICE_1		|
-					drive->nice2		<<	IDE_NICE_2,
+					drive->atapi_overlap	<<	IDE_NICE_ATAPI_OVERLAP,
 					(long *) arg);
 
 		case HDIO_DRIVE_CMD:
@@ -2558,7 +2547,7 @@
 
 		case HDIO_SET_NICE:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
+			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
 				return -EPERM;
 			drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
 			/* Only CD-ROM's and tapes support DSC overlap. */
@@ -2566,7 +2555,6 @@
 				drive->dsc_overlap = 0;
 				return -EPERM;
 			}
-			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 		case BLKGETSIZE:
 		case BLKGETSIZE64:
@@ -2591,15 +2579,15 @@
 		case HDIO_GET_BUSSTATE:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			if (put_user(HWIF(drive)->bus_state, (long *)arg))
+			if (put_user(drive->channel->bus_state, (long *)arg))
 				return -EFAULT;
 			return 0;
 
 		case HDIO_SET_BUSSTATE:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			if (HWIF(drive)->busproc)
-				HWIF(drive)->busproc(drive, (int)arg);
+			if (drive->channel->busproc)
+				drive->channel->busproc(drive, (int)arg);
 			return 0;
 
 		default:
@@ -2802,7 +2790,7 @@
 int __init ide_setup (char *s)
 {
 	int i, vals[3];
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	ide_drive_t *drive;
 	unsigned int hw, unit;
 	const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1);
@@ -3116,7 +3104,7 @@
 	unsigned int unit, index, i;
 
 	for (index = 0, i = 0; index < MAX_HWIFS; ++index) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
+		struct ata_channel *hwif = &ide_hwifs[index];
 		if (!hwif->present)
 			continue;
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
@@ -3146,7 +3134,7 @@
 	}
 
 	/* FIXME: This will be pushed to the drivers! Thus allowing us to
-	 * save one parameter here eparate this out.
+	 * save one parameter here separate this out.
 	 */
 
 	drive->driver = driver;
@@ -3154,7 +3142,7 @@
 	restore_flags(flags);		/* all CPUs */
 	/* FIXME: Check what this magic number is supposed to be about? */
 	if (drive->autotune != 2) {
-		if (HWIF(drive)->dmaproc != NULL) {
+		if (drive->channel->dmaproc != NULL) {
 
 			/*
 			 * Force DMAing for the beginning of the check.  Some
@@ -3164,13 +3152,12 @@
 			 *   PARANOIA!!!
 			 */
 
-			HWIF(drive)->dmaproc(ide_dma_off_quietly, drive);
-			HWIF(drive)->dmaproc(ide_dma_check, drive);
+			drive->channel->dmaproc(ide_dma_off_quietly, drive);
+			drive->channel->dmaproc(ide_dma_check, drive);
 		}
 		/* Only CD-ROMs and tape drives support DSC overlap. */
 		drive->dsc_overlap = (drive->next != drive
 				&& (drive->type == ATA_ROM || drive->type == ATA_TAPE));
-		drive->nice1 = 1;
 	}
 	drive->revalidate = 1;
 	drive->suspend_reset = 0;
@@ -3193,10 +3180,19 @@
 
 	save_flags(flags);		/* all CPUs */
 	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || !ata_ops(drive) || ata_ops(drive)->busy) {
+
+#if 0
+	if (__MOD_IN_USE(ata_ops(drive)->owner)) {
+		restore_flags(flags);
+		return 1;
+	}
+#endif
+
+	if (drive->usage || drive->busy || !ata_ops(drive)) {
 		restore_flags(flags);	/* all CPUs */
 		return 1;
 	}
+
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
 	pnpide_init(0);
 #endif
@@ -3207,7 +3203,10 @@
 #endif
 	auto_remove_settings(drive);
 	drive->driver = NULL;
+	drive->present = 0;
+
 	restore_flags(flags);		/* all CPUs */
+
 	return 0;
 }
 
@@ -3297,7 +3296,7 @@
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
-	ide_hwif_t *hwif;
+	struct ata_channel *hwif;
 	ide_drive_t *drive;
 	int i, unit;
 
@@ -3316,6 +3315,7 @@
 		hwif = &ide_hwifs[i];
 		if (!hwif->present)
 			continue;
+
 		for (unit = 0; unit < MAX_DRIVES; ++unit) {
 			drive = &hwif->drives[unit];
 			if (!drive->present)
@@ -3479,12 +3479,13 @@
 	initializing = 0;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
-		ide_hwif_t  *hwif = &ide_hwifs[h];
-		if (hwif->present)
-			ide_geninit(hwif);
+		struct ata_channel *channel = &ide_hwifs[h];
+		if (channel->present)
+			ide_geninit(channel);
 	}
 
 	register_reboot_notifier(&ide_notifier);
+
 	return 0;
 }
 
diff -Nru a/drivers/ide/it8172.c b/drivers/ide/it8172.c
--- a/drivers/ide/it8172.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/it8172.c	Wed Apr  3 17:11:14 2002
@@ -53,7 +53,7 @@
 static int it8172_config_drive_for_dma (ide_drive_t *drive);
 static int it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
 #endif
-void __init ide_init_it8172 (ide_hwif_t *hwif);
+void __init ide_init_it8172(struct ata_channel *channel);
 
 
 static void it8172_tune_drive (ide_drive_t *drive, byte pio)
@@ -61,7 +61,7 @@
     unsigned long flags;
     u16 master_data;
     u32 slave_data;
-    int is_slave	= (&HWIF(drive)->drives[1] == drive);
+    int is_slave	= (&drive->channel->drives[1] == drive);
     int master_port	= 0x40;
     int slave_port      = 0x44;
 
@@ -70,8 +70,8 @@
     else
        pio = min_t(byte, pio, 4);
 
-    pci_read_config_word(HWIF(drive)->pci_dev, master_port, &master_data);
-    pci_read_config_dword(HWIF(drive)->pci_dev, slave_port, &slave_data);
+    pci_read_config_word(drive->channel->pci_dev, master_port, &master_data);
+    pci_read_config_dword(drive->channel->pci_dev, slave_port, &slave_data);
 
     /*
      * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
@@ -94,7 +94,7 @@
 
     save_flags(flags);
     cli();
-    pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
+    pci_write_config_word(drive->channel->pci_dev, master_port, master_data);
     restore_flags(flags);
 }
 
@@ -133,7 +133,7 @@
 
 static int it8172_tune_chipset (ide_drive_t *drive, byte speed)
 {
-    ide_hwif_t *hwif	= HWIF(drive);
+    struct ata_channel *hwif = drive->channel;
     struct pci_dev *dev	= hwif->pci_dev;
     int a_speed		= 3 << (drive->dn * 4);
     int u_flag		= 1 << drive->dn;
@@ -231,7 +231,7 @@
 }
 
 
-void __init ide_init_it8172 (ide_hwif_t *hwif)
+void __init ide_init_it8172(struct ata_channel *hwif)
 {
     struct pci_dev* dev = hwif->pci_dev;
     unsigned long cmdBase, ctrlBase;
diff -Nru a/drivers/ide/macide.c b/drivers/ide/macide.c
--- a/drivers/ide/macide.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/macide.c	Wed Apr  3 17:11:14 2002
@@ -69,7 +69,7 @@
     IDE_HCYL, IDE_SELECT, IDE_STATUS,  IDE_CONTROL
 };
 
-int macide_ack_intr(ide_hwif_t* hwif)
+int macide_ack_intr(struct ata_channel *hwif)
 {
 	if (*ide_ifr & 0x20) {
 		*ide_ifr &= ~0x20;
diff -Nru a/drivers/ide/ns87415.c b/drivers/ide/ns87415.c
--- a/drivers/ide/ns87415.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/ns87415.c	Wed Apr  3 17:11:15 2002
@@ -28,12 +28,12 @@
 
 /*
  * This routine either enables/disables (according to drive->present)
- * the IRQ associated with the port (HWIF(drive)),
+ * the IRQ associated with the port (drive->channel),
  * and selects either PIO or DMA handshaking for the next I/O operation.
  */
 static void ns87415_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned int bit, other, new, *old = (unsigned int *) hwif->select_data;
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned long flags;
@@ -43,12 +43,12 @@
 	new = *old;
 
 	/* Adjust IRQ enable bit */
-	bit = 1 << (8 + hwif->channel);
+	bit = 1 << (8 + hwif->unit);
 	new = drive->present ? (new & ~bit) : (new | bit);
 
 	/* Select PIO or DMA, DMA may only be selected for one drive/channel. */
-	bit   = 1 << (20 + drive->select.b.unit       + (hwif->channel << 1));
-	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->channel << 1));
+	bit   = 1 << (20 + drive->select.b.unit       + (hwif->unit << 1));
+	other = 1 << (20 + (1 - drive->select.b.unit) + (hwif->unit << 1));
 	new = use_dma ? ((new & ~other) | bit) : (new & ~bit);
 
 	if (new != *old) {
@@ -84,7 +84,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t	*hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	byte		dma_stat;
 
 	switch (func) {
@@ -112,7 +112,7 @@
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-void __init ide_init_ns87415 (ide_hwif_t *hwif)
+void __init ide_init_ns87415(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned int ctrl, using_inta;
@@ -138,9 +138,9 @@
 	(void) pci_read_config_dword(dev, 0x40, &ctrl);
 	(void) pci_read_config_byte(dev, 0x09, &progif);
 	/* is irq in "native" mode? */
-	using_inta = progif & (1 << (hwif->channel << 1));
+	using_inta = progif & (1 << (hwif->unit << 1));
 	if (!using_inta)
-		using_inta = ctrl & (1 << (4 + hwif->channel));
+		using_inta = ctrl & (1 << (4 + hwif->unit));
 	if (hwif->mate) {
 		hwif->select_data = hwif->mate->select_data;
 	} else {
@@ -180,7 +180,7 @@
 		outb(0x60, hwif->dma_base + 2);
 
 	if (!using_inta)
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
 		hwif->irq = hwif->mate->irq;	/* share IRQ with mate */
 
diff -Nru a/drivers/ide/opti621.c b/drivers/ide/opti621.c
--- a/drivers/ide/opti621.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/opti621.c	Wed Apr  3 17:11:14 2002
@@ -142,7 +142,7 @@
  */
 {
 	int d;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 
 	if (pio == PIO_DONT_KNOW)
 		drive->drive_data = min(ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0, OPTI621_MAX_PIO);
@@ -252,7 +252,7 @@
 	pio_clocks_t first, second;
 	int ax, drdy;
 	byte cycle1, cycle2, misc;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 
 	/* sets drive->drive_data for both drives */
 	compute_pios(drive, pio);
@@ -310,7 +310,7 @@
 /*
  * ide_init_opti621() is called once for each hwif found at boot.
  */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
+void __init ide_init_opti621(struct ata_channel *hwif)
 {
 	hwif->drives[0].drive_data = PIO_DONT_KNOW;
 	hwif->drives[1].drive_data = PIO_DONT_KNOW;
diff -Nru a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c
--- a/drivers/ide/pdc202xx.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/ide/pdc202xx.c	Wed Apr  3 17:11:16 2002
@@ -217,6 +217,9 @@
 		case PCI_DEVICE_ID_PROMISE_20275:
 			p += sprintf(p, "\n                                PDC20275 Chipset.\n");
 			break;
+		case PCI_DEVICE_ID_PROMISE_20276:
+			p += sprintf(p, "\n                                PDC20276 Chipset.\n");
+			break;
 		case PCI_DEVICE_ID_PROMISE_20269:
 			p += sprintf(p, "\n                                PDC20269 TX2 Chipset.\n");
 			break;
@@ -236,6 +239,7 @@
 	char *p = buffer;
 	switch(bmide_dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
 		case PCI_DEVICE_ID_PROMISE_20268R:
@@ -395,8 +399,8 @@
 
 static int pdc202xx_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
+	struct ata_channel *hwif = drive->channel;
+	struct pci_dev *dev = hwif->pci_dev;
 
 	unsigned int		drive_conf;
 	int			err;
@@ -519,14 +523,14 @@
 
 static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	unsigned long indexreg	= (hwif->dma_base + 1);
 	unsigned long datareg	= (hwif->dma_base + 3);
 #else
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long indexreg	= high_16 + (hwif->channel ? 0x09 : 0x01);
+	unsigned long indexreg	= high_16 + (hwif->unit ? 0x09 : 0x01);
 	unsigned long datareg	= (indexreg + 2);
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	byte thold		= 0x10;
@@ -660,6 +664,7 @@
 			OUT_BYTE(0xac, datareg);
 			break;
 		default:
+			;
 	}
 
 	if (!drive->init_speed)
@@ -698,7 +703,7 @@
 static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
 	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16   = pci_resource_start(dev, 4);
 	unsigned long dma_base  = hwif->dma_base;
@@ -720,8 +725,8 @@
 	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 1 : 0;
 	byte udma_100		= 0;
 	byte udma_133		= 0;
-	byte mask		= hwif->channel ? 0x08 : 0x02;
-	unsigned short c_mask	= hwif->channel ? (1<<11) : (1<<10);
+	byte mask		= hwif->unit ? 0x08 : 0x02;
+	unsigned short c_mask	= hwif->unit ? (1<<11) : (1<<10);
 
 	byte ultra_66		= ((id->dma_ultra & 0x0010) ||
 				   (id->dma_ultra & 0x0008)) ? 1 : 0;
@@ -732,6 +737,7 @@
 
 	switch(dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 			udma_133 = (udma_66) ? 1 : 0;
 			udma_100 = (udma_66) ? 1 : 0;
@@ -786,14 +792,14 @@
 
 	if (((ultra_66) || (ultra_100) || (ultra_133)) && (cable)) {
 #ifdef DEBUG
-		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->channel ? "Secondary" : "Primary");
+		printk("ULTRA66: %s channel of Ultra 66 requires an 80-pin cable for Ultra66 operation.\n", hwif->unit ? "Secondary" : "Primary");
 		printk("         Switching to Ultra33 mode.\n");
 #endif /* DEBUG */
 		/* Primary   : zero out second bit */
 		/* Secondary : zero out fourth bit */
 		if (!jumpbit)
 			OUT_BYTE(CLKSPD & ~mask, (high_16 + 0x11));
-		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->channel ? "Secondary":"Primary");
+		printk("Warning: %s channel requires an 80-pin cable for operation.\n", hwif->unit ? "Secondary":"Primary");
 		printk("%s reduced to Ultra33 mode.\n", drive->name);
 		udma_66 = 0; udma_100 = 0; udma_133 = 0;
 	} else {
@@ -918,7 +924,7 @@
 static int config_drive_xfer_rate (ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	ide_dma_action_t dma_func = ide_dma_off_quietly;
 
 	if (id && (id->capability & 1) && hwif->autodma) {
@@ -963,7 +969,7 @@
 		(void) config_chipset_for_pio(drive, 5);
 	}
 
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 int pdc202xx_quirkproc (ide_drive_t *drive)
@@ -981,14 +987,15 @@
 	byte newchip		= 0;
 	byte clock		= 0;
 	byte hardware48hack	= 0;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	unsigned long high_16	= pci_resource_start(dev, 4);
-	unsigned long atapi_reg	= high_16 + (hwif->channel ? 0x24 : 0x00);
+	unsigned long atapi_reg	= high_16 + (hwif->unit ? 0x24 : 0x00);
 	unsigned long dma_base	= hwif->dma_base;
 
 	switch (dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268R:
 		case PCI_DEVICE_ID_PROMISE_20268:
@@ -1016,7 +1023,7 @@
 				struct request *rq = HWGROUP(drive)->rq;
 				unsigned long word_count = 0;
 
-				outb(clock|(hwif->channel ? 0x08 : 0x02), high_16 + 0x11);
+				outb(clock|(hwif->unit ? 0x08 : 0x02), high_16 + 0x11);
 				word_count = (rq->nr_sectors << 8);
 				word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000;
 				outl(word_count, atapi_reg);
@@ -1026,7 +1033,7 @@
 			if ((drive->addressing) && (hardware48hack)) {
 				outl(0, atapi_reg);	/* zero out extra */
 				clock = IN_BYTE(high_16 + 0x11);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), high_16 + 0x11);
+				OUT_BYTE(clock & ~(hwif->unit ? 0x08:0x02), high_16 + 0x11);
 			}
 			break;
 		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
@@ -1035,7 +1042,7 @@
 				return (dma_stat & 4) == 4;
 
 			sc1d = IN_BYTE(high_16 + 0x001d);
-			if (HWIF(drive)->channel) {
+			if (drive->channel->unit) {
 				if ((sc1d & 0x50) == 0x50) goto somebody_else;
 				else if ((sc1d & 0x40) == 0x40)
 					return (dma_stat & 4) == 4;
@@ -1048,8 +1055,8 @@
 			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
 		case ide_dma_lostirq:
 		case ide_dma_timeout:
-			if (HWIF(drive)->resetproc != NULL)
-				HWIF(drive)->resetproc(drive);
+			if (drive->channel->resetproc != NULL)
+				drive->channel->resetproc(drive);
 		default:
 			break;
 	}
@@ -1064,12 +1071,12 @@
 	OUT_BYTE(0x00,IDE_CONTROL_REG);
 	mdelay(1000);
 	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
+		drive->channel->unit ? "Secondary" : "Primary");
 }
 
 void pdc202xx_reset (ide_drive_t *drive)
 {
-	unsigned long high_16	= pci_resource_start(HWIF(drive)->pci_dev, 4);
+	unsigned long high_16	= pci_resource_start(drive->channel->pci_dev, 4);
 	byte udma_speed_flag	= IN_BYTE(high_16 + 0x001f);
 
 	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
@@ -1077,7 +1084,7 @@
 	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
 	mdelay(2000);		/* 2 seconds ?! */
 	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
+		drive->channel->unit ? "Secondary" : "Primary");
 }
 
 /*
@@ -1088,7 +1095,7 @@
 static int pdc202xx_tristate (ide_drive_t * drive, int state)
 {
 #if 0
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned long high_16	= pci_resource_start(hwif->pci_dev, 4);
 	byte sc1f		= inb(high_16 + 0x001f);
 
@@ -1121,6 +1128,7 @@
 
 	switch (dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268R:
 		case PCI_DEVICE_ID_PROMISE_20268:
@@ -1208,13 +1216,14 @@
 	return dev->irq;
 }
 
-unsigned int __init ata66_pdc202xx (ide_hwif_t *hwif)
+unsigned int __init ata66_pdc202xx(struct ata_channel *hwif)
 {
-	unsigned short mask = (hwif->channel) ? (1<<11) : (1<<10);
+	unsigned short mask = (hwif->unit) ? (1<<11) : (1<<10);
 	unsigned short CIS;
 
         switch(hwif->pci_dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
 		case PCI_DEVICE_ID_PROMISE_20268R:
@@ -1226,13 +1235,14 @@
 	}
 }
 
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
+void __init ide_init_pdc202xx(struct ata_channel *hwif)
 {
 	hwif->tuneproc  = &pdc202xx_tune_drive;
 	hwif->quirkproc = &pdc202xx_quirkproc;
 
         switch(hwif->pci_dev->device) {
 		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
 		case PCI_DEVICE_ID_PROMISE_20269:
 		case PCI_DEVICE_ID_PROMISE_20268:
 		case PCI_DEVICE_ID_PROMISE_20268R:
diff -Nru a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c
--- a/drivers/ide/pdc4030.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/pdc4030.c	Wed Apr  3 17:11:14 2002
@@ -99,7 +99,7 @@
 {
 	unsigned int number;
 
-	number = (HWIF(drive)->channel << 1) + drive->select.b.unit;
+	number = (drive->channel->unit << 1) + drive->select.b.unit;
 	OUT_BYTE(number,IDE_FEATURE_REG);
 }
 
@@ -155,10 +155,10 @@
  * setup_pdc4030()
  * Completes the setup of a Promise DC4030 controller card, once found.
  */
-int __init setup_pdc4030 (ide_hwif_t *hwif)
+int __init setup_pdc4030(struct ata_channel *hwif)
 {
         ide_drive_t *drive;
-	ide_hwif_t *hwif2;
+	struct ata_channel *hwif2;
 	struct dc_ident ident;
 	int i;
 	ide_startstop_t startstop;
@@ -226,13 +226,13 @@
 	hwif->chipset	= hwif2->chipset = ide_pdc4030;
 	hwif->mate	= hwif2;
 	hwif2->mate	= hwif;
-	hwif2->channel	= 1;
+	hwif2->unit	= 1;
 	hwif->selectproc = hwif2->selectproc = &promise_selectproc;
 	hwif->serialized = hwif2->serialized = 1;
 
 /* Shift the remaining interfaces down by one */
 	for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
-		ide_hwif_t *h = &ide_hwifs[i];
+		struct ata_channel *h = &ide_hwifs[i];
 
 #ifdef DEBUG
 		printk(KERN_DEBUG "Shifting i/f %d values to i/f %d\n",i-1,i);
@@ -263,7 +263,7 @@
  * Tests for the presence of a DC4030 Promise card on this interface
  * Returns: 1 if found, 0 if not found
  */
-int __init detect_pdc4030(ide_hwif_t *hwif)
+int __init detect_pdc4030(struct ata_channel *hwif)
 {
 	ide_drive_t *drive = &hwif->drives[0];
 
@@ -288,7 +288,7 @@
 void __init ide_probe_for_pdc4030(void)
 {
 	unsigned int	index;
-	ide_hwif_t	*hwif;
+	struct ata_channel *hwif;
 
 	if (enable_promise_support == 0)
 		return;
@@ -394,6 +394,7 @@
 
 	if (GET_STAT() & BUSY_STAT) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
@@ -476,6 +477,7 @@
 
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
 			return ide_started; /* continue polling... */
 		}
@@ -489,6 +491,7 @@
 	 */
 	promise_multwrite(drive, 4);
 	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	BUG_ON(HWGROUP(drive)->handler);
 	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
@@ -523,6 +526,7 @@
 		if (promise_multwrite(drive, rq->nr_sectors - 4))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);
 		return ide_started;
 	} else {
@@ -533,6 +537,7 @@
 		if (promise_multwrite(drive, rq->nr_sectors))
 			return ide_stopped;
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		BUG_ON(HWGROUP(drive)->handler);
 		ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
@@ -549,14 +554,21 @@
  */
 ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task)
 {
-	struct request *rq	= HWGROUP(drive)->rq;
-	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;
+	struct request *rq = HWGROUP(drive)->rq;
+	struct hd_drive_task_hdr *taskfile = &task->taskfile;
 	unsigned long timeout;
 	byte stat;
 
+	/* Check that it's a regular command. If not, bomb out early. */
+	if (!(rq->flags & REQ_CMD)) {
+		blk_dump_rq_flags(rq, "pdc4030 bad flags");
+		ide_end_request(drive, 0);
+		return ide_stopped;
+	}
+
 	if (IDE_CONTROL_REG)
 		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
+	SELECT_MASK(drive->channel, drive, 0);
 
 	OUT_BYTE(taskfile->feature, IDE_FEATURE_REG);
 	OUT_BYTE(taskfile->sector_count, IDE_NSECTOR_REG);
@@ -568,20 +580,12 @@
 	OUT_BYTE(taskfile->device_head, IDE_SELECT_REG);
 	OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
 
-/* Check that it's a regular command. If not, bomb out early. */
-	if (!(rq->flags & REQ_CMD)) {
-		blk_dump_rq_flags(rq, "pdc4030 bad flags");
-		ide_end_request(drive, 0);
-		return ide_stopped;
-	}
-
 	switch (rq_data_dir(rq)) {
 	case READ:
-		OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
 /*
  * The card's behaviour is odd at this point. If the data is
  * available, DRQ will be true, and no interrupt will be
- * generated by the card. If this is the case, we need to call the 
+ * generated by the card. If this is the case, we need to call the
  * "interrupt" handler (promise_read_intr) directly. Otherwise, if
  * an interrupt is going to occur, bit0 of the SELECT register will
  * be high, so we can set the handler the just return and be interrupted.
@@ -600,6 +604,7 @@
 				printk(KERN_DEBUG "%s: read: waiting for "
 				                  "interrupt\n", drive->name);
 #endif
+				BUG_ON(HWGROUP(drive)->handler);
 				ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
@@ -612,7 +617,6 @@
 
 	case WRITE: {
 		ide_startstop_t startstop;
-		OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
 /*
  * Strategy on write is:
  *	look for the DRQ that should have been immediately asserted
@@ -624,7 +628,7 @@
 			printk(KERN_ERR "%s: no DRQ after issuing "
 			       "PROMISE_WRITE\n", drive->name);
 			return startstop;
-	    	}
+		}
 		if (!drive->unmask)
 			__cli();	/* local CPU only */
 		HWGROUP(drive)->wrq = *rq; /* scratchpad */
@@ -652,15 +656,13 @@
 	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;
 	taskfile.command	= (rq_data_dir(rq)==READ)?PROMISE_READ:PROMISE_WRITE;
 
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, NULL, sizeof(struct hd_drive_hob_hdr));
+	args.taskfile = taskfile;
+	memset(&args.hobfile, 0, sizeof(struct hd_drive_hob_hdr));
+
 	ide_cmd_type_parser(&args);
 	/* We don't use the generic inerrupt handlers here? */
 	args.prehandler		= NULL;
 	args.handler		= NULL;
-	args.rq			= rq;
-	args.block		= block;
-	rq->special		= NULL;
 	rq->special		= &args;
 
 	return do_pdc4030_io(drive, &args);
diff -Nru a/drivers/ide/pdcadma.c b/drivers/ide/pdcadma.c
--- a/drivers/ide/pdcadma.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/pdcadma.c	Wed Apr  3 17:11:14 2002
@@ -82,12 +82,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_pdcadma (ide_hwif_t *hwif)
+unsigned int __init ata66_pdcadma(struct ata_channel *channel)
 {
 	return 1;
 }
 
-void __init ide_init_pdcadma (ide_hwif_t *hwif)
+void __init ide_init_pdcadma(struct ata_channel *hwif)
 {
 	hwif->autodma = 0;
 	hwif->dma_base = 0;
@@ -101,7 +101,7 @@
 //	}
 }
 
-void __init ide_dmacapable_pdcadma (ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_pdcadma(struct ata_channel *hwif, unsigned long dmabase)
 {
 //	ide_setup_dma(hwif, dmabase, 8);
 }
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/piix.c	Wed Apr  3 17:11:15 2002
@@ -316,7 +316,7 @@
 
 static int piix_set_drive(ide_drive_t *drive, unsigned char speed)
 {
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
 	struct ata_timing t, p;
 	int err, T, UT, umul;
 
@@ -341,7 +341,7 @@
 				ata_timing_merge(&p, &t, &t, IDE_TIMING_ALL);
 	}
 
-	piix_set_speed(HWIF(drive)->pci_dev, drive->dn, &t, umul);
+	piix_set_speed(drive->channel->pci_dev, drive->dn, &t, umul);
 
 	if (!drive->init_speed)	
 		drive->init_speed = speed;
@@ -357,7 +357,7 @@
 
 static void piix_tune_drive(ide_drive_t *drive, unsigned char pio)
 {
-	if (!((piix_enabled >> HWIF(drive)->channel) & 1))
+	if (!((piix_enabled >> drive->channel->unit) & 1))
 		return;
 
 	if (pio == 255) {
@@ -381,7 +381,7 @@
 
 	if (func == ide_dma_check) {
 
-		short w80 = HWIF(drive)->udma_four;
+		short w80 = drive->channel->udma_four;
 
 		short speed = ata_timing_mode(drive,
 			XFER_PIO | XFER_EPIO | 
@@ -392,7 +392,7 @@
 
 		piix_set_drive(drive, speed);
 
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+		func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
 			? ide_dma_on : ide_dma_off_quietly;
 
 	}
@@ -533,12 +533,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_piix(ide_hwif_t *hwif)
+unsigned int __init ata66_piix(struct ata_channel *hwif)
 {
-	return ((piix_enabled & piix_80w) >> hwif->channel) & 1;
+	return ((piix_enabled & piix_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_piix(ide_hwif_t *hwif)
+void __init ide_init_piix(struct ata_channel *hwif)
 {
 	int i;
 
@@ -550,7 +550,7 @@
 		hwif->drives[i].io_32bit = 1;
 		hwif->drives[i].unmask = 1;
 		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
+		hwif->drives[i].dn = hwif->unit * 2 + i;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -570,9 +570,9 @@
  * and only if DMA is safe with the chip and bridge.
  */
 
-void __init ide_dmacapable_piix(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_piix(struct ata_channel *hwif, unsigned long dmabase)
 {
-	if (((piix_enabled >> hwif->channel) & 1)
+	if (((piix_enabled >> hwif->unit) & 1)
 		&& !(piix_config->flags & PIIX_NODMA))
 			ide_setup_dma(hwif, dmabase, 8);
 }
diff -Nru a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c
--- a/drivers/ide/qd65xx.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/qd65xx.c	Wed Apr  3 17:11:14 2002
@@ -125,11 +125,11 @@
  * qd6500_compute_timing
  *
  * computes the timing value where
- * 	lower nibble represents active time,   in count of VLB clocks
- * 	upper nibble represents recovery time, in count of VLB clocks
+ *	lower nibble represents active time,   in count of VLB clocks
+ *	upper nibble represents recovery time, in count of VLB clocks
  */
 
-static byte qd6500_compute_timing (ide_hwif_t *hwif, int active_time, int recovery_time)
+static byte qd6500_compute_timing(struct ata_channel *hwif, int active_time, int recovery_time)
 {
 	byte active_cycle,recovery_cycle;
 
@@ -208,7 +208,7 @@
 
 static void qd_set_timing (ide_drive_t *drive, byte timing)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 
 	drive->drive_data &= 0xff00;
 	drive->drive_data |= timing;
@@ -240,7 +240,7 @@
 		recovery_time = drive->id->eide_pio - 120;
 	}
 
-	qd_set_timing(drive,qd6500_compute_timing(HWIF(drive),active_time,recovery_time));
+	qd_set_timing(drive,qd6500_compute_timing(drive->channel, active_time,recovery_time));
 }
 
 /*
@@ -250,7 +250,7 @@
 static void qd6580_tune_drive (ide_drive_t *drive, byte pio)
 {
 	struct ata_timing *t;
-	int base = HWIF(drive)->select_data;
+	int base = drive->channel->select_data;
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
@@ -291,9 +291,9 @@
 		printk(KERN_INFO "%s: PIO mode%d\n", drive->name, pio - XFER_PIO_0);
 	}
 
-	if (!HWIF(drive)->channel && drive->type != ATA_DISK) {
+	if (!drive->channel->unit && drive->type != ATA_DISK) {
 		qd_write_reg(0x5f,QD_CONTROL_PORT);
-		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name,HWIF(drive)->name);
+		printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n",drive->name, drive->channel->name);
 	}
 
 	qd_set_timing(drive,qd6580_compute_timing(active_time,recovery_time));
@@ -348,7 +348,7 @@
 	index = ! (config & QD_CONFIG_IDE_BASEPORT);
 
 	if ((config & 0xf0) == QD_CONFIG_QD6500) {
-		ide_hwif_t *hwif = &ide_hwifs[index];
+		struct ata_channel *hwif = &ide_hwifs[index];
 
 		if (qd_testreg(base)) return 1;		/* bad register */
 
@@ -392,7 +392,7 @@
 			config, control, QD_ID3);
 
 		if (control & QD_CONTR_SEC_DISABLED) {
-			ide_hwif_t *hwif = &ide_hwifs[index];
+			struct ata_channel *hwif = &ide_hwifs[index];
 
 			/* secondary disabled */
 			printk(KERN_INFO "%s: qd6580: single IDE board\n",
@@ -420,7 +420,7 @@
 
 				ide_hwifs[i].chipset = ide_qd65xx;
 				ide_hwifs[i].mate = &ide_hwifs[i^1];
-				ide_hwifs[i].channel = i;
+				ide_hwifs[i].unit = i;
 
 				ide_hwifs[i].select_data = base;
 				ide_hwifs[i].config_data = config | (control <<8);
diff -Nru a/drivers/ide/rz1000.c b/drivers/ide/rz1000.c
--- a/drivers/ide/rz1000.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/rz1000.c	Wed Apr  3 17:11:14 2002
@@ -28,7 +28,7 @@
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 
-void __init ide_init_rz1000 (ide_hwif_t *hwif)	/* called from ide-pci.c */
+void __init ide_init_rz1000(struct ata_channel *hwif)	/* called from ide-pci.c */
 {
 	unsigned short reg;
 	struct pci_dev *dev = hwif->pci_dev;
@@ -62,7 +62,7 @@
 		printk("IDE: disabled chipset read-ahead (buggy %s)\n", name);
 	} else {
 		for (h = 0; h < MAX_HWIFS; ++h) {
-			ide_hwif_t *hwif = &ide_hwifs[h];
+			struct ata_channel *hwif = &ide_hwifs[h];
 			if ((hwif->io_ports[IDE_DATA_OFFSET] == 0x1f0 || hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
 			 && (hwif->chipset == ide_unknown || hwif->chipset == ide_generic))
 			{
@@ -71,7 +71,7 @@
 				hwif->drives[0].no_unmask = 1;
 				hwif->drives[1].no_unmask = 1;
 				if (hwif->io_ports[IDE_DATA_OFFSET] == 0x170)
-					hwif->channel = 1;
+					hwif->unit = 1;
 				printk("%s: serialized, disabled unmasking (buggy %s)\n", hwif->name, name);
 			}
 		}
diff -Nru a/drivers/ide/serverworks.c b/drivers/ide/serverworks.c
--- a/drivers/ide/serverworks.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/ide/serverworks.c	Wed Apr  3 17:11:13 2002
@@ -243,7 +243,7 @@
 	byte dma_modes[]	= { 0x77, 0x21, 0x20 };
 	byte pio_modes[]	= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
 
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 	byte unit		= (drive->select.b.unit & 0x01);
 	byte csb5		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
@@ -255,7 +255,7 @@
 
 	byte drive_pci		= 0x00;
 	byte drive_pci2		= 0x00;
-	byte drive_pci3		= hwif->channel ? 0x57 : 0x56;
+	byte drive_pci3		= hwif->unit ? 0x57 : 0x56;
 
 	byte ultra_enable	= 0x00;
 	byte ultra_timing	= 0x00;
@@ -413,7 +413,7 @@
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
 	struct hd_driveid *id	= drive->id;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
+	struct pci_dev *dev	= drive->channel->pci_dev;
 	byte udma_66	= eighty_ninty_three(drive);
 	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
 	int ultra100	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
@@ -436,7 +436,7 @@
 	struct hd_driveid *id = drive->id;
 	ide_dma_action_t dma_func = ide_dma_on;
 
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -477,7 +477,7 @@
 no_dma_set:
 		config_chipset_for_pio(drive);
 	}
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 static int svwks_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
@@ -487,7 +487,7 @@
 			return config_drive_xfer_rate(drive);
 		case ide_dma_end:
 		{
-			ide_hwif_t *hwif		= HWIF(drive);
+			struct ata_channel *hwif = drive->channel;
 			unsigned long dma_base		= hwif->dma_base;
 	
 			if(inb(dma_base+0x02)&1)
@@ -584,13 +584,13 @@
  * Bit 14 clear = primary IDE channel does not have 80-pin cable.
  * Bit 14 set   = primary IDE channel has 80-pin cable.
  */
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_dell(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
 	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
 	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
+		return ((1 << (hwif->unit + 14)) &
 			dev->subsystem_device) ? 1 : 0;
 	return 0;
 }
@@ -601,18 +601,18 @@
  *
  * WARNING: this only works on Alpine hardware!
  */
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __init ata66_svwks_cobalt(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 	if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
 	    dev->vendor	== PCI_VENDOR_ID_SERVERWORKS &&
 	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
-		return ((1 << (hwif->channel + 14)) &
+		return ((1 << (hwif->unit + 14)) &
 			dev->subsystem_device) ? 1 : 0;
 	return 0;
 }
 
-unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+unsigned int __init ata66_svwks(struct ata_channel *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
 
@@ -627,10 +627,10 @@
 	return 0;
 }
 
-void __init ide_init_svwks (ide_hwif_t *hwif)
+void __init ide_init_svwks(struct ata_channel *hwif)
 {
 	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
+		hwif->irq = hwif->unit ? 15 : 14;
 
 	hwif->tuneproc = &svwks_tune_drive;
 	hwif->speedproc = &svwks_tune_chipset;
diff -Nru a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
--- a/drivers/ide/sis5513.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ide/sis5513.c	Wed Apr  3 17:11:15 2002
@@ -434,7 +434,7 @@
 /* Enables per-drive prefetch and postwrite */
 static void config_drive_art_rwp (ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 
 	byte reg4bh		= 0;
@@ -460,7 +460,7 @@
 /* Set per-drive active and recovery time */
 static void config_art_rwp_pio (ide_drive_t *drive, byte pio)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 
 	byte			timing, drive_pci, test1, test2;
@@ -560,7 +560,7 @@
 
 static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev	= hwif->pci_dev;
 
 	byte			drive_pci, reg;
@@ -640,12 +640,12 @@
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 /*
- * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four))
+ * ((id->hw_config & 0x4000|0x2000) && (drive->channel->udma_four))
  */
 static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 {
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
+	struct hd_driveid *id = drive->id;
+	struct ata_channel *hwif = drive->channel;
 
 	byte			speed = 0;
 
@@ -700,7 +700,7 @@
 	struct hd_driveid *id		= drive->id;
 	ide_dma_action_t dma_func	= ide_dma_off_quietly;
 
-	if (id && (id->capability & 1) && HWIF(drive)->autodma) {
+	if (id && (id->capability & 1) && drive->channel->autodma) {
 		/* Consult the list of known "bad" drives */
 		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
 			dma_func = ide_dma_off;
@@ -740,7 +740,7 @@
 		(void) config_chipset_for_pio(drive, 5);
 	}
 
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 /* initiates/aborts (U)DMA read/write operations on a drive. */
@@ -841,10 +841,10 @@
 	return 0;
 }
 
-unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
+unsigned int __init ata66_sis5513(struct ata_channel *hwif)
 {
 	byte reg48h = 0, ata66 = 0;
-	byte mask = hwif->channel ? 0x20 : 0x10;
+	byte mask = hwif->unit ? 0x20 : 0x10;
 	pci_read_config_byte(hwif->pci_dev, 0x48, &reg48h);
 
 	if (dma_capability >= ATA_66) {
@@ -853,10 +853,10 @@
         return ata66;
 }
 
-void __init ide_init_sis5513 (ide_hwif_t *hwif)
+void __init ide_init_sis5513(struct ata_channel *hwif)
 {
 
-	hwif->irq = hwif->channel ? 15 : 14;
+	hwif->irq = hwif->unit ? 15 : 14;
 
 	hwif->tuneproc = &sis5513_tune_drive;
 	hwif->speedproc = &sis5513_tune_chipset;
diff -Nru a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c
--- a/drivers/ide/sl82c105.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/sl82c105.c	Wed Apr  3 17:11:14 2002
@@ -57,13 +57,13 @@
  */
 static void config_for_pio(ide_drive_t *drive, int pio, int report)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev = hwif->pci_dev;
 	struct ata_timing *t;
 	unsigned short drv_ctrl = 0x909;
 	unsigned int xfer_mode, reg;
 
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+	reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
 
 	if (pio == 255)
 		xfer_mode = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
@@ -95,12 +95,12 @@
  */
 static int config_for_dma(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	struct pci_dev *dev = hwif->pci_dev;
 	unsigned short drv_ctrl = 0x909;
 	unsigned int reg;
 
-	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+	reg = (hwif->unit ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
 
 	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
 		drv_ctrl = 0x0240;
@@ -120,7 +120,7 @@
 
 	do {
 		struct hd_driveid *id = drive->id;
-		ide_hwif_t *hwif = HWIF(drive);
+		struct ata_channel *hwif = drive->channel;
 
 		if (!hwif->autodma)
 			break;
@@ -146,7 +146,7 @@
 		}
 	} while (0);
 
-	return HWIF(drive)->dmaproc(dma_func, drive);
+	return drive->channel->dmaproc(dma_func, drive);
 }
 
 /*
@@ -232,7 +232,7 @@
 	return dev->irq;
 }
 
-void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+void __init dma_init_sl82c105(struct ata_channel *hwif, unsigned long dma_base)
 {
 	unsigned int rev;
 	byte dma_state;
@@ -261,7 +261,7 @@
 /*
  * Initialise the chip
  */
-void __init ide_init_sl82c105(ide_hwif_t *hwif)
+void __init ide_init_sl82c105(struct ata_channel *hwif)
 {
 	hwif->tuneproc = tune_sl82c105;
 }
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/trm290.c	Wed Apr  3 17:11:14 2002
@@ -141,7 +141,7 @@
 
 static void trm290_prepare_drive (ide_drive_t *drive, unsigned int use_dma)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned int reg;
 	unsigned long flags;
 
@@ -153,14 +153,14 @@
 
 	if (reg != hwif->select_data) {
 		hwif->select_data = reg;
-		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
+		outb(0x51|(hwif->unit<<3), hwif->config_data+1);	/* set PIO/DMA */
 		outw(reg & 0xff, hwif->config_data);
 	}
 
 	/* enable IRQ if not probing */
 	if (drive->present) {
 		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
+		reg &= ~(1 << hwif->unit);
 		outw(reg, hwif->config_data+3);
 	}
 
@@ -175,7 +175,7 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static int trm290_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
-	ide_hwif_t *hwif = HWIF(drive);
+	struct ata_channel *hwif = drive->channel;
 	unsigned int count, reading = 2, writing = 0;
 
 	switch (func) {
@@ -194,6 +194,7 @@
 			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
 			if (drive->type != ATA_DISK)
 				return 0;
+			BUG_ON(HWGROUP(drive)->handler);
 			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
 			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
 			return 0;
@@ -216,7 +217,7 @@
 /*
  * Invoked from ide-dma.c at boot time.
  */
-void __init ide_init_trm290 (ide_hwif_t *hwif)
+void __init ide_init_trm290(struct ata_channel *hwif)
 {
 	unsigned int cfgbase = 0;
 	unsigned long flags;
@@ -237,7 +238,7 @@
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
 	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
+	outb(0x51|(hwif->unit<<3), hwif->config_data+1);
 	hwif->select_data = 0x21;			/* select PIO as default */
 	outb(hwif->select_data, hwif->config_data);
 	reg = inb(hwif->config_data+3);			/* get IRQ info */
@@ -246,10 +247,10 @@
 	__restore_flags(flags);	/* local CPU only */
 
 	if ((reg & 0x10))
-		hwif->irq = hwif->channel ? 15 : 14;	/* legacy mode */
+		hwif->irq = hwif->unit ? 15 : 14;	/* legacy mode */
 	else if (!hwif->irq && hwif->mate && hwif->mate->irq)
 		hwif->irq = hwif->mate->irq;		/* sharing IRQ with mate */
-	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3);
+	ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->unit ? 0x0080 : 0x0000), 3);
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	hwif->dmaproc = &trm290_dmaproc;
@@ -264,10 +265,10 @@
 		 * for the control basereg, so this kludge ensures that we use only
 		 * values that are known to work.  Ugh.		-ml
 		 */
-		unsigned short old, compat = hwif->channel ? 0x374 : 0x3f4;
+		unsigned short old, compat = hwif->unit ? 0x374 : 0x3f4;
 		static unsigned short next_offset = 0;
 
-		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
+		outb(0x54|(hwif->unit<<3), hwif->config_data+1);
 		old = inw(hwif->config_data) & ~1;
 		if (old != compat && inb(old+2) == 0xff) {
 			compat += (next_offset += 0x400);	/* leave lower 10 bits untouched */
diff -Nru a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c
--- a/drivers/ide/umc8672.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/umc8672.c	Wed Apr  3 17:11:14 2002
@@ -111,7 +111,7 @@
 static void tune_umc (ide_drive_t *drive, byte pio)
 {
 	unsigned long flags;
-	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
+	ide_hwgroup_t *hwgroup = ide_hwifs[drive->channel->index ^ 1].hwgroup;
 
 	if (pio == 255)
 		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
@@ -160,5 +160,5 @@
 	ide_hwifs[1].tuneproc = &tune_umc;
 	ide_hwifs[0].mate = &ide_hwifs[1];
 	ide_hwifs[1].mate = &ide_hwifs[0];
-	ide_hwifs[1].channel = 1;
+	ide_hwifs[1].unit = 1;
 }
diff -Nru a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c
--- a/drivers/ide/via82cxxx.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ide/via82cxxx.c	Wed Apr  3 17:11:14 2002
@@ -302,7 +302,7 @@
 
 static int via_set_drive(ide_drive_t *drive, unsigned char speed)
 {
-	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
+	ide_drive_t *peer = drive->channel->drives + (~drive->dn & 1);
 	struct ata_timing t, p;
 	unsigned int T, UT;
 
@@ -328,7 +328,7 @@
 		ata_timing_merge(&p, &t, &t, IDE_TIMING_8BIT);
 	}
 
-	via_set_speed(HWIF(drive)->pci_dev, drive->dn, &t);
+	via_set_speed(drive->channel->pci_dev, drive->dn, &t);
 
 	if (!drive->init_speed)
 		drive->init_speed = speed;
@@ -344,7 +344,7 @@
 
 static void via82cxxx_tune_drive(ide_drive_t *drive, unsigned char pio)
 {
-	if (!((via_enabled >> HWIF(drive)->channel) & 1))
+	if (!((via_enabled >> drive->channel->unit) & 1))
 		return;
 
 	if (pio == 255) {
@@ -368,7 +368,7 @@
 
 	if (func == ide_dma_check) {
 
-		short w80 = HWIF(drive)->udma_four;
+		short w80 = drive->channel->udma_four;
 
 		short speed = ata_timing_mode(drive,
 			XFER_PIO | XFER_EPIO | XFER_SWDMA | XFER_MWDMA |
@@ -379,7 +379,7 @@
 
 		via_set_drive(drive, speed);
 
-		func = (HWIF(drive)->autodma && (speed & XFER_MODE) != XFER_PIO)
+		func = (drive->channel->autodma && (speed & XFER_MODE) != XFER_PIO)
 			? ide_dma_on : ide_dma_off_quietly;
 	}
 
@@ -523,12 +523,12 @@
 	return 0;
 }
 
-unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif)
+unsigned int __init ata66_via82cxxx(struct ata_channel *hwif)
 {
-	return ((via_enabled & via_80w) >> hwif->channel) & 1;
+	return ((via_enabled & via_80w) >> hwif->unit) & 1;
 }
 
-void __init ide_init_via82cxxx(ide_hwif_t *hwif)
+void __init ide_init_via82cxxx(struct ata_channel *hwif)
 {
 	int i;
 
@@ -540,7 +540,7 @@
 		hwif->drives[i].io_32bit = 1;
 		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
 		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->channel * 2 + i;
+		hwif->drives[i].dn = hwif->unit * 2 + i;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
@@ -559,8 +559,8 @@
  * We allow the BM-DMA driver to only work on enabled interfaces.
  */
 
-void __init ide_dmacapable_via82cxxx(ide_hwif_t *hwif, unsigned long dmabase)
+void __init ide_dmacapable_via82cxxx(struct ata_channel *hwif, unsigned long dmabase)
 {
-	if ((via_enabled >> hwif->channel) & 1)
+	if ((via_enabled >> hwif->unit) & 1)
 		ide_setup_dma(hwif, dmabase, 8);
 }
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ieee1394/dv1394.c	Wed Apr  3 17:11:14 2002
@@ -100,7 +100,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
--- a/drivers/ieee1394/pcilynx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/ieee1394/pcilynx.c	Wed Apr  3 17:11:15 2002
@@ -56,7 +56,6 @@
 #define PRINTD(level, card, fmt, args...) do {} while (0)
 #endif
 
-
 static struct hpsb_host_driver *lynx_driver;
 static unsigned int card_id;
 
@@ -636,7 +635,7 @@
 
 static int mem_open(struct inode *inode, struct file *file)
 {
-        int cid = MINOR(inode->i_rdev);
+        int cid = minor(inode->i_rdev);
         enum { t_rom, t_aux, t_ram } type;
         struct memdata *md;
         
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/ieee1394/video1394.c	Wed Apr  3 17:11:14 2002
@@ -43,7 +43,6 @@
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <linux/sched.h>
-#include <asm/segment.h>
 #include <linux/types.h>
 #include <linux/wrapper.h>
 #include <linux/vmalloc.h>
diff -Nru a/drivers/isdn/avmb1/capifs.c b/drivers/isdn/avmb1/capifs.c
--- a/drivers/isdn/avmb1/capifs.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/isdn/avmb1/capifs.c	Wed Apr  3 17:11:14 2002
@@ -235,10 +235,9 @@
 	unsigned int maxncci = 512;
 	char *this_char, *value;
 
-	this_char = NULL;
-	if ( options )
-		this_char = strtok(options,",");
-	for ( ; this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(this_char,"uid")) {
diff -Nru a/drivers/isdn/avmb1/kcapi.c b/drivers/isdn/avmb1/kcapi.c
--- a/drivers/isdn/avmb1/kcapi.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/isdn/avmb1/kcapi.c	Wed Apr  3 17:11:16 2002
@@ -102,8 +102,8 @@
 #define APPL(a)		   (&applications[(a)-1])
 #define	VALID_APPLID(a)	   ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
 #define APPL_IS_FREE(a)    (APPL(a)->applid == 0)
-#define APPL_MARK_FREE(a)  do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
-#define APPL_MARK_USED(a)  do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+#define APPL_MARK_FREE(a)  do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0)
+#define APPL_MARK_USED(a)  do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0)
 
 #define NCCI2CTRL(ncci)    (((ncci) >> 24) & 0x7f)
 
diff -Nru a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
--- a/drivers/isdn/eicon/eicon_mod.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/isdn/eicon/eicon_mod.c	Wed Apr  3 17:11:14 2002
@@ -665,8 +665,11 @@
 			else
 				cnt = skb->len;
 
-			if (user)
+			if (user) {
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				copy_to_user(p, skb->data, cnt);
+				spin_lock_irqsave(&eicon_lock, flags);
+			}
 			else
 				memcpy(p, skb->data, cnt);
 
diff -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c	Wed Apr  3 17:11:14 2002
@@ -65,6 +65,7 @@
 
 static int protocol = 2;       /* EURO-ISDN Default */
 MODULE_PARM(protocol, "i");
+MODULE_LICENSE("GPL");
 
 // ----------------------------------------------------------------------
 
diff -Nru a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c
--- a/drivers/isdn/hisax/hisax_isac.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/isdn/hisax/hisax_isac.c	Wed Apr  3 17:11:14 2002
@@ -44,6 +44,7 @@
 
 MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
 MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+MODULE_LICENSE("GPL");
 
 #define DBG_WARN      0x0001
 #define DBG_IRQ       0x0002
diff -Nru a/drivers/md/lvm-snap.c b/drivers/md/lvm-snap.c
--- a/drivers/md/lvm-snap.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/md/lvm-snap.c	Wed Apr  3 17:11:16 2002
@@ -302,6 +302,7 @@
 {
 	const char * reason;
 	kdev_t snap_phys_dev;
+	struct block_device *org_bdev, *snap_bdev;
 	unsigned long org_start, snap_start, virt_start, pe_off;
 	int idx = lv_snap->u.lv_remap_ptr, chunk_size = lv_snap->u.lv_chunk_size;
 	struct kiobuf * iobuf;
@@ -321,6 +322,15 @@
 	snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
 	snap_start = lv_snap->u.lv_block_exception[idx].rsector_new;
 
+	org_bdev = bdget(kdev_t_to_nr(org_phys_dev));
+	if (!org_bdev)
+		goto fail_enomem;
+	snap_bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+	if (!snap_bdev) {
+		bdput(org_bdev);
+		goto fail_enomem;
+	}
+
 #ifdef DEBUG_SNAPSHOT
 	printk(KERN_INFO
 	       "%s -- COW: "
@@ -356,7 +366,7 @@
 						nr_sectors, blksize_org))
 			goto fail_prepare;
 
-		if (brw_kiovec(READ, 1, &iobuf, org_phys_dev,
+		if (brw_kiovec(READ, 1, &iobuf, org_bdev,
 			       lv_snap->blocks, blksize_org) != (nr_sectors<<9))
 			goto fail_raw_read;
 
@@ -364,7 +374,7 @@
 						nr_sectors, blksize_snap))
 			goto fail_prepare;
 
-		if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev,
+		if (brw_kiovec(WRITE, 1, &iobuf, snap_bdev,
 			       lv_snap->blocks, blksize_snap) !=(nr_sectors<<9))
 			goto fail_raw_write;
 	}
@@ -387,16 +397,21 @@
 		if (lv_snap->u.lv_remap_ptr * 100 / lv_snap->u.lv_remap_end >= lv_snap->lv_snapshot_use_rate)
 			wake_up_interruptible(&lv_snap->lv_snapshot_wait);
 	}
+	bdput(snap_bdev);
+	bdput(org_bdev);
 	return 0;
 
 	/* slow path */
  out:
+	bdput(snap_bdev);
+	bdput(org_bdev);
+ out1:
 	lvm_drop_snapshot(vg, lv_snap, reason);
 	return 1;
 
  fail_out_of_space:
 	reason = "out of space";
-	goto out;
+	goto out1;
  fail_raw_read:
 	reason = "read error";
 	goto out;
@@ -405,7 +420,9 @@
 	goto out;
  fail_blksize:
 	reason = "blocksize error";
-	goto out;
+ fail_enomem:
+	reason = "out of memory";
+	goto out1;
 
  fail_prepare:
 	reason = "couldn't prepare kiovec blocks "
@@ -569,6 +586,7 @@
 		COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block;
 	ulong blocks[1];
 	kdev_t snap_phys_dev;
+	struct block_device *bdev;
 	lv_block_exception_t *be;
 	struct kiobuf * COW_table_iobuf = lv_snap->lv_COW_table_iobuf;
 	lv_COW_table_disk_t * lv_COW_table =
@@ -581,6 +599,8 @@
 	snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
 	snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
 
+	bdev = bdget(kdev_t_to_nr(snap_phys_dev));
+
 	blksize_snap = block_size(snap_phys_dev);
 
         COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t);
@@ -611,7 +631,7 @@
 
 	COW_table_iobuf->length = blksize_snap;
 
-	if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+	if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
 		       blocks, blksize_snap) != blksize_snap)
 		goto fail_raw_write;
 
@@ -629,25 +649,30 @@
 			idx++;
 			snap_phys_dev = lv_snap->u.lv_block_exception[idx].rdev_new;
 			snap_pe_start = lv_snap->u.lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->u.lv_chunk_size;
+			bdput(bdev);
+			bdev = bdget(kdev_t_to_nr(snap_phys_dev));
 			blksize_snap = block_size(snap_phys_dev);
 			blocks[0] = snap_pe_start >> (blksize_snap >> 10);
 		} else blocks[0]++;
 
-               if (brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev,
+               if (brw_kiovec(WRITE, 1, &COW_table_iobuf, bdev,
                                  blocks, blksize_snap) !=
                     blksize_snap)
 			goto fail_raw_write;
 	}
 
  out:
+	bdput(bdev);
 	return 0;
 
  fail_raw_write:
 	*reason = "write error";
+	bdput(bdev);
 	return 1;
 
  fail_pv_get_number:
 	*reason = "_pv_get_number failed";
+	bdput(bdev);
 	return 1;
 }
 
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/md/md.c	Wed Apr  3 17:11:14 2002
@@ -3768,7 +3768,7 @@
 		printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
 		return 0;
 	} else if (md_setup_args.device_names[minor]) {
-		printk(KERN_WARNING "md: md=%d, Specified more then once. "
+		printk(KERN_WARNING "md: md=%d, Specified more than once. "
 		       "Replacing previous definition.\n", minor);
 	}
 	switch (get_option(&str, &level)) {	/* RAID Personality */
diff -Nru a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
--- a/drivers/media/radio/radio-gemtek-pci.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/media/radio/radio-gemtek-pci.c	Wed Apr  3 17:11:14 2002
@@ -385,7 +385,7 @@
     name:	"gemtek_pci",
 id_table:	gemtek_pci_id,
    probe:	gemtek_pci_probe,
-  remove:	__devexit_p(gemtek_pci_remove)
+  remove:	__devexit_p(gemtek_pci_remove),
 };
 
 static int __init gemtek_pci_init_module( void )
diff -Nru a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
--- a/drivers/media/video/videodev.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/media/video/videodev.c	Wed Apr  3 17:11:14 2002
@@ -107,20 +107,18 @@
 }
 
 /*
- * ioctl helper function -- handles userspace copying
+ * helper function -- handles userspace copying for ioctl arguments
  */
 int
-video_generic_ioctl(struct inode *inode, struct file *file,
-		    unsigned int cmd, unsigned long arg)
+video_usercopy(struct inode *inode, struct file *file,
+	       unsigned int cmd, unsigned long arg,
+	       int (*func)(struct inode *inode, struct file *file,
+			   unsigned int cmd, void *arg))
 {
-	struct  video_device *vfl = video_devdata(file);
 	char	sbuf[128];
 	void    *mbuf = NULL;
 	void	*parg = NULL;
 	int	err  = -EINVAL;
-	
-	if (vfl->kernel_ioctl == NULL)
-		return -EINVAL;
 
 	/*  Copy arguments into temp kernel buffer  */
 	switch (_IOC_DIR(cmd)) {
@@ -147,7 +145,7 @@
 	}
 
 	/* call driver */
-	err = vfl->kernel_ioctl(inode, file, cmd, parg);
+	err = func(inode, file, cmd, parg);
 	if (err == -ENOIOCTLCMD)
 		err = -EINVAL;
 	if (err < 0)
@@ -512,7 +510,7 @@
 EXPORT_SYMBOL(video_register_device);
 EXPORT_SYMBOL(video_unregister_device);
 EXPORT_SYMBOL(video_devdata);
-EXPORT_SYMBOL(video_generic_ioctl);
+EXPORT_SYMBOL(video_usercopy);
 EXPORT_SYMBOL(video_exclusive_open);
 EXPORT_SYMBOL(video_exclusive_release);
 
diff -Nru a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
--- a/drivers/mtd/chips/sharp.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/mtd/chips/sharp.c	Wed Apr  3 17:11:15 2002
@@ -440,7 +440,7 @@
 
 	timeo = jiffies + HZ;
 
-	while(jiffies<timeo){
+	while(time_before(jiffies, timeo)){
 		map->write32(map,CMD_READ_STATUS,adr);
 		status = map->read32(map,adr);
 		if((status & SR_READY)==SR_READY){
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/mtd/devices/blkmtd.c	Wed Apr  3 17:11:13 2002
@@ -264,7 +264,7 @@
 
 
   DEBUG(3, "bklmtd: readpage: starting brw_kiovec\n");
-  err = brw_kiovec(READ, 1, &iobuf, dev, blocks, rawdevice->sector_size);
+  err = brw_kiovec(READ, 1, &iobuf, rawdevice->binding, blocks, rawdevice->sector_size);
   DEBUG(3, "blkmtd: readpage: finished, err = %d\n", err);
   iobuf->locked = 0;
   free_kiovec(1, &iobuf);
@@ -401,7 +401,7 @@
 	iobuf->nr_pages = cpagecnt;
 	iobuf->length = cursectors << item->rawdevice->sector_bits;
 	DEBUG(3, "blkmtd: write_task: about to kiovec\n");
-	err = brw_kiovec(WRITE, 1, &iobuf, dev, blocks, item->rawdevice->sector_size);
+	err = brw_kiovec(WRITE, 1, &iobuf, item->rawdevice->binding, blocks, item->rawdevice->sector_size);
 	DEBUG(3, "bklmtd: write_task: done, err = %d\n", err);
 	if(err != (cursectors << item->rawdevice->sector_bits)) {
 	  /* if an error occured - set this to exit the loop */
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/mtd/ftl.c	Wed Apr  3 17:11:14 2002
@@ -195,7 +195,7 @@
 		     u_int cmd, u_long arg);
 static int ftl_open(struct inode *inode, struct file *file);
 static release_t ftl_close(struct inode *inode, struct file *file);
-static int ftl_reread_partitions(int minor);
+static int ftl_reread_partitions(kdev_t dev);
 
 static void ftl_erase_callback(struct erase_info *done);
 
@@ -842,7 +842,7 @@
 
 static int ftl_open(struct inode *inode, struct file *file)
 {
-    int minor = MINOR(inode->i_rdev);
+    int minor = minor(inode->i_rdev);
     partition_t *partition;
 
     if (minor>>4 >= MAX_MTD_DEVICES)
@@ -878,7 +878,7 @@
 
 static release_t ftl_close(struct inode *inode, struct file *file)
 {
-    int minor = MINOR(inode->i_rdev);
+    int minor = minor(inode->i_rdev);
     partition_t *part = myparts[minor >> 4];
     int i;
     
@@ -1114,7 +1114,7 @@
 		     u_int cmd, u_long arg)
 {
     struct hd_geometry *geo = (struct hd_geometry *)arg;
-    int ret = 0, minor = MINOR(inode->i_rdev);
+    int ret = 0, minor = minor(inode->i_rdev);
     partition_t *part= myparts[minor >> 4];
     u_long sect;
 
@@ -1139,7 +1139,7 @@
 	ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg);
 	break;
     case BLKRRPART:
-	ret = ftl_reread_partitions(minor);
+	ret = ftl_reread_partitions(inode->i_rdev);
 	break;
     case BLKROSET:
     case BLKROGET:
@@ -1161,7 +1161,7 @@
 
 static int ftl_reread_partitions(kdev_t dev)
 {
-    int minor = MINOR(dev);
+    int minor = minor(dev);
     partition_t *part = myparts[minor >> 4];
     int res;
 
@@ -1197,7 +1197,7 @@
       //	    sti();
 	INIT_REQUEST;
 
-	minor = MINOR(CURRENT->rq_dev);
+	minor = minor(CURRENT->rq_dev);
 	
 	part = myparts[minor >> 4];
 	if (part) {
@@ -1369,7 +1369,7 @@
 
     unregister_blkdev(FTL_MAJOR, "ftl");
     blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR));
-    bklk_clear(FTL_MAJOR);
+    blk_clear(FTL_MAJOR);
 
     del_gendisk(&ftl_gendisk);
 }
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/mtd/mtdblock.c	Wed Apr  3 17:11:15 2002
@@ -541,7 +541,7 @@
 			return -EACCES;
 #endif
 		fsync_bdev(inode->i_bdev);
-		invalidate_buffers(inode->i_rdev);
+		invalidate_bdev(inode->b_rdev, 0);
 		down(&mtdblk->cache_sem);
 		write_cached_data(mtdblk);
 		up(&mtdblk->cache_sem);
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/mtd/mtdblock_ro.c	Wed Apr  3 17:11:15 2002
@@ -222,7 +222,7 @@
 		if(!capable(CAP_SYS_ADMIN))  return -EACCES;
 #endif
 		fsync_bdev(inode->i_bdev);
-		invalidate_buffers(inode->i_rdev);
+		invalidate_bdev(inode->i_bdev, 0);
 		if (mtd->sync)
 			mtd->sync(mtd);
 		return 0;
diff -Nru a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
--- a/drivers/mtd/nand/nand_ecc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/mtd/nand/nand_ecc.c	Wed Apr  3 17:11:14 2002
@@ -207,3 +207,5 @@
 
 EXPORT_SYMBOL(nand_calculate_ecc);
 EXPORT_SYMBOL(nand_correct_data);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/mtd/nftlcore.c	Wed Apr  3 17:11:13 2002
@@ -796,7 +796,7 @@
 	case BLKFLSBUF:
 		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 		fsync_bdev(inode->i_bdev);
-		invalidate_buffers(inode->i_rdev);
+		invalidate_bdev(inode->i_bdev, 0);
 		if (nftl->mtd->sync)
 			nftl->mtd->sync(nftl->mtd);
 		return 0;
diff -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c
--- a/drivers/net/3c503.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/3c503.c	Wed Apr  3 17:11:15 2002
@@ -263,13 +263,13 @@
 #endif  /* EL2MEMTEST */
 
 	if (dev->mem_start)
-		dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE;
+		dev->mem_end = ei_status.rmem_end = dev->mem_start + EL2_MEMSIZE;
 
 	if (wordlength) {	/* No Tx pages to skip over to get to Rx */
-		dev->rmem_start = dev->mem_start;
+		ei_status.rmem_start = dev->mem_start;
 		ei_status.name = "3c503/16";
 	} else {
-		dev->rmem_start = TX_PAGES*256 + dev->mem_start;
+		ei_status.rmem_start = TX_PAGES*256 + dev->mem_start;
 		ei_status.name = "3c503";
 	}
     }
@@ -549,7 +549,7 @@
     unsigned short int *buf;
     unsigned short word;
 
-    int end_of_ring = dev->rmem_end;
+    int end_of_ring = ei_status.rmem_end;
 
     /* Maybe enable shared memory just be to be safe... nahh.*/
     if (dev->mem_start) {	/* Use the shared memory. */
@@ -559,7 +559,7 @@
 	    int semi_count = end_of_ring - (dev->mem_start + ring_offset);
 	    isa_memcpy_fromio(skb->data, dev->mem_start + ring_offset, semi_count);
 	    count -= semi_count;
-	    isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+	    isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
 		isa_eth_io_copy_and_sum(skb, dev->mem_start + ring_offset, count, 0);
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/3c505.c	Wed Apr  3 17:11:15 2002
@@ -1383,7 +1383,7 @@
 	/*
 	 * memory information
 	 */
-	dev->mem_start = dev->mem_end = dev->rmem_end = dev->rmem_start = 0;
+	dev->mem_start = dev->mem_end = 0;
 }
 
 /************************************************************
diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h
--- a/drivers/net/8390.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/8390.h	Wed Apr  3 17:11:15 2002
@@ -51,8 +51,6 @@
 extern int ei_close(struct net_device *dev);
 extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
-/* Most of these entries should be in 'struct net_device' (or most of the
-   things in there should be here!) */
 /* You have one of these per-board */
 struct ei_device {
 	const char *name;
@@ -60,6 +58,8 @@
 	void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
 	void (*block_output)(struct net_device *, int, const unsigned char *, int);
 	void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+	unsigned long rmem_start;
+	unsigned long rmem_end;
 	unsigned char mcfilter[8];
 	unsigned open:1;
 	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/Config.in	Wed Apr  3 17:11:14 2002
@@ -57,6 +57,9 @@
    if [ "$CONFIG_MIPS_AU1000" = "y" ]; then
       bool '  MIPS AU1000 Ethernet support' CONFIG_MIPS_AU1000_ENET
    fi
+   if [ "$CONFIG_SIBYTE_SB1250" = "y" ]; then
+      tristate '  SB1250 Ethernet support' CONFIG_NET_SB1250_MAC
+   fi
    if [ "$CONFIG_SGI_IP27" = "y" ]; then
       bool '  SGI IOC3 Ethernet' CONFIG_SGI_IOC3_ETH
    fi
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/Makefile	Wed Apr  3 17:11:14 2002
@@ -82,6 +82,7 @@
 obj-$(CONFIG_STNIC) += stnic.o 8390.o
 obj-$(CONFIG_FEALNX) += fealnx.o mii.o
 obj-$(CONFIG_TIGON3) += tg3.o
+obj-$(CONFIG_TC35815) += tc35815.o
 
 ifeq ($(CONFIG_SK98LIN),y)
 obj-y += sk98lin/sk98lin.o
@@ -133,6 +134,7 @@
 obj-$(CONFIG_ES3210) += es3210.o 8390.o
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
+obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
 
 obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
@@ -153,6 +155,7 @@
 obj-$(CONFIG_DE620) += de620.o
 obj-$(CONFIG_AT1500) += lance.o
 obj-$(CONFIG_LANCE) += lance.o
+obj-$(CONFIG_SUN3_82586) += sun3_82586.o
 obj-$(CONFIG_SUN3LANCE) += sun3lance.o
 obj-$(CONFIG_DEFXX) += defxx.o
 obj-$(CONFIG_SGISEEQ) += sgiseeq.o
diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/Space.c	Wed Apr  3 17:11:14 2002
@@ -12,6 +12,8 @@
  *		Donald J. Becker, <becker@scyld.com>
  *
  * Changelog:
+ *		Paul Gortmaker (03/2002)
+		- struct init cleanup, enable multiple ISA autoprobes.
  *		Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
  *		- fix sbni: s/device/net_device/
  *		Paul Gortmaker (06/98): 
@@ -86,6 +88,7 @@
 extern int sgiseeq_probe(struct net_device *);
 extern int atarilance_probe(struct net_device *);
 extern int sun3lance_probe(struct net_device *);
+extern int sun3_82586_probe(struct net_device *);
 extern int apne_probe(struct net_device *);
 extern int bionet_probe(struct net_device *);
 extern int pamsnet_probe(struct net_device *);
@@ -332,6 +335,9 @@
 #ifdef CONFIG_SUN3LANCE         /* sun3 onboard Lance chip */
 	{sun3lance_probe, 0},
 #endif
+#ifdef CONFIG_SUN3_82586        /* sun3 onboard Intel 82586 chip */
+	{sun3_82586_probe, 0},
+#endif
 #ifdef CONFIG_APNE		/* A1200 PCMCIA NE2000 */
 	{apne_probe, 0},
 #endif
@@ -410,14 +416,7 @@
 		return 0;
 	if (probe_list(dev, mca_probes) == 0)
 		return 0;
-        /*
-         * Backwards compatibility - an I/O of 0xffe0 was used to indicate
-         * that we shouldn't do a bunch of potentially risky ISA probes
-         * for ethN (N>1).  Since the widespread use of modules, *nobody*
-         * compiles a kernel with all the ISA drivers built in anymore,
-         * and so we should delete this check in linux 2.3 - Paul G.
-         */
-	if (base_addr != 0xffe0 && probe_list(dev, isa_probes) == 0) 
+	if (probe_list(dev, isa_probes) == 0) 
 		return 0;
 	if (probe_list(dev, parport_probes) == 0)
 		return 0;
@@ -466,74 +465,102 @@
 
 
 #ifdef CONFIG_ETHERTAP
-    static struct net_device tap0_dev = { "tap0", 0, 0, 0, 0, NETLINK_TAPBASE, 0, 0, 0, 0, NEXT_DEV, ethertap_probe, };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&tap0_dev)
+static struct net_device tap0_dev = {
+	name:		"tap0",
+	base_addr:	NETLINK_TAPBASE,
+	next:		NEXT_DEV,
+	init:		ethertap_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV	(&tap0_dev)
 #endif
 
 #ifdef CONFIG_SDLA
-    extern int sdla_init(struct net_device *);
-    static struct net_device sdla0_dev = { "sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sdla_init, };
-
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&sdla0_dev)
+extern int sdla_init(struct net_device *);
+static struct net_device sdla0_dev = {
+	name:		 "sdla0",
+	next:		 NEXT_DEV,
+	init:		 sdla_init,
+};
+#undef NEXT_DEV
+#define NEXT_DEV	(&sdla0_dev)
 #endif
 
 #if defined(CONFIG_LTPC)
-    extern int ltpc_probe(struct net_device *);
-    static struct net_device dev_ltpc = {
-        "lt0",
-                0, 0, 0, 0,
-                0x0, 0,
-                0, 0, 0, NEXT_DEV, ltpc_probe };
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&dev_ltpc)
+extern int ltpc_probe(struct net_device *);
+static struct net_device dev_ltpc = {
+	name:		"lt0",
+	next:		NEXT_DEV,
+	init:		ltpc_probe
+};
+#undef NEXT_DEV
+#define NEXT_DEV	(&dev_ltpc)
 #endif  /* LTPC */
 
 #if defined(CONFIG_COPS)
-    extern int cops_probe(struct net_device *);
-    static struct net_device cops2_dev = { "lt2", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NEXT_DEV, cops_probe };
-    static struct net_device cops1_dev = { "lt1", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops2_dev, cops_probe };
-    static struct net_device cops0_dev = { "lt0", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, &cops1_dev, cops_probe };
-#   undef NEXT_DEV
-#   define NEXT_DEV     (&cops0_dev)
+extern int cops_probe(struct net_device *);
+static struct net_device cops2_dev = {
+	name:		"lt2",
+	next:		NEXT_DEV,
+	init:		cops_probe,
+};
+static struct net_device cops1_dev = {
+	name:		"lt1",
+	next:		&cops2_dev,
+	init:		cops_probe,
+};
+static struct net_device cops0_dev = {
+	name:		"lt0",
+	next:		&cops1_dev,
+	init:		cops_probe,
+};
+#undef NEXT_DEV
+#define NEXT_DEV     (&cops0_dev)
 #endif  /* COPS */
 
-
-/* The first device defaults to I/O base '0', which means autoprobe. */
-#ifndef ETH0_ADDR
-# define ETH0_ADDR 0
-#endif
-#ifndef ETH0_IRQ
-# define ETH0_IRQ 0
-#endif
-
-/* "eth0" defaults to autoprobe (== 0), other use a base of 0xffe0 (== -0x20),
-   which means "don't do ISA probes".  Distributions don't ship kernels with
-   all ISA drivers compiled in anymore, so its probably no longer an issue. */
-
-#define ETH_NOPROBE_ADDR 0xffe0
-
 static struct net_device eth7_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe };
+	name:		"eth%d",
+	next:		NEXT_DEV,
+	init:		ethif_probe,
+};
 static struct net_device eth6_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth7_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth7_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth5_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth6_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth6_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth4_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth5_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth5_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth3_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth4_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth4_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth2_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth3_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth3_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth1_dev = {
-    "eth%d", 0,0,0,0,ETH_NOPROBE_ADDR /* I/O base*/, 0,0,0,0, &eth2_dev, ethif_probe };
-
+	name:		"eth%d",
+	next:		&eth2_dev,
+	init:		ethif_probe,
+};
 static struct net_device eth0_dev = {
-    "eth%d", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, &eth1_dev, ethif_probe };
+	name:		"eth%d",
+	next:		&eth1_dev,
+	init:		ethif_probe,
+};
 
-#   undef NEXT_DEV
-#   define NEXT_DEV	(&eth0_dev)
+#undef NEXT_DEV
+#define NEXT_DEV	(&eth0_dev)
 
 
 
@@ -558,75 +585,153 @@
     return 0;
 }
 static struct net_device tr7_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, NEXT_DEV, trif_probe };
+	name:		"tr%d",
+	next:		NEXT_DEV,
+	init:		trif_probe,
+};
 static struct net_device tr6_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr7_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr7_dev,
+	init:		trif_probe,
+};
 static struct net_device tr5_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr6_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr6_dev,
+	init:		trif_probe,
+};
 static struct net_device tr4_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr5_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr5_dev,
+	init:		trif_probe,
+};
 static struct net_device tr3_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr4_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr4_dev,
+	init:		trif_probe,
+};
 static struct net_device tr2_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr3_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr3_dev,
+	init:		trif_probe,
+};
 static struct net_device tr1_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr2_dev, trif_probe };
+	name:		"tr%d",
+	next:		&tr2_dev,
+	init:		trif_probe,
+};
 static struct net_device tr0_dev = {
-    "tr%d",0,0,0,0,0,0,0,0,0, &tr1_dev, trif_probe };
-#   undef       NEXT_DEV
-#   define      NEXT_DEV        (&tr0_dev)
+	name:		"tr%d",
+	next:		&tr1_dev,
+	init:		trif_probe,
+};
+#undef       NEXT_DEV
+#define      NEXT_DEV        (&tr0_dev)
 
 #endif 
 
 #ifdef CONFIG_FDDI
-	static struct net_device fddi7_dev =
-		{"fddi7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fddiif_probe};
-	static struct net_device fddi6_dev =
-		{"fddi6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi7_dev, fddiif_probe};
-	static struct net_device fddi5_dev =
-		{"fddi5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi6_dev, fddiif_probe};
-	static struct net_device fddi4_dev =
-		{"fddi4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi5_dev, fddiif_probe};
-	static struct net_device fddi3_dev =
-		{"fddi3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi4_dev, fddiif_probe};
-	static struct net_device fddi2_dev =
-		{"fddi2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi3_dev, fddiif_probe};
-	static struct net_device fddi1_dev =
-		{"fddi1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi2_dev, fddiif_probe};
-	static struct net_device fddi0_dev =
-		{"fddi0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fddi1_dev, fddiif_probe};
+static struct net_device fddi7_dev = {
+	name:		"fddi7",
+	next:		 NEXT_DEV,
+	init:		fddiif_probe
+};
+static struct net_device fddi6_dev = {
+	name:		"fddi6",
+	next:		&fddi7_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi5_dev = {
+	name:		"fddi5",
+	next:		&fddi6_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi4_dev = {
+	name:		"fddi4",
+	next:		&fddi5_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi3_dev = {
+	name:		"fddi3",
+	next:		&fddi4_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi2_dev = {
+	name:		"fddi2",
+	next:		&fddi3_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi1_dev = {
+	name:		"fddi1",
+	next:		&fddi2_dev,
+	init:		fddiif_probe
+};
+static struct net_device fddi0_dev = {
+	name:		"fddi0",
+	next:		&fddi1_dev,
+	init:		fddiif_probe
+};
 #undef	NEXT_DEV
 #define	NEXT_DEV	(&fddi0_dev)
 #endif 
 
 
 #ifdef CONFIG_NET_FC
-    static struct net_device fc1_dev = {
-        "fc1", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, fcif_probe};
-	static struct net_device fc0_dev = {
-		"fc0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &fc1_dev, fcif_probe};
-#   undef       NEXT_DEV
-#   define      NEXT_DEV        (&fc0_dev)
+static struct net_device fc1_dev = {
+	name:		"fc1",
+	next:		NEXT_DEV,
+	init:		fcif_probe
+};
+static struct net_device fc0_dev = {
+	name:		"fc0",
+	next:		 &fc1_dev,
+	init:		fcif_probe
+};
+#undef       NEXT_DEV
+#define      NEXT_DEV        (&fc0_dev)
 #endif
 
 
 #ifdef CONFIG_SBNI
-	static struct net_device sbni7_dev =
-		{"sbni7", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, sbni_probe};
-	static struct net_device sbni6_dev =
-		{"sbni6", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni7_dev, sbni_probe};
-	static struct net_device sbni5_dev =
-		{"sbni5", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni6_dev, sbni_probe};
-	static struct net_device sbni4_dev =
-		{"sbni4", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni5_dev, sbni_probe};
-	static struct net_device sbni3_dev =
-		{"sbni3", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni4_dev, sbni_probe};
-	static struct net_device sbni2_dev =
-		{"sbni2", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni3_dev, sbni_probe};
-	static struct net_device sbni1_dev =
-		{"sbni1", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni2_dev, sbni_probe};
-	static struct net_device sbni0_dev =
-		{"sbni0", 0, 0, 0, 0, 0, 0, 0, 0, 0, &sbni1_dev, sbni_probe};
+static struct net_device sbni7_dev = {
+	name:		"sbni7",
+	next:		NEXT_DEV,
+	init:		sbni_probe,
+};
+static struct net_device sbni6_dev =
+	name:		"sbni6",
+	next:		&sbni7_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni5_dev =
+	name:		"sbni5",
+	next:		&sbni6_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni4_dev =
+	name:		"sbni4",
+	next:		&sbni5_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni3_dev =
+	name:		"sbni3",
+	next:		&sbni4_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni2_dev =
+	name:		"sbni2",
+	next:		&sbni3_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni1_dev =
+	name:		"sbni1",
+	next:		&sbni2_dev,
+	init:		sbni_probe,
+};
+static struct net_device sbni0_dev =
+	name:		"sbni0",
+	next:		&sbni1_dev,
+	init:		sbni_probe,
+};
 
 #undef	NEXT_DEV
 #define	NEXT_DEV	(&sbni0_dev)
@@ -638,8 +743,11 @@
  */
 
 extern int loopback_init(struct net_device *dev);
-struct net_device loopback_dev = 
-	{"lo", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, loopback_init};
+struct net_device loopback_dev = {
+	name:		"lo",
+	next:		NEXT_DEV,
+	init:		loopback_init
+};
 
 /*
  * The @dev_base list is protected by @dev_base_lock and the rtln
diff -Nru a/drivers/net/ac3200.c b/drivers/net/ac3200.c
--- a/drivers/net/ac3200.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/ac3200.c	Wed Apr  3 17:11:14 2002
@@ -226,8 +226,8 @@
 				AC_STOP_PG/4, dev->mem_start);
 	}
 
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = dev->rmem_end = dev->mem_start
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = ei_status.rmem_end = dev->mem_start
 		+ (AC_STOP_PG - AC_START_PG)*256;
 
 	ei_status.name = "AC3200";
@@ -302,12 +302,12 @@
 {
 	unsigned long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
 		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c
--- a/drivers/net/acenic.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/acenic.c	Wed Apr  3 17:11:15 2002
@@ -65,7 +65,10 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/sockios.h>
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #include <linux/if_vlan.h>
+#endif
 
 #ifdef SIOCETHTOOL
 #include <linux/ethtool.h>
@@ -320,9 +323,11 @@
 
 #if (defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)) && \
 	defined(NETIF_F_HW_VLAN_RX)
-#define ACENIC_DO_VLAN	1
+#define ACENIC_DO_VLAN		1
+#define ACE_RCB_VLAN_FLAG	RCB_FLG_VLAN_ASSIST
 #else
-#define ACENIC_DO_VLAN	0
+#define ACENIC_DO_VLAN		0
+#define ACE_RCB_VLAN_FLAG	0
 #endif
 
 #include "acenic.h"
@@ -563,7 +568,7 @@
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.88 03/14/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.89 03/15/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -1461,10 +1466,8 @@
 
 	set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_ring_base_dma);
 	info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
-	info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-	info->rx_std_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+	info->rx_std_ctrl.flags =
+	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
 
 	memset(ap->rx_std_ring, 0,
 	       RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1479,10 +1482,8 @@
 		    (ap->rx_ring_base_dma +
 		     (sizeof(struct rx_desc) * RX_STD_RING_ENTRIES)));
 	info->rx_jumbo_ctrl.max_len = 0;
-	info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-	info->rx_jumbo_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+	info->rx_jumbo_ctrl.flags =
+	  RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
 
 	memset(ap->rx_jumbo_ring, 0,
 	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
@@ -1504,10 +1505,7 @@
 			       RX_JUMBO_RING_ENTRIES))));
 		info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
 		info->rx_mini_ctrl.flags = 
-			RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
-#if ACENIC_DO_VLAN
-		info->rx_mini_ctrl.flags |= RCB_FLG_VLAN_ASSIST;
-#endif
+		  RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
 
 		for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
 			ap->rx_mini_ring[i].flags =
@@ -1554,7 +1552,7 @@
 	}
 
 	info->tx_ctrl.max_len = ACE_TX_RING_ENTRIES(ap);
-	tmp = RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR;
+	tmp = RCB_FLG_TCP_UDP_SUM | RCB_FLG_NO_PSEUDO_HDR | ACE_RCB_VLAN_FLAG;
 
 	/*
 	 * The Tigon I does not like having the TX ring in host memory ;-(
@@ -1564,9 +1562,6 @@
 #if TX_COAL_INTS_ONLY
 	tmp |= RCB_FLG_COAL_INT_ONLY;
 #endif
-#if ACENIC_DO_VLAN
-	tmp |= RCB_FLG_VLAN_ASSIST;
-#endif
 	info->tx_ctrl.flags = tmp;
 
 	set_aceaddr(&info->tx_csm_ptr, ap->tx_csm_dma);
@@ -1592,7 +1587,7 @@
 	ace_set_rxtx_parms(dev, 0);
 
 	if (board_idx == BOARD_IDX_OVERFLOW) {
-		printk(KERN_WARNING "%s: more then %i NICs detected, "
+		printk(KERN_WARNING "%s: more than %i NICs detected, "
 		       "ignoring module parameters!\n",
 		       dev->name, ACE_MAX_MOD_PARMS);
 	} else if (board_idx >= 0) {
@@ -2181,14 +2176,6 @@
 }
 
 
-#if ACENIC_DO_VLAN
-static int ace_vlan_rx(struct ace_private *ap, struct sk_buff *skb, u16 vlan_tag)
-{
-	return vlan_hwaccel_rx(skb, ap->vlgrp, vlan_tag);
-}
-#endif
-
-
 static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
 	struct ace_private *ap = dev->priv;
@@ -2274,11 +2261,9 @@
 		}
 
 		/* send it up */
-
 #if ACENIC_DO_VLAN
-		if (ap->vlgrp != NULL &&
-		    (bd_flags & BD_FLG_VLAN_TAG)) {
-			ace_vlan_rx(ap, skb, retdesc->vlan);
+		if (ap->vlgrp && (bd_flags & BD_FLG_VLAN_TAG)) {
+			vlan_hwaccel_rx(skb, ap->vlgrp, retdesc->vlan);
 		} else
 #endif
 			netif_rx(skb);
diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h
--- a/drivers/net/acenic.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/acenic.h	Wed Apr  3 17:11:15 2002
@@ -642,10 +642,6 @@
 	struct ace_skb		*skb;
 	dma_addr_t		info_dma;	/* 32/64 bit */
 
-#if ACENIC_DO_VLAN
-	struct vlan_group	*vlgrp;
-#endif
-
 	int			version, link;
 	int			promisc, mcast_all;
 
@@ -655,7 +651,6 @@
 	struct tx_desc		*tx_ring;
 	u32			tx_prd;
 	volatile u32		tx_ret_csm;
-	struct timer_list	timer;
 	int			tx_ring_entries;
 
 	/*
@@ -674,6 +669,10 @@
 	struct rx_desc		*rx_jumbo_ring;
 	struct rx_desc		*rx_mini_ring;
 	struct rx_desc		*rx_return_ring;
+
+#if ACENIC_DO_VLAN
+	struct vlan_group	*vlgrp;
+#endif
 
 	int			tasklet_pending, jumbo;
 	struct tasklet_struct	ace_tasklet;
diff -Nru a/drivers/net/aironet4500.h b/drivers/net/aironet4500.h
--- a/drivers/net/aironet4500.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/aironet4500.h	Wed Apr  3 17:11:13 2002
@@ -450,7 +450,7 @@
 };
 
 
-extern  __inline__ void
+static  __inline__ void
 awc_fid_queue_init(struct awc_fid_queue * queue){
 
 	unsigned long flags;
@@ -463,7 +463,7 @@
 	spin_unlock_irqrestore(&queue->spinlock,flags);	
 };
 
-extern inline void
+static inline void
 awc_fid_queue_push_tail(	struct awc_fid_queue * 	queue,
 				struct awc_fid *	fid){
 
@@ -488,7 +488,7 @@
 };
 
 
-extern inline void
+static inline void
 awc_fid_queue_push_head(	struct awc_fid_queue * 	queue,
 				struct awc_fid *	fid){
 
@@ -513,7 +513,7 @@
 
 
 
-extern inline void
+static inline void
 awc_fid_queue_rm(		struct awc_fid_queue * 	queue,
 				struct awc_fid *	fid){
 
@@ -541,7 +541,7 @@
 	}		
 };
 
-extern inline void
+static inline void
 awc_fid_queue_remove(		struct awc_fid_queue * 	queue,
 				struct awc_fid *	fid){
 	unsigned long flags;
@@ -555,7 +555,7 @@
 
 
 
-extern inline struct awc_fid * 
+static inline struct awc_fid * 
 awc_fid_queue_pop_head(		struct awc_fid_queue * 	queue){
 
 	unsigned long flags;
@@ -575,7 +575,7 @@
 
 
 
-extern inline struct awc_fid * 
+static inline struct awc_fid * 
 awc_fid_queue_pop_tail(		struct awc_fid_queue * 	queue){
 
 	unsigned long flags;
diff -Nru a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c
--- a/drivers/net/arcnet/arc-rimi.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/arcnet/arc-rimi.c	Wed Apr  3 17:11:14 2002
@@ -153,8 +153,6 @@
 
 	dev->mem_start = first_mirror;
 	dev->mem_end = last_mirror + MIRROR_SIZE - 1;
-	dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
-	dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
 
 	/* initialize the rest of the device structure. */
 
diff -Nru a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c
--- a/drivers/net/arcnet/com90xx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/arcnet/com90xx.c	Wed Apr  3 17:11:15 2002
@@ -447,8 +447,6 @@
 
 	dev->mem_start = first_mirror;
 	dev->mem_end = last_mirror + MIRROR_SIZE - 1;
-	dev->rmem_start = dev->mem_start + BUFFER_SIZE * 0;
-	dev->rmem_end = dev->mem_start + BUFFER_SIZE * 2 - 1;
 
 	/* Initialize the rest of the device structure. */
 	memset(lp, 0, sizeof(struct arcnet_local));
diff -Nru a/drivers/net/arlan.c b/drivers/net/arlan.c
--- a/drivers/net/arlan.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/arlan.c	Wed Apr  3 17:11:14 2002
@@ -128,7 +128,7 @@
 
 EXPORT_SYMBOL(arlan_command);
 
-extern inline long long arlan_time(void)
+static inline long long arlan_time(void)
 {
 	struct timeval timev;
 	do_gettimeofday(&timev);
@@ -186,7 +186,7 @@
 
 
 
-extern inline int arlan_drop_tx(struct net_device *dev)
+static inline int arlan_drop_tx(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
@@ -554,7 +554,7 @@
 
 };
 
-extern inline void arlan_command_process(struct net_device *dev)
+static inline void arlan_command_process(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
@@ -575,7 +575,7 @@
 }
 
 
-extern inline void arlan_retransmit_now(struct net_device *dev)
+static inline void arlan_retransmit_now(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
@@ -1405,7 +1405,7 @@
 }
 
 
-extern inline int DoNotReTransmitCrap(struct net_device *dev)
+static inline int DoNotReTransmitCrap(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
@@ -1415,7 +1415,7 @@
 
 }
 
-extern inline int DoNotWaitReTransmitCrap(struct net_device *dev)
+static inline int DoNotWaitReTransmitCrap(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
@@ -1424,7 +1424,7 @@
 	return 0;
 }
 
-extern inline void arlan_queue_retransmit(struct net_device *dev)
+static inline void arlan_queue_retransmit(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c
--- a/drivers/net/at1700.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/at1700.c	Wed Apr  3 17:11:15 2002
@@ -465,7 +465,7 @@
 #define EE_DATA_READ	0x80	/* EEPROM chip data out, in reg. 17. */
 
 /* Delay between EEPROM clock transitions. */
-#define eeprom_delay()	do {} while (0);
+#define eeprom_delay()	do { } while (0)
 
 /* The EEPROM commands include the alway-set leading bit. */
 #define EE_WRITE_CMD	(5 << 6)
diff -Nru a/drivers/net/atp.c b/drivers/net/atp.c
--- a/drivers/net/atp.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/atp.c	Wed Apr  3 17:11:15 2002
@@ -667,7 +667,7 @@
 			}
 			num_tx_since_rx++;
 		} else if (num_tx_since_rx > 8
-				   && jiffies > dev->last_rx + HZ) {
+				   && time_after(jiffies, dev->last_rx + HZ)) {
 			if (net_debug > 2)
 				printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and "
 					   "%ld jiffies status %02x  CMR1 %02x.\n", dev->name,
diff -Nru a/drivers/net/daynaport.c b/drivers/net/daynaport.c
--- a/drivers/net/daynaport.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/daynaport.c	Wed Apr  3 17:11:13 2002
@@ -513,14 +513,14 @@
                ei_status.tx_start_page = CABLETRON_TX_START_PG;
                ei_status.rx_start_page = CABLETRON_RX_START_PG;
                ei_status.stop_page = CABLETRON_RX_STOP_PG;
-               dev->rmem_start = dev->mem_start;
-               dev->rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
+               ei_status.rmem_start = dev->mem_start;
+               ei_status.rmem_end = dev->mem_start + CABLETRON_RX_STOP_PG*256;
        } else {
                ei_status.tx_start_page = WD_START_PG;
                ei_status.rx_start_page = WD_START_PG + TX_PAGES;
                ei_status.stop_page = (dev->mem_end - dev->mem_start)/256;
-               dev->rmem_start = dev->mem_start + TX_PAGES*256;
-               dev->rmem_end = dev->mem_end;
+               ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+               ei_status.rmem_end = dev->mem_end;
        }
 	
 	if(promoff==-1)		/* Use nubus resources ? */
@@ -779,14 +779,14 @@
 	 *	is word per long onto our space.
 	 */
 	 
-	if (xfer_start + count > dev->rmem_end) 
+	if (xfer_start + count > ei_status.rmem_end) 
 	{
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		dayna_memcpy_fromcard(dev, skb->data, xfer_base, semi_count);
 		count -= semi_count;
 		dayna_memcpy_fromcard(dev, skb->data + semi_count, 
-			dev->rmem_start - dev->mem_start, count);
+			ei_status.rmem_start - dev->mem_start, count);
 	}
 	else
 	{
@@ -820,14 +820,14 @@
 	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
 	unsigned long xfer_start = xfer_base+dev->mem_start;
 
-	if (xfer_start + count > dev->rmem_end) 
+	if (xfer_start + count > ei_status.rmem_end) 
 	{
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		memcpy(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
 		count -= semi_count;
 		memcpy(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
+			(char *)ei_status.rmem_start, count);
 	}
 	else
 	{
@@ -881,14 +881,14 @@
 	unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
 	unsigned long xfer_start = xfer_base+dev->mem_start;
 
-	if (xfer_start + count > dev->rmem_end) 
+	if (xfer_start + count > ei_status.rmem_end) 
 	{
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
 		count -= semi_count;
 		word_memcpy_fromcard(skb->data + semi_count, 
-			(char *)dev->rmem_start, count);
+			(char *)ei_status.rmem_start, count);
 	}
 	else
 	{
diff -Nru a/drivers/net/de620.c b/drivers/net/de620.c
--- a/drivers/net/de620.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/de620.c	Wed Apr  3 17:11:13 2002
@@ -449,11 +449,17 @@
 		return ret;
 	}
 
-	if (adapter_init(dev))
-		return -EIO;
+	if (adapter_init(dev)) {
+		ret = -EIO;
+		goto out_free_irq;
+	}
 
 	netif_start_queue(dev);
 	return 0;
+
+out_free_irq:
+	free_irq(dev->irq, dev);
+	return ret;
 }
 
 /************************************************
@@ -850,7 +856,10 @@
 		return -EBUSY;
 	}
 #endif
-	request_region(dev->base_addr, 3, "de620");
+	if (!request_region(dev->base_addr, 3, "de620")) {
+		printk(KERN_ERR "io 0x%3lX, which is busy.\n", dev->base_addr);
+		return -EBUSY;
+	}
 
 	/* else, got it! */
 	printk(", Ethernet Address: %2.2X",
diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/dl2k.c	Wed Apr  3 17:11:15 2002
@@ -1,6 +1,6 @@
 /*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
 /*
-    Copyright (c) 2001 by D-Link Corporation
+    Copyright (c) 2001,2002 by D-Link Corporation
     Written by Edward Peng.<edward_peng@dlink.com.tw>
     Created 03-May-2001, base on Linux' sundance.c.
 
@@ -27,12 +27,14 @@
 				Added tx_coalesce paramter.
     1.07	2002/01/03	Fixed miscount of RX frame error.
     1.08	2002/01/17	Fixed the multicast bug.
+    1.09	2002/03/07	Move rx-poll-now to re-fill loop.	
+    				Added rio_timer() to watch rx buffers. 
  */
 
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.08 2002/01/17\n";
+    KERN_INFO "D-Link DL2000-based linux driver v1.09 2002/03/07\n";
 
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
@@ -42,9 +44,10 @@
 static int tx_flow[MAX_UNITS];
 static int rx_flow[MAX_UNITS];
 static int copy_thresh;
-static int rx_coalesce = DEFAULT_RXC;
-static int rx_timeout = DEFAULT_RXT;	
-static int tx_coalesce = DEFAULT_TXC;	
+static int rx_coalesce;			/* Rx frame count each interrupt */
+static int rx_timeout; 			/* Rx DMA wait time in 64ns increments */
+static int tx_coalesce = DEFAULT_TXC; 	/* HW xmit count each TxComplete [1-8] */
+
 
 MODULE_AUTHOR ("Edward Peng");
 MODULE_DESCRIPTION ("D-Link DL2000-based Gigabit Ethernet Adapter");
@@ -71,6 +74,7 @@
 static int multicast_filter_limit = 0x40;
 
 static int rio_open (struct net_device *dev);
+static void rio_timer (unsigned long data);
 static void tx_timeout (struct net_device *dev);
 static void alloc_list (struct net_device *dev);
 static int start_xmit (struct sk_buff *skb, struct net_device *dev);
@@ -146,6 +150,7 @@
 	np->chip_id = chip_idx;
 	np->pdev = pdev;
 	spin_lock_init (&np->lock);
+	spin_lock_init (&np->rx_lock);
 
 	/* Parse manual configuration */
 	np->an_enable = 1;
@@ -260,6 +265,7 @@
 			np->an_enable = 1;
 		mii_set_media (dev);
 	}
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
 
 	/* Reset all logic functions */
 	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
@@ -340,7 +346,7 @@
 	}
 
 	/* Check CRC */
-	crc = ~ether_crc_le(256 - 4, sromdata);
+ 	crc = ~ether_crc_le(256 - 4, sromdata);
 	if (psrom->crc != crc) {
 		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
 		return -1;
@@ -421,8 +427,10 @@
 			ioaddr + RxDMAIntCtrl);
 	}
 	/* Set RIO to poll every N*320nsec. */
-	writeb (0xff, ioaddr + RxDMAPollPeriod);
+	writeb (0x20, ioaddr + RxDMAPollPeriod);
 	writeb (0xff, ioaddr + TxDMAPollPeriod);
+	writeb (0x30, ioaddr + RxDMABurstThresh);
+	writeb (0x30, ioaddr + RxDMAUrgentThresh);
 	netif_start_queue (dev);
 	writel (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl);
 	/* VLAN supported */
@@ -445,9 +453,59 @@
 
 	/* clear statistics */
 	get_stats (dev);
+	init_timer (&np->timer);
+	np->timer.expires = jiffies + 1*HZ;
+	np->timer.data = (unsigned long) dev;
+	np->timer.function = &rio_timer;
+	add_timer (&np->timer);
 	return 0;
 }
+static void 
+rio_timer (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	unsigned int entry;
+	int next_tick = 1*HZ;
+	unsigned long flags;
 
+	/* Recover rx ring exhausted error */
+	if (np->cur_rx - np->old_rx >= RX_RING_SIZE) {
+		printk(KERN_INFO "Try to recover rx ring exhausted...\n");
+		spin_lock_irqsave(&np->rx_lock, flags);
+		/* Re-allocate skbuffs to fill the descriptor ring */
+		for (; np->cur_rx - np->old_rx > 0; np->old_rx++) {
+			struct sk_buff *skb;
+			entry = np->old_rx % RX_RING_SIZE;
+			/* Dropped packets don't need to re-allocate */
+			if (np->rx_skbuff[entry] == NULL) {
+				skb = dev_alloc_skb (np->rx_buf_sz);
+				if (skb == NULL) {
+					np->rx_ring[entry].fraginfo = 0;
+					printk (KERN_INFO
+						"%s: Still unable to re-allocate Rx skbuff.#%d\n",
+						dev->name, entry);
+					break;
+				}
+				np->rx_skbuff[entry] = skb;
+				skb->dev = dev;
+				/* 16 byte align the IP header */
+				skb_reserve (skb, 2);
+				np->rx_ring[entry].fraginfo =
+				    cpu_to_le64 (pci_map_single
+					 (np->pdev, skb->tail, np->rx_buf_sz,
+					  PCI_DMA_FROMDEVICE));
+			}
+			np->rx_ring[entry].fraginfo |=
+			    cpu_to_le64 (np->rx_buf_sz) << 48;
+			np->rx_ring[entry].status = 0;
+		} /* end for */
+		spin_unlock_irqrestore (&np->rx_lock, flags);
+	} /* end if */
+	np->timer.expires = jiffies + next_tick;
+	add_timer(&np->timer);
+}
+	
 static void
 tx_timeout (struct net_device *dev)
 {
@@ -499,16 +557,14 @@
 		np->tx_ring[i].status = cpu_to_le64 (TFDDone);
 		np->tx_ring[i].next_desc = cpu_to_le64 (np->tx_ring_dma +
 					      ((i+1)%TX_RING_SIZE) *
-					      sizeof (struct
-					      netdev_desc));
+					      sizeof (struct netdev_desc));
 	}
 
 	/* Initialize Rx descriptors */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].next_desc = cpu_to_le64 (np->rx_ring_dma +
 						((i + 1) % RX_RING_SIZE) *
-						sizeof (struct
-						netdev_desc));
+						sizeof (struct netdev_desc));
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].fraginfo = 0;
 		np->rx_skbuff[i] = 0;
@@ -529,8 +585,8 @@
 		skb_reserve (skb, 2);	/* 16 byte align the IP header. */
 		/* Rubicon now supports 40 bits of addressing space. */
 		np->rx_ring[i].fraginfo =
-		    cpu_to_le64 (pci_map_single
-				 (np->pdev, skb->tail, np->rx_buf_sz,
+		    cpu_to_le64 ( pci_map_single (
+			 	  np->pdev, skb->tail, np->rx_buf_sz,
 				  PCI_DMA_FROMDEVICE));
 		np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
 	}
@@ -773,6 +829,8 @@
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int cnt = np->old_rx + RX_RING_SIZE - np->cur_rx;
 	int rx_shift;
+
+	spin_lock (&np->rx_lock);
 	if (np->old_rx > RX_RING_SIZE) {
 		rx_shift = RX_RING_SIZE;
 		np->old_rx -= rx_shift;
@@ -828,12 +886,14 @@
 				skb_put (skb, pkt_len);
 			}
 			skb->protocol = eth_type_trans (skb, dev);
-#if 0
+#if 0			
 			/* Checksum done by hw, but csum value unavailable. */
-			if (!(frame_status & (TCPError | UDPError | IPError))) {
+			if (np->pci_rev_id >= 0x0c && 
+				!(frame_status & (TCPError | UDPError | IPError))) {
 				skb->ip_summed = CHECKSUM_UNNECESSARY;
-			}
+			} 
 #endif
+					
 			netif_rx (skb);
 			dev->last_rx = jiffies;
 		}
@@ -849,9 +909,10 @@
 			skb = dev_alloc_skb (np->rx_buf_sz);
 			if (skb == NULL) {
 				np->rx_ring[entry].fraginfo = 0;
-				printk (KERN_ERR
-					"%s: Allocate Rx buffer error!",
-					dev->name);
+				printk (KERN_INFO
+					"%s: receive_packet: "
+					"Unable to re-allocate Rx skbuff.#%d\n",
+					dev->name, entry);
 				break;
 			}
 			np->rx_skbuff[entry] = skb;
@@ -866,13 +927,12 @@
 		np->rx_ring[entry].fraginfo |=
 		    cpu_to_le64 (np->rx_buf_sz) << 48;
 		np->rx_ring[entry].status = 0;
+		/* RxDMAPollNow */
+		writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
+			dev->base_addr + DMACtrl);
 	}
-
-	/* RxDMAPollNow */
-	writel (readl (dev->base_addr + DMACtrl) | 0x00000010,
-		dev->base_addr + DMACtrl);
-
 	DEBUG_RFD_DUMP (np, 2);
+	spin_unlock(&np->rx_lock);
 	return 0;
 }
 
@@ -1006,7 +1066,7 @@
 	
 	hash_table[0] = hash_table[1] = 0;
 	/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
-	hash_table[1] |= 0x02000000;
+	hash_table[1] |= cpu_to_le32(0x02000000);
 	if (dev->flags & IFF_PROMISC) {
 		/* Receive all frames promiscuously. */
 		rx_mode = ReceiveAllFrames;
@@ -1020,11 +1080,16 @@
 		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
-				i++, mclist=mclist->next) {
+			i++, mclist=mclist->next) {
+
 			crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
-			for (index=0, bit=0; bit<6; bit++, crc<<=1) {
-				if (crc & 0x80000000) index |= 1 << bit;
-			}
+
+			/* The inverted high significant 6 bits of CRC are
+			   used as an index to hashtable */
+			for (index = 0, bit = 0; bit < 6; bit++)
+				if (test_bit(31 - bit, &crc))
+					set_bit(bit, &index);
+
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
 	} else {
@@ -1094,6 +1159,7 @@
 		     np->old_rx);
 		break;
 	case SIOCDEVPRIVATE + 8:
+		printk("TX ring:\n");
 		for (i = 0; i < TX_RING_SIZE; i++) {
 			desc = &np->tx_ring[i];
 			printk
@@ -1629,7 +1695,8 @@
 	writel (TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl);
 	synchronize_irq ();
 	free_irq (dev->irq, dev);
-
+	del_timer_sync (&np->timer);
+	
 	/* Free all the skbuffs in the queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].status = 0;
@@ -1679,10 +1746,10 @@
 }
 
 static struct pci_driver rio_driver = {
-	name:"dl2k",
-	id_table:rio_pci_tbl,
-	probe:rio_probe1,
-	remove: __devexit_p(rio_remove1),
+	name:		"dl2k",
+	id_table:	rio_pci_tbl,
+	probe:		rio_probe1,
+	remove:		__devexit_p(rio_remove1),
 };
 
 static int __init
diff -Nru a/drivers/net/dl2k.h b/drivers/net/dl2k.h
--- a/drivers/net/dl2k.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/dl2k.h	Wed Apr  3 17:11:15 2002
@@ -1,6 +1,6 @@
 /*  D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
 /*  
-    Copyright (c) 2001 by D-Link Corporation
+    Copyright (c) 2001, 2002 by D-Link Corporation
     Written by Edward Peng.<edward_peng@dlink.com.tw>
     Created 03-May-2001, base on Linux' sundance.c.
 
@@ -649,6 +649,7 @@
 	dma_addr_t rx_ring_dma;
 	struct pci_dev *pdev;
 	spinlock_t lock;
+	spinlock_t rx_lock;
 	struct net_device_stats stats;
 	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
 	unsigned int speed;		/* Operating speed */
@@ -664,9 +665,11 @@
 	unsigned int tx_flow:1;		/* Tx flow control enable */
 	unsigned int rx_flow:1;		/* Rx flow control enable */
 	unsigned int phy_media:1;	/* 1: fiber, 0: copper */
+	unsigned char pci_rev_id;	/* PCI revision ID */
 	struct netdev_desc *last_tx;	/* Last Tx descriptor used. */
 	unsigned long cur_rx, old_rx;	/* Producer/consumer ring indices */
 	unsigned long cur_tx, old_tx;
+	struct timer_list timer;
 	int wake_polarity;
 	char name[256];		/* net device description */
 	u8 duplex_polarity;
diff -Nru a/drivers/net/e100/Makefile b/drivers/net/e100/Makefile
--- a/drivers/net/e100/Makefile	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/e100/Makefile	Wed Apr  3 17:11:16 2002
@@ -10,7 +10,7 @@
 O_TARGET := e100.o
 
 obj-y   := e100_main.o e100_config.o e100_proc.o e100_phy.o \
-	   e100_eeprom.o
+	   e100_eeprom.o e100_test.o
 obj-m   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
--- a/drivers/net/e100/e100.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e100/e100.h	Wed Apr  3 17:11:14 2002
@@ -899,6 +899,15 @@
 	int PollingMaxWork;
 	u32 b_params;
 };
+#ifdef ETHTOOL_TEST 
+struct ethtool_lpbk_data{
+        dma_addr_t dma_handle;
+        tcb_t *tcb;
+        rfd_t *rfd;
+
+};
+#endif
+
 
 struct e100_private {
 	u32 flags;		/* board management flags */
@@ -988,6 +997,9 @@
 	u32 wolopts;
 	u16 ip_lbytes;
 #endif
+#ifdef ETHTOOL_TEST
+struct ethtool_lpbk_data loopback;
+#endif
 
 #ifdef CONFIG_PM
 	u32 pci_state[16];
@@ -1027,5 +1039,24 @@
 				  u8 recover, u8 full_reset);
 extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
 					   u32 reset_cmd);
+
+#ifdef ETHTOOL_TEST
+
+#define ROM_TEST_FAIL		0x01
+#define REGISTER_TEST_FAIL	0x02
+#define SELF_TEST_FAIL		0x04
+#define TEST_TIMEOUT		0x08
+
+enum test_offsets {
+	E100_EEPROM_TEST_FAIL = 0,
+	E100_CHIP_TIMEOUT,
+	E100_ROM_TEST_FAIL,
+	E100_REG_TEST_FAIL,
+	E100_MAC_TEST_FAIL,
+	E100_LPBK_MAC_FAIL,
+	E100_LPBK_PHY_FAIL,
+	E100_MAX_TEST_RES
+};
+#endif
 
 #endif
diff -Nru a/drivers/net/e100/e100_config.c b/drivers/net/e100/e100_config.c
--- a/drivers/net/e100/e100_config.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e100/e100_config.c	Wed Apr  3 17:11:14 2002
@@ -593,3 +593,102 @@
 }
 #endif
 
+#ifdef ETHTOOL_TEST
+/**
+ * e100_config_loopback_mode
+ * @bdp: atapter's private data struct
+ * @mode: loopback mode(phy/mac/none)
+ *
+ */
+unsigned char
+e100_config_loopback_mode(struct e100_private *bdp, u8 mode)
+{
+	unsigned char bc_changed = false;
+	u8 config_byte;
+
+	spin_lock_bh(&(bdp->config_lock));
+
+	switch (mode) {
+	case NO_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_NORMAL;
+		break;
+	case MAC_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_INTERNAL;
+		break;
+	case PHY_LOOPBACK:
+		config_byte = CB_CFIG_LOOPBACK_EXTERNAL;
+		break;
+	default:
+		printk(KERN_NOTICE "e100_config_loopback_mode: "
+		       "Invalid argument 'mode': %d\n", mode);
+		goto exit;
+	}
+
+	if ((bdp->config[10] & CB_CFIG_LOOPBACK_MODE) != config_byte) {
+
+		bdp->config[10] &= (~CB_CFIG_LOOPBACK_MODE);
+		bdp->config[10] |= config_byte;
+		E100_CONFIG(bdp, 10);
+		bc_changed = true;
+	}
+
+exit:
+	spin_unlock_bh(&(bdp->config_lock));
+	return bc_changed;
+}
+unsigned char
+e100_config_tcb_ext_enable(struct e100_private *bdp, unsigned char enable)
+{
+        unsigned char bc_changed = false;
+ 
+        spin_lock_bh(&(bdp->config_lock));
+ 
+        if (enable) {
+                if (bdp->config[6] & CB_CFIG_EXT_TCB_DIS) {
+ 
+                        bdp->config[6] &= (~CB_CFIG_EXT_TCB_DIS);
+                        E100_CONFIG(bdp, 6);
+                        bc_changed = true;
+                }
+ 
+        } else {
+                if (!(bdp->config[6] & CB_CFIG_EXT_TCB_DIS)) {
+ 
+                        bdp->config[6] |= CB_CFIG_EXT_TCB_DIS;
+                        E100_CONFIG(bdp, 6);
+                        bc_changed = true;
+                }
+        }
+        spin_unlock_bh(&(bdp->config_lock));
+ 
+        return bc_changed;
+}
+unsigned char
+e100_config_dynamic_tbd(struct e100_private *bdp, unsigned char enable)
+{
+        unsigned char bc_changed = false;
+ 
+        spin_lock_bh(&(bdp->config_lock));
+ 
+        if (enable) {
+                if (!(bdp->config[7] & CB_CFIG_DYNTBD_EN)) {
+ 
+                        bdp->config[7] |= CB_CFIG_DYNTBD_EN;
+                        E100_CONFIG(bdp, 7);
+                        bc_changed = true;
+                }
+ 
+        } else {
+                if (bdp->config[7] & CB_CFIG_DYNTBD_EN) {
+ 
+                        bdp->config[7] &= (~CB_CFIG_DYNTBD_EN);
+                        E100_CONFIG(bdp, 7);
+                        bc_changed = true;
+                }
+        }
+        spin_unlock_bh(&(bdp->config_lock));
+ 
+        return bc_changed;
+}
+#endif
+
diff -Nru a/drivers/net/e100/e100_config.h b/drivers/net/e100/e100_config.h
--- a/drivers/net/e100/e100_config.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e100/e100_config.h	Wed Apr  3 17:11:14 2002
@@ -190,6 +190,10 @@
 
 #define CB_CFIG_LONG_RX_OK	    BIT_3
 
+#define NO_LOOPBACK	0	
+#define MAC_LOOPBACK	0x01
+#define PHY_LOOPBACK	0x02
+
 /* function prototypes */
 extern void e100_config_init(struct e100_private *bdp);
 extern unsigned char e100_force_config(struct e100_private *bdp);
@@ -201,5 +205,8 @@
 				     unsigned char enable);
 extern void e100_config_ifs(struct e100_private *bdp);
 extern void e100_config_force_dplx(struct e100_private *bdp);
+extern u8 e100_config_loopback_mode(struct e100_private *bdp, u8 mode);
+extern u8 e100_config_dynamic_tbd(struct e100_private *bdp, u8 enable);
+extern u8 e100_config_tcb_ext_enable(struct e100_private *bdp, u8 enable);
 
 #endif /* _E100_CONFIG_INC_ */
diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
--- a/drivers/net/e100/e100_main.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/e100/e100_main.c	Wed Apr  3 17:11:15 2002
@@ -147,6 +147,23 @@
 static u16 e100_get_ip_lbytes(struct net_device *dev);
 extern void e100_config_wol(struct e100_private *bdp);
 #endif
+#ifdef ETHTOOL_TEST
+extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
+static int e100_ethtool_test(struct net_device *, struct ifreq *);
+#endif
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *, struct ifreq *);
+static char *test_strings[] = {
+	"E100_EEPROM_TEST_FAIL",
+	"E100_CHIP_TIMEOUT",
+	"E100_ROM_TEST_FAIL",
+	"E100_REG_TEST_FAIL",
+	"E100_MAC_TEST_FAIL",
+	"E100_LPBK_MAC_FAIL",
+	"E100_LPBK_PHY_FAIL"
+};
+
+#endif
 #endif /*E100_ETHTOOL_IOCTL */
 
 #ifdef SIOCGMIIPHY
@@ -165,7 +182,7 @@
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
 
-#define E100_VERSION  "2.0.24-pre1"
+#define E100_VERSION  "2.0.25-pre1"
 
 #define E100_FULL_DRIVER_NAME 	"Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "
 
@@ -382,6 +399,7 @@
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);
 MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
 
 E100_PARAM(TxDescriptors, "Number of transmit descriptors");
 E100_PARAM(RxDescriptors, "Number of receive descriptors");
@@ -2715,8 +2733,10 @@
 	ntcb_hdr->cb_lnk_ptr = 0;
 
 	wmb();
+	if (in_interrupt())
+		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
-	if (in_interrupt() || netif_running(bdp->device))
+	if (netif_running(bdp->device) && (!bdp->driver_isolated))
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -3302,6 +3322,16 @@
 		rc = e100_ethtool_wol(dev, ifr);
 		break;
 #endif
+#ifdef ETHTOOL_TEST
+	case ETHTOOL_TEST:
+		rc = e100_ethtool_test(dev, ifr);
+		break;
+#endif
+#ifdef ETHTOOL_GSTRINGS
+	case ETHTOOL_GSTRINGS:
+		rc = e100_ethtool_gstrings(dev,ifr);
+		break;
+#endif
 	default:
 		break;
 	}			//switch
@@ -3464,6 +3494,36 @@
 }
 #endif
 
+#ifdef ETHTOOL_TEST
+static int
+e100_ethtool_test(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_test *info;
+	int rc = -EFAULT;
+
+	info = kmalloc(sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64),
+		       GFP_ATOMIC);
+
+	if (!info)
+		return -EFAULT;
+
+	memset((void *) info, 0, sizeof(*info) +
+				 E100_MAX_TEST_RES * sizeof(u64));
+
+	if (copy_from_user(info, ifr->ifr_data, sizeof(*info)))
+		goto exit;
+
+	info->flags = e100_run_diag(dev, info->data, info->flags);
+
+	if (!copy_to_user(ifr->ifr_data, info,
+			 sizeof(*info) + E100_MAX_TEST_RES * sizeof(u64)))
+		rc = 0;
+exit:
+	kfree(info);
+	return rc;
+}
+#endif
+
 #ifdef ETHTOOL_NWAY_RST
 static int
 e100_ethtool_nway_rst(struct net_device *dev, struct ifreq *ifr)
@@ -3505,7 +3565,9 @@
 #ifdef ETHTOOL_GEEPROM
 	info.eedump_len = (bdp->eeprom_size << 1);	
 #endif
-
+#ifdef ETHTOOL_TEST
+	info.testinfo_len = E100_MAX_TEST_RES;
+#endif
 	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
 		return -EFAULT;
 
@@ -3737,6 +3799,51 @@
 	return res;
 }
 
+#endif
+
+#ifdef ETHTOOL_GSTRINGS
+static int e100_ethtool_gstrings(struct net_device *dev, struct ifreq *ifr)
+{
+	struct ethtool_gstrings info;
+	char *strings = NULL;
+	char *usr_strings;
+	int i;
+
+	memset((void *) &info, 0, sizeof(info));
+
+	usr_strings = (u8 *) (ifr->ifr_data + 
+			      offsetof(struct ethtool_gstrings, data));
+
+	if (copy_from_user(&info, ifr->ifr_data, sizeof (info)))
+		return -EFAULT;
+
+	switch (info.string_set) {
+	case ETH_SS_TEST:
+		if (info.len > E100_MAX_TEST_RES)
+			info.len = E100_MAX_TEST_RES;
+		strings = kmalloc(info.len * ETH_GSTRING_LEN, GFP_ATOMIC);
+		if (!strings)
+			return -EFAULT;
+		memset(strings, 0, info.len * ETH_GSTRING_LEN);
+
+		for (i = 0; i < info.len; i++) {
+			sprintf(strings + i * ETH_GSTRING_LEN, "%-31s",
+				test_strings[i]);
+		}
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
+		return -EFAULT;
+
+	if (copy_to_user(usr_strings, strings, info.len * ETH_GSTRING_LEN))
+		return -EFAULT;
+
+	kfree(strings);
+	return 0;
+}
 #endif
 #endif /*E100_ETHTOOL_IOCTL */
 
diff -Nru a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/e100/e100_test.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,467 @@
+/*******************************************************************************
+
+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 2.0, 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 General Public License 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 
+General Public License 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 General 
+Public License 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.h"
+#include "e100_config.h"
+#ifdef ETHTOOL_TEST
+
+extern u16 e100_eeprom_read(struct e100_private *, u16);
+extern int e100_wait_exec_cmplx(struct e100_private *, u32,u8);
+extern void e100_phy_reset(struct e100_private *bdp);
+
+static u8 e100_diag_selftest(struct net_device *);
+static u8 e100_diag_eeprom(struct net_device *);
+static u8 e100_diag_loopback(struct net_device *);
+
+static u8 e100_diag_one_loopback (struct net_device *, u8);
+static u8 e100_diag_rcv_loopback_pkt(struct e100_private *);
+static void e100_diag_config_loopback(struct e100_private *, u8, u8, u8 *,u8 *);
+static u8 e100_diag_loopback_alloc(struct e100_private *);
+static void e100_diag_loopback_cu_ru_exec(struct e100_private *);
+static u8 e100_diag_check_pkt(u8 *);
+static void e100_diag_loopback_free(struct e100_private *);
+
+#define LB_PACKET_SIZE 1500
+
+/**
+ * e100_run_diag - main test execution handler - checks mask of requests and calls the diag routines  
+ * @dev: atapter's net device data struct
+ * @test_info: array with test request mask also used to store test results
+ *
+ * RETURNS: updated flags field of struct ethtool_test
+ */
+u32
+e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags)
+{
+	struct e100_private* bdp = dev->priv;
+	u8 test_result = true;
+
+	e100_isolate_driver(bdp);
+
+	if (flags & ETH_TEST_FL_OFFLINE) {
+		u8 fail_mask;
+		
+		fail_mask = e100_diag_selftest(dev);
+		if (fail_mask) {
+			test_result = false;
+			if (fail_mask & REGISTER_TEST_FAIL)
+				test_info [E100_REG_TEST_FAIL] = true;
+			if (fail_mask & ROM_TEST_FAIL)
+				test_info [E100_ROM_TEST_FAIL] = true;
+			if (fail_mask & SELF_TEST_FAIL)
+				test_info [E100_MAC_TEST_FAIL] = true;
+			if (fail_mask & TEST_TIMEOUT)
+				test_info [E100_CHIP_TIMEOUT] = true;
+		}
+
+		fail_mask = e100_diag_loopback(dev);
+		if (fail_mask) {
+			test_result = false;
+			if (fail_mask & PHY_LOOPBACK)
+				test_info [E100_LPBK_PHY_FAIL] = true;
+			if (fail_mask & MAC_LOOPBACK)
+				test_info [E100_LPBK_MAC_FAIL] = true;
+		}
+	}
+
+	if (!e100_diag_eeprom(dev)) {
+		test_result = false;
+		test_info [E100_EEPROM_TEST_FAIL] = true;
+	}
+
+	/* fully recover only if the device is open*/
+	if (netif_running(dev))  {
+		e100_deisolate_driver(bdp, true, false);
+	} else {
+    		e100_deisolate_driver(bdp, false, false);
+	}
+	/*Let card recover from the test*/
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ * 2);
+
+	return flags | (test_result ? 0 : ETH_TEST_FL_FAILED);
+}
+
+/**
+ * e100_diag_selftest - run hardware selftest 
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_selftest(struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	u32 st_timeout, st_result;
+	u8 retval = 0;
+
+	if (!e100_selftest(bdp, &st_timeout, &st_result)) {
+		if (!st_timeout) {
+			if (st_result & CB_SELFTEST_REGISTER_BIT)
+				retval |= REGISTER_TEST_FAIL;
+			if (st_result & CB_SELFTEST_DIAG_BIT)
+				retval |= SELF_TEST_FAIL;
+			if (st_result & CB_SELFTEST_ROM_BIT)
+				retval |= ROM_TEST_FAIL;
+		} else {
+            		retval = TEST_TIMEOUT;
+		}
+	}
+
+	e100_hw_reset_recover(bdp,PORT_SOFTWARE_RESET);
+
+	return retval;
+}
+
+/**
+ * e100_diag_eeprom - validate eeprom checksum correctness
+ * @dev: atapter's net device data struct
+ *
+ */
+static u8
+e100_diag_eeprom (struct net_device *dev)
+{
+	struct e100_private *bdp = dev->priv;
+	u16 i, eeprom_sum, eeprom_actual_csm;
+
+	for (i = 0, eeprom_sum = 0; i < (bdp->eeprom_size - 1); i++) {
+		eeprom_sum += e100_eeprom_read(bdp, i);
+	}
+
+	eeprom_actual_csm = e100_eeprom_read(bdp, bdp->eeprom_size - 1);
+
+	if (eeprom_actual_csm == (u16)(EEPROM_SUM - eeprom_sum)) {
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test  
+ * @dev: atapter's net device data struct
+ */
+static u8
+e100_diag_loopback (struct net_device *dev)
+{
+	u8 rc = 0;
+
+	if (!e100_diag_one_loopback(dev, PHY_LOOPBACK)) {
+		rc |= PHY_LOOPBACK;
+	}
+
+	if (!e100_diag_one_loopback(dev, MAC_LOOPBACK)) {
+		rc |= MAC_LOOPBACK;
+	}
+
+	return rc;
+}
+
+/**
+ * e100_diag_loopback - performs loopback test  
+ * @dev: atapter's net device data struct
+ * @mode: lopback test type
+ */
+static u8
+e100_diag_one_loopback (struct net_device *dev, u8 mode)
+{
+        struct e100_private *bdp = dev->priv;
+        u8 res = false;
+   	u8 saved_dynamic_tbd = false;
+   	u8 saved_extended_tcb = false;
+
+	if (!e100_diag_loopback_alloc(bdp))
+		return false;
+
+	/* change the config block to standard tcb and the correct loopback */
+        e100_diag_config_loopback(bdp, true, mode,
+				  &saved_extended_tcb, &saved_dynamic_tbd);
+
+	e100_diag_loopback_cu_ru_exec(bdp);
+
+        if (e100_diag_rcv_loopback_pkt(bdp)) {
+		res = true;
+	}
+
+        e100_diag_loopback_free(bdp);
+
+        /* change the config block to previous tcb mode and the no loopback */
+        e100_diag_config_loopback(bdp, false, mode,
+				  &saved_extended_tcb, &saved_dynamic_tbd);
+	return res;
+}
+
+/**
+ * e100_diag_config_loopback - setup/clear loopback before/after lpbk test
+ * @bdp: atapter's private data struct
+ * @set_loopback: true if the function is called to set lb
+ * @loopback_mode: the loopback mode(MAC or PHY)
+ * @tcb_extended: true if need to set extended tcb mode after clean loopback
+ * @dynamic_tbd: true if needed to set dynamic tbd mode after clean loopback
+ *
+ */
+void
+e100_diag_config_loopback(struct e100_private* bdp,
+			  u8 set_loopback,
+			  u8 loopback_mode,
+			  u8* tcb_extended,
+			  u8* dynamic_tbd)
+{
+	/* if set_loopback == true - we want to clear tcb_extended/dynamic_tbd.
+	 * the previous values are saved in the params tcb_extended/dynamic_tbd
+	 * if set_loopback == false - we want to restore previous value.
+	 */
+	if (set_loopback || (*tcb_extended))
+		  *tcb_extended = e100_config_tcb_ext_enable(bdp,*tcb_extended);
+
+	if (set_loopback || (*dynamic_tbd))
+		 *dynamic_tbd = e100_config_dynamic_tbd(bdp,*dynamic_tbd);
+
+	if (set_loopback) {
+		e100_config_loopback_mode(bdp,loopback_mode);
+	} else {
+		e100_config_loopback_mode(bdp,NO_LOOPBACK);
+	}
+
+	e100_config(bdp);
+
+	if (loopback_mode == PHY_LOOPBACK) {
+		unsigned long expires = jiffies + HZ * 5;
+
+		if (set_loopback)
+			e100_phy_reset(bdp);
+
+		/* wait up to 5 secs for PHY loopback ON/OFF to take effect */
+		while ((e100_get_link_state(bdp) != set_loopback) &&
+		       time_before(jiffies, expires)) {
+			yield();
+		}
+	} else { /* For MAC loopback wait 500 msec to take effect */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ / 2);
+	}
+}
+  
+/**
+ * e100_diag_loopback_alloc - alloc & initate tcb and rfd for the loopback
+ * @bdp: atapter's private data struct
+ *
+ */
+static u8
+e100_diag_loopback_alloc(struct e100_private *bdp)
+{
+	dma_addr_t dma_handle;
+	tcb_t *tcb;
+	rfd_t *rfd;
+	tbd_t *tbd;
+
+	tcb = pci_alloc_consistent(bdp->pdev,
+				   (sizeof (tcb_t) + sizeof (tbd_t) +
+				    LB_PACKET_SIZE),
+				   &dma_handle);
+        if (tcb == NULL)
+		return false;
+
+	memset(tcb, 0x00, sizeof (tcb_t) + LB_PACKET_SIZE);
+	tcb->tcb_phys = dma_handle;
+	tcb->tcb_hdr.cb_status = 0;
+	tcb->tcb_hdr.cb_cmd =
+		cpu_to_le16(CB_EL_BIT | CB_TRANSMIT | CB_TX_SF_BIT);
+	tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(tcb->tcb_phys);
+	tcb->tcb_tbd_ptr = cpu_to_le32(0xffffffff);
+	tcb->tcb_cnt = 0;
+	tcb->tcb_thrshld = bdp->tx_thld;
+	tcb->tcb_tbd_num = 1;
+	tcb->tcb_tbd_ptr = cpu_to_le32(tcb->tcb_phys + sizeof (tcb_t));
+	tbd = (tbd_t *) ((u8 *) tcb + sizeof (tcb_t));
+	tbd->tbd_buf_addr =
+		cpu_to_le32(le32_to_cpu(tcb->tcb_tbd_ptr) + sizeof (tbd_t));
+	tbd->tbd_buf_cnt = __constant_cpu_to_le16(1024);
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t)), 0xFF, 1024);
+	memset((void *) ((u8 *) tbd + sizeof (tbd_t) + 512), 0xBA, 512);
+	wmb();
+	rfd = pci_alloc_consistent(bdp->pdev, sizeof (rfd_t), &dma_handle);
+
+	if (rfd == NULL) {
+		pci_free_consistent(bdp->pdev,
+				    sizeof (tcb_t) + sizeof (tbd_t) +
+				    LB_PACKET_SIZE, tcb, tcb->tcb_phys);
+		return false;
+	}
+
+	memset(rfd, 0x00, sizeof (rfd_t));
+
+	/* init all fields in rfd */
+	rfd->rfd_header.cb_status = 0;
+	rfd->rfd_header.cb_cmd = cpu_to_le16(RFD_EL_BIT);
+	rfd->rfd_act_cnt = 0;
+	rfd->rfd_sz = cpu_to_le16(ETH_FRAME_LEN + CHKSUM_SIZE);
+	bdp->loopback.dma_handle = dma_handle;
+	bdp->loopback.tcb = tcb;
+	bdp->loopback.rfd = rfd;
+	wmb();
+	return true;
+}
+
+/**
+ * e100_diag_loopback_cu_ru_exec - activates cu and ru to send & receive the pkt
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_cu_ru_exec(struct e100_private *bdp)
+{
+	/*load CU & RU base */ 
+	if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE))
+		printk("@@@ SCB_CUC_LOAD_BASE failed\n");
+	if(!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE))
+		printk("@@@ SCB_RUC_LOAD_BASE failed!\n");
+	if(!e100_wait_exec_cmplx(bdp, bdp->loopback.dma_handle, SCB_RUC_START))
+		printk("@@@ SCB_RUC_START failed!\n");
+
+	bdp->next_cu_cmd = START_WAIT;
+	e100_start_cu(bdp, bdp->loopback.tcb);
+	bdp->last_tcb = NULL;
+	rmb();
+}
+/**
+ * e100_diag_check_pkt - checks if a given packet is a loopback packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_check_pkt(u8 *datap)
+{
+        if( (*datap)==0xFF) {
+                if(*(datap + 600) == 0xBA) {
+                        return true;
+                }
+        }
+        return false;
+}
+
+/**
+ * e100_diag_rcv_loopback_pkt - waits for receive and checks lpbk packet
+ * @bdp: atapter's private data struct
+ *
+ * Returns true if OK false otherwise.
+ */
+static u8
+e100_diag_rcv_loopback_pkt(struct e100_private* bdp) 
+{    
+	rfd_t *rfdp;
+	u16 rfd_status;
+	unsigned long expires = jiffies + HZ * 2;
+
+        rfdp =bdp->loopback.rfd;
+
+        rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+
+        while (!(rfd_status & RFD_STATUS_COMPLETE)) { 
+		if (time_before(jiffies, expires)) {
+			yield();
+			rmb();
+			rfd_status = le16_to_cpu(rfdp->rfd_header.cb_status);
+		} else {
+			break;
+		}
+        }
+
+        if (rfd_status & RFD_STATUS_COMPLETE)
+                return e100_diag_check_pkt(((u8 *)rfdp+bdp->rfd_size));
+	else
+		return false;
+}
+
+/**
+ * e100_diag_loopback_free - free data allocated for loopback pkt send/receive
+ * @bdp: atapter's private data struct
+ *
+ */
+static void
+e100_diag_loopback_free (struct e100_private *bdp)
+{
+        pci_free_consistent(bdp->pdev,
+			    sizeof(tcb_t) + sizeof(tbd_t) + LB_PACKET_SIZE,
+			    bdp->loopback.tcb, bdp->loopback.tcb->tcb_phys);
+
+        pci_free_consistent(bdp->pdev, sizeof(rfd_t), bdp->loopback.rfd,
+			    bdp->loopback.dma_handle);
+}
+
+#endif
+
+
+
+
+
+
+
+
diff -Nru a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE
--- a/drivers/net/e1000/LICENSE	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/e1000/LICENSE	Wed Apr  3 17:11:15 2002
@@ -1,8 +1,7 @@
 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:
+License 2.0, 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
@@ -16,7 +15,7 @@
 "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
+any operating system available under the GNU General Public License 2.0 or
 later.
 
 Copyright (c) 1999 - 2002 Intel Corporation.
@@ -49,10 +48,10 @@
 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
+General Public License 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
+available versions of such operating systems available under the GNU General
+Public License 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.
diff -Nru a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
--- a/drivers/net/e1000/Makefile	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/e1000/Makefile	Wed Apr  3 17:11:13 2002
@@ -9,8 +9,7 @@
 
 O_TARGET := e1000.o
 
-obj-y   := e1000_main.o e1000_mac.o e1000_phy.o \
-           e1000_ethtool.o e1000_param.o e1000_proc.o
+obj-y   := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o e1000_proc.o
 obj-m   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
--- a/drivers/net/e1000/e1000.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/e1000/e1000.h	Wed Apr  3 17:11:13 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
@@ -109,11 +108,14 @@
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <asm/uaccess.h>
+#include <linux/ethtool.h>
+#ifdef NETIF_F_HW_VLAN_TX
+#include <linux/if_vlan.h>
+#endif
 
 struct e1000_adapter;
 
-#include "e1000_mac.h"
-#include "e1000_phy.h"
+#include "e1000_hw.h"
 
 #define BAR_0 0
 
@@ -138,7 +140,9 @@
 #define E1000_RXBUFFER_16384 16384
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
-#define E1000_TX_QUEUE_WAKE 16
+#define E1000_TX_QUEUE_WAKE	16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE	16
 
 #define E1000_JUMBO_PBA      0x00000028
 #define E1000_DEFAULT_PBA    0x00000030
@@ -163,10 +167,6 @@
 	unsigned int size;
 	/* number of descriptors in the ring */
 	unsigned int count;
-	/* (atomic) number of desc with no buffer */
-	atomic_t unused;
-	/* number of desc with no buffer */
-	unsigned int unused_count;
 	/* next descriptor to associate a buffer with */
 	unsigned int next_to_use;
 	/* next descriptor to check for DD status bit */
@@ -175,14 +175,13 @@
 	struct e1000_buffer *buffer_info;
 };
 
-#define E1000_RX_DESC(ring, i) \
-	(&(((struct e1000_rx_desc *)((ring).desc))[i]))
-
-#define E1000_TX_DESC(ring, i) \
-	(&(((struct e1000_tx_desc *)((ring).desc))[i]))
+#define E1000_DESC_UNUSED(R) \
+((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
 
-#define E1000_CONTEXT_DESC(ring, i) \
-	(&(((struct e1000_context_desc *)((ring).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
 
 /* board specific private data structure */
 
@@ -192,6 +191,9 @@
 #ifdef CONFIG_PROC_FS
 	struct list_head proc_list_head;
 #endif
+#ifdef NETIF_F_HW_VLAN_TX
+	struct vlan_group *vlgrp;
+#endif
 	char *id_string;
 	uint32_t bd_number;
 	uint32_t rx_buffer_len;
@@ -201,28 +203,29 @@
 	uint16_t link_duplex;
 	spinlock_t stats_lock;
 	atomic_t irq_sem;
-	boolean_t rx_csum;
 
 	/* TX */
 	struct e1000_desc_ring tx_ring;
 	unsigned long trans_finish;
-	uint32_t tx_int_delay;
+	spinlock_t tx_lock;
 	uint32_t txd_cmd;
+	int max_data_per_txd;
 
 	/* RX */
 	struct e1000_desc_ring rx_ring;
 	uint64_t hw_csum_err;
 	uint64_t hw_csum_good;
 	uint32_t rx_int_delay;
+	boolean_t rx_csum;
 
 	/* OS defined structs */
 	struct net_device *netdev;
 	struct pci_dev *pdev;
 	struct net_device_stats net_stats;
 
-	/* structs defined in e1000_mac.h or e1000_phy.h */
-	struct e1000_shared_adapter shared;
-	struct e1000_shared_stats stats;
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+	struct e1000_hw_stats stats;
 	struct e1000_phy_info phy_info;
 	struct e1000_phy_stats phy_stats;
 };
diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
--- a/drivers/net/e1000/e1000_ethtool.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/e1000/e1000_ethtool.c	Wed Apr  3 17:11:15 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
@@ -89,9 +88,9 @@
 static void
 e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 
-	if(shared->media_type == e1000_media_type_copper) {
+	if(hw->media_type == e1000_media_type_copper) {
 
 		ecmd->supported = (SUPPORTED_10baseT_Half |
 		                   SUPPORTED_10baseT_Full |
@@ -103,18 +102,18 @@
 
 		ecmd->advertising = ADVERTISED_TP;
 
-		if(shared->autoneg == 1) {
+		if(hw->autoneg == 1) {
 			ecmd->advertising |= ADVERTISED_Autoneg;
 
 			/* the e1000 autoneg seems to match ethtool nicely */
 
-			ecmd->advertising |= shared->autoneg_advertised;
+			ecmd->advertising |= hw->autoneg_advertised;
 		}
 
 		ecmd->port = PORT_TP;
-		ecmd->phy_address = shared->phy_addr;
+		ecmd->phy_address = hw->phy_addr;
 
-		if(shared->mac_type == e1000_82543)
+		if(hw->mac_type == e1000_82543)
 			ecmd->transceiver = XCVR_EXTERNAL;
 		else
 			ecmd->transceiver = XCVR_INTERNAL;
@@ -129,13 +128,12 @@
 				     SUPPORTED_Autoneg);
 
 		ecmd->port = PORT_FIBRE;
-
 		ecmd->transceiver = XCVR_EXTERNAL;
 	}
 
 	if(netif_carrier_ok(adapter->netdev)) {
 
-		e1000_get_speed_and_duplex(shared, &adapter->link_speed,
+		e1000_get_speed_and_duplex(hw, &adapter->link_speed,
 		                                   &adapter->link_duplex);
 		ecmd->speed = adapter->link_speed;
 
@@ -151,37 +149,35 @@
 		ecmd->duplex = -1;
 	}
 
-	ecmd->autoneg = (shared->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
-
-	return;
+	ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
 }
 
 static int
 e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 
 	if(ecmd->autoneg == AUTONEG_ENABLE) {
-		shared->autoneg = 1;
-		shared->autoneg_advertised = (ecmd->advertising & 0x002F);
+		hw->autoneg = 1;
+		hw->autoneg_advertised = (ecmd->advertising & 0x002F);
 	} else {
-		shared->autoneg = 0;
+		hw->autoneg = 0;
 		switch(ecmd->speed + ecmd->duplex) {
 		case SPEED_10 + DUPLEX_HALF:
-			shared->forced_speed_duplex = e1000_10_half;
+			hw->forced_speed_duplex = e1000_10_half;
 			break;
 		case SPEED_10 + DUPLEX_FULL:
-			shared->forced_speed_duplex = e1000_10_full;
+			hw->forced_speed_duplex = e1000_10_full;
 			break;
 		case SPEED_100 + DUPLEX_HALF:
-			shared->forced_speed_duplex = e1000_100_half;
+			hw->forced_speed_duplex = e1000_100_half;
 			break;
 		case SPEED_100 + DUPLEX_FULL:
-			shared->forced_speed_duplex = e1000_100_full;
+			hw->forced_speed_duplex = e1000_100_full;
 			break;
 		case SPEED_1000 + DUPLEX_FULL:
-			shared->autoneg = 1;
-			shared->autoneg_advertised = ADVERTISE_1000_FULL;
+			hw->autoneg = 1;
+			hw->autoneg_advertised = ADVERTISE_1000_FULL;
 			break;
 		case SPEED_1000 + DUPLEX_HALF: /* not supported */
 		default:
@@ -198,9 +194,13 @@
 }
 
 static inline int
-e1000_eeprom_size(struct e1000_shared_adapter *shared)
+e1000_eeprom_size(struct e1000_hw *hw)
 {
-	return 128;
+	if((hw->mac_type > e1000_82544) &&
+	   (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
+		return 512;
+	else
+		return 128;
 }
 
 static void
@@ -211,36 +211,33 @@
 	strncpy(drvinfo->version, e1000_driver_version, 32);
 	strncpy(drvinfo->fw_version, "", 32);
 	strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
-	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->shared);
-	return;
+	drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
 }
 
 static void
 e1000_ethtool_geeprom(struct e1000_adapter *adapter,
                       struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	int i, max_len;
 
-	eeprom->magic = shared->vendor_id | (shared->device_id << 16);
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
-	max_len = e1000_eeprom_size(shared);
+	max_len = e1000_eeprom_size(hw);
 
 	if ((eeprom->offset + eeprom->len) > max_len)
 		eeprom->len = (max_len - eeprom->offset);
 
 	for(i = 0; i < max_len; i++)
-		eeprom_buff[i] = e1000_read_eeprom(&adapter->shared, i);
-
-	return;
+		e1000_read_eeprom(&adapter->hw, i, &eeprom_buff[i]);
 }
 
 static void
 e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	
-	if(shared->mac_type < e1000_82544) {
+	if(hw->mac_type < e1000_82544) {
 		wol->supported = 0;
 		wol->wolopts   = 0;
 		return;
@@ -260,17 +257,15 @@
 		wol->wolopts |= WAKE_BCAST;
 	if(adapter->wol & E1000_WUFC_MAG)
 		wol->wolopts |= WAKE_MAGIC;
-
-	return;
 }
 
 static int
 e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 
-	if(shared->mac_type < e1000_82544)
-		return wol->wolopts == 0 ? 0 : -EOPNOTSUPP;
+	if(hw->mac_type < e1000_82544)
+		return wol->wolopts ? -EOPNOTSUPP : 0;
 
 	adapter->wol = 0;
 
diff -Nru a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/e1000/e1000_hw.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,3228 @@
+/*******************************************************************************
+
+  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 2.0, 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/1000 Family of Adapters (e1000) (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 General Public License 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
+  General Public License 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 General
+  Public License 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.
+
+*******************************************************************************/
+
+/* e1000_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include "e1000_hw.h"
+
+static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
+static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
+static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
+static void e1000_setup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
+
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+    uint32_t icr;
+    uint32_t manc;
+    uint16_t pci_cmd_word;
+
+    DEBUGFUNC("e1000_reset_hw");
+    
+    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+            pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+            e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+        }
+    }
+
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Disable the Transmit and Receive units.  Then delay to allow
+     * any pending transactions to complete before we hit the MAC with
+     * the global reset.
+     */
+    E1000_WRITE_REG(hw, RCTL, 0);
+    E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+
+    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+    hw->tbi_compatibility_on = FALSE;
+
+    /* Delay to allow any outstanding PCI transactions to complete before
+     * resetting the device
+     */ 
+    msec_delay(10);
+
+    /* Issue a global reset to the MAC.  This will reset the chip's
+     * transmit, receive, DMA, and link units.  It will not effect
+     * the current PCI configuration.  The global reset bit is self-
+     * clearing, and should clear within a microsecond.
+     */
+    DEBUGOUT("Issuing a global reset to MAC\n");
+    ctrl = E1000_READ_REG(hw, CTRL);
+    E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+    /* Force a reload from the EEPROM if necessary */
+    if(hw->mac_type < e1000_82540) {
+        /* Wait for reset to complete */
+        usec_delay(10);
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        /* Wait for EEPROM reload */
+        msec_delay(2);
+    } else {
+        /* Wait for EEPROM reload (it happens automatically) */
+        msec_delay(4);
+        /* Dissable HW ARPs on ASF enabled adapters */
+        manc = E1000_READ_REG(hw, MANC);
+        manc &= ~(E1000_MANC_ARP_EN);
+        E1000_WRITE_REG(hw, MANC, manc);
+    }
+    
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Clear any pending interrupt events. */
+    icr = E1000_READ_REG(hw, ICR);
+
+    /* If MWI was previously enabled, reenable it. */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+    }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Assumes that the controller has previously been reset and is in a 
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+e1000_init_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl, status;
+    uint32_t i;
+    int32_t ret_val;
+    uint16_t pci_cmd_word;
+
+    DEBUGFUNC("e1000_init_hw");
+
+    /* Set the Media Type and exit with error if it is not valid. */
+    if(hw->mac_type != e1000_82543) {
+        /* tbi_compatibility is only valid on 82543 */
+        hw->tbi_compatibility_en = FALSE;
+    }
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_TBIMODE) {
+            hw->media_type = e1000_media_type_fiber;
+            /* tbi_compatibility not valid on fiber */
+            hw->tbi_compatibility_en = FALSE;
+        } else {
+            hw->media_type = e1000_media_type_copper;
+        }
+    } else {
+        /* This is an 82542 (fiber only) */
+        hw->media_type = e1000_media_type_fiber;
+    }
+
+    /* Disabling VLAN filtering. */
+    DEBUGOUT("Initializing the IEEE VLAN\n");
+    E1000_WRITE_REG(hw, VET, 0);
+
+    e1000_clear_vfta(hw);
+
+    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
+            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+            pci_cmd_word = hw->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
+            e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &pci_cmd_word);
+        }
+        E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+        msec_delay(5);
+    }
+
+    /* Setup the receive address. This involves initializing all of the Receive
+     * Address Registers (RARs 0 - 15).
+     */
+    e1000_init_rx_addrs(hw);
+
+    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        E1000_WRITE_REG(hw, RCTL, 0);
+        msec_delay(1);
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_write_pci_cfg(hw, PCI_COMMAND_REGISTER, &hw->pci_cmd_word);
+    }
+
+    /* Zero out the Multicast HASH table */
+    DEBUGOUT("Zeroing the MTA\n");
+    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+    /* Set the PCI priority bit correctly in the CTRL register.  This
+     * determines if the adapter gives priority to receives, or if it
+     * gives equal priority to transmits and receives.
+     */
+    if(hw->dma_fairness) {
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+    }
+
+    /* Call a subroutine to configure the link and setup flow control. */
+    ret_val = e1000_setup_link(hw);
+
+    /* Clear all of the statistics registers (clear on read).  It is
+     * important that we do this after we have tried to establish link
+     * because the symbol error count will increment wildly if there
+     * is no link.
+     */
+    e1000_clear_hw_cntrs(hw);
+
+    return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the 
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+e1000_setup_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl_ext;
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_setup_link");
+
+    /* Read and store word 0x0F of the EEPROM. This word contains bits
+     * that determine the hardware's default PAUSE (flow control) mode,
+     * a bit that determines whether the HW defaults to enabling or
+     * disabling auto-negotiation, and the direction of the
+     * SW defined pins. If there is no SW over-ride of the flow
+     * control setting, then the variable hw->fc will
+     * be initialized based on a value in the EEPROM.
+     */
+    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    if(hw->fc == e1000_fc_default) {
+        if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+            hw->fc = e1000_fc_none;
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 
+                EEPROM_WORD0F_ASM_DIR)
+            hw->fc = e1000_fc_tx_pause;
+        else
+            hw->fc = e1000_fc_full;
+    }
+
+    /* We want to save off the original Flow Control configuration just
+     * in case we get disconnected and then reconnected into a different
+     * hub or switch with different Flow Control capabilities.
+     */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        hw->fc &= (~e1000_fc_tx_pause);
+
+    if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+        hw->fc &= (~e1000_fc_rx_pause);
+
+    hw->original_fc = hw->fc;
+
+    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+    /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+     * polarity value for the SW controlled pins, and setup the
+     * Extended Device Control reg with that info.
+     * This is needed because one of the SW controlled pins is used for
+     * signal detection.  So this should be done before e1000_setup_pcs_link()
+     * or e1000_phy_setup() is called.
+     */
+    if(hw->mac_type == e1000_82543) {
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << 
+                    SWDPIO__EXT_SHIFT);
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+
+    /* Call the necessary subroutine to configure the link. */
+    ret_val = (hw->media_type == e1000_media_type_fiber) ?
+              e1000_setup_fiber_link(hw) :
+              e1000_setup_copper_link(hw);
+
+    /* Initialize the flow control address, type, and PAUSE timer
+     * registers to their default values.  This is done even if flow
+     * control is disabled, because it does not hurt anything to
+     * initialize these registers.
+     */
+    DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+    E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+    E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+    E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+    E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+    /* Set the flow control receive threshold registers.  Normally,
+     * these registers will be set to a default threshold that may be
+     * adjusted later by the driver's runtime code.  However, if the
+     * ability to transmit pause frames in not enabled, then these
+     * registers will be set to 0. 
+     */
+    if(!(hw->fc & e1000_fc_tx_pause)) {
+        E1000_WRITE_REG(hw, FCRTL, 0);
+        E1000_WRITE_REG(hw, FCRTH, 0);
+    } else {
+        /* We need to set up the Receive Threshold high and low water marks
+         * as well as (optionally) enabling the transmission of XON frames.
+         */
+        if(hw->fc_send_xon) {
+            E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        } else {
+            E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        }
+    }
+    return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ * ctrl - Current value of the device control register
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t 
+e1000_setup_fiber_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t txcw = 0;
+    uint32_t i;
+    uint32_t signal;
+    int32_t ret_val;
+
+    DEBUGFUNC("e1000_setup_fiber_link");
+
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+   
+    /* Take the link out of reset */
+    ctrl &= ~(E1000_CTRL_LRST);
+    
+    e1000_config_collision_dist(hw);
+
+    /* Check for a software override of the flow control settings, and setup
+     * the device accordingly.  If auto-negotiation is enabled, then software
+     * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+     * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
+     * auto-negotiation is disabled, then software will have to manually 
+     * configure the two flow control enable bits in the CTRL register.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames, but 
+     *          not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames but we do
+     *          not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none:
+        /* Flow control is completely disabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+        break;
+    case e1000_fc_rx_pause:
+        /* RX Flow control is enabled and TX Flow control is disabled by a 
+         * software over-ride. Since there really isn't a way to advertise 
+         * that we are capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE. Later, we will
+         *  disable the adapter's ability to send PAUSE frames.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    case e1000_fc_tx_pause:
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a 
+         * software over-ride.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+        break;
+    case e1000_fc_full:
+        /* Flow control (both RX and TX) is enabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+        break;
+    }
+
+    /* Since auto-negotiation is enabled, take the link out of reset (the link
+     * will be in reset, because we previously reset the chip). This will
+     * restart auto-negotiation.  If auto-neogtiation is successful then the
+     * link-up status bit will be set and the flow control enable bits (RFCE
+     * and TFCE) will be set according to their negotiated value.
+     */
+    DEBUGOUT("Auto-negotiation enabled\n");
+
+    E1000_WRITE_REG(hw, TXCW, txcw);
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    hw->txcw = txcw;
+    msec_delay(1);
+
+    /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+     * indication in the Device Status Register.  Time-out if a link isn't 
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in 
+     * less than 500 milliseconds even if the other end is doing it in SW).
+     */
+    if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+        DEBUGOUT("Looking for Link\n");
+        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+            msec_delay(10);
+            status = E1000_READ_REG(hw, STATUS);
+            if(status & E1000_STATUS_LU) break;
+        }
+        if(i == (LINK_UP_TIMEOUT / 10)) {
+            /* AutoNeg failed to achieve a link, so we'll call 
+             * e1000_check_for_link. This routine will force the link up if we
+             * detect a signal. This will allow us to communicate with
+             * non-autonegotiating link partners.
+             */
+            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+            hw->autoneg_failed = 1;
+            ret_val = e1000_check_for_link(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while checking for link\n");
+                return ret_val;
+            }
+            hw->autoneg_failed = 0;
+        } else {
+            hw->autoneg_failed = 0;
+            DEBUGOUT("Valid Link Found\n");
+        }
+    } else {
+        DEBUGOUT("No Signal Detected\n");
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - current value of the device control register
+******************************************************************************/
+static int32_t 
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_setup_copper_link");
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    /* With 82543, we need to force speed and duplex on the MAC equal to what
+     * the PHY speed and duplex configuration is. In addition, we need to
+     * perform a hardware reset on the PHY to take it out of reset.
+     */
+    if(hw->mac_type > e1000_82543) {
+        ctrl |= E1000_CTRL_SLU;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+    } else {
+        ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        e1000_phy_hw_reset(hw);
+    }
+
+    /* Make sure we have a valid PHY */
+    ret_val = e1000_detect_gig_phy(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error, did not detect valid phy.\n");
+        return ret_val;
+    }
+    DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+    /* Options:
+     *   MDI/MDI-X = 0 (default)
+     *   0 - Auto for all speeds
+     *   1 - MDI mode
+     *   2 - MDI-X mode
+     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+    switch (hw->mdix) {
+    case 1:
+        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+        break;
+    case 2:
+        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+        break;
+    case 3:
+        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+        break;
+    case 0:
+    default:
+        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+        break;
+    }
+
+    /* Options:
+     *   disable_polarity_correction = 0 (default)
+     *       Automatic Correction for Reversed Cable Polarity
+     *   0 - Disabled
+     *   1 - Enabled
+     */
+    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+    if(hw->disable_polarity_correction == 1)
+        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+    /* Configure Master and Slave downshift values */
+    phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                  M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+    phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                 M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = e1000_phy_reset(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+    
+    /* Options:
+     *   autoneg = 1 (default)
+     *      PHY will advertise value(s) parsed from
+     *      autoneg_advertised and fc
+     *   autoneg = 0
+     *      PHY will be set to 10H, 10F, 100H, or 100F
+     *      depending on value parsed from forced_speed_duplex.
+     */
+
+    /* Is autoneg enabled?  This is enabled by default or by software override.
+     * If so, call e1000_phy_setup_autoneg routine to parse the
+     * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+     * user should have provided a speed/duplex override.  If so, then call
+     * e1000_phy_force_speed_duplex to parse and set this up.
+     */
+    if(hw->autoneg) {
+        /* Perform some bounds checking on the hw->autoneg_advertised
+         * parameter.  If this variable is zero, then set it to the default.
+         */
+        hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        /* If autoneg_advertised is zero, we assume it was not defaulted
+         * by the calling code so we set to advertise full capability.
+         */
+        if(hw->autoneg_advertised == 0)
+            hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+        ret_val = e1000_phy_setup_autoneg(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Setting up Auto-Negotiation\n");
+            return ret_val;
+        }
+        DEBUGOUT("Restarting Auto-Neg\n");
+
+        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+         * the Auto Neg Restart bit in the PHY control register.
+         */
+        if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+        if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Does the user want to wait for Auto-Neg to complete here, or
+         * check at a later time (for example, callback routine).
+         */
+        if(hw->wait_autoneg_complete) {
+            ret_val = e1000_wait_autoneg(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while waiting for autoneg to complete\n");
+                return ret_val;
+            }
+        }
+    } else {
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = e1000_phy_force_speed_duplex(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Forcing Speed and Duplex\n");
+            return ret_val;
+        }
+    }
+
+    /* Check link status. Wait up to 100 microseconds for link to become
+     * valid.
+     */
+    for(i = 0; i < 10; i++) {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* We have link, so we need to finish the config process:
+             *   1) Set up the MAC to the current PHY speed/duplex
+             *      if we are on 82543.  If we
+             *      are on newer silicon, we only need to configure
+             *      collision distance in the Transmit Control Register.
+             *   2) Set up flow control on the MAC to that established with
+             *      the link partner.
+             */
+            if(hw->mac_type >= e1000_82544) {
+                e1000_config_collision_dist(hw);
+            } else {
+                ret_val = e1000_config_mac_to_phy(hw);
+                if(ret_val < 0) {
+                    DEBUGOUT("Error configuring MAC to PHY settings\n");
+                    return ret_val;
+                  }
+            }
+            ret_val = e1000_config_fc_after_link_up(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Configuring Flow Control\n");
+                return ret_val;
+            }
+            DEBUGOUT("Valid link established!!!\n");
+            return 0;
+        }
+        usec_delay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return 0;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+    uint16_t mii_autoneg_adv_reg;
+    uint16_t mii_1000t_ctrl_reg;
+
+    DEBUGFUNC("e1000_phy_setup_autoneg");
+
+    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+    if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Read the MII 1000Base-T Control Register (Address 9). */
+    if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Need to parse both autoneg_advertised and fc and set up
+     * the appropriate PHY registers.  First we will parse for
+     * autoneg_advertised software override.  Since we can advertise
+     * a plethora of combinations, we need to check each bit
+     * individually.
+     */
+
+    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+     * Advertisement Register (Address 4) and the 1000 mb speed bits in
+     * the  1000Base-T Control Register (Address 9).
+     */
+    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+    /* Do we want to advertise 10 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+        DEBUGOUT("Advertise 10mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+    }
+
+    /* Do we want to advertise 10 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+        DEBUGOUT("Advertise 10mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+        DEBUGOUT("Advertise 100mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+        DEBUGOUT("Advertise 100mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+    }
+
+    /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+    if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+    }
+
+    /* Do we want to advertise 1000 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+        DEBUGOUT("Advertise 1000mb Full duplex\n");
+        mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+    }
+
+    /* Check for a software override of the flow control settings, and
+     * setup the PHY advertisement registers accordingly.  If
+     * auto-negotiation is enabled, then software will have to set the
+     * "PAUSE" bits to the correct value in the Auto-Negotiation
+     * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames
+     *          but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          but we do not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     *  other:  No software override.  The flow control configuration
+     *          in the EEPROM is used.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none: /* 0 */
+        /* Flow control (RX & TX) is completely disabled by a
+         * software over-ride.
+         */
+        mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_rx_pause: /* 1 */
+        /* RX Flow control is enabled, and TX Flow control is
+         * disabled, by a software over-ride.
+         */
+        /* Since there really isn't a way to advertise that we are
+         * capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE.  Later
+         * (in e1000_config_fc_after_link_up) we will disable the
+         *hw's ability to send PAUSE frames.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_tx_pause: /* 2 */
+        /* TX Flow control is enabled, and RX Flow control is
+         * disabled, by a software over-ride.
+         */
+        mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+        mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+        break;
+    case e1000_fc_full: /* 3 */
+        /* Flow control (both RX and TX) is enabled by a software
+         * over-ride.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if(e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+    if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t mii_ctrl_reg;
+    uint16_t mii_status_reg;
+    uint16_t phy_data;
+    uint16_t i;
+
+    DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+    /* Turn off Flow control if we are forcing speed and duplex. */
+    hw->fc = e1000_fc_none;
+
+    DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+    /* Read the Device Control Register. */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(DEVICE_SPEED_MASK);
+
+    /* Clear the Auto Speed Detect Enable bit. */
+    ctrl &= ~E1000_CTRL_ASDE;
+
+    /* Read the MII Control Register. */
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* We need to disable autoneg in order to force link and duplex. */
+
+    mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+    /* Are we forcing Full or Half Duplex? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_10_full) {
+        /* We want to force full duplex so we SET the full duplex bits in the
+         * Device and MII Control Registers.
+         */
+        ctrl |= E1000_CTRL_FD;
+        mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Full Duplex\n");
+    } else {
+        /* We want to force half duplex so we CLEAR the full duplex bits in
+         * the Device and MII Control Registers.
+         */
+        ctrl &= ~E1000_CTRL_FD;
+        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Half Duplex\n");
+    }
+
+    /* Are we forcing 100Mbps??? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_100_half) {
+        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+        ctrl |= E1000_CTRL_SPD_100;
+        mii_ctrl_reg |= MII_CR_SPEED_100;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+        DEBUGOUT("Forcing 100mb ");
+    } else {
+        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+        ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+        mii_ctrl_reg |= MII_CR_SPEED_10;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+        DEBUGOUT("Forcing 10mb ");
+    }
+
+    e1000_config_collision_dist(hw);
+
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    /* Write the MII Control Register with the new PHY configuration. */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+     * forced whenever speed are duplex are forced.
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+    
+    /* Need to reset the PHY or these changes will be ignored */
+    mii_ctrl_reg |= MII_CR_RESET;
+    if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    usec_delay(1);
+
+    /* The wait_autoneg_complete flag may be a little misleading here.
+     * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+     * But we do want to delay for a period while forcing only so we
+     * don't generate false No Link messages.  So we will wait here
+     * only if the user has set wait_autoneg_complete to 1, which is
+     * the default.
+     */
+    if(hw->wait_autoneg_complete) {
+        /* We will wait for autoneg to complete. */
+        DEBUGOUT("Waiting for forced speed/duplex link.\n");
+        mii_status_reg = 0;
+
+        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+        }
+        if(i == 0) { /* We didn't get link */
+            /* Reset the DSP and wait again for link. */
+            
+            ret_val = e1000_phy_reset_dsp(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Resetting PHY DSP\n");
+                return ret_val;
+            }
+        }
+        /* This loop will early-out if the link condition has been met.  */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
+    }
+    
+    /* Because we reset the PHY above, we need to re-force TX_CLK in the
+     * Extended PHY Specific Control Register to 25MHz clock.  This value
+     * defaults back to a 2.5MHz clock when the PHY is reset.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* In addition, because of the s/w reset above, we need to enable CRS on
+     * TX.  This must be set for both full and half duplex operation.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+    uint32_t tctl;
+
+    tctl = E1000_READ_REG(hw, TCTL);
+
+    tctl &= ~E1000_TCTL_COLD;
+    tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+    E1000_WRITE_REG(hw, TCTL, tctl);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_config_mac_to_phy");
+
+    /* Read the Device Control Register and set the bits to Force Speed
+     * and Duplex.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+    /* Set up duplex in the Device Control and Transmit Control
+     * registers depending on negotiated values.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+    else ctrl &= ~E1000_CTRL_FD;
+
+    e1000_config_collision_dist(hw);
+
+    /* Set up speed in the Device Control register depending on
+     * negotiated values.
+     */
+    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+        ctrl |= E1000_CTRL_SPD_1000;
+    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+        ctrl |= E1000_CTRL_SPD_100;
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int32_t
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_force_mac_fc");
+
+    /* Get the current configuration of the Device Control Register */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Because we didn't get link via the internal auto-negotiation
+     * mechanism (we either forced link or we got link via PHY
+     * auto-neg), we have to manually enable/disable transmit an
+     * receive flow control.
+     *
+     * The "Case" statement below enables/disable flow control
+     * according to the "hw->fc" parameter.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause
+     *          frames but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          frames but we do not receive pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) is enabled.
+     *  other:  No other values should be possible at this point.
+     */
+
+    switch (hw->fc) {
+    case e1000_fc_none:
+        ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+        break;
+    case e1000_fc_rx_pause:
+        ctrl &= (~E1000_CTRL_TFCE);
+        ctrl |= E1000_CTRL_RFCE;
+        break;
+    case e1000_fc_tx_pause:
+        ctrl &= (~E1000_CTRL_RFCE);
+        ctrl |= E1000_CTRL_TFCE;
+        break;
+    case e1000_fc_full:
+        ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    /* Disable TX Flow Control for 82542 (rev 2.0) */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        ctrl &= (~E1000_CTRL_TFCE);
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t mii_nway_adv_reg;
+    uint16_t mii_nway_lp_ability_reg;
+    uint16_t speed;
+    uint16_t duplex;
+
+    DEBUGFUNC("e1000_config_fc_after_link_up");
+
+    /* Check for the case where we have fiber media and auto-neg failed
+     * so we had to force link.  In this case, we need to force the
+     * configuration of the MAC to match the "fc" parameter.
+     */
+    if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+       ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+        ret_val = e1000_force_mac_fc(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error forcing flow control settings\n");
+            return ret_val;
+        }
+    }
+
+    /* Check for the case where we have copper media and auto-neg is
+     * enabled.  In this case, we need to check and see if Auto-Neg
+     * has completed, and if so, how the PHY and link partner has
+     * flow control configured.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+        /* Read the MII Status Register and check to see if AutoNeg
+         * has completed.  We read this twice because this reg has
+         * some "sticky" (latched) bits.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+            /* The AutoNeg process has completed, so we now need to
+             * read both the Auto Negotiation Advertisement Register
+             * (Address 4) and the Auto_Negotiation Base Page Ability
+             * Register (Address 5) to determine how flow control was
+             * negotiated.
+             */
+            if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+
+            /* Two bits in the Auto Negotiation Advertisement Register
+             * (Address 4) and two bits in the Auto Negotiation Base
+             * Page Ability Register (Address 5) determine flow control
+             * for both the PHY and the link partner.  The following
+             * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+             * 1999, describes these PAUSE resolution bits and how flow
+             * control is determined based upon these settings.
+             * NOTE:  DC = Don't Care
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+             *-------|---------|-------|---------|--------------------
+             *   0   |    0    |  DC   |   DC    | e1000_fc_none
+             *   0   |    1    |   0   |   DC    | e1000_fc_none
+             *   0   |    1    |   1   |    0    | e1000_fc_none
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *   1   |    0    |   0   |   DC    | e1000_fc_none
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *   1   |    1    |   0   |    0    | e1000_fc_none
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            /* Are both PAUSE bits set to 1?  If so, this implies
+             * Symmetric Flow Control is enabled at both ends.  The
+             * ASM_DIR bits are irrelevant per the spec.
+             *
+             * For Symmetric Flow Control:
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *
+             */
+            if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+               (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+                /* Now we need to check if the user selected RX ONLY
+                 * of pause frames.  In this case, we had to advertise
+                 * FULL flow control because we could not advertise RX
+                 * ONLY. Hence, we must now check to see if we need to
+                 * turn OFF  the TRANSMISSION of PAUSE frames.
+                 */
+                if(hw->original_fc == e1000_fc_full) {
+                    hw->fc = e1000_fc_full;
+                    DEBUGOUT("Flow Control = FULL.\r\n");
+                } else {
+                    hw->fc = e1000_fc_rx_pause;
+                    DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+                }
+            }
+            /* For receiving PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *
+             */
+            else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_tx_pause;
+                DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+            }
+            /* For transmitting PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+            /* Per the IEEE spec, at this point flow control should be
+             * disabled.  However, we want to consider that we could
+             * be connected to a legacy switch that doesn't advertise
+             * desired flow control, but can be forced on the link
+             * partner.  So if we advertised no flow control, that is
+             * what we will resolve to.  If we advertised some kind of
+             * receive capability (Rx Pause Only or Full Flow Control)
+             * and the link partner advertised none, we will configure
+             * ourselves to enable Rx Flow Control only.  We can do
+             * this safely for two reasons:  If the link partner really
+             * didn't want flow control enabled, and we enable Rx, no
+             * harm done since we won't be receiving any PAUSE frames
+             * anyway.  If the intent on the link partner was to have
+             * flow control enabled, then by us enabling RX only, we
+             * can at least receive pause frames and process them.
+             * This is a good idea because in most cases, since we are
+             * predominantly a server NIC, more times than not we will
+             * be asked to delay transmission of packets than asking
+             * our link partner to pause transmission of frames.
+             */
+            else if(hw->original_fc == e1000_fc_none ||
+                    hw->original_fc == e1000_fc_tx_pause) {
+                hw->fc = e1000_fc_none;
+                DEBUGOUT("Flow Control = NONE.\r\n");
+            } else {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+
+            /* Now we need to do one last check...  If we auto-
+             * negotiated to HALF DUPLEX, flow control should not be
+             * enabled per IEEE 802.3 spec.
+             */
+            e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+            if(duplex == HALF_DUPLEX)
+                hw->fc = e1000_fc_none;
+
+            /* Now we call a subroutine to actually force the MAC
+             * controller to use the correct flow control settings.
+             */
+            ret_val = e1000_force_mac_fc(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error forcing flow control settings\n");
+                return ret_val;
+             }
+        } else {
+            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+        }
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+e1000_check_for_link(struct e1000_hw *hw)
+{
+    uint32_t rxcw;
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t rctl;
+    uint32_t signal;
+    int32_t ret_val;
+    uint16_t phy_data;
+    uint16_t lp_capability;
+
+    DEBUGFUNC("e1000_check_for_link");
+    
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    status = E1000_READ_REG(hw, STATUS);
+    rxcw = E1000_READ_REG(hw, RXCW);
+
+    /* If we have a copper PHY then we only want to go out to the PHY
+     * registers to see if Auto-Neg has completed and/or if our link
+     * status has changed.  The get_link_status flag will be set if we
+     * receive a Link Status Change interrupt or we have Rx Sequence
+     * Errors.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+        /* First we want to see if the MII Status Register reports
+         * link.  If so, then we want to get the current speed/duplex
+         * of the PHY.
+         * Read the register twice since the link bit is sticky.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            hw->get_link_status = FALSE;
+        } else {
+            /* No link detected */
+            return 0;
+        }
+
+        /* If we are forcing speed/duplex, then we simply return since
+         * we have already determined whether we have link or not.
+         */
+        if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+        /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+         * have Si on board that is 82544 or newer, Auto
+         * Speed Detection takes care of MAC speed/duplex
+         * configuration.  So we only need to configure Collision
+         * Distance in the MAC.  Otherwise, we need to force
+         * speed/duplex on the MAC to the current PHY speed/duplex
+         * settings.
+         */
+        if(hw->mac_type >= e1000_82544)
+            e1000_config_collision_dist(hw);
+        else {
+            ret_val = e1000_config_mac_to_phy(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error configuring MAC to PHY settings\n");
+                return ret_val;
+            }
+        }
+
+        /* Configure Flow Control now that Auto-Neg has completed. First, we 
+         * need to restore the desired flow control settings because we may
+         * have had to re-autoneg with a different link partner.
+         */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+
+        /* At this point we know that we are on copper and we have
+         * auto-negotiated link.  These are conditions for checking the link
+         * parter capability register.  We use the link partner capability to
+         * determine if TBI Compatibility needs to be turned on or off.  If
+         * the link partner advertises any speed in addition to Gigabit, then
+         * we assume that they are GMII-based, and TBI compatibility is not
+         * needed. If no other speeds are advertised, we assume the link
+         * partner is TBI-based, and we turn on TBI Compatibility.
+         */
+        if(hw->tbi_compatibility_en) {
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+                                NWAY_LPAR_10T_FD_CAPS |
+                                NWAY_LPAR_100TX_HD_CAPS |
+                                NWAY_LPAR_100TX_FD_CAPS |
+                                NWAY_LPAR_100T4_CAPS)) {
+                /* If our link partner advertises anything in addition to 
+                 * gigabit, we do not need to enable TBI compatibility.
+                 */
+                if(hw->tbi_compatibility_on) {
+                    /* If we previously were in the mode, turn it off. */
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl &= ~E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                    hw->tbi_compatibility_on = FALSE;
+                }
+            } else {
+                /* If TBI compatibility is was previously off, turn it on. For
+                 * compatibility with a TBI link partner, we will store bad
+                 * packets. Some frames have an additional byte on the end and
+                 * will look like CRC errors to to the hardware.
+                 */
+                if(!hw->tbi_compatibility_on) {
+                    hw->tbi_compatibility_on = TRUE;
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl |= E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                }
+            }
+        }
+    }
+    /* If we don't have link (auto-negotiation failed or link partner cannot
+     * auto-negotiate), the cable is plugged in (we have signal), and our
+     * link partner is not trying to auto-negotiate with us (we are receiving
+     * idles or data), we need to force link up. We also need to give
+     * auto-negotiation time to complete, in case the cable was just plugged
+     * in. The autoneg_failed flag does this.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+            (!(status & E1000_STATUS_LU)) &&
+            ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+            (!(rxcw & E1000_RXCW_C))) {
+        if(hw->autoneg_failed == 0) {
+            hw->autoneg_failed = 1;
+            return 0;
+        }
+        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+        /* Disable auto-negotiation in the TXCW register */
+        E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+        /* Force link-up and also force full-duplex. */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+
+        /* Configure Flow Control after forcing link up. */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+    }
+    /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+     * auto-negotiation in the TXCW register and disable forced link in the
+     * Device Control register in an attempt to auto-negotiate with our link
+     * partner.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+              (ctrl & E1000_CTRL_SLU) &&
+              (rxcw & E1000_RXCW_C)) {
+        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+        E1000_WRITE_REG(hw, TXCW, hw->txcw);
+        E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+                           uint16_t *speed,
+                           uint16_t *duplex)
+{
+    uint32_t status;
+
+    DEBUGFUNC("e1000_get_speed_and_duplex");
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_SPEED_1000) {
+            *speed = SPEED_1000;
+            DEBUGOUT("1000 Mbs, ");
+        } else if(status & E1000_STATUS_SPEED_100) {
+            *speed = SPEED_100;
+            DEBUGOUT("100 Mbs, ");
+        } else {
+            *speed = SPEED_10;
+            DEBUGOUT("10 Mbs, ");
+        }
+
+        if(status & E1000_STATUS_FD) {
+            *duplex = FULL_DUPLEX;
+            DEBUGOUT("Full Duplex\r\n");
+        } else {
+            *duplex = HALF_DUPLEX;
+            DEBUGOUT(" Half Duplex\r\n");
+        }
+    } else {
+        DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+        *speed = SPEED_1000;
+        *duplex = FULL_DUPLEX;
+    }
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_wait_autoneg");
+    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+    /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+    for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Auto-Neg
+         * Complete bit to be set.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+            return 0;
+        }
+        msec_delay(100);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Raise the clock input to the Management Data Clock (by setting the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+    usec_delay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Lower the clock input to the Management Data Clock (by clearing the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+    usec_delay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw,
+                         uint32_t data,
+                         uint16_t count)
+{
+    uint32_t ctrl;
+    uint32_t mask;
+
+    /* We need to shift "count" number of bits out to the PHY. So, the value
+     * in the "data" parameter will be shifted out to the PHY one bit at a 
+     * time. In order to do this, "data" must be broken down into bits.
+     */
+    mask = 0x01;
+    mask <<= (count - 1);
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+    ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+    while(mask) {
+        /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+         * then raising and lowering the Management Data Clock. A "0" is
+         * shifted out to the PHY by setting the MDIO bit to "0" and then
+         * raising and lowering the clock.
+         */
+        if(data & mask) ctrl |= E1000_CTRL_MDIO;
+        else ctrl &= ~E1000_CTRL_MDIO;
+
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+
+        usec_delay(2);
+
+        e1000_raise_mdi_clk(hw, &ctrl);
+        e1000_lower_mdi_clk(hw, &ctrl);
+
+        mask = mask >> 1;
+    }
+
+    /* Clear the data bit just before leaving this routine. */
+    ctrl &= ~E1000_CTRL_MDIO;
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order. 
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t data = 0;
+    uint8_t i;
+
+    /* In order to read a register from the PHY, we need to shift in a total
+     * of 18 bits from the PHY. The first two bit (turnaround) times are used
+     * to avoid contention on the MDIO pin when a read operation is performed.
+     * These two bits are ignored by us and thrown away. Bits are "shifted in"
+     * by raising the input to the Management Data Clock (setting the MDC bit),
+     * and then reading the value of the MDIO bit.
+     */ 
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+    ctrl &= ~E1000_CTRL_MDIO_DIR;
+    ctrl &= ~E1000_CTRL_MDIO;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    /* Raise and Lower the clock before reading in the data. This accounts for
+     * the turnaround bits. The first clock occurred when we clocked out the
+     * last bit of the Register Address.
+     */
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    for(data = 0, i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_mdi_clk(hw, &ctrl);
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Check to see if we shifted in a "1". */
+        if(ctrl & E1000_CTRL_MDIO) data |= 1;
+        e1000_lower_mdi_clk(hw, &ctrl);
+    }
+
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    /* Clear the MDIO bit just before leaving this routine. */
+    ctrl &= ~E1000_CTRL_MDIO;
+
+    return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+e1000_read_phy_reg(struct e1000_hw *hw,
+                   uint32_t reg_addr,
+                   uint16_t *phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_read_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, and register address in the MDI
+         * Control register.  The MAC will take care of interfacing with the
+         * PHY to retrieve the desired data.
+         */
+        mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_READ));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            usec_delay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Read did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+        if(mdic & E1000_MDIC_ERROR) {
+            DEBUGOUT("MDI Error\n");
+            return -E1000_ERR_PHY;
+        }
+        *phy_data = (uint16_t) mdic;
+    } else {
+        /* We must first send a preamble through the MDIO pin to signal the
+         * beginning of an MII instruction.  This is done by sending 32
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the next few fields that are required for a read
+         * operation.  We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine five different times. The format of
+         * a MII read instruction consists of a shift out of 14 bits and is
+         * defined as follows:
+         *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+         * followed by a shift in of 18 bits.  This first two bits shifted in
+         * are TurnAround bits used to avoid contention on the MDIO pin when a
+         * READ operation is performed.  These two bits are thrown away
+         * followed by a shift in of 16 bits which contains the desired data.
+         */
+        mdic = ((reg_addr) | (phy_addr << 5) | 
+                (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+        e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+        /* Now that we've shifted out the read command to the MII, we need to
+         * "shift in" the 16-bit value (18 total bits) of the requested PHY
+         * register address.
+         */
+        *phy_data = e1000_shift_in_mdi_bits(hw);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+e1000_write_phy_reg(struct e1000_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_write_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, register address, and data intended
+         * for the PHY register in the MDI Control register.  The MAC will take
+         * care of interfacing with the PHY to send the desired data.
+         */
+        mdic = (((uint32_t) phy_data) |
+                (reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_WRITE));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            usec_delay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Write did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+    } else {
+        /* We'll need to use the SW defined pins to shift the write command
+         * out to the PHY. We first send a preamble to the PHY to signal the
+         * beginning of the MII instruction.  This is done by sending 32 
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the remaining required fields that will indicate a 
+         * write operation. We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine for each field in the command. The
+         * format of a MII write instruction is as follows:
+         * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+         */
+        mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+                (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+        mdic <<= 16;
+        mdic |= (uint32_t) phy_data;
+
+        e1000_shift_out_mdi_bits(hw, mdic, 32);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+
+    DEBUGFUNC("e1000_phy_hw_reset");
+
+    DEBUGOUT("Resetting Phy...\n");
+
+    if(hw->mac_type > e1000_82543) {
+        /* Read the device control register and assert the E1000_CTRL_PHY_RST
+         * bit. Then, take it out of reset.
+         */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+        msec_delay(10);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+    } else {
+        /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+         * bit to put the PHY into reset. Then, take it out of reset.
+         */
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+        ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        msec_delay(10);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+    usec_delay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_reset");
+
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= MII_CR_RESET;
+    if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    usec_delay(1);
+    return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+    uint16_t phy_id_high, phy_id_low;
+    boolean_t match = FALSE;
+
+    DEBUGFUNC("e1000_detect_gig_phy");
+
+    /* Read the PHY ID Registers to identify which PHY is onboard. */
+    if(e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id = (uint32_t) (phy_id_high << 16);
+    usec_delay(2);
+    if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+    
+    switch(hw->mac_type) {
+    case e1000_82543:
+        if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+        break;
+    case e1000_82544:
+        if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+        break;
+    case e1000_82540:
+        if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+        break;
+    default:
+        DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+        return -E1000_ERR_CONFIG;
+    }
+    if(match) {
+        DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+        return 0;
+    }
+    DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+    return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_reset_dsp(struct e1000_hw *hw)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    DEBUGFUNC("e1000_phy_reset_dsp");
+    
+    do {
+        if(e1000_write_phy_reg(hw, 29, 0x1d) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0xc1) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0x00) < 0) break;
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
+    return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+                   struct e1000_phy_info *phy_info)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_get_info");
+
+    phy_info->cable_length = e1000_cable_length_undefined;
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+    phy_info->cable_polarity = e1000_rev_polarity_undefined;
+    phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+    phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+    phy_info->local_rx = e1000_1000t_rx_status_undefined;
+    phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+    if(hw->media_type != e1000_media_type_copper) {
+        DEBUGOUT("PHY info is only valid for copper media\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    do {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+            DEBUGOUT("PHY info is only valid if link is up\n");
+            return -E1000_ERR_CONFIG;
+        }
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+            break;
+        phy_info->extended_10bt_distance =
+            (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+            M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+        phy_info->polarity_correction =
+            (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+            M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            break;
+        phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+            M88E1000_PSSR_REV_POLARITY_SHIFT;
+        phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+            M88E1000_PSSR_MDIX_SHIFT;
+        if(phy_data & M88E1000_PSSR_1000MBS) {
+            /* Cable Length Estimation and Local/Remote Receiver Informatoion
+	     * are only valid at 1000 Mbps
+	     */
+            phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                      M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+            if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) 
+                break;
+            phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                SR_1000T_LOCAL_RX_STATUS_SHIFT;
+            phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                SR_1000T_REMOTE_RX_STATUS_SHIFT;
+        }
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
+    return ret_val;
+}
+
+int32_t
+e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_validate_mdi_settings");
+
+    if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+        DEBUGOUT("Invalid MDI setting detected\n");
+        hw->mdix = 1;
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+     * wait 50 microseconds.
+     */
+    *eecd = *eecd | E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    usec_delay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
+     * wait 50 microseconds. 
+     */
+    *eecd = *eecd & ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    usec_delay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+                        uint16_t data,
+                        uint16_t count)
+{
+    uint32_t eecd;
+    uint32_t mask;
+
+    /* We need to shift "count" bits out to the EEPROM. So, value in the
+     * "data" parameter will be shifted out to the EEPROM one bit at a time.
+     * In order to do this, "data" must be broken down into bits. 
+     */
+    mask = 0x01 << (count - 1);
+    eecd = E1000_READ_REG(hw, EECD);
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    do {
+        /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+         * and then raising and then lowering the clock (the SK bit controls
+         * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
+         * by setting "DI" to "0" and then raising and then lowering the clock.
+         */
+        eecd &= ~E1000_EECD_DI;
+
+        if(data & mask)
+            eecd |= E1000_EECD_DI;
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+
+        usec_delay(50);
+
+        e1000_raise_ee_clk(hw, &eecd);
+        e1000_lower_ee_clk(hw, &eecd);
+
+        mask = mask >> 1;
+
+    } while(mask);
+
+    /* We leave the "DI" bit set to "0" when we leave this routine. */
+    eecd &= ~E1000_EECD_DI;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+    uint32_t i;
+    uint16_t data;
+
+    /* In order to read a register from the EEPROM, we need to shift 16 bits 
+     * in from the EEPROM. Bits are "shifted in" by raising the clock input to
+     * the EEPROM (setting the SK bit), and then reading the value of the "DO"
+     * bit.  During this "shifting in" process the "DI" bit should always be 
+     * clear..
+     */
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    data = 0;
+
+    for(i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_ee_clk(hw, &eecd);
+
+        eecd = E1000_READ_REG(hw, EECD);
+
+        eecd &= ~(E1000_EECD_DI);
+        if(eecd & E1000_EECD_DO)
+            data |= 1;
+
+        e1000_lower_ee_clk(hw, &eecd);
+    }
+
+    return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Clear SK and DI */
+    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+    E1000_WRITE_REG(hw, EECD, eecd);
+
+    /* Set CS */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Deselct EEPROM */
+    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+    E1000_WRITE_REG(hw, EECD, eecd);
+    usec_delay(50);
+
+    /* Clock high */
+    eecd |= E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    usec_delay(50);
+
+    /* Select EEPROM */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    usec_delay(50);
+
+    /* Clock low */
+    eecd &= ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    usec_delay(50);
+}
+
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM 
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom(struct e1000_hw *hw,
+                  uint16_t offset,
+                  uint16_t *data)
+{
+    uint32_t eecd;
+    uint32_t i = 0;
+    boolean_t large_eeprom = FALSE;
+
+    DEBUGFUNC("e1000_read_eeprom");
+
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+            i++;
+            usec_delay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    /*  Prepare the EEPROM for reading  */
+    e1000_setup_eeprom(hw);
+
+    /*  Send the READ command (opcode + addr)  */
+    e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+    if(large_eeprom) {
+        /* If we have a 256 word EEPROM, there are 8 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 8);
+    } else {
+        /* If we have a 64 word EEPROM, there are 6 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 6);
+    }
+
+    /* Read the data */
+    *data = e1000_shift_in_ee_bits(hw);
+
+    /* End this read operation */
+    e1000_standby_eeprom(hw);
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    return 0;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+
+    if(checksum == (uint16_t) EEPROM_SUM) {
+        return 0;
+    } else {
+        DEBUGOUT("EEPROM Checksum Invalid\n");    
+        return -E1000_ERR_EEPROM;
+    }
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+e1000_read_part_num(struct e1000_hw *hw,
+                    uint32_t *part_num)
+{
+    uint16_t offset = EEPROM_PBA_BYTE_1;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_read_part_num");
+
+    /* Get word 0 from EEPROM */
+    if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 0 in upper half of part_num */
+    *part_num = (uint32_t) (eeprom_data << 16);
+
+    /* Get word 1 from EEPROM */
+    if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 1 in lower half of part_num */
+    *part_num |= eeprom_data;
+
+    return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_read_mac_addr(struct e1000_hw * hw)
+{
+    uint16_t offset;
+    uint16_t eeprom_data, i;
+
+    DEBUGFUNC("e1000_read_mac_addr");
+
+    for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+        offset = i >> 1;
+        if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+        hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+    }
+    for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+        hw->mac_addr[i] = hw->perm_mac_addr[i];
+    return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+    uint32_t i;
+    uint32_t addr_low;
+    uint32_t addr_high;
+
+    DEBUGFUNC("e1000_init_rx_addrs");
+
+    /* Setup the receive address. */
+    DEBUGOUT("Programming MAC Address into RAR[0]\n");
+    addr_low = (hw->mac_addr[0] |
+                (hw->mac_addr[1] << 8) |
+                (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+    addr_high = (hw->mac_addr[4] |
+                 (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+    /* Zero out the other 15 receive addresses. */
+    DEBUGOUT("Clearing RAR[1-15]\n");
+    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the 
+ * multicast table.
+ *****************************************************************************/
+void
+e1000_mc_addr_list_update(struct e1000_hw *hw,
+                          uint8_t *mc_addr_list,
+                          uint32_t mc_addr_count,
+                          uint32_t pad)
+{
+    uint32_t hash_value;
+    uint32_t i;
+    uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
+
+    DEBUGFUNC("e1000_mc_addr_list_update");
+
+    /* Set the new number of MC addresses that we are being requested to use. */
+    hw->num_mc_addrs = mc_addr_count;
+
+    /* Clear RAR[1-15] */
+    DEBUGOUT(" Clearing RAR[1-15]\n");
+    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+
+    /* Clear the MTA */
+    DEBUGOUT(" Clearing MTA\n");
+    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+    }
+
+    /* Add the new addresses */
+    for(i = 0; i < mc_addr_count; i++) {
+        DEBUGOUT(" Adding the multicast addresses:\n");
+        DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+        hash_value = e1000_hash_mc_addr(hw,
+                                        mc_addr_list +
+                                        (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+        DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+        /* Place this multicast address in the RAR if there is room, *
+         * else put it in the MTA            
+         */
+        if(rar_used_count < E1000_RAR_ENTRIES) {
+            e1000_rar_set(hw,
+                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+                          rar_used_count);
+            rar_used_count++;
+        } else {
+            e1000_mta_set(hw, hash_value);
+        }
+    }
+    DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash 
+ *****************************************************************************/
+uint32_t
+e1000_hash_mc_addr(struct e1000_hw *hw,
+                   uint8_t *mc_addr)
+{
+    uint32_t hash_value = 0;
+
+    /* The portion of the address that is used for the hash table is
+     * determined by the mc_filter_type setting.  
+     */
+    switch (hw->mc_filter_type) {
+    /* [0] [1] [2] [3] [4] [5]
+     * 01  AA  00  12  34  56
+     * LSB                 MSB
+     */
+    case 0:
+        /* [47:36] i.e. 0x563 for above example address */
+        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        break;
+    case 1:
+        /* [46:35] i.e. 0xAC6 for above example address */
+        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        break;
+    case 2:
+        /* [45:34] i.e. 0x5D8 for above example address */
+        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        break;
+    case 3:
+        /* [43:32] i.e. 0x634 for above example address */
+        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        break;
+    }
+
+    hash_value &= 0xFFF;
+    return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+e1000_mta_set(struct e1000_hw *hw,
+              uint32_t hash_value)
+{
+    uint32_t hash_bit, hash_reg;
+    uint32_t mta;
+    uint32_t temp;
+
+    /* The MTA is a register array of 128 32-bit registers.  
+     * It is treated like an array of 4096 bits.  We want to set 
+     * bit BitArray[hash_value]. So we figure out what register
+     * the bit is in, read it, OR in the new bit, then write
+     * back the new value.  The register is determined by the 
+     * upper 7 bits of the hash value and the bit within that 
+     * register are determined by the lower 5 bits of the value.
+     */
+    hash_reg = (hash_value >> 5) & 0x7F;
+    hash_bit = hash_value & 0x1F;
+
+    mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+    mta |= (1 << hash_bit);
+
+    /* If we are on an 82544 and we are trying to write an odd offset
+     * in the MTA, save off the previous entry before writing and
+     * restore the old value after writing.
+     */
+    if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+    }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+e1000_rar_set(struct e1000_hw *hw,
+              uint8_t *addr,
+              uint32_t index)
+{
+    uint32_t rar_low, rar_high;
+
+    /* HW expects these in little endian so we reverse the byte order
+     * from network order (big endian) to little endian              
+     */
+    rar_low = ((uint32_t) addr[0] |
+               ((uint32_t) addr[1] << 8) |
+               ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+    rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+e1000_write_vfta(struct e1000_hw *hw,
+                 uint32_t offset,
+                 uint32_t value)
+{
+    uint32_t temp;
+
+    if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+    }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+    uint32_t offset;
+
+    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_setup_led(struct e1000_hw *hw)
+{
+    uint32_t ledctl;
+ 
+    DEBUGFUNC("e1000_setup_led");
+   
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No setup necessary */
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+        ledctl = E1000_READ_REG(hw, LEDCTL);
+        /* Save current LEDCTL settings */
+        hw->ledctl = ledctl;
+        /* Turn off LED2 and LED3 */
+        ledctl &= ~(E1000_LEDCTL_LED2_IVRT |
+                    E1000_LEDCTL_LED2_BLINK | 
+                    E1000_LEDCTL_LED2_MODE_MASK);
+        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED2_MODE_SHIFT);
+        ledctl &= ~(E1000_LEDCTL_LED3_IVRT |
+                    E1000_LEDCTL_LED3_BLINK | 
+                    E1000_LEDCTL_LED3_MODE_MASK);
+        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+        E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_cleanup_led(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_cleanup_led");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No cleanup necessary */
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+        /* Restore LEDCTL settings */
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+    
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_on(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ledctl;
+
+    DEBUGFUNC("e1000_led_on");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn on the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn on the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+        ledctl = E1000_READ_REG(hw, LEDCTL);
+        /* Set LED 3 mode to on */
+        ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+        ledctl |= (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED3_MODE_SHIFT);
+        E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_off(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ledctl;
+
+    DEBUGFUNC("e1000_led_off");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn off the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn off the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+        ledctl = E1000_READ_REG(hw, LEDCTL);
+        /* Set LED 3 mode to off */
+        ledctl &= ~E1000_LEDCTL_LED3_MODE_MASK;
+        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED3_MODE_SHIFT);
+        E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters. 
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_hw_cntrs(struct e1000_hw *hw)
+{
+    volatile uint32_t temp;
+
+    temp = E1000_READ_REG(hw, CRCERRS);
+    temp = E1000_READ_REG(hw, SYMERRS);
+    temp = E1000_READ_REG(hw, MPC);
+    temp = E1000_READ_REG(hw, SCC);
+    temp = E1000_READ_REG(hw, ECOL);
+    temp = E1000_READ_REG(hw, MCC);
+    temp = E1000_READ_REG(hw, LATECOL);
+    temp = E1000_READ_REG(hw, COLC);
+    temp = E1000_READ_REG(hw, DC);
+    temp = E1000_READ_REG(hw, SEC);
+    temp = E1000_READ_REG(hw, RLEC);
+    temp = E1000_READ_REG(hw, XONRXC);
+    temp = E1000_READ_REG(hw, XONTXC);
+    temp = E1000_READ_REG(hw, XOFFRXC);
+    temp = E1000_READ_REG(hw, XOFFTXC);
+    temp = E1000_READ_REG(hw, FCRUC);
+    temp = E1000_READ_REG(hw, PRC64);
+    temp = E1000_READ_REG(hw, PRC127);
+    temp = E1000_READ_REG(hw, PRC255);
+    temp = E1000_READ_REG(hw, PRC511);
+    temp = E1000_READ_REG(hw, PRC1023);
+    temp = E1000_READ_REG(hw, PRC1522);
+    temp = E1000_READ_REG(hw, GPRC);
+    temp = E1000_READ_REG(hw, BPRC);
+    temp = E1000_READ_REG(hw, MPRC);
+    temp = E1000_READ_REG(hw, GPTC);
+    temp = E1000_READ_REG(hw, GORCL);
+    temp = E1000_READ_REG(hw, GORCH);
+    temp = E1000_READ_REG(hw, GOTCL);
+    temp = E1000_READ_REG(hw, GOTCH);
+    temp = E1000_READ_REG(hw, RNBC);
+    temp = E1000_READ_REG(hw, RUC);
+    temp = E1000_READ_REG(hw, RFC);
+    temp = E1000_READ_REG(hw, ROC);
+    temp = E1000_READ_REG(hw, RJC);
+    temp = E1000_READ_REG(hw, TORL);
+    temp = E1000_READ_REG(hw, TORH);
+    temp = E1000_READ_REG(hw, TOTL);
+    temp = E1000_READ_REG(hw, TOTH);
+    temp = E1000_READ_REG(hw, TPR);
+    temp = E1000_READ_REG(hw, TPT);
+    temp = E1000_READ_REG(hw, PTC64);
+    temp = E1000_READ_REG(hw, PTC127);
+    temp = E1000_READ_REG(hw, PTC255);
+    temp = E1000_READ_REG(hw, PTC511);
+    temp = E1000_READ_REG(hw, PTC1023);
+    temp = E1000_READ_REG(hw, PTC1522);
+    temp = E1000_READ_REG(hw, MPTC);
+    temp = E1000_READ_REG(hw, BPTC);
+
+    if(hw->mac_type < e1000_82543) return;
+
+    temp = E1000_READ_REG(hw, ALGNERRC);
+    temp = E1000_READ_REG(hw, RXERRC);
+    temp = E1000_READ_REG(hw, TNCRS);
+    temp = E1000_READ_REG(hw, CEXTERR);
+    temp = E1000_READ_REG(hw, TSCTC);
+    temp = E1000_READ_REG(hw, TSCTFC);
+
+    if(hw->mac_type <= e1000_82544) return;
+
+    temp = E1000_READ_REG(hw, MGTPRC);
+    temp = E1000_READ_REG(hw, MGTPDC);
+    temp = E1000_READ_REG(hw, MGTPTC);
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after e1000_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+e1000_reset_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_reset_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if(!hw->ifs_params_forced) {
+            hw->current_ifs_val = 0;
+            hw->ifs_min_val = IFS_MIN;
+            hw->ifs_max_val = IFS_MAX;
+            hw->ifs_step_size = IFS_STEP;
+            hw->ifs_ratio = IFS_RATIO;
+        }
+        hw->in_ifs_mode = FALSE;
+        E1000_WRITE_REG(hw, AIT, 0);
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+e1000_update_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_update_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if((hw->collision_delta * hw->ifs_ratio) > 
+           hw->tx_packet_delta) {
+            if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+                hw->in_ifs_mode = TRUE;
+                if(hw->current_ifs_val < hw->ifs_max_val) {
+                    if(hw->current_ifs_val == 0)
+                        hw->current_ifs_val = hw->ifs_min_val;
+                    else
+                        hw->current_ifs_val += hw->ifs_step_size;
+                    E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+                }
+            }
+        } else {
+            if((hw->in_ifs_mode == TRUE) && 
+               (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+                hw->current_ifs_val = 0;
+                hw->in_ifs_mode = FALSE;
+                E1000_WRITE_REG(hw, AIT, 0);
+            }
+        }
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+e1000_tbi_adjust_stats(struct e1000_hw *hw,
+                       struct e1000_hw_stats *stats,
+                       uint32_t frame_len,
+                       uint8_t *mac_addr)
+{
+    uint64_t carry_bit;
+
+    /* First adjust the frame length. */
+    frame_len--;
+    /* We need to adjust the statistics counters, since the hardware
+     * counters overcount this packet as a CRC error and undercount
+     * the packet as a good packet
+     */
+    /* This packet should not be counted as a CRC error.    */
+    stats->crcerrs--;
+    /* This packet does count as a Good Packet Received.    */
+    stats->gprc++;
+
+    /* Adjust the Good Octets received counters             */
+    carry_bit = 0x80000000 & stats->gorcl;
+    stats->gorcl += frame_len;
+    /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+     * Received Count) was one before the addition, 
+     * AND it is zero after, then we lost the carry out, 
+     * need to add one to Gorch (Good Octets Received Count High).
+     * This could be simplified if all environments supported 
+     * 64-bit integers.
+     */
+    if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+        stats->gorch++;
+    /* Is this a broadcast or multicast?  Check broadcast first,
+     * since the test for a multicast frame will test positive on 
+     * a broadcast frame.
+     */
+    if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+        /* Broadcast packet */
+        stats->bprc++;
+    else if(*mac_addr & 0x01)
+        /* Multicast packet */
+        stats->mprc++;
+
+    if(frame_len == hw->max_frame_size) {
+        /* In this case, the hardware has overcounted the number of
+         * oversize frames.
+         */
+        if(stats->roc > 0)
+            stats->roc--;
+    }
+
+    /* Adjust the bin counters when the extra byte put the frame in the
+     * wrong bin. Remember that the frame_len was adjusted above.
+     */
+    if(frame_len == 64) {
+        stats->prc64++;
+        stats->prc127--;
+    } else if(frame_len == 127) {
+        stats->prc127++;
+        stats->prc255--;
+    } else if(frame_len == 255) {
+        stats->prc255++;
+        stats->prc511--;
+    } else if(frame_len == 511) {
+        stats->prc511++;
+        stats->prc1023--;
+    } else if(frame_len == 1023) {
+        stats->prc1023++;
+        stats->prc1522--;
+    } else if(frame_len == 1522) {
+        stats->prc1522++;
+    }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_get_bus_info(struct e1000_hw *hw)
+{
+    uint32_t status;
+
+    if(hw->mac_type < e1000_82543) {
+        hw->bus_type = e1000_bus_type_unknown;
+        hw->bus_speed = e1000_bus_speed_unknown;
+        hw->bus_width = e1000_bus_width_unknown;
+        return;
+    }
+
+    status = E1000_READ_REG(hw, STATUS);
+    hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                   e1000_bus_type_pcix : e1000_bus_type_pci;
+    if(hw->bus_type == e1000_bus_type_pci) {
+        hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+                        e1000_bus_speed_66 : e1000_bus_speed_33;
+    } else {
+        switch (status & E1000_STATUS_PCIX_SPEED) {
+        case E1000_STATUS_PCIX_SPEED_66:
+            hw->bus_speed = e1000_bus_speed_66;
+            break;
+        case E1000_STATUS_PCIX_SPEED_100:
+            hw->bus_speed = e1000_bus_speed_100;
+            break;
+        case E1000_STATUS_PCIX_SPEED_133:
+            hw->bus_speed = e1000_bus_speed_133;
+            break;
+        default:
+            hw->bus_speed = e1000_bus_speed_reserved;
+            break;
+        }
+    }
+    hw->bus_width = (status & E1000_STATUS_BUS64) ?
+                    e1000_bus_width_64 : e1000_bus_width_32;
+}
+
diff -Nru a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/e1000/e1000_hw.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,1767 @@
+/*******************************************************************************
+
+  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 2.0, 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/1000 Family of Adapters (e1000) (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 General Public License 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
+  General Public License 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 General
+  Public License 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.
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+
+/* Forward declarations of structures used by the shared code */
+struct e1000_hw;
+struct e1000_hw_stats;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+    e1000_82542_rev2_0 = 0,
+    e1000_82542_rev2_1,
+    e1000_82543,
+    e1000_82544,
+    e1000_82540,
+    e1000_num_macs
+} e1000_mac_type;
+
+/* Media Types */
+typedef enum {
+    e1000_media_type_copper = 0,
+    e1000_media_type_fiber = 1,
+    e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+    e1000_10_half = 0,
+    e1000_10_full = 1,
+    e1000_100_half = 2,
+    e1000_100_full = 3
+} e1000_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+    e1000_fc_none = 0,
+    e1000_fc_rx_pause = 1,
+    e1000_fc_tx_pause = 2,
+    e1000_fc_full = 3,
+    e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+/* PCI bus types */
+typedef enum {
+    e1000_bus_type_unknown = 0,
+    e1000_bus_type_pci,
+    e1000_bus_type_pcix
+} e1000_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+    e1000_bus_speed_unknown = 0,
+    e1000_bus_speed_33,
+    e1000_bus_speed_66,
+    e1000_bus_speed_100,
+    e1000_bus_speed_133,
+    e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+    e1000_bus_width_unknown = 0,
+    e1000_bus_width_32,
+    e1000_bus_width_64
+} e1000_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+    e1000_cable_length_50 = 0,
+    e1000_cable_length_50_80,
+    e1000_cable_length_80_110,
+    e1000_cable_length_110_140,
+    e1000_cable_length_140,
+    e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+
+typedef enum {
+    e1000_10bt_ext_dist_enable_normal = 0,
+    e1000_10bt_ext_dist_enable_lower,
+    e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
+
+typedef enum {
+    e1000_rev_polarity_normal = 0,
+    e1000_rev_polarity_reversed,
+    e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+    e1000_polarity_reversal_enabled = 0,
+    e1000_polarity_reversal_disabled,
+    e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+    e1000_auto_x_mode_manual_mdi = 0,
+    e1000_auto_x_mode_manual_mdix,
+    e1000_auto_x_mode_auto1,
+    e1000_auto_x_mode_auto2,
+    e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+    e1000_1000t_rx_status_not_ok = 0,
+    e1000_1000t_rx_status_ok,
+    e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+    e1000_cable_length cable_length;
+    e1000_10bt_ext_dist_enable extended_10bt_distance;
+    e1000_rev_polarity cable_polarity;
+    e1000_polarity_reversal polarity_correction;
+    e1000_auto_x_mode mdix_mode;
+    e1000_1000t_rx_status local_rx;
+    e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+    uint32_t idle_errors;
+    uint32_t receive_errors;
+};
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS    0
+#define E1000_ERR_EEPROM 1
+#define E1000_ERR_PHY    2
+#define E1000_ERR_CONFIG 3
+#define E1000_ERR_PARAM  4
+
+/* Function prototypes */
+/* Initialization */
+void e1000_reset_hw(struct e1000_hw *hw);
+int32_t e1000_init_hw(struct e1000_hw *hw);
+
+/* Link Configuration */
+int32_t e1000_setup_link(struct e1000_hw *hw);
+int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+int32_t e1000_check_for_link(struct e1000_hw *hw);
+void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* PHY */
+int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+void e1000_phy_hw_reset(struct e1000_hw *hw);
+int32_t e1000_phy_reset(struct e1000_hw *hw);
+int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
+
+/* EEPROM Functions */
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+/* Filters (multicast, vlan, receive) */
+void e1000_init_rx_addrs(struct e1000_hw *hw);
+void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
+uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
+void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
+void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+void e1000_clear_vfta(struct e1000_hw *hw);
+
+/* LED functions */
+int32_t e1000_setup_led(struct e1000_hw *hw);
+int32_t e1000_cleanup_led(struct e1000_hw *hw);
+int32_t e1000_led_on(struct e1000_hw *hw);
+int32_t e1000_led_off(struct e1000_hw *hw);
+
+/* Adaptive IFS Functions */
+
+/* Everything else */
+void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542          0x1000
+#define E1000_DEV_ID_82543GC_FIBER  0x1001
+#define E1000_DEV_ID_82543GC_COPPER 0x1004
+#define E1000_DEV_ID_82544EI_COPPER 0x1008
+#define E1000_DEV_ID_82544EI_FIBER  0x1009
+#define E1000_DEV_ID_82544GC_COPPER 0x100C
+#define E1000_DEV_ID_82544GC_LOM    0x100D
+#define E1000_DEV_ID_82540EM        0x100E
+#define E1000_DEV_ID_82540EM_LOM    0x1015
+#define NUM_DEV_IDS 9
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
+#define ETHERNET_FCS_SIZE            4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH                   ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE         0x3F00
+
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE                     4     /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+#define ETHERNET_IP_TYPE        0x0800  /* IP packets */
+#define ETHERNET_ARP_TYPE       0x0806  /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP    6
+#define IP_PROTOCOL_UDP    0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error 
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |         \
+    E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* The number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses. 
+ */
+#define E1000_RAR_ENTRIES 16
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 0x000D  /* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16   /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+
+/* Receive Address Register */
+struct e1000_rar {
+    volatile uint32_t low;      /* receive address low */
+    volatile uint32_t high;     /* receive address high */
+};
+
+/* The number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct e1000_ipv4_at_entry {
+    volatile uint32_t ipv4_addr;        /* IP Address (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE                  1
+
+/* IPv6 Address Table Entry */
+struct e1000_ipv6_at_entry {
+    volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct e1000_fflt_entry {
+    volatile uint32_t length;   /* Flexible Filter Length (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct e1000_ffmt_entry {
+    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct e1000_ffvt_entry {
+    volatile uint32_t value;    /* Flexible Filter Value (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the 
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_STATUS   E1000_STATUS
+#define E1000_82542_EECD     E1000_EECD
+#define E1000_82542_EERD     E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_FCAL     E1000_FCAL
+#define E1000_82542_FCAH     E1000_FCAH
+#define E1000_82542_FCT      E1000_FCT
+#define E1000_82542_VET      E1000_VET
+#define E1000_82542_RA       0x00040
+#define E1000_82542_ICR      E1000_ICR
+#define E1000_82542_ITR      E1000_ITR
+#define E1000_82542_ICS      E1000_ICS
+#define E1000_82542_IMS      E1000_IMS
+#define E1000_82542_IMC      E1000_IMC
+#define E1000_82542_RCTL     E1000_RCTL
+#define E1000_82542_RDTR     0x00108
+#define E1000_82542_RDBAL    0x00110
+#define E1000_82542_RDBAH    0x00114
+#define E1000_82542_RDLEN    0x00118
+#define E1000_82542_RDH      0x00120
+#define E1000_82542_RDT      0x00128
+#define E1000_82542_FCRTH    0x00160
+#define E1000_82542_FCRTL    0x00168
+#define E1000_82542_FCTTV    E1000_FCTTV
+#define E1000_82542_TXCW     E1000_TXCW
+#define E1000_82542_RXCW     E1000_RXCW
+#define E1000_82542_MTA      0x00200
+#define E1000_82542_TCTL     E1000_TCTL
+#define E1000_82542_TIPG     E1000_TIPG
+#define E1000_82542_TDBAL    0x00420
+#define E1000_82542_TDBAH    0x00424
+#define E1000_82542_TDLEN    0x00428
+#define E1000_82542_TDH      0x00430
+#define E1000_82542_TDT      0x00438
+#define E1000_82542_TIDV     0x00440
+#define E1000_82542_TBT      E1000_TBT
+#define E1000_82542_AIT      E1000_AIT
+#define E1000_82542_VFTA     0x00600
+#define E1000_82542_LEDCTL   E1000_LEDCTL
+#define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RADV     E1000_RADV
+#define E1000_82542_RSRPD    E1000_RSRPD
+#define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TXDCTL   E1000_TXDCTL
+#define E1000_82542_TADV     E1000_TADV
+#define E1000_82542_TSPMT    E1000_TSPMT
+#define E1000_82542_CRCERRS  E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS  E1000_SYMERRS
+#define E1000_82542_RXERRC   E1000_RXERRC
+#define E1000_82542_MPC      E1000_MPC
+#define E1000_82542_SCC      E1000_SCC
+#define E1000_82542_ECOL     E1000_ECOL
+#define E1000_82542_MCC      E1000_MCC
+#define E1000_82542_LATECOL  E1000_LATECOL
+#define E1000_82542_COLC     E1000_COLC
+#define E1000_82542_DC       E1000_DC
+#define E1000_82542_TNCRS    E1000_TNCRS
+#define E1000_82542_SEC      E1000_SEC
+#define E1000_82542_CEXTERR  E1000_CEXTERR
+#define E1000_82542_RLEC     E1000_RLEC
+#define E1000_82542_XONRXC   E1000_XONRXC
+#define E1000_82542_XONTXC   E1000_XONTXC
+#define E1000_82542_XOFFRXC  E1000_XOFFRXC
+#define E1000_82542_XOFFTXC  E1000_XOFFTXC
+#define E1000_82542_FCRUC    E1000_FCRUC
+#define E1000_82542_PRC64    E1000_PRC64
+#define E1000_82542_PRC127   E1000_PRC127
+#define E1000_82542_PRC255   E1000_PRC255
+#define E1000_82542_PRC511   E1000_PRC511
+#define E1000_82542_PRC1023  E1000_PRC1023
+#define E1000_82542_PRC1522  E1000_PRC1522
+#define E1000_82542_GPRC     E1000_GPRC
+#define E1000_82542_BPRC     E1000_BPRC
+#define E1000_82542_MPRC     E1000_MPRC
+#define E1000_82542_GPTC     E1000_GPTC
+#define E1000_82542_GORCL    E1000_GORCL
+#define E1000_82542_GORCH    E1000_GORCH
+#define E1000_82542_GOTCL    E1000_GOTCL
+#define E1000_82542_GOTCH    E1000_GOTCH
+#define E1000_82542_RNBC     E1000_RNBC
+#define E1000_82542_RUC      E1000_RUC
+#define E1000_82542_RFC      E1000_RFC
+#define E1000_82542_ROC      E1000_ROC
+#define E1000_82542_RJC      E1000_RJC
+#define E1000_82542_MGTPRC   E1000_MGTPRC
+#define E1000_82542_MGTPDC   E1000_MGTPDC
+#define E1000_82542_MGTPTC   E1000_MGTPTC
+#define E1000_82542_TORL     E1000_TORL
+#define E1000_82542_TORH     E1000_TORH
+#define E1000_82542_TOTL     E1000_TOTL
+#define E1000_82542_TOTH     E1000_TOTH
+#define E1000_82542_TPR      E1000_TPR
+#define E1000_82542_TPT      E1000_TPT
+#define E1000_82542_PTC64    E1000_PTC64
+#define E1000_82542_PTC127   E1000_PTC127
+#define E1000_82542_PTC255   E1000_PTC255
+#define E1000_82542_PTC511   E1000_PTC511
+#define E1000_82542_PTC1023  E1000_PTC1023
+#define E1000_82542_PTC1522  E1000_PTC1522
+#define E1000_82542_MPTC     E1000_MPTC
+#define E1000_82542_BPTC     E1000_BPTC
+#define E1000_82542_TSCTC    E1000_TSCTC
+#define E1000_82542_TSCTFC   E1000_TSCTFC
+#define E1000_82542_RXCSUM   E1000_RXCSUM
+#define E1000_82542_WUC      E1000_WUC
+#define E1000_82542_WUFC     E1000_WUFC
+#define E1000_82542_WUS      E1000_WUS
+#define E1000_82542_MANC     E1000_MANC
+#define E1000_82542_IPAV     E1000_IPAV
+#define E1000_82542_IP4AT    E1000_IP4AT
+#define E1000_82542_IP6AT    E1000_IP6AT
+#define E1000_82542_WUPL     E1000_WUPL
+#define E1000_82542_WUPM     E1000_WUPM
+#define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_FFMT     E1000_FFMT
+#define E1000_82542_FFVT     E1000_FFVT
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+    uint64_t crcerrs;
+    uint64_t algnerrc;
+    uint64_t symerrs;
+    uint64_t rxerrc;
+    uint64_t mpc;
+    uint64_t scc;
+    uint64_t ecol;
+    uint64_t mcc;
+    uint64_t latecol;
+    uint64_t colc;
+    uint64_t dc;
+    uint64_t tncrs;
+    uint64_t sec;
+    uint64_t cexterr;
+    uint64_t rlec;
+    uint64_t xonrxc;
+    uint64_t xontxc;
+    uint64_t xoffrxc;
+    uint64_t xofftxc;
+    uint64_t fcruc;
+    uint64_t prc64;
+    uint64_t prc127;
+    uint64_t prc255;
+    uint64_t prc511;
+    uint64_t prc1023;
+    uint64_t prc1522;
+    uint64_t gprc;
+    uint64_t bprc;
+    uint64_t mprc;
+    uint64_t gptc;
+    uint64_t gorcl;
+    uint64_t gorch;
+    uint64_t gotcl;
+    uint64_t gotch;
+    uint64_t rnbc;
+    uint64_t ruc;
+    uint64_t rfc;
+    uint64_t roc;
+    uint64_t rjc;
+    uint64_t mgprc;
+    uint64_t mgpdc;
+    uint64_t mgptc;
+    uint64_t torl;
+    uint64_t torh;
+    uint64_t totl;
+    uint64_t toth;
+    uint64_t tpr;
+    uint64_t tpt;
+    uint64_t ptc64;
+    uint64_t ptc127;
+    uint64_t ptc255;
+    uint64_t ptc511;
+    uint64_t ptc1023;
+    uint64_t ptc1522;
+    uint64_t mptc;
+    uint64_t bptc;
+    uint64_t tsctc;
+    uint64_t tsctfc;
+};
+
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
+    uint8_t *hw_addr;
+    e1000_mac_type mac_type;
+    e1000_media_type media_type;
+    void *back;
+    e1000_fc_type fc;
+    e1000_bus_speed bus_speed;
+    e1000_bus_width bus_width;
+    e1000_bus_type bus_type;
+    uint32_t phy_id;
+    uint32_t phy_addr;
+    uint32_t original_fc;
+    uint32_t txcw;
+    uint32_t autoneg_failed;
+    uint32_t max_frame_size;
+    uint32_t min_frame_size;
+    uint32_t mc_filter_type;
+    uint32_t num_mc_addrs;
+    uint32_t collision_delta;
+    uint32_t tx_packet_delta;
+    uint32_t ledctl;
+    uint16_t autoneg_advertised;
+    uint16_t pci_cmd_word;
+    uint16_t fc_high_water;
+    uint16_t fc_low_water;
+    uint16_t fc_pause_time;
+    uint16_t current_ifs_val;
+    uint16_t ifs_min_val;
+    uint16_t ifs_max_val;
+    uint16_t ifs_step_size;
+    uint16_t ifs_ratio;
+    uint16_t device_id;
+    uint16_t vendor_id;
+    uint16_t subsystem_id;
+    uint16_t subsystem_vendor_id;
+    uint8_t revision_id;
+    uint8_t autoneg;
+    uint8_t mdix;
+    uint8_t forced_speed_duplex;
+    uint8_t wait_autoneg_complete;
+    uint8_t dma_fairness;
+    uint8_t mac_addr[NODE_ADDRESS_SIZE];
+    uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+    boolean_t disable_polarity_correction;
+    boolean_t get_link_status;
+    boolean_t tbi_compatibility_en;
+    boolean_t tbi_compatibility_on;
+    boolean_t fc_send_xon;
+    boolean_t report_tx_early;
+    boolean_t adaptive_ifs;
+    boolean_t ifs_params_forced;
+    boolean_t in_ifs_mode;
+};
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030 
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+
+/* EEPROM Read */
+#define E1000_EERD_START      0x00000001 /* Start Read */
+#define E1000_EERD_DONE       0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK  0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK  0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT       0x00000040
+#define E1000_LEDCTL_LED0_BLINK      0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK  0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_IVRT       0x00004000
+#define E1000_LEDCTL_LED1_BLINK      0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK  0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_IVRT       0x00400000
+#define E1000_LEDCTL_LED2_BLINK      0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK  0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT       0x40000000
+#define E1000_LEDCTL_LED3_BLINK      0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW    0x00000001    /* Transmit desc written back */
+#define E1000_ICR_TXQE    0x00000002    /* Transmit Queue empty */
+#define E1000_ICR_LSC     0x00000004    /* Link Status Change */
+#define E1000_ICR_RXSEQ   0x00000008    /* rx sequence error */
+#define E1000_ICR_RXDMT0  0x00000010    /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO     0x00000040    /* rx overrun */
+#define E1000_ICR_RXT0    0x00000080    /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC    0x00000200    /* MDIO access complete */
+#define E1000_ICR_RXCFG   0x00000400    /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800    /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000    /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000    /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000    /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD    0x00010000
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_ICS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_ICS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_ICS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_ICS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_ICS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_ICS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_ICS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_ICS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMC_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMC_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMC_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMC_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMC_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMC_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMC_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMC_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD    E1000_ICR_SRPD
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001      /* Software reset */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB  0x80000000      /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80      /* descriptor length */
+#define E1000_RDH_RDH   0x0000ffff      /* receive descriptor head */
+#define E1000_RDT_RDT   0x0000ffff      /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW    0x0000ffff     /* RxConfigWord mask */
+#define E1000_RXCW_NC    0x04000000     /* Receive config no carrier */
+#define E1000_RXCW_IV    0x08000000     /* Receive config invalid */
+#define E1000_RXCW_CC    0x10000000     /* Receive config change */
+#define E1000_RXCW_C     0x20000000     /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000     /* Receive config synch */
+#define E1000_RXCW_ANC   0x80000000     /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16       /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG  0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX   0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC   0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC   0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP  0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
+                                             * Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN          4096
+
+/* EEPROM Commands */
+#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
+#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
+#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
+#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
+#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_INIT_CONTROL1_REG 0x000A
+#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_FLASH_VERSION     0x0032
+#define EEPROM_CHECKSUM_REG      0x003F
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS   0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST   0x0200
+#define EEPROM_WORD0A_FD     0x0400
+#define EEPROM_WORD0A_66MHZ  0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE      0x1000
+#define EEPROM_WORD0F_ASM_DIR    0x2000
+#define EEPROM_WORD0F_ANE        0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1          8
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       16
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        64
+#define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_GB_HDX_COLLISION_DISTANCE 512
+#define E1000_COLD_SHIFT                12
+
+/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START     8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP      190
+#define TX_THRESHOLD_DISABLE   0
+#define TX_THRESHOLD_TIMER_MS  10000
+#define MIN_NUM_XMITS          1000
+#define IFS_MAX                80
+#define IFS_STEP               10
+#define IFS_MIN                40
+#define IFS_RATIO              4
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH        (0x8000)    /* 32KB */
+#define FC_DEFAULT_LO_THRESH        (0x4000)    /* 16KB */
+#define FC_DEFAULT_TX_TIMER         (0x100)     /* ~130 us */
+
+
+/* The number of bits that we need to shift right to move the "pause"
+ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
+ * in the TXCW register 
+ */
+#define PAUSE_SHIFT 5
+
+/* The number of bits that we need to shift left to move the "SWDPIO"
+ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
+ * in the CTRL register 
+ */
+#define SWDPIO_SHIFT 17
+
+/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
+ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
+ * Extended CTRL register.
+ * in the CTRL register 
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* The number of bits that we need to shift left to move the "ILOS"
+ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
+ * in the CTRL register 
+ */
+#define ILOS_SHIFT  3
+
+
+#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
+
+/* The number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT             500
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct e1000_hw 
+ *      status = the 8 bit status field of the RX descriptor with EOP set
+ *      error = the 8 bit error field of the RX descriptor with EOP set
+ *      length = the sum of all the length fields of the RX descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt 
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = TRUE;
+ *      e1000_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = FALSE;
+ *  }
+ *  ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+    ((adapter)->tbi_compatibility_on && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+          (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= ((adapter)->max_frame_size + 1))) : \
+          (((length) > (adapter)->min_frame_size) && \
+           ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges
+                                    * of different NP
+                                    */
+#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
+                                    * 0 = cannot comply with msg
+                                    */
+#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
+                                    * 0 = sending last NP
+                                    */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
+                                       * of different NP
+                                       */
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
+                                       * 0 = cannot comply with msg
+                                       */
+#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
+                                        * 0 = sending last NP 
+                                        */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT  13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */
+                                      /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
+                                                * 0=CLK125 toggling
+                                                */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
+                                                *  100BASE-TX/10BASE-T: 
+                                                *  MDI Mode
+                                                */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
+                                                * all speeds. 
+                                                */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
+                                        /* 1=Enable Extended 10BASE-T distance
+                                         * (Lower 10BASE-T RX Threshold)
+                                         * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+                                        /* 1=5-Bit interface in 100BASE-TX
+                                         * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+                                            * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT         6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
+                                              * Will assert lost lock and bring
+                                              * link down if idle not seen
+                                              * within 1ms in 1000BASE-T 
+                                              */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000    
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID  0x01410C50
+#define M88E1000_I_PHY_ID  0x01410C30
+#define M88E1011_I_PHY_ID  0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE        0xFFFFFFFF
+#define PHY_SOF             0x01
+#define PHY_OP_READ         0x02
+#define PHY_OP_WRITE        0x01
+#define PHY_TURNAROUND      0x02
+#define PHY_PREAMBLE_SIZE   32
+#define MII_CR_SPEED_1000   0x0040
+#define MII_CR_SPEED_100    0x2000
+#define MII_CR_SPEED_10     0x0000
+#define E1000_PHY_ADDRESS   0x01
+#define PHY_AUTO_NEG_TIME   45  /* 4.5 Seconds */
+#define PHY_FORCE_TIME      20  /* 2.0 Seconds */
+#define PHY_REVISION_MASK   0xFFFFFFF0
+#define DEVICE_SPEED_MASK   0x00000300  /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK     0x01E0
+#define REG9_SPEED_MASK     0x0300
+#define ADVERTISE_10_HALF   0x0001
+#define ADVERTISE_10_FULL   0x0002
+#define ADVERTISE_100_HALF  0x0004
+#define ADVERTISE_100_FULL  0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
+
+#endif /* _E1000_HW_H_ */
diff -Nru a/drivers/net/e1000/e1000_mac.c b/drivers/net/e1000/e1000_mac.c
--- a/drivers/net/e1000/e1000_mac.c	Wed Apr  3 17:11:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1821 +0,0 @@
-/*******************************************************************************
-
-  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/1000 Family of Adapters (e1000) (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.
-
-*******************************************************************************/
-
-/* e1000_mac.c
- * Shared functions for accessing and configuring the MAC
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
- * Raises the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_raise_clock(struct e1000_shared_adapter *shared,
-                  uint32_t *eecd_reg)
-{
-    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
-     * wait 50 microseconds.
-     */
-    *eecd_reg = *eecd_reg | E1000_EECD_SK;
-    E1000_WRITE_REG(shared, EECD, *eecd_reg);
-    usec_delay(50);
-    return;
-}
-
-/******************************************************************************
- * Lowers the EEPROM's clock input.
- *
- * shared - Struct containing variables accessed by shared code 
- * eecd_reg - EECD's current value
- *****************************************************************************/
-static void
-e1000_lower_clock(struct e1000_shared_adapter *shared,
-                  uint32_t *eecd_reg)
-{
-    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
-     * wait 50 microseconds. 
-     */
-    *eecd_reg = *eecd_reg & ~E1000_EECD_SK;
-    E1000_WRITE_REG(shared, EECD, *eecd_reg);
-    usec_delay(50);
-    return;
-}
-
-/******************************************************************************
- * Shift data bits out to the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * data - data to send to the EEPROM
- * count - number of bits to shift out
- *****************************************************************************/
-static void
-e1000_shift_out_bits(struct e1000_shared_adapter *shared,
-                     uint16_t data,
-                     uint16_t count)
-{
-    uint32_t eecd_reg;
-    uint32_t mask;
-
-    /* We need to shift "count" bits out to the EEPROM. So, value in the
-     * "data" parameter will be shifted out to the EEPROM one bit at a time.
-     * In order to do this, "data" must be broken down into bits. 
-     */
-    mask = 0x01 << (count - 1);
-    eecd_reg = E1000_READ_REG(shared, EECD);
-    eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
-    do {
-        /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
-         * and then raising and then lowering the clock (the SK bit controls
-         * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
-         * by setting "DI" to "0" and then raising and then lowering the clock.
-         */
-        eecd_reg &= ~E1000_EECD_DI;
-
-        if(data & mask)
-            eecd_reg |= E1000_EECD_DI;
-
-        E1000_WRITE_REG(shared, EECD, eecd_reg);
-
-        usec_delay(50);
-
-        e1000_raise_clock(shared, &eecd_reg);
-        e1000_lower_clock(shared, &eecd_reg);
-
-        mask = mask >> 1;
-
-    } while(mask);
-
-    /* We leave the "DI" bit set to "0" when we leave this routine. */
-    eecd_reg &= ~E1000_EECD_DI;
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    return;
-}
-
-/******************************************************************************
- * Shift data bits in from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static uint16_t
-e1000_shift_in_bits(struct e1000_shared_adapter *shared)
-{
-    uint32_t eecd_reg;
-    uint32_t i;
-    uint16_t data;
-
-    /* In order to read a register from the EEPROM, we need to shift 16 bits 
-     * in from the EEPROM. Bits are "shifted in" by raising the clock input to
-     * the EEPROM (setting the SK bit), and then reading the value of the "DO"
-     * bit.  During this "shifting in" process the "DI" bit should always be 
-     * clear..
-     */
-
-    eecd_reg = E1000_READ_REG(shared, EECD);
-
-    eecd_reg &= ~(E1000_EECD_DO | E1000_EECD_DI);
-    data = 0;
-
-    for(i = 0; i < 16; i++) {
-        data = data << 1;
-        e1000_raise_clock(shared, &eecd_reg);
-
-        eecd_reg = E1000_READ_REG(shared, EECD);
-
-        eecd_reg &= ~(E1000_EECD_DI);
-        if(eecd_reg & E1000_EECD_DO)
-            data |= 1;
-
-        e1000_lower_clock(shared, &eecd_reg);
-    }
-
-    return data;
-}
-
-/******************************************************************************
- * Prepares EEPROM for access
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
- * function should be called before issuing a command to the EEPROM.
- *****************************************************************************/
-static void
-e1000_setup_eeprom(struct e1000_shared_adapter *shared)
-{
-    uint32_t eecd_reg;
-
-    eecd_reg = E1000_READ_REG(shared, EECD);
-
-    /* Clear SK and DI */
-    eecd_reg &= ~(E1000_EECD_SK | E1000_EECD_DI);
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-
-    /* Set CS */
-    eecd_reg |= E1000_EECD_CS;
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    return;
-}
-
-/******************************************************************************
- * Returns EEPROM to a "standby" state
- * 
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-static void
-e1000_standby_eeprom(struct e1000_shared_adapter *shared)
-{
-    uint32_t eecd_reg;
-
-    eecd_reg = E1000_READ_REG(shared, EECD);
-
-    /* Deselct EEPROM */
-    eecd_reg &= ~(E1000_EECD_CS | E1000_EECD_SK);
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    usec_delay(50);
-
-    /* Clock high */
-    eecd_reg |= E1000_EECD_SK;
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    usec_delay(50);
-
-    /* Select EEPROM */
-    eecd_reg |= E1000_EECD_CS;
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    usec_delay(50);
-
-    /* Clock low */
-    eecd_reg &= ~E1000_EECD_SK;
-    E1000_WRITE_REG(shared, EECD, eecd_reg);
-    usec_delay(50);
-    return;
-}
-
-
-/******************************************************************************
- * Forces the MAC's flow control settings.
- * 
- * shared - Struct containing variables accessed by shared code
- *
- * Sets the TFCE and RFCE bits in the device control register to reflect
- * the adapter settings. TFCE and RFCE need to be explicitly set by
- * software when a Copper PHY is used because autonegotiation is managed
- * by the PHY rather than the MAC. Software must also configure these
- * bits when link is forced on a fiber connection.
- *****************************************************************************/
-static void
-e1000_force_mac_fc(struct e1000_shared_adapter *shared)
-{
-    uint32_t ctrl_reg;
-
-    DEBUGFUNC("e1000_force_mac_fc");
-
-    /* Get the current configuration of the Device Control Register */
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    /* Because we didn't get link via the internal auto-negotiation
-     * mechanism (we either forced link or we got link via PHY
-     * auto-neg), we have to manually enable/disable transmit an
-     * receive flow control.
-     *
-     * The "Case" statement below enables/disable flow control
-     * according to the "shared->fc" parameter.
-     *
-     * The possible values of the "fc" parameter are:
-     *      0:  Flow control is completely disabled
-     *      1:  Rx flow control is enabled (we can receive pause
-     *          frames but not send pause frames).
-     *      2:  Tx flow control is enabled (we can send pause frames
-     *          frames but we do not receive pause frames).
-     *      3:  Both Rx and TX flow control (symmetric) is enabled.
-     *  other:  No other values should be possible at this point.
-     */
-
-    switch (shared->fc) {
-    case e1000_fc_none:
-        ctrl_reg &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
-        break;
-    case e1000_fc_rx_pause:
-        ctrl_reg &= (~E1000_CTRL_TFCE);
-        ctrl_reg |= E1000_CTRL_RFCE;
-        break;
-    case e1000_fc_tx_pause:
-        ctrl_reg &= (~E1000_CTRL_RFCE);
-        ctrl_reg |= E1000_CTRL_TFCE;
-        break;
-    case e1000_fc_full:
-        ctrl_reg |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
-        break;
-    default:
-        DEBUGOUT("Flow control param set incorrectly\n");
-        ASSERT(0);
-        break;
-    }
-
-    /* Disable TX Flow Control for 82542 (rev 2.0) */
-    if(shared->mac_type == e1000_82542_rev2_0)
-        ctrl_reg &= (~E1000_CTRL_TFCE);
-
-
-    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-    return;
-}
-
-/******************************************************************************
- * Reset the transmit and receive units; mask and clear all interrupts.
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_adapter_stop(struct e1000_shared_adapter *shared)
-{
-    uint32_t ctrl_reg;
-    uint32_t ctrl_ext_reg;
-    uint32_t icr_reg;
-    uint16_t pci_cmd_word;
-
-    DEBUGFUNC("e1000_shared_adapter_stop");
-
-    /* If we are stopped or resetting exit gracefully and wait to be
-     * started again before accessing the hardware.
-     */
-    if(shared->adapter_stopped) {
-        DEBUGOUT("Exiting because the adapter is already stopped!!!\n");
-        return;
-    }
-
-    /* Set the Adapter Stopped flag so other driver functions stop
-     * touching the Hardware.
-     */
-    shared->adapter_stopped = TRUE;
-
-    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
-    if(shared->mac_type == e1000_82542_rev2_0) {
-        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-
-            pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-
-            e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
-        }
-    }
-
-    /* Clear interrupt mask to stop board from generating interrupts */
-    DEBUGOUT("Masking off all interrupts\n");
-    E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
-    /* Disable the Transmit and Receive units.  Then delay to allow
-     * any pending transactions to complete before we hit the MAC with
-     * the global reset.
-     */
-    E1000_WRITE_REG(shared, RCTL, 0);
-    E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
-    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
-    shared->tbi_compatibility_on = FALSE;
-
-    msec_delay(10);
-
-    /* Issue a global reset to the MAC.  This will reset the chip's
-     * transmit, receive, DMA, and link units.  It will not effect
-     * the current PCI configuration.  The global reset bit is self-
-     * clearing, and should clear within a microsecond.
-     */
-    DEBUGOUT("Issuing a global reset to MAC\n");
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-    E1000_WRITE_REG(shared, CTRL, (ctrl_reg | E1000_CTRL_RST));
-
-    /* Delay a few ms just to allow the reset to complete */
-    msec_delay(10);
-
-#if DBG
-    /* Make sure the self-clearing global reset bit did self clear */
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    ASSERT(!(ctrl_reg & E1000_CTRL_RST));
-#endif
-
-    /* Force a reload from the EEPROM */
-    ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-    ctrl_ext_reg |= E1000_CTRL_EXT_EE_RST;
-    E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-    msec_delay(2);
-    
-    /* Clear interrupt mask to stop board from generating interrupts */
-    DEBUGOUT("Masking off all interrupts\n");
-    E1000_WRITE_REG(shared, IMC, 0xffffffff);
-
-    /* Clear any pending interrupt events. */
-    icr_reg = E1000_READ_REG(shared, ICR);
-
-    /* If MWI was previously enabled, reenable it. */
-    if(shared->mac_type == e1000_82542_rev2_0) {
-        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            e1000_write_pci_cfg(shared,
-                                PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
-        }
-    }
-    return;
-}
-
-/******************************************************************************
- * Performs basic configuration of the adapter.
- *
- * shared - Struct containing variables accessed by shared code
- * 
- * Assumes that the controller has previously been reset and is in a 
- * post-reset uninitialized state. Initializes the receive address registers,
- * multicast table, and VLAN filter table. Calls routines to setup link
- * configuration and flow control settings. Clears all on-chip counters. Leaves
- * the transmit and receive units disabled and uninitialized.
- *****************************************************************************/
-boolean_t
-e1000_init_hw(struct e1000_shared_adapter *shared)
-{
-    uint32_t status_reg;
-    uint32_t i;
-    uint16_t pci_cmd_word;
-    boolean_t status;
-
-    DEBUGFUNC("e1000_init_hw");
-
-    /* Set the Media Type and exit with error if it is not valid. */
-    if(shared->mac_type != e1000_82543) {
-        /* tbi_compatibility is only valid on 82543 */
-        shared->tbi_compatibility_en = FALSE;
-    }
-
-    if(shared->mac_type >= e1000_82543) {
-        status_reg = E1000_READ_REG(shared, STATUS);
-        if(status_reg & E1000_STATUS_TBIMODE) {
-            shared->media_type = e1000_media_type_fiber;
-            /* tbi_compatibility not valid on fiber */
-            shared->tbi_compatibility_en = FALSE;
-        } else {
-            shared->media_type = e1000_media_type_copper;
-        }
-    } else {
-        /* This is an 82542 (fiber only) */
-        shared->media_type = e1000_media_type_fiber;
-    }
-
-    /* Disabling VLAN filtering. */
-    DEBUGOUT("Initializing the IEEE VLAN\n");
-    E1000_WRITE_REG(shared, VET, 0);
-
-    e1000_clear_vfta(shared);
-
-    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
-    if(shared->mac_type == e1000_82542_rev2_0) {
-        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
-            pci_cmd_word = shared->pci_cmd_word & ~CMD_MEM_WRT_INVALIDATE;
-            e1000_write_pci_cfg(shared, PCI_COMMAND_REGISTER, &pci_cmd_word);
-        }
-        E1000_WRITE_REG(shared, RCTL, E1000_RCTL_RST);
-
-        msec_delay(5);
-    }
-
-    /* Setup the receive address. This involves initializing all of the Receive
-     * Address Registers (RARs 0 - 15).
-     */
-    e1000_init_rx_addrs(shared);
-
-    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
-    if(shared->mac_type == e1000_82542_rev2_0) {
-        E1000_WRITE_REG(shared, RCTL, 0);
-
-        msec_delay(1);
-
-        if(shared->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) {
-            e1000_write_pci_cfg(shared,
-                                PCI_COMMAND_REGISTER, &shared->pci_cmd_word);
-        }
-    }
-
-    /* Zero out the Multicast HASH table */
-    DEBUGOUT("Zeroing the MTA\n");
-    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
-        E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
-
-    /* Call a subroutine to configure the link and setup flow control. */
-    status = e1000_setup_fc_and_link(shared);
-
-    /* Clear all of the statistics registers (clear on read).  It is
-     * important that we do this after we have tried to establish link
-     * because the symbol error count will increment wildly if there
-     * is no link.
-     */
-    e1000_clear_hw_cntrs(shared);
-
-    return (status);
-}
-
-/******************************************************************************
- * Initializes receive address filters.
- *
- * shared - Struct containing variables accessed by shared code 
- *
- * Places the MAC address in receive address register 0 and clears the rest
- * of the receive addresss registers. Clears the multicast table. Assumes
- * the receiver is in reset when the routine is called.
- *****************************************************************************/
-void
-e1000_init_rx_addrs(struct e1000_shared_adapter *shared)
-{
-    uint32_t i;
-    uint32_t addr_low;
-    uint32_t addr_high;
-
-    DEBUGFUNC("e1000_init_rx_addrs");
-
-    /* Setup the receive address. */
-    DEBUGOUT("Programming MAC Address into RAR[0]\n");
-    addr_low = (shared->mac_addr[0] |
-                (shared->mac_addr[1] << 8) |
-                (shared->mac_addr[2] << 16) | (shared->mac_addr[3] << 24));
-
-    addr_high = (shared->mac_addr[4] |
-                 (shared->mac_addr[5] << 8) | E1000_RAH_AV);
-
-    E1000_WRITE_REG_ARRAY(shared, RA, 0, addr_low);
-    E1000_WRITE_REG_ARRAY(shared, RA, 1, addr_high);
-
-    /* Zero out the other 15 receive addresses. */
-    DEBUGOUT("Clearing RAR[1-15]\n");
-    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
-        E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
-        E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
-    }
-
-    return;
-}
-
-/******************************************************************************
- * Updates the MAC's list of multicast addresses.
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr_list - the list of new multicast addresses
- * mc_addr_count - number of addresses
- * pad - number of bytes between addresses in the list
- *
- * The given list replaces any existing list. Clears the last 15 receive
- * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the 
- * multicast table.
- *****************************************************************************/
-void
-e1000_mc_addr_list_update(struct e1000_shared_adapter *shared,
-                          uint8_t *mc_addr_list,
-                          uint32_t mc_addr_count,
-                          uint32_t pad)
-{
-    uint32_t hash_value;
-    uint32_t i;
-    uint32_t rar_used_count = 1;        /* RAR[0] is used for our MAC address */
-
-    DEBUGFUNC("e1000_mc_addr_list_update");
-
-    /* Set the new number of MC addresses that we are being requested to use. */
-    shared->num_mc_addrs = mc_addr_count;
-
-    /* Clear RAR[1-15] */
-    DEBUGOUT(" Clearing RAR[1-15]\n");
-    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
-        E1000_WRITE_REG_ARRAY(shared, RA, (i << 1), 0);
-        E1000_WRITE_REG_ARRAY(shared, RA, ((i << 1) + 1), 0);
-    }
-
-    /* Clear the MTA */
-    DEBUGOUT(" Clearing MTA\n");
-    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
-        E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
-    }
-
-    /* Add the new addresses */
-    for(i = 0; i < mc_addr_count; i++) {
-        DEBUGOUT(" Adding the multicast addresses:\n");
-        DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
-                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
-
-        hash_value = e1000_hash_mc_addr(shared,
-                                        mc_addr_list +
-                                        (i * (ETH_LENGTH_OF_ADDRESS + pad)));
-
-        DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
-
-        /* Place this multicast address in the RAR if there is room, *
-         * else put it in the MTA            
-         */
-        if(rar_used_count < E1000_RAR_ENTRIES) {
-            e1000_rar_set(shared,
-                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
-                          rar_used_count);
-            rar_used_count++;
-        } else {
-            e1000_mta_set(shared, hash_value);
-        }
-    }
-
-    DEBUGOUT("MC Update Complete\n");
-    return;
-}
-
-/******************************************************************************
- * Hashes an address to determine its location in the multicast table
- *
- * shared - Struct containing variables accessed by shared code
- * mc_addr - the multicast address to hash 
- *****************************************************************************/
-uint32_t
-e1000_hash_mc_addr(struct e1000_shared_adapter *shared,
-                   uint8_t *mc_addr)
-{
-    uint32_t hash_value = 0;
-
-    /* The portion of the address that is used for the hash table is
-     * determined by the mc_filter_type setting.  
-     */
-    switch (shared->mc_filter_type) {
-        /* [0] [1] [2] [3] [4] [5]
-            * 01  AA  00  12  34  56
-            * LSB                 MSB - According to H/W docs */
-    case 0:
-        /* [47:36] i.e. 0x563 for above example address */
-        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
-        break;
-    case 1:                   /* [46:35] i.e. 0xAC6 for above example address */
-        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
-        break;
-    case 2:                   /* [45:34] i.e. 0x5D8 for above example address */
-        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
-        break;
-    case 3:                   /* [43:32] i.e. 0x634 for above example address */
-        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
-        break;
-    }
-
-    hash_value &= 0xFFF;
-    return (hash_value);
-}
-
-/******************************************************************************
- * Sets the bit in the multicast table corresponding to the hash value.
- *
- * shared - Struct containing variables accessed by shared code
- * hash_value - Multicast address hash value
- *****************************************************************************/
-void
-e1000_mta_set(struct e1000_shared_adapter *shared,
-              uint32_t hash_value)
-{
-    uint32_t hash_bit, hash_reg;
-    uint32_t mta_reg;
-    uint32_t temp;
-
-    /* The MTA is a register array of 128 32-bit registers.  
-     * It is treated like an array of 4096 bits.  We want to set 
-     * bit BitArray[hash_value]. So we figure out what register
-     * the bit is in, read it, OR in the new bit, then write
-     * back the new value.  The register is determined by the 
-     * upper 7 bits of the hash value and the bit within that 
-     * register are determined by the lower 5 bits of the value.
-     */
-    hash_reg = (hash_value >> 5) & 0x7F;
-    hash_bit = hash_value & 0x1F;
-
-    mta_reg = E1000_READ_REG_ARRAY(shared, MTA, hash_reg);
-
-    mta_reg |= (1 << hash_bit);
-
-    /* If we are on an 82544 and we are trying to write an odd offset
-     * in the MTA, save off the previous entry before writing and
-     * restore the old value after writing.
-     */
-    if((shared->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
-        temp = E1000_READ_REG_ARRAY(shared, MTA, (hash_reg - 1));
-        E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
-        E1000_WRITE_REG_ARRAY(shared, MTA, (hash_reg - 1), temp);
-    } else {
-        E1000_WRITE_REG_ARRAY(shared, MTA, hash_reg, mta_reg);
-    }
-    return;
-}
-
-/******************************************************************************
- * Puts an ethernet address into a receive address register.
- *
- * shared - Struct containing variables accessed by shared code
- * addr - Address to put into receive address register
- * index - Receive address register to write
- *****************************************************************************/
-void
-e1000_rar_set(struct e1000_shared_adapter *shared,
-              uint8_t *addr,
-              uint32_t index)
-{
-    uint32_t rar_low, rar_high;
-
-    /* HW expects these in little endian so we reverse the byte order
-     * from network order (big endian) to little endian              
-     */
-    rar_low = ((uint32_t) addr[0] |
-               ((uint32_t) addr[1] << 8) |
-               ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
-
-    rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
-
-    E1000_WRITE_REG_ARRAY(shared, RA, (index << 1), rar_low);
-    E1000_WRITE_REG_ARRAY(shared, RA, ((index << 1) + 1), rar_high);
-    return;
-}
-
-/******************************************************************************
- * Writes a value to the specified offset in the VLAN filter table.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - Offset in VLAN filer table to write
- * value - Value to write into VLAN filter table
- *****************************************************************************/
-void
-e1000_write_vfta(struct e1000_shared_adapter *shared,
-                 uint32_t offset,
-                 uint32_t value)
-{
-    uint32_t temp;
-
-    if((shared->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
-        temp = E1000_READ_REG_ARRAY(shared, VFTA, (offset - 1));
-        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
-        E1000_WRITE_REG_ARRAY(shared, VFTA, (offset - 1), temp);
-    } else {
-        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, value);
-    }
-    return;
-}
-
-/******************************************************************************
- * Clears the VLAN filer table
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_vfta(struct e1000_shared_adapter *shared)
-{
-    uint32_t offset;
-
-    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
-        E1000_WRITE_REG_ARRAY(shared, VFTA, offset, 0);
-    return;
-}
-
-/******************************************************************************
- * Configures flow control and link settings.
- * 
- * shared - Struct containing variables accessed by shared code
- * 
- * Determines which flow control settings to use. Calls the apropriate media-
- * specific link configuration function. Configures the flow control settings.
- * Assuming the adapter has a valid link partner, a valid link should be
- * established. Assumes the hardware has previously been reset and the 
- * transmitter and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_fc_and_link(struct e1000_shared_adapter *shared)
-{
-    uint32_t ctrl_reg;
-    uint32_t eecd_reg;
-    uint32_t ctrl_ext_reg;
-    boolean_t status = TRUE;
-
-    DEBUGFUNC("e1000_setup_fc_and_link");
-
-    /* Read the SWDPIO bits and the ILOS bit out of word 0x0A in the
-     * EEPROM.  Store these bits in a variable that we will later write
-     * to the Device Control Register (CTRL).
-     */
-    eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL1_REG);
-
-    ctrl_reg =
-        (((eecd_reg & EEPROM_WORD0A_SWDPIO) << SWDPIO_SHIFT) |
-         ((eecd_reg & EEPROM_WORD0A_ILOS) << ILOS_SHIFT));
-
-    /* Set the PCI priority bit correctly in the CTRL register.  This
-     * determines if the adapter gives priority to receives, or if it
-     * gives equal priority to transmits and receives.
-     */
-    if(shared->dma_fairness)
-        ctrl_reg |= E1000_CTRL_PRIOR;
-
-    /* Read and store word 0x0F of the EEPROM. This word contains bits
-     * that determine the hardware's default PAUSE (flow control) mode,
-     * a bit that determines whether the HW defaults to enabling or
-     * disabling auto-negotiation, and the direction of the
-     * SW defined pins. If there is no SW over-ride of the flow
-     * control setting, then the variable shared->fc will
-     * be initialized based on a value in the EEPROM.
-     */
-    eecd_reg = e1000_read_eeprom(shared, EEPROM_INIT_CONTROL2_REG);
-
-    if(shared->fc > e1000_fc_full) {
-        if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == 0)
-            shared->fc = e1000_fc_none;
-        else if((eecd_reg & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
-            shared->fc = e1000_fc_tx_pause;
-        else
-            shared->fc = e1000_fc_full;
-    }
-
-    /* We want to save off the original Flow Control configuration just
-     * in case we get disconnected and then reconnected into a different
-     * hub or switch with different Flow Control capabilities.
-     */
-    shared->original_fc = shared->fc;
-
-    if(shared->mac_type == e1000_82542_rev2_0)
-        shared->fc &= (~e1000_fc_tx_pause);
-
-    if((shared->mac_type < e1000_82543) && (shared->report_tx_early == 1))
-        shared->fc &= (~e1000_fc_rx_pause);
-
-    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", shared->fc);
-
-    /* Take the 4 bits from EEPROM word 0x0F that determine the initial
-     * polarity value for the SW controlled pins, and setup the
-     * Extended Device Control reg with that info.
-     * This is needed because one of the SW controlled pins is used for
-     * signal detection.  So this should be done before e1000_setup_pcs_link()
-     * or e1000_phy_setup() is called.
-     */
-    if(shared->mac_type == e1000_82543) {
-        ctrl_ext_reg = ((eecd_reg & EEPROM_WORD0F_SWPDIO_EXT)
-                        << SWDPIO__EXT_SHIFT);
-        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-    }
-
-    /* Call the necessary subroutine to configure the link. */
-    if(shared->media_type == e1000_media_type_fiber)
-        status = e1000_setup_pcs_link(shared, ctrl_reg);
-    else
-        status = e1000_phy_setup(shared, ctrl_reg);
-
-    /* Initialize the flow control address, type, and PAUSE timer
-     * registers to their default values.  This is done even if flow
-     * control is disabled, because it does not hurt anything to
-     * initialize these registers.
-     */
-    DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
-
-    E1000_WRITE_REG(shared, FCAL, FLOW_CONTROL_ADDRESS_LOW);
-    E1000_WRITE_REG(shared, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
-    E1000_WRITE_REG(shared, FCT, FLOW_CONTROL_TYPE);
-    E1000_WRITE_REG(shared, FCTTV, shared->fc_pause_time);
-
-    /* Set the flow control receive threshold registers.  Normally,
-     * these registers will be set to a default threshold that may be
-     * adjusted later by the driver's runtime code.  However, if the
-     * ability to transmit pause frames in not enabled, then these
-     * registers will be set to 0. 
-     */
-    if(!(shared->fc & e1000_fc_tx_pause)) {
-        E1000_WRITE_REG(shared, FCRTL, 0);
-        E1000_WRITE_REG(shared, FCRTH, 0);
-    } else {
-        /* We need to set up the Receive Threshold high and low water marks
-         * as well as (optionally) enabling the transmission of XON frames.
-         */
-        if(shared->fc_send_xon) {
-            E1000_WRITE_REG(shared, FCRTL,
-                            (shared->fc_low_water | E1000_FCRTL_XONE));
-            E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
-        } else {
-            E1000_WRITE_REG(shared, FCRTL, shared->fc_low_water);
-            E1000_WRITE_REG(shared, FCRTH, shared->fc_high_water);
-        }
-    }
-    return (status);
-}
-
-/******************************************************************************
- * Sets up link for a fiber based adapter
- *
- * shared - Struct containing variables accessed by shared code
- * ctrl_reg - Current value of the device control register
- *
- * Manipulates Physical Coding Sublayer functions in order to configure
- * link. Assumes the hardware has been previously reset and the transmitter
- * and receiver are not enabled.
- *****************************************************************************/
-boolean_t
-e1000_setup_pcs_link(struct e1000_shared_adapter *shared,
-                     uint32_t ctrl_reg)
-{
-    uint32_t status_reg;
-    uint32_t tctl_reg;
-    uint32_t txcw_reg = 0;
-    uint32_t i;
-
-    DEBUGFUNC("e1000_setup_pcs_link");
-
-    /* Setup the collsion distance.  Since this is configuring the
-     * TBI it is assumed that we are in Full Duplex.
-     */
-    tctl_reg = E1000_READ_REG(shared, TCTL);
-    i = E1000_FDX_COLLISION_DISTANCE;
-    i <<= E1000_COLD_SHIFT;
-    tctl_reg |= i;
-    E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
-    /* Check for a software override of the flow control settings, and
-     * setup the device accordingly.  If auto-negotiation is enabled,
-     * then software will have to set the "PAUSE" bits to the correct
-     * value in the Tranmsit Config Word Register (TXCW) and re-start
-     * auto-negotiation.  However, if auto-negotiation is disabled,
-     * then software will have to manually configure the two flow
-     * control enable bits in the CTRL register.
-     *
-     * The possible values of the "fc" parameter are:
-     *      0:  Flow control is completely disabled
-     *      1:  Rx flow control is enabled (we can receive pause frames
-     *          but not send pause frames).
-     *      2:  Tx flow control is enabled (we can send pause frames
-     *          but we do not support receiving pause frames).
-     *      3:  Both Rx and TX flow control (symmetric) are enabled.
-     *  other:  No software override.  The flow control configuration
-     *          in the EEPROM is used.
-     */
-    switch (shared->fc) {
-    case e1000_fc_none:        /* 0 */
-        /* Flow control (RX & TX) is completely disabled by a
-         * software over-ride.
-         */
-        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD);
-        break;
-    case e1000_fc_rx_pause:    /* 1 */
-        /* RX Flow control is enabled, and TX Flow control is
-         * disabled, by a software over-ride.
-         */
-        /* Since there really isn't a way to advertise that we are
-         * capable of RX Pause ONLY, we will advertise that we
-         * support both symmetric and asymmetric RX PAUSE.  Later
-         * we will disable the adapter's ability to send PAUSE
-         * frames.
-         */
-        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-        break;
-    case e1000_fc_tx_pause:    /* 2 */
-        /* TX Flow control is enabled, and RX Flow control is
-         * disabled, by a software over-ride.
-         */
-        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
-        break;
-    case e1000_fc_full:        /* 3 */
-        /* Flow control (both RX and TX) is enabled by a software
-         * over-ride.
-         */
-        txcw_reg = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
-        break;
-    default:
-        /* We should never get here.  The value should be 0-3. */
-        DEBUGOUT("Flow control param set incorrectly\n");
-        ASSERT(0);
-        break;
-    }
-
-    /* Since auto-negotiation is enabled, take the link out of reset.
-     * (the link will be in reset, because we previously reset the
-     * chip). This will restart auto-negotiation.  If auto-neogtiation
-     * is successful then the link-up status bit will be set and the
-     * flow control enable bits (RFCE and TFCE) will be set according
-     * to their negotiated value.
-     */
-    DEBUGOUT("Auto-negotiation enabled\n");
-
-    E1000_WRITE_REG(shared, TXCW, txcw_reg);
-    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-    shared->txcw_reg = txcw_reg;
-    msec_delay(1);
-
-    /* If we have a signal then poll for a "Link-Up" indication in the
-     * Device Status Register.   Time-out if a link isn't seen in 500
-     * milliseconds seconds (Auto-negotiation should complete in less
-     * than 500 milliseconds even if the other end is doing it in SW).
-     */
-    if(!(E1000_READ_REG(shared, CTRL) & E1000_CTRL_SWDPIN1)) {
-
-        DEBUGOUT("Looking for Link\n");
-        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
-            msec_delay(10);
-            status_reg = E1000_READ_REG(shared, STATUS);
-            if(status_reg & E1000_STATUS_LU)
-                break;
-        }
-
-        if(i == (LINK_UP_TIMEOUT / 10)) {
-            /* AutoNeg failed to achieve a link, so we'll call the
-             * "CheckForLink" routine.  This routine will force the link
-             * up if we have "signal-detect".  This will allow us to
-             * communicate with non-autonegotiating link partners.
-             */
-            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
-
-            shared->autoneg_failed = 1;
-            e1000_check_for_link(shared);
-            shared->autoneg_failed = 0;
-        } else {
-            shared->autoneg_failed = 0;
-            DEBUGOUT("Valid Link Found\n");
-        }
-    } else {
-        DEBUGOUT("No Signal Detected\n");
-    }
-
-    return (TRUE);
-}
-
-/******************************************************************************
- * Configures flow control settings after link is established
- * 
- * shared - Struct containing variables accessed by shared code
- *
- * Should be called immediately after a valid link has been established.
- * Forces MAC flow control settings if link was forced. When in MII/GMII mode
- * and autonegotiation is enabled, the MAC flow control settings will be set
- * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
- * and RFCE bits will be automaticaly set to the negotiated flow control mode.
- *****************************************************************************/
-void
-e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared)
-{
-    uint16_t mii_status_reg;
-    uint16_t mii_nway_adv_reg;
-    uint16_t mii_nway_lp_ability_reg;
-    uint16_t speed;
-    uint16_t duplex;
-
-    DEBUGFUNC("e1000_config_fc_after_link_up");
-
-    /* Check for the case where we have fiber media and auto-neg failed
-     * so we had to force link.  In this case, we need to force the
-     * configuration of the MAC to match the "fc" parameter.
-     */
-    if(((shared->media_type == e1000_media_type_fiber)
-        && (shared->autoneg_failed))
-       || ((shared->media_type == e1000_media_type_copper)
-           && (!shared->autoneg))) {
-        e1000_force_mac_fc(shared);
-    }
-
-    /* Check for the case where we have copper media and auto-neg is
-     * enabled.  In this case, we need to check and see if Auto-Neg
-     * has completed, and if so, how the PHY and link partner has
-     * flow control configured.
-     */
-    if((shared->media_type == e1000_media_type_copper) && shared->autoneg) {
-        /* Read the MII Status Register and check to see if AutoNeg
-         * has completed.  We read this twice because this reg has
-         * some "sticky" (latched) bits.
-         */
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
-            /* The AutoNeg process has completed, so we now need to
-             * read both the Auto Negotiation Advertisement Register
-             * (Address 4) and the Auto_Negotiation Base Page Ability
-             * Register (Address 5) to determine how flow control was
-             * negotiated.
-             */
-            mii_nway_adv_reg = e1000_read_phy_reg(shared,
-                                                  PHY_AUTONEG_ADV);
-            mii_nway_lp_ability_reg = e1000_read_phy_reg(shared,
-                                                         PHY_LP_ABILITY);
-
-            /* Two bits in the Auto Negotiation Advertisement Register
-             * (Address 4) and two bits in the Auto Negotiation Base
-             * Page Ability Register (Address 5) determine flow control
-             * for both the PHY and the link partner.  The following
-             * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
-             * 1999, describes these PAUSE resolution bits and how flow
-             * control is determined based upon these settings.
-             * NOTE:  DC = Don't Care
-             *
-             *   LOCAL DEVICE  |   LINK PARTNER
-             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
-             *-------|---------|-------|---------|--------------------
-             *   0   |    0    |  DC   |   DC    | e1000_fc_none
-             *   0   |    1    |   0   |   DC    | e1000_fc_none
-             *   0   |    1    |   1   |    0    | e1000_fc_none
-             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-             *   1   |    0    |   0   |   DC    | e1000_fc_none
-             *   1   |   DC    |   1   |   DC    | e1000_fc_full
-             *   1   |    1    |   0   |    0    | e1000_fc_none
-             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-             *
-             */
-            /* Are both PAUSE bits set to 1?  If so, this implies
-             * Symmetric Flow Control is enabled at both ends.  The
-             * ASM_DIR bits are irrelevant per the spec.
-             *
-             * For Symmetric Flow Control:
-             *
-             *   LOCAL DEVICE  |   LINK PARTNER
-             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-             *-------|---------|-------|---------|--------------------
-             *   1   |   DC    |   1   |   DC    | e1000_fc_full
-             *
-             */
-            if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-               (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
-                /* Now we need to check if the user selected RX ONLY
-                 * of pause frames.  In this case, we had to advertise
-                 * FULL flow control because we could not advertise RX
-                 * ONLY. Hence, we must now check to see if we need to
-                 * turn OFF  the TRANSMISSION of PAUSE frames.
-                 */
-                if(shared->original_fc == e1000_fc_full) {
-                    shared->fc = e1000_fc_full;
-                    DEBUGOUT("Flow Control = FULL.\r\n");
-                } else {
-                    shared->fc = e1000_fc_rx_pause;
-                    DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
-                }
-            }
-            /* For receiving PAUSE frames ONLY.
-             *
-             *   LOCAL DEVICE  |   LINK PARTNER
-             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-             *-------|---------|-------|---------|--------------------
-             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
-             *
-             */
-            else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-                    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-                shared->fc = e1000_fc_tx_pause;
-                DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
-            }
-            /* For transmitting PAUSE frames ONLY.
-             *
-             *   LOCAL DEVICE  |   LINK PARTNER
-             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
-             *-------|---------|-------|---------|--------------------
-             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
-             *
-             */
-            else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
-                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
-                    !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
-                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
-                shared->fc = e1000_fc_rx_pause;
-                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
-            }
-            /* Per the IEEE spec, at this point flow control should be
-             * disabled.  However, we want to consider that we could
-             * be connected to a legacy switch that doesn't advertise
-             * desired flow control, but can be forced on the link
-             * partner.  So if we advertised no flow control, that is
-             * what we will resolve to.  If we advertised some kind of
-             * receive capability (Rx Pause Only or Full Flow Control)
-             * and the link partner advertised none, we will configure
-             * ourselves to enable Rx Flow Control only.  We can do
-             * this safely for two reasons:  If the link partner really
-             * didn't want flow control enabled, and we enable Rx, no
-             * harm done since we won't be receiving any PAUSE frames
-             * anyway.  If the intent on the link partner was to have
-             * flow control enabled, then by us enabling RX only, we
-             * can at least receive pause frames and process them.
-             * This is a good idea because in most cases, since we are
-             * predominantly a server NIC, more times than not we will
-             * be asked to delay transmission of packets than asking
-             * our link partner to pause transmission of frames.
-             */
-            else if(shared->original_fc == e1000_fc_none ||
-                    shared->original_fc == e1000_fc_tx_pause) {
-                shared->fc = e1000_fc_none;
-                DEBUGOUT("Flow Control = NONE.\r\n");
-            } else {
-                shared->fc = e1000_fc_rx_pause;
-                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
-            }
-
-            /* Now we need to do one last check...  If we auto-
-             * negotiated to HALF DUPLEX, flow control should not be
-             * enabled per IEEE 802.3 spec.
-             */
-            e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
-            if(duplex == HALF_DUPLEX)
-                shared->fc = e1000_fc_none;
-
-            /* Now we call a subroutine to actually force the MAC
-             * controller to use the correct flow control settings.
-             */
-            e1000_force_mac_fc(shared);
-        } else {
-            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
-        }
-    }
-    return;  
-}
-
-/******************************************************************************
- * Checks to see if the link status of the hardware has changed.
- *
- * shared - Struct containing variables accessed by shared code
- *
- * Called by any function that needs to check the link status of the adapter.
- *****************************************************************************/
-void
-e1000_check_for_link(struct e1000_shared_adapter *shared)
-{
-    uint32_t rxcw_reg;
-    uint32_t ctrl_reg;
-    uint32_t status_reg;
-    uint32_t rctl_reg;
-    uint16_t phy_data;
-    uint16_t lp_capability;
-
-    DEBUGFUNC("e1000_check_for_link");
-
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-    status_reg = E1000_READ_REG(shared, STATUS);
-    rxcw_reg = E1000_READ_REG(shared, RXCW);
-
-    /* If we have a copper PHY then we only want to go out to the PHY
-     * registers to see if Auto-Neg has completed and/or if our link
-     * status has changed.  The get_link_status flag will be set if we
-     * receive a Link Status Change interrupt or we have Rx Sequence
-     * Errors.
-     */
-    if(shared->media_type == e1000_media_type_copper
-       && shared->get_link_status) {
-        /* First we want to see if the MII Status Register reports
-         * link.  If so, then we want to get the current speed/duplex
-         * of the PHY.
-         * Read the register twice since the link bit is sticky.
-         */
-        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
-        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
-
-        if(phy_data & MII_SR_LINK_STATUS) {
-            shared->get_link_status = FALSE;
-        } else {
-            DEBUGOUT("**** CFL - No link detected. ****\r\n");
-            return;
-        }
-
-        /* If we are forcing speed/duplex, then we simply return since
-         * we have already determined whether we have link or not.
-         */
-        if(!shared->autoneg) {
-            return;
-        }
-
-        switch (shared->phy_id) {
-        case M88E1000_12_PHY_ID:
-        case M88E1000_14_PHY_ID:
-        case M88E1000_I_PHY_ID:
-            /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
-             * have Si on board that is 82544 or newer, Auto
-             * Speed Detection takes care of MAC speed/duplex
-             * configuration.  So we only need to configure Collision
-             * Distance in the MAC.  Otherwise, we need to force
-             * speed/duplex on the MAC to the current PHY speed/duplex
-             * settings.
-             */
-            if(shared->mac_type >= e1000_82544) {
-                DEBUGOUT("CFL - Auto-Neg complete.");
-                DEBUGOUT("Configuring Collision Distance.");
-                e1000_config_collision_dist(shared);
-            } else {
-                /* Read the Phy Specific Status register to get the
-                 * resolved speed/duplex settings.  Then call
-                 * e1000_config_mac_to_phy which will retrieve
-                 * PHY register information and configure the MAC to
-                 * equal the negotiated speed/duplex.
-                 */
-                phy_data = e1000_read_phy_reg(shared, 
-                                              M88E1000_PHY_SPEC_STATUS);
-
-                DEBUGOUT1("CFL - Auto-Neg complete.  phy_data = %x\r\n",
-                          phy_data);
-                e1000_config_mac_to_phy(shared, phy_data);
-            }
-
-            /* Configure Flow Control now that Auto-Neg has completed.
-             * We need to first restore the users desired Flow
-             * Control setting since we may have had to re-autoneg
-             * with a different link partner.
-             */
-            e1000_config_fc_after_link_up(shared);
-            break;
-
-        default:
-            DEBUGOUT("CFL - Invalid PHY detected.\r\n");
-
-        } /* end switch statement */
-
-        /* At this point we know that we are on copper, link is up, 
-         * and we are auto-neg'd.  These are pre-conditions for checking
-         * the link parter capabilities register.  We use the link partner
-         * capabilities to determine if TBI Compatibility needs to be turned on
-         * or turned off.  If the link partner advertises any speed in addition
-         * to Gigabit, then we assume that they are GMII-based and TBI 
-         * compatibility is not needed.
-         * If no other speeds are advertised, then we assume the link partner
-         * is TBI-based and we turn on TBI Compatibility.
-         */
-        if(shared->tbi_compatibility_en) {
-            lp_capability = e1000_read_phy_reg(shared, PHY_LP_ABILITY);
-            if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
-                                NWAY_LPAR_10T_FD_CAPS |
-                                NWAY_LPAR_100TX_HD_CAPS |
-                                NWAY_LPAR_100TX_FD_CAPS |
-                                NWAY_LPAR_100T4_CAPS)) {
-                /* If our link partner advertises below Gig, then they do not
-                 * need the special Tbi Compatibility mode. 
-                 */
-                if(shared->tbi_compatibility_on) {
-                    /* If we previously were in the mode, turn it off, now. */
-                    rctl_reg = E1000_READ_REG(shared, RCTL);
-                    rctl_reg &= ~E1000_RCTL_SBP;
-                    E1000_WRITE_REG(shared, RCTL, rctl_reg);
-                    shared->tbi_compatibility_on = FALSE;
-                }
-            } else {
-                /* If the mode is was previously off, turn it on. 
-                 * For compatibility with a suspected Tbi link partners, 
-                 * we will store bad packets.
-                 * (Certain frames have an additional byte on the end and will 
-                 * look like CRC errors to to the hardware).
-                 */
-                if(!shared->tbi_compatibility_on) {
-                    shared->tbi_compatibility_on = TRUE;
-                    rctl_reg = E1000_READ_REG(shared, RCTL);
-                    rctl_reg |= E1000_RCTL_SBP;
-                    E1000_WRITE_REG(shared, RCTL, rctl_reg);
-                }
-            }
-        }
-    } /* end if e1000_media_type_copper statement */
-    /* If we don't have link (auto-negotiation failed or link partner
-     * cannot auto-negotiate) and the cable is plugged in since we don't
-     * have Loss-Of-Signal (we HAVE a signal) and our link partner is
-     * not trying to AutoNeg with us (we are receiving idles/data
-     * then we need to force our link to connect to a non
-     * auto-negotiating link partner.  We also need to give
-     * auto-negotiation time to complete in case the cable was just
-     * plugged in.  The autoneg_failed flag does this.
-     */
-    else if((shared->media_type == e1000_media_type_fiber) &&  /* Fiber PHY */
-            (!(status_reg & E1000_STATUS_LU)) &&        /* no link and    */
-            (!(ctrl_reg & E1000_CTRL_SWDPIN1)) &&       /* we have signal */
-            (!(rxcw_reg & E1000_RXCW_C))) {     /* and rxing idle/data */
-        if(shared->autoneg_failed == 0) {      /* given AutoNeg time */
-            shared->autoneg_failed = 1;
-            return;
-        }
-
-        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
-
-        /* Disable auto-negotiation in the TXCW register */
-        E1000_WRITE_REG(shared, TXCW, (shared->txcw_reg & ~E1000_TXCW_ANE));
-
-        /* Force link-up and also force full-duplex. */
-        ctrl_reg = E1000_READ_REG(shared, CTRL);
-        ctrl_reg |= (E1000_CTRL_SLU | E1000_CTRL_FD);
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-        /* Configure Flow Control after forcing link up. */
-        e1000_config_fc_after_link_up(shared);
-
-    } else if((shared->media_type == e1000_media_type_fiber) && /* Fiber */
-              (ctrl_reg & E1000_CTRL_SLU) &&    /* we have forced link */
-              (rxcw_reg & E1000_RXCW_C)) {      /* and Rxing /C/ ordered sets */
-        /* If we are forcing link and we are receiving /C/ ordered sets,
-         * then re-enable auto-negotiation in the RXCW register and
-         * disable forced link in the Device Control register in an attempt
-         * to AutoNeg with our link partner.
-         */
-        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
-
-        /* Enable auto-negotiation in the TXCW register and stop
-         * forcing link.
-         */
-        E1000_WRITE_REG(shared, TXCW, shared->txcw_reg);
-
-        E1000_WRITE_REG(shared, CTRL, (ctrl_reg & ~E1000_CTRL_SLU));
-    }
-
-    return;
-}
-
-/******************************************************************************
- * Clears all hardware statistics counters. 
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared)
-{
-    volatile uint32_t temp_reg;
-
-    DEBUGFUNC("e1000_clear_hw_cntrs");
-
-    /* if we are stopped or resetting exit gracefully */
-    if(shared->adapter_stopped) {
-        DEBUGOUT("Exiting because the adapter is stopped!!!\n");
-        return;
-    }
-
-    temp_reg = E1000_READ_REG(shared, CRCERRS);
-    temp_reg = E1000_READ_REG(shared, SYMERRS);
-    temp_reg = E1000_READ_REG(shared, MPC);
-    temp_reg = E1000_READ_REG(shared, SCC);
-    temp_reg = E1000_READ_REG(shared, ECOL);
-    temp_reg = E1000_READ_REG(shared, MCC);
-    temp_reg = E1000_READ_REG(shared, LATECOL);
-    temp_reg = E1000_READ_REG(shared, COLC);
-    temp_reg = E1000_READ_REG(shared, DC);
-    temp_reg = E1000_READ_REG(shared, SEC);
-    temp_reg = E1000_READ_REG(shared, RLEC);
-    temp_reg = E1000_READ_REG(shared, XONRXC);
-    temp_reg = E1000_READ_REG(shared, XONTXC);
-    temp_reg = E1000_READ_REG(shared, XOFFRXC);
-    temp_reg = E1000_READ_REG(shared, XOFFTXC);
-    temp_reg = E1000_READ_REG(shared, FCRUC);
-    temp_reg = E1000_READ_REG(shared, PRC64);
-    temp_reg = E1000_READ_REG(shared, PRC127);
-    temp_reg = E1000_READ_REG(shared, PRC255);
-    temp_reg = E1000_READ_REG(shared, PRC511);
-    temp_reg = E1000_READ_REG(shared, PRC1023);
-    temp_reg = E1000_READ_REG(shared, PRC1522);
-    temp_reg = E1000_READ_REG(shared, GPRC);
-    temp_reg = E1000_READ_REG(shared, BPRC);
-    temp_reg = E1000_READ_REG(shared, MPRC);
-    temp_reg = E1000_READ_REG(shared, GPTC);
-    temp_reg = E1000_READ_REG(shared, GORCL);
-    temp_reg = E1000_READ_REG(shared, GORCH);
-    temp_reg = E1000_READ_REG(shared, GOTCL);
-    temp_reg = E1000_READ_REG(shared, GOTCH);
-    temp_reg = E1000_READ_REG(shared, RNBC);
-    temp_reg = E1000_READ_REG(shared, RUC);
-    temp_reg = E1000_READ_REG(shared, RFC);
-    temp_reg = E1000_READ_REG(shared, ROC);
-    temp_reg = E1000_READ_REG(shared, RJC);
-    temp_reg = E1000_READ_REG(shared, TORL);
-    temp_reg = E1000_READ_REG(shared, TORH);
-    temp_reg = E1000_READ_REG(shared, TOTL);
-    temp_reg = E1000_READ_REG(shared, TOTH);
-    temp_reg = E1000_READ_REG(shared, TPR);
-    temp_reg = E1000_READ_REG(shared, TPT);
-    temp_reg = E1000_READ_REG(shared, PTC64);
-    temp_reg = E1000_READ_REG(shared, PTC127);
-    temp_reg = E1000_READ_REG(shared, PTC255);
-    temp_reg = E1000_READ_REG(shared, PTC511);
-    temp_reg = E1000_READ_REG(shared, PTC1023);
-    temp_reg = E1000_READ_REG(shared, PTC1522);
-    temp_reg = E1000_READ_REG(shared, MPTC);
-    temp_reg = E1000_READ_REG(shared, BPTC);
-
-    if(shared->mac_type < e1000_82543)
-        return;
-
-    temp_reg = E1000_READ_REG(shared, ALGNERRC);
-    temp_reg = E1000_READ_REG(shared, RXERRC);
-    temp_reg = E1000_READ_REG(shared, TNCRS);
-    temp_reg = E1000_READ_REG(shared, CEXTERR);
-    temp_reg = E1000_READ_REG(shared, TSCTC);
-    temp_reg = E1000_READ_REG(shared, TSCTFC);
-    return;
-}
-
-/******************************************************************************
- * Detects the current speed and duplex settings of the hardware.
- *
- * shared - Struct containing variables accessed by shared code
- * speed - Speed of the connection
- * duplex - Duplex setting of the connection
- *****************************************************************************/
-void
-e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared,
-                           uint16_t *speed,
-                           uint16_t *duplex)
-{
-    uint32_t status_reg;
-#if DBG
-    uint16_t phy_data;
-#endif
-
-    DEBUGFUNC("e1000_get_speed_and_duplex");
-
-    /* If the adapter is stopped we don't have a speed or duplex */
-    if(shared->adapter_stopped) {
-        *speed = 0;
-        *duplex = 0;
-        return;
-    }
-
-    if(shared->mac_type >= e1000_82543) {
-        status_reg = E1000_READ_REG(shared, STATUS);
-        if(status_reg & E1000_STATUS_SPEED_1000) {
-            *speed = SPEED_1000;
-            DEBUGOUT("1000 Mbs, ");
-        } else if(status_reg & E1000_STATUS_SPEED_100) {
-            *speed = SPEED_100;
-            DEBUGOUT("100 Mbs, ");
-        } else {
-            *speed = SPEED_10;
-            DEBUGOUT("10 Mbs, ");
-        }
-
-        if(status_reg & E1000_STATUS_FD) {
-            *duplex = FULL_DUPLEX;
-            DEBUGOUT("Full Duplex\r\n");
-        } else {
-            *duplex = HALF_DUPLEX;
-            DEBUGOUT(" Half Duplex\r\n");
-        }
-    } else {
-        DEBUGOUT("1000 Mbs, Full Duplex\r\n");
-        *speed = SPEED_1000;
-        *duplex = FULL_DUPLEX;
-    }
-
-#if DBG
-    if(shared->phy_id == M88E1000_12_PHY_ID ||
-       shared->phy_id == M88E1000_14_PHY_ID ||
-       shared->phy_id == M88E1000_I_PHY_ID) {
-        /* read the phy specific status register */
-        phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-        DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", phy_data);
-        phy_data = e1000_read_phy_reg(shared, PHY_STATUS);
-        DEBUGOUT1("Phy MII Status Reg contents = %x\n", phy_data);
-        DEBUGOUT1("Device Status Reg contents = %x\n", 
-                  E1000_READ_REG(shared, STATUS));
-    }
-#endif
-    return;
-}
-
-/******************************************************************************
- * Reads a 16 bit word from the EEPROM.
- *
- * shared - Struct containing variables accessed by shared code
- * offset - offset of 16 bit word in the EEPROM to read
- *****************************************************************************/
-uint16_t
-e1000_read_eeprom(struct e1000_shared_adapter *shared,
-                  uint16_t offset)
-{
-    uint16_t data;
-
-    /*  Prepare the EEPROM for reading  */
-    e1000_setup_eeprom(shared);
-
-    /*  Send the READ command (opcode + addr)  */
-    e1000_shift_out_bits(shared, EEPROM_READ_OPCODE, 3);
-    e1000_shift_out_bits(shared, offset, 6);
-
-    /* Read the data */
-    data = e1000_shift_in_bits(shared);
-
-    /* End this read operation */
-    e1000_standby_eeprom(shared);
-
-    return (data);
-}
-
-/******************************************************************************
- * Verifies that the EEPROM has a valid checksum
- * 
- * shared - Struct containing variables accessed by shared code
- *
- * Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
- * valid.
- *****************************************************************************/
-boolean_t
-e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared)
-{
-    uint16_t checksum = 0;
-    uint16_t i;
-
-    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++)
-        checksum += e1000_read_eeprom(shared, i);
-
-    if(checksum == (uint16_t) EEPROM_SUM)
-        return (TRUE);
-    else
-        return (FALSE);
-}
-/******************************************************************************
- * Reads the adapter's part number from the EEPROM
- *
- * shared - Struct containing variables accessed by shared code
- * part_num - Adapter's part number
- *****************************************************************************/
-boolean_t
-e1000_read_part_num(struct e1000_shared_adapter *shared,
-                    uint32_t *part_num)
-{
-    uint16_t eeprom_word;
-
-    DEBUGFUNC("e1000_read_part_num");
-
-    /* Don't read the EEPROM if we are stopped */
-    if(shared->adapter_stopped) {
-        *part_num = 0;
-        return (FALSE);
-    }
-
-    /* Get word 0 from EEPROM */
-    eeprom_word = e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1));
-
-    DEBUGOUT("Read first part number word\n");
-
-    /* Save word 0 in upper half is PartNumber */
-    *part_num = (uint32_t) eeprom_word;
-    *part_num = *part_num << 16;
-
-    /* Get word 1 from EEPROM */
-    eeprom_word =
-        e1000_read_eeprom(shared, (uint16_t) (EEPROM_PBA_BYTE_1 + 1));
-
-    DEBUGOUT("Read second part number word\n");
-
-    /* Save word 1 in lower half of PartNumber */
-    *part_num |= eeprom_word;
-
-    /* read a valid part number */
-    return (TRUE);
-}
-
-void
-e1000_read_mac_addr(struct e1000_shared_adapter * shared)
-{
-    uint16_t temp, x;
-
-    for(x = 0; x < NODE_ADDRESS_SIZE; x += 2) {
-        temp = e1000_read_eeprom(shared, (uint16_t) 
-                                         (EEPROM_NODE_ADDRESS_BYTE_0 + (x/2)));
-        shared->perm_mac_addr[x] = (uint8_t) (temp & 0x00FF);
-        shared->perm_mac_addr[x+1] = (uint8_t) (temp >> 8);
-    }
-    
-    for(x = 0; x < NODE_ADDRESS_SIZE; x++)
-        shared->mac_addr[x] = shared->perm_mac_addr[x];
-}
-
-/******************************************************************************
- * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
- * 
- * shared - Struct containing variables accessed by shared code
- * frame_len - The length of the frame in question
- * mac_addr - The Ethernet destination address of the frame in question
- *****************************************************************************/
-uint32_t
-e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared,
-                       struct e1000_shared_stats *stats,
-                       uint32_t frame_len,
-                       uint8_t *mac_addr)
-{
-    uint64_t carry_bit;
-
-    /* First adjust the frame length. */
-    frame_len--;
-    /* We need to adjust the statistics counters, since the hardware
-     * counters overcount this packet as a CRC error and undercount
-     * the packet as a good packet
-     */
-    /* This packet should not be counted as a CRC error.    */
-    stats->crcerrs--;
-    /* This packet does count as a Good Packet Received.    */
-    stats->gprc++;
-
-    /* Adjust the Good Octets received counters             */
-    carry_bit = 0x80000000 & stats->gorcl;
-    stats->gorcl += frame_len;
-    /* If the high bit of Gorcl (the low 32 bits of the Good Octets
-     * Received Count) was one before the addition, 
-     * AND it is zero after, then we lost the carry out, 
-     * need to add one to Gorch (Good Octets Received Count High).
-     * This could be simplified if all environments supported 
-     * 64-bit integers.
-     */
-    if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
-        stats->gorch++;
-    /* Is this a broadcast or multicast?  Check broadcast first,
-     * since the test for a multicast frame will test positive on 
-     * a broadcast frame.
-     */
-    if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
-        /* Broadcast packet */
-        stats->bprc++;
-    else if(*mac_addr & 0x01)
-        /* Multicast packet */
-        stats->mprc++;
-
-    if(frame_len == shared->max_frame_size) {
-        /* In this case, the hardware has overcounted the number of
-         * oversize frames.
-         */
-        if(stats->roc > 0)
-            stats->roc--;
-    }
-
-    /* Adjust the bin counters when the extra byte put the frame in the
-     * wrong bin. Remember that the frame_len was adjusted above.
-     */
-    if(frame_len == 64) {
-        stats->prc64++;
-        stats->prc127--;
-    } else if(frame_len == 127) {
-        stats->prc127++;
-        stats->prc255--;
-    } else if(frame_len == 255) {
-        stats->prc255++;
-        stats->prc511--;
-    } else if(frame_len == 511) {
-        stats->prc511++;
-        stats->prc1023--;
-    } else if(frame_len == 1023) {
-        stats->prc1023++;
-        stats->prc1522--;
-    } else if(frame_len == 1522) {
-        stats->prc1522++;
-    }
-    return frame_len;
-}
-
-/******************************************************************************
- * Gets the current PCI bus type, speed, and width of the hardware
- *
- * shared - Struct containing variables accessed by shared code
- *****************************************************************************/
-void
-e1000_get_bus_info(struct e1000_shared_adapter *shared)
-{
-    uint32_t status_reg;
-
-    if(shared->mac_type < e1000_82543) {
-        shared->bus_type = e1000_bus_type_unknown;
-        shared->bus_speed = e1000_bus_speed_unknown;
-        shared->bus_width = e1000_bus_width_unknown;
-        return;
-    }
-
-    status_reg = E1000_READ_REG(shared, STATUS);
-
-    shared->bus_type = (status_reg & E1000_STATUS_PCIX_MODE) ?
-        e1000_bus_type_pcix : e1000_bus_type_pci;
-
-    if(shared->bus_type == e1000_bus_type_pci) {
-        shared->bus_speed = (status_reg & E1000_STATUS_PCI66) ?
-            e1000_bus_speed_66 : e1000_bus_speed_33;
-    } else {
-        switch (status_reg & E1000_STATUS_PCIX_SPEED) {
-        case E1000_STATUS_PCIX_SPEED_66:
-            shared->bus_speed = e1000_bus_speed_66;
-            break;
-        case E1000_STATUS_PCIX_SPEED_100:
-            shared->bus_speed = e1000_bus_speed_100;
-            break;
-        case E1000_STATUS_PCIX_SPEED_133:
-            shared->bus_speed = e1000_bus_speed_133;
-            break;
-        default:
-            shared->bus_speed = e1000_bus_speed_reserved;
-            break;
-        }
-    }
-
-    shared->bus_width = (status_reg & E1000_STATUS_BUS64) ?
-        e1000_bus_width_64 : e1000_bus_width_32;
-
-    return;
-}
diff -Nru a/drivers/net/e1000/e1000_mac.h b/drivers/net/e1000/e1000_mac.h
--- a/drivers/net/e1000/e1000_mac.h	Wed Apr  3 17:11:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1383 +0,0 @@
-/*******************************************************************************
-
-  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/1000 Family of Adapters (e1000) (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.
-
-*******************************************************************************/
-
-/* e1000_mac.h
- * Structures, enums, and macros for the MAC
- */
-
-#ifndef _E1000_MAC_H_
-#define _E1000_MAC_H_
-
-#include "e1000_osdep.h"
-
-/* Forward declarations of structures used by the shared code */
-struct e1000_shared_adapter;
-struct e1000_shared_stats;
-
-/* Enumerated types specific to the e1000 hardware */
-/* Media Access Controlers */
-typedef enum {
-    e1000_82542_rev2_0 = 0,
-    e1000_82542_rev2_1,
-    e1000_82543,
-    e1000_82544,
-    e1000_num_macs
-} e1000_mac_type;
-
-/* Media Types */
-typedef enum {
-    e1000_media_type_copper = 0,
-    e1000_media_type_fiber = 1,
-    e1000_num_media_types
-} e1000_media_type;
-
-typedef enum {
-    e1000_10_half = 0,
-    e1000_10_full = 1,
-    e1000_100_half = 2,
-    e1000_100_full = 3
-} e1000_speed_duplex_type;
-
-/* Flow Control Settings */
-typedef enum {
-    e1000_fc_none = 0,
-    e1000_fc_rx_pause = 1,
-    e1000_fc_tx_pause = 2,
-    e1000_fc_full = 3,
-    e1000_fc_default = 0xFF
-} e1000_fc_type;
-
-/* PCI bus types */
-typedef enum {
-    e1000_bus_type_unknown = 0,
-    e1000_bus_type_pci,
-    e1000_bus_type_pcix
-} e1000_bus_type;
-
-/* PCI bus speeds */
-typedef enum {
-    e1000_bus_speed_unknown = 0,
-    e1000_bus_speed_33,
-    e1000_bus_speed_66,
-    e1000_bus_speed_100,
-    e1000_bus_speed_133,
-    e1000_bus_speed_reserved
-} e1000_bus_speed;
-
-/* PCI bus widths */
-typedef enum {
-    e1000_bus_width_unknown = 0,
-    e1000_bus_width_32,
-    e1000_bus_width_64
-} e1000_bus_width;
-
-
-
-/* Function prototypes */
-/* Setup */
-void e1000_adapter_stop(struct e1000_shared_adapter *shared);
-boolean_t e1000_init_hw(struct e1000_shared_adapter *shared);
-void e1000_init_rx_addrs(struct e1000_shared_adapter *shared);
-
-/* Filters (multicast, vlan, receive) */
-void e1000_mc_addr_list_update(struct e1000_shared_adapter *shared, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
-uint32_t e1000_hash_mc_addr(struct e1000_shared_adapter *shared, uint8_t * mc_addr);
-void e1000_mta_set(struct e1000_shared_adapter *shared, uint32_t hash_value);
-void e1000_rar_set(struct e1000_shared_adapter *shared, uint8_t * mc_addr, uint32_t rar_index);
-void e1000_write_vfta(struct e1000_shared_adapter *shared, uint32_t offset, uint32_t value);
-void e1000_clear_vfta(struct e1000_shared_adapter *shared);
-
-/* Link layer setup functions */
-boolean_t e1000_setup_fc_and_link(struct e1000_shared_adapter *shared);
-boolean_t e1000_setup_pcs_link(struct e1000_shared_adapter *shared, uint32_t dev_ctrl_reg);
-void e1000_config_fc_after_link_up(struct e1000_shared_adapter *shared);
-void e1000_check_for_link(struct e1000_shared_adapter *shared);
-void e1000_get_speed_and_duplex(struct e1000_shared_adapter *shared, uint16_t * speed, uint16_t * duplex);
-
-/* EEPROM Functions */
-uint16_t e1000_read_eeprom(struct e1000_shared_adapter *shared, uint16_t reg);
-boolean_t e1000_validate_eeprom_checksum(struct e1000_shared_adapter *shared);
-
-/* Everything else */
-void e1000_clear_hw_cntrs(struct e1000_shared_adapter *shared);
-boolean_t e1000_read_part_num(struct e1000_shared_adapter *shared, uint32_t * part_num);
-void e1000_read_mac_addr(struct e1000_shared_adapter * shared);
-void e1000_get_bus_info(struct e1000_shared_adapter *shared);
-uint32_t e1000_tbi_adjust_stats(struct e1000_shared_adapter *shared, struct e1000_shared_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
-void e1000_write_pci_cfg(struct e1000_shared_adapter *shared, uint32_t reg, uint16_t * value);
-
-/* PCI Device IDs */
-#define E1000_DEV_ID_82542          0x1000
-#define E1000_DEV_ID_82543GC_FIBER  0x1001
-#define E1000_DEV_ID_82543GC_COPPER 0x1004
-#define E1000_DEV_ID_82544EI_COPPER 0x1008
-#define E1000_DEV_ID_82544EI_FIBER  0x1009
-#define E1000_DEV_ID_82544GC_COPPER 0x100C
-#define E1000_DEV_ID_82544GC_LOM    0x100D
-#define NUM_DEV_IDS 7
-
-#define NODE_ADDRESS_SIZE 6
-#define ETH_LENGTH_OF_ADDRESS 6
-
-/* MAC decode size is 128K - This is the size of BAR0 */
-#define MAC_DECODE_SIZE (128 * 1024)
-
-#define E1000_82542_2_0_REV_ID 2
-#define E1000_82542_2_1_REV_ID 3
-
-#define SPEED_10    10
-#define SPEED_100   100
-#define SPEED_1000  1000
-#define HALF_DUPLEX 1
-#define FULL_DUPLEX 2
-
-/* The sizes (in bytes) of a ethernet packet */
-#define ENET_HEADER_SIZE             14
-#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 /* Without FCS */
-#define MINIMUM_ETHERNET_PACKET_SIZE 60   /* Without FCS */
-#define CRC_LENGTH                   4
-#define MAX_JUMBO_FRAME_SIZE         0x3F00
-
-
-/* 802.1q VLAN Packet Sizes */
-#define VLAN_TAG_SIZE                     4     /* 802.3ac tag (not DMAed) */
-
-/* Ethertype field values */
-#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
-#define ETHERNET_IP_TYPE        0x0800  /* IP packets */
-#define ETHERNET_ARP_TYPE       0x0806  /* Address Resolution Protocol (ARP) */
-
-/* Packet Header defines */
-#define IP_PROTOCOL_TCP    6
-#define IP_PROTOCOL_UDP    0x11
-
-/* This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error 
- */
-#define POLL_IMS_ENABLE_MASK ( \
-    E1000_IMS_RXDMT0 |         \
-    E1000_IMS_RXSEQ)
-
-/* This defines the bits that are set in the Interrupt Mask
- * Set/Read Register.  Each bit is documented below:
- *   o RXT0   = Receiver Timer Interrupt (ring 0)
- *   o TXDW   = Transmit Descriptor Written Back
- *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
- *   o RXSEQ  = Receive Sequence Error
- *   o LSC    = Link Status Change
- */
-#define IMS_ENABLE_MASK ( \
-    E1000_IMS_RXT0   |    \
-    E1000_IMS_TXDW   |    \
-    E1000_IMS_RXDMT0 |    \
-    E1000_IMS_RXSEQ  |    \
-    E1000_IMS_LSC)
-
-/* The number of high/low register pairs in the RAR. The RAR (Receive Address
- * Registers) holds the directed and multicast addresses that we monitor. We
- * reserve one of these spots for our directed address, allowing us room for
- * E1000_RAR_ENTRIES - 1 multicast addresses. 
- */
-#define E1000_RAR_ENTRIES 16
-
-#define MIN_NUMBER_OF_DESCRIPTORS 8
-#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
-
-/* Receive Descriptor */
-struct e1000_rx_desc {
-    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
-    uint16_t length;     /* Length of data DMAed into data buffer */
-    uint16_t csum;       /* Packet checksum */
-    uint8_t status;      /* Descriptor status */
-    uint8_t errors;      /* Descriptor Errors */
-    uint16_t special;
-};
-
-/* Receive Decriptor bit definitions */
-#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
-#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
-#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
-#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
-#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
-#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
-#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
-#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
-#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
-#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
-#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
-#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
-#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
-#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
-#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
-#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
-#define E1000_RXD_SPC_PRI_SHIFT 0x000D  /* Priority is in upper 3 of 16 */
-#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
-#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
-
-/* mask to determine if packets should be dropped due to frame errors */
-#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
-    E1000_RXD_ERR_CE  |                \
-    E1000_RXD_ERR_SE  |                \
-    E1000_RXD_ERR_SEQ |                \
-    E1000_RXD_ERR_CXE |                \
-    E1000_RXD_ERR_RXE)
-
-/* Transmit Descriptor */
-struct e1000_tx_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
-    union {
-        uint32_t data;
-        struct {
-            uint16_t length;    /* Data buffer length */
-            uint8_t cso;        /* Checksum offset */
-            uint8_t cmd;        /* Descriptor control */
-        } flags;
-    } lower;
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t css;        /* Checksum start */
-            uint16_t special;
-        } fields;
-    } upper;
-};
-
-/* Transmit Descriptor bit definitions */
-#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
-#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
-#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
-#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
-#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
-#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
-#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
-#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
-#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
-#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
-#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
-#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
-#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
-#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
-#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
-#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
-#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
-#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
-#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
-#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
-
-/* Offload Context Descriptor */
-struct e1000_context_desc {
-    union {
-        uint32_t ip_config;
-        struct {
-            uint8_t ipcss;      /* IP checksum start */
-            uint8_t ipcso;      /* IP checksum offset */
-            uint16_t ipcse;     /* IP checksum end */
-        } ip_fields;
-    } lower_setup;
-    union {
-        uint32_t tcp_config;
-        struct {
-            uint8_t tucss;      /* TCP checksum start */
-            uint8_t tucso;      /* TCP checksum offset */
-            uint16_t tucse;     /* TCP checksum end */
-        } tcp_fields;
-    } upper_setup;
-    uint32_t cmd_and_length;    /* */
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t hdr_len;    /* Header length */
-            uint16_t mss;       /* Maximum segment size */
-        } fields;
-    } tcp_seg_setup;
-};
-
-/* Offload data descriptor */
-struct e1000_data_desc {
-    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
-    union {
-        uint32_t data;
-        struct {
-            uint16_t length;    /* Data buffer length */
-            uint8_t typ_len_ext;        /* */
-            uint8_t cmd;        /* */
-        } flags;
-    } lower;
-    union {
-        uint32_t data;
-        struct {
-            uint8_t status;     /* Descriptor status */
-            uint8_t popts;      /* Packet Options */
-            uint16_t special;   /* */
-        } fields;
-    } upper;
-};
-
-/* Filters */
-#define E1000_NUM_UNICAST          16   /* Unicast filter entries */
-#define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
-#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
-
-
-/* Receive Address Register */
-struct e1000_rar {
-    volatile uint32_t low;      /* receive address low */
-    volatile uint32_t high;     /* receive address high */
-};
-
-/* The number of entries in the Multicast Table Array (MTA). */
-#define E1000_NUM_MTA_REGISTERS 128
-
-/* IPv4 Address Table Entry */
-struct e1000_ipv4_at_entry {
-    volatile uint32_t ipv4_addr;        /* IP Address (RW) */
-    volatile uint32_t reserved;
-};
-
-/* Four wakeup IP addresses are supported */
-#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
-#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
-#define E1000_IP6AT_SIZE                  1
-
-/* IPv6 Address Table Entry */
-struct e1000_ipv6_at_entry {
-    volatile uint8_t ipv6_addr[16];
-};
-
-/* Flexible Filter Length Table Entry */
-struct e1000_fflt_entry {
-    volatile uint32_t length;   /* Flexible Filter Length (RW) */
-    volatile uint32_t reserved;
-};
-
-/* Flexible Filter Mask Table Entry */
-struct e1000_ffmt_entry {
-    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
-    volatile uint32_t reserved;
-};
-
-/* Flexible Filter Value Table Entry */
-struct e1000_ffvt_entry {
-    volatile uint32_t value;    /* Flexible Filter Value (RW) */
-    volatile uint32_t reserved;
-};
-
-/* Four Flexible Filters are supported */
-#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
-
-/* Each Flexible Filter is at most 128 (0x80) bytes in length */
-#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
-
-#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
-#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
-
-/* Register Set. (82543, 82544)
- *
- * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
- * These registers are physically located on the NIC, but are mapped into the 
- * host memory address space.
- *
- * RW - register is both readable and writable
- * RO - register is read only
- * WO - register is write only
- * R/clr - register is read only and is cleared when read
- * A - register array
- */
-#define E1000_CTRL     0x00000  /* Device Control - RW */
-#define E1000_STATUS   0x00008  /* Device Status - RO */
-#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
-#define E1000_EERD     0x00014  /* EEPROM Read - RW */
-#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
-#define E1000_MDIC     0x00020  /* MDI Control - RW */
-#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
-#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
-#define E1000_FCT      0x00030  /* Flow Control Type - RW */
-#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
-#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
-#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
-#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
-#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
-#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
-#define E1000_RCTL     0x00100  /* RX Control - RW */
-#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
-#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
-#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
-#define E1000_TCTL     0x00400  /* TX Control - RW */
-#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
-#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
-#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
-#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
-#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
-#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
-#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
-#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
-#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
-#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
-#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
-#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
-#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
-#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
-#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
-#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
-#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
-#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
-#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
-#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
-#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
-#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
-#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
-#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
-#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
-#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
-#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
-#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
-#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
-#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
-#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
-#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
-#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
-#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
-#define E1000_COLC     0x04028  /* Collision Count - R/clr */
-#define E1000_DC       0x04030  /* Defer Count - R/clr */
-#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
-#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
-#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
-#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
-#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
-#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
-#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
-#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
-#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
-#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
-#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
-#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
-#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
-#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
-#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
-#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
-#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
-#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
-#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
-#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
-#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
-#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
-#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
-#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
-#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
-#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
-#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
-#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
-#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
-#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
-#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
-#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
-#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
-#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
-#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
-#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
-#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
-#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
-#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
-#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
-#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
-#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
-#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
-#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
-#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
-#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
-#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
-#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
-#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
-#define E1000_RA       0x05400  /* Receive Address - RW Array */
-#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_WUC      0x05800  /* Wakeup Control - RW */
-#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
-#define E1000_WUS      0x05810  /* Wakeup Status - RO */
-#define E1000_MANC     0x05820  /* Management Control - RW */
-#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
-#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
-#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
-#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
-#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
-#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
-#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
-#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
-
-/* Register Set (82542)
- *
- * Some of the 82542 registers are located at different offsets than they are
- * in more current versions of the 8254x. Despite the difference in location,
- * the registers function in the same manner.
- */
-#define E1000_82542_CTRL     E1000_CTRL
-#define E1000_82542_STATUS   E1000_STATUS
-#define E1000_82542_EECD     E1000_EECD
-#define E1000_82542_EERD     E1000_EERD
-#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
-#define E1000_82542_MDIC     E1000_MDIC
-#define E1000_82542_FCAL     E1000_FCAL
-#define E1000_82542_FCAH     E1000_FCAH
-#define E1000_82542_FCT      E1000_FCT
-#define E1000_82542_VET      E1000_VET
-#define E1000_82542_RA       0x00040
-#define E1000_82542_ICR      E1000_ICR
-#define E1000_82542_ITR      E1000_ITR
-#define E1000_82542_ICS      E1000_ICS
-#define E1000_82542_IMS      E1000_IMS
-#define E1000_82542_IMC      E1000_IMC
-#define E1000_82542_RCTL     E1000_RCTL
-#define E1000_82542_RDTR     0x00108
-#define E1000_82542_RDBAL    0x00110
-#define E1000_82542_RDBAH    0x00114
-#define E1000_82542_RDLEN    0x00118
-#define E1000_82542_RDH      0x00120
-#define E1000_82542_RDT      0x00128
-#define E1000_82542_FCRTH    0x00160
-#define E1000_82542_FCRTL    0x00168
-#define E1000_82542_FCTTV    E1000_FCTTV
-#define E1000_82542_TXCW     E1000_TXCW
-#define E1000_82542_RXCW     E1000_RXCW
-#define E1000_82542_MTA      0x00200
-#define E1000_82542_TCTL     E1000_TCTL
-#define E1000_82542_TIPG     E1000_TIPG
-#define E1000_82542_TDBAL    0x00420
-#define E1000_82542_TDBAH    0x00424
-#define E1000_82542_TDLEN    0x00428
-#define E1000_82542_TDH      0x00430
-#define E1000_82542_TDT      0x00438
-#define E1000_82542_TIDV     0x00440
-#define E1000_82542_TBT      E1000_TBT
-#define E1000_82542_VFTA     0x00600
-#define E1000_82542_LEDCTL   E1000_LEDCTL
-#define E1000_82542_PBA      E1000_PBA
-#define E1000_82542_RXDCTL   E1000_RXDCTL
-#define E1000_82542_RADV     E1000_RADV
-#define E1000_82542_RSRPD    E1000_RSRPD
-#define E1000_82542_TXDMAC   E1000_TXDMAC
-#define E1000_82542_TXDCTL   E1000_TXDCTL
-#define E1000_82542_TADV     E1000_TADV
-#define E1000_82542_TSPMT    E1000_TSPMT
-#define E1000_82542_CRCERRS  E1000_CRCERRS
-#define E1000_82542_ALGNERRC E1000_ALGNERRC
-#define E1000_82542_SYMERRS  E1000_SYMERRS
-#define E1000_82542_RXERRC   E1000_RXERRC
-#define E1000_82542_MPC      E1000_MPC
-#define E1000_82542_SCC      E1000_SCC
-#define E1000_82542_ECOL     E1000_ECOL
-#define E1000_82542_MCC      E1000_MCC
-#define E1000_82542_LATECOL  E1000_LATECOL
-#define E1000_82542_COLC     E1000_COLC
-#define E1000_82542_DC       E1000_DC
-#define E1000_82542_TNCRS    E1000_TNCRS
-#define E1000_82542_SEC      E1000_SEC
-#define E1000_82542_CEXTERR  E1000_CEXTERR
-#define E1000_82542_RLEC     E1000_RLEC
-#define E1000_82542_XONRXC   E1000_XONRXC
-#define E1000_82542_XONTXC   E1000_XONTXC
-#define E1000_82542_XOFFRXC  E1000_XOFFRXC
-#define E1000_82542_XOFFTXC  E1000_XOFFTXC
-#define E1000_82542_FCRUC    E1000_FCRUC
-#define E1000_82542_PRC64    E1000_PRC64
-#define E1000_82542_PRC127   E1000_PRC127
-#define E1000_82542_PRC255   E1000_PRC255
-#define E1000_82542_PRC511   E1000_PRC511
-#define E1000_82542_PRC1023  E1000_PRC1023
-#define E1000_82542_PRC1522  E1000_PRC1522
-#define E1000_82542_GPRC     E1000_GPRC
-#define E1000_82542_BPRC     E1000_BPRC
-#define E1000_82542_MPRC     E1000_MPRC
-#define E1000_82542_GPTC     E1000_GPTC
-#define E1000_82542_GORCL    E1000_GORCL
-#define E1000_82542_GORCH    E1000_GORCH
-#define E1000_82542_GOTCL    E1000_GOTCL
-#define E1000_82542_GOTCH    E1000_GOTCH
-#define E1000_82542_RNBC     E1000_RNBC
-#define E1000_82542_RUC      E1000_RUC
-#define E1000_82542_RFC      E1000_RFC
-#define E1000_82542_ROC      E1000_ROC
-#define E1000_82542_RJC      E1000_RJC
-#define E1000_82542_MGTPRC   E1000_MGTPRC
-#define E1000_82542_MGTPDC   E1000_MGTPDC
-#define E1000_82542_MGTPTC   E1000_MGTPTC
-#define E1000_82542_TORL     E1000_TORL
-#define E1000_82542_TORH     E1000_TORH
-#define E1000_82542_TOTL     E1000_TOTL
-#define E1000_82542_TOTH     E1000_TOTH
-#define E1000_82542_TPR      E1000_TPR
-#define E1000_82542_TPT      E1000_TPT
-#define E1000_82542_PTC64    E1000_PTC64
-#define E1000_82542_PTC127   E1000_PTC127
-#define E1000_82542_PTC255   E1000_PTC255
-#define E1000_82542_PTC511   E1000_PTC511
-#define E1000_82542_PTC1023  E1000_PTC1023
-#define E1000_82542_PTC1522  E1000_PTC1522
-#define E1000_82542_MPTC     E1000_MPTC
-#define E1000_82542_BPTC     E1000_BPTC
-#define E1000_82542_TSCTC    E1000_TSCTC
-#define E1000_82542_TSCTFC   E1000_TSCTFC
-#define E1000_82542_RXCSUM   E1000_RXCSUM
-#define E1000_82542_WUC      E1000_WUC
-#define E1000_82542_WUFC     E1000_WUFC
-#define E1000_82542_WUS      E1000_WUS
-#define E1000_82542_MANC     E1000_MANC
-#define E1000_82542_IPAV     E1000_IPAV
-#define E1000_82542_IP4AT    E1000_IP4AT
-#define E1000_82542_IP6AT    E1000_IP6AT
-#define E1000_82542_WUPL     E1000_WUPL
-#define E1000_82542_WUPM     E1000_WUPM
-#define E1000_82542_FFLT     E1000_FFLT
-#define E1000_82542_FFMT     E1000_FFMT
-#define E1000_82542_FFVT     E1000_FFVT
-
-/* Statistics counters collected by the MAC */
-struct e1000_shared_stats {
-    uint64_t crcerrs;
-    uint64_t algnerrc;
-    uint64_t symerrs;
-    uint64_t rxerrc;
-    uint64_t mpc;
-    uint64_t scc;
-    uint64_t ecol;
-    uint64_t mcc;
-    uint64_t latecol;
-    uint64_t colc;
-    uint64_t dc;
-    uint64_t tncrs;
-    uint64_t sec;
-    uint64_t cexterr;
-    uint64_t rlec;
-    uint64_t xonrxc;
-    uint64_t xontxc;
-    uint64_t xoffrxc;
-    uint64_t xofftxc;
-    uint64_t fcruc;
-    uint64_t prc64;
-    uint64_t prc127;
-    uint64_t prc255;
-    uint64_t prc511;
-    uint64_t prc1023;
-    uint64_t prc1522;
-    uint64_t gprc;
-    uint64_t bprc;
-    uint64_t mprc;
-    uint64_t gptc;
-    uint64_t gorcl;
-    uint64_t gorch;
-    uint64_t gotcl;
-    uint64_t gotch;
-    uint64_t rnbc;
-    uint64_t ruc;
-    uint64_t rfc;
-    uint64_t roc;
-    uint64_t rjc;
-    uint64_t mgprc;
-    uint64_t mgpdc;
-    uint64_t mgptc;
-    uint64_t torl;
-    uint64_t torh;
-    uint64_t totl;
-    uint64_t toth;
-    uint64_t tpr;
-    uint64_t tpt;
-    uint64_t ptc64;
-    uint64_t ptc127;
-    uint64_t ptc255;
-    uint64_t ptc511;
-    uint64_t ptc1023;
-    uint64_t ptc1522;
-    uint64_t mptc;
-    uint64_t bptc;
-    uint64_t tsctc;
-    uint64_t tsctfc;
-};
-
-/* Structure containing variables used by the shared code (e1000_mac.c and 
- * e1000_phy.c)
- */
-struct e1000_shared_adapter {
-    uint8_t *hw_addr;
-    e1000_mac_type mac_type;
-    e1000_media_type media_type;
-    void *back;
-    e1000_fc_type fc;
-    e1000_bus_speed bus_speed;
-    e1000_bus_width bus_width;
-    e1000_bus_type bus_type;
-    uint32_t phy_id;
-    uint32_t phy_addr;
-    uint32_t original_fc;
-    uint32_t txcw_reg;
-    uint32_t autoneg_failed;
-    uint32_t max_frame_size;
-    uint32_t min_frame_size;
-    uint32_t mc_filter_type;
-    uint32_t num_mc_addrs;
-    uint16_t autoneg_advertised;
-    uint16_t pci_cmd_word;
-    uint16_t fc_high_water;
-    uint16_t fc_low_water;
-    uint16_t fc_pause_time;
-    uint16_t device_id;
-    uint16_t vendor_id;
-    uint16_t subsystem_id;
-    uint16_t subsystem_vendor_id;
-    uint8_t revision_id;
-    boolean_t disable_polarity_correction;
-    boolean_t get_link_status;
-    boolean_t tbi_compatibility_en;
-    boolean_t tbi_compatibility_on;
-    boolean_t adapter_stopped;
-    boolean_t fc_send_xon;
-    boolean_t report_tx_early;
-    uint8_t autoneg;
-    uint8_t mdix;
-    uint8_t forced_speed_duplex;
-    uint8_t wait_autoneg_complete;
-    uint8_t dma_fairness;
-    uint8_t mac_addr[NODE_ADDRESS_SIZE];
-    uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
-};
-
-
-#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
-#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
-
-/* Register Bit Masks */
-/* Device Control */
-#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
-#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
-#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
-#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
-#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
-#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
-#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
-#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
-#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
-#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
-#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
-#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
-#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
-#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
-#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
-#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
-#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
-#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
-#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
-#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
-#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
-#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
-#define E1000_CTRL_RST      0x04000000  /* Global reset */
-#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
-#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
-#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
-#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
-#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
-
-/* Device Status */
-#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
-#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
-#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
-#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
-#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
-#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
-#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
-#define E1000_STATUS_SPEED_MASK 0x000000C0
-#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
-#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
-#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
-#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
-#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
-#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
-#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
-#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
-#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
-
-/* Constants used to intrepret the masked PCI-X bus speed. */
-#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
-#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
-#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
-
-/* EEPROM/Flash Control */
-#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
-#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
-#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
-#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
-#define E1000_EECD_FWE_MASK  0x00000030 
-#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
-#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
-#define E1000_EECD_FWE_SHIFT 4
-#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
-#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
-#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
-#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
-
-/* EEPROM Read */
-#define E1000_EERD_START      0x00000001 /* Start Read */
-#define E1000_EERD_DONE       0x00000010 /* Read Done */
-#define E1000_EERD_ADDR_SHIFT 8
-#define E1000_EERD_ADDR_MASK  0x0000FF00 /* Read Address */
-#define E1000_EERD_DATA_SHIFT 16
-#define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
-
-/* Extended Device Control */
-#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
-#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
-#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
-#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
-#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
-#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
-#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
-#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
-#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
-#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
-#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
-#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
-#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
-#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
-#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
-#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
-#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
-#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
-#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
-#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
-#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
-#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
-#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
-#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
-#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
-
-/* MDI Control */
-#define E1000_MDIC_DATA_MASK 0x0000FFFF
-#define E1000_MDIC_REG_MASK  0x001F0000
-#define E1000_MDIC_REG_SHIFT 16
-#define E1000_MDIC_PHY_MASK  0x03E00000
-#define E1000_MDIC_PHY_SHIFT 21
-#define E1000_MDIC_OP_WRITE  0x04000000
-#define E1000_MDIC_OP_READ   0x08000000
-#define E1000_MDIC_READY     0x10000000
-#define E1000_MDIC_INT_EN    0x20000000
-#define E1000_MDIC_ERROR     0x40000000
-
-/* LED Control */
-#define E1000_LEDCTL_LED0_MODE_MASK  0x0000000F
-#define E1000_LEDCTL_LED0_MODE_SHIFT 0
-#define E1000_LEDCTL_LED0_IVRT       0x00000040
-#define E1000_LEDCTL_LED0_BLINK      0x00000080
-#define E1000_LEDCTL_LED1_MODE_MASK  0x00000F00
-#define E1000_LEDCTL_LED1_MODE_SHIFT 8
-#define E1000_LEDCTL_LED1_IVRT       0x00004000
-#define E1000_LEDCTL_LED1_BLINK      0x00008000
-#define E1000_LEDCTL_LED2_MODE_MASK  0x000F0000
-#define E1000_LEDCTL_LED2_MODE_SHIFT 16
-#define E1000_LEDCTL_LED2_IVRT       0x00400000
-#define E1000_LEDCTL_LED2_BLINK      0x00800000
-#define E1000_LEDCTL_LED3_MODE_MASK  0x0F000000
-#define E1000_LEDCTL_LED3_MODE_SHIFT 24
-#define E1000_LEDCTL_LED3_IVRT       0x40000000
-#define E1000_LEDCTL_LED3_BLINK      0x80000000
-
-#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
-#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
-#define E1000_LEDCTL_MODE_LINK_UP       0x2
-#define E1000_LEDCTL_MODE_ACTIVITY      0x3
-#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
-#define E1000_LEDCTL_MODE_LINK_10       0x5
-#define E1000_LEDCTL_MODE_LINK_100      0x6
-#define E1000_LEDCTL_MODE_LINK_1000     0x7
-#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
-#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
-#define E1000_LEDCTL_MODE_COLLISION     0xA
-#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
-#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
-#define E1000_LEDCTL_MODE_PAUSED        0xD
-#define E1000_LEDCTL_MODE_LED_ON        0xE
-#define E1000_LEDCTL_MODE_LED_OFF       0xF
-
-/* Receive Address */
-#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
-
-/* Interrupt Cause Read */
-#define E1000_ICR_TXDW    0x00000001    /* Transmit desc written back */
-#define E1000_ICR_TXQE    0x00000002    /* Transmit Queue empty */
-#define E1000_ICR_LSC     0x00000004    /* Link Status Change */
-#define E1000_ICR_RXSEQ   0x00000008    /* rx sequence error */
-#define E1000_ICR_RXDMT0  0x00000010    /* rx desc min. threshold (0) */
-#define E1000_ICR_RXO     0x00000040    /* rx overrun */
-#define E1000_ICR_RXT0    0x00000080    /* rx timer intr (ring 0) */
-#define E1000_ICR_MDAC    0x00000200    /* MDIO access complete */
-#define E1000_ICR_RXCFG   0x00000400    /* RX /c/ ordered set */
-#define E1000_ICR_GPI_EN0 0x00000800    /* GP Int 0 */
-#define E1000_ICR_GPI_EN1 0x00001000    /* GP Int 1 */
-#define E1000_ICR_GPI_EN2 0x00002000    /* GP Int 2 */
-#define E1000_ICR_GPI_EN3 0x00004000    /* GP Int 3 */
-#define E1000_ICR_TXD_LOW 0x00008000
-#define E1000_ICR_SRPD    0x00010000
-
-/* Interrupt Cause Set */
-#define E1000_ICS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
-#define E1000_ICS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
-#define E1000_ICS_LSC     E1000_ICR_LSC         /* Link Status Change */
-#define E1000_ICS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
-#define E1000_ICS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
-#define E1000_ICS_RXO     E1000_ICR_RXO         /* rx overrun */
-#define E1000_ICS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
-#define E1000_ICS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
-#define E1000_ICS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
-#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
-#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
-#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
-#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
-#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_ICS_SRPD    E1000_ICR_SRPD
-
-/* Interrupt Mask Set */
-#define E1000_IMS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
-#define E1000_IMS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
-#define E1000_IMS_LSC     E1000_ICR_LSC         /* Link Status Change */
-#define E1000_IMS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
-#define E1000_IMS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
-#define E1000_IMS_RXO     E1000_ICR_RXO         /* rx overrun */
-#define E1000_IMS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
-#define E1000_IMS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
-#define E1000_IMS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
-#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
-#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
-#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
-#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
-#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_IMS_SRPD    E1000_ICR_SRPD
-
-/* Interrupt Mask Clear */
-#define E1000_IMC_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
-#define E1000_IMC_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
-#define E1000_IMC_LSC     E1000_ICR_LSC         /* Link Status Change */
-#define E1000_IMC_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
-#define E1000_IMC_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
-#define E1000_IMC_RXO     E1000_ICR_RXO         /* rx overrun */
-#define E1000_IMC_RXT0    E1000_ICR_RXT0        /* rx timer intr */
-#define E1000_IMC_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
-#define E1000_IMC_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
-#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
-#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
-#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
-#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
-#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
-#define E1000_IMC_SRPD    E1000_ICR_SRPD
-
-/* Receive Control */
-#define E1000_RCTL_RST          0x00000001      /* Software reset */
-#define E1000_RCTL_EN           0x00000002      /* enable */
-#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
-#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
-#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
-#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
-#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
-#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
-#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
-#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
-#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
-#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
-#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
-#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
-#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
-#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
-#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
-#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
-#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
-#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
-#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
-#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
-#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
-/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
-#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
-#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
-#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
-#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
-#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
-#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
-#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
-#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
-#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
-
-/* Receive Descriptor */
-#define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
-#define E1000_RDT_FPDB  0x80000000      /* Flush descriptor block */
-#define E1000_RDLEN_LEN 0x0007ff80      /* descriptor length */
-#define E1000_RDH_RDH   0x0000ffff      /* receive descriptor head */
-#define E1000_RDT_RDT   0x0000ffff      /* receive descriptor tail */
-
-/* Flow Control */
-#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
-#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
-#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
-#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
-
-/* Receive Descriptor Control */
-#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
-#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
-#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
-#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
-
-/* Transmit Descriptor Control */
-#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
-#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
-#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
-#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
-#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
-
-/* Transmit Configuration Word */
-#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
-#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
-#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
-#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
-#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
-#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
-#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
-#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
-#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
-#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
-
-/* Receive Configuration Word */
-#define E1000_RXCW_CW    0x0000ffff     /* RxConfigWord mask */
-#define E1000_RXCW_NC    0x04000000     /* Receive config no carrier */
-#define E1000_RXCW_IV    0x08000000     /* Receive config invalid */
-#define E1000_RXCW_CC    0x10000000     /* Receive config change */
-#define E1000_RXCW_C     0x20000000     /* Receive config */
-#define E1000_RXCW_SYNCH 0x40000000     /* Receive config synch */
-#define E1000_RXCW_ANC   0x80000000     /* Auto-neg complete */
-
-/* Transmit Control */
-#define E1000_TCTL_RST    0x00000001    /* software reset */
-#define E1000_TCTL_EN     0x00000002    /* enable tx */
-#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
-#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
-#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
-#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
-#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
-#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
-#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
-#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
-
-/* Receive Checksum Control */
-#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
-#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
-#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
-#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
-
-/* Definitions for power management and wakeup registers */
-/* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
-#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
-
-/* Wake Up Filter Control */
-#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
-#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
-#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
-#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
-#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
-#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
-#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
-#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
-#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
-#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
-#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
-#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
-#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
-#define E1000_WUFC_FLX_OFFSET 16       /* Offset to the Flexible Filters bits */
-#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
-
-/* Wake Up Status */
-#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
-#define E1000_WUS_MAG  0x00000002 /* Magic Packet Received */
-#define E1000_WUS_EX   0x00000004 /* Directed Exact Received */
-#define E1000_WUS_MC   0x00000008 /* Directed Multicast Received */
-#define E1000_WUS_BC   0x00000010 /* Broadcast Received */
-#define E1000_WUS_ARP  0x00000020 /* ARP Request Packet Received */
-#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
-#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
-#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
-#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
-#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
-#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
-#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
-
-/* Management Control */
-#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
-#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
-#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
-#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
-#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
-#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
-#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
-#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
-#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
-#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
-                                             * Filtering */
-#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
-#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
-#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
-#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
-#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
-#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
-#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
-#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
-#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
-
-#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
-#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
-
-/* Wake Up Packet Length */
-#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
-
-#define E1000_MDALIGN          4096
-
-/* EEPROM Commands */
-#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
-#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
-#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
-#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
-#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
-
-/* EEPROM Word Offsets */
-#define EEPROM_INIT_CONTROL1_REG 0x000A
-#define EEPROM_INIT_CONTROL2_REG 0x000F
-#define EEPROM_FLASH_VERSION     0x0032
-#define EEPROM_CHECKSUM_REG      0x003F
-
-/* Mask bits for fields in Word 0x0a of the EEPROM */
-#define EEPROM_WORD0A_ILOS   0x0010
-#define EEPROM_WORD0A_SWDPIO 0x01E0
-#define EEPROM_WORD0A_LRST   0x0200
-#define EEPROM_WORD0A_FD     0x0400
-#define EEPROM_WORD0A_66MHZ  0x0800
-
-/* Mask bits for fields in Word 0x0f of the EEPROM */
-#define EEPROM_WORD0F_PAUSE_MASK 0x3000
-#define EEPROM_WORD0F_PAUSE      0x1000
-#define EEPROM_WORD0F_ASM_DIR    0x2000
-#define EEPROM_WORD0F_ANE        0x0800
-#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
-
-/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
-#define EEPROM_SUM 0xBABA
-
-/* EEPROM Map defines (WORD OFFSETS)*/
-#define EEPROM_NODE_ADDRESS_BYTE_0 0
-#define EEPROM_PBA_BYTE_1          8
-
-/* EEPROM Map Sizes (Byte Counts) */
-#define PBA_SIZE 4
-
-/* Collision related configuration parameters */
-#define E1000_COLLISION_THRESHOLD       16
-#define E1000_CT_SHIFT                  4
-#define E1000_FDX_COLLISION_DISTANCE    64
-#define E1000_HDX_COLLISION_DISTANCE    64
-#define E1000_GB_HDX_COLLISION_DISTANCE 512
-#define E1000_COLD_SHIFT                12
-
-/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
-#define REQ_TX_DESCRIPTOR_MULTIPLE  8
-#define REQ_RX_DESCRIPTOR_MULTIPLE  8
-
-/* Default values for the transmit IPG register */
-#define DEFAULT_82542_TIPG_IPGT        10
-#define DEFAULT_82543_TIPG_IPGT_FIBER  9
-#define DEFAULT_82543_TIPG_IPGT_COPPER 8
-
-#define E1000_TIPG_IPGT_MASK  0x000003FF
-#define E1000_TIPG_IPGR1_MASK 0x000FFC00
-#define E1000_TIPG_IPGR2_MASK 0x3FF00000
-
-#define DEFAULT_82542_TIPG_IPGR1 2
-#define DEFAULT_82543_TIPG_IPGR1 8
-#define E1000_TIPG_IPGR1_SHIFT  10
-
-#define DEFAULT_82542_TIPG_IPGR2 10
-#define DEFAULT_82543_TIPG_IPGR2 6
-#define E1000_TIPG_IPGR2_SHIFT  20
-
-#define E1000_TXDMAC_DPP 0x00000001
-
-/* PBA constants */
-#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
-#define E1000_PBA_24K 0x0018
-#define E1000_PBA_40K 0x0028
-#define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
-
-/* Flow Control Constants */
-#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
-#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
-#define FLOW_CONTROL_TYPE         0x8808
-
-/* The historical defaults for the flow control values are given below. */
-#define FC_DEFAULT_HI_THRESH        (0x8000)    /* 32KB */
-#define FC_DEFAULT_LO_THRESH        (0x4000)    /* 16KB */
-#define FC_DEFAULT_TX_TIMER         (0x100)     /* ~130 us */
-
-
-/* The number of bits that we need to shift right to move the "pause"
- * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
- * in the TXCW register 
- */
-#define PAUSE_SHIFT 5
-
-/* The number of bits that we need to shift left to move the "SWDPIO"
- * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
- * in the CTRL register 
- */
-#define SWDPIO_SHIFT 17
-
-/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
- * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
- * Extended CTRL register.
- * in the CTRL register 
- */
-#define SWDPIO__EXT_SHIFT 4
-
-/* The number of bits that we need to shift left to move the "ILOS"
- * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
- * in the CTRL register 
- */
-#define ILOS_SHIFT  3
-
-
-#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
-
-/* The number of milliseconds we wait for auto-negotiation to complete */
-#define LINK_UP_TIMEOUT             500
-
-#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
-
-/* The carrier extension symbol, as received by the NIC. */
-#define CARRIER_EXTENSION   0x0F
-
-/* TBI_ACCEPT macro definition:
- *
- * If Tbi Compatibility mode is turned-on, then we should accept frames with
- * receive errors if and only if:
- *      1) errors is equal to the CRC error bit.
- *      2) The last byte is a Carrier extension (0x0F).
- *      3) The frame length (as reported by Hardware) is greater than 64 (60
- *         if a VLAN tag was stripped from the frame.
- *      4) "    "     "      "   "       "   "        <= max_frame_size+1.
- *
- * This macro requires:
- *      adapter = a pointer to struct e1000_shared_adapter 
- *      special = the 16 bit special field of the RX descriptor with EOP set
- *      error = the 8 bit error field of the RX descriptor with EOP set
- *      length = the sum of all the length fields of the RX descriptors that
- *               make up the current frame
- *      last_byte = the last byte of the frame DMAed by the hardware
- *      max_frame_length = the maximum frame length we want to accept.
- *      min_frame_length = the minimum frame length we want to accept.
- *
- * This macro is a conditional that should be used in the interrupt 
- * handler's Rx processing routine when RxErrors have been detected.
- *
- * Typical use:
- *  ...
- *  if (TBI_ACCEPT) {
- *      accept_frame = TRUE;
- *      e1000_tbi_adjust_stats(adapter, MacAddress);
- *      frame_length--;
- *  } else {
- *      accept_frame = FALSE;
- *  }
- *  ...
- */
-
-#define TBI_ACCEPT(adapter, special, errors, length, last_byte) \
-    ((adapter)->tbi_compatibility_on && \
-     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
-     ((last_byte) == CARRIER_EXTENSION) && \
-     ((length) <= ((adapter)->max_frame_size + 1)) && \
-     ((length) > ((special == 0x0000) ? \
-		  ((adapter)->min_frame_size) : \
-		  ((adapter)->min_frame_size - VLAN_TAG_SIZE))))
-
-
-#endif /* _E1000_MAC_H_ */
diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/e1000/e1000_main.c	Wed Apr  3 17:11:15 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
@@ -76,11 +75,8 @@
 #include "e1000.h"
 
 char e1000_driver_name[] = "e1000";
-
 char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-
-char e1000_driver_version[] = "4.2.4-k2";
-
+char e1000_driver_version[] = "4.2.8";
 char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
 
 /* e1000_pci_tbl - PCI Device ID Table
@@ -100,6 +96,7 @@
 	{0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
 	{0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
 	{0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
+	{0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
 	/* Compaq Gigabit Ethernet Server Adapter */
 	{0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
 	{0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
@@ -116,6 +113,7 @@
 	{0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	/* required last entry */
 	{0,}
 };
@@ -132,6 +130,8 @@
 
 int e1000_up(struct e1000_adapter *adapter);
 void e1000_down(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+
 static int e1000_init_module(void);
 static void e1000_exit_module(void);
 static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -164,13 +164,17 @@
 static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
 static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
 static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
-static void e1000_reset(struct e1000_adapter *adapter);
 static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
 static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
 static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
                                      struct e1000_rx_desc *rx_desc,
                                      struct sk_buff *skb);
 void e1000_enable_WOL(struct e1000_adapter *adapter);
+#ifdef NETIF_F_HW_VLAN_TX
+static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+#endif
 
 /* Exported from other modules */
 
@@ -192,6 +196,7 @@
 MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
 MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
 MODULE_LICENSE("Dual BSD/GPL");
+EXPORT_NO_SYMBOLS;
 
 /**
  * e1000_init_module - Driver Registration Routine
@@ -224,8 +229,6 @@
 e1000_exit_module(void)
 {
 	pci_unregister_driver(&e1000_driver);
-
-	return;
 }
 
 module_exit(e1000_exit_module);
@@ -249,8 +252,6 @@
 	e1000_configure_rx(adapter);
 	e1000_alloc_rx_buffers(adapter);
 
-	e1000_clear_hw_cntrs(&adapter->shared);
-
 	mod_timer(&adapter->watchdog_timer, jiffies);
 	e1000_irq_enable(adapter);
 
@@ -260,74 +261,41 @@
 void
 e1000_down(struct e1000_adapter *adapter)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
 	struct net_device *netdev = adapter->netdev;
 
 	e1000_irq_disable(adapter);
 	free_irq(netdev->irq, netdev);
 	del_timer_sync(&adapter->watchdog_timer);
 	del_timer_sync(&adapter->phy_info_timer);
+	adapter->link_speed = 0;
+	adapter->link_duplex = 0;
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 
-	/* disable the transmit and receive units */
-
-	E1000_WRITE_REG(shared, RCTL, 0);
-	E1000_WRITE_REG(shared, TCTL, E1000_TCTL_PSP);
-
-	/* delay to allow PCI transactions to complete */
-
-	msec_delay(10);
-
+	e1000_reset(adapter);
 	e1000_clean_tx_ring(adapter);
 	e1000_clean_rx_ring(adapter);
-
-	e1000_reset(adapter);
 }
 
-static void
+void
 e1000_reset(struct e1000_adapter *adapter)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
-	uint32_t ctrl_ext;
-
 	/* Repartition Pba for greater than 9k mtu
 	 * To take effect CTRL.RST is required.
 	 */
 
 	if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
-		E1000_WRITE_REG(shared, PBA, E1000_JUMBO_PBA);
+		E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
 	else
-		E1000_WRITE_REG(shared, PBA, E1000_DEFAULT_PBA);
-
-	/* 82542 2.0 needs MWI disabled while issuing a reset */
-
-	if(shared->mac_type == e1000_82542_rev2_0)
-		e1000_enter_82542_rst(adapter);
-
-	/* global reset */
-
-	E1000_WRITE_REG(shared, CTRL, E1000_CTRL_RST);
-	msec_delay(10);
-
-	/* EEPROM reload */
-
-	ctrl_ext = E1000_READ_REG(shared, CTRL_EXT);
-	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
-	E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext);
-	msec_delay(5);
-
-	if(shared->mac_type == e1000_82542_rev2_0)
-		e1000_leave_82542_rst(adapter);
+		E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
 
-	shared->tbi_compatibility_on = FALSE;
-	shared->fc = shared->original_fc;
-
-	e1000_init_hw(shared);
+	adapter->hw.fc = adapter->hw.original_fc;
+	e1000_reset_hw(&adapter->hw);
+	e1000_init_hw(&adapter->hw);
+	e1000_reset_adaptive(&adapter->hw);
+	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
 
 	e1000_enable_WOL(adapter);
-
-	return;
 }
 
 /**
@@ -382,13 +350,13 @@
 	adapter = netdev->priv;
 	adapter->netdev = netdev;
 	adapter->pdev = pdev;
-	adapter->shared.back = adapter;
+	adapter->hw.back = adapter;
 
 	mmio_start = pci_resource_start(pdev, BAR_0);
 	mmio_len = pci_resource_len(pdev, BAR_0);
 
-	adapter->shared.hw_addr = ioremap(mmio_start, mmio_len);
-	if(!adapter->shared.hw_addr)
+	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	if(!adapter->hw.hw_addr)
 		goto err_ioremap;
 
 	netdev->open = &e1000_open;
@@ -401,6 +369,11 @@
 	netdev->do_ioctl = &e1000_ioctl;
 	netdev->tx_timeout = &e1000_tx_timeout;
 	netdev->watchdog_timeo = HZ;
+#ifdef NETIF_F_HW_VLAN_TX
+	netdev->vlan_rx_register = e1000_vlan_rx_register;
+	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+#endif
 
 	netdev->irq = pdev->irq;
 	netdev->base_addr = mmio_start;
@@ -412,8 +385,16 @@
 
 	e1000_sw_init(adapter);
 
-	if(adapter->shared.mac_type >= e1000_82543) {
+	if(adapter->hw.mac_type >= e1000_82543) {
+#ifdef NETIF_F_HW_VLAN_TX
+		netdev->features = NETIF_F_SG |
+			           NETIF_F_HW_CSUM |
+		       	           NETIF_F_HW_VLAN_TX |
+		                   NETIF_F_HW_VLAN_RX |
+				   NETIF_F_HW_VLAN_FILTER;
+#else
 		netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM;
+#endif
 	} else {
 		netdev->features = NETIF_F_SG;
 	}
@@ -423,19 +404,28 @@
 
 	/* make sure the EEPROM is good */
 
-	if(!e1000_validate_eeprom_checksum(&adapter->shared))
+	if(e1000_validate_eeprom_checksum(&adapter->hw) < 0)
 		goto err_eeprom;
 
 	/* copy the MAC address out of the EEPROM */
 
-	e1000_read_mac_addr(&adapter->shared);
-	memcpy(netdev->dev_addr, adapter->shared.mac_addr, netdev->addr_len);
+	e1000_read_mac_addr(&adapter->hw);
+	memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
 
 	if(!is_valid_ether_addr(netdev->dev_addr))
 		goto err_eeprom;
 
-	e1000_read_part_num(&adapter->shared, &(adapter->part_num));
-	e1000_get_bus_info(&adapter->shared);
+	e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+
+	e1000_get_bus_info(&adapter->hw);
+
+	if((adapter->hw.mac_type == e1000_82544) &&
+	   (adapter->hw.bus_type == e1000_bus_type_pcix))
+
+		adapter->max_data_per_txd = 4096;
+	else
+		adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
+
 
 	init_timer(&adapter->watchdog_timer);
 	adapter->watchdog_timer.function = &e1000_watchdog;
@@ -464,7 +454,7 @@
 	return 0;
 
 err_eeprom:
-	iounmap(adapter->shared.hw_addr);
+	iounmap(adapter->hw.hw_addr);
 err_ioremap:
 	pci_release_regions(pdev);
 	kfree(netdev);
@@ -480,10 +470,6 @@
  * that it should release a PCI device.  The could be caused by a
  * Hot-Plug event, or because the driver is going to be removed from
  * memory.
- *
- * This routine is also called to clean up from a failure in
- * e1000_probe.  The Adapter struct and netdev will always exist,
- * all other pointers must be checked for NULL before freeing.
  **/
 
 static void __devexit
@@ -494,15 +480,14 @@
 
 	unregister_netdev(netdev);
 
-	e1000_phy_hw_reset(&adapter->shared);
+	e1000_phy_hw_reset(&adapter->hw);
 
 	e1000_proc_dev_free(adapter);
 
-	iounmap(adapter->shared.hw_addr);
+	iounmap(adapter->hw.hw_addr);
 	pci_release_regions(pdev);
 
 	kfree(netdev);
-	return;
 }
 
 /**
@@ -517,17 +502,17 @@
 static void __devinit
 e1000_sw_init(struct e1000_adapter *adapter)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
 	struct pci_dev *pdev = adapter->pdev;
 
 	/* PCI config space info */
 
-	uint16_t *vendor = &shared->vendor_id;
-	uint16_t *device = &shared->device_id;
-	uint16_t *subvendor = &shared->subsystem_vendor_id;
-	uint16_t *subsystem = &shared->subsystem_id;
-	uint8_t  *revision  = &shared->revision_id;
+	uint16_t *vendor = &hw->vendor_id;
+	uint16_t *device = &hw->device_id;
+	uint16_t *subvendor = &hw->subsystem_vendor_id;
+	uint16_t *subsystem = &hw->subsystem_id;
+	uint8_t  *revision  = &hw->revision_id;
 
 	pci_read_config_word(pdev, PCI_VENDOR_ID, vendor);
 	pci_read_config_word(pdev, PCI_DEVICE_ID, device);
@@ -535,11 +520,12 @@
 	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, subvendor);
 	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, subsystem);
 
-	pci_read_config_word(pdev, PCI_COMMAND, &shared->pci_cmd_word);
+	pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
 
 	adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-	shared->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + CRC_LENGTH;
-	shared->min_frame_size = MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH;
+	hw->max_frame_size = netdev->mtu +
+	                         ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
 
 	/* identify the MAC */
 
@@ -547,25 +533,28 @@
 	case E1000_DEV_ID_82542:
 		switch (*revision) {
 		case E1000_82542_2_0_REV_ID:
-			shared->mac_type = e1000_82542_rev2_0;
+			hw->mac_type = e1000_82542_rev2_0;
 			break;
 		case E1000_82542_2_1_REV_ID:
-			shared->mac_type = e1000_82542_rev2_1;
+			hw->mac_type = e1000_82542_rev2_1;
 			break;
 		default:
-			shared->mac_type = e1000_82542_rev2_0;
+			hw->mac_type = e1000_82542_rev2_0;
 			E1000_ERR("Could not identify 82542 revision\n");
 		}
 		break;
 	case E1000_DEV_ID_82543GC_FIBER:
 	case E1000_DEV_ID_82543GC_COPPER:
-		shared->mac_type = e1000_82543;
+		hw->mac_type = e1000_82543;
 		break;
 	case E1000_DEV_ID_82544EI_COPPER:
 	case E1000_DEV_ID_82544EI_FIBER:
 	case E1000_DEV_ID_82544GC_COPPER:
 	case E1000_DEV_ID_82544GC_LOM:
-		shared->mac_type = e1000_82544;
+		hw->mac_type = e1000_82544;
+		break;
+	case E1000_DEV_ID_82540EM:
+		hw->mac_type = e1000_82540;
 		break;
 	default:
 		/* should never have loaded on this device */
@@ -574,33 +563,35 @@
 
 	/* flow control settings */
 
-	shared->fc_high_water = FC_DEFAULT_HI_THRESH;
-	shared->fc_low_water = FC_DEFAULT_LO_THRESH;
-	shared->fc_pause_time = FC_DEFAULT_TX_TIMER;
-	shared->fc_send_xon = 1;
+	hw->fc_high_water = FC_DEFAULT_HI_THRESH;
+	hw->fc_low_water = FC_DEFAULT_LO_THRESH;
+	hw->fc_pause_time = FC_DEFAULT_TX_TIMER;
+	hw->fc_send_xon = 1;
 
 	/* Media type - copper or fiber */
 
-	if(shared->mac_type >= e1000_82543) {
-		uint32_t status = E1000_READ_REG(shared, STATUS);
+	if(hw->mac_type >= e1000_82543) {
+		uint32_t status = E1000_READ_REG(hw, STATUS);
 
 		if(status & E1000_STATUS_TBIMODE)
-			shared->media_type = e1000_media_type_fiber;
+			hw->media_type = e1000_media_type_fiber;
 		else
-			shared->media_type = e1000_media_type_copper;
+			hw->media_type = e1000_media_type_copper;
 	} else {
-		shared->media_type = e1000_media_type_fiber;
+		hw->media_type = e1000_media_type_fiber;
 	}
 
-	if(shared->mac_type < e1000_82543)
-		shared->report_tx_early = 0;
+	if(hw->mac_type < e1000_82543)
+		hw->report_tx_early = 0;
 	else
-		shared->report_tx_early = 1;
+		hw->report_tx_early = 1;
 
-	shared->wait_autoneg_complete = FALSE;
-	shared->tbi_compatibility_en = TRUE;
+	hw->wait_autoneg_complete = FALSE;
+	hw->tbi_compatibility_en = TRUE;
+	hw->adaptive_ifs = TRUE;
 
 	atomic_set(&adapter->irq_sem, 1);
+	spin_lock_init(&adapter->tx_lock);
 	spin_lock_init(&adapter->stats_lock);
 }
 
@@ -677,9 +668,6 @@
  * @adapter: board private structure
  *
  * Return 0 on success, negative on failure
- *
- * e1000_setup_tx_resources allocates all software transmit resources
- * and enabled the Tx unit of the MAC.
  **/
 
 static int
@@ -708,7 +696,6 @@
 	}
 	memset(txdr->desc, 0, txdr->size);
 
-	atomic_set(&txdr->unused, txdr->count);
 	txdr->next_to_use = 0;
 	txdr->next_to_clean = 0;
 
@@ -729,19 +716,19 @@
 	uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
 	uint32_t tctl, tipg;
 
-	E1000_WRITE_REG(&adapter->shared, TDBAL, (tdba & 0x00000000FFFFFFFF));
-	E1000_WRITE_REG(&adapter->shared, TDBAH, (tdba >> 32));
+	E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000FFFFFFFF));
+	E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
 
-	E1000_WRITE_REG(&adapter->shared, TDLEN, tdlen);
+	E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
 
 	/* Setup the HW Tx Head and Tail descriptor pointers */
 
-	E1000_WRITE_REG(&adapter->shared, TDH, 0);
-	E1000_WRITE_REG(&adapter->shared, TDT, 0);
+	E1000_WRITE_REG(&adapter->hw, TDH, 0);
+	E1000_WRITE_REG(&adapter->hw, TDT, 0);
 
 	/* Set the default values for the Tx Inter Packet Gap timer */
 
-	switch (adapter->shared.mac_type) {
+	switch (adapter->hw.mac_type) {
 	case e1000_82542_rev2_0:
 	case e1000_82542_rev2_1:
 		tipg = DEFAULT_82542_TIPG_IPGT;
@@ -749,53 +736,45 @@
 		tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
 		break;
 	default:
-		if(adapter->shared.media_type == e1000_media_type_fiber)
+		if(adapter->hw.media_type == e1000_media_type_fiber)
 			tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
 		else
 			tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
 		tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
 		tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
 	}
-	E1000_WRITE_REG(&adapter->shared, TIPG, tipg);
+	E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
 
 	/* Set the Tx Interrupt Delay register */
 
-	E1000_WRITE_REG(&adapter->shared, TIDV, adapter->tx_int_delay);
+	E1000_WRITE_REG(&adapter->hw, TIDV, 64);
 
 	/* Program the Transmit Control Register */
 
-	tctl = E1000_TCTL_PSP | E1000_TCTL_EN |
+	tctl = E1000_READ_REG(&adapter->hw, TCTL);
+
+	tctl &= ~E1000_TCTL_CT;	
+	tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
 	       (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
 
-	if(adapter->link_duplex == FULL_DUPLEX) {
-		tctl |= E1000_FDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-	} else {
-		tctl |= E1000_HDX_COLLISION_DISTANCE << E1000_COLD_SHIFT;
-	}
+	E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
 
-	E1000_WRITE_REG(&adapter->shared, TCTL, tctl);
+	e1000_config_collision_dist(&adapter->hw);
 
 	/* Setup Transmit Descriptor Settings for this adapter */
-	adapter->txd_cmd = E1000_TXD_CMD_IFCS;
+	adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
 
-	if(adapter->tx_int_delay > 0)
-		adapter->txd_cmd |= E1000_TXD_CMD_IDE;
-	if(adapter->shared.report_tx_early == 1)
+	if(adapter->hw.report_tx_early == 1)
 		adapter->txd_cmd |= E1000_TXD_CMD_RS;
 	else
 		adapter->txd_cmd |= E1000_TXD_CMD_RPS;
-
-	return;
 }
 
 /**
- * e1000_setup_rx_resources - allocate Rx resources (Descriptors, receive SKBs)
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
  * @adapter: board private structure
  *
  * Returns 0 on success, negative on failure
- *
- * e1000_setup_rx_resources allocates all software receive resources
- * and network buffers, and enables the Rx unit of the MAC.
  **/
 
 static int
@@ -826,7 +805,6 @@
 	memset(rxdr->desc, 0, rxdr->size);
 
 	rxdr->next_to_clean = 0;
-	rxdr->unused_count = rxdr->count;
 	rxdr->next_to_use = 0;
 
 	return 0;
@@ -842,18 +820,25 @@
 {
 	uint32_t rctl;
 
-	/* Setup the Receive Control Register */
-	rctl = E1000_RCTL_EN | E1000_RCTL_BAM |
-	       E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
-	       (adapter->shared.mc_filter_type << E1000_RCTL_MO_SHIFT);
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
 
-	if(adapter->shared.tbi_compatibility_on == 1)
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+	        E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+	        (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+	if(adapter->hw.tbi_compatibility_on == 1)
 		rctl |= E1000_RCTL_SBP;
+	else
+		rctl &= ~E1000_RCTL_SBP;
 
+	rctl &= ~(E1000_RCTL_SZ_4096);
 	switch (adapter->rx_buffer_len) {
 	case E1000_RXBUFFER_2048:
 	default:
 		rctl |= E1000_RCTL_SZ_2048;
+		rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
 		break;
 	case E1000_RXBUFFER_4096:
 		rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
@@ -866,7 +851,7 @@
 		break;
 	}
 
-	E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 }
 
 /**
@@ -886,38 +871,47 @@
 
 	/* make sure receives are disabled while setting up the descriptors */
 
-	rctl = E1000_READ_REG(&adapter->shared, RCTL);
-	E1000_WRITE_REG(&adapter->shared, RCTL, rctl & ~E1000_RCTL_EN);
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
 
 	/* set the Receive Delay Timer Register */
 
-	E1000_WRITE_REG(&adapter->shared, RDTR,
-	                adapter->rx_int_delay | E1000_RDT_FPDB);
+	if(adapter->hw.mac_type == e1000_82540) {
+		E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_int_delay);
+		E1000_WRITE_REG(&adapter->hw, RDTR, 64);
+
+		/* Set the interrupt throttling rate.  Value is calculated
+		 * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC        8000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+		E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+
+	} else {
+		E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+	}
 
 	/* Setup the Base and Length of the Rx Descriptor Ring */
 
-	E1000_WRITE_REG(&adapter->shared, RDBAL, (rdba & 0x00000000FFFFFFFF));
-	E1000_WRITE_REG(&adapter->shared, RDBAH, (rdba >> 32));
+	E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000FFFFFFFF));
+	E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
 
-	E1000_WRITE_REG(&adapter->shared, RDLEN, rdlen);
+	E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
 
 	/* Setup the HW Rx Head and Tail Descriptor Pointers */
-	E1000_WRITE_REG(&adapter->shared, RDH, 0);
-	E1000_WRITE_REG(&adapter->shared, RDT, 0);
+	E1000_WRITE_REG(&adapter->hw, RDH, 0);
+	E1000_WRITE_REG(&adapter->hw, RDT, 0);
 
 	/* Enable 82543 Receive Checksum Offload for TCP and UDP */
-	if((adapter->shared.mac_type >= e1000_82543) &&
+	if((adapter->hw.mac_type >= e1000_82543) &&
 	   (adapter->rx_csum == TRUE)) {
-		rxcsum = E1000_READ_REG(&adapter->shared, RXCSUM);
+		rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
 		rxcsum |= E1000_RXCSUM_TUOFL;
-		E1000_WRITE_REG(&adapter->shared, RXCSUM, rxcsum);
+		E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
 	}
 
 	/* Enable Receives */
 
-	E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
-
-	return;
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 }
 
 /**
@@ -941,8 +935,6 @@
 	                    adapter->tx_ring.desc, adapter->tx_ring.dma);
 
 	adapter->tx_ring.desc = NULL;
-
-	return;
 }
 
 /**
@@ -980,14 +972,11 @@
 
 	memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
 
-	atomic_set(&adapter->tx_ring.unused, adapter->tx_ring.count);
 	adapter->tx_ring.next_to_use = 0;
 	adapter->tx_ring.next_to_clean = 0;
 
-	E1000_WRITE_REG(&adapter->shared, TDH, 0);
-	E1000_WRITE_REG(&adapter->shared, TDT, 0);
-
-	return;
+	E1000_WRITE_REG(&adapter->hw, TDH, 0);
+	E1000_WRITE_REG(&adapter->hw, TDT, 0);
 }
 
 /**
@@ -1011,8 +1000,6 @@
 	                    adapter->rx_ring.desc, adapter->rx_ring.dma);
 
 	adapter->rx_ring.desc = NULL;
-
-	return;
 }
 
 /**
@@ -1050,14 +1037,11 @@
 
 	memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
 
-	adapter->rx_ring.unused_count = adapter->rx_ring.count;
 	adapter->rx_ring.next_to_clean = 0;
 	adapter->rx_ring.next_to_use = 0;
 
-	E1000_WRITE_REG(&adapter->shared, RDH, 0);
-	E1000_WRITE_REG(&adapter->shared, RDT, 0);
-
-	return;
+	E1000_WRITE_REG(&adapter->hw, RDH, 0);
+	E1000_WRITE_REG(&adapter->hw, RDT, 0);
 }
 
 /* The 82542 2.0 (revision 2) needs to have the receive unit in reset
@@ -1068,7 +1052,7 @@
 {
 	struct pci_dev *pdev = adapter->pdev;
 	struct net_device *netdev = adapter->netdev;
-	uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+	uint16_t pci_command_word = adapter->hw.pci_cmd_word;
 	uint32_t rctl;
 
 	if(pci_command_word & PCI_COMMAND_INVALIDATE) {
@@ -1076,14 +1060,13 @@
 		pci_write_config_word(pdev, PCI_COMMAND, pci_command_word);
 	}
 
-	rctl = E1000_READ_REG(&adapter->shared, RCTL);
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
 	rctl |= E1000_RCTL_RST;
-	E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 	msec_delay(5);
 
 	if(netif_running(netdev))
 		e1000_clean_rx_ring(adapter);
-	return;
 }
 
 static void
@@ -1091,12 +1074,12 @@
 {
 	struct pci_dev *pdev = adapter->pdev;
 	struct net_device *netdev = adapter->netdev;
-	uint16_t pci_command_word = adapter->shared.pci_cmd_word;
+	uint16_t pci_command_word = adapter->hw.pci_cmd_word;
 	uint32_t rctl;
 
-	rctl = E1000_READ_REG(&adapter->shared, RCTL);
+	rctl = E1000_READ_REG(&adapter->hw, RCTL);
 	rctl &= ~E1000_RCTL_RST;
-	E1000_WRITE_REG(&adapter->shared, RCTL, rctl);
+	E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
 	msec_delay(5);
 
 	if(pci_command_word & PCI_COMMAND_INVALIDATE)
@@ -1106,7 +1089,6 @@
 		e1000_configure_rx(adapter);
 		e1000_alloc_rx_buffers(adapter);
 	}
-	return;
 }
 
 /**
@@ -1125,15 +1107,15 @@
 
 	/* 82542 2.0 needs to be in reset to write receive address registers */
 
-	if(adapter->shared.mac_type == e1000_82542_rev2_0)
+	if(adapter->hw.mac_type == e1000_82542_rev2_0)
 		e1000_enter_82542_rst(adapter);
 
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
-	memcpy(adapter->shared.mac_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
 
-	e1000_rar_set(&adapter->shared, adapter->shared.mac_addr, 0);
+	e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
 
-	if(adapter->shared.mac_type == e1000_82542_rev2_0)
+	if(adapter->hw.mac_type == e1000_82542_rev2_0)
 		e1000_leave_82542_rst(adapter);
 
 	return 0;
@@ -1153,7 +1135,7 @@
 e1000_set_multi(struct net_device *netdev)
 {
 	struct e1000_adapter *adapter = netdev->priv;
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	struct dev_mc_list *mc_ptr;
 	uint32_t rctl;
 	uint32_t hash_value;
@@ -1161,7 +1143,7 @@
 
 	/* Check for Promiscuous and All Multicast modes */
 
-	rctl = E1000_READ_REG(shared, RCTL);
+	rctl = E1000_READ_REG(hw, RCTL);
 
 	if(netdev->flags & IFF_PROMISC) {
 		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
@@ -1172,11 +1154,11 @@
 		rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
 	}
 
-	E1000_WRITE_REG(shared, RCTL, rctl);
+	E1000_WRITE_REG(hw, RCTL, rctl);
 
 	/* 82542 2.0 needs to be in reset to write receive address registers */
 
-	if(shared->mac_type == e1000_82542_rev2_0)
+	if(hw->mac_type == e1000_82542_rev2_0)
 		e1000_enter_82542_rst(adapter);
 
 	/* load the first 15 multicast address into the exact filters 1-15
@@ -1187,29 +1169,28 @@
 
 	for(i = 1; i < E1000_RAR_ENTRIES; i++) {
 		if(mc_ptr) {
-			e1000_rar_set(shared, mc_ptr->dmi_addr, i);
+			e1000_rar_set(hw, mc_ptr->dmi_addr, i);
 			mc_ptr = mc_ptr->next;
 		} else {
-			E1000_WRITE_REG_ARRAY(shared, RA, i << 1, 0);
-			E1000_WRITE_REG_ARRAY(shared, RA, (i << 1) + 1, 0);
+			E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+			E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
 		}
 	}
 
 	/* clear the old settings from the multicast hash table */
 
 	for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
-		E1000_WRITE_REG_ARRAY(shared, MTA, i, 0);
+		E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
 
 	/* load any remaining addresses into the hash table */
 
 	for(; mc_ptr; mc_ptr = mc_ptr->next) {
-		hash_value = e1000_hash_mc_addr(shared, mc_ptr->dmi_addr);
-		e1000_mta_set(shared, hash_value);
+		hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+		e1000_mta_set(hw, hash_value);
 	}
 
-	if(shared->mac_type == e1000_82542_rev2_0)
+	if(hw->mac_type == e1000_82542_rev2_0)
 		e1000_leave_82542_rst(adapter);
-	return;
 }
 
 
@@ -1219,8 +1200,7 @@
 e1000_update_phy_info(unsigned long data)
 {
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-	e1000_phy_get_info(&adapter->shared, &adapter->phy_info);
-	return;
+	e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
 }
 
 /**
@@ -1234,11 +1214,11 @@
 	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
 	struct net_device *netdev = adapter->netdev;
 
-	e1000_check_for_link(&adapter->shared);
+	e1000_check_for_link(&adapter->hw);
 
-	if(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_LU) {
+	if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
 		if(!netif_carrier_ok(netdev)) {
-			e1000_get_speed_and_duplex(&adapter->shared,
+			e1000_get_speed_and_duplex(&adapter->hw,
 			                           &adapter->link_speed,
 			                           &adapter->link_duplex);
 
@@ -1262,171 +1242,203 @@
 			       netdev->name);
 			netif_carrier_off(netdev);
 			netif_stop_queue(netdev);
+			mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
 		}
 	}
 
 	e1000_update_stats(adapter);
+	e1000_update_adaptive(&adapter->hw);
 
 	/* Reset the timer */
 	mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
-
-	return;
 }
 
-/**
- * e1000_xmit_frame - Transmit entry point
- * @skb: buffer with frame data to transmit
- * @netdev: network interface device structure
- *
- * Returns 0 on success, 1 on error
- *
- * e1000_xmit_frame is called by the stack to initiate a transmit.
- * The out of resource condition is checked after each successful Tx
- * so that the stack can be notified, preventing the driver from
- * ever needing to drop a frame.  The atomic operations on
- * tx_ring.unused are used to syncronize with the transmit
- * interrupt processing code without the need for a spinlock.
- **/
-
-#define TXD_USE_COUNT(x) (((x) >> 12) + ((x) & 0x0fff ? 1 : 0))
-
-#define SETUP_TXD_PAGE(L, P, O) do { \
-	tx_ring->buffer_info[i].length = (L); \
-	tx_ring->buffer_info[i].dma = \
-		pci_map_page(pdev, (P), (O), (L), PCI_DMA_TODEVICE); \
-	tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); \
-	tx_desc->lower.data = cpu_to_le32(txd_lower | (L)); \
-	tx_desc->upper.data = cpu_to_le32(txd_upper); \
-} while (0)
+#define E1000_TX_FLAGS_CSUM		0x00000001
+#define E1000_TX_FLAGS_VLAN		0x00000002
+#define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT	16
 
-#define SETUP_TXD_PTR(L, P) \
-	SETUP_TXD_PAGE((L), virt_to_page(P), (unsigned long)(P) & ~PAGE_MASK)
+static inline boolean_t
+e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	struct e1000_context_desc *context_desc;
+	int i;
+	uint8_t css, cso;
 
-#define QUEUE_TXD() do { i = (i + 1) % tx_ring->count; \
-                         atomic_dec(&tx_ring->unused); } while (0)
+	if(skb->ip_summed == CHECKSUM_HW) {
+		css = skb->h.raw - skb->data;
+		cso = (skb->h.raw + skb->csum) - skb->data;
 
+		i = adapter->tx_ring.next_to_use;
+		context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
 
-static int
-e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+		context_desc->upper_setup.tcp_fields.tucss = css;
+		context_desc->upper_setup.tcp_fields.tucso = cso;
+		context_desc->upper_setup.tcp_fields.tucse = 0;
+		context_desc->tcp_seg_setup.data = 0;
+		context_desc->cmd_and_length =
+			cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+
+		i = (i + 1) % adapter->tx_ring.count;
+		adapter->tx_ring.next_to_use = i;
+
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static inline int
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
 {
-	struct e1000_adapter *adapter = netdev->priv;
 	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
-	struct pci_dev *pdev = adapter->pdev;
-	struct e1000_tx_desc *tx_desc;
-	int f, len, offset, txd_needed;
-	skb_frag_t *frag;
+	int len, offset, size, count, i;
 
-	int i = tx_ring->next_to_use;
-	uint32_t txd_upper = 0;
-	uint32_t txd_lower = adapter->txd_cmd;
+	int f;
+	len = skb->len - skb->data_len;
 
+	i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
+	count = 0;
 
-	/* If controller appears hung, force transmit timeout */
+	offset = 0;
 
-	if (time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
-	    /* If transmitting XOFFs, we're not really hung */
-	    !(E1000_READ_REG(&adapter->shared, STATUS) & E1000_STATUS_TXOFF)) {
-		adapter->trans_finish = jiffies;
-		netif_stop_queue(netdev);
-		return 1;
+	while(len) {
+		i = (i + 1) % tx_ring->count;
+		size = min(len, adapter->max_data_per_txd);
+		tx_ring->buffer_info[i].length = size;
+		tx_ring->buffer_info[i].dma =
+			pci_map_single(adapter->pdev,
+				skb->data + offset,
+				size,
+				PCI_DMA_TODEVICE);
+
+		len -= size;
+		offset += size;
+		count++;
 	}
 
-	txd_needed = TXD_USE_COUNT(skb->len - skb->data_len);
-
 	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
-		frag = &skb_shinfo(skb)->frags[f];
-		txd_needed += TXD_USE_COUNT(frag->size);
-	}
+		struct skb_frag_struct *frag;
 
-	if(skb->ip_summed == CHECKSUM_HW)
-		txd_needed += 1;
-
-	/* make sure there are enough Tx descriptors available in the ring */
+		frag = &skb_shinfo(skb)->frags[f];
+		len = frag->size;
+		offset = 0;
 
-	if(atomic_read(&tx_ring->unused) <= (txd_needed + 1)) {
-		adapter->net_stats.tx_dropped++;
-		netif_stop_queue(netdev);
-		return 1;
+		while(len) {
+			i = (i + 1) % tx_ring->count;
+			size = min(len, adapter->max_data_per_txd);
+			tx_ring->buffer_info[i].length = size;
+			tx_ring->buffer_info[i].dma =
+				pci_map_page(adapter->pdev,
+					frag->page,
+					frag->page_offset + offset,
+					size,
+					PCI_DMA_TODEVICE);
+
+			len -= size;
+			offset += size;
+			count++;
+		}
 	}
+	tx_ring->buffer_info[i].skb = skb;
 
-	if(skb->ip_summed == CHECKSUM_HW) {
-		struct e1000_context_desc *context_desc;
-		uint8_t css = skb->h.raw - skb->data;
-		uint8_t cso = (skb->h.raw + skb->csum) - skb->data;
-
-		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+	return count;
+}
 
-		context_desc->upper_setup.tcp_fields.tucss = css;
-		context_desc->upper_setup.tcp_fields.tucso = cso;
-		context_desc->upper_setup.tcp_fields.tucse = 0;
-		context_desc->tcp_seg_setup.data = 0;
-		context_desc->cmd_and_length =
-			cpu_to_le32(txd_lower | E1000_TXD_CMD_DEXT);
+static inline void
+e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+{
+	struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc = NULL;
+	uint32_t txd_upper, txd_lower;
+	int i;
 
-		QUEUE_TXD();
+	txd_upper = 0;
+	txd_lower = adapter->txd_cmd;
 
-		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+	if(tx_flags & E1000_TX_FLAGS_CSUM) {
 		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
 	}
 
-	tx_desc = E1000_TX_DESC(*tx_ring, i);
-	len = skb->len - skb->data_len;
-	offset = 0;
+	if(tx_flags & E1000_TX_FLAGS_VLAN) {
+		txd_lower |= E1000_TXD_CMD_VLE;
+		txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+	}
 
-	while(len > 4096) {
-		SETUP_TXD_PTR(4096, skb->data + offset);
-		QUEUE_TXD();
+	i = tx_ring->next_to_use;
 
+	while(count--) {
 		tx_desc = E1000_TX_DESC(*tx_ring, i);
-		len -= 4096;
-		offset += 4096;
+		tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+		tx_desc->lower.data =
+			cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
+		tx_desc->upper.data = cpu_to_le32(txd_upper);
+		i = (i + 1) % tx_ring->count;
 	}
 
-	SETUP_TXD_PTR(len, skb->data + offset);
+	tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
 
-	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
-		frag = &skb_shinfo(skb)->frags[f];
+	tx_ring->next_to_use = i;
+	E1000_WRITE_REG(&adapter->hw, TDT, i);
+}
 
-		QUEUE_TXD();
+#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
 
-		tx_desc = E1000_TX_DESC(*tx_ring, i);
-		len = frag->size;
-		offset = 0;
+static int
+e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	unsigned long flags;
+	int tx_flags = 0, count;
 
-		while(len > 4096) {
-			SETUP_TXD_PAGE(4096, frag->page,
-			               frag->page_offset + offset);
-			QUEUE_TXD();
-
-			tx_desc = E1000_TX_DESC(*tx_ring, i);
-			len -= 4096;
-			offset += 4096;
-		}
-		SETUP_TXD_PAGE(len, frag->page, frag->page_offset + offset);
-	}
+	int f;
 
-	/* EOP and SKB pointer go with the last fragment */
 
-	tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
-	tx_ring->buffer_info[i].skb = skb;
+	if(time_after(netdev->trans_start, adapter->trans_finish + HZ) &&
+	   !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) {
 
-	QUEUE_TXD();
+		adapter->trans_finish = jiffies;
+		netif_stop_queue(netdev);
+		return 1;
+	}
 
-	tx_ring->next_to_use = i;
+	count = TXD_USE_COUNT(skb->len - skb->data_len,
+	                      adapter->max_data_per_txd);
+	for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+		                       adapter->max_data_per_txd);
+	if(skb->ip_summed == CHECKSUM_HW)
+		count++;
 
-	/* Move the HW Tx Tail Pointer */
+	spin_lock_irqsave(&adapter->tx_lock, flags);
+	e1000_clean_tx_irq(adapter);
+	if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&adapter->tx_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&adapter->tx_lock, flags);
 
-	E1000_WRITE_REG(&adapter->shared, TDT, i);
+	if(e1000_tx_csum(adapter, skb))
+		tx_flags |= E1000_TX_FLAGS_CSUM;
+
+#ifdef NETIF_F_HW_VLAN_TX
+	if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= E1000_TX_FLAGS_VLAN;
+		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+	}
+#endif
+	
+	count = e1000_tx_map(adapter, skb);
+
+	e1000_tx_queue(adapter, count, tx_flags);
 
 	netdev->trans_start = jiffies;
 
 	return 0;
 }
 
-#undef TXD_USE_COUNT
-#undef SETUP_TXD
-#undef QUEUE_TXD
-
 /**
  * e1000_tx_timeout - Respond to a Tx Hang
  * @netdev: network interface device structure
@@ -1470,24 +1482,21 @@
 {
 	struct e1000_adapter *adapter = netdev->priv;
 	int old_mtu = adapter->rx_buffer_len;
-	int max_frame = new_mtu + ENET_HEADER_SIZE + CRC_LENGTH;
+	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
 
-	if((max_frame < MINIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) ||
-	   (max_frame > MAX_JUMBO_FRAME_SIZE + CRC_LENGTH)) {
+	if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+	   (max_frame > MAX_JUMBO_FRAME_SIZE)) {
 		E1000_ERR("Invalid MTU setting\n");
 		return -EINVAL;
 	}
 
-	if(max_frame <= MAXIMUM_ETHERNET_PACKET_SIZE + CRC_LENGTH) {
+	if(max_frame <= E1000_RXBUFFER_2048) {
 		adapter->rx_buffer_len = E1000_RXBUFFER_2048;
 
-	} else if(adapter->shared.mac_type < e1000_82543) {
+	} else if(adapter->hw.mac_type < e1000_82543) {
 		E1000_ERR("Jumbo Frames not supported on 82542\n");
 		return -EINVAL;
 
-	} else if(max_frame <= E1000_RXBUFFER_2048) {
-		adapter->rx_buffer_len = E1000_RXBUFFER_2048;
-
 	} else if(max_frame <= E1000_RXBUFFER_4096) {
 		adapter->rx_buffer_len = E1000_RXBUFFER_4096;
 
@@ -1501,13 +1510,11 @@
 	if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
 
 		e1000_down(adapter);
-		e1000_clean_rx_ring(adapter);
-		e1000_clean_tx_ring(adapter);
 		e1000_up(adapter);
 	}
 
 	netdev->mtu = new_mtu;
-	adapter->shared.max_frame_size = max_frame;
+	adapter->hw.max_frame_size = max_frame;
 
 	return 0;
 }
@@ -1520,8 +1527,9 @@
 static void
 e1000_update_stats(struct e1000_adapter *adapter)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	unsigned long flags;
+	uint16_t phy_tmp;
 
 #define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
 
@@ -1532,68 +1540,73 @@
 	 * be written while holding adapter->stats_lock
 	 */
 
-	adapter->stats.crcerrs += E1000_READ_REG(shared, CRCERRS);
-	adapter->stats.gprc += E1000_READ_REG(shared, GPRC);
-	adapter->stats.gorcl += E1000_READ_REG(shared, GORCL);
-	adapter->stats.gorch += E1000_READ_REG(shared, GORCH);
-	adapter->stats.bprc += E1000_READ_REG(shared, BPRC);
-	adapter->stats.mprc += E1000_READ_REG(shared, MPRC);
-	adapter->stats.roc += E1000_READ_REG(shared, ROC);
-	adapter->stats.prc64 += E1000_READ_REG(shared, PRC64);
-	adapter->stats.prc127 += E1000_READ_REG(shared, PRC127);
-	adapter->stats.prc255 += E1000_READ_REG(shared, PRC255);
-	adapter->stats.prc511 += E1000_READ_REG(shared, PRC511);
-	adapter->stats.prc1023 += E1000_READ_REG(shared, PRC1023);
-	adapter->stats.prc1522 += E1000_READ_REG(shared, PRC1522);
+	adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
+	adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
+	adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+	adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
+	adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
+	adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
+	adapter->stats.roc += E1000_READ_REG(hw, ROC);
+	adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
+	adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
+	adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
+	adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
+	adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
+	adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
 
 	spin_unlock_irqrestore(&adapter->stats_lock, flags);
 
 	/* the rest of the counters are only modified here */
 
-	adapter->stats.symerrs += E1000_READ_REG(shared, SYMERRS);
-	adapter->stats.mpc += E1000_READ_REG(shared, MPC);
-	adapter->stats.scc += E1000_READ_REG(shared, SCC);
-	adapter->stats.ecol += E1000_READ_REG(shared, ECOL);
-	adapter->stats.mcc += E1000_READ_REG(shared, MCC);
-	adapter->stats.latecol += E1000_READ_REG(shared, LATECOL);
-	adapter->stats.colc += E1000_READ_REG(shared, COLC);
-	adapter->stats.dc += E1000_READ_REG(shared, DC);
-	adapter->stats.sec += E1000_READ_REG(shared, SEC);
-	adapter->stats.rlec += E1000_READ_REG(shared, RLEC);
-	adapter->stats.xonrxc += E1000_READ_REG(shared, XONRXC);
-	adapter->stats.xontxc += E1000_READ_REG(shared, XONTXC);
-	adapter->stats.xoffrxc += E1000_READ_REG(shared, XOFFRXC);
-	adapter->stats.xofftxc += E1000_READ_REG(shared, XOFFTXC);
-	adapter->stats.fcruc += E1000_READ_REG(shared, FCRUC);
-	adapter->stats.gptc += E1000_READ_REG(shared, GPTC);
-	adapter->stats.gotcl += E1000_READ_REG(shared, GOTCL);
-	adapter->stats.gotch += E1000_READ_REG(shared, GOTCH);
-	adapter->stats.rnbc += E1000_READ_REG(shared, RNBC);
-	adapter->stats.ruc += E1000_READ_REG(shared, RUC);
-	adapter->stats.rfc += E1000_READ_REG(shared, RFC);
-	adapter->stats.rjc += E1000_READ_REG(shared, RJC);
-	adapter->stats.torl += E1000_READ_REG(shared, TORL);
-	adapter->stats.torh += E1000_READ_REG(shared, TORH);
-	adapter->stats.totl += E1000_READ_REG(shared, TOTL);
-	adapter->stats.toth += E1000_READ_REG(shared, TOTH);
-	adapter->stats.tpr += E1000_READ_REG(shared, TPR);
-	adapter->stats.tpt += E1000_READ_REG(shared, TPT);
-	adapter->stats.ptc64 += E1000_READ_REG(shared, PTC64);
-	adapter->stats.ptc127 += E1000_READ_REG(shared, PTC127);
-	adapter->stats.ptc255 += E1000_READ_REG(shared, PTC255);
-	adapter->stats.ptc511 += E1000_READ_REG(shared, PTC511);
-	adapter->stats.ptc1023 += E1000_READ_REG(shared, PTC1023);
-	adapter->stats.ptc1522 += E1000_READ_REG(shared, PTC1522);
-	adapter->stats.mptc += E1000_READ_REG(shared, MPTC);
-	adapter->stats.bptc += E1000_READ_REG(shared, BPTC);
-
-	if(adapter->shared.mac_type >= e1000_82543) {
-		adapter->stats.algnerrc += E1000_READ_REG(shared, ALGNERRC);
-		adapter->stats.rxerrc += E1000_READ_REG(shared, RXERRC);
-		adapter->stats.tncrs += E1000_READ_REG(shared, TNCRS);
-		adapter->stats.cexterr += E1000_READ_REG(shared, CEXTERR);
-		adapter->stats.tsctc += E1000_READ_REG(shared, TSCTC);
-		adapter->stats.tsctfc += E1000_READ_REG(shared, TSCTFC);
+	adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
+	adapter->stats.mpc += E1000_READ_REG(hw, MPC);
+	adapter->stats.scc += E1000_READ_REG(hw, SCC);
+	adapter->stats.ecol += E1000_READ_REG(hw, ECOL);
+	adapter->stats.mcc += E1000_READ_REG(hw, MCC);
+	adapter->stats.latecol += E1000_READ_REG(hw, LATECOL);
+	adapter->stats.dc += E1000_READ_REG(hw, DC);
+	adapter->stats.sec += E1000_READ_REG(hw, SEC);
+	adapter->stats.rlec += E1000_READ_REG(hw, RLEC);
+	adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC);
+	adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC);
+	adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC);
+	adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
+	adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
+	adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
+	adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+	adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
+	adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
+	adapter->stats.ruc += E1000_READ_REG(hw, RUC);
+	adapter->stats.rfc += E1000_READ_REG(hw, RFC);
+	adapter->stats.rjc += E1000_READ_REG(hw, RJC);
+	adapter->stats.torl += E1000_READ_REG(hw, TORL);
+	adapter->stats.torh += E1000_READ_REG(hw, TORH);
+	adapter->stats.totl += E1000_READ_REG(hw, TOTL);
+	adapter->stats.toth += E1000_READ_REG(hw, TOTH);
+	adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+	adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
+	adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
+	adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
+	adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
+	adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
+	adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+	adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
+	adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
+
+	/* used for adaptive IFS */
+
+	hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
+	adapter->stats.tpt += hw->tx_packet_delta;
+	hw->collision_delta = E1000_READ_REG(hw, COLC);
+	adapter->stats.colc += hw->collision_delta;
+
+	if(hw->mac_type >= e1000_82543) {
+		adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC);
+		adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC);
+		adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS);
+		adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR);
+		adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
+		adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
 	}
 
 	/* Fill out the OS statistics structure */
@@ -1627,14 +1640,18 @@
 
 	/* Tx Dropped needs to be maintained elsewhere */
 
-	if(adapter->shared.media_type == e1000_media_type_copper) {
-		adapter->phy_stats.idle_errors +=
-			(e1000_read_phy_reg(shared, PHY_1000T_STATUS)
-			 & PHY_IDLE_ERROR_COUNT_MASK);
-		adapter->phy_stats.receive_errors +=
-			e1000_read_phy_reg(shared, M88E1000_RX_ERR_CNTR);
+	/* Phy Stats */
+
+	if(hw->media_type == e1000_media_type_copper) {
+		if((adapter->link_speed == SPEED_1000) &&
+		   (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
+			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+			adapter->phy_stats.idle_errors += phy_tmp;
+		}
+
+		if(!e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+			adapter->phy_stats.receive_errors += phy_tmp;
 	}
-	return;
 }
 
 /**
@@ -1646,9 +1663,8 @@
 e1000_irq_disable(struct e1000_adapter *adapter)
 {
 	atomic_inc(&adapter->irq_sem);
-	E1000_WRITE_REG(&adapter->shared, IMC, ~0);
+	E1000_WRITE_REG(&adapter->hw, IMC, ~0);
 	synchronize_irq();
-	return;
 }
 
 /**
@@ -1660,8 +1676,7 @@
 e1000_irq_enable(struct e1000_adapter *adapter)
 {
 	if(atomic_dec_and_test(&adapter->irq_sem))
-		E1000_WRITE_REG(&adapter->shared, IMS, IMS_ENABLE_MASK);
-	return;
+		E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
 }
 
 /**
@@ -1679,20 +1694,23 @@
 	uint32_t icr;
 	int i = E1000_MAX_INTR;
 
-	while(i && (icr = E1000_READ_REG(&adapter->shared, ICR))) {
+	while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
 
 		if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
-			/* run the watchdog ASAP */
-			adapter->shared.get_link_status = 1;
+			adapter->hw.get_link_status = 1;
 			mod_timer(&adapter->watchdog_timer, jiffies);
 		}
 
 		e1000_clean_rx_irq(adapter);
-		e1000_clean_tx_irq(adapter);
+
+		if((icr & E1000_ICR_TXDW) && spin_trylock(&adapter->tx_lock)) {
+			e1000_clean_tx_irq(adapter);
+			spin_unlock(&adapter->tx_lock);
+		}
+
 		i--;
-	}
 
-	return;
+	}
 }
 
 /**
@@ -1726,7 +1744,7 @@
 
 		if(tx_ring->buffer_info[i].skb) {
 
-			dev_kfree_skb_irq(tx_ring->buffer_info[i].skb);
+			dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
 
 			tx_ring->buffer_info[i].skb = NULL;
 		}
@@ -1734,7 +1752,6 @@
 		memset(tx_desc, 0, sizeof(struct e1000_tx_desc));
 		mb();
 
-		atomic_inc(&tx_ring->unused);
 		i = (i + 1) % tx_ring->count;
 		tx_desc = E1000_TX_DESC(*tx_ring, i);
 
@@ -1744,11 +1761,10 @@
 	tx_ring->next_to_clean = i;
 
 	if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
-	   (atomic_read(&tx_ring->unused) > E1000_TX_QUEUE_WAKE)) {
+	   (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
 
 		netif_wake_queue(netdev);
 	}
-	return;
 }
 
 /**
@@ -1789,12 +1805,10 @@
 			E1000_DBG("Receive packet consumed multiple buffers\n");
 
 			dev_kfree_skb_irq(skb);
-			memset(rx_desc, 0, 16);
+			memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
 			mb();
 			rx_ring->buffer_info[i].skb = NULL;
 
-			rx_ring->unused_count++;
-
 			i = (i + 1) % rx_ring->count;
 
 			rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1805,12 +1819,12 @@
 
 			last_byte = *(skb->data + length - 1);
 
-			if(TBI_ACCEPT(&adapter->shared, rx_desc->special,
+			if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
 			              rx_desc->errors, length, last_byte)) {
 
 				spin_lock_irqsave(&adapter->stats_lock, flags);
 
-				e1000_tbi_adjust_stats(&adapter->shared,
+				e1000_tbi_adjust_stats(&adapter->hw,
 				                       &adapter->stats,
 				                       length, skb->data);
 
@@ -1820,11 +1834,10 @@
 			} else {
 
 				dev_kfree_skb_irq(skb);
-				memset(rx_desc, 0, 16);
+				memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
 				mb();
 				rx_ring->buffer_info[i].skb = NULL;
 
-				rx_ring->unused_count++;
 				i = (i + 1) % rx_ring->count;
 
 				rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1833,20 +1846,28 @@
 		}
 
 		/* Good Receive */
-		skb_put(skb, length - CRC_LENGTH);
+		skb_put(skb, length - ETHERNET_FCS_SIZE);
 
 		/* Receive Checksum Offload */
 		e1000_rx_checksum(adapter, rx_desc, skb);
 
 		skb->protocol = eth_type_trans(skb, netdev);
+#ifdef NETIF_F_HW_VLAN_TX
+		if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+			vlan_hwaccel_rx(skb, adapter->vlgrp,
+				(rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+		} else {
+			netif_rx(skb);
+		}
+#else
 		netif_rx(skb);
+#endif
+		netdev->last_rx = jiffies;
 
 		memset(rx_desc, 0, sizeof(struct e1000_rx_desc));
 		mb();
 		rx_ring->buffer_info[i].skb = NULL;
 
-		rx_ring->unused_count++;
-
 		i = (i + 1) % rx_ring->count;
 
 		rx_desc = E1000_RX_DESC(*rx_ring, i);
@@ -1855,8 +1876,6 @@
 	rx_ring->next_to_clean = i;
 
 	e1000_alloc_rx_buffers(adapter);
-
-	return;
 }
 
 /**
@@ -1911,16 +1930,13 @@
 
 		rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
 
-		/* move tail */
-		E1000_WRITE_REG(&adapter->shared, RDT, i);
-
-		atomic_dec(&rx_ring->unused);
+		if(!(i % E1000_RX_BUFFER_WRITE))
+			E1000_WRITE_REG(&adapter->hw, RDT, i);
 
 		i = (i + 1) % rx_ring->count;
 	}
 
 	rx_ring->next_to_use = i;
-	return;
 }
 
 /**
@@ -1954,7 +1970,7 @@
                   struct sk_buff *skb)
 {
 	/* 82543 or newer only */
-	if((adapter->shared.mac_type < e1000_82543) ||
+	if((adapter->hw.mac_type < e1000_82543) ||
 	/* Ignore Checksum bit is set */
 	(rx_desc->status & E1000_RXD_STAT_IXSM) ||
 	/* TCP Checksum has not been calculated */
@@ -1974,10 +1990,8 @@
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 		adapter->hw_csum_good++;
 	}
-	return;
 }
 
-
 /**
  * e1000_enable_WOL - Wake On Lan Support (Magic Pkt)
  * @adapter: Adapter structure
@@ -1988,29 +2002,104 @@
 {
 	uint32_t wuc;
 
-	if(adapter->shared.mac_type < e1000_82544)
+	if(adapter->hw.mac_type < e1000_82544)
 		return;
 
 	if(adapter->wol) {
 		wuc = E1000_WUC_APME | E1000_WUC_PME_EN |
 		      E1000_WUC_PME_STATUS | E1000_WUC_APMPME;
 
-		E1000_WRITE_REG(&adapter->shared, WUC, wuc);
+		E1000_WRITE_REG(&adapter->hw, WUC, wuc);
 
-		E1000_WRITE_REG(&adapter->shared, WUFC, adapter->wol);
+		E1000_WRITE_REG(&adapter->hw, WUFC, adapter->wol);
 	}
-
-	return;
 }
 
 void
-e1000_write_pci_cfg(struct e1000_shared_adapter *shared,
+e1000_write_pci_cfg(struct e1000_hw *hw,
                     uint32_t reg, uint16_t *value)
 {
-	struct e1000_adapter *adapter = shared->back;
+	struct e1000_adapter *adapter = hw->back;
 
 	pci_write_config_word(adapter->pdev, reg, *value);
-	return;
 }
+
+#ifdef NETIF_F_HW_VLAN_TX
+static void
+e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t ctrl, rctl;
+
+	e1000_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if(grp) {
+		/* enable VLAN tag insert/strip */
+
+		E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
+		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+		ctrl |= E1000_CTRL_VME;
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+		/* enable VLAN receive filtering */
+
+		rctl = E1000_READ_REG(&adapter->hw, RCTL);
+		rctl |= E1000_RCTL_VFE;
+		rctl &= ~E1000_RCTL_CFIEN;
+		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	} else {
+		/* disable VLAN tag insert/strip */
+
+		ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+		ctrl &= ~E1000_CTRL_VME;
+		E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+		/* disable VLAN filtering */
+
+		rctl = E1000_READ_REG(&adapter->hw, RCTL);
+		rctl &= ~E1000_RCTL_VFE;
+		E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+	}
+
+	e1000_irq_enable(adapter);
+}
+
+static void
+e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t vfta, index;
+
+	/* add VID to filter table */
+
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+	vfta |= (1 << (vid & 0x1F));
+	e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+	struct e1000_adapter *adapter = netdev->priv;
+	uint32_t vfta, index;
+
+	e1000_irq_disable(adapter);
+	
+	if(adapter->vlgrp)
+		adapter->vlgrp->vlan_devices[vid] = NULL;
+	
+	e1000_irq_enable(adapter);
+
+	/* remove VID from filter table*/
+
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+	vfta &= ~(1 << (vid & 0x1F));
+	e1000_write_vfta(&adapter->hw, index, vfta);
+}
+#endif
 
 /* e1000_main.c */
diff -Nru a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
--- a/drivers/net/e1000/e1000_osdep.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e1000/e1000_osdep.h	Wed Apr  3 17:11:14 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
diff -Nru a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
--- a/drivers/net/e1000/e1000_param.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e1000/e1000_param.c	Wed Apr  3 17:11:14 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
@@ -153,7 +152,7 @@
 
 /* Auto-negotiation Advertisement Override
  *
- * Valid Range: 0x00-0x0F, 0x20-0x2F
+ * Valid Range: 0x01-0x0F, 0x20-0x2F
  *
  * The AutoNeg value is a bit mask describing which speed and duplex
  * combinations should be advertised during auto-negotiation.
@@ -193,20 +192,11 @@
 
 E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
 
-/* Transmit Interrupt Delay in units of 1.024 microseconds
- *
- * Valid Range: 0-65535
- *
- * Default Value: 64
- */
-
-E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
-
 /* Receive Interrupt Delay in units of 1.024 microseconds
  *
  * Valid Range: 0-65535
  *
- * Default Value: 64
+ * Default Value: 64/128
  */
 
 E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
@@ -252,13 +242,10 @@
 #define MIN_RXD                       80
 #define MAX_82544_RXD               4096
 
-#define DEFAULT_TIDV                  64
-#define MAX_TIDV                  0xFFFF
-#define MIN_TIDV                       0
-
-#define DEFAULT_RIDV                  64
-#define MAX_RIDV                  0xFFFF
-#define MIN_RIDV                       0
+#define DEFAULT_RDTR                  64
+#define DEFAULT_RADV                 128
+#define MAX_RXDELAY               0xFFFF
+#define MIN_RXDELAY                    0
 
 #define DEFAULT_MDIX                   0
 #define MAX_MDIX                       3
@@ -332,8 +319,6 @@
 	return -1;
 }
 
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
 static void e1000_check_fiber_options(struct e1000_adapter *adapter);
 static void e1000_check_copper_options(struct e1000_adapter *adapter);
 
@@ -367,7 +352,7 @@
 			arg: { r: { min: MIN_TXD }}
 		};
 		struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
-		e1000_mac_type mac_type = adapter->shared.mac_type;
+		e1000_mac_type mac_type = adapter->hw.mac_type;
 		opt.arg.r.max = mac_type < e1000_82544 ? MAX_TXD : MAX_82544_TXD;
 
 		tx_ring->count = TxDescriptors[bd];
@@ -383,7 +368,7 @@
 			arg: { r: { min: MIN_RXD }}
 		};
 		struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
-		e1000_mac_type mac_type = adapter->shared.mac_type;
+		e1000_mac_type mac_type = adapter->hw.mac_type;
 		opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD;
 
 		rx_ring->count = RxDescriptors[bd];
@@ -416,39 +401,30 @@
 			name: "Flow Control",
 			err:  "reading default settings from EEPROM",
 			def:  e1000_fc_default,
-			arg: { l: { nr: LIST_LEN(fc_list), p: fc_list }}
+			arg: { l: { nr: ARRAY_SIZE(fc_list), p: fc_list }}
 		};
 
 		int fc = FlowControl[bd];
 		e1000_validate_option(&fc, &opt);
-		adapter->shared.fc = adapter->shared.original_fc = fc;
-	}
-	{ /* Transmit Interrupt Delay */
-		struct e1000_option opt = {
-			type: range_option,
-			name: "Transmit Interrupt Delay",
-			err:  "using default of " __MODULE_STRING(DEFAULT_TIDV),
-			def:  DEFAULT_TIDV,
-			arg: { r: { min: MIN_TIDV, max: MAX_TIDV }}
-		};
-
-		adapter->tx_int_delay = TxIntDelay[bd];
-		e1000_validate_option(&adapter->tx_int_delay, &opt);
+		adapter->hw.fc = adapter->hw.original_fc = fc;
 	}
 	{ /* Receive Interrupt Delay */
+		char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
+		char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
 		struct e1000_option opt = {
 			type: range_option,
 			name: "Receive Interrupt Delay",
-			err:  "using default of " __MODULE_STRING(DEFAULT_RIDV),
-			def:  DEFAULT_RIDV,
-			arg: { r: { min: MIN_RIDV, max: MAX_RIDV }}
+			arg: { r: { min: MIN_RXDELAY, max: MAX_RXDELAY }}
 		};
+		e1000_mac_type mac_type = adapter->hw.mac_type;
+		opt.def = mac_type < e1000_82540 ? DEFAULT_RDTR : DEFAULT_RADV;
+		opt.err = mac_type < e1000_82540 ? rdtr : radv;
 
 		adapter->rx_int_delay = RxIntDelay[bd];
 		e1000_validate_option(&adapter->rx_int_delay, &opt);
 	}
 	
-	switch(adapter->shared.media_type) {
+	switch(adapter->hw.media_type) {
 	case e1000_media_type_fiber:
 		e1000_check_fiber_options(adapter);
 		break;
@@ -511,7 +487,7 @@
 			name: "Speed",
 			err:  "parameter ignored",
 			def:  0,
-			arg: { l: { nr: LIST_LEN(speed_list), p: speed_list }}
+			arg: { l: { nr: ARRAY_SIZE(speed_list), p: speed_list }}
 		};
 
 		speed = Speed[bd];
@@ -526,7 +502,7 @@
 			name: "Duplex",
 			err:  "parameter ignored",
 			def:  0,
-			arg: { l: { nr: LIST_LEN(dplx_list), p: dplx_list }}
+			arg: { l: { nr: ARRAY_SIZE(dplx_list), p: dplx_list }}
 		};
 
 		dplx = Duplex[bd];
@@ -537,10 +513,10 @@
 		printk(KERN_INFO
 		       "AutoNeg specified along with Speed or Duplex, "
 		       "parameter ignored\n");
-		adapter->shared.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+		adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
 	} else { /* Autoneg */
 		struct e1000_opt_list an_list[] =
-			#define AA "Autoneg advertising "
+			#define AA "AutoNeg advertising "
 			{{ 0x01, AA "10/HD" },
 			 { 0x02, AA "10/FD" },
 			 { 0x03, AA "10/FD, 10/HD" },
@@ -575,20 +551,20 @@
 
 		struct e1000_option opt = {
 			type: list_option,
-			name: "Autoneg",
+			name: "AutoNeg",
 			err:  "parameter ignored",
 			def:  AUTONEG_ADV_DEFAULT,
-			arg: { l: { nr: LIST_LEN(an_list), p: an_list }}
+			arg: { l: { nr: ARRAY_SIZE(an_list), p: an_list }}
 		};
 
 		int an = AutoNeg[bd];
 		e1000_validate_option(&an, &opt);
-		adapter->shared.autoneg_advertised = an;
+		adapter->hw.autoneg_advertised = an;
 	}
 
 	switch (speed + dplx) {
 	case 0:
-		adapter->shared.autoneg = 1;
+		adapter->hw.autoneg = 1;
 		if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
 			printk(KERN_INFO
 			       "Speed and duplex autonegotiation enabled\n");
@@ -596,75 +572,75 @@
 	case HALF_DUPLEX:
 		printk(KERN_INFO "Half Duplex specified without Speed\n");
 		printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_10_HALF | 
-		                                     ADVERTISE_100_HALF;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF | 
+		                                 ADVERTISE_100_HALF;
 		break;
 	case FULL_DUPLEX:
 		printk(KERN_INFO "Full Duplex specified without Speed\n");
 		printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_10_FULL |
-		                                     ADVERTISE_100_FULL |
-		                                     ADVERTISE_1000_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
+		                                 ADVERTISE_100_FULL |
+		                                 ADVERTISE_1000_FULL;
 		break;
 	case SPEED_10:
 		printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
 		printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_10_HALF |
-		                                     ADVERTISE_10_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+		                                 ADVERTISE_10_FULL;
 		break;
 	case SPEED_10 + HALF_DUPLEX:
 		printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
-		adapter->shared.autoneg = 0;
-		adapter->shared.forced_speed_duplex = e1000_10_half;
-		adapter->shared.autoneg_advertised = 0;
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_10_half;
+		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_10 + FULL_DUPLEX:
 		printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
-		adapter->shared.autoneg = 0;
-		adapter->shared.forced_speed_duplex = e1000_10_full;
-		adapter->shared.autoneg_advertised = 0;
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_10_full;
+		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_100:
 		printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
 		printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_100_HALF |
-		                                     ADVERTISE_100_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
+		                                 ADVERTISE_100_FULL;
 		break;
 	case SPEED_100 + HALF_DUPLEX:
 		printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
-		adapter->shared.autoneg = 0;
-		adapter->shared.forced_speed_duplex = e1000_100_half;
-		adapter->shared.autoneg_advertised = 0;
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_100_half;
+		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_100 + FULL_DUPLEX:
 		printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
-		adapter->shared.autoneg = 0;
-		adapter->shared.forced_speed_duplex = e1000_100_full;
-		adapter->shared.autoneg_advertised = 0;
+		adapter->hw.autoneg = 0;
+		adapter->hw.forced_speed_duplex = e1000_100_full;
+		adapter->hw.autoneg_advertised = 0;
 		break;
 	case SPEED_1000:
 		printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
 		printk(KERN_INFO
 		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
 		break;
 	case SPEED_1000 + HALF_DUPLEX:
 		printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
 		printk(KERN_INFO
 		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
 		break;
 	case SPEED_1000 + FULL_DUPLEX:
 		printk(KERN_INFO
 		       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
-		adapter->shared.autoneg = 1;
-		adapter->shared.autoneg_advertised = ADVERTISE_1000_FULL;
+		adapter->hw.autoneg = 1;
+		adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
 		break;
 	default:
 		BUG();
@@ -683,7 +659,7 @@
 
 		int mdix = MdiX[bd];
 		e1000_validate_option(&mdix, &opt);
-		adapter->shared.mdix = mdix;
+		adapter->hw.mdix = mdix;
 	}
 	{ /* Automatic Correction for Reverse Cable Polarity */
 	  /* option is actually to disable polarity correction,
@@ -697,11 +673,11 @@
 
 		int dpc = DisablePolarityCorrection[bd];
 		e1000_validate_option(&dpc, &opt);
-		adapter->shared.disable_polarity_correction = dpc;
+		adapter->hw.disable_polarity_correction = dpc;
 	}
 	
 	/* Speed, AutoNeg and MDI/MDI-X must all play nice */
-	if (!e1000_validate_mdi_setting(&(adapter->shared))) {
+	if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
 		printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are "
 		       "incompatible. Setting MDI-X to a compatible value.\n");
 	}
diff -Nru a/drivers/net/e1000/e1000_phy.c b/drivers/net/e1000/e1000_phy.c
--- a/drivers/net/e1000/e1000_phy.c	Wed Apr  3 17:11:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1485 +0,0 @@
-/*******************************************************************************
-
-  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/1000 Family of Adapters (e1000) (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.
-
-*******************************************************************************/
-
-/* e1000_phy.c
- * Shared functions for accessing and configuring the PHY
- */
-
-#include "e1000_mac.h"
-#include "e1000_phy.h"
-
-/******************************************************************************
-* Raises the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_raise_mdc(struct e1000_shared_adapter *shared,
-                uint32_t *ctrl_reg)
-{
-    /* Raise the clock input to the Management Data Clock (by setting
-     * the MDC bit), and then delay 2 microseconds.
-     */
-    E1000_WRITE_REG(shared, CTRL, (*ctrl_reg | E1000_CTRL_MDC));
-    usec_delay(2);
-    return;
-}
-
-/******************************************************************************
-* Lowers the Management Data Clock
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - Device control register's current value
-******************************************************************************/
-static void
-e1000_lower_mdc(struct e1000_shared_adapter *shared,
-                uint32_t *ctrl_reg)
-{
-    /* Lower the clock input to the Management Data Clock (by clearing
-     * the MDC bit), and then delay 2 microseconds.
-     */
-    E1000_WRITE_REG(shared, CTRL, (*ctrl_reg & ~E1000_CTRL_MDC));
-    usec_delay(2);
-    return;
-}
-
-/******************************************************************************
-* Shifts data bits out to the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* data - Data to send out to the PHY
-* count - Number of bits to shift out
-*
-* Bits are shifted out in MSB to LSB order.
-******************************************************************************/
-static void
-e1000_phy_shift_out(struct e1000_shared_adapter *shared,
-                    uint32_t data,
-                    uint16_t count)
-{
-    uint32_t ctrl_reg;
-    uint32_t mask;
-
-    ASSERT(count <= 32);
-
-    /* We need to shift "count" number of bits out to the PHY.  So, the
-     * value in the "Data" parameter will be shifted out to the PHY
-     * one bit at a time.  In order to do this, "Data" must be broken
-     * down into bits, which is what the "while" logic does below.
-     */
-    mask = 0x01;
-    mask <<= (count - 1);
-
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    /* Set MDIO_DIR (SWDPIO1) and MDC_DIR (SWDPIO2) direction bits to
-     * be used as output pins.
-     */
-    ctrl_reg |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
-
-    while(mask) {
-        /* A "1" is shifted out to the PHY by setting the MDIO bit to
-         * "1" and then raising and lowering the Management Data Clock
-         * (MDC).  A "0" is shifted out to the PHY by setting the MDIO
-         * bit to "0" and then raising and lowering the clock.
-         */
-        if(data & mask)
-            ctrl_reg |= E1000_CTRL_MDIO;
-        else
-            ctrl_reg &= ~E1000_CTRL_MDIO;
-
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-        usec_delay(2);
-
-        e1000_raise_mdc(shared, &ctrl_reg);
-        e1000_lower_mdc(shared, &ctrl_reg);
-
-        mask = mask >> 1;
-    }
-
-    /* Clear the data bit just before leaving this routine. */
-    ctrl_reg &= ~E1000_CTRL_MDIO;
-    return;
-}
-
-/******************************************************************************
-* Shifts data bits in from the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Bits are shifted in in MSB to LSB order. 
-******************************************************************************/
-static uint16_t
-e1000_phy_shift_in(struct e1000_shared_adapter *shared)
-{
-    uint32_t ctrl_reg;
-    uint16_t data = 0;
-    uint8_t i;
-
-    /* In order to read a register from the PHY, we need to shift in a
-     * total of 18 bits from the PHY.  The first two bit (TurnAround)
-     * times are used to avoid contention on the MDIO pin when a read
-     * operation is performed.  These two bits are ignored by us and
-     * thrown away.  Bits are "shifted in" by raising the clock input
-     * to the Management Data Clock (setting the MDC bit), and then
-     * reading the value of the MDIO bit.
-     */ 
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as
-     * input.
-     */ 
-    ctrl_reg &= ~E1000_CTRL_MDIO_DIR;
-    ctrl_reg &= ~E1000_CTRL_MDIO;
-
-    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-    /* Raise and Lower the clock before reading in the data.  This
-     * accounts for the TurnAround bits.  The first clock occurred
-     * when we clocked out the last bit of the Register Address.
-     */
-    e1000_raise_mdc(shared, &ctrl_reg);
-    e1000_lower_mdc(shared, &ctrl_reg);
-
-    for(data = 0, i = 0; i < 16; i++) {
-        data = data << 1;
-        e1000_raise_mdc(shared, &ctrl_reg);
-
-        ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-        /* Check to see if we shifted in a "1". */
-        if(ctrl_reg & E1000_CTRL_MDIO)
-            data |= 1;
-
-        e1000_lower_mdc(shared, &ctrl_reg);
-    }
-
-    e1000_raise_mdc(shared, &ctrl_reg);
-    e1000_lower_mdc(shared, &ctrl_reg);
-
-    /* Clear the MDIO bit just before leaving this routine. */
-    ctrl_reg &= ~E1000_CTRL_MDIO;
-
-    return (data);
-}
-
-/******************************************************************************
-* Force PHY speed and duplex settings to shared->forced_speed_duplex
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-static void
-e1000_phy_force_speed_duplex(struct e1000_shared_adapter *shared)
-{
-    uint32_t tctl_reg;
-    uint32_t ctrl_reg;
-    uint32_t shift;
-    uint16_t mii_ctrl_reg;
-    uint16_t mii_status_reg;
-    uint16_t phy_data;
-    uint16_t i;
-
-    DEBUGFUNC("e1000_phy_force_speed_duplex");
-
-    /* Turn off Flow control if we are forcing speed and duplex. */
-    shared->fc = e1000_fc_none;
-
-    DEBUGOUT1("shared->fc = %d\n", shared->fc);
-
-    /* Read the Device Control Register. */
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
-    ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-    ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
-    /* Clear the Auto Speed Detect Enable bit. */
-    ctrl_reg &= ~E1000_CTRL_ASDE;
-
-    /* Read the MII Control Register. */
-    mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
-    /* We need to disable autoneg in order to force link and duplex. */
-
-    mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
-
-    /* Are we forcing Full or Half Duplex? */
-    if(shared->forced_speed_duplex == e1000_100_full ||
-       shared->forced_speed_duplex == e1000_10_full) {
-
-        /* We want to force full duplex so we SET the full duplex bits
-         * in the Device and MII Control Registers.
-         */
-        ctrl_reg |= E1000_CTRL_FD;
-        mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
-
-        DEBUGOUT("Full Duplex\n");
-    } else {
-
-        /* We want to force half duplex so we CLEAR the full duplex
-         * bits in the Device and MII Control Registers.
-         */
-        ctrl_reg &= ~E1000_CTRL_FD;
-        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;    /* Do this implies HALF */
-
-        DEBUGOUT("Half Duplex\n");
-    }
-
-    /* Are we forcing 100Mbps??? */
-    if(shared->forced_speed_duplex == e1000_100_full ||
-       shared->forced_speed_duplex == e1000_100_half) {
-
-        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
-        ctrl_reg |= E1000_CTRL_SPD_100;
-        mii_ctrl_reg |= MII_CR_SPEED_100;
-        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
-
-        DEBUGOUT("Forcing 100mb ");
-    } else {                    /* Force 10MB Full or Half */
-
-        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
-        ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-        mii_ctrl_reg |= MII_CR_SPEED_10;
-        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
-
-        DEBUGOUT("Forcing 10mb ");
-    }
-
-    /* Now we need to configure the Collision Distance.  We need to read
-     * the Transmit Control Register to do this.
-     * Note: This must be done for both Half or Full Duplex.
-     */
-    tctl_reg = E1000_READ_REG(shared, TCTL);
-    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
-    if(!(mii_ctrl_reg & MII_CR_FULL_DUPLEX)) {
-
-       /* We are in Half Duplex mode so we need to set up our collision
-        * distance for 10/100.
-        */
-        tctl_reg &= ~E1000_TCTL_COLD;
-        shift = E1000_HDX_COLLISION_DISTANCE;
-        shift <<= E1000_COLD_SHIFT;
-        tctl_reg |= shift;
-    } else {
-        /* We are in Full Duplex mode.  We have the same collision
-         * distance regardless of speed.
-         */
-        tctl_reg &= ~E1000_TCTL_COLD;
-        shift = E1000_FDX_COLLISION_DISTANCE;
-        shift <<= E1000_COLD_SHIFT;
-        tctl_reg |= shift;
-    }
-
-    /* Write the configured values back to the Transmit Control Reg. */
-    E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
-    /* Write the configured values back to the Device Control Reg. */
-    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-    /* Write the MII Control Register with the new PHY configuration. */
-    phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
-    /* Clear Auto-Crossover to force MDI manually.
-     * M88E1000 requires MDI forced whenever speed/duplex is forced
-     */
-    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
-
-    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
-
-    /* Need to reset the PHY or these bits will get ignored. */
-    mii_ctrl_reg |= MII_CR_RESET;
-
-    e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
-    /* The wait_autoneg_complete flag may be a little misleading here.
-     * Since we are forcing speed and duplex, Auto-Neg is not enabled.
-     * But we do want to delay for a period while forcing only so we
-     * don't generate false No Link messages.  So we will wait here
-     * only if the user has set wait_autoneg_complete to 1, which is
-     * the default.
-     */
-    if(shared->wait_autoneg_complete) {
-        /* We will wait for autoneg to complete. */
-        DEBUGOUT("Waiting for forced speed/duplex link.\n");
-        mii_status_reg = 0;
-
-        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
-        for(i = PHY_FORCE_TIME; i > 0; i--) {
-            /* Read the MII Status Register and wait for Auto-Neg
-             * Complete bit to be set.
-             */
-            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-            if(mii_status_reg & MII_SR_LINK_STATUS)
-                break;
-
-            msec_delay(100);
-        }                       /* end for loop */
-
-        if(i == 0) {            /* We didn't get link   */
-
-            /* Reset the DSP and wait again for link.   */
-            e1000_phy_reset_dsp(shared);
-        }
-
-        /* This loop will early-out if the link condition has been met.  */
-        for(i = PHY_FORCE_TIME; i > 0; i--) {
-            if(mii_status_reg & MII_SR_LINK_STATUS)
-                break;
-
-            msec_delay(100);
-            /* Read the MII Status Register and wait for Auto-Neg
-             * Complete bit to be set.
-             */
-            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-            mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-        }                       /* end for loop */
-    }    /* end if wait_autoneg_complete */
-    /*
-     * Because we reset the PHY above, we need to re-force TX_CLK in the
-     * Extended PHY Specific Control Register to 25MHz clock.  This
-     * value defaults back to a 2.5MHz clock when the PHY is reset.
-     */
-    phy_data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
-    phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
-    e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
-
-    /* In addition, because of the s/w reset above, we need to enable
-     * CRS on TX.  This must be set for both full and half duplex
-     * operation.
-     */
-    phy_data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
-    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_data);
-    DEBUGOUT1("M88E1000 Phy Specific Ctrl Reg = %4x\r\n", phy_data);
-
-    return;
-}
-
-/*****************************************************************************
-* Reads the value from a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to read
-******************************************************************************/
-uint16_t
-e1000_read_phy_reg(struct e1000_shared_adapter *shared,
-                   uint32_t reg_addr)
-{
-    uint32_t i;
-    uint32_t data = 0;
-    uint32_t command = 0;
-
-    ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
-    if(shared->mac_type > e1000_82543) {
-        /* Set up Op-code, Phy Address, and
-         * register address in the MDI Control register.  The MAC will
-         * take care of interfacing with the PHY to retrieve the
-         * desired data.
-         */
-        command = ((reg_addr << E1000_MDIC_REG_SHIFT) |
-                   (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | 
-                   (E1000_MDIC_OP_READ));
-
-        E1000_WRITE_REG(shared, MDIC, command);
-
-        /* Check every 10 usec to see if the read completed.  The read
-         * may take as long as 64 usecs (we'll wait 100 usecs max)
-         * from the CPU Write to the Ready bit assertion.
-         */
-        for(i = 0; i < 64; i++) {
-            usec_delay(10);
-
-            data = E1000_READ_REG(shared, MDIC);
-
-            if(data & E1000_MDIC_READY)
-                break;
-        }
-    } else {
-        /* We must first send a preamble through the MDIO pin to signal the
-         * beginning of an MII instruction.  This is done by sending 32
-         * consecutive "1" bits.
-         */
-        e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
-        /* Now combine the next few fields that are required for a read
-         * operation.  We use this method instead of calling the
-         * e1000_phy_shift_out routine five different times.  The format of
-         * a MII read instruction consists of a shift out of 14 bits and is
-         * defined as follows:
-         *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
-         * followed by a shift in of 18 bits.  This first two bits shifted
-         * in are TurnAround bits used to avoid contention on the MDIO pin
-         * when a READ operation is performed.  These two bits are thrown
-         * away followed by a shift in of 16 bits which contains the
-         * desired data.
-         */
-        command = ((reg_addr) |
-                   (shared->phy_addr << 5) |
-                   (PHY_OP_READ << 10) | (PHY_SOF << 12));
-
-        e1000_phy_shift_out(shared, command, 14);
-
-        /* Now that we've shifted out the read command to the MII, we need
-         * to "shift in" the 16-bit value (18 total bits) of the requested
-         * PHY register address.
-         */
-        data = (uint32_t) e1000_phy_shift_in(shared);
-    }
-
-    ASSERT(!(data & E1000_MDIC_ERROR));
-
-    return ((uint16_t) data);
-}
-
-/******************************************************************************
-* Writes a value to a PHY register
-*
-* shared - Struct containing variables accessed by shared code
-* reg_addr - address of the PHY register to write
-* data - data to write to the PHY
-******************************************************************************/
-void
-e1000_write_phy_reg(struct e1000_shared_adapter *shared,
-                    uint32_t reg_addr,
-                    uint16_t data)
-{
-    uint32_t i;
-    uint32_t command = 0;
-    uint32_t mdic_reg;
-
-    ASSERT(reg_addr <= MAX_PHY_REG_ADDRESS);
-
-    if(shared->mac_type > e1000_82543) {
-        /* Set up Op-code, Phy Address, register
-         * address, and data intended for the PHY register in the MDI
-         * Control register.  The MAC will take care of interfacing
-         * with the PHY to send the desired data.
-         */
-        command = (((uint32_t) data) |
-                   (reg_addr << E1000_MDIC_REG_SHIFT) |
-                   (shared->phy_addr << E1000_MDIC_PHY_SHIFT) | 
-                   (E1000_MDIC_OP_WRITE));
-
-        E1000_WRITE_REG(shared, MDIC, command);
-
-        /* Check every 10 usec to see if the read completed.  The read
-         * may take as long as 64 usecs (we'll wait 100 usecs max)
-         * from the CPU Write to the Ready bit assertion.
-         */
-        for(i = 0; i < 10; i++) {
-            usec_delay(10);
-
-            mdic_reg = E1000_READ_REG(shared, MDIC);
-
-            if(mdic_reg & E1000_MDIC_READY)
-                break;
-        }
-    } else {
-        /* We'll need to use the SW defined pins to shift the write command
-         *  out to the PHY. We first send a preamble to the PHY to signal the
-         * beginning of the MII instruction.  This is done by sending 32 
-         * consecutive "1" bits.
-         */
-        e1000_phy_shift_out(shared, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
-
-        /* Now combine the remaining required fields that will indicate
-         * a write operation.  We use this method instead of calling the
-         * e1000_phy_shift_out routine for each field in the command.  The
-         * format of a MII write instruction is as follows:
-         * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
-         */
-        command = ((PHY_TURNAROUND) |
-                   (reg_addr << 2) |
-                   (shared->phy_addr << 7) |
-                   (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
-        command <<= 16;
-        command |= ((uint32_t) data);
-
-        e1000_phy_shift_out(shared, command, 32);
-    }
-    return;
-}
-
-/******************************************************************************
-* Returns the PHY to the power-on reset state
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_hw_reset(struct e1000_shared_adapter *shared)
-{
-    uint32_t ctrl_reg;
-    uint32_t ctrl_ext_reg;
-
-    DEBUGFUNC("e1000_phy_hw_reset");
-
-    DEBUGOUT("Resetting Phy...\n");
-
-    if(shared->mac_type > e1000_82543) {
-        /* Read the device control register and assert the
-         * E1000_CTRL_PHY_RST bit.  Hold for 20ms and then take it out
-         * of reset.
-         */
-        ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-        ctrl_reg |= E1000_CTRL_PHY_RST;
-
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-        msec_delay(20);
-
-        ctrl_reg &= ~E1000_CTRL_PHY_RST;
-
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-        msec_delay(20);
-    } else {
-        /* Read the Extended Device Control Register, assert the
-         * PHY_RESET_DIR bit.  Then clock it out to the PHY.
-         */
-        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
-        ctrl_ext_reg |= E1000_CTRL_PHY_RESET_DIR4;
-
-        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
-        msec_delay(20);
-
-        /* Set the reset bit in the device control register and clock
-         * it out to the PHY.
-         */
-        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
-        ctrl_ext_reg &= ~E1000_CTRL_PHY_RESET4;
-
-        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
-        msec_delay(20);
-
-        ctrl_ext_reg = E1000_READ_REG(shared, CTRL_EXT);
-
-        ctrl_ext_reg |= E1000_CTRL_PHY_RESET4;
-
-        E1000_WRITE_REG(shared, CTRL_EXT, ctrl_ext_reg);
-
-        msec_delay(20);
-    }
-    return;
-}
-
-/******************************************************************************
-* Resets the PHY
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Sets bit 15 of the MII Control regiser
-******************************************************************************/
-boolean_t
-e1000_phy_reset(struct e1000_shared_adapter *shared)
-{
-    uint16_t reg_data;
-    uint16_t i;
-
-    DEBUGFUNC("e1000_phy_reset");
-
-    /* Read the MII control register, set the reset bit and write the
-     * value back by clocking it out to the PHY.
-     */
-    reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
-
-    reg_data |= MII_CR_RESET;
-
-    e1000_write_phy_reg(shared, PHY_CTRL, reg_data);
-
-    /* Wait for bit 15 of the MII Control Register to be cleared
-     * indicating the PHY has been reset.
-     */
-    i = 0;
-    while((reg_data & MII_CR_RESET) && i++ < 500) {
-        reg_data = e1000_read_phy_reg(shared, PHY_CTRL);
-        usec_delay(1);
-    }
-
-    if(i >= 500) {
-        DEBUGOUT("Timeout waiting for PHY to reset.\n");
-        return FALSE;
-    }
-    return TRUE;
-}
-
-/******************************************************************************
-* Detects which PHY is present and the speed and duplex
-*
-* shared - Struct containing variables accessed by shared code
-* ctrl_reg - current value of the device control register
-******************************************************************************/
-boolean_t
-e1000_phy_setup(struct e1000_shared_adapter *shared,
-                uint32_t ctrl_reg)
-{
-    uint16_t mii_ctrl_reg;
-    uint16_t mii_status_reg;
-    uint16_t phy_specific_ctrl_reg;
-    uint16_t mii_autoneg_adv_reg;
-    uint16_t mii_1000t_ctrl_reg;
-    uint16_t i;
-    uint16_t data;
-    uint16_t autoneg_hw_setting;
-    uint16_t autoneg_fc_setting;
-    boolean_t restart_autoneg = FALSE;
-    boolean_t force_autoneg_restart = FALSE;
-
-    DEBUGFUNC("e1000_phy_setup");
-
-    /* We want to enable the Auto-Speed Detection bit in the Device
-     * Control Register.  When set to 1, the MAC automatically detects
-     * the resolved speed of the link and self-configures appropriately.
-     * The Set Link Up bit must also be set for this behavior work
-     * properly.
-     */
-    /* Nothing but 82543 and newer */
-    ASSERT(shared->mac_type >= e1000_82543);
-
-    /* With 82543, we need to force speed/duplex
-     * on the MAC equal to what the PHY speed/duplex configuration is.
-     * In addition, on 82543, we need to perform a hardware reset
-     * on the PHY to take it out of reset.
-     */
-    if(shared->mac_type >= e1000_82544) {
-        ctrl_reg |= E1000_CTRL_SLU;
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-    } else {
-        ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
-        E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-        if(shared->mac_type == e1000_82543)
-            e1000_phy_hw_reset(shared);
-    }
-
-    if(!e1000_detect_gig_phy(shared)) {
-        /* No PHY detected, return FALSE */
-        DEBUGOUT("PhySetup failure, did not detect valid phy.\n");
-        return (FALSE);
-    }
-
-    DEBUGOUT1("Phy ID = %x \n", shared->phy_id);
-
-    /* Read the MII Control Register. */
-    mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
-    DEBUGOUT1("MII Ctrl Reg contents = %x\n", mii_ctrl_reg);
-
-    /* Check to see if the Auto Neg Enable bit is set in the MII Control
-     * Register.  If not, we could be in a situation where a driver was
-     * loaded previously and was forcing speed and duplex.  Then the
-     * driver was unloaded but a e1000_phy_hw_reset was not performed, so
-     * link was still being forced and link was still achieved.  Then
-     * the driver was reloaded with the intention to auto-negotiate, but
-     * since link is already established we end up not restarting
-     * auto-neg.  So if the auto-neg bit is not enabled and the driver
-     * is being loaded with the desire to auto-neg, we set this flag to
-     * to ensure the restart of the auto-neg engine later in the logic.
-     */
-    if(!(mii_ctrl_reg & MII_CR_AUTO_NEG_EN))
-        force_autoneg_restart = TRUE;
-
-    /* Clear the isolate bit for normal operation and write it back to
-     * the MII Control Reg.  Although the spec says this doesn't need
-     * to be done when the PHY address is not equal to zero, we do it
-     * anyway just to be safe.
-     */
-    mii_ctrl_reg &= ~(MII_CR_ISOLATE);
-
-    e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
-    data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
-    /* Enable CRS on TX.  This must be set for half-duplex operation. */
-    data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
-
-    DEBUGOUT1("M88E1000 PSCR: %x \n", data);
-
-    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, data);
-
-    data = e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-
-    /* Force TX_CLK in the Extended PHY Specific Control Register
-     * to 25MHz clock.
-     */
-    data |= M88E1000_EPSCR_TX_CLK_25;
-
-    e1000_write_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL, data);
-
-    /* Certain PHYs will set the default of MII register 4 differently.
-     * We need to check this against our fc value.  If it is
-     * different, we need to setup up register 4 correctly and restart
-     * autonegotiation.
-     */
-    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-    mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
-    /* Shift right to put 10T-Half bit in bit 0
-     * Isolate the four bits for 100/10 Full/Half.
-     */ 
-    autoneg_hw_setting = (mii_autoneg_adv_reg >> 5) & 0xF;
-
-    /* Get the 1000T settings. */
-    mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
-    /* Isolate and OR in the 1000T settings. */
-    autoneg_hw_setting |= ((mii_1000t_ctrl_reg & 0x0300) >> 4);
-
-    /* mask all bits in the MII Auto-Neg Advertisement Register
-     * except for ASM_DIR and PAUSE and shift.  This value
-     * will be used later to see if we need to restart Auto-Negotiation.
-     */
-    autoneg_fc_setting = ((mii_autoneg_adv_reg & 0x0C00) >> 10);
-
-    /* Perform some bounds checking on the shared->autoneg_advertised
-     * parameter.  If this variable is zero, then set it to the default.
-     */
-    shared->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
-    /* If autoneg_advertised is zero, we assume it was not defaulted
-     * by the calling code so we set to advertise full capability.
-     */
-    if(shared->autoneg_advertised == 0)
-        shared->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
-
-    /* We could be in the situation where Auto-Neg has already completed
-     * and the user has not indicated any overrides.  In this case we
-     * simply need to call e1000_get_speed_and_duplex to obtain the Auto-
-     * Negotiated speed and duplex, then return.
-     */
-    if(!force_autoneg_restart && shared->autoneg &&
-       (shared->autoneg_advertised == autoneg_hw_setting) &&
-       (shared->fc == autoneg_fc_setting)) {
-
-        DEBUGOUT("No overrides - Reading MII Status Reg..\n");
-
-        /* Read the MII Status Register.  We read this twice because
-         * certain bits are "sticky" and need to be read twice.
-         */
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-        DEBUGOUT1("MII Status Reg contents = %x\n", mii_status_reg);
-
-        /* Do we have link now? (if so, auto-neg has completed) */
-        if(mii_status_reg & MII_SR_LINK_STATUS) {
-            data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-            DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
-            /* We have link, so we need to finish the config process:
-             *   1) Set up the MAC to the current PHY speed/duplex
-             *      if we are on 82543.  If we
-             *      are on newer silicon, we only need to configure
-             *      collision distance in the Transmit Control Register.
-             *   2) Set up flow control on the MAC to that established
-             *      with the link partner.
-             */
-            if(shared->mac_type >= e1000_82544)
-                e1000_config_collision_dist(shared);
-            else
-                e1000_config_mac_to_phy(shared, data);
-
-            e1000_config_fc_after_link_up(shared);
-
-            return (TRUE);
-        }
-    }
-
-    /* Options:
-     *   MDI/MDI-X = 0 (default)
-     *   0 - Auto for all speeds
-     *   1 - MDI mode
-     *   2 - MDI-X mode
-     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
-     */
-    phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
-    phy_specific_ctrl_reg &= ~M88E1000_PSCR_AUTO_X_MODE;
-
-    switch (shared->mdix) {
-    case 1:
-        phy_specific_ctrl_reg |= M88E1000_PSCR_MDI_MANUAL_MODE;
-        break;
-    case 2:
-        phy_specific_ctrl_reg |= M88E1000_PSCR_MDIX_MANUAL_MODE;
-        break;
-    case 3:
-        phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_1000T;
-        break;
-    case 0:
-    default:
-        phy_specific_ctrl_reg |= M88E1000_PSCR_AUTO_X_MODE;
-        break;
-    }
-
-    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
-    /* Options:
-     *   disable_polarity_correction = 0 (default)
-     *       Automatic Correction for Reversed Cable Polarity
-     *   0 - Disabled
-     *   1 - Enabled
-     */
-    phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-
-    phy_specific_ctrl_reg &= ~M88E1000_PSCR_POLARITY_REVERSAL;
-
-    if(shared->disable_polarity_correction == 1)
-        phy_specific_ctrl_reg |= M88E1000_PSCR_POLARITY_REVERSAL;
-
-    e1000_write_phy_reg(shared, M88E1000_PHY_SPEC_CTRL, phy_specific_ctrl_reg);
-
-    /* Options:
-     *   autoneg = 1 (default)
-     *      PHY will advertise value(s) parsed from
-     *      autoneg_advertised and fc
-     *   autoneg = 0
-     *      PHY will be set to 10H, 10F, 100H, or 100F
-     *      depending on value parsed from forced_speed_duplex.
-     */
-
-    /* Is autoneg enabled?  This is enabled by default or by software override.
-     * If so, call e1000_phy_setup_autoneg routine to parse the
-     * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
-     * user should have provided a speed/duplex override.  If so, then call
-     * e1000_phy_force_speed_duplex to parse and set this up.  Otherwise,
-     * we are in an error situation and need to bail.
-     */
-    if(shared->autoneg) {
-        DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
-        restart_autoneg = e1000_phy_setup_autoneg(shared);
-    } else {
-        DEBUGOUT("Forcing speed and duplex\n");
-        e1000_phy_force_speed_duplex(shared);
-    }
-
-    /* Based on information parsed above, check the flag to indicate
-     * whether we need to restart Auto-Neg.
-     */
-    if(restart_autoneg) {
-        DEBUGOUT("Restarting Auto-Neg\n");
-
-        /* Read the MII Control Register. */
-        mii_ctrl_reg = e1000_read_phy_reg(shared, PHY_CTRL);
-
-        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
-         * the Auto Neg Restart bit.
-         */
-        mii_ctrl_reg |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
-
-        e1000_write_phy_reg(shared, PHY_CTRL, mii_ctrl_reg);
-
-        /* Does the user want to wait for Auto-Neg to complete here, or
-         * check at a later time (for example, callback routine).
-         */
-        if(shared->wait_autoneg_complete)
-            e1000_wait_autoneg(shared);
-    } /* end if restart_autoneg */
-
-    /* Read the MII Status Register. */
-    mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-    mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-    DEBUGOUT1("Checking for link status - MII Status Reg contents = %x\n",
-              mii_status_reg);
-
-    /* Check link status.  Wait up to 100 microseconds for link to
-     * become valid.
-     */
-    for(i = 0; i < 10; i++) {
-        if(mii_status_reg & MII_SR_LINK_STATUS)
-            break;
-        usec_delay(10);
-        DEBUGOUT(". ");
-
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-    }
-
-    if(mii_status_reg & MII_SR_LINK_STATUS) {
-        /* Yes, so configure MAC to PHY settings as well as flow control
-         * registers.
-         */
-        data = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-
-        DEBUGOUT1("M88E1000 Phy Specific Status Reg contents = %x\n", data);
-
-        /* We have link, so we need to finish the config process:
-         *   1) Set up the MAC to the current PHY speed/duplex
-         *      if we are on 82543.  If we
-         *      are on newer silicon, we only need to configure
-         *      collision distance in the Transmit Control Register.
-         *   2) Set up flow control on the MAC to that established with
-         *      the link partner.
-         */
-        if(shared->mac_type >= e1000_82544)
-            e1000_config_collision_dist(shared);
-        else
-            e1000_config_mac_to_phy(shared, data);
-
-        e1000_config_fc_after_link_up(shared);
-
-        DEBUGOUT("Valid link established!!!\n");
-    } else {
-        DEBUGOUT("Unable to establish link!!!\n");
-    }
-
-    return (TRUE);
-}
-
-/******************************************************************************
-* Configures PHY autoneg and flow control advertisement settings
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared)
-{
-    uint16_t mii_autoneg_adv_reg;
-    uint16_t mii_1000t_ctrl_reg;
-
-    DEBUGFUNC("e1000_phy_setup_autoneg");
-
-    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
-    mii_autoneg_adv_reg = e1000_read_phy_reg(shared, PHY_AUTONEG_ADV);
-
-    /* Read the MII 1000Base-T Control Register (Address 9). */
-    mii_1000t_ctrl_reg = e1000_read_phy_reg(shared, PHY_1000T_CTRL);
-
-    /* Need to parse both autoneg_advertised and fc and set up
-     * the appropriate PHY registers.  First we will parse for
-     * autoneg_advertised software override.  Since we can advertise
-     * a plethora of combinations, we need to check each bit
-     * individually.
-     */
-
-    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
-     * Advertisement Register (Address 4) and the 1000 mb speed bits in
-     * the  1000Base-T Control Register (Address 9).
-     */
-    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
-    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
-
-    DEBUGOUT1("autoneg_advertised %x\n", shared->autoneg_advertised);
-
-    /* Do we want to advertise 10 Mb Half Duplex? */
-    if(shared->autoneg_advertised & ADVERTISE_10_HALF) {
-        DEBUGOUT("Advertise 10mb Half duplex\n");
-        mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
-    }
-
-    /* Do we want to advertise 10 Mb Full Duplex? */
-    if(shared->autoneg_advertised & ADVERTISE_10_FULL) {
-        DEBUGOUT("Advertise 10mb Full duplex\n");
-        mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
-    }
-
-    /* Do we want to advertise 100 Mb Half Duplex? */
-    if(shared->autoneg_advertised & ADVERTISE_100_HALF) {
-        DEBUGOUT("Advertise 100mb Half duplex\n");
-        mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
-    }
-
-    /* Do we want to advertise 100 Mb Full Duplex? */
-    if(shared->autoneg_advertised & ADVERTISE_100_FULL) {
-        DEBUGOUT("Advertise 100mb Full duplex\n");
-        mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
-    }
-
-    /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
-    if(shared->autoneg_advertised & ADVERTISE_1000_HALF) {
-        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
-    }
-
-    /* Do we want to advertise 1000 Mb Full Duplex? */
-    if(shared->autoneg_advertised & ADVERTISE_1000_FULL) {
-        DEBUGOUT("Advertise 1000mb Full duplex\n");
-        mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
-    }
-
-    /* Check for a software override of the flow control settings, and
-     * setup the PHY advertisement registers accordingly.  If
-     * auto-negotiation is enabled, then software will have to set the
-     * "PAUSE" bits to the correct value in the Auto-Negotiation
-     * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
-     *
-     * The possible values of the "fc" parameter are:
-     *      0:  Flow control is completely disabled
-     *      1:  Rx flow control is enabled (we can receive pause frames
-     *          but not send pause frames).
-     *      2:  Tx flow control is enabled (we can send pause frames
-     *          but we do not support receiving pause frames).
-     *      3:  Both Rx and TX flow control (symmetric) are enabled.
-     *  other:  No software override.  The flow control configuration
-     *          in the EEPROM is used.
-     */
-    switch (shared->fc) {
-    case e1000_fc_none:        /* 0 */
-            /* Flow control (RX & TX) is completely disabled by a
-             * software over-ride.
-             */
-        mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-        break;
-    case e1000_fc_rx_pause:    /* 1 */
-            /* RX Flow control is enabled, and TX Flow control is
-             * disabled, by a software over-ride.
-             */
-
-            /* Since there really isn't a way to advertise that we are
-             * capable of RX Pause ONLY, we will advertise that we
-             * support both symmetric and asymmetric RX PAUSE.  Later
-             * (in e1000_config_fc_after_link_up) we will disable the
-             *shared's ability to send PAUSE frames.
-             */
-        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-        break;
-    case e1000_fc_tx_pause:    /* 2 */
-            /* TX Flow control is enabled, and RX Flow control is
-             * disabled, by a software over-ride.
-             */
-        mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
-        mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
-        break;
-    case e1000_fc_full:        /* 3 */
-            /* Flow control (both RX and TX) is enabled by a software
-             * over-ride.
-             */
-        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
-        break;
-    default:
-            /* We should never get here.  The value should be 0-3. */
-        DEBUGOUT("Flow control param set incorrectly\n");
-        ASSERT(0);
-        break;
-    }
-
-    /* Write the MII Auto-Neg Advertisement Register (Address 4). */
-    e1000_write_phy_reg(shared, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
-
-    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
-
-    /* Write the MII 1000Base-T Control Register (Address 9). */
-    e1000_write_phy_reg(shared, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
-    return (TRUE);
-}
-
-/******************************************************************************
-* Sets MAC speed and duplex settings to reflect the those in the PHY
-*
-* shared - Struct containing variables accessed by shared code
-* mii_reg - data to write to the MII control register
-*
-* The contents of the PHY register containing the needed information need to
-* be passed in.
-******************************************************************************/
-void
-e1000_config_mac_to_phy(struct e1000_shared_adapter *shared,
-                        uint16_t mii_reg)
-{
-    uint32_t ctrl_reg;
-    uint32_t tctl_reg;
-    uint32_t shift;
-
-    DEBUGFUNC("e1000_config_mac_to_phy");
-
-    /* We need to read the Transmit Control register to configure the
-     * collision distance.
-     * Note: This must be done for both Half or Full Duplex.
-     */
-    tctl_reg = E1000_READ_REG(shared, TCTL);
-    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
-    /* Read the Device Control Register and set the bits to Force Speed
-     * and Duplex.
-     */
-    ctrl_reg = E1000_READ_REG(shared, CTRL);
-
-    ctrl_reg |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
-    ctrl_reg &= ~(DEVICE_SPEED_MASK);
-
-    DEBUGOUT1("MII Register Data = %x\r\n", mii_reg);
-
-    /* Clear the ILOS bit. */
-    ctrl_reg &= ~E1000_CTRL_ILOS;
-
-    /* Set up duplex in the Device Control and Transmit Control
-     * registers depending on negotiated values.
-     */
-    if(mii_reg & M88E1000_PSSR_DPLX) {
-        ctrl_reg |= E1000_CTRL_FD;
-
-        /* We are in Full Duplex mode.  We have the same collision
-         * distance regardless of speed.
-         */
-        tctl_reg &= ~E1000_TCTL_COLD;
-        shift = E1000_FDX_COLLISION_DISTANCE;
-        shift <<= E1000_COLD_SHIFT;
-        tctl_reg |= shift;
-    } else {
-        ctrl_reg &= ~E1000_CTRL_FD;
-
-        /* We are in Half Duplex mode.  Our Half Duplex collision
-         * distance is different for Gigabit than for 10/100 so we will
-         * set accordingly.
-         */
-        if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { 
-            /* 1000Mbs HDX */
-            tctl_reg &= ~E1000_TCTL_COLD;
-            shift = E1000_GB_HDX_COLLISION_DISTANCE;
-            shift <<= E1000_COLD_SHIFT;
-            tctl_reg |= shift;
-            tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
-        } else {
-            /* 10/100Mbs HDX */
-            tctl_reg &= ~E1000_TCTL_COLD;
-            shift = E1000_HDX_COLLISION_DISTANCE;
-            shift <<= E1000_COLD_SHIFT;
-            tctl_reg |= shift;
-        }
-    }
-
-    /* Set up speed in the Device Control register depending on
-     * negotiated values.
-     */
-    if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
-        ctrl_reg |= E1000_CTRL_SPD_1000;
-    else if((mii_reg & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
-        ctrl_reg |= E1000_CTRL_SPD_100;
-    else
-        ctrl_reg &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
-
-    /* Write the configured values back to the Transmit Control Reg. */
-    E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
-    /* Write the configured values back to the Device Control Reg. */
-    E1000_WRITE_REG(shared, CTRL, ctrl_reg);
-
-    return;
-}
-
-/******************************************************************************
-* Sets the collision distance in the Transmit Control register
-*
-* shared - Struct containing variables accessed by shared code
-*
-* Link should have been established previously. Reads the speed and duplex
-* information from the Device Status register.
-******************************************************************************/
-void
-e1000_config_collision_dist(struct e1000_shared_adapter *shared)
-{
-    uint32_t tctl_reg;
-    uint16_t speed;
-    uint16_t duplex;
-    uint32_t shift;
-
-    DEBUGFUNC("e1000_config_collision_dist");
-
-    /* Get our current speed and duplex from the Device Status Register. */
-    e1000_get_speed_and_duplex(shared, &speed, &duplex);
-
-    /* We need to configure the Collision Distance for both Full or
-     * Half Duplex.
-     */
-    tctl_reg = E1000_READ_REG(shared, TCTL);
-    DEBUGOUT1("tctl_reg = %x\n", tctl_reg);
-
-    /* mask the Collision Distance bits in the Transmit Control Reg. */
-    tctl_reg &= ~E1000_TCTL_COLD;
-
-    if(duplex == FULL_DUPLEX) {
-        /* We are in Full Duplex mode.  Therefore, the collision distance
-         * is the same regardless of speed.
-         */
-        shift = E1000_FDX_COLLISION_DISTANCE;
-        shift <<= E1000_COLD_SHIFT;
-        tctl_reg |= shift;
-    } else {
-        /* We are in Half Duplex mode.  Half Duplex collision distance is
-         * different for Gigabit vs. 10/100, so we will set accordingly.
-         */
-        if(speed == SPEED_1000) {       /* 1000Mbs HDX */
-            shift = E1000_GB_HDX_COLLISION_DISTANCE;
-            shift <<= E1000_COLD_SHIFT;
-            tctl_reg |= shift;
-            tctl_reg |= E1000_TCTL_PBE; /* Enable Packet Bursting */
-        } else {                /* 10/100Mbs HDX */
-            shift = E1000_HDX_COLLISION_DISTANCE;
-            shift <<= E1000_COLD_SHIFT;
-            tctl_reg |= shift;
-        }
-    }
-
-    /* Write the configured values back to the Transmit Control Reg. */
-    E1000_WRITE_REG(shared, TCTL, tctl_reg);
-
-    return;
-}
-
-/******************************************************************************
-* Probes the expected PHY address for known PHY IDs
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_detect_gig_phy(struct e1000_shared_adapter *shared)
-{
-    uint32_t phy_id_high;
-    uint16_t phy_id_low;
-
-    DEBUGFUNC("e1000_detect_gig_phy");
-
-    /* Read the PHY ID Registers to identify which PHY is onboard. */
-    shared->phy_addr = 1;
-
-    phy_id_high = e1000_read_phy_reg(shared, PHY_ID1);
-
-    usec_delay(2);
-
-    phy_id_low = e1000_read_phy_reg(shared, PHY_ID2);
-
-    shared->phy_id = (phy_id_low | (phy_id_high << 16)) & PHY_REVISION_MASK;
-
-    if(shared->phy_id == M88E1000_12_PHY_ID ||
-       shared->phy_id == M88E1000_14_PHY_ID ||
-       shared->phy_id == M88E1000_I_PHY_ID) {
-
-        DEBUGOUT2("phy_id 0x%x detected at address 0x%x\n",
-                  shared->phy_id, shared->phy_addr);
-        return (TRUE);
-    } else {
-        DEBUGOUT("Could not auto-detect Phy!\n");
-        return (FALSE);
-    }
-}
-
-/******************************************************************************
-* Resets the PHY's DSP
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-void
-e1000_phy_reset_dsp(struct e1000_shared_adapter *shared)
-{
-    e1000_write_phy_reg(shared, 29, 0x1d);
-    e1000_write_phy_reg(shared, 30, 0xc1);
-    e1000_write_phy_reg(shared, 30, 0x00);
-    return;
-}
-
-/******************************************************************************
-* Blocks until autoneg completes or times out (~4.5 seconds)
-*
-* shared - Struct containing variables accessed by shared code
-******************************************************************************/
-boolean_t
-e1000_wait_autoneg(struct e1000_shared_adapter *shared)
-{
-    uint16_t i;
-    uint16_t mii_status_reg;
-    boolean_t autoneg_complete = FALSE;
-
-    DEBUGFUNC("e1000_wait_autoneg");
-
-    /* We will wait for autoneg to complete. */
-    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
-    mii_status_reg = 0;
-
-    /* We will wait for autoneg to complete or 4.5 seconds to expire. */
-
-    for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
-        /* Read the MII Status Register and wait for Auto-Neg
-         * Complete bit to be set.
-         */
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-        mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-
-        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
-            autoneg_complete = TRUE;
-            break;
-        }
-
-        msec_delay(100);
-    }
-
-    return (autoneg_complete);
-}
-
-/******************************************************************************
-* Get PHY information from various PHY registers
-*
-* shared - Struct containing variables accessed by shared code
-* phy_status_info - PHY information structure
-******************************************************************************/
-boolean_t
-e1000_phy_get_info(struct e1000_shared_adapter *shared,
-                   struct e1000_phy_info *phy_status_info)
-{
-    uint16_t phy_mii_status_reg;
-    uint16_t phy_specific_ctrl_reg;
-    uint16_t phy_specific_status_reg;
-    uint16_t phy_specific_ext_ctrl_reg;
-    uint16_t phy_1000t_stat_reg;
-
-    phy_status_info->cable_length = e1000_cable_length_undefined;
-    phy_status_info->extended_10bt_distance =
-        e1000_10bt_ext_dist_enable_undefined;
-    phy_status_info->cable_polarity = e1000_rev_polarity_undefined;
-    phy_status_info->polarity_correction = e1000_polarity_reversal_undefined;
-    phy_status_info->link_reset = e1000_down_no_idle_undefined;
-    phy_status_info->mdix_mode = e1000_auto_x_mode_undefined;
-    phy_status_info->local_rx = e1000_1000t_rx_status_undefined;
-    phy_status_info->remote_rx = e1000_1000t_rx_status_undefined;
-
-    /* PHY info only valid for copper media. */
-    if(shared == NULL || shared->media_type != e1000_media_type_copper)
-        return FALSE;
-
-    /* PHY info only valid for LINK UP.  Read MII status reg 
-     * back-to-back to get link status.
-     */
-    phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-    phy_mii_status_reg = e1000_read_phy_reg(shared, PHY_STATUS);
-    if((phy_mii_status_reg & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
-        return FALSE;
-
-    /* Read various PHY registers to get the PHY info. */
-    phy_specific_ctrl_reg = e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_CTRL);
-    phy_specific_status_reg =
-        e1000_read_phy_reg(shared, M88E1000_PHY_SPEC_STATUS);
-    phy_specific_ext_ctrl_reg =
-        e1000_read_phy_reg(shared, M88E1000_EXT_PHY_SPEC_CTRL);
-    phy_1000t_stat_reg = e1000_read_phy_reg(shared, PHY_1000T_STATUS);
-
-    phy_status_info->cable_length =
-        ((phy_specific_status_reg & M88E1000_PSSR_CABLE_LENGTH) >>
-         M88E1000_PSSR_CABLE_LENGTH_SHIFT);
-
-    phy_status_info->extended_10bt_distance =
-        (phy_specific_ctrl_reg & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
-        M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
-
-    phy_status_info->cable_polarity =
-        (phy_specific_status_reg & M88E1000_PSSR_REV_POLARITY) >>
-        M88E1000_PSSR_REV_POLARITY_SHIFT;
-
-    phy_status_info->polarity_correction =
-        (phy_specific_ctrl_reg & M88E1000_PSCR_POLARITY_REVERSAL) >>
-        M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
-
-    phy_status_info->link_reset =
-        (phy_specific_ext_ctrl_reg & M88E1000_EPSCR_DOWN_NO_IDLE) >>
-        M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT;
-
-    phy_status_info->mdix_mode =
-        (phy_specific_status_reg & M88E1000_PSSR_MDIX) >>
-        M88E1000_PSSR_MDIX_SHIFT;
-
-    phy_status_info->local_rx =
-        (phy_1000t_stat_reg & SR_1000T_LOCAL_RX_STATUS) >>
-        SR_1000T_LOCAL_RX_STATUS_SHIFT;
-
-    phy_status_info->remote_rx =
-        (phy_1000t_stat_reg & SR_1000T_REMOTE_RX_STATUS) >>
-        SR_1000T_REMOTE_RX_STATUS_SHIFT;
-
-    return TRUE;
-}
-
-boolean_t
-e1000_validate_mdi_setting(struct e1000_shared_adapter *shared)
-{
-    if(!shared->autoneg && (shared->mdix == 0 || shared->mdix == 3)) {
-        shared->mdix = 1;
-        return FALSE;
-    }
-    return TRUE;
-}
diff -Nru a/drivers/net/e1000/e1000_phy.h b/drivers/net/e1000/e1000_phy.h
--- a/drivers/net/e1000/e1000_phy.h	Wed Apr  3 17:11:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,422 +0,0 @@
-/*******************************************************************************
-
-  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/1000 Family of Adapters (e1000) (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.
-
-*******************************************************************************/
-
-/* e1000_phy.h
- * Structures, enums, and macros for the PHY
- */
-
-#ifndef _E1000_PHY_H_
-#define _E1000_PHY_H_
-
-#include "e1000_osdep.h"
-
-/* PHY status info structure and supporting enums */
-typedef enum {
-    e1000_cable_length_50 = 0,
-    e1000_cable_length_50_80,
-    e1000_cable_length_80_110,
-    e1000_cable_length_110_140,
-    e1000_cable_length_140,
-    e1000_cable_length_undefined = 0xFF
-} e1000_cable_length;
-
-typedef enum {
-    e1000_10bt_ext_dist_enable_normal = 0,
-    e1000_10bt_ext_dist_enable_lower,
-    e1000_10bt_ext_dist_enable_undefined = 0xFF
-} e1000_10bt_ext_dist_enable;
-
-typedef enum {
-    e1000_rev_polarity_normal = 0,
-    e1000_rev_polarity_reversed,
-    e1000_rev_polarity_undefined = 0xFF
-} e1000_rev_polarity;
-
-typedef enum {
-    e1000_polarity_reversal_enabled = 0,
-    e1000_polarity_reversal_disabled,
-    e1000_polarity_reversal_undefined = 0xFF
-} e1000_polarity_reversal;
-
-typedef enum {
-    e1000_down_no_idle_no_detect = 0,
-    e1000_down_no_idle_detect,
-    e1000_down_no_idle_undefined = 0xFF
-} e1000_down_no_idle;
-
-typedef enum {
-    e1000_auto_x_mode_manual_mdi = 0,
-    e1000_auto_x_mode_manual_mdix,
-    e1000_auto_x_mode_auto1,
-    e1000_auto_x_mode_auto2,
-    e1000_auto_x_mode_undefined = 0xFF
-} e1000_auto_x_mode;
-
-typedef enum {
-    e1000_1000t_rx_status_not_ok = 0,
-    e1000_1000t_rx_status_ok,
-    e1000_1000t_rx_status_undefined = 0xFF
-} e1000_1000t_rx_status;
-
-struct e1000_phy_info {
-    e1000_cable_length cable_length;
-    e1000_10bt_ext_dist_enable extended_10bt_distance;
-    e1000_rev_polarity cable_polarity;
-    e1000_polarity_reversal polarity_correction;
-    e1000_down_no_idle link_reset;
-    e1000_auto_x_mode mdix_mode;
-    e1000_1000t_rx_status local_rx;
-    e1000_1000t_rx_status remote_rx;
-};
-
-struct e1000_phy_stats {
-    uint32_t idle_errors;
-    uint32_t receive_errors;
-};
-
-/* Function Prototypes */
-uint16_t e1000_read_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr);
-void e1000_write_phy_reg(struct e1000_shared_adapter *shared, uint32_t reg_addr, uint16_t data);
-void e1000_phy_hw_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_reset(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_setup(struct e1000_shared_adapter *shared, uint32_t ctrl_reg);
-boolean_t e1000_phy_setup_autoneg(struct e1000_shared_adapter *shared);
-void e1000_config_mac_to_phy(struct e1000_shared_adapter *shared, uint16_t mii_reg);
-void e1000_config_collision_dist(struct e1000_shared_adapter *shared);
-boolean_t e1000_detect_gig_phy(struct e1000_shared_adapter *shared);
-void e1000_phy_reset_dsp(struct e1000_shared_adapter *shared);
-boolean_t e1000_wait_autoneg(struct e1000_shared_adapter *shared);
-boolean_t e1000_phy_get_info(struct e1000_shared_adapter *shared, struct e1000_phy_info *phy_status_info);
-boolean_t e1000_validate_mdi_setting(struct e1000_shared_adapter *shared);
-
-/* Bit definitions for the Management Data IO (MDIO) and Management Data
- * Clock (MDC) pins in the Device Control Register.
- */
-#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
-#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
-#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
-#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
-#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
-#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
-#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
-#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
-
-/* PHY 1000 MII Register/Bit Definitions */
-/* PHY Registers defined by IEEE */
-#define PHY_CTRL         0x00 /* Control Register */
-#define PHY_STATUS       0x01 /* Status Regiser */
-#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
-#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
-#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
-#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
-#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
-#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
-#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
-#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
-#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
-#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
-
-/* M88E1000 Specific Registers */
-#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
-#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
-#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
-#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
-#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
-#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
-
-#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
-
-/* PHY Control Register */
-#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
-#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
-#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
-#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
-#define MII_CR_POWER_DOWN       0x0800  /* Power down */
-#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
-#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
-#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
-#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
-
-/* PHY Status Register */
-#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
-#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
-#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
-#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
-#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
-#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
-#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
-#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
-#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
-#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
-#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
-#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
-#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
-#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
-#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
-
-/* Autoneg Advertisement Register */
-#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */
-#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */
-#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */
-#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */
-#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */
-#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */
-#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */
-#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */
-#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */
-#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */
-
-/* Link Partner Ability Register (Base Page) */
-#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
-#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
-#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
-#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
-#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
-#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
-#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
-#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
-#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
-#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
-#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
-
-/* Autoneg Expansion Register */
-#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
-#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
-#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
-#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
-#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
-
-/* Next Page TX Register */
-#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges
-                                    * of different NP
-                                    */
-#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
-                                    * 0 = cannot comply with msg
-                                    */
-#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
-#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
-                                    * 0 = sending last NP
-                                    */
-
-/* Link Partner Next Page Register */
-#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
-#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
-                                       * of different NP
-                                       */
-#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
-                                       * 0 = cannot comply with msg
-                                       */
-#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
-#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
-#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
-                                        * 0 = sending last NP 
-                                        */
-
-/* 1000BASE-T Control Register */
-#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
-#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
-#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
-#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
-                                        /* 0=DTE device */
-#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
-                                        /* 0=Configure PHY as Slave */
-#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
-                                        /* 0=Automatic Master/Slave config */
-#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
-#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
-#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
-#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
-#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
-
-/* 1000BASE-T Status Register */
-#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
-#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
-#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
-#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
-#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
-#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
-#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */
-#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
-#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
-#define SR_1000T_LOCAL_RX_STATUS_SHIFT  13
-
-/* Extended Status Register */
-#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
-#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
-#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
-#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
-
-#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */
-#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */
-
-#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */
-                                      /* (0=enable, 1=disable) */
-
-/* M88E1000 PHY Specific Control Register */
-#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
-#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
-#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
-#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
-                                                * 0=CLK125 toggling
-                                                */
-#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
-                                               /* Manual MDI configuration */
-#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
-#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
-                                                *  100BASE-TX/10BASE-T: 
-                                                *  MDI Mode
-                                                */
-#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
-                                                * all speeds. 
-                                                */
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
-                                        /* 1=Enable Extended 10BASE-T distance
-                                         * (Lower 10BASE-T RX Threshold)
-                                         * 0=Normal 10BASE-T RX Threshold */
-#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
-                                        /* 1=5-Bit interface in 100BASE-TX
-                                         * 0=MII interface in 100BASE-TX */
-#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
-#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
-#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
-
-#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
-#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
-#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
-
-/* M88E1000 PHY Specific Status Register */
-#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
-#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
-#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
-#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
-                                            * 3=110-140M;4=>140M */
-#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
-#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
-#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
-#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
-#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
-#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
-#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
-#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
-
-#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
-#define M88E1000_PSSR_MDIX_SHIFT         6
-#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
-
-/* M88E1000 Extended PHY Specific Control Register */
-#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
-#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
-                                              * Will assert lost lock and bring
-                                              * link down if idle not seen
-                                              * within 1ms in 1000BASE-T 
-                                              */
-#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
-#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
-
-#define M88E1000_EPSCR_DOWN_NO_IDLE_SHIFT 15
-
-/* Bit definitions for valid PHY IDs. */
-#define M88E1000_12_PHY_ID 0x01410C50
-#define M88E1000_14_PHY_ID 0x01410C40
-#define M88E1000_I_PHY_ID  0x01410C30
-
-/* Miscellaneous PHY bit definitions. */
-#define PHY_PREAMBLE        0xFFFFFFFF
-#define PHY_SOF             0x01
-#define PHY_OP_READ         0x02
-#define PHY_OP_WRITE        0x01
-#define PHY_TURNAROUND      0x02
-#define PHY_PREAMBLE_SIZE   32
-#define MII_CR_SPEED_1000   0x0040
-#define MII_CR_SPEED_100    0x2000
-#define MII_CR_SPEED_10     0x0000
-#define E1000_PHY_ADDRESS   0x01
-#define PHY_AUTO_NEG_TIME   45  /* 4.5 Seconds */
-#define PHY_FORCE_TIME      20  /* 2.0 Seconds */
-#define PHY_REVISION_MASK   0xFFFFFFF0
-#define DEVICE_SPEED_MASK   0x00000300  /* Device Ctrl Reg Speed Mask */
-#define REG4_SPEED_MASK     0x01E0
-#define REG9_SPEED_MASK     0x0300
-#define ADVERTISE_10_HALF   0x0001
-#define ADVERTISE_10_FULL   0x0002
-#define ADVERTISE_100_HALF  0x0004
-#define ADVERTISE_100_FULL  0x0008
-#define ADVERTISE_1000_HALF 0x0010
-#define ADVERTISE_1000_FULL 0x0020
-#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
-
-#endif /* _E1000_PHY_H_ */
diff -Nru a/drivers/net/e1000/e1000_proc.c b/drivers/net/e1000/e1000_proc.c
--- a/drivers/net/e1000/e1000_proc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/e1000/e1000_proc.c	Wed Apr  3 17:11:14 2002
@@ -2,9 +2,8 @@
 
   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:
+  License 2.0, 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
@@ -18,7 +17,7 @@
   "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
+  any operating system available under the GNU General Public License 2.0 or
   later.
   
   Copyright (c) 1999 - 2002 Intel Corporation.
@@ -51,10 +50,10 @@
   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
+  General Public License 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
+  available versions of such operating systems available under the GNU General
+  Public License 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.
@@ -96,7 +95,9 @@
 #include <linux/proc_fs.h>
 
 #define ADAPTERS_PROC_DIR           "PRO_LAN_Adapters"
-#define TAG_MAX_LENGTH              36
+#define TAG_MAX_LENGTH              32
+#define LINE_MAX_LENGTH             80
+#define FIELD_MAX_LENGTH            LINE_MAX_LENGTH - TAG_MAX_LENGTH - 3
 
 extern char e1000_driver_name[];
 extern char e1000_driver_version[];
@@ -110,7 +111,7 @@
 
 struct proc_list {
 	struct list_head list;                  /* link list */
-	char tag[TAG_MAX_LENGTH];               /* attribute name */
+	char tag[TAG_MAX_LENGTH + 1];           /* attribute name */
 	void *data;                             /* attribute data */
 	size_t len;				/* sizeof data */
 	char *(*func)(void *, size_t, char *);  /* format data func */
@@ -142,15 +143,20 @@
 	struct list_head *proc_list_head = data, *curr;
 	struct proc_list *elem;
 	char *p = page;
-	char buf[64];
+	char buf[FIELD_MAX_LENGTH + 1];
 
 	list_for_each(curr, proc_list_head) {
 		elem = list_entry(curr, struct proc_list, list);
 
-		if(strlen(elem->tag) == 0)
+		if (p - page + LINE_MAX_LENGTH >= PAGE_SIZE)
+			break;
+
+		if(!strlen(elem->tag))
 			p += sprintf(p, "\n");
 		else
-			p += sprintf(p, "%-32s %s\n", elem->tag,
+			p += sprintf(p, "%-*.*s %.*s\n", 
+				TAG_MAX_LENGTH, TAG_MAX_LENGTH,
+				elem->tag, FIELD_MAX_LENGTH,
 				elem->func(elem->data, elem->len, buf));
 	}
 
@@ -165,7 +171,8 @@
 {
 	struct proc_list *elem = data;
 
-	sprintf(page, "%s", elem->func(elem->data, elem->len, page));
+	sprintf(page, "%.*s", FIELD_MAX_LENGTH, elem->func(elem->data, 
+	        elem->len, page));
 
 	return e1000_proc_read(page, start, off, count, eof);
 }
@@ -179,8 +186,7 @@
 	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
 		intel_proc_dir = intel_proc_dir->next) {
 		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-			(memcmp(intel_proc_dir->name,
-			ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
 			break;
 	}
 
@@ -224,8 +230,6 @@
 
 	if(!proc_dir)
 		remove_proc_entry(ADAPTERS_PROC_DIR, proc_net);
-
-	return;
 }
 
 
@@ -241,7 +245,7 @@
 
 		elem = list_entry(curr, struct proc_list, list);
 
-		if(strlen(elem->tag) == 0)
+		if(!strlen(elem->tag))
 			continue;
 
 		if(!(proc_entry =
@@ -256,8 +260,9 @@
 	return 1;
 }
 
-static int __devinit
-e1000_proc_dirs_create(char *name, struct list_head *proc_list_head)
+static void __devinit
+e1000_proc_dirs_create(void *data, char *name, 
+                       struct list_head *proc_list_head)
 {
 	struct proc_dir_entry *intel_proc_dir, *proc_dir, *info_entry;
 	char info_name[strlen(name) + strlen(".info")];
@@ -265,8 +270,7 @@
 	for(intel_proc_dir = proc_net->subdir; intel_proc_dir;
 		intel_proc_dir = intel_proc_dir->next) {
 		if((intel_proc_dir->namelen == strlen(ADAPTERS_PROC_DIR)) &&
-			(memcmp(intel_proc_dir->name,
-			ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)) == 0))
+		   !memcmp(intel_proc_dir->name, ADAPTERS_PROC_DIR, strlen(ADAPTERS_PROC_DIR)))
 			break;
 	}
 
@@ -274,28 +278,26 @@
 		if(!(intel_proc_dir =
 			create_proc_entry(ADAPTERS_PROC_DIR,
 				S_IFDIR, proc_net)))
-			return 0;
+			return;
 
 	if(!(proc_dir =
 		create_proc_entry(name, S_IFDIR, intel_proc_dir)))
-		return 0;
+		return;
 	SET_MODULE_OWNER(proc_dir);
 
 	if(!e1000_proc_singles_create(proc_dir, proc_list_head))
-		return 0;
+		return;
 
 	strcpy(info_name, name);
 	strcat(info_name, ".info");
 
 	if(!(info_entry =
 		create_proc_entry(info_name, S_IFREG, intel_proc_dir)))
-		return 0;
+		return;
 	SET_MODULE_OWNER(info_entry);
 
 	info_entry->read_proc = e1000_proc_info_read;
 	info_entry->data = proc_list_head;
-
-	return 1;
 }
 
 static void __devinit
@@ -315,8 +317,6 @@
 	new->func = func;
 
 	list_add_tail(&new->list, proc_list_head);
-
-	return;
 }
 
 static void __devexit
@@ -329,8 +329,6 @@
 		list_del(&elem->list);
 		kfree(elem);
 	}
-
-	return;
 }
 
 /*
@@ -491,7 +489,7 @@
 {
 	struct e1000_adapter *adapter = data;
 	sprintf(buf,
-		adapter->shared.media_type == e1000_media_type_copper ?
+		adapter->hw.media_type == e1000_media_type_copper ?
 		"Copper" : "Fiber");
 	return buf;
 }
@@ -547,18 +545,6 @@
 	sprintf(buf,
 		correction == e1000_polarity_reversal_enabled  ? "Disabled" :
 		correction == e1000_polarity_reversal_disabled ? "Enabled"  :
-		"Undefined");
-	return buf;
-}
-
-static char *
-e1000_proc_link_reset_enabled(void *data, size_t len, char *buf)
-{
-	struct e1000_adapter *adapter = data;
-	e1000_down_no_idle link_reset = adapter->phy_info.link_reset;
-	sprintf(buf,
-		link_reset == e1000_down_no_idle_no_detect ? "Disabled" :
-		link_reset == e1000_down_no_idle_detect    ? "Enabled"  :
 		"Unknown");
 	return buf;
 }
@@ -568,7 +554,10 @@
 {
 	struct e1000_adapter *adapter = data;
 	e1000_auto_x_mode mdix_mode = adapter->phy_info.mdix_mode;
-	sprintf(buf, mdix_mode == 0 ? "MDI" : "MDI-X");
+	sprintf(buf, 
+		mdix_mode == e1000_auto_x_mode_manual_mdi  ? "MDI"   : 
+		mdix_mode == e1000_auto_x_mode_manual_mdix ? "MDI-X" :
+		"Unknown");
 	return buf;
 }
 
@@ -601,7 +590,7 @@
 static void __devinit
 e1000_proc_list_setup(struct e1000_adapter *adapter)
 {
-	struct e1000_shared_adapter *shared = &adapter->shared;
+	struct e1000_hw *hw = &adapter->hw;
 	struct list_head *proc_list_head = &adapter->proc_list_head;
 
 	INIT_LIST_HEAD(proc_list_head);
@@ -610,21 +599,21 @@
 	LIST_ADD_F("Part_Number", &adapter->part_num, e1000_proc_part_number);
 	LIST_ADD_S("Driver_Name", e1000_driver_name);
 	LIST_ADD_S("Driver_Version", e1000_driver_version);
-	LIST_ADD_H("PCI_Vendor", &shared->vendor_id);
-	LIST_ADD_H("PCI_Device_ID", &shared->device_id);
-	LIST_ADD_H("PCI_Subsystem_Vendor", &shared->subsystem_vendor_id);
-	LIST_ADD_H("PCI_Subsystem_ID", &shared->subsystem_id);
-	LIST_ADD_H("PCI_Revision_ID", &shared->revision_id);
+	LIST_ADD_H("PCI_Vendor", &hw->vendor_id);
+	LIST_ADD_H("PCI_Device_ID", &hw->device_id);
+	LIST_ADD_H("PCI_Subsystem_Vendor", &hw->subsystem_vendor_id);
+	LIST_ADD_H("PCI_Subsystem_ID", &hw->subsystem_id);
+	LIST_ADD_H("PCI_Revision_ID", &hw->revision_id);
 	LIST_ADD_U("PCI_Bus", &adapter->pdev->bus->number);
 	LIST_ADD_F("PCI_Slot", adapter, e1000_proc_slot);
 
-	if(adapter->shared.mac_type >= e1000_82543) {
+	if(adapter->hw.mac_type >= e1000_82543) {
 		LIST_ADD_F("PCI_Bus_Type",
-		           &shared->bus_type, e1000_proc_bus_type);
+		           &hw->bus_type, e1000_proc_bus_type);
 		LIST_ADD_F("PCI_Bus_Speed",
-		           &shared->bus_speed, e1000_proc_bus_speed);
+		           &hw->bus_speed, e1000_proc_bus_speed);
 		LIST_ADD_F("PCI_Bus_Width",
-		           &shared->bus_width, e1000_proc_bus_width);
+		           &hw->bus_width, e1000_proc_bus_width);
 	}
 
 	LIST_ADD_U("IRQ", &adapter->pdev->irq);
@@ -632,7 +621,7 @@
 	LIST_ADD_F("Current_HWaddr",
 	            adapter->netdev->dev_addr, e1000_proc_hwaddr);
 	LIST_ADD_F("Permanent_HWaddr",
-	            adapter->shared.perm_mac_addr, e1000_proc_hwaddr);
+	            adapter->hw.perm_mac_addr, e1000_proc_hwaddr);
 
 	LIST_ADD_BLANK();
 
@@ -679,7 +668,7 @@
 	LIST_ADD_U("Rx_Short_Length_Errors", &adapter->stats.ruc);
 	
 	/* The 82542 does not have an alignment error count register */
-	if(adapter->shared.mac_type >= e1000_82543)
+	if(adapter->hw.mac_type >= e1000_82543)
 		LIST_ADD_U("Rx_Align_Errors", &adapter->stats.algnerrc);
 	
 	LIST_ADD_U("Rx_Flow_Control_XON", &adapter->stats.xonrxc);
@@ -693,7 +682,7 @@
 
 	/* Cable diags */
 	LIST_ADD_F("PHY_Media_Type", adapter, e1000_proc_media_type);
-	if(adapter->shared.media_type == e1000_media_type_copper) {
+	if(adapter->hw.media_type == e1000_media_type_copper) {
 		LIST_ADD_F("PHY_Cable_Length",
 		           adapter, e1000_proc_cable_length);
 		LIST_ADD_F("PHY_Extended_10Base_T_Distance",
@@ -704,8 +693,6 @@
 		           adapter, e1000_proc_polarity_correction);
 		LIST_ADD_U("PHY_Idle_Errors", 
 		           &adapter->phy_stats.idle_errors);
-		LIST_ADD_F("PHY_Link_Reset_Enabled",
-		           adapter, e1000_proc_link_reset_enabled);
 		LIST_ADD_U("PHY_Receive_Errors",
 		           &adapter->phy_stats.receive_errors);
 		LIST_ADD_F("PHY_MDI_X_Enabled",
@@ -718,7 +705,6 @@
 			   e1000_proc_rx_status);
 	}
 
-	return;
 }
 
 /*
@@ -731,9 +717,9 @@
 {
 	e1000_proc_list_setup(adapter);
 
-	e1000_proc_dirs_create(adapter->netdev->name,&adapter->proc_list_head);
-
-	return;
+	e1000_proc_dirs_create(adapter, 
+	                       adapter->netdev->name,
+	                       &adapter->proc_list_head);
 }
 
 /*
@@ -747,8 +733,6 @@
 	e1000_proc_dirs_free(adapter->netdev->name, &adapter->proc_list_head);
 
 	e1000_proc_list_free(&adapter->proc_list_head);
-
-	return;
 }
 
 #else /* CONFIG_PROC_FS */
diff -Nru a/drivers/net/e2100.c b/drivers/net/e2100.c
--- a/drivers/net/e2100.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/e2100.c	Wed Apr  3 17:11:16 2002
@@ -72,7 +72,7 @@
 #define E21_SAPROM		0x10	/* Offset to station address data. */
 #define E21_IO_EXTENT	 0x20
 
-extern inline void mem_on(short port, volatile char *mem_base,
+static inline void mem_on(short port, volatile char *mem_base,
 						  unsigned char start_page )
 {
 	/* This is a little weird: set the shared memory window by doing a
@@ -82,7 +82,7 @@
 	outb(E21_MEM_ON, port + E21_MEM_ENABLE + E21_MEM_ON);
 }
 
-extern inline void mem_off(short port)
+static inline void mem_off(short port)
 {
 	inb(port + E21_MEM_ENABLE);
 	outb(0x00, port + E21_MEM_ENABLE);
@@ -234,8 +234,8 @@
 #ifdef notdef
 	/* These values are unused.  The E2100 has a 2K window into the packet
 	   buffer.  The window can be set to start on any page boundary. */
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = dev->rmem_end = dev->mem_start + 2*1024;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = ei_status.rmem_end = dev->mem_start + 2*1024;
 #endif
 
 	printk(", IRQ %d, %s media, memory @ %#lx.\n", dev->irq,
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/eepro100.c	Wed Apr  3 17:11:15 2002
@@ -1795,6 +1795,7 @@
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
+			dev->last_rx = jiffies;
 			sp->stats.rx_packets++;
 			sp->stats.rx_bytes += pkt_len;
 		}
diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/epic100.c	Wed Apr  3 17:11:15 2002
@@ -60,11 +60,14 @@
 	LK1.1.12:
 	* fix power-up sequence
 
+	LK1.1.13:
+	* revert version 1.1.12, power-up sequence "fix"
+
 */
 
 #define DRV_NAME	"epic100"
-#define DRV_VERSION	"1.11+LK1.1.12"
-#define DRV_RELDATE	"Jan 18, 2002"
+#define DRV_VERSION	"1.11+LK1.1.13"
+#define DRV_RELDATE	"Mar 20, 2002"
 
 
 /* The user-configurable values.
@@ -678,8 +681,9 @@
 	   required by the details of which bits are reset and the transceiver
 	   wiring on the Ositech CardBus card.
 	*/
-
-	outl(0x12, ioaddr + MIICfg);
+#if 0
+	outl(dev->if_port == 1 ? 0x13 : 0x12, ioaddr + MIICfg);
+#endif
 	if (ep->chip_flags & MII_PWRDWN)
 		outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
 
diff -Nru a/drivers/net/es3210.c b/drivers/net/es3210.c
--- a/drivers/net/es3210.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/es3210.c	Wed Apr  3 17:11:14 2002
@@ -233,9 +233,9 @@
 		printk(" assigning ");
 	}
 
-	dev->mem_end = dev->rmem_end = dev->mem_start
+	dev->mem_end = ei_status.rmem_end = dev->mem_start
 		+ (ES_STOP_PG - ES_START_PG)*256;
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 
 	printk("mem %#lx-%#lx\n", dev->mem_start, dev->mem_end-1);
 
@@ -335,12 +335,12 @@
 {
 	unsigned long xfer_start = dev->mem_start + ring_offset - (ES_START_PG<<8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* Packet wraps over end of ring buffer. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk. */
 		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff -Nru a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
--- a/drivers/net/hamradio/6pack.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/6pack.c	Wed Apr  3 17:11:14 2002
@@ -256,7 +256,7 @@
 	skb->mac.raw = skb->data;
 	skb->protocol = htons(ETH_P_AX25);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
+	sp->dev->last_rx = jiffies;
 	sp->stats.rx_packets++;
 }
 
@@ -701,7 +701,6 @@
 /* Initialize 6pack control device -- register 6pack line discipline */
 
 static char msg_banner[]  __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
-static char msg_invparm[] __initdata = KERN_ERR  "6pack: sixpack_maxdev parameter too large.\n";
 static char msg_nomem[]   __initdata = KERN_ERR  "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
 static char msg_regfail[] __initdata = KERN_ERR  "6pack: can't register line discipline (err = %d)\n";
 
diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
--- a/drivers/net/hamradio/baycom_epp.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/baycom_epp.c	Wed Apr  3 17:11:15 2002
@@ -302,7 +302,7 @@
 /*---------------------------------------------------------------------------*/
 
 #if 0
-extern inline void append_crc_ccitt(unsigned char *buffer, int len)
+static inline void append_crc_ccitt(unsigned char *buffer, int len)
 {
  	unsigned int crc = 0xffff;
 
@@ -316,7 +316,7 @@
 
 /*---------------------------------------------------------------------------*/
 
-extern inline int check_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int check_crc_ccitt(const unsigned char *buf, int cnt)
 {
 	unsigned int crc = 0xffff;
 
@@ -327,7 +327,7 @@
 
 /*---------------------------------------------------------------------------*/
 
-extern inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
+static inline int calc_crc_ccitt(const unsigned char *buf, int cnt)
 {
 	unsigned int crc = 0xffff;
 
diff -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
--- a/drivers/net/hamradio/baycom_ser_fdx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/baycom_ser_fdx.c	Wed Apr  3 17:11:15 2002
@@ -201,12 +201,12 @@
 /* --------------------------------------------------------------------- */
 
 #if 0
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
         __attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
         __attribute__ ((unused));
 
-extern inline unsigned int hweight16(unsigned int w)
+static inline unsigned int hweight16(unsigned int w)
 {
         unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
         res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -214,7 +214,7 @@
         return (res & 0x00FF) + ((res >> 8) & 0x00FF);
 }
 
-extern inline unsigned int hweight8(unsigned int w)
+static inline unsigned int hweight8(unsigned int w)
 {
         unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
         res = (res & 0x33) + ((res >> 2) & 0x33);
diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
--- a/drivers/net/hamradio/dmascc.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/dmascc.c	Wed Apr  3 17:11:15 2002
@@ -1121,6 +1121,7 @@
       skb->protocol = ntohs(ETH_P_AX25);
       skb->mac.raw = skb->data;
       netif_rx(skb);
+      priv->dev->last_rx = jiffies;
       priv->stats.rx_packets++;
       priv->stats.rx_bytes += cb;
     }
diff -Nru a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
--- a/drivers/net/hamradio/mkiss.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/mkiss.c	Wed Apr  3 17:11:15 2002
@@ -345,7 +345,7 @@
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_AX25);
 	netif_rx(skb);
-	dev->last_rx = jiffies;
+	tmp_ax->dev->last_rx = jiffies;
 	tmp_ax->rx_packets++;
 }
 
diff -Nru a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
--- a/drivers/net/hamradio/scc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/scc.c	Wed Apr  3 17:11:14 2002
@@ -1661,7 +1661,7 @@
 	skb->pkt_type = PACKET_HOST;
 	
 	netif_rx(skb);
-	dev->last_rx = jiffies;
+	scc->dev->last_rx = jiffies;
 	return;
 }
 
diff -Nru a/drivers/net/hamradio/soundmodem/sm.h b/drivers/net/hamradio/soundmodem/sm.h
--- a/drivers/net/hamradio/soundmodem/sm.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/hamradio/soundmodem/sm.h	Wed Apr  3 17:11:13 2002
@@ -158,7 +158,7 @@
  * ===================== diagnostics stuff ===============================
  */
 
-extern inline void diag_trigger(struct sm_state *sm)
+static inline void diag_trigger(struct sm_state *sm)
 {
 	if (sm->diag.ptr < 0)
 		if (!(sm->diag.flags & SM_DIAGFLAG_DCDGATE) || sm->hdrv.hdlcrx.dcd)
@@ -170,7 +170,7 @@
 #define SHRT_MAX ((short)(((unsigned short)(~0U))>>1))
 #define SHRT_MIN (-SHRT_MAX-1)
 
-extern inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
+static inline void diag_add(struct sm_state *sm, int valinp, int valdemod)
 {
 	int val;
 
@@ -189,7 +189,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern inline void diag_add_one(struct sm_state *sm, int val)
+static inline void diag_add_one(struct sm_state *sm, int val)
 {
 	if ((sm->diag.mode != SM_DIAGMODE_INPUT &&
 	     sm->diag.mode != SM_DIAGMODE_DEMOD) ||
@@ -229,14 +229,14 @@
  */
 
 #if 0
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
 	__attribute__ ((unused));
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
 	__attribute__ ((unused));
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
         __attribute__ ((unused));
 
-extern inline unsigned int hweight32(unsigned int w)
+static inline unsigned int hweight32(unsigned int w)
 {
         unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
         res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
@@ -245,7 +245,7 @@
         return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
 }
 
-extern inline unsigned int hweight16(unsigned short w)
+static inline unsigned int hweight16(unsigned short w)
 {
         unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
         res = (res & 0x3333) + ((res >> 2) & 0x3333);
@@ -253,7 +253,7 @@
         return (res & 0x00FF) + ((res >> 8) & 0x00FF);
 }
 
-extern inline unsigned int hweight8(unsigned char w)
+static inline unsigned int hweight8(unsigned char w)
 {
         unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
         res = (res & 0x33) + ((res >> 2) & 0x33);
@@ -262,12 +262,12 @@
 
 #endif
 
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
 	__attribute__ ((unused));
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
 	__attribute__ ((unused));
 
-extern inline unsigned int gcd(unsigned int x, unsigned int y)
+static inline unsigned int gcd(unsigned int x, unsigned int y)
 {
 	for (;;) {
 		if (!x)
@@ -281,7 +281,7 @@
 	}
 }
 
-extern inline unsigned int lcm(unsigned int x, unsigned int y)
+static inline unsigned int lcm(unsigned int x, unsigned int y)
 {
 	return x * y / gcd(x, y);
 }
diff -Nru a/drivers/net/hamradio/soundmodem/sm_afsk1200.c b/drivers/net/hamradio/soundmodem/sm_afsk1200.c
--- a/drivers/net/hamradio/soundmodem/sm_afsk1200.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/soundmodem/sm_afsk1200.c	Wed Apr  3 17:11:15 2002
@@ -94,7 +94,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
 {
 	int sum = -0x80 * csum;
 	
@@ -111,7 +111,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
 {
 	int sum = 0;
 	
@@ -128,7 +128,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
+static __inline__ int do_filter_1200_u8(const unsigned char *buf)
 {
 	int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
 	sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
@@ -137,7 +137,7 @@
 	return sum;
 }
 
-extern __inline__ int do_filter_1200_s16(const short *buf)
+static __inline__ int do_filter_1200_s16(const short *buf)
 {
 	int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
 	sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
diff -Nru a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c	Wed Apr  3 17:11:14 2002
@@ -104,7 +104,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
 {
 	int sum = -0x80 * csum;
 	
@@ -127,7 +127,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
 {
 	int sum = 0;
 	
@@ -150,7 +150,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
 {
 	int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
 	sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@
 	return sum;
 }
 
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
 {
 	int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
 	sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff -Nru a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
--- a/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c	Wed Apr  3 17:11:14 2002
@@ -104,7 +104,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
 {
 	int sum = -0x80 * csum;
 	
@@ -127,7 +127,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
 {
 	int sum = 0;
 	
@@ -150,7 +150,7 @@
 	return sum * sum;
 }
 
-extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+static __inline__ int do_filter_2400_u8(const unsigned char *buf)
 {
 	int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
 	sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
@@ -159,7 +159,7 @@
 	return sum;
 }
 
-extern __inline__ int do_filter_2400_s16(const short *buf)
+static __inline__ int do_filter_2400_s16(const short *buf)
 {
 	int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
 	sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
diff -Nru a/drivers/net/hamradio/soundmodem/sm_afsk2666.c b/drivers/net/hamradio/soundmodem/sm_afsk2666.c
--- a/drivers/net/hamradio/soundmodem/sm_afsk2666.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/hamradio/soundmodem/sm_afsk2666.c	Wed Apr  3 17:11:16 2002
@@ -114,7 +114,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
+static __inline__ int convolution12_u8(const unsigned char *st, const int *coeff, int csum)
 {
 	int sum = -0x80 * csum;
 	
@@ -134,7 +134,7 @@
 	return sum;
 }
 
-extern __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
+static __inline__ int convolution12_s16(const short *st, const int *coeff, int csum)
 {
 	int sum = 0;
 	
diff -Nru a/drivers/net/hamradio/soundmodem/sm_sbc.c b/drivers/net/hamradio/soundmodem/sm_sbc.c
--- a/drivers/net/hamradio/soundmodem/sm_sbc.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/soundmodem/sm_sbc.c	Wed Apr  3 17:11:14 2002
@@ -59,7 +59,7 @@
 #define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
 #define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
 
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
 {
         int i = verify_area(VERIFY_READ, from, n);
         if (i)
@@ -68,7 +68,7 @@
         return 0;
 }
 
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
 {
         int i = verify_area(VERIFY_WRITE, to, n);
         if (i)
diff -Nru a/drivers/net/hamradio/soundmodem/sm_wss.c b/drivers/net/hamradio/soundmodem/sm_wss.c
--- a/drivers/net/hamradio/soundmodem/sm_wss.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/hamradio/soundmodem/sm_wss.c	Wed Apr  3 17:11:15 2002
@@ -58,7 +58,7 @@
 #define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
 #define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
 
-extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+static inline int copy_from_user(void *to, const void *from, unsigned long n)
 {
         int i = verify_area(VERIFY_READ, from, n);
         if (i)
@@ -67,7 +67,7 @@
         return 0;
 }
 
-extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+static inline int copy_to_user(void *to, const void *from, unsigned long n)
 {
         int i = verify_area(VERIFY_WRITE, to, n);
         if (i)
diff -Nru a/drivers/net/hamradio/soundmodem/smdma.h b/drivers/net/hamradio/soundmodem/smdma.h
--- a/drivers/net/hamradio/soundmodem/smdma.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hamradio/soundmodem/smdma.h	Wed Apr  3 17:11:14 2002
@@ -52,7 +52,7 @@
 /*
  * returns the number of samples per fragment
  */
-extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
+static __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
 {
 	if (send) {
 		disable_dma(dmanr);
@@ -79,7 +79,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
+static __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
 				       unsigned int *curfrag)
 {
 	unsigned int dmaptr, sz, frg, offs;
@@ -120,7 +120,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
+static __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
 {
 	unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
 
@@ -137,7 +137,7 @@
 	return 0;
 }
 
-extern __inline__ void dma_transmit(struct sm_state *sm)
+static __inline__ void dma_transmit(struct sm_state *sm)
 {
 	void *p;
 
@@ -155,13 +155,13 @@
 	}
 }
 
-extern __inline__ void dma_init_transmit(struct sm_state *sm)
+static __inline__ void dma_init_transmit(struct sm_state *sm)
 {
 	sm->dma.ofragptr = 0;
 	sm->dma.ptt_cnt = 0;
 }
 
-extern __inline__ void dma_start_transmit(struct sm_state *sm)
+static __inline__ void dma_start_transmit(struct sm_state *sm)
 {
 	sm->dma.ofragptr = 0;
 	if (sm->dma.o16bit) {
@@ -174,7 +174,7 @@
 	sm->dma.ptt_cnt = 1;
 }
 
-extern __inline__ void dma_clear_transmit(struct sm_state *sm)
+static __inline__ void dma_clear_transmit(struct sm_state *sm)
 {
 	sm->dma.ptt_cnt = 0;
 	memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
@@ -182,7 +182,7 @@
 
 /* --------------------------------------------------------------------- */
 
-extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
+static __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
 {
 	void *p;
 
@@ -205,7 +205,7 @@
 	}
 }
 
-extern __inline__ void dma_init_receive(struct sm_state *sm)
+static __inline__ void dma_init_receive(struct sm_state *sm)
 {
 	sm->dma.ifragptr = 0;
 }
diff -Nru a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
--- a/drivers/net/hamradio/yam.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/hamradio/yam.c	Wed Apr  3 17:11:16 2002
@@ -308,7 +308,8 @@
 static void delay(int ms)
 {
 	unsigned long timeout = jiffies + ((ms * HZ) / 1000);
-	while (jiffies < timeout);
+	while (time_before(jiffies, timeout))
+		cpu_relax();
 }
 
 /*
diff -Nru a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
--- a/drivers/net/hp-plus.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/hp-plus.c	Wed Apr  3 17:11:14 2002
@@ -230,8 +230,8 @@
 		ei_status.block_output = &hpp_mem_block_output;
 		ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
 		dev->mem_start = mem_start;
-		dev->rmem_start = dev->mem_start + TX_2X_PAGES*256;
-		dev->mem_end = dev->rmem_end
+		ei_status.rmem_start = dev->mem_start + TX_2X_PAGES*256;
+		dev->mem_end = ei_status.rmem_end
 			= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
 	}
 
diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
--- a/drivers/net/irda/sa1100_ir.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/irda/sa1100_ir.c	Wed Apr  3 17:11:15 2002
@@ -597,6 +597,7 @@
 		sa1100_irda_rx_alloc(si);
 
 		netif_rx(skb);
+		dev->last_rx = jiffies;
 	} else {
 		/*
 		 * Remap the buffer.
diff -Nru a/drivers/net/lance.c b/drivers/net/lance.c
--- a/drivers/net/lance.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/lance.c	Wed Apr  3 17:11:14 2002
@@ -383,7 +383,7 @@
 					return 0;
 				}
 			}
-			release_resource(r);
+			release_region(ioaddr, LANCE_TOTAL_SIZE);
 		}
 	}
 	return -ENODEV;
diff -Nru a/drivers/net/lne390.c b/drivers/net/lne390.c
--- a/drivers/net/lne390.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/lne390.c	Wed Apr  3 17:11:16 2002
@@ -247,9 +247,9 @@
 				LNE390_STOP_PG/4, dev->mem_start);
 	}
 
-	dev->mem_end = dev->rmem_end = dev->mem_start
+	dev->mem_end = ei_status.rmem_end = dev->mem_start
 		+ (LNE390_STOP_PG - LNE390_START_PG)*256;
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 
 	/* The 8390 offset is zero for the LNE390 */
 	dev->base_addr = ioaddr;
@@ -334,12 +334,12 @@
 {
 	unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* Packet wraps over end of ring buffer. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk. */
 		isa_memcpy_fromio(skb->data, xfer_start, count);
diff -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c
--- a/drivers/net/ne3210.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/ne3210.c	Wed Apr  3 17:11:15 2002
@@ -234,9 +234,9 @@
 				NE3210_STOP_PG/4, dev->mem_start);
 	}
 
-	dev->mem_end = dev->rmem_end = dev->mem_start
+	dev->mem_end = ei_status.rmem_end = dev->mem_start
 		+ (NE3210_STOP_PG - NE3210_START_PG)*256;
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 
 	/* The 8390 offset is zero for the NE3210 */
 	dev->base_addr = ioaddr;
@@ -323,12 +323,12 @@
 {
 	unsigned long xfer_start = dev->mem_start + ring_offset - (NE3210_START_PG<<8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* Packet wraps over end of ring buffer. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk. */
 		isa_memcpy_fromio(skb->data, xfer_start, count);
diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c
--- a/drivers/net/ns83820.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/ns83820.c	Wed Apr  3 17:11:16 2002
@@ -797,23 +797,6 @@
 	}
 }
 
-/* I hate the network stack sometimes */
-#ifdef __i386__
-#define skb_mangle_for_davem(skb,len)	(skb)
-#else
-static inline struct sk_buff *skb_mangle_for_davem(struct sk_buff *skb, int len)
-{
-	tmp = __dev_alloc_skb(len+2, GFP_ATOMIC);
-	if (!tmp)
-		goto done;
-	tmp->dev = &dev->net_dev;
-	skb_reserve(tmp, 2);
-	memcpy(skb_put(tmp, len), skb->data, len);
-	kfree_skb(skb);
-	return tmp;
-}
-#endif
-
 static void FASTCALL(ns83820_rx_kick(struct ns83820 *dev));
 static void ns83820_rx_kick(struct ns83820 *dev)
 {
@@ -883,7 +866,6 @@
 		if (likely(CMDSTS_OK & cmdsts)) {
 			int len = cmdsts & 0xffff;
 			skb_put(skb, len);
-			skb = skb_mangle_for_davem(skb, len);
 			if (unlikely(!skb))
 				goto netdev_mangle_me_harder_failed;
 			if (cmdsts & CMDSTS_DEST_MULTI)
diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/pcnet32.c	Wed Apr  3 17:11:14 2002
@@ -511,7 +511,6 @@
 		struct pci_dev *pdev)
 {
     struct pcnet32_private *lp;
-    struct resource *res;
     dma_addr_t lp_dma_addr;
     int i, media;
     int fdx, mii, fset, dxsuflo, ltint;
@@ -689,13 +688,12 @@
     }
 
     dev->base_addr = ioaddr;
-    res = request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
-    if (!res)
+    if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL)
 	return -EBUSY;
     
     /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
     if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
-	release_resource(res);
+	release_region(ioaddr, PCNET32_TOTAL_SIZE);
 	return -ENOMEM;
     }
 
@@ -727,7 +725,7 @@
     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);
+      release_region(ioaddr, PCNET32_TOTAL_SIZE);
       return -ENODEV;
     }
     lp->a = *a;
@@ -775,7 +773,7 @@
 	else {
 	    printk(", failed to detect IRQ line.\n");
 	    pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
-	    release_resource(res);
+	    release_region(ioaddr, PCNET32_TOTAL_SIZE);
 	    return -ENODEV;
 	}
     }
diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c
--- a/drivers/net/sb1000.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/sb1000.c	Wed Apr  3 17:11:14 2002
@@ -196,7 +196,7 @@
 		/* check I/O base and IRQ */
 		if (dev->base_addr != 0 && dev->base_addr != ioaddr[0])
 			continue;
-		if (dev->rmem_end != 0 && dev->rmem_end != ioaddr[1])
+		if (dev->mem_start != 0 && dev->mem_start != ioaddr[1])
 			continue;
 		if (dev->irq != 0 && dev->irq != irq)
 			continue;
@@ -212,14 +212,14 @@
 		}
 		 
 		dev->base_addr = ioaddr[0];
-		/* rmem_end holds the second I/O address - fv */
-		dev->rmem_end = ioaddr[1];
+		/* mem_start holds the second I/O address */
+		dev->mem_start = ioaddr[1];
 		dev->irq = irq;
 
 		if (sb1000_debug > 0)
 			printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
 				"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
-				dev->rmem_end, serial_number, dev->irq);
+				dev->mem_start, serial_number, dev->irq);
 
 		dev = init_etherdev(dev, 0);
 		if (!dev)
@@ -405,7 +405,7 @@
 	}
 	timeout = jiffies + Sb1000TimeOutJiffies;
 	while (!(inb(ioaddr[1] + 6) & 0x40)) {
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
 				name);
 			return -ETIME;
@@ -423,7 +423,7 @@
 
 	timeout = jiffies + Sb1000TimeOutJiffies;
 	while (inb(ioaddr[1] + 6) & 0x80) {
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
 				name);
 			return -ETIME;
@@ -431,7 +431,7 @@
 	}
 	timeout = jiffies + Sb1000TimeOutJiffies;
 	while (inb(ioaddr[1] + 6) & 0x40) {
-		if (jiffies >= timeout) {
+		if (time_after_eq(jiffies, timeout)) {
 			printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
 				name);
 			return -ETIME;
@@ -935,8 +935,8 @@
 	const int ErrorDpcCounterInitialize = 200;
 
 	ioaddr[0] = dev->base_addr;
-	/* rmem_end holds the second I/O address - fv */
-	ioaddr[1] = dev->rmem_end;
+	/* mem_start holds the second I/O address */
+	ioaddr[1] = dev->mem_start;
 	name = dev->name;
 
 	sb1000_wait_for_ready_clear(ioaddr, name);
@@ -961,8 +961,8 @@
 	const unsigned short FirmwareVersion[] = {0x01, 0x01};
 
 	ioaddr[0] = dev->base_addr;
-	/* rmem_end holds the second I/O address - fv */
-	ioaddr[1] = dev->rmem_end;
+	/* mem_start holds the second I/O address */
+	ioaddr[1] = dev->mem_start;
 	name = dev->name;
 
 	/* initialize sb1000 */
@@ -1029,8 +1029,8 @@
 		return -ENODEV;
 
 	ioaddr[0] = dev->base_addr;
-	/* rmem_end holds the second I/O address - fv */
-	ioaddr[1] = dev->rmem_end;
+	/* mem_start holds the second I/O address */
+	ioaddr[1] = dev->mem_start;
 	name = dev->name;
 
 	switch (cmd) {
@@ -1130,8 +1130,8 @@
 	}
 
 	ioaddr[0] = dev->base_addr;
-	/* rmem_end holds the second I/O address - fv */
-	ioaddr[1] = dev->rmem_end;
+	/* mem_start holds the second I/O address */
+	ioaddr[1] = dev->mem_start;
 	name = dev->name;
 
 	/* is it a good interrupt? */
@@ -1189,8 +1189,8 @@
 	netif_stop_queue(dev);
 	
 	ioaddr[0] = dev->base_addr;
-	/* rmem_end holds the second I/O address - fv */
-	ioaddr[1] = dev->rmem_end;
+	/* mem_start holds the second I/O address */
+	ioaddr[1] = dev->mem_start;
 
 	free_irq(dev->irq, dev);
 	/* If we don't do this, we can't re-insmod it later. */
@@ -1234,8 +1234,8 @@
 	}
 	dev_sb1000.init = sb1000_probe;
 	dev_sb1000.base_addr = io[0];
-	/* rmem_end holds the second I/O address - fv */
-	dev_sb1000.rmem_end = io[1];
+	/* mem_start holds the second I/O address */
+	dev_sb1000.mem_start = io[1];
 	dev_sb1000.irq = irq;
 	if (register_netdev(&dev_sb1000) != 0) {
 		printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x   "
@@ -1249,7 +1249,7 @@
 {
 	unregister_netdev(&dev_sb1000);
 	release_region(dev_sb1000.base_addr, 16);
-	release_region(dev_sb1000.rmem_end, 16);
+	release_region(dev_sb1000.mem_start, 16);
 	kfree(dev_sb1000.priv);
 	dev_sb1000.priv = NULL;
 }
diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/sb1250-mac.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,2673 @@
+/*
+ * Copyright (C) 2001 Broadcom 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.
+ */
+
+/*
+  This driver is designed for the Broadcom BCM12500 SOC chip's built-in
+  Ethernet controllers.
+  
+  The author may be reached as mpl@broadcom.com
+*/
+
+
+/* A few user-configurable values.
+   These may be modified when a driver module is loaded. */
+
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+
+/* 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 3		/* More are supported, limit only on options */
+#ifdef MODULE
+static int options[MAX_UNITS] = {-1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1};
+#endif
+
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (2*HZ)
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error  You must compile this driver with "-O".
+#endif
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/64bit.h>
+
+/* This is only here until the firmware is ready.  In that case,
+   the firmware leaves the ethernet address in the register for us. */
+#ifdef CONFIG_SWARM_STANDALONE
+#define SBMAC_ETH0_HWADDR "40:00:00:00:01:00"
+#define SBMAC_ETH1_HWADDR "40:00:00:00:01:01"
+#define SBMAC_ETH2_HWADDR "40:00:00:00:01:02"
+#endif
+
+
+/* These identify the driver base version and may not be removed. */
+#if 0
+static char version1[] __devinitdata =
+"sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg (mpl@broadcom.com)\n";
+#endif
+
+
+
+MODULE_AUTHOR("Mitch Lichtenberg (mpl@broadcom.com)");
+MODULE_DESCRIPTION("Broadcom BCM12500 SOC GB Ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+
+#include <asm/sibyte/sb1250_defs.h>
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_mac.h>
+#include <asm/sibyte/sb1250_dma.h>
+#include <asm/sibyte/sb1250_int.h>
+
+
+/**********************************************************************
+ *  Simple types
+ ********************************************************************* */
+
+
+typedef unsigned long sbmac_port_t;
+typedef uint64_t sbmac_physaddr_t;
+typedef uint64_t sbmac_enetaddr_t;
+
+typedef enum { sbmac_speed_auto, sbmac_speed_10,
+	       sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
+
+typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
+	       sbmac_duplex_full } sbmac_duplex_t;
+
+typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
+	       sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
+
+typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, 
+	       sbmac_state_broken } sbmac_state_t;
+
+
+/**********************************************************************
+ *  Macros
+ ********************************************************************* */
+
+
+#define SBDMA_NEXTBUF(d,f) ((((d)->f+1) == (d)->sbdma_dscrtable_end) ? \
+			  (d)->sbdma_dscrtable : (d)->f+1)
+
+
+#define CACHELINESIZE 32
+#define NUMCACHEBLKS(x) (((x)+CACHELINESIZE-1)/CACHELINESIZE)
+#define KMALLOC(x) kmalloc((x),GFP_KERNEL)
+#define KFREE(x) kfree(x)
+#define KVTOPHYS(x) virt_to_bus((void *)(x))
+
+ 
+#define SBMAC_READCSR(t)    (in64((unsigned long)(t)))
+#define SBMAC_WRITECSR(t,v) (out64(v, (unsigned long)(t)))
+
+#define PKSEG1(x) ((sbmac_port_t) KSEG1ADDR(x))
+
+#define SBMAC_MAX_TXDESCR	32
+#define SBMAC_MAX_RXDESCR	32
+
+#define ETHER_ALIGN	2
+#define ETHER_ADDR_LEN	6
+#define ENET_PACKET_SIZE	1518
+
+/**********************************************************************
+ *  DMA Descriptor structure
+ ********************************************************************* */
+
+typedef struct sbdmadscr_s {
+	uint64_t  dscr_a;
+	uint64_t  dscr_b;
+} sbdmadscr_t;
+
+typedef unsigned long paddr_t;
+typedef unsigned long vaddr_t;
+
+/**********************************************************************
+ *  DMA Controller structure
+ ********************************************************************* */
+
+typedef struct sbmacdma_s {
+	
+	/* 
+	 * This stuff is used to identify the channel and the registers
+	 * associated with it.
+	 */
+	
+	struct sbmac_softc *sbdma_eth;	        /* back pointer to associated MAC */
+	int              sbdma_channel;	/* channel number */
+	int		     sbdma_txdir;       /* direction (1=transmit) */
+	int		     sbdma_maxdescr;	/* total # of descriptors in ring */
+	sbmac_port_t     sbdma_config0;	/* DMA config register 0 */
+	sbmac_port_t     sbdma_config1;	/* DMA config register 1 */
+	sbmac_port_t     sbdma_dscrbase;	/* Descriptor base address */
+	sbmac_port_t     sbdma_dscrcnt;     /* Descriptor count register */
+	sbmac_port_t     sbdma_curdscr;	/* current descriptor address */
+	
+	/*
+	 * This stuff is for maintenance of the ring
+	 */
+	
+	sbdmadscr_t     *sbdma_dscrtable;	/* base of descriptor table */
+	sbdmadscr_t     *sbdma_dscrtable_end; /* end of descriptor table */
+	
+	struct sk_buff **sbdma_ctxtable;    /* context table, one per descr */
+	
+	paddr_t          sbdma_dscrtable_phys; /* and also the phys addr */
+	sbdmadscr_t     *sbdma_addptr;	/* next dscr for sw to add */
+	sbdmadscr_t     *sbdma_remptr;	/* next dscr for sw to remove */
+	
+} sbmacdma_t;
+
+
+/**********************************************************************
+ *  Ethernet softc structure
+ ********************************************************************* */
+
+struct sbmac_softc {
+	
+	/*
+	 * Linux-specific things
+	 */
+	
+	struct net_device *sbm_dev;		/* pointer to linux device */
+	spinlock_t sbm_lock;		/* spin lock */
+	struct timer_list sbm_timer;     	/* for monitoring MII */
+	struct net_device_stats sbm_stats; 
+	int sbm_devflags;			/* current device flags */
+
+        int	     sbm_phy_oldbmsr;
+        int	     sbm_phy_oldanlpar;
+        int	     sbm_phy_oldk1stsr;
+        int          sbm_phy_oldlinkstat;
+	int sbm_buffersize;
+	
+	unsigned char sbm_phys[2];
+	
+	/*
+	 * Controller-specific things
+	 */
+	
+	sbmac_port_t     sbm_base;          /* MAC's base address */
+	sbmac_state_t    sbm_state;         /* current state */
+	
+	sbmac_port_t     sbm_macenable;	/* MAC Enable Register */
+	sbmac_port_t     sbm_maccfg;	/* MAC Configuration Register */
+	sbmac_port_t     sbm_fifocfg;	/* FIFO configuration register */
+	sbmac_port_t     sbm_framecfg;	/* Frame configuration register */
+	sbmac_port_t     sbm_rxfilter;	/* receive filter register */
+	sbmac_port_t     sbm_isr;		/* Interrupt status register */
+	sbmac_port_t     sbm_imr;		/* Interrupt mask register */
+	sbmac_port_t     sbm_mdio;		/* MDIO register */
+	
+	sbmac_speed_t    sbm_speed;		/* current speed */
+	sbmac_duplex_t   sbm_duplex;	/* current duplex */
+	sbmac_fc_t       sbm_fc;		/* current flow control setting */
+	
+	u_char           sbm_hwaddr[ETHER_ADDR_LEN];
+	
+	sbmacdma_t       sbm_txdma;		/* for now, only use channel 0 */
+	sbmacdma_t       sbm_rxdma;
+	
+};
+
+
+/**********************************************************************
+ *  Externs
+ ********************************************************************* */
+
+/**********************************************************************
+ *  Prototypes
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+			  struct sbmac_softc *s,
+			  int chan,
+			  int txrx,
+			  int maxdescr);
+static void sbdma_channel_start(sbmacdma_t *d);
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
+static void sbdma_emptyring(sbmacdma_t *d);
+static void sbdma_fillring(sbmacdma_t *d);
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbmac_initctx(struct sbmac_softc *s);
+static void sbmac_channel_start(struct sbmac_softc *s);
+static void sbmac_channel_stop(struct sbmac_softc *s);
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+/*static void sbmac_init_and_start(struct sbmac_softc *sc);*/
+static uint64_t sbmac_addr2reg(unsigned char *ptr);
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
+static void sbmac_setmulti(struct sbmac_softc *sc);
+static int sbmac_init(struct net_device *dev);
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+
+static int sbmac_open(struct net_device *dev);
+static void sbmac_timer(unsigned long data);
+static void sbmac_tx_timeout (struct net_device *dev);
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
+static void sbmac_set_rx_mode(struct net_device *dev);
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int sbmac_close(struct net_device *dev);
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+
+static void sbmac_mii_sync(struct sbmac_softc *s);
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+			    unsigned int regval);
+
+
+/**********************************************************************
+ *  Globals
+ ********************************************************************* */
+
+
+/**********************************************************************
+ *  MDIO constants
+ ********************************************************************* */
+
+#define	MII_COMMAND_START	0x01
+#define	MII_COMMAND_READ	0x02
+#define	MII_COMMAND_WRITE	0x01
+#define	MII_COMMAND_ACK		0x02
+
+#define BMCR_RESET     0x8000
+#define BMCR_LOOPBACK  0x4000
+#define BMCR_SPEED0    0x2000
+#define BMCR_ANENABLE  0x1000
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE   0x0400
+#define BMCR_RESTARTAN 0x0200
+#define BMCR_DUPLEX    0x0100
+#define BMCR_COLTEST   0x0080
+#define BMCR_SPEED1    0x0040
+#define BMCR_SPEED1000 (BMCR_SPEED1|BMCR_SPEED0)
+#define BMCR_SPEED100  (BMCR_SPEED0)
+#define BMCR_SPEED10 	0
+
+#define BMSR_100BT4	0x8000
+#define BMSR_100BT_FDX	0x4000
+#define BMSR_100BT_HDX  0x2000
+#define BMSR_10BT_FDX   0x1000
+#define BMSR_10BT_HDX   0x0800
+#define BMSR_100BT2_FDX 0x0400
+#define BMSR_100BT2_HDX 0x0200
+#define BMSR_1000BT_XSR	0x0100
+#define BMSR_PRESUP	0x0040
+#define BMSR_ANCOMPLT	0x0020
+#define BMSR_REMFAULT	0x0010
+#define BMSR_AUTONEG	0x0008
+#define BMSR_LINKSTAT	0x0004
+#define BMSR_JABDETECT	0x0002
+#define BMSR_EXTCAPAB	0x0001
+
+#define PHYIDR1 	0x2000
+#define PHYIDR2		0x5C60
+
+#define ANAR_NP		0x8000
+#define ANAR_RF		0x2000
+#define ANAR_ASYPAUSE	0x0800
+#define ANAR_PAUSE	0x0400
+#define ANAR_T4		0x0200
+#define ANAR_TXFD	0x0100
+#define ANAR_TXHD	0x0080
+#define ANAR_10FD	0x0040
+#define ANAR_10HD	0x0020
+#define ANAR_PSB	0x0001
+
+#define ANLPAR_NP	0x8000
+#define ANLPAR_ACK	0x4000
+#define ANLPAR_RF	0x2000
+#define ANLPAR_ASYPAUSE	0x0800
+#define ANLPAR_PAUSE	0x0400
+#define ANLPAR_T4	0x0200
+#define ANLPAR_TXFD	0x0100
+#define ANLPAR_TXHD	0x0080
+#define ANLPAR_10FD	0x0040
+#define ANLPAR_10HD	0x0020
+#define ANLPAR_PSB	0x0001	/* 802.3 */
+
+#define ANER_PDF	0x0010
+#define ANER_LPNPABLE	0x0008
+#define ANER_NPABLE	0x0004
+#define ANER_PAGERX	0x0002
+#define ANER_LPANABLE	0x0001
+
+#define ANNPTR_NP	0x8000
+#define ANNPTR_MP	0x2000
+#define ANNPTR_ACK2	0x1000
+#define ANNPTR_TOGTX	0x0800
+#define ANNPTR_CODE	0x0008
+
+#define ANNPRR_NP	0x8000
+#define ANNPRR_MP	0x2000
+#define ANNPRR_ACK3	0x1000
+#define ANNPRR_TOGTX	0x0800
+#define ANNPRR_CODE	0x0008
+
+#define K1TCR_TESTMODE	0x0000
+#define K1TCR_MSMCE	0x1000
+#define K1TCR_MSCV	0x0800
+#define K1TCR_RPTR	0x0400
+#define K1TCR_1000BT_FDX 0x200
+#define K1TCR_1000BT_HDX 0x100
+
+#define K1STSR_MSMCFLT	0x8000
+#define K1STSR_MSCFGRES	0x4000
+#define K1STSR_LRSTAT	0x2000
+#define K1STSR_RRSTAT	0x1000
+#define K1STSR_LP1KFD	0x0800
+#define K1STSR_LP1KHD   0x0400
+#define K1STSR_LPASMDIR	0x0200
+
+#define K1SCR_1KX_FDX	0x8000
+#define K1SCR_1KX_HDX	0x4000
+#define K1SCR_1KT_FDX	0x2000
+#define K1SCR_1KT_HDX	0x1000
+
+#define STRAP_PHY1	0x0800
+#define STRAP_NCMODE	0x0400
+#define STRAP_MANMSCFG	0x0200
+#define STRAP_ANENABLE	0x0100
+#define STRAP_MSVAL	0x0080
+#define STRAP_1KHDXADV	0x0010
+#define STRAP_1KFDXADV	0x0008
+#define STRAP_100ADV	0x0004
+#define STRAP_SPEEDSEL	0x0000
+#define STRAP_SPEED100	0x0001
+
+#define PHYSUP_SPEED1000 0x10
+#define PHYSUP_SPEED100  0x08
+#define PHYSUP_SPEED10   0x00
+#define PHYSUP_LINKUP	 0x04
+#define PHYSUP_FDX       0x02
+
+#define	MII_BMCR	0x00 	/* Basic mode control register (rw) */
+#define	MII_BMSR	0x01	/* Basic mode status register (ro) */
+#define MII_K1STSR	0x0A	/* 1K Status Register (ro) */
+#define	MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
+
+
+#define M_MAC_MDIO_DIR_OUTPUT	0		/* for clarity */
+
+
+/**********************************************************************
+ *  SBMAC_MII_SYNC(s)
+ *  
+ *  Synchronize with the MII - send a pattern of bits to the MII
+ *  that will guarantee that it is ready to accept a command.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_mii_sync(struct sbmac_softc *s)
+{
+	int cnt;
+	uint64_t bits;
+	
+	bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
+	
+	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	
+	for (cnt = 0; cnt < 32; cnt++) {
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+		SBMAC_WRITECSR(s->sbm_mdio,bits);
+	}
+}
+
+/**********************************************************************
+ *  SBMAC_MII_SENDDATA(s,data,bitcnt)
+ *  
+ *  Send some bits to the MII.  The bits to be sent are right-
+ *  justified in the 'data' parameter.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   data - data to send
+ *  	   bitcnt - number of bits to send
+ ********************************************************************* */
+
+static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+{
+	int i;
+	uint64_t bits;
+	unsigned int curmask;
+	
+	bits = M_MAC_MDIO_DIR_OUTPUT;
+	SBMAC_WRITECSR(s->sbm_mdio,bits);
+	
+	curmask = 1 << (bitcnt - 1);
+	
+	for (i = 0; i < bitcnt; i++) {
+		if (data & curmask) bits |= M_MAC_MDIO_OUT;
+		else bits &= ~M_MAC_MDIO_OUT;
+		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		SBMAC_WRITECSR(s->sbm_mdio,bits | M_MAC_MDC);
+		SBMAC_WRITECSR(s->sbm_mdio,bits);
+		curmask >>= 1;
+	}
+}
+
+
+
+/**********************************************************************
+ *  SBMAC_MII_READ(s,phyaddr,regidx)
+ *  
+ *  Read a PHY register.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   phyaddr - PHY's address
+ *  	   regidx = index of register to read
+ *  	   
+ *  Return value:
+ *  	   value read, or 0 if an error occured.
+ ********************************************************************* */
+
+static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+{
+	int idx;
+	int error;
+	int regval;
+	
+	/*
+	 * Synchronize ourselves so that the PHY knows the next
+	 * thing coming down is a command
+	 */
+	
+	sbmac_mii_sync(s);
+	
+	/*
+	 * Send the data to the PHY.  The sequence is
+	 * a "start" command (2 bits)
+	 * a "read" command (2 bits)
+	 * the PHY addr (5 bits)
+	 * the register index (5 bits)
+	 */
+	
+	sbmac_mii_senddata(s,MII_COMMAND_START, 2);
+	sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
+	sbmac_mii_senddata(s,phyaddr, 5);
+	sbmac_mii_senddata(s,regidx, 5);
+	
+	/* 
+	 * Switch the port around without a clock transition.
+	 */
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	
+	/*
+	 * Send out a clock pulse to signal we want the status
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	
+	/* 
+	 * If an error occured, the PHY will signal '1' back
+	 */
+	error = SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN;
+	
+	/* 
+	 * Issue an 'idle' clock pulse, but keep the direction
+	 * the same.
+	 */
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	
+	regval = 0;
+	
+	for (idx = 0; idx < 16; idx++) {
+		regval <<= 1;
+		
+		if (error == 0) {
+			if (SBMAC_READCSR(s->sbm_mdio) & M_MAC_MDIO_IN) regval |= 1;
+		}
+		
+		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT | M_MAC_MDC);
+		SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_INPUT);
+	}
+	
+	/* Switch back to output */
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+	
+	if (error == 0) return regval;
+	return 0;
+}
+
+
+/**********************************************************************
+ *  SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ *  
+ *  Write a value to a PHY register.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   phyaddr - PHY to use
+ *  	   regidx - register within the PHY
+ *  	   regval - data to write to register
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
+			    unsigned int regval)
+{
+	
+	sbmac_mii_sync(s);
+	
+	sbmac_mii_senddata(s,MII_COMMAND_START,2);
+	sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
+	sbmac_mii_senddata(s,phyaddr, 5);
+	sbmac_mii_senddata(s,regidx, 5);
+	sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
+	sbmac_mii_senddata(s,regval,16);
+	
+	SBMAC_WRITECSR(s->sbm_mdio,M_MAC_MDIO_DIR_OUTPUT);
+}
+
+
+
+/**********************************************************************
+ *  SBDMA_INITCTX(d,s,chan,txrx,maxdescr)
+ *  
+ *  Initialize a DMA channel context.  Since there are potentially
+ *  eight DMA channels per MAC, it's nice to do this in a standard
+ *  way.  
+ *  
+ *  Input parameters: 
+ *  	   d - sbmacdma_t structure (DMA channel context)
+ *  	   s - sbmac_softc structure (pointer to a MAC)
+ *  	   chan - channel number (0..1 right now)
+ *  	   txrx - Identifies DMA_TX or DMA_RX for channel direction
+ *      maxdescr - number of descriptors
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_initctx(sbmacdma_t *d,
+			  struct sbmac_softc *s,
+			  int chan,
+			  int txrx,
+			  int maxdescr)
+{
+	/* 
+	 * Save away interesting stuff in the structure 
+	 */
+	
+	d->sbdma_eth       = s;
+	d->sbdma_channel   = chan;
+	d->sbdma_txdir     = txrx;
+	
+	/* 
+	 * initialize register pointers 
+	 */
+	
+	d->sbdma_config0 = 
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+	d->sbdma_config1 = 
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CONFIG0));
+	d->sbdma_dscrbase = 
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_BASE));
+	d->sbdma_dscrcnt = 
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT));
+	d->sbdma_curdscr = 	
+		PKSEG1(s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR));
+	
+	/*
+	 * Allocate memory for the ring
+	 */
+	
+	d->sbdma_maxdescr = maxdescr;
+	
+	d->sbdma_dscrtable = (sbdmadscr_t *) 
+		KMALLOC(d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+	
+	memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+	
+	d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
+	
+	d->sbdma_dscrtable_phys = KVTOPHYS(d->sbdma_dscrtable);
+	
+	/*
+	 * And context table
+	 */
+	
+	d->sbdma_ctxtable = (struct sk_buff **) 
+		KMALLOC(d->sbdma_maxdescr*sizeof(struct sk_buff *));
+	
+	memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+	
+}
+
+/**********************************************************************
+ *  SBDMA_CHANNEL_START(d)
+ *  
+ *  Initialize the hardware registers for a DMA channel.
+ *  
+ *  Input parameters: 
+ *  	   d - DMA channel to init (context must be previously init'd
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_channel_start(sbmacdma_t *d)
+{
+	/*
+	 * Turn on the DMA channel
+	 */
+	
+	SBMAC_WRITECSR(d->sbdma_config1,0);
+	
+	SBMAC_WRITECSR(d->sbdma_dscrbase,d->sbdma_dscrtable_phys);
+	
+	SBMAC_WRITECSR(d->sbdma_config0,
+		       V_DMA_RINGSZ(d->sbdma_maxdescr) |
+		       0);
+	
+	/*
+	 * Initialize ring pointers
+	 */
+	
+	d->sbdma_addptr = d->sbdma_dscrtable;
+	d->sbdma_remptr = d->sbdma_dscrtable;
+}
+
+
+static void sbdma_align_skb(struct sk_buff *skb,int power2,int offset)
+{
+	unsigned long addr;
+	unsigned long newaddr;
+	
+	addr = (unsigned long) skb->data;
+	
+	newaddr = (addr + power2 - 1) & ~(power2 - 1);
+	
+	skb_reserve(skb,newaddr-addr+offset);
+}
+
+
+/**********************************************************************
+ *  SBDMA_ADD_RCVBUFFER(d,sb)
+ *  
+ *  Add a buffer to the specified DMA channel.   For receive channels,
+ *  this queues a buffer for inbound packets.
+ *  
+ *  Input parameters: 
+ *  	   d - DMA channel descriptor
+ * 	   sb - sk_buff to add, or NULL if we should allocate one
+ *  	   
+ *  Return value:
+ *  	   0 if buffer could not be added (ring is full)
+ *  	   1 if buffer added successfully
+ ********************************************************************* */
+
+
+static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+	sbdmadscr_t *dsc;
+	sbdmadscr_t *nextdsc;
+	struct sk_buff *sb_new = NULL;
+	int pktsize = ENET_PACKET_SIZE;
+	
+	/* get pointer to our current place in the ring */
+	
+	dsc = d->sbdma_addptr;
+	nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+	
+	/*
+	 * figure out if the ring is full - if the next descriptor
+	 * is the same as the one that we're going to remove from
+	 * the ring, the ring is full
+	 */
+	
+	if (nextdsc == d->sbdma_remptr) {
+		return -ENOSPC;
+	}
+	
+	/* 
+	 * Allocate a sk_buff if we don't already have one.  
+	 * If we do have an sk_buff, reset it so that it's empty.
+	 *
+	 * Note: sk_buffs don't seem to be guaranteed to have any sort
+	 * of alignment when they are allocated.  Therefore, allocate enough
+	 * extra space to make sure that:
+	 *
+	 *    1. the data does not start in the middle of a cache line.
+	 *    2. The data does not end in the middle of a cache line
+	 * 	  3. The buffer can be aligned such that the IP addresses are 
+	 *       naturally aligned.
+	 *
+	 *  Remember, the SB1250's MAC writes whole cache lines at a time,
+	 *  without reading the old contents first.  So, if the sk_buff's
+	 *  data portion starts in the middle of a cache line, the SB1250
+	 *  DMA will trash the beginning (and ending) portions.
+	 */
+	
+	if (sb == NULL) {
+		sb_new = dev_alloc_skb(ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN);
+		if (sb_new == NULL) {
+			printk(KERN_INFO "%s: sk_buff allocation failed\n",
+			       d->sbdma_eth->sbm_dev->name);
+			return -ENOBUFS;
+		}
+		
+		sbdma_align_skb(sb_new,CACHELINESIZE,ETHER_ALIGN);
+		
+		/* mark skbuff owned by our device */
+		sb_new->dev = d->sbdma_eth->sbm_dev;
+	}
+	else {
+		sb_new = sb;
+		/* 
+		 * nothing special to reinit buffer, it's already aligned
+		 * and sb->tail already points to a good place.
+		 */
+	}
+	
+	/*
+	 * fill in the descriptor 
+	 */
+	
+	dsc->dscr_a = KVTOPHYS(sb_new->tail) |
+		V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
+		M_DMA_DSCRA_INTERRUPT;
+	
+	/* receiving: no options */
+	dsc->dscr_b = 0;
+	
+	/*
+	 * fill in the context 
+	 */
+	
+	d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb_new;
+	
+	/* 
+	 * point at next packet 
+	 */
+	
+	d->sbdma_addptr = nextdsc;
+	
+	/* 
+	 * Give the buffer to the DMA engine.
+	 */
+	
+	SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+	
+	return 0;					/* we did it */
+}
+
+/**********************************************************************
+ *  SBDMA_ADD_TXBUFFER(d,sb)
+ *  
+ *  Add a transmit buffer to the specified DMA channel, causing a
+ *  transmit to start.
+ *  
+ *  Input parameters: 
+ *  	   d - DMA channel descriptor
+ * 	   sb - sk_buff to add
+ *  	   
+ *  Return value:
+ *  	   0 transmit queued successfully
+ *  	   otherwise error code
+ ********************************************************************* */
+
+
+static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+{
+	sbdmadscr_t *dsc;
+	sbdmadscr_t *nextdsc;
+	uint64_t phys;
+	uint64_t ncb;
+	int length;
+	
+	/* get pointer to our current place in the ring */
+	
+	dsc = d->sbdma_addptr;
+	nextdsc = SBDMA_NEXTBUF(d,sbdma_addptr);
+	
+	/*
+	 * figure out if the ring is full - if the next descriptor
+	 * is the same as the one that we're going to remove from
+	 * the ring, the ring is full
+	 */
+	
+	if (nextdsc == d->sbdma_remptr) {
+		return -ENOSPC;
+	}
+	
+	/*
+	 * Under Linux, it's not necessary to copy/coalesce buffers
+	 * like it is on NetBSD.  We think they're all contiguous,
+	 * but that may not be true for GBE.
+	 */
+	
+	length = sb->len;
+	
+	/*
+	 * fill in the descriptor.  Note that the number of cache
+	 * blocks in the descriptor is the number of blocks
+	 * *spanned*, so we need to add in the offset (if any)
+	 * while doing the calculation.
+	 */
+	
+	phys = KVTOPHYS(sb->data);
+	ncb = NUMCACHEBLKS(length+(phys & (CACHELINESIZE-1)));
+	
+	dsc->dscr_a = phys | 
+		V_DMA_DSCRA_A_SIZE(ncb) |
+		M_DMA_DSCRA_INTERRUPT |
+		M_DMA_ETHTX_SOP;
+	
+	/* transmitting: set outbound options and length */
+
+	dsc->dscr_b = V_DMA_DSCRB_OPTIONS(K_DMA_ETHTX_APPENDCRC_APPENDPAD) |
+		V_DMA_DSCRB_PKT_SIZE(length);
+	
+	/*
+	 * fill in the context 
+	 */
+	
+	d->sbdma_ctxtable[dsc-d->sbdma_dscrtable] = sb;
+	
+	/* 
+	 * point at next packet 
+	 */
+	
+	d->sbdma_addptr = nextdsc;
+	
+	/* 
+	 * Give the buffer to the DMA engine.
+	 */
+	
+	SBMAC_WRITECSR(d->sbdma_dscrcnt,1);
+	
+	return 0;					/* we did it */
+}
+
+
+
+
+/**********************************************************************
+ *  SBDMA_EMPTYRING(d)
+ *  
+ *  Free all allocated sk_buffs on the specified DMA channel;
+ *  
+ *  Input parameters: 
+ *  	   d  - DMA channel
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_emptyring(sbmacdma_t *d)
+{
+	int idx;
+	struct sk_buff *sb;
+	
+	for (idx = 0; idx < d->sbdma_maxdescr; idx++) {
+		sb = d->sbdma_ctxtable[idx];
+		if (sb) {
+			dev_kfree_skb(sb);
+			d->sbdma_ctxtable[idx] = NULL;
+		}
+	}
+}
+
+
+/**********************************************************************
+ *  SBDMA_FILLRING(d)
+ *  
+ *  Fill the specified DMA channel (must be receive channel)
+ *  with sk_buffs
+ *  
+ *  Input parameters: 
+ *  	   d - DMA channel
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_fillring(sbmacdma_t *d)
+{
+	int idx;
+	
+	for (idx = 0; idx < SBMAC_MAX_RXDESCR-1; idx++) {
+		if (sbdma_add_rcvbuffer(d,NULL) != 0) break;
+	}
+}
+
+
+/**********************************************************************
+ *  SBDMA_RX_PROCESS(sc,d)
+ *  
+ *  Process "completed" receive buffers on the specified DMA channel.  
+ *  Note that this isn't really ideal for priority channels, since
+ *  it processes all of the packets on a given channel before 
+ *  returning. 
+ *
+ *  Input parameters: 
+ *	   sc - softc structure
+ *  	   d - DMA channel context
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+	int curidx;
+	int hwidx;
+	sbdmadscr_t *dsc;
+	struct sk_buff *sb;
+	int len;
+	
+	for (;;) {
+		/* 
+		 * figure out where we are (as an index) and where
+		 * the hardware is (also as an index)
+		 *
+		 * This could be done faster if (for example) the 
+		 * descriptor table was page-aligned and contiguous in
+		 * both virtual and physical memory -- you could then
+		 * just compare the low-order bits of the virtual address
+		 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+		 */
+		
+		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+		hwidx = (int) (((SBMAC_READCSR(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+		
+		/*
+		 * If they're the same, that means we've processed all
+		 * of the descriptors up to (but not including) the one that
+		 * the hardware is working on right now.
+		 */
+		
+		if (curidx == hwidx) break;
+		
+		/*
+		 * Otherwise, get the packet's sk_buff ptr back
+		 */
+		
+		dsc = &(d->sbdma_dscrtable[curidx]);
+		sb = d->sbdma_ctxtable[curidx];
+		d->sbdma_ctxtable[curidx] = NULL;
+		
+		len = (int)G_DMA_DSCRB_PKT_SIZE(dsc->dscr_b) - 4;
+		
+		/*
+		 * Check packet status.  If good, process it.
+		 * If not, silently drop it and put it back on the
+		 * receive ring.
+		 */
+		
+		if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+			
+			/*
+			 * Set length into the packet
+			 */
+			skb_put(sb,len);
+			
+       			/*
+			 * Add a new buffer to replace the old one.  If we fail
+			 * to allocate a buffer, we're going to drop this
+			 * packet and put it right back on the receive ring.
+			 */
+			
+			if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
+			    sbdma_add_rcvbuffer(d,sb);	/* re-add old buffer */
+			    }
+			else {
+			    /*
+			     * Buffer has been replaced on the receive ring.
+			     * Pass the buffer to the kernel
+			     */
+			    sc->sbm_stats.rx_bytes += len;
+			    sc->sbm_stats.rx_packets++;
+			    sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
+			    netif_rx(sb);
+			    }
+		}
+		else {
+			/*
+			 * Packet was mangled somehow.  Just drop it and
+			 * put it back on the receive ring.
+			 */
+			sbdma_add_rcvbuffer(d,sb);
+		}
+		
+		
+		/* 
+		 * .. and advance to the next buffer.
+		 */
+		
+		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+		
+	}
+}
+
+
+
+/**********************************************************************
+ *  SBDMA_TX_PROCESS(sc,d)
+ *  
+ *  Process "completed" transmit buffers on the specified DMA channel.  
+ *  This is normally called within the interrupt service routine.
+ *  Note that this isn't really ideal for priority channels, since
+ *  it processes all of the packets on a given channel before 
+ *  returning. 
+ *
+ *  Input parameters: 
+ *      sc - softc structure
+ *  	   d - DMA channel context
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+{
+	int curidx;
+	int hwidx;
+	sbdmadscr_t *dsc;
+	struct sk_buff *sb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&(sc->sbm_lock), flags);
+	
+	for (;;) {
+		/* 
+		 * figure out where we are (as an index) and where
+		 * the hardware is (also as an index)
+		 *
+		 * This could be done faster if (for example) the 
+		 * descriptor table was page-aligned and contiguous in
+		 * both virtual and physical memory -- you could then
+		 * just compare the low-order bits of the virtual address
+		 * (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
+		 */
+		
+		curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+		{
+			/* XXX This is gross, ugly, and only here because justin hacked it
+			   in to fix a problem without really understanding it. 
+			   
+			   It seems that, for whatever reason, this routine is invoked immediately upon the enabling of interrupts.
+			   So then the Read below returns zero, making hwidx a negative number, and anti-hilarity
+			   ensues.
+			   
+			   I'm guessing there's a proper fix involving clearing out interrupt state from old packets
+			   before enabling interrupts, but I'm not sure.  
+
+			   Anyways, this hack seems to work, and is Good Enough for 11 PM.  :)
+			   
+			   -Justin
+			*/
+			  
+			uint64_t tmp = SBMAC_READCSR(d->sbdma_curdscr);
+			if (!tmp) {
+				break;
+			}
+			hwidx = (int) (((tmp & M_DMA_CURDSCR_ADDR) -
+					d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+		}
+		/*
+		 * If they're the same, that means we've processed all
+		 * of the descriptors up to (but not including) the one that
+		 * the hardware is working on right now.
+		 */
+		
+		if (curidx == hwidx) break;
+		
+		/*
+		 * Otherwise, get the packet's sk_buff ptr back
+		 */
+		
+		dsc = &(d->sbdma_dscrtable[curidx]);
+		sb = d->sbdma_ctxtable[curidx];
+		d->sbdma_ctxtable[curidx] = NULL;
+		
+		/*
+		 * Stats
+		 */
+		
+		sc->sbm_stats.tx_bytes += sb->len;
+		sc->sbm_stats.tx_packets++;
+		
+		/*
+		 * for transmits, we just free buffers.
+		 */
+		
+		dev_kfree_skb_irq(sb);
+		
+		/* 
+		 * .. and advance to the next buffer.
+		 */
+
+		d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+		
+	}
+	
+	/*
+	 * Decide if we should wake up the protocol or not.
+	 * Other drivers seem to do this when we reach a low
+	 * watermark on the transmit queue.
+	 */
+	
+	netif_wake_queue(d->sbdma_eth->sbm_dev);
+	
+	spin_unlock_irqrestore(&(sc->sbm_lock), flags);
+	
+}
+
+
+
+/**********************************************************************
+ *  SBMAC_INITCTX(s)
+ *  
+ *  Initialize an Ethernet context structure - this is called
+ *  once per MAC on the 1250.  Memory is allocated here, so don't
+ *  call it again from inside the ioctl routines that bring the
+ *  interface up/down
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac context structure
+ *  	   
+ *  Return value:
+ *  	   0
+ ********************************************************************* */
+
+static int sbmac_initctx(struct sbmac_softc *s)
+{
+	
+	/* 
+	 * figure out the addresses of some ports 
+	 */
+	
+	s->sbm_macenable = PKSEG1(s->sbm_base + R_MAC_ENABLE);
+	s->sbm_maccfg    = PKSEG1(s->sbm_base + R_MAC_CFG);
+	s->sbm_fifocfg   = PKSEG1(s->sbm_base + R_MAC_THRSH_CFG);
+	s->sbm_framecfg  = PKSEG1(s->sbm_base + R_MAC_FRAMECFG);
+	s->sbm_rxfilter  = PKSEG1(s->sbm_base + R_MAC_ADFILTER_CFG);
+	s->sbm_isr       = PKSEG1(s->sbm_base + R_MAC_STATUS);
+	s->sbm_imr       = PKSEG1(s->sbm_base + R_MAC_INT_MASK);
+	s->sbm_mdio      = PKSEG1(s->sbm_base + R_MAC_MDIO);
+
+	s->sbm_phys[0]   = 1;
+	s->sbm_phys[1]   = 0;
+
+	s->sbm_phy_oldbmsr = 0;
+	s->sbm_phy_oldanlpar = 0;
+	s->sbm_phy_oldk1stsr = 0;
+	s->sbm_phy_oldlinkstat = 0;
+	
+	/*
+	 * Initialize the DMA channels.  Right now, only one per MAC is used
+	 * Note: Only do this _once_, as it allocates memory from the kernel!
+	 */
+	
+	sbdma_initctx(&(s->sbm_txdma),s,0,DMA_TX,SBMAC_MAX_TXDESCR);
+	sbdma_initctx(&(s->sbm_rxdma),s,0,DMA_RX,SBMAC_MAX_RXDESCR);
+	
+	/*
+	 * initial state is OFF
+	 */
+	
+	s->sbm_state = sbmac_state_off;
+	
+	/*
+	 * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
+	 */
+	
+	s->sbm_speed = sbmac_speed_10;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_disabled;
+	
+	return 0;
+}
+
+
+static void sbdma_uninitctx(struct sbmacdma_s *d)
+{
+	if (d->sbdma_dscrtable) {
+		KFREE(d->sbdma_dscrtable);
+		d->sbdma_dscrtable = NULL;
+	}
+	
+	if (d->sbdma_ctxtable) {
+		KFREE(d->sbdma_ctxtable);
+		d->sbdma_ctxtable = NULL;
+	}
+}
+
+
+static void sbmac_uninitctx(struct sbmac_softc *sc)
+{
+	sbdma_uninitctx(&(sc->sbm_txdma));
+	sbdma_uninitctx(&(sc->sbm_rxdma));
+}
+
+
+/**********************************************************************
+ *  SBMAC_CHANNEL_START(s)
+ *  
+ *  Start packet processing on this MAC.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_channel_start(struct sbmac_softc *s)
+{
+	uint64_t reg;
+	sbmac_port_t port;
+	uint64_t cfg,fifo,framecfg;
+	int idx;
+	
+	/*
+	 * Don't do this if running
+	 */
+
+	if (s->sbm_state == sbmac_state_on) return;
+	
+	/*
+	 * Bring the controller out of reset, but leave it off.
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_macenable,0);
+	
+	/*
+	 * Ignore all received packets
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_rxfilter,0);
+	
+	/* 
+	 * Calculate values for various control registers.
+	 */
+	
+	cfg = M_MAC_RETRY_EN |
+		M_MAC_TX_HOLD_SOP_EN | 
+		V_MAC_TX_PAUSE_CNT_16K |
+		M_MAC_AP_STAT_EN |
+		M_MAC_FAST_SYNC |
+		M_MAC_SS_EN |
+		0;
+	
+	fifo = V_MAC_TX_WR_THRSH(4) |	/* Must be '4' or '8' */
+		V_MAC_TX_RD_THRSH(4) |
+		V_MAC_TX_RL_THRSH(4) |
+		V_MAC_RX_PL_THRSH(4) |
+		V_MAC_RX_RD_THRSH(4) |	/* Must be '4' */
+		V_MAC_RX_PL_THRSH(4) |
+		V_MAC_RX_RL_THRSH(8) |
+		0;
+	
+	framecfg = V_MAC_MIN_FRAMESZ_DEFAULT |
+		V_MAC_MAX_FRAMESZ_DEFAULT |
+		V_MAC_BACKOFF_SEL(1);
+	
+	
+	/*
+	 * Clear out the hash address map 
+	 */
+	
+	port = PKSEG1(s->sbm_base + R_MAC_HASH_BASE);
+        for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+		SBMAC_WRITECSR(port,0);
+		port += sizeof(uint64_t);
+	}
+	
+	/*
+	 * Clear out the exact-match table
+	 */
+	
+	port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+	for (idx = 0; idx < MAC_ADDR_COUNT; idx++) {
+		SBMAC_WRITECSR(port,0);
+		port += sizeof(uint64_t);
+	}
+	
+	/*
+	 * Clear out the DMA Channel mapping table registers
+	 */
+	
+	port = PKSEG1(s->sbm_base + R_MAC_CHUP0_BASE);
+	for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+		SBMAC_WRITECSR(port,0);
+		port += sizeof(uint64_t);
+	}
+
+
+	port = PKSEG1(s->sbm_base + R_MAC_CHLO0_BASE);
+	for (idx = 0; idx < MAC_CHMAP_COUNT; idx++) {
+		SBMAC_WRITECSR(port,0);
+		port += sizeof(uint64_t);
+	}
+	
+	/*
+	 * Program the hardware address.  It goes into the hardware-address
+	 * register as well as the first filter register.
+	 */
+	
+	reg = sbmac_addr2reg(s->sbm_hwaddr);
+	
+	port = PKSEG1(s->sbm_base + R_MAC_ADDR_BASE);
+	SBMAC_WRITECSR(port,reg);
+	port = PKSEG1(s->sbm_base + R_MAC_ETHERNET_ADDR);
+
+#ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
+	/*
+	 * Pass1 SB1250s do not receive packets addressed to the
+	 * destination address in the R_MAC_ETHERNET_ADDR register.
+	 * Set the value to zero.
+	 */
+	SBMAC_WRITECSR(port,0);
+#else
+	SBMAC_WRITECSR(port,reg);
+#endif
+	
+	/*
+	 * Set the receive filter for no packets, and write values
+	 * to the various config registers
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_rxfilter,0);
+	SBMAC_WRITECSR(s->sbm_imr,0);
+	SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+	SBMAC_WRITECSR(s->sbm_fifocfg,fifo);
+	SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+	
+	/*
+	 * Initialize DMA channels (rings should be ok now)
+	 */
+	
+	sbdma_channel_start(&(s->sbm_rxdma));
+	sbdma_channel_start(&(s->sbm_txdma));
+	
+	/*
+	 * Configure the speed, duplex, and flow control
+	 */
+
+	sbmac_set_speed(s,s->sbm_speed);
+	sbmac_set_duplex(s,s->sbm_duplex,s->sbm_fc);
+	
+	/*
+	 * Fill the receive ring
+	 */
+	
+	sbdma_fillring(&(s->sbm_rxdma));
+	
+	/* 
+	 * Turn on the rest of the bits in the enable register
+	 */      
+	
+	SBMAC_WRITECSR(s->sbm_macenable,
+		       M_MAC_RXDMA_EN0 |
+		       M_MAC_TXDMA_EN0 |
+		       M_MAC_RX_ENABLE |
+		       M_MAC_TX_ENABLE);
+	
+	
+
+	/*
+	 * Accept any kind of interrupt on TX and RX DMA channel 0
+	 */
+	SBMAC_WRITECSR(s->sbm_imr,
+		       (M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+		       (M_MAC_INT_CHANNEL << S_MAC_RX_CH0));
+	
+	/* 
+	 * Enable receiving unicasts and broadcasts 
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_rxfilter,M_MAC_UCAST_EN | M_MAC_BCAST_EN);
+	
+	/*
+	 * we're running now. 
+	 */
+	
+	s->sbm_state = sbmac_state_on;
+	
+	/* 
+	 * Program multicast addresses 
+	 */
+	
+	sbmac_setmulti(s);
+	
+	/* 
+	 * If channel was in promiscuous mode before, turn that on 
+	 */
+	
+	if (s->sbm_devflags & IFF_PROMISC) {
+		sbmac_promiscuous_mode(s,1);
+	}
+	
+}
+
+
+/**********************************************************************
+ *  SBMAC_CHANNEL_STOP(s)
+ *  
+ *  Stop packet processing on this MAC.
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_channel_stop(struct sbmac_softc *s)
+{
+	uint64_t ctl;
+	
+	/* don't do this if already stopped */
+	
+	if (s->sbm_state == sbmac_state_off) return;
+	
+	/* don't accept any packets, disable all interrupts */
+	
+	SBMAC_WRITECSR(s->sbm_rxfilter,0);
+	SBMAC_WRITECSR(s->sbm_imr,0);
+	
+	/* Turn off ticker */
+	
+	/* XXX */
+	
+	/* turn off receiver and transmitter */
+	
+	ctl = SBMAC_READCSR(s->sbm_macenable);
+	ctl &= ~(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0);
+	SBMAC_WRITECSR(s->sbm_macenable,ctl);
+	
+	/* We're stopped now. */
+	
+	s->sbm_state = sbmac_state_off;
+	
+	
+	/* Empty the receive and transmit rings */
+	
+	sbdma_emptyring(&(s->sbm_rxdma));
+	sbdma_emptyring(&(s->sbm_txdma));
+	
+}
+
+/**********************************************************************
+ *  SBMAC_SET_CHANNEL_STATE(state)
+ *  
+ *  Set the channel's state ON or OFF
+ *  
+ *  Input parameters: 
+ *  	   state - new state
+ *  	   
+ *  Return value:
+ *  	   old state
+ ********************************************************************* */
+static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
+					     sbmac_state_t state)
+{
+	sbmac_state_t oldstate = sc->sbm_state;
+	
+	/*
+	 * If same as previous state, return
+	 */
+	
+	if (state == oldstate) {
+		return oldstate;
+	}
+	
+	/*
+	 * If new state is ON, turn channel on 
+	 */
+	
+	if (state == sbmac_state_on) {
+		sbmac_channel_start(sc);
+	}
+	else {
+		sbmac_channel_stop(sc);
+	}
+	
+	/*
+	 * Return previous state
+	 */
+	
+	return oldstate;
+}
+
+
+/**********************************************************************
+ *  SBMAC_PROMISCUOUS_MODE(sc,onoff)
+ *  
+ *  Turn on or off promiscuous mode
+ *  
+ *  Input parameters: 
+ *  	   sc - softc
+ *      onoff - 1 to turn on, 0 to turn off
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff)
+{
+	uint64_t reg;
+	
+	if (sc->sbm_state != sbmac_state_on) return;
+	
+	if (onoff) {
+		reg = SBMAC_READCSR(sc->sbm_rxfilter);
+		reg |= M_MAC_ALLPKT_EN;
+		SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+	}	
+	else {
+		reg = SBMAC_READCSR(sc->sbm_rxfilter);
+		reg &= ~M_MAC_ALLPKT_EN;
+		SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+	}
+}
+
+
+
+#if 0
+/**********************************************************************
+ *  SBMAC_INIT_AND_START(sc)
+ *  
+ *  Stop the channel and restart it.  This is generally used
+ *  when we have to do something to the channel that requires
+ *  a swift kick.
+ *  
+ *  Input parameters: 
+ *  	   sc - softc
+ ********************************************************************* */
+
+static void sbmac_init_and_start(struct sbmac_softc *sc)
+{
+	unsigned long flags;
+	
+	spin_lock_irqsave(&(sc->sbm_lock),flags);
+	
+	sbmac_set_channel_state(sc,sbmac_state_on);
+	
+	spin_unlock_irqrestore(&(sc->sbm_lock),flags);
+}
+#endif
+
+
+/**********************************************************************
+ *  SBMAC_ADDR2REG(ptr)
+ *  
+ *  Convert six bytes into the 64-bit register value that
+ *  we typically write into the SBMAC's address/mcast registers
+ *  
+ *  Input parameters: 
+ *  	   ptr - pointer to 6 bytes
+ *  	   
+ *  Return value:
+ *  	   register value
+ ********************************************************************* */
+
+static uint64_t sbmac_addr2reg(unsigned char *ptr)
+{
+	uint64_t reg = 0;
+	
+	ptr += 6;
+	
+	reg |= (uint64_t) *(--ptr); 
+	reg <<= 8;
+	reg |= (uint64_t) *(--ptr); 
+	reg <<= 8;
+	reg |= (uint64_t) *(--ptr); 
+	reg <<= 8;
+	reg |= (uint64_t) *(--ptr); 
+	reg <<= 8;
+	reg |= (uint64_t) *(--ptr); 
+	reg <<= 8;
+	reg |= (uint64_t) *(--ptr); 
+	
+	return reg;
+}
+
+
+/**********************************************************************
+ *  SBMAC_SET_SPEED(s,speed)
+ *  
+ *  Configure LAN speed for the specified MAC.
+ *  Warning: must be called when MAC is off!
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   speed - speed to set MAC to (see sbmac_speed_t enum)
+ *  	   
+ *  Return value:
+ *  	   1 if successful
+ *      0 indicates invalid parameters
+ ********************************************************************* */
+
+static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+{
+	uint64_t cfg;
+	uint64_t framecfg;
+
+	/*
+	 * Save new current values
+	 */
+	
+	s->sbm_speed = speed;
+	
+	if (s->sbm_state == sbmac_state_on) return 0;	/* save for next restart */
+
+	/*
+	 * Read current register values 
+	 */
+	
+	cfg = SBMAC_READCSR(s->sbm_maccfg);
+	framecfg = SBMAC_READCSR(s->sbm_framecfg);
+	
+	/*
+	 * Mask out the stuff we want to change
+	 */
+	
+	cfg &= ~(M_MAC_BURST_EN | M_MAC_SPEED_SEL);
+	framecfg &= ~(M_MAC_IFG_RX | M_MAC_IFG_TX | M_MAC_IFG_THRSH |
+		      M_MAC_SLOT_SIZE);
+	
+	/*
+	 * Now add in the new bits
+	 */
+	
+	switch (speed) {
+	case sbmac_speed_10:
+		framecfg |= V_MAC_IFG_RX_10 |
+			V_MAC_IFG_TX_10 |
+			K_MAC_IFG_THRSH_10 |
+			V_MAC_SLOT_SIZE_10;
+		cfg |= V_MAC_SPEED_SEL_10MBPS;
+		break;
+		
+	case sbmac_speed_100:
+		framecfg |= V_MAC_IFG_RX_100 |
+			V_MAC_IFG_TX_100 |
+			V_MAC_IFG_THRSH_100 |
+			V_MAC_SLOT_SIZE_100;
+		cfg |= V_MAC_SPEED_SEL_100MBPS ;
+		break;
+		
+	case sbmac_speed_1000:
+		framecfg |= V_MAC_IFG_RX_1000 |
+			V_MAC_IFG_TX_1000 |
+			V_MAC_IFG_THRSH_1000 |
+			V_MAC_SLOT_SIZE_1000;
+		cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
+		break;
+		
+	case sbmac_speed_auto:		/* XXX not implemented */
+		/* fall through */
+	default:
+		return 0;
+	}
+	
+	/*
+	 * Send the bits back to the hardware 
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_framecfg,framecfg);
+	SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+	
+	return 1;
+	
+}
+
+/**********************************************************************
+ *  SBMAC_SET_DUPLEX(s,duplex,fc)
+ *  
+ *  Set Ethernet duplex and flow control options for this MAC
+ *  Warning: must be called when MAC is off!
+ *  
+ *  Input parameters: 
+ *  	   s - sbmac structure
+ *  	   duplex - duplex setting (see sbmac_duplex_t)
+ *  	   fc - flow control setting (see sbmac_fc_t)
+ *  	   
+ *  Return value:
+ *  	   1 if ok
+ *  	   0 if an invalid parameter combination was specified
+ ********************************************************************* */
+
+static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+{
+	uint64_t cfg;
+	
+	/*
+	 * Save new current values
+	 */
+	
+	s->sbm_duplex = duplex;
+	s->sbm_fc = fc;
+	
+	if (s->sbm_state == sbmac_state_on) return 0;	/* save for next restart */
+	
+	/*
+	 * Read current register values 
+	 */
+	
+	cfg = SBMAC_READCSR(s->sbm_maccfg);
+	
+	/*
+	 * Mask off the stuff we're about to change
+	 */
+	
+	cfg &= ~(M_MAC_FC_SEL | M_MAC_FC_CMD | M_MAC_HDX_EN);
+	
+	
+	switch (duplex) {
+	case sbmac_duplex_half:
+		switch (fc) {
+		case sbmac_fc_disabled:
+			cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_DISABLED;
+			break;
+			
+		case sbmac_fc_collision:
+			cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENABLED;
+			break;
+			
+		case sbmac_fc_carrier:
+			cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
+			break;
+			
+		case sbmac_fc_auto:		/* XXX not implemented */
+			/* fall through */					   
+		case sbmac_fc_frame:		/* not valid in half duplex */
+		default:			/* invalid selection */
+			return 0;
+		}
+		break;
+		
+	case sbmac_duplex_full:
+		switch (fc) {
+		case sbmac_fc_disabled:
+			cfg |= V_MAC_FC_CMD_DISABLED;
+			break;
+			
+		case sbmac_fc_frame:
+			cfg |= V_MAC_FC_CMD_ENABLED;
+			break;
+			
+		case sbmac_fc_collision:	/* not valid in full duplex */
+		case sbmac_fc_carrier:		/* not valid in full duplex */
+		case sbmac_fc_auto:		/* XXX not implemented */
+			/* fall through */					   
+		default:
+			return 0;
+		}
+		break;
+	case sbmac_duplex_auto:
+		/* XXX not implemented */
+		break;
+	}
+	
+	/*
+	 * Send the bits back to the hardware 
+	 */
+	
+	SBMAC_WRITECSR(s->sbm_maccfg,cfg);
+	
+	return 1;
+}
+
+
+
+
+/**********************************************************************
+ *  SBMAC_INTR()
+ *  
+ *  Interrupt handler for MAC interrupts
+ *  
+ *  Input parameters: 
+ *  	   MAC structure
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+static void sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
+{
+	struct net_device *dev = (struct net_device *) dev_instance;
+	struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv);
+	uint64_t isr;
+	
+	for (;;) {
+		
+		/*
+		 * Read the ISR (this clears the bits in the real register)
+		 */
+		
+		isr = SBMAC_READCSR(sc->sbm_isr);
+		
+		if (isr == 0) break;
+		
+		/*
+		 * Transmits on channel 0
+		 */
+		
+		if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+			sbdma_tx_process(sc,&(sc->sbm_txdma));
+		}
+		
+		/*
+		 * Receives on channel 0
+		 */
+		
+		if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+			sbdma_rx_process(sc,&(sc->sbm_rxdma));
+		}
+	}
+	
+}
+
+
+/**********************************************************************
+ *  SBMAC_START_TX(skb,dev)
+ *  
+ *  Start output on the specified interface.  Basically, we 
+ *  queue as many buffers as we can until the ring fills up, or
+ *  we run off the end of the queue, whichever comes first.
+ *  
+ *  Input parameters: 
+ *  	   
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	
+	/* lock eth irq */
+	spin_lock_irq (&sc->sbm_lock);
+	
+	/*
+	 * Put the buffer on the transmit ring.  If we 
+	 * don't have room, stop the queue.
+	 */
+	
+	if (sbdma_add_txbuffer(&(sc->sbm_txdma),skb)) {
+		/* XXX save skb that we could not send */
+		netif_stop_queue(dev);
+	}
+	
+	dev->trans_start = jiffies;
+	
+	spin_unlock_irq (&sc->sbm_lock);
+	
+	return 0;
+}
+
+/**********************************************************************
+ *  SBMAC_SETMULTI(sc)
+ *  
+ *  Reprogram the multicast table into the hardware, given
+ *  the list of multicasts associated with the interface
+ *  structure.
+ *  
+ *  Input parameters: 
+ *  	   sc - softc
+ *  	   
+ *  Return value:
+ *  	   nothing
+ ********************************************************************* */
+
+static void sbmac_setmulti(struct sbmac_softc *sc)
+{
+	uint64_t reg;
+	sbmac_port_t port;
+	int idx;
+	struct dev_mc_list *mclist;
+	struct net_device *dev = sc->sbm_dev;
+	
+	/* 
+	 * Clear out entire multicast table.  We do this by nuking
+	 * the entire hash table and all the direct matches except
+	 * the first one, which is used for our station address 
+	 */
+	
+	for (idx = 1; idx < MAC_ADDR_COUNT; idx++) {
+		port = PKSEG1(sc->sbm_base + R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+		SBMAC_WRITECSR(port,0);	
+	}
+	
+	for (idx = 0; idx < MAC_HASH_COUNT; idx++) {
+		port = PKSEG1(sc->sbm_base + R_MAC_HASH_BASE+(idx*sizeof(uint64_t)));
+		SBMAC_WRITECSR(port,0);	
+	}
+	
+	/*
+	 * Clear the filter to say we don't want any multicasts.
+	 */
+	
+	reg = SBMAC_READCSR(sc->sbm_rxfilter);
+	reg &= ~(M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+	SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+	
+	if (dev->flags & IFF_ALLMULTI) {
+		/* 
+		 * Enable ALL multicasts.  Do this by inverting the 
+		 * multicast enable bit. 
+		 */
+		reg = SBMAC_READCSR(sc->sbm_rxfilter);
+		reg |= (M_MAC_MCAST_INV | M_MAC_MCAST_EN);
+		SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+		return;
+	}
+	
+
+	/* 
+	 * Progam new multicast entries.  For now, only use the
+	 * perfect filter.  In the future we'll need to use the
+	 * hash filter if the perfect filter overflows
+	 */
+	
+	/* XXX only using perfect filter for now, need to use hash
+	 * XXX if the table overflows */
+	
+	idx = 1;		/* skip station address */
+	mclist = dev->mc_list;
+	while (mclist && (idx < MAC_ADDR_COUNT)) {
+		reg = sbmac_addr2reg(mclist->dmi_addr);
+		port = PKSEG1(sc->sbm_base + 
+			      R_MAC_ADDR_BASE+(idx*sizeof(uint64_t)));
+		SBMAC_WRITECSR(port,reg);
+		idx++;
+		mclist = mclist->next;
+	}
+	
+	/*	
+	 * Enable the "accept multicast bits" if we programmed at least one
+	 * multicast. 
+	 */
+	
+	if (idx > 1) {
+		reg = SBMAC_READCSR(sc->sbm_rxfilter);
+		reg |= M_MAC_MCAST_EN;
+		SBMAC_WRITECSR(sc->sbm_rxfilter,reg);
+	}
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+/**********************************************************************
+ *  SBMAC_PARSE_XDIGIT(str)
+ *  
+ *  Parse a hex digit, returning its value
+ *  
+ *  Input parameters: 
+ *  	   str - character
+ *  	   
+ *  Return value:
+ *  	   hex value, or -1 if invalid
+ ********************************************************************* */
+
+static int sbmac_parse_xdigit(char str)
+{
+	int digit;
+	
+	if ((str >= '0') && (str <= '9')) digit = str - '0';
+	else if ((str >= 'a') && (str <= 'f')) digit = str - 'a' + 10;
+	else if ((str >= 'A') && (str <= 'F')) digit = str - 'A' + 10;
+	else return -1;
+	
+	return digit;
+}
+
+/**********************************************************************
+ *  SBMAC_PARSE_HWADDR(str,hwaddr)
+ *  
+ *  Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ *  Ethernet address.
+ *  
+ *  Input parameters: 
+ *  	   str - string
+ *  	   hwaddr - pointer to hardware address
+ *  	   
+ *  Return value:
+ *  	   0 if ok, else -1
+ ********************************************************************* */
+
+static int sbmac_parse_hwaddr(char *str,u_char *hwaddr)
+{
+	int digit1,digit2;
+	int idx = 6;
+	
+	while (*str && (idx > 0)) {
+		digit1 = sbmac_parse_xdigit(*str);
+		if (digit1 < 0) return -1;
+		str++;
+		if (!*str) return -1;
+		
+		if ((*str == ':') || (*str == '-')) {
+			digit2 = digit1;
+			digit1 = 0;
+		}
+		else {
+			digit2 = sbmac_parse_xdigit(*str);
+			if (digit2 < 0) return -1;
+			str++;
+		}
+		
+		*hwaddr++ = (digit1 << 4) | digit2;
+		idx--;
+		
+		if (*str == '-') str++;
+		if (*str == ':') str++;
+	}
+	return 0;
+}
+#endif
+
+/**********************************************************************
+ *  SBMAC_INIT(dev)
+ *  
+ *  Attach routine - init hardware and hook ourselves into linux
+ *  
+ *  Input parameters: 
+ *  	   dev - net_device structure
+ *  	   
+ *  Return value:
+ *  	   status
+ ********************************************************************* */
+
+static int sbmac_init(struct net_device *dev)
+{
+	struct sbmac_softc *sc;
+	u_char *eaddr;
+	uint64_t ea_reg;
+	int idx;
+	
+	sc = (struct sbmac_softc *)dev->priv;
+	
+	/* Determine controller base address */
+	
+	sc->sbm_base = (sbmac_port_t) dev->base_addr;
+	sc->sbm_dev = dev;
+	
+	eaddr = sc->sbm_hwaddr;
+	
+	/* 
+	 * Read the ethernet address.  The firwmare left this programmed
+	 * for us in the ethernet address register for each mac.
+	 */
+	
+	ea_reg = SBMAC_READCSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR));
+	SBMAC_WRITECSR(PKSEG1(sc->sbm_base + R_MAC_ETHERNET_ADDR), 0);
+	for (idx = 0; idx < 6; idx++) {
+		eaddr[idx] = (uint8_t) (ea_reg & 0xFF);
+		ea_reg >>= 8;
+	}
+	
+	
+	for (idx = 0; idx < 6; idx++) {
+		dev->dev_addr[idx] = eaddr[idx];
+	}
+	
+	
+	/*
+	 * Init packet size 
+	 */
+	
+	sc->sbm_buffersize = ENET_PACKET_SIZE + CACHELINESIZE*2 + ETHER_ALIGN;
+	
+	/* 
+	 * Initialize context (get pointers to registers and stuff), then
+	 * allocate the memory for the descriptor tables.
+	 */
+	
+	sbmac_initctx(sc);
+	
+	
+	/*
+	 * Display Ethernet address (this is called during the config process
+	 * so we need to finish off the config message that was being displayed)
+	 */
+	printk(KERN_INFO
+	       "%s: SB1250 Ethernet at 0x%08lX, address: %02X-%02X-%02X-%02X-%02X-%02X\n", 
+	       dev->name,
+	       (unsigned long) sc->sbm_base,
+	       eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
+	
+	/*
+	 * Set up Linux device callins
+	 */
+	
+	spin_lock_init(&(sc->sbm_lock));
+	
+	ether_setup(dev);
+	dev->open               = sbmac_open;
+	dev->hard_start_xmit    = sbmac_start_tx;
+	dev->stop               = sbmac_close;
+	dev->get_stats          = sbmac_get_stats;
+	dev->set_multicast_list = sbmac_set_rx_mode;
+	dev->do_ioctl           = sbmac_mii_ioctl;
+	dev->tx_timeout         = sbmac_tx_timeout;
+	dev->watchdog_timeo     = TX_TIMEOUT;
+	
+	return 0;
+	
+}
+
+
+static int sbmac_open(struct net_device *dev)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	
+	MOD_INC_USE_COUNT;
+
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
+	}
+	
+	/* 
+	 * map/route interrupt 
+	 */
+	
+	if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev)) {
+		MOD_DEC_USE_COUNT;
+		return -EBUSY;
+	}
+	
+	/*
+	 * Configure default speed 
+	 */
+
+	sbmac_mii_poll(sc,1);
+	
+	/*
+	 * Turn on the channel
+	 */
+
+	sbmac_set_channel_state(sc,sbmac_state_on);
+	
+	/*
+	 * XXX Station address is in dev->dev_addr
+	 */
+	
+	if (dev->if_port == 0)
+		dev->if_port = 0; 
+	
+	netif_start_queue(dev);
+	
+	sbmac_set_rx_mode(dev);
+	
+	/* Set the timer to check for link beat. */
+	init_timer(&sc->sbm_timer);
+	sc->sbm_timer.expires = jiffies + 2;
+	sc->sbm_timer.data = (unsigned long)dev;
+	sc->sbm_timer.function = &sbmac_timer;
+	add_timer(&sc->sbm_timer);
+	
+	return 0;
+}
+
+
+
+static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
+{
+    int bmsr,bmcr,k1stsr,anlpar;
+    int chg;
+    char buffer[100];
+    char *p = buffer;
+
+    /* Read the mode status and mode control registers. */
+    bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
+    bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
+
+    /* get the link partner status */
+    anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
+
+    /* if supported, read the 1000baseT register */
+    if (bmsr & BMSR_1000BT_XSR) {
+	k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
+	}
+    else {
+	k1stsr = 0;
+	}
+
+    chg = 0;
+
+    if ((bmsr & BMSR_LINKSTAT) == 0) {
+	/*
+	 * If link status is down, clear out old info so that when
+	 * it comes back up it will force us to reconfigure speed
+	 */
+	s->sbm_phy_oldbmsr = 0;
+	s->sbm_phy_oldanlpar = 0;
+	s->sbm_phy_oldk1stsr = 0;
+	return 0;
+	}
+
+    if ((s->sbm_phy_oldbmsr != bmsr) ||
+	(s->sbm_phy_oldanlpar != anlpar) ||
+	(s->sbm_phy_oldk1stsr != k1stsr)) {
+	if (debug > 1) {
+	    printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x  k1stsr:%x/%x\n",
+	       s->sbm_dev->name,
+	       s->sbm_phy_oldbmsr,bmsr,
+	       s->sbm_phy_oldanlpar,anlpar,
+	       s->sbm_phy_oldk1stsr,k1stsr);
+	    }
+	s->sbm_phy_oldbmsr = bmsr;
+	s->sbm_phy_oldanlpar = anlpar;
+	s->sbm_phy_oldk1stsr = k1stsr;
+	chg = 1;
+	}
+
+    if (chg == 0) return 0;
+
+    p += sprintf(p,"Link speed: ");
+
+    if (k1stsr & K1STSR_LP1KFD) {
+	s->sbm_speed = sbmac_speed_1000;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = sbmac_fc_frame;
+	p += sprintf(p,"1000BaseT FDX");
+	}
+    else if (k1stsr & K1STSR_LP1KHD) {
+	s->sbm_speed = sbmac_speed_1000;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_disabled;
+	p += sprintf(p,"1000BaseT HDX");
+	}
+    else if (anlpar & ANLPAR_TXFD) {
+	s->sbm_speed = sbmac_speed_100;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
+	p += sprintf(p,"100BaseT FDX");
+	}
+    else if (anlpar & ANLPAR_TXHD) {
+	s->sbm_speed = sbmac_speed_100;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_disabled;
+	p += sprintf(p,"100BaseT HDX");
+	}
+    else if (anlpar & ANLPAR_10FD) {
+	s->sbm_speed = sbmac_speed_10;
+	s->sbm_duplex = sbmac_duplex_full;
+	s->sbm_fc = sbmac_fc_frame;
+	p += sprintf(p,"10BaseT FDX");
+	}
+    else if (anlpar & ANLPAR_10HD) {
+	s->sbm_speed = sbmac_speed_10;
+	s->sbm_duplex = sbmac_duplex_half;
+	s->sbm_fc = sbmac_fc_collision;
+	p += sprintf(p,"10BaseT HDX");
+	}
+    else {
+	p += sprintf(p,"Unknown");
+	}
+
+    if (noisy) {
+	    printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
+	    }
+
+    return 1;
+}
+
+
+
+
+static void sbmac_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	int next_tick = HZ;
+	int mii_status;
+
+	spin_lock_irq (&sc->sbm_lock);
+	
+	/* make IFF_RUNNING follow the MII status bit "Link established" */
+	mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
+	
+	if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
+    	        sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
+		if (mii_status & BMSR_LINKSTAT) {
+			netif_carrier_on(dev);
+		}
+		else {
+			netif_carrier_off(dev);	
+		}
+	}
+	
+	/*
+	 * Poll the PHY to see what speed we should be running at
+	 */
+
+	if (sbmac_mii_poll(sc,1)) {
+	    if (sc->sbm_state != sbmac_state_off) {
+		/*
+		 * something changed, restart the channel
+		 */
+		if (debug > 1) {
+		    printk("%s: restarting channel because speed changed\n",
+			   sc->sbm_dev->name);
+		    }
+		sbmac_channel_stop(sc);
+		sbmac_channel_start(sc);
+		}
+	    }
+	
+	spin_unlock_irq (&sc->sbm_lock);
+	
+	sc->sbm_timer.expires = jiffies + next_tick;
+	add_timer(&sc->sbm_timer);
+}
+
+
+static void sbmac_tx_timeout (struct net_device *dev)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+	
+	spin_lock_irq (&sc->sbm_lock);
+	
+	
+	dev->trans_start = jiffies;
+	sc->sbm_stats.tx_errors++;
+	
+	spin_unlock_irq (&sc->sbm_lock);
+
+	printk (KERN_WARNING "%s: Transmit timed out\n",dev->name);
+}
+
+
+
+
+static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&sc->sbm_lock, flags);
+	
+	/* XXX update other stats here */
+	
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	
+	return &sc->sbm_stats;
+}
+
+
+
+static void sbmac_set_rx_mode(struct net_device *dev)
+{
+	unsigned long flags;
+	int msg_flag = 0;
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+
+	spin_lock_irqsave(&sc->sbm_lock, flags);
+	if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) {
+		/*
+		 * Promiscuous changed.
+		 */
+		
+		if (dev->flags & IFF_PROMISC) {	
+			/* Unconditionally log net taps. */
+			msg_flag = 1;
+			sbmac_promiscuous_mode(sc,1);
+		}
+		else {
+			msg_flag = 2;
+			sbmac_promiscuous_mode(sc,0);
+		}
+	}
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	
+	if (msg_flag) {
+		printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n", dev->name,(msg_flag==1)?"en":"dis");
+	}
+	
+	/*
+	 * Program the multicasts.  Do this every time.
+	 */
+	
+	sbmac_setmulti(sc);
+	
+}
+
+static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+	unsigned long flags;
+	int retval;
+	
+	spin_lock_irqsave(&sc->sbm_lock, flags);
+	retval = 0;
+	
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = sc->sbm_phys[0] & 0x1f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
+		break;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN)) {
+			retval = -EPERM;
+			break;
+		}
+		if (debug > 1) {
+		    printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
+		       data[0],data[1],data[2]);
+		    }
+		sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		break;
+	default:
+		retval = -EOPNOTSUPP;
+	}
+	
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	return retval;
+}
+
+static int sbmac_close(struct net_device *dev)
+{
+	struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv;
+	unsigned long flags;
+	
+	sbmac_set_channel_state(sc,sbmac_state_off);
+	
+	del_timer_sync(&sc->sbm_timer);
+	
+	spin_lock_irqsave(&sc->sbm_lock, flags);
+	
+	netif_stop_queue(dev);
+	
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
+	}
+	
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	
+	/* Make sure there is no irq-handler running on a different CPU. */
+	synchronize_irq();
+	
+	free_irq(dev->irq, dev);
+	
+	sbdma_emptyring(&(sc->sbm_txdma));
+	sbdma_emptyring(&(sc->sbm_rxdma));
+	
+	MOD_DEC_USE_COUNT;
+	
+	return 0;
+}
+
+
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR)
+static void
+sbmac_setup_hwaddr(int chan,char *addr)
+{
+	uint8_t eaddr[6];
+	uint64_t val;
+	sbmac_port_t port;
+
+	port = A_MAC_CHANNEL_BASE(chan);
+	sbmac_parse_hwaddr(addr,eaddr);
+	val = sbmac_addr2reg(eaddr);
+	SBMAC_WRITECSR(PKSEG1(port+R_MAC_ETHERNET_ADDR),val);
+	val = SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR));
+}
+#endif
+
+static struct net_device *dev_sbmac[MAX_UNITS] = {0,0,0};
+
+static int __init
+sbmac_init_module(void)
+{
+	int idx;
+	int macidx = 0;
+	struct net_device *dev;
+	sbmac_port_t port;
+	
+	/*
+	 * For bringup when not using the firmware, we can pre-fill
+	 * the MAC addresses using the environment variables
+	 * specified in this file (or maybe from the config file?)
+	 */
+#ifdef SBMAC_ETH0_HWADDR
+	sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+#endif
+#ifdef SBMAC_ETH1_HWADDR
+	sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+#endif
+#ifdef SBMAC_ETH2_HWADDR
+	sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+#endif
+
+	/*
+	 * Walk through the Ethernet controllers and find
+	 * those who have their MAC addresses set.
+	 */
+	
+	for (idx = 0; idx < MAX_UNITS; idx++) {
+
+	        /*
+	         * This is the base address of the MAC.
+		 */
+
+	        port = A_MAC_CHANNEL_BASE(idx);
+
+		/*	
+		 * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+		 * value for us by the firmware if we're going to use this MAC.
+		 * If we find a zero, skip this MAC.
+		 */
+
+		if (SBMAC_READCSR(PKSEG1(port+R_MAC_ETHERNET_ADDR)) == 0) {
+		    continue;
+		    }
+
+		/*
+		 * Okay, cool.  Initialize this MAC.
+		 */
+
+		dev = init_etherdev(NULL,sizeof(struct sbmac_softc));
+		if (!dev) break;			/* problems, get out now. */
+		dev->irq = K_INT_MAC_0 + idx;
+		dev->base_addr = port;
+		dev->mem_end = 0;
+		/*dev->init = sbmac_init;*/
+		sbmac_init(dev);
+
+		dev_sbmac[macidx] = dev;
+		macidx++;
+
+	}
+
+	/*
+	 * Should we care, 'macidx' is the total number of enabled MACs.
+	 */
+	
+	return 0;
+}
+
+
+static void __exit
+sbmac_cleanup_module(void)
+{
+	int idx;
+	struct net_device *dev;
+	for (idx = 0; idx < MAX_UNITS; idx++) {
+		dev = dev_sbmac[idx];
+		if (dev == NULL) continue;
+		if (dev->priv != NULL) {
+			struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv;
+			
+			unregister_netdev(dev);
+			
+			sbmac_uninitctx(sc);
+			
+			KFREE(sc);
+		}
+		KFREE(dev);
+		dev_sbmac[idx] = NULL;
+	}
+}
+
+module_init(sbmac_init_module);
+module_exit(sbmac_cleanup_module);
diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
--- a/drivers/net/skfp/skfddi.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/skfp/skfddi.c	Wed Apr  3 17:11:14 2002
@@ -520,8 +520,6 @@
 {
 	/* Initialize new device structure */
 
-	dev->rmem_end = 0;	/* shared memory isn't used */
-	dev->rmem_start = 0;	/* shared memory isn't used */
 	dev->mem_end = 0;	/* shared memory isn't used */
 	dev->mem_start = 0;	/* shared memory isn't used */
 	dev->base_addr = iobase;	/* save port (I/O) base address */
diff -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
--- a/drivers/net/smc-mca.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/smc-mca.c	Wed Apr  3 17:11:14 2002
@@ -299,8 +299,8 @@
 	ei_status.rx_start_page = START_PG + TX_PAGES;
 	ei_status.stop_page = num_pages;
 
-	dev->rmem_start = dev->mem_start + TX_PAGES * 256;
-	dev->mem_end = dev->rmem_end =
+	ei_status.rmem_start = dev->mem_start + TX_PAGES * 256;
+	dev->mem_end = ei_status.rmem_end =
 	dev->mem_start + (ei_status.stop_page - START_PG) * 256;
 
 	printk(KERN_INFO ", IRQ %d memory %#lx-%#lx.\n",
@@ -387,12 +387,12 @@
 {
 	unsigned long xfer_start = dev->mem_start + ring_offset - (START_PG << 8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
 		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff -Nru a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
--- a/drivers/net/smc-ultra.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/smc-ultra.c	Wed Apr  3 17:11:14 2002
@@ -251,8 +251,8 @@
 	ei_status.rx_start_page = START_PG + TX_PAGES;
 	ei_status.stop_page = num_pages;
 
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = dev->rmem_end
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = ei_status.rmem_end
 		= dev->mem_start + (ei_status.stop_page - START_PG)*256;
 
 	if (piomode) {
@@ -403,12 +403,12 @@
 	/* Enable shared memory. */
 	outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
 		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff -Nru a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
--- a/drivers/net/smc-ultra32.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/smc-ultra32.c	Wed Apr  3 17:11:14 2002
@@ -231,8 +231,8 @@
 	/* All Ultra32 cards have 32KB memory with an 8KB window. */
 	ei_status.stop_page = 128;
 
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
-	dev->mem_end = dev->rmem_end = dev->mem_start + 0x1fff;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = ei_status.rmem_end = dev->mem_start + 0x1fff;
 
 	printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n",
 	       dev->irq, dev->mem_start, dev->mem_end);
@@ -353,7 +353,7 @@
 		} else {
 			/* Select first 8KB Window. */
 			outb(ei_status.reg0, RamReg);
-			isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+			isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 		}
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
diff -Nru a/drivers/net/strip.c b/drivers/net/strip.c
--- a/drivers/net/strip.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/strip.c	Wed Apr  3 17:11:14 2002
@@ -2080,6 +2080,7 @@
 #ifdef EXT_COUNTERS
         strip_info->rx_bytes += packetlen;
 #endif
+        skb->dev->last_rx = jiffies;
         netif_rx(skb);
     }
 }
diff -Nru a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/sun3_82586.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,1206 @@
+/*
+ * Sun3 i82586 Ethernet driver
+ *
+ * Cloned from ni52.c for the Sun3 by Sam Creasey (sammy@sammy.net)
+ *
+ * Original copyright follows:
+ * --------------------------
+ *
+ * net-3-driver for the NI5210 card (i82586 Ethernet chip)
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
+ * --------------------------
+ * 
+ * Consult ni52.c for further notes from the original driver.
+ *
+ * This incarnation currently supports the OBIO version of the i82586 chip 
+ * used in certain sun3 models.  It should be fairly doable to expand this
+ * to support VME if I should every acquire such a board.
+ *
+ */
+
+static int debuglevel = 0; /* debug-printk 0: off 1: a few 2: more */
+static int automatic_resume = 0; /* experimental .. better should be zero */
+static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */
+static int fifo=0x8;	/* don't change */
+
+/* #define REALLY_SLOW_IO */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sun3_82586.h"
+
+#define DEBUG       /* debug on */
+#define SYSBUSVAL 0 /* 16 Bit */
+
+#define sun3_attn586()  {*(volatile unsigned char *)(dev->base_addr) |= IEOB_ATTEN; *(volatile unsigned char *)(dev->base_addr) &= ~IEOB_ATTEN;}
+#define sun3_reset586() {*(volatile unsigned char *)(dev->base_addr) = 0; udelay(100); *(volatile unsigned char *)(dev->base_addr) = IEOB_NORSET;}
+#define sun3_disint()   {*(volatile unsigned char *)(dev->base_addr) &= ~IEOB_IENAB;}
+#define sun3_enaint()   {*(volatile unsigned char *)(dev->base_addr) |= IEOB_IENAB;}
+#define sun3_active()   {*(volatile unsigned char *)(dev->base_addr) |= (IEOB_IENAB|IEOB_ONAIR|IEOB_NORSET);}
+
+#define make32(ptr16) (p->memtop + (swab16((unsigned short) (ptr16))) )
+#define make24(ptr32) (char *)swab32(( ((unsigned long) (ptr32)) - p->base))
+#define make16(ptr32) (swab16((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )))
+
+/******************* how to calculate the buffers *****************************
+
+  * IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
+  * --------------- in a different (more stable?) mode. Only in this mode it's
+  *                 possible to configure the driver with 'NO_NOPCOMMANDS'
+
+sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
+sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
+sizeof(rfd) = 24; sizeof(rbd) = 12;
+sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
+sizeof(nop_cmd) = 8;
+
+  * if you don't know the driver, better do not change these values: */
+
+#define RECV_BUFF_SIZE 1536 /* slightly oversized */
+#define XMIT_BUFF_SIZE 1536 /* slightly oversized */
+#define NUM_XMIT_BUFFS 1    /* config for 32K shmem */
+#define NUM_RECV_BUFFS_8 4 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_16 9 /* config for 32K shared mem */
+#define NUM_RECV_BUFFS_32 16 /* config for 32K shared mem */
+#define NO_NOPCOMMANDS      /* only possible with NUM_XMIT_BUFFS=1 */
+
+/**************************************************************************/
+
+/* different DELAYs */
+#define DELAY(x) mdelay(32 * x);
+#define DELAY_16(); { udelay(16); }
+#define DELAY_18(); { udelay(4); }
+
+/* wait for command with timeout: */
+#define WAIT_4_SCB_CMD() \
+{ int i; \
+  for(i=0;i<16384;i++) { \
+    if(!p->scb->cmd_cuc) break; \
+    DELAY_18(); \
+    if(i == 16383) { \
+      printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \
+       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_SCB_CMD_RUC() { int i; \
+  for(i=0;i<16384;i++) { \
+    if(!p->scb->cmd_ruc) break; \
+    DELAY_18(); \
+    if(i == 16383) { \
+      printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \
+       if(!p->reseted) { p->reseted = 1; sun3_reset586(); } } } }
+
+#define WAIT_4_STAT_COMPL(addr) { int i; \
+   for(i=0;i<32767;i++) { \
+     if(swab16((addr)->cmd_status) & STAT_COMPL) break; \
+     DELAY_16(); DELAY_16(); } }
+
+static int     sun3_82586_probe1(struct net_device *dev,int ioaddr);
+static void    sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
+static int     sun3_82586_open(struct net_device *dev);
+static int     sun3_82586_close(struct net_device *dev);
+static int     sun3_82586_send_packet(struct sk_buff *,struct net_device *);
+static struct  net_device_stats *sun3_82586_get_stats(struct net_device *dev);
+static void    set_multicast_list(struct net_device *dev);
+static void    sun3_82586_timeout(struct net_device *dev);
+#if 0
+static void    sun3_82586_dump(struct net_device *,void *);
+#endif
+
+/* helper-functions */
+static int     init586(struct net_device *dev);
+static int     check586(struct net_device *dev,char *where,unsigned size);
+static void    alloc586(struct net_device *dev);
+static void    startrecv586(struct net_device *dev);
+static void   *alloc_rfa(struct net_device *dev,void *ptr);
+static void    sun3_82586_rcv_int(struct net_device *dev);
+static void    sun3_82586_xmt_int(struct net_device *dev);
+static void    sun3_82586_rnr_int(struct net_device *dev);
+
+struct priv
+{
+	struct net_device_stats stats;
+	unsigned long base;
+	char *memtop;
+	long int lock;
+	int reseted;
+	volatile struct rfd_struct	*rfd_last,*rfd_top,*rfd_first;
+	volatile struct scp_struct	*scp;	/* volatile is important */
+	volatile struct iscp_struct	*iscp;	/* volatile is important */
+	volatile struct scb_struct	*scb;	/* volatile is important */
+	volatile struct tbd_struct	*xmit_buffs[NUM_XMIT_BUFFS];
+	volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
+#if (NUM_XMIT_BUFFS == 1)
+	volatile struct nop_cmd_struct *nop_cmds[2];
+#else
+	volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
+#endif
+	volatile int		nop_point,num_recv_buffs;
+	volatile char		*xmit_cbuffs[NUM_XMIT_BUFFS];
+	volatile int		xmit_count,xmit_last;
+};
+
+/**********************************************
+ * close device
+ */
+static int sun3_82586_close(struct net_device *dev)
+{
+	free_irq(dev->irq, dev);
+
+	sun3_reset586(); /* the hard way to stop the receiver */
+
+	netif_stop_queue(dev);
+
+	return 0;
+}
+
+/**********************************************
+ * open device
+ */
+static int sun3_82586_open(struct net_device *dev)
+{
+	int ret;
+
+	sun3_disint();
+	alloc586(dev);
+	init586(dev);
+	startrecv586(dev);
+	sun3_enaint();
+
+	ret = request_irq(dev->irq, &sun3_82586_interrupt,0,dev->name,dev);
+	if (ret)
+	{
+		sun3_reset586();
+		return ret;
+	}
+
+	netif_start_queue(dev);
+
+	return 0; /* most done by init */
+}
+
+/**********************************************
+ * Check to see if there's an 82586 out there.
+ */
+static int check586(struct net_device *dev,char *where,unsigned size)
+{
+	struct priv pb;
+	struct priv *p = /* (struct priv *) dev->priv*/ &pb;
+	char *iscp_addr;
+	int i;
+
+	p->base = (unsigned long) dvma_btov(0);
+	p->memtop = (char *)dvma_btov((unsigned long)where);
+	p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
+	memset((char *)p->scp,0, sizeof(struct scp_struct));
+	for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */
+		if(((char *)p->scp)[i])
+			return 0;
+	p->scp->sysbus = SYSBUSVAL;				/* 1 = 8Bit-Bus, 0 = 16 Bit */
+	if(p->scp->sysbus != SYSBUSVAL)
+		return 0;
+
+	iscp_addr = (char *)dvma_btov((unsigned long)where);
+	
+	p->iscp = (struct iscp_struct *) iscp_addr;
+	memset((char *)p->iscp,0, sizeof(struct iscp_struct));
+
+	p->scp->iscp = make24(p->iscp);
+	p->iscp->busy = 1;
+
+	sun3_reset586();
+	sun3_attn586();
+	DELAY(1);	/* wait a while... */
+	
+	if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
+		return 0;
+
+	return 1;
+}
+
+/******************************************************************
+ * set iscp at the right place, called by sun3_82586_probe1 and open586.
+ */
+static void alloc586(struct net_device *dev)
+{
+	struct priv *p =	(struct priv *) dev->priv;
+
+	sun3_reset586();
+	DELAY(1);
+
+	p->scp	= (struct scp_struct *)	(p->base + SCP_DEFAULT_ADDRESS);
+	p->iscp	= (struct iscp_struct *) dvma_btov(dev->mem_start);
+	p->scb  = (struct scb_struct *)  ((char *)p->iscp + sizeof(struct iscp_struct));
+
+	memset((char *) p->iscp,0,sizeof(struct iscp_struct));
+	memset((char *) p->scp ,0,sizeof(struct scp_struct));
+
+	p->scp->iscp = make24(p->iscp);
+	p->scp->sysbus = SYSBUSVAL;
+	p->iscp->scb_offset = make16(p->scb);
+	p->iscp->scb_base = make24(dvma_btov(dev->mem_start));
+
+	p->iscp->busy = 1;
+	sun3_reset586();
+	sun3_attn586();
+
+	DELAY(1);
+
+	if(p->iscp->busy)
+		printk("%s: Init-Problems (alloc).\n",dev->name);
+
+	p->reseted = 0;
+
+	memset((char *)p->scb,0,sizeof(struct scb_struct));
+}
+
+int __init sun3_82586_probe(struct net_device *dev)
+{
+	unsigned long ioaddr, iopte;
+	static int found = 0;
+	
+	/* check that this machine has an onboard lance */
+	switch(idprom->id_machtype) {
+	case SM_SUN3|SM_3_160:
+	case SM_SUN3|SM_3_260:
+		/* these machines have lance */
+		break;
+
+	default:
+		return(-ENODEV);
+	}
+
+	if(found)
+		return -ENODEV;
+	
+	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
+	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
+
+		iopte = sun3_get_pte(ioaddr);
+		if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+			continue;
+
+		if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+		   IE_OBIO) {
+			found = 1;
+			break;
+		}
+	}
+	
+	if(!found)
+		return 0;
+	
+	SET_MODULE_OWNER(dev);
+
+	dev->irq = IE_IRQ;
+	dev->base_addr = ioaddr;
+	if(sun3_82586_probe1(dev, ioaddr) == 0)
+		return 0;
+
+	return -ENODEV;
+}
+
+static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
+{
+	int i, size, retval;
+
+//	if (!request_region(ioaddr, SUN3_82586_TOTAL_SIZE, dev->name))
+//		return -EBUSY;
+
+	/* copy in the ethernet address from the prom */
+	for(i = 0; i < 6 ; i++)
+	     dev->dev_addr[i] = idprom->id_ethaddr[i];
+
+	printk("%s: SUN3 Intel 82586 found at %lx, ",dev->name,dev->base_addr);
+
+	/*
+	 * check (or search) IO-Memory, 32K
+	 */
+	size = 0x8000;
+
+	dev->mem_start = (unsigned long)dvma_malloc_align(0x8000, 0x1000);
+	dev->mem_end = dev->mem_start + size;
+
+	if(size != 0x2000 && size != 0x4000 && size != 0x8000) {
+		printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 or 0x8000 bytes.\n",dev->name,size);
+		retval = -ENODEV;
+		goto out;
+	}
+	if(!check586(dev,(char *) dev->mem_start,size)) {
+		printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size);
+		retval = -ENODEV;
+		goto out;
+	}
+
+	dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
+	if(dev->priv == NULL) {
+		printk("%s: Ooops .. can't allocate private driver memory.\n",dev->name);
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	/* warning: we don't free it on errors */
+	memset((char *) dev->priv,0,sizeof(struct priv));
+
+	((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start);
+	((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0);
+	alloc586(dev);
+
+	/* set number of receive-buffs according to memsize */
+	if(size == 0x2000)
+		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8;
+	else if(size == 0x4000)
+		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16;
+	else
+		((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
+
+	printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
+	
+	dev->open		= sun3_82586_open;
+	dev->stop		= sun3_82586_close;
+	dev->get_stats		= sun3_82586_get_stats;
+	dev->tx_timeout 	= sun3_82586_timeout;
+	dev->watchdog_timeo	= HZ/20;
+	dev->hard_start_xmit 	= sun3_82586_send_packet;
+	dev->set_multicast_list = set_multicast_list;
+
+	dev->if_port 		= 0;
+
+	ether_setup(dev);
+
+	return 0;
+out:
+	return retval;
+}
+
+
+static int init586(struct net_device *dev)
+{
+	void *ptr;
+	int i,result=0;
+	struct priv *p = (struct priv *) dev->priv;
+	volatile struct configure_cmd_struct	*cfg_cmd;
+	volatile struct iasetup_cmd_struct *ias_cmd;
+	volatile struct tdr_cmd_struct *tdr_cmd;
+	volatile struct mcsetup_cmd_struct *mc_cmd;
+	struct dev_mc_list *dmi=dev->mc_list;
+	int num_addrs=dev->mc_count;
+
+	ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
+
+	cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
+	cfg_cmd->cmd_status	= 0;
+	cfg_cmd->cmd_cmd	= swab16(CMD_CONFIGURE | CMD_LAST);
+	cfg_cmd->cmd_link	= 0xffff;
+
+	cfg_cmd->byte_cnt	= 0x0a; /* number of cfg bytes */
+	cfg_cmd->fifo		= fifo; /* fifo-limit (8=tx:32/rx:64) */
+	cfg_cmd->sav_bf		= 0x40; /* hold or discard bad recv frames (bit 7) */
+	cfg_cmd->adr_len	= 0x2e; /* addr_len |!src_insert |pre-len |loopback */
+	cfg_cmd->priority	= 0x00;
+	cfg_cmd->ifs		= 0x60;
+	cfg_cmd->time_low	= 0x00;
+	cfg_cmd->time_high	= 0xf2;
+	cfg_cmd->promisc	= 0;
+	if(dev->flags & IFF_ALLMULTI) {
+		int len = ((char *) p->iscp - (char *) ptr - 8) / 6;
+		if(num_addrs > len)	{
+			printk("%s: switching to promisc. mode\n",dev->name);
+			dev->flags|=IFF_PROMISC;
+		}
+	}
+	if(dev->flags&IFF_PROMISC)
+	{
+			 cfg_cmd->promisc=1;
+			 dev->flags|=IFF_PROMISC;
+	}
+	cfg_cmd->carr_coll	= 0x00;
+
+	p->scb->cbl_offset	= make16(cfg_cmd);
+	p->scb->cmd_ruc		= 0;
+
+	p->scb->cmd_cuc		= CUC_START; /* cmd.-unit start */
+	sun3_attn586();
+
+	WAIT_4_STAT_COMPL(cfg_cmd);
+
+	if((swab16(cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
+	{
+		printk("%s: configure command failed: %x\n",dev->name,swab16(cfg_cmd->cmd_status));
+		return 1;
+	}
+
+	/*
+	 * individual address setup
+	 */
+
+	ias_cmd = (struct iasetup_cmd_struct *)ptr;
+
+	ias_cmd->cmd_status	= 0;
+	ias_cmd->cmd_cmd	= swab16(CMD_IASETUP | CMD_LAST);
+	ias_cmd->cmd_link	= 0xffff;
+
+	memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
+
+	p->scb->cbl_offset = make16(ias_cmd);
+
+	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+	sun3_attn586();
+
+	WAIT_4_STAT_COMPL(ias_cmd);
+
+	if((swab16(ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
+		printk("%s (82586): individual address setup command failed: %04x\n",dev->name,swab16(ias_cmd->cmd_status));
+		return 1;
+	}
+
+	/*
+	 * TDR, wire check .. e.g. no resistor e.t.c
+	 */
+	 
+	tdr_cmd = (struct tdr_cmd_struct *)ptr;
+
+	tdr_cmd->cmd_status	= 0;
+	tdr_cmd->cmd_cmd	= swab16(CMD_TDR | CMD_LAST);
+	tdr_cmd->cmd_link	= 0xffff;
+	tdr_cmd->status		= 0;
+
+	p->scb->cbl_offset = make16(tdr_cmd);
+	p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */
+	sun3_attn586();
+
+	WAIT_4_STAT_COMPL(tdr_cmd);
+
+	if(!(swab16(tdr_cmd->cmd_status) & STAT_COMPL))
+	{
+		printk("%s: Problems while running the TDR.\n",dev->name);
+	}
+	else
+	{
+		DELAY_16(); /* wait for result */
+		result = swab16(tdr_cmd->status);
+
+		p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+		sun3_attn586(); /* ack the interrupts */
+
+		if(result & TDR_LNK_OK)
+			;
+		else if(result & TDR_XCVR_PRB)
+			printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name);
+		else if(result & TDR_ET_OPN)
+			printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+		else if(result & TDR_ET_SRT)
+		{
+			if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
+				printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
+		}
+		else
+			printk("%s: TDR: Unknown status %04x\n",dev->name,result);
+	}
+
+	/*
+	 * Multicast setup
+	 */
+	if(num_addrs && !(dev->flags & IFF_PROMISC) )
+	{
+		mc_cmd = (struct mcsetup_cmd_struct *) ptr;
+		mc_cmd->cmd_status = 0;
+		mc_cmd->cmd_cmd = swab16(CMD_MCSETUP | CMD_LAST);
+		mc_cmd->cmd_link = 0xffff;
+		mc_cmd->mc_cnt = swab16(num_addrs * 6);
+
+		for(i=0;i<num_addrs;i++,dmi=dmi->next)
+			memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6);
+
+		p->scb->cbl_offset = make16(mc_cmd);
+		p->scb->cmd_cuc = CUC_START;
+		sun3_attn586();
+
+		WAIT_4_STAT_COMPL(mc_cmd);
+
+		if( (swab16(mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+			printk("%s: Can't apply multicast-address-list.\n",dev->name);
+	}
+
+	/*
+	 * alloc nop/xmit-cmds
+	 */
+#if (NUM_XMIT_BUFFS == 1)
+	for(i=0;i<2;i++)
+	{
+		p->nop_cmds[i] 			= (struct nop_cmd_struct *)ptr;
+		p->nop_cmds[i]->cmd_cmd		= swab16(CMD_NOP);
+		p->nop_cmds[i]->cmd_status 	= 0;
+		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));
+		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+	}
+#else
+	for(i=0;i<NUM_XMIT_BUFFS;i++)
+	{
+		p->nop_cmds[i]			= (struct nop_cmd_struct *)ptr;
+		p->nop_cmds[i]->cmd_cmd		= swab16(CMD_NOP);
+		p->nop_cmds[i]->cmd_status	= 0;
+		p->nop_cmds[i]->cmd_link	= make16((p->nop_cmds[i]));
+		ptr = (char *) ptr + sizeof(struct nop_cmd_struct);
+	}
+#endif
+
+	ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
+
+	/*
+	 * alloc xmit-buffs / init xmit_cmds
+	 */
+	for(i=0;i<NUM_XMIT_BUFFS;i++)
+	{
+		p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/
+		ptr = (char *) ptr + sizeof(struct transmit_cmd_struct);
+		p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
+		ptr = (char *) ptr + XMIT_BUFF_SIZE;
+		p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
+		ptr = (char *) ptr + sizeof(struct tbd_struct);
+		if((void *)ptr > (void *)dev->mem_end)
+		{
+			printk("%s: not enough shared-mem for your configuration!\n",dev->name);
+			return 1;
+		}
+		memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
+		memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
+		p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]);
+		p->xmit_cmds[i]->cmd_status = swab16(STAT_COMPL);
+		p->xmit_cmds[i]->cmd_cmd = swab16(CMD_XMIT | CMD_INT);
+		p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
+		p->xmit_buffs[i]->next = 0xffff;
+		p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
+	}
+
+	p->xmit_count = 0;
+	p->xmit_last	= 0;
+#ifndef NO_NOPCOMMANDS
+	p->nop_point	= 0;
+#endif
+
+	 /*
+		* 'start transmitter'
+		*/
+#ifndef NO_NOPCOMMANDS
+	p->scb->cbl_offset = make16(p->nop_cmds[0]);
+	p->scb->cmd_cuc = CUC_START;
+	sun3_attn586();
+	WAIT_4_SCB_CMD();
+#else
+	p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]);
+	p->xmit_cmds[0]->cmd_cmd	= swab16(CMD_XMIT | CMD_SUSPEND | CMD_INT);
+#endif
+
+	/*
+	 * ack. interrupts
+	 */
+	p->scb->cmd_cuc = p->scb->cus & STAT_MASK;
+	sun3_attn586();
+	DELAY_16();
+
+	sun3_enaint();
+	sun3_active();
+
+	return 0;
+}
+
+/******************************************************
+ * This is a helper routine for sun3_82586_rnr_int() and init586().
+ * It sets up the Receive Frame Area (RFA).
+ */
+
+static void *alloc_rfa(struct net_device *dev,void *ptr)
+{
+	volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
+	volatile struct rbd_struct *rbd;
+	int i;
+	struct priv *p = (struct priv *) dev->priv;
+
+	memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd));
+	p->rfd_first = rfd;
+
+	for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) {
+		rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) );
+		rfd[i].rbd_offset = 0xffff;
+	}
+	rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP;	 /* RU suspend */
+
+	ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) );
+
+	rbd = (struct rbd_struct *) ptr;
+	ptr = (void *) (rbd + p->num_recv_buffs);
+
+	 /* clr descriptors */
+	memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs));
+
+	for(i=0;i<p->num_recv_buffs;i++)
+	{
+		rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs));
+		rbd[i].size = swab16(RECV_BUFF_SIZE);
+		rbd[i].buffer = make24(ptr);
+		ptr = (char *) ptr + RECV_BUFF_SIZE;
+	}
+
+	p->rfd_top	= p->rfd_first;
+	p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd);
+
+	p->scb->rfa_offset		= make16(p->rfd_first);
+	p->rfd_first->rbd_offset	= make16(rbd);
+
+	return ptr;
+}
+
+
+/**************************************************
+ * Interrupt Handler ...
+ */
+
+static void sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
+{
+	struct net_device *dev = dev_id;
+	unsigned short stat;
+	int cnt=0;
+	struct priv *p;
+
+	if (!dev) {
+		printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq);
+		return;
+	}
+	p = (struct priv *) dev->priv;
+
+	if(debuglevel > 1)
+		printk("I");
+
+	WAIT_4_SCB_CMD(); /* wait for last command	*/
+
+	while((stat=p->scb->cus & STAT_MASK))
+	{
+		p->scb->cmd_cuc = stat;
+		sun3_attn586();
+
+		if(stat & STAT_FR)	 /* received a frame */
+			sun3_82586_rcv_int(dev);
+
+		if(stat & STAT_RNR) /* RU went 'not ready' */
+		{
+			printk("(R)");
+			if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */
+			{
+				WAIT_4_SCB_CMD();
+				p->scb->cmd_ruc = RUC_RESUME;
+				sun3_attn586();
+				WAIT_4_SCB_CMD_RUC();
+			}
+			else
+			{
+				printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus);
+				sun3_82586_rnr_int(dev);
+			}
+		}
+
+		if(stat & STAT_CX)		/* command with I-bit set complete */
+			 sun3_82586_xmt_int(dev);
+
+#ifndef NO_NOPCOMMANDS
+		if(stat & STAT_CNA)	/* CU went 'not ready' */
+		{
+			if(netif_running(dev))
+				printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus);
+		}
+#endif
+
+		if(debuglevel > 1)
+			printk("%d",cnt++);
+
+		WAIT_4_SCB_CMD(); /* wait for ack. (sun3_82586_xmt_int can be faster than ack!!) */
+		if(p->scb->cmd_cuc)	 /* timed out? */
+		{
+			printk("%s: Acknowledge timed out.\n",dev->name);
+			sun3_disint();
+			break;
+		}
+	}
+
+	if(debuglevel > 1)
+		printk("i");
+}
+
+/*******************************************************
+ * receive-interrupt
+ */
+
+static void sun3_82586_rcv_int(struct net_device *dev)
+{
+	int status,cnt=0;
+	unsigned short totlen;
+	struct sk_buff *skb;
+	struct rbd_struct *rbd;
+	struct priv *p = (struct priv *) dev->priv;
+
+	if(debuglevel > 0)
+		printk("R");
+
+	for(;(status = p->rfd_top->stat_high) & RFD_COMPL;)
+	{
+			rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
+
+			if(status & RFD_OK) /* frame received without error? */
+			{
+				if( (totlen = swab16(rbd->status)) & RBD_LAST) /* the first and the last buffer? */
+				{
+					totlen &= RBD_MASK; /* length of this frame */
+					rbd->status = 0;
+					skb = (struct sk_buff *) dev_alloc_skb(totlen+2);
+					if(skb != NULL)
+					{
+						skb->dev = dev;
+						skb_reserve(skb,2);
+						skb_put(skb,totlen);
+						eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);
+						skb->protocol=eth_type_trans(skb,dev);
+						netif_rx(skb);
+						p->stats.rx_packets++;
+					}
+					else
+						p->stats.rx_dropped++;
+				}
+				else
+				{
+					int rstat;
+						 /* free all RBD's until RBD_LAST is set */
+					totlen = 0;
+					while(!((rstat=swab16(rbd->status)) & RBD_LAST))
+					{
+						totlen += rstat & RBD_MASK;
+						if(!rstat)
+						{
+							printk("%s: Whoops .. no end mark in RBD list\n",dev->name);
+							break;
+						}
+						rbd->status = 0;
+						rbd = (struct rbd_struct *) make32(rbd->next);
+					}
+					totlen += rstat & RBD_MASK;
+					rbd->status = 0;
+					printk("%s: received oversized frame! length: %d\n",dev->name,totlen);
+					p->stats.rx_dropped++;
+			 }
+		}
+		else /* frame !(ok), only with 'save-bad-frames' */
+		{
+			printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
+			p->stats.rx_errors++;
+		}
+		p->rfd_top->stat_high = 0;
+		p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */
+		p->rfd_top->rbd_offset = 0xffff;
+		p->rfd_last->last = 0;				/* delete RFD_SUSP	*/
+		p->rfd_last = p->rfd_top;
+		p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */
+		p->scb->rfa_offset = make16(p->rfd_top);
+
+		if(debuglevel > 0)
+			printk("%d",cnt++);
+	}
+
+	if(automatic_resume)
+	{
+		WAIT_4_SCB_CMD();
+		p->scb->cmd_ruc = RUC_RESUME;
+		sun3_attn586();
+		WAIT_4_SCB_CMD_RUC();
+	}
+
+#ifdef WAIT_4_BUSY
+	{
+		int i;
+		for(i=0;i<1024;i++)
+		{
+			if(p->rfd_top->status)
+				break;
+			DELAY_16();
+			if(i == 1023)
+				printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name);
+		}
+	}
+#endif
+
+#if 0
+	if(!at_least_one)
+	{
+		int i;
+		volatile struct rfd_struct *rfds=p->rfd_top;
+		volatile struct rbd_struct *rbds;
+		printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least);
+		for(i=0;i< (p->num_recv_buffs+4);i++)
+		{
+			rbds = (struct rbd_struct *) make32(rfds->rbd_offset);
+			printk("%04x:%04x ",rfds->status,rbds->status);
+			rfds = (struct rfd_struct *) make32(rfds->next);
+		}
+		printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status);
+		printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus);
+	}
+	old_at_least = at_least_one;
+#endif
+
+	if(debuglevel > 0)
+		printk("r");
+}
+
+/**********************************************************
+ * handle 'Receiver went not ready'.
+ */
+
+static void sun3_82586_rnr_int(struct net_device *dev)
+{
+	struct priv *p = (struct priv *) dev->priv;
+
+	p->stats.rx_errors++;
+
+	WAIT_4_SCB_CMD();		/* wait for the last cmd, WAIT_4_FULLSTAT?? */
+	p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
+	sun3_attn586();
+	WAIT_4_SCB_CMD_RUC();		/* wait for accept cmd. */
+
+	alloc_rfa(dev,(char *)p->rfd_first);
+/* maybe add a check here, before restarting the RU */
+	startrecv586(dev); /* restart RU */
+
+	printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus);
+
+}
+
+/**********************************************************
+ * handle xmit - interrupt
+ */
+
+static void sun3_82586_xmt_int(struct net_device *dev)
+{
+	int status;
+	struct priv *p = (struct priv *) dev->priv;
+
+	if(debuglevel > 0)
+		printk("X");
+
+	status = swab16(p->xmit_cmds[p->xmit_last]->cmd_status);
+	if(!(status & STAT_COMPL))
+		printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name);
+
+	if(status & STAT_OK)
+	{
+		p->stats.tx_packets++;
+		p->stats.collisions += (status & TCMD_MAXCOLLMASK);
+	}
+	else
+	{
+		p->stats.tx_errors++;
+		if(status & TCMD_LATECOLL) {
+			printk("%s: late collision detected.\n",dev->name);
+			p->stats.collisions++;
+		}
+		else if(status & TCMD_NOCARRIER) {
+			p->stats.tx_carrier_errors++;
+			printk("%s: no carrier detected.\n",dev->name);
+		}
+		else if(status & TCMD_LOSTCTS)
+			printk("%s: loss of CTS detected.\n",dev->name);
+		else if(status & TCMD_UNDERRUN) {
+			p->stats.tx_fifo_errors++;
+			printk("%s: DMA underrun detected.\n",dev->name);
+		}
+		else if(status & TCMD_MAXCOLL) {
+			printk("%s: Max. collisions exceeded.\n",dev->name);
+			p->stats.collisions += 16;
+		}
+	}
+
+#if (NUM_XMIT_BUFFS > 1)
+	if( (++p->xmit_last) == NUM_XMIT_BUFFS)
+		p->xmit_last = 0;
+#endif
+	netif_wake_queue(dev);
+}
+
+/***********************************************************
+ * (re)start the receiver
+ */
+
+static void startrecv586(struct net_device *dev)
+{
+	struct priv *p = (struct priv *) dev->priv;
+
+	WAIT_4_SCB_CMD();
+	WAIT_4_SCB_CMD_RUC();
+	p->scb->rfa_offset = make16(p->rfd_first);
+	p->scb->cmd_ruc = RUC_START;
+	sun3_attn586();		/* start cmd. */
+	WAIT_4_SCB_CMD_RUC();	/* wait for accept cmd. (no timeout!!) */
+}
+
+static void sun3_82586_timeout(struct net_device *dev)
+{
+	struct priv *p = (struct priv *) dev->priv;
+#ifndef NO_NOPCOMMANDS
+	if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */
+	{
+		netif_wake_queue(dev);
+#ifdef DEBUG
+		printk("%s: strange ... timeout with CU active?!?\n",dev->name);
+		printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)swab16(p->xmit_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[0]->cmd_status),(int)swab16(p->nop_cmds[1]->cmd_status),(int)p->nop_point);
+#endif
+		p->scb->cmd_cuc = CUC_ABORT;
+		sun3_attn586();
+		WAIT_4_SCB_CMD();
+		p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]);
+		p->scb->cmd_cuc = CUC_START;
+		sun3_attn586();
+		WAIT_4_SCB_CMD();
+		dev->trans_start = jiffies;
+		return 0;
+	}
+#endif
+	{
+#ifdef DEBUG
+		printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus);
+		printk("%s: command-stats: %04x %04x\n",dev->name,swab16(p->xmit_cmds[0]->cmd_status),swab16(p->xmit_cmds[1]->cmd_status));
+		printk("%s: check, whether you set the right interrupt number!\n",dev->name);
+#endif
+		sun3_82586_close(dev);
+		sun3_82586_open(dev);
+	}
+	dev->trans_start = jiffies;
+}
+
+/******************************************************
+ * send frame
+ */
+
+static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	int len,i;
+#ifndef NO_NOPCOMMANDS
+	int next_nop;
+#endif
+	struct priv *p = (struct priv *) dev->priv;
+
+	if(skb->len > XMIT_BUFF_SIZE)
+	{
+		printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
+		return 0;
+	}
+
+	netif_stop_queue(dev);
+
+#if(NUM_XMIT_BUFFS > 1)
+	if(test_and_set_bit(0,(void *) &p->lock)) {
+		printk("%s: Queue was locked\n",dev->name);
+		return 1;
+	}
+	else
+#endif
+	{
+		memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
+		len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+#if (NUM_XMIT_BUFFS == 1)
+#	ifdef NO_NOPCOMMANDS
+
+#ifdef DEBUG
+		if(p->scb->cus & CU_ACTIVE)
+		{
+			printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name);
+			printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,swab16(p->xmit_cmds[0]->cmd_status));
+		}
+#endif
+
+		p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+		for(i=0;i<16;i++)
+		{
+			p->xmit_cmds[0]->cmd_status = 0;
+			WAIT_4_SCB_CMD();
+			if( (p->scb->cus & CU_STATUS) == CU_SUSPEND)
+				p->scb->cmd_cuc = CUC_RESUME;
+			else
+			{
+				p->scb->cbl_offset = make16(p->xmit_cmds[0]);
+				p->scb->cmd_cuc = CUC_START;
+			}
+
+			sun3_attn586();
+			dev->trans_start = jiffies;
+			if(!i)
+				dev_kfree_skb(skb);
+			WAIT_4_SCB_CMD();
+			if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */
+				break;
+			if(p->xmit_cmds[0]->cmd_status)
+				break;
+			if(i==15)
+				printk("%s: Can't start transmit-command.\n",dev->name);
+		}
+#	else
+		next_nop = (p->nop_point + 1) & 0x1;
+		p->xmit_buffs[0]->size = swab16(TBD_LAST | len);
+
+		p->xmit_cmds[0]->cmd_link	 = p->nop_cmds[next_nop]->cmd_link
+			= make16((p->nop_cmds[next_nop]));
+		p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
+
+		p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
+		dev->trans_start = jiffies;
+		p->nop_point = next_nop;
+		dev_kfree_skb(skb);
+#	endif
+#else
+		p->xmit_buffs[p->xmit_count]->size = swab16(TBD_LAST | len);
+		if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
+			next_nop = 0;
+
+		p->xmit_cmds[p->xmit_count]->cmd_status	= 0;
+		/* linkpointer of xmit-command already points to next nop cmd */
+		p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop]));
+		p->nop_cmds[next_nop]->cmd_status = 0;
+
+		p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
+		dev->trans_start = jiffies;
+		p->xmit_count = next_nop;
+
+		{
+			unsigned long flags;
+			save_flags(flags);
+			cli();
+			if(p->xmit_count != p->xmit_last)
+				netif_wake_queue(dev);
+			p->lock = 0;
+			restore_flags(flags);
+		}
+		dev_kfree_skb(skb);
+#endif
+	}
+	return 0;
+}
+
+/*******************************************
+ * Someone wanna have the statistics
+ */
+
+static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev)
+{
+	struct priv *p = (struct priv *) dev->priv;
+	unsigned short crc,aln,rsc,ovrn;
+
+	crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */
+	p->scb->crc_errs = 0;
+	aln = swab16(p->scb->aln_errs);
+	p->scb->aln_errs = 0;
+	rsc = swab16(p->scb->rsc_errs);
+	p->scb->rsc_errs = 0;
+	ovrn = swab16(p->scb->ovrn_errs);
+	p->scb->ovrn_errs = 0;
+
+	p->stats.rx_crc_errors += crc;
+	p->stats.rx_fifo_errors += ovrn;
+	p->stats.rx_frame_errors += aln;
+	p->stats.rx_dropped += rsc;
+
+	return &p->stats;
+}
+
+/********************************************************
+ * Set MC list ..
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	sun3_disint();
+	alloc586(dev);
+	init586(dev);
+	startrecv586(dev);
+	sun3_enaint();
+	netif_wake_queue(dev);
+}
+
+#ifdef MODULE
+#error This code is not currently supported as a module
+static struct net_device dev_sun3_82586;
+
+int init_module(void)
+{
+	dev_sun3_82586.init = sun3_82586_probe;
+	if (register_netdev(&dev_sun3_82586) != 0)
+		return -EIO;
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev(&dev_sun3_82586);
+	kfree(dev_sun3_82586.priv);
+	dev_sun3_82586.priv = NULL;
+}
+#endif /* MODULE */
+
+#if 0
+/*
+ * DUMP .. we expect a not running CMD unit and enough space
+ */
+void sun3_82586_dump(struct net_device *dev,void *ptr)
+{
+	struct priv *p = (struct priv *) dev->priv;
+	struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr;
+	int i;
+
+	p->scb->cmd_cuc = CUC_ABORT;
+	sun3_attn586();
+	WAIT_4_SCB_CMD();
+	WAIT_4_SCB_CMD_RUC();
+
+	dump_cmd->cmd_status = 0;
+	dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST;
+	dump_cmd->dump_offset = make16((dump_cmd + 1));
+	dump_cmd->cmd_link = 0xffff;
+
+	p->scb->cbl_offset = make16(dump_cmd);
+	p->scb->cmd_cuc = CUC_START;
+	sun3_attn586();
+	WAIT_4_STAT_COMPL(dump_cmd);
+
+	if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) )
+				printk("%s: Can't get dump information.\n",dev->name);
+
+	for(i=0;i<170;i++) {
+		printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]);
+		if(i % 24 == 23)
+			printk("\n");
+	}
+	printk("\n");
+}
+#endif
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/sun3_82586.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,318 @@
+/*
+ * Intel i82586 Ethernet definitions
+ *
+ * This is an extension to the Linux operating system, and is covered by the
+ * same Gnu Public License that covers that work.
+ *
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
+ *
+ * I have done a look in the following sources:
+ *   crynwr-packet-driver by Russ Nelson
+ *   Garret A. Wollman's i82586-driver for BSD
+ */
+
+/*
+ * Cloned from ni52.h, copyright as above.  
+ *
+ * Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
+ */
+
+
+/* defines for the obio chip (not vme) */ 
+#define IEOB_NORSET 0x80        /* don't reset the board */
+#define IEOB_ONAIR  0x40        /* put us on the air */
+#define IEOB_ATTEN  0x20        /* attention! */
+#define IEOB_IENAB  0x10        /* interrupt enable */
+#define IEOB_XXXXX  0x08        /* free bit */
+#define IEOB_XCVRL2 0x04        /* level 2 transceiver? */
+#define IEOB_BUSERR 0x02        /* bus error */
+#define IEOB_INT    0x01        /* interrupt */
+
+/* where the obio one lives */
+#define IE_OBIO 0xc0000
+#define IE_IRQ 3
+
+/*
+ * where to find the System Configuration Pointer (SCP)
+ */
+#define SCP_DEFAULT_ADDRESS 0xfffff4
+
+
+/*
+ * System Configuration Pointer Struct
+ */
+
+struct scp_struct
+{
+  unsigned short zero_dum0;	/* has to be zero */
+  unsigned char  sysbus;	/* 0=16Bit,1=8Bit */
+  unsigned char  zero_dum1;	/* has to be zero for 586 */
+  unsigned short zero_dum2;
+  unsigned short zero_dum3;
+  char          *iscp;		/* pointer to the iscp-block */
+};
+
+
+/*
+ * Intermediate System Configuration Pointer (ISCP)
+ */
+struct iscp_struct
+{
+  unsigned char  busy;          /* 586 clears after successful init */
+  unsigned char  zero_dummy;    /* has to be zero */
+  unsigned short scb_offset;    /* pointeroffset to the scb_base */
+  char          *scb_base;      /* base-address of all 16-bit offsets */
+};
+
+/*
+ * System Control Block (SCB)
+ */
+struct scb_struct
+{
+  unsigned char rus;
+  unsigned char cus;
+  unsigned char cmd_ruc;           /* command word: RU part */
+  unsigned char cmd_cuc;           /* command word: CU part & ACK */
+  unsigned short cbl_offset;    /* pointeroffset, command block list */
+  unsigned short rfa_offset;    /* pointeroffset, receive frame area */
+  unsigned short crc_errs;      /* CRC-Error counter */
+  unsigned short aln_errs;      /* allignmenterror counter */
+  unsigned short rsc_errs;      /* Resourceerror counter */
+  unsigned short ovrn_errs;     /* OVerrunerror counter */
+};
+
+/*
+ * possible command values for the command word
+ */
+#define RUC_MASK	0x0070	/* mask for RU commands */
+#define RUC_NOP		0x0000	/* NOP-command */
+#define RUC_START	0x0010	/* start RU */
+#define RUC_RESUME	0x0020	/* resume RU after suspend */
+#define RUC_SUSPEND	0x0030	/* suspend RU */
+#define RUC_ABORT	0x0040	/* abort receiver operation immediately */
+
+#define CUC_MASK        0x07  /* mask for CU command */
+#define CUC_NOP         0x00  /* NOP-command */
+#define CUC_START       0x01  /* start execution of 1. cmd on the CBL */
+#define CUC_RESUME      0x02  /* resume after suspend */
+#define CUC_SUSPEND     0x03  /* Suspend CU */
+#define CUC_ABORT       0x04  /* abort command operation immediately */
+
+#define ACK_MASK        0xf0  /* mask for ACK command */
+#define ACK_CX          0x80  /* acknowledges STAT_CX */
+#define ACK_FR          0x40  /* ack. STAT_FR */
+#define ACK_CNA         0x20  /* ack. STAT_CNA */
+#define ACK_RNR         0x10  /* ack. STAT_RNR */
+
+/*
+ * possible status values for the status word
+ */
+#define STAT_MASK       0xf0  /* mask for cause of interrupt */
+#define STAT_CX         0x80  /* CU finished cmd with its I bit set */
+#define STAT_FR         0x40  /* RU finished receiving a frame */
+#define STAT_CNA        0x20  /* CU left active state */
+#define STAT_RNR        0x10  /* RU left ready state */
+
+#define CU_STATUS       0x7   /* CU status, 0=idle */
+#define CU_SUSPEND      0x1   /* CU is suspended */
+#define CU_ACTIVE       0x2   /* CU is active */
+
+#define RU_STATUS	0x70	/* RU status, 0=idle */
+#define RU_SUSPEND	0x10	/* RU suspended */
+#define RU_NOSPACE	0x20	/* RU no resources */
+#define RU_READY	0x40	/* RU is ready */
+
+/*
+ * Receive Frame Descriptor (RFD)
+ */
+struct rfd_struct
+{
+  unsigned char  stat_low;	/* status word */
+  unsigned char  stat_high;	/* status word */
+  unsigned char  rfd_sf;	/* 82596 mode only */
+  unsigned char  last;		/* Bit15,Last Frame on List / Bit14,suspend */
+  unsigned short next;		/* linkoffset to next RFD */
+  unsigned short rbd_offset;	/* pointeroffset to RBD-buffer */
+  unsigned char  dest[6];	/* ethernet-address, destination */
+  unsigned char  source[6];	/* ethernet-address, source */
+  unsigned short length;	/* 802.3 frame-length */
+  unsigned short zero_dummy;	/* dummy */
+};
+
+#define RFD_LAST     0x80	/* last: last rfd in the list */
+#define RFD_SUSP     0x40	/* last: suspend RU after  */
+#define RFD_COMPL    0x80
+#define RFD_OK       0x20
+#define RFD_BUSY     0x40
+#define RFD_ERR_LEN  0x10     /* Length error (if enabled length-checking */
+#define RFD_ERR_CRC  0x08     /* CRC error */
+#define RFD_ERR_ALGN 0x04     /* Alignment error */
+#define RFD_ERR_RNR  0x02     /* status: receiver out of resources */
+#define RFD_ERR_OVR  0x01     /* DMA Overrun! */
+
+#define RFD_ERR_FTS  0x0080	/* Frame to short */
+#define RFD_ERR_NEOP 0x0040	/* No EOP flag (for bitstuffing only) */
+#define RFD_ERR_TRUN 0x0020	/* (82596 only/SF mode) indicates truncated frame */
+#define RFD_MATCHADD 0x0002     /* status: Destinationaddress !matches IA (only 82596) */
+#define RFD_COLLDET  0x0001	/* Detected collision during reception */
+
+/*
+ * Receive Buffer Descriptor (RBD)
+ */
+struct rbd_struct 
+{
+  unsigned short status;	/* status word,number of used bytes in buff */
+  unsigned short next;		/* pointeroffset to next RBD */
+  char          *buffer;	/* receive buffer address pointer */
+  unsigned short size;		/* size of this buffer */
+  unsigned short zero_dummy;    /* dummy */
+};
+
+#define RBD_LAST	0x8000	/* last buffer */
+#define RBD_USED	0x4000	/* this buffer has data */
+#define RBD_MASK	0x3fff	/* size-mask for length */
+
+/*
+ * Statusvalues for Commands/RFD
+ */
+#define STAT_COMPL   0x8000	/* status: frame/command is complete */
+#define STAT_BUSY    0x4000	/* status: frame/command is busy */
+#define STAT_OK      0x2000	/* status: frame/command is ok */
+
+/*
+ * Action-Commands
+ */
+#define CMD_NOP		0x0000	/* NOP */
+#define CMD_IASETUP	0x0001	/* initial address setup command */
+#define CMD_CONFIGURE	0x0002	/* configure command */
+#define CMD_MCSETUP	0x0003	/* MC setup command */
+#define CMD_XMIT	0x0004	/* transmit command */
+#define CMD_TDR		0x0005	/* time domain reflectometer (TDR) command */
+#define CMD_DUMP	0x0006	/* dump command */
+#define CMD_DIAGNOSE	0x0007	/* diagnose command */
+
+/*
+ * Action command bits
+ */
+#define CMD_LAST	0x8000	/* indicates last command in the CBL */
+#define CMD_SUSPEND	0x4000	/* suspend CU after this CB */
+#define CMD_INT		0x2000	/* generate interrupt after execution */
+
+/*
+ * NOP - command
+ */
+struct nop_cmd_struct
+{
+  unsigned short cmd_status;	/* status of this command */
+  unsigned short cmd_cmd;       /* the command itself (+bits) */
+  unsigned short cmd_link;      /* offsetpointer to next command */
+};
+
+/*
+ * IA Setup command
+ */
+struct iasetup_cmd_struct 
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  iaddr[6];
+};
+
+/*
+ * Configure command 
+ */
+struct configure_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned char  byte_cnt;   /* size of the config-cmd */
+  unsigned char  fifo;       /* fifo/recv monitor */
+  unsigned char  sav_bf;     /* save bad frames (bit7=1)*/
+  unsigned char  adr_len;    /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
+  unsigned char  priority;   /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
+  unsigned char  ifs;        /* inter frame spacing */
+  unsigned char  time_low;   /* slot time low */
+  unsigned char  time_high;  /* slot time high(0-2) and max. retries(4-7) */
+  unsigned char  promisc;    /* promisc-mode(0) , et al (1-7) */
+  unsigned char  carr_coll;  /* carrier(0-3)/collision(4-7) stuff */
+  unsigned char  fram_len;   /* minimal frame len */
+  unsigned char  dummy;	     /* dummy */
+};
+
+/*
+ * Multicast Setup command 
+ */
+struct mcsetup_cmd_struct 
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short mc_cnt;		/* number of bytes in the MC-List */
+  unsigned char  mc_list[0][6];  	/* pointer to 6 bytes entries */
+};
+
+/*
+ * DUMP command
+ */
+struct dump_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short dump_offset;    /* pointeroffset to DUMP space */
+};
+
+/*
+ * transmit command 
+ */
+struct transmit_cmd_struct 
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short tbd_offset;	/* pointeroffset to TBD */
+  unsigned char  dest[6];       /* destination address of the frame */
+  unsigned short length;	/* user defined: 802.3 length / Ether type */
+};
+
+#define TCMD_ERRMASK     0x0fa0
+#define TCMD_MAXCOLLMASK 0x000f
+#define TCMD_MAXCOLL     0x0020
+#define TCMD_HEARTBEAT   0x0040
+#define TCMD_DEFERRED    0x0080
+#define TCMD_UNDERRUN    0x0100
+#define TCMD_LOSTCTS     0x0200
+#define TCMD_NOCARRIER   0x0400
+#define TCMD_LATECOLL    0x0800
+
+struct tdr_cmd_struct
+{
+  unsigned short cmd_status;
+  unsigned short cmd_cmd;
+  unsigned short cmd_link;
+  unsigned short status;
+};
+
+#define TDR_LNK_OK	0x8000	/* No link problem identified */
+#define TDR_XCVR_PRB	0x4000	/* indicates a transceiver problem */
+#define TDR_ET_OPN	0x2000	/* open, no correct termination */
+#define TDR_ET_SRT	0x1000	/* TDR detected a short circuit */
+#define TDR_TIMEMASK	0x07ff	/* mask for the time field */
+
+/*
+ * Transmit Buffer Descriptor (TBD)
+ */
+struct tbd_struct
+{
+  unsigned short size;		/* size + EOF-Flag(15) */
+  unsigned short next;          /* pointeroffset to next TBD */
+  char          *buffer;        /* pointer to buffer */
+};
+
+#define TBD_LAST 0x8000         /* EOF-Flag, indicates last buffer in list */
+
+
+
+
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/sungem.c	Wed Apr  3 17:11:16 2002
@@ -1,7 +1,7 @@
 /* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
- * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
  * 
  * Support for Apple GMAC and assorted PHYs by
  * Benjamin Herrenscmidt (benh@kernel.crashing.org)
@@ -16,6 +16,8 @@
  *    I can at least detect gigabit with autoneg.
  */
 
+#include <linux/config.h>
+
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -35,9 +37,10 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
+#include <linux/crc32.h>
+#include <linux/random.h>
 
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -67,8 +70,8 @@
 			 NETIF_MSG_LINK)
 
 #define DRV_NAME	"sungem"
-#define DRV_VERSION	"0.96"
-#define DRV_RELDATE	"11/17/01"
+#define DRV_VERSION	"0.97"
+#define DRV_RELDATE	"3/20/02"
 #define DRV_AUTHOR	"David S. Miller (davem@redhat.com)"
 
 static char version[] __devinitdata =
@@ -293,19 +296,119 @@
 	return 0;
 }
 
+/* When we get a RX fifo overflow, the RX unit in GEM is probably hung
+ * so we do the following.
+ *
+ * If any part of the reset goes wrong, we return 1 and that causes the
+ * whole chip to be reset.
+ */
+static int gem_rxmac_reset(struct gem *gp)
+{
+	struct net_device *dev = gp->dev;
+	int limit, i;
+	u64 desc_dma;
+	u32 val;
+
+	/* First, reset MAC RX. */
+	writel(gp->mac_rx_cfg & ~MAC_RXCFG_ENAB,
+	       gp->regs + MAC_RXCFG);
+	for (limit = 0; limit < 5000; limit++) {
+		if (!(readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB))
+			break;
+		udelay(10);
+	}
+	if (limit == 5000) {
+		printk(KERN_ERR "%s: RX MAC will not disable, resetting whole "
+		       "chip.\n", dev->name);
+		return 1;
+	}
+
+	/* Second, disable RX DMA. */
+	writel(0, gp->regs + RXDMA_CFG);
+	for (limit = 0; limit < 5000; limit++) {
+		if (!(readl(gp->regs + RXDMA_CFG) & RXDMA_CFG_ENABLE))
+			break;
+		udelay(10);
+	}
+	if (limit == 5000) {
+		printk(KERN_ERR "%s: RX DMA will not disable, resetting whole "
+		       "chip.\n", dev->name);
+		return 1;
+	}
+
+	udelay(5000);
+
+	/* Execute RX reset command. */
+	writel(gp->swrst_base | GREG_SWRST_RXRST,
+	       gp->regs + GREG_SWRST);
+	for (limit = 0; limit < 5000; limit++) {
+		if (!(readl(gp->regs + GREG_SWRST) & GREG_SWRST_RXRST))
+			break;
+		udelay(10);
+	}
+	if (limit == 5000) {
+		printk(KERN_ERR "%s: RX reset command will not execute, resetting "
+		       "whole chip.\n", dev->name);
+		return 1;
+	}
+
+	/* Refresh the RX ring. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct gem_rxd *rxd = &gp->init_block->rxd[i];
+
+		if (gp->rx_skbs[i] == NULL) {
+			printk(KERN_ERR "%s: Parts of RX ring empty, resetting "
+			       "whole chip.\n", dev->name);
+			return 1;
+		}
+
+		rxd->status_word = cpu_to_le64(RXDCTRL_FRESH(gp));
+	}
+	gp->rx_new = gp->rx_old = 0;
+
+	/* Now we must reprogram the rest of RX unit. */
+	desc_dma = (u64) gp->gblock_dvma;
+	desc_dma += (INIT_BLOCK_TX_RING_SIZE * sizeof(struct gem_txd));
+	writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
+	writel(desc_dma & 0xffffffff, gp->regs + RXDMA_DBLOW);
+	writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+	val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
+	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
+	writel(val, gp->regs + RXDMA_CFG);
+	if (readl(gp->regs + GREG_BIFCFG) & GREG_BIFCFG_M66EN)
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((8 << 12) & RXDMA_BLANK_ITIME)),
+		       gp->regs + RXDMA_BLANK);
+	else
+		writel(((5 & RXDMA_BLANK_IPKTS) |
+			((4 << 12) & RXDMA_BLANK_ITIME)),
+		       gp->regs + RXDMA_BLANK);
+	val  = (((gp->rx_pause_off / 64) << 0) & RXDMA_PTHRESH_OFF);
+	val |= (((gp->rx_pause_on / 64) << 12) & RXDMA_PTHRESH_ON);
+	writel(val, gp->regs + RXDMA_PTHRESH);
+	val = readl(gp->regs + RXDMA_CFG);
+	writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+	writel(MAC_RXSTAT_RCV, gp->regs + MAC_RXMASK);
+	val = readl(gp->regs + MAC_RXCFG);
+	writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+	return 0;
+}
+
 static int gem_rxmac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
 {
 	u32 rxmac_stat = readl(gp->regs + MAC_RXSTAT);
+	int ret = 0;
 
 	if (netif_msg_intr(gp))
 		printk(KERN_DEBUG "%s: rxmac interrupt, rxmac_stat: 0x%x\n",
 			gp->dev->name, rxmac_stat);
 
 	if (rxmac_stat & MAC_RXSTAT_OFLW) {
-		printk(KERN_ERR "%s: RX MAC fifo overflow.\n",
-		       dev->name);
 		gp->net_stats.rx_over_errors++;
 		gp->net_stats.rx_fifo_errors++;
+
+		ret = gem_rxmac_reset(gp);
 	}
 
 	if (rxmac_stat & MAC_RXSTAT_ACE)
@@ -320,7 +423,7 @@
 	/* We do not track MAC_RXSTAT_FCE and MAC_RXSTAT_VCE
 	 * events.
 	 */
-	return 0;
+	return ret;
 }
 
 static int gem_mac_interrupt(struct net_device *dev, struct gem *gp, u32 gem_status)
@@ -480,7 +583,7 @@
 	return 0;
 
 do_reset:
-	gp->reset_task_pending = 1;
+	gp->reset_task_pending = 2;
 	schedule_task(&gp->reset_task);
 
 	return 1;
@@ -542,7 +645,7 @@
 	gp->tx_old = entry;
 
 	if (netif_queue_stopped(dev) &&
-	    TX_BUFFS_AVAIL(gp) > 0)
+	    TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
 		netif_wake_queue(dev);
 }
 
@@ -717,7 +820,7 @@
 
 	spin_lock_irq(&gp->lock);
 
-	gp->reset_task_pending = 1;
+	gp->reset_task_pending = 2;
 	schedule_task(&gp->reset_task);
 
 	spin_unlock_irq(&gp->lock);
@@ -752,9 +855,12 @@
 
 	spin_lock_irq(&gp->lock);
 
+	/* This is a hard error, log it. */
 	if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		spin_unlock_irq(&gp->lock);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
 		return 1;
 	}
 
@@ -829,7 +935,7 @@
 	}
 
 	gp->tx_new = entry;
-	if (TX_BUFFS_AVAIL(gp) <= 0)
+	if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
 
 	if (netif_msg_tx_queued(gp))
@@ -844,19 +950,28 @@
 }
 
 /* Jumbo-grams don't seem to work :-( */
+#define GEM_MIN_MTU	68
 #if 1
-#define MAX_MTU		1500
+#define GEM_MAX_MTU	1500
 #else
-#define MAX_MTU		9000
+#define GEM_MAX_MTU	9000
 #endif
 
 static int gem_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct gem *gp = dev->priv;
 
-	if (new_mtu < 0 || new_mtu > MAX_MTU)
+	if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
 		return -EINVAL;
 
+	if (!netif_running(dev) || !netif_device_present(dev)) {
+		/* We'll just catch it later when the
+		 * device is up'd or resumed.
+		 */
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
 	spin_lock_irq(&gp->lock);
 	dev->mtu = new_mtu;
 	gp->reset_task_pending = 1;
@@ -870,6 +985,7 @@
 
 #define STOP_TRIES 32
 
+/* Must be invoked under gp->lock. */
 static void gem_stop(struct gem *gp)
 {
 	int limit;
@@ -879,7 +995,8 @@
 	writel(0xffffffff, gp->regs + GREG_IMASK);
 
 	/* Reset the chip */
-	writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, gp->regs + GREG_SWRST);
+	writel(gp->swrst_base | GREG_SWRST_TXRST | GREG_SWRST_RXRST,
+	       gp->regs + GREG_SWRST);
 
 	limit = STOP_TRIES;
 
@@ -894,6 +1011,7 @@
 		printk(KERN_ERR "gem: SW reset is ghetto.\n");
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_start_dma(struct gem *gp)
 {
 	unsigned long val;
@@ -929,6 +1047,7 @@
 	{ 1, 0, 1 },	/* 1000BT */
 };
 
+/* Must be invoked under gp->lock. */
 static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
 {
 	u16 ctl;
@@ -954,11 +1073,8 @@
 	}
 
 start_aneg:
-	spin_lock_irq(&gp->lock);
-	if (!gp->hw_running) {
-		spin_unlock_irq(&gp->lock);
+	if (!gp->hw_running)
 		return;
-	}
 
 	/* Configure PHY & start aneg */
 	ctl = phy_read(gp, MII_BMCR);
@@ -973,11 +1089,10 @@
 	phy_write(gp, MII_BMCR, ctl);
 
 	gp->timer_ticks = 0;
-	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-	add_timer(&gp->link_timer);
-	spin_unlock_irq(&gp->lock);
+	mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
 {
 	u32 val;
@@ -1021,6 +1136,8 @@
 
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
+ *
+ * Must be invoked under gp->lock.
  */
 static void gem_set_link_modes(struct gem *gp)
 {
@@ -1101,6 +1218,20 @@
 			pause = 1;
 	}
 
+	if (netif_msg_link(gp)) {
+		if (pause) {
+			printk(KERN_INFO "%s: Pause is enabled "
+			       "(rxfifo: %d off: %d on: %d)\n",
+			       gp->dev->name,
+			       gp->rx_fifo_sz,
+			       gp->rx_pause_off,
+			       gp->rx_pause_on);
+		} else {
+			printk(KERN_INFO "%s: Pause is disabled\n",
+			       gp->dev->name);
+		}
+	}
+
 	if (!full_duplex)
 		writel(512, gp->regs + MAC_STIME);
 	else
@@ -1115,6 +1246,7 @@
 	gem_start_dma(gp);
 }
 
+/* Must be invoked under gp->lock. */
 static int gem_mdio_link_not_up(struct gem *gp)
 {
 	u16 val;
@@ -1158,7 +1290,7 @@
 	return 0;
 }
 
-static void gem_init_rings(struct gem *, int);
+static void gem_init_rings(struct gem *);
 static void gem_init_hw(struct gem *, int);
 
 static void gem_reset_task(void *data)
@@ -1169,24 +1301,27 @@
 	 * DMA stopped. Todo: Use this function for reset
 	 * on error as well.
 	 */
+
+	spin_lock_irq(&gp->lock);
+
 	if (gp->hw_running && gp->opened) {
 		/* Make sure we don't get interrupts or tx packets */
-		spin_lock_irq(&gp->lock);
-
 		netif_stop_queue(gp->dev);
 
 		writel(0xffffffff, gp->regs + GREG_IMASK);
 
-		spin_unlock_irq(&gp->lock);
-
 		/* Reset the chip & rings */
 		gem_stop(gp);
-		gem_init_rings(gp, 0);
-		gem_init_hw(gp, 0);
+		gem_init_rings(gp);
+
+		gem_init_hw(gp,
+			    (gp->reset_task_pending == 2));
 
 		netif_wake_queue(gp->dev);
 	}
 	gp->reset_task_pending = 0;
+
+	spin_unlock_irq(&gp->lock);
 }
 
 static void gem_link_timer(unsigned long data)
@@ -1196,13 +1331,14 @@
 	if (!gp->hw_running)
 		return;
 
+	spin_lock_irq(&gp->lock);
+
 	/* If the link of task is still pending, we just
 	 * reschedule the link timer
 	 */
 	if (gp->reset_task_pending)
 		goto restart;
 	    	
-	spin_lock_irq(&gp->lock);
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
 		u16 val = phy_read(gp, MII_BMSR);
@@ -1247,16 +1383,15 @@
 				if (netif_msg_link(gp))
 					printk(KERN_INFO "%s: Link down\n",
 						gp->dev->name);
-				gp->reset_task_pending = 1;
+				gp->reset_task_pending = 2;
 				schedule_task(&gp->reset_task);
 				restart = 1;
 			} else if (++gp->timer_ticks > 10)
 				restart = gem_mdio_link_not_up(gp);
 
 			if (restart) {
-				spin_unlock_irq(&gp->lock);
 				gem_begin_auto_negotiation(gp, NULL);
-				return;
+				goto out_unlock;
 			}
 		}
 	} else {
@@ -1273,11 +1408,12 @@
 	}
 
 restart:
-	gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
-	add_timer(&gp->link_timer);
+	mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
+out_unlock:
 	spin_unlock_irq(&gp->lock);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_clean_rings(struct gem *gp)
 {
 	struct gem_init_block *gb = gp->init_block;
@@ -1311,7 +1447,9 @@
 			gp->tx_skbs[i] = NULL;
 
 			for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
-				txd = &gb->txd[i];
+				int ent = i & (TX_RING_SIZE - 1);
+
+				txd = &gb->txd[ent];
 				dma_addr = le64_to_cpu(txd->buffer);
 				pci_unmap_page(gp->pdev, dma_addr,
 					       le64_to_cpu(txd->control_word) &
@@ -1325,16 +1463,14 @@
 	}
 }
 
-static void gem_init_rings(struct gem *gp, int from_irq)
+/* Must be invoked under gp->lock. */
+static void gem_init_rings(struct gem *gp)
 {
 	struct gem_init_block *gb = gp->init_block;
 	struct net_device *dev = gp->dev;
-	int i, gfp_flags = GFP_KERNEL;
+	int i;
 	dma_addr_t dma_addr;
 
-	if (from_irq)
-		gfp_flags = GFP_ATOMIC;
-
 	gp->rx_new = gp->rx_old = gp->tx_new = gp->tx_old = 0;
 
 	gem_clean_rings(gp);
@@ -1343,7 +1479,7 @@
 		struct sk_buff *skb;
 		struct gem_rxd *rxd = &gb->rxd[i];
 
-		skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), gfp_flags);
+		skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
 		if (!skb) {
 			rxd->buffer = 0;
 			rxd->status_word = 0;
@@ -1372,6 +1508,7 @@
 	}
 }
 
+/* Must be invoked under gp->lock. */
 static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
 {
 	u16 val;
@@ -1396,6 +1533,7 @@
 	return (limit <= 0);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_bcm5201_phy(struct gem *gp)
 {
 	u16 data;
@@ -1405,6 +1543,7 @@
 	phy_write(gp, MII_BCM5201_MULTIPHY, data);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_bcm5400_phy(struct gem *gp)
 {
 	u16 data;
@@ -1432,6 +1571,7 @@
 	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_bcm5401_phy(struct gem *gp)
 {
 	u16 data;
@@ -1446,6 +1586,9 @@
 		 * WARNING ! OF and Darwin don't agree on the
 		 * register addresses. OF seem to interpret the
 		 * register numbers below as decimal
+		 *
+		 * Note: This should (and does) match tg3_init_5401phy_dsp
+		 *       in the tg3.c driver. -DaveM
 		 */
 		phy_write(gp, 0x18, 0x0c20);
 		phy_write(gp, 0x17, 0x0012);
@@ -1475,6 +1618,7 @@
 	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_bcm5411_phy(struct gem *gp)
 {
 	u16 data;
@@ -1501,6 +1645,7 @@
 	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_phy(struct gem *gp)
 {
 	u32 mifcfg;
@@ -1649,7 +1794,9 @@
 		val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO);
 		writel(val, gp->regs + PCS_CFG);
 
-		/* Advertise all capabilities. */
+		/* Advertise all capabilities except assymetric
+		 * pause.
+		 */
 		val = readl(gp->regs + PCS_MIIADV);
 		val |= (PCS_MIIADV_FD | PCS_MIIADV_HD |
 			PCS_MIIADV_SP | PCS_MIIADV_AP);
@@ -1684,9 +1831,9 @@
 	if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
 	    gp->phy_mod != phymod_bcm5411)
 	    	gp->link_cntl &= ~BMCR_SPD2;
-	    
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_dma(struct gem *gp)
 {
 	u64 desc_dma = (u64) gp->gblock_dvma;
@@ -1702,7 +1849,7 @@
 	writel(0, gp->regs + TXDMA_KICK);
 
 	val = (RXDMA_CFG_BASE | (RX_OFFSET << 10) |
-	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_512);
+	       ((14 / 2) << 13) | RXDMA_CFG_FTHRESH_128);
 	writel(val, gp->regs + RXDMA_CFG);
 
 	writel(desc_dma >> 32, gp->regs + RXDMA_DBHI);
@@ -1724,6 +1871,7 @@
 		       gp->regs + RXDMA_BLANK);
 }
 
+/* Must be invoked under gp->lock. */
 static u32
 gem_setup_multicast(struct gem *gp)
 {
@@ -1766,10 +1914,10 @@
 	return rxcfg;
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_mac(struct gem *gp)
 {
 	unsigned char *e = &gp->dev->dev_addr[0];
-	u32 rxcfg;
 
 	if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
 	    gp->pdev->device == PCI_DEVICE_ID_SUN_GEM)
@@ -1780,7 +1928,10 @@
 	writel(0x04, gp->regs + MAC_IPG2);
 	writel(0x40, gp->regs + MAC_STIME);
 	writel(0x40, gp->regs + MAC_MINFSZ);
-	writel(0x20000000 | (gp->dev->mtu + 18), gp->regs + MAC_MAXFSZ);
+
+	/* Ethernet payload + header + FCS + optional VLAN tag. */
+	writel(0x20000000 | (gp->dev->mtu + ETH_HLEN + 4 + 4), gp->regs + MAC_MAXFSZ);
+
 	writel(0x07, gp->regs + MAC_PASIZE);
 	writel(0x04, gp->regs + MAC_JAMSIZE);
 	writel(0x10, gp->regs + MAC_ATTLIM);
@@ -1806,7 +1957,7 @@
 	writel(0, gp->regs + MAC_AF21MSK);
 	writel(0, gp->regs + MAC_AF0MSK);
 
-	rxcfg = gem_setup_multicast(gp);
+	gp->mac_rx_cfg = gem_setup_multicast(gp);
 
 	writel(0, gp->regs + MAC_NCOLL);
 	writel(0, gp->regs + MAC_FASUCC);
@@ -1824,7 +1975,7 @@
 	 * them once a link is established.
 	 */
 	writel(0, gp->regs + MAC_TXCFG);
-	writel(rxcfg, gp->regs + MAC_RXCFG);
+	writel(gp->mac_rx_cfg, gp->regs + MAC_RXCFG);
 	writel(0, gp->regs + MAC_MCCFG);
 	writel(0, gp->regs + MAC_XIFCFG);
 
@@ -1841,6 +1992,7 @@
 	writel(0xffffffff, gp->regs + MAC_MCMASK);
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_pause_thresholds(struct gem *gp)
 {
 	/* Calculate pause thresholds.  Setting the OFF threshold to the
@@ -1851,8 +2003,9 @@
 	if (gp->rx_fifo_sz <= (2 * 1024)) {
 		gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
 	} else {
-		int off = (gp->rx_fifo_sz - (5 * 1024));
-		int on = off - 1024;
+		int max_frame = (gp->dev->mtu + ETH_HLEN + 4 + 4 + 64) & ~63;
+		int off = (gp->rx_fifo_sz - (max_frame * 2));
+		int on = off - max_frame;
 
 		gp->rx_pause_off = off;
 		gp->rx_pause_on = on;
@@ -1861,7 +2014,10 @@
 	{
 		u32 cfg;
 
-		cfg  = GREG_CFG_IBURST;
+		cfg  = 0;
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_ALPHA)
+		cfg |= GREG_CFG_IBURST;
+#endif
 		cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
 		cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
 		writel(cfg, gp->regs + GREG_CFG);
@@ -1881,6 +2037,7 @@
 		gp->phy_type = phy_mii_mdio0;
 		gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
 		gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+		gp->swrst_base = 0;
 		return 0;
 	}
 
@@ -1943,6 +2100,7 @@
 				       gp->tx_fifo_sz, gp->rx_fifo_sz);
 				return -1;
 			}
+			gp->swrst_base = 0;
 		} else {
 			if (gp->tx_fifo_sz != (2 * 1024) ||
 			    gp->rx_fifo_sz != (2 * 1024)) {
@@ -1950,12 +2108,14 @@
 				       gp->tx_fifo_sz, gp->rx_fifo_sz);
 				return -1;
 			}
+			gp->swrst_base = (64 / 4) << GREG_SWRST_CACHE_SHIFT;
 		}
 	}
 
 	return 0;
 }
 
+/* Must be invoked under gp->lock. */
 static void gem_init_hw(struct gem *gp, int restart_link)
 {
 	/* On Apple's gmac, I initialize the PHY only after
@@ -1970,21 +2130,16 @@
 	gem_init_mac(gp);
 	gem_init_pause_thresholds(gp);
 
-	spin_lock_irq(&gp->lock);
 	if (restart_link) {
 		/* Default aneg parameters */
 		gp->timer_ticks = 0;
 		gp->lstate = link_down;
 
-		spin_unlock_irq(&gp->lock);
-
 		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
 		gem_begin_auto_negotiation(gp, NULL);
 	} else {
 		if (gp->lstate == link_up)
 			gem_set_link_modes(gp);
-
-		spin_unlock_irq(&gp->lock);
 	}
 }
 
@@ -2029,6 +2184,7 @@
 
 #endif /* CONFIG_ALL_PPC */
 
+/* Must be invoked under gp->lock. */
 static void gem_stop_phy(struct gem *gp)
 {
 	u32 mifcfg;
@@ -2100,14 +2256,21 @@
 		schedule();
 	
 	/* Actually stop the chip */
+	spin_lock_irq(&gp->lock);
 	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gem_stop_phy(gp);
+
+		spin_unlock_irq(&gp->lock);
+
 #ifdef CONFIG_ALL_PPC
 		/* Power down the chip */
 		gem_apple_powerdown(gp);
 #endif /* CONFIG_ALL_PPC */
-	} else
+	} else {
 		gem_stop(gp);
+
+		spin_unlock_irq(&gp->lock);
+	}
 }
 
 static void gem_pm_task(void *data)
@@ -2142,14 +2305,19 @@
 static int gem_open(struct net_device *dev)
 {
 	struct gem *gp = dev->priv;
-	int hw_was_up = gp->hw_running;
+	int hw_was_up;
 
 	down(&gp->pm_sem);
 
+	hw_was_up = gp->hw_running;
+
 	/* Stop the PM timer/task */
 	del_timer(&gp->pm_timer);
 	flush_scheduled_tasks();
 
+	/* The power-management semaphore protects the hw_running
+	 * etc. state so it is safe to do this bit without gp->lock
+	 */
 	if (!gp->hw_running) {
 #ifdef CONFIG_ALL_PPC
 		/* First, we need to bring up the chip */
@@ -2158,18 +2326,26 @@
 			gem_check_invariants(gp);
 		}
 #endif /* CONFIG_ALL_PPC */
+
 		/* Reset the chip */
+		spin_lock_irq(&gp->lock);
 		gem_stop(gp);
+		spin_unlock_irq(&gp->lock);
 
 		gp->hw_running = 1;
 	}
 
+	spin_lock_irq(&gp->lock);
+
 	/* We can now request the interrupt as we know it's masked
 	 * on the controller
 	 */
 	if (request_irq(gp->pdev->irq, gem_interrupt,
 			SA_SHIRQ, dev->name, (void *)dev)) {
+		spin_unlock_irq(&gp->lock);
+
 		printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
+
 #ifdef CONFIG_ALL_PPC
 		if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			gem_apple_powerdown(gp);
@@ -2183,13 +2359,15 @@
 	}
 
 	/* Allocate & setup ring buffers */
-	gem_init_rings(gp, 0);
+	gem_init_rings(gp);
 
 	/* Init & setup chip hardware */
 	gem_init_hw(gp, !hw_was_up);
 
 	gp->opened = 1;
 
+	spin_unlock_irq(&gp->lock);
+
 	up(&gp->pm_sem);
 
 	return 0;
@@ -2209,8 +2387,6 @@
 	writel(0xffffffff, gp->regs + GREG_IMASK);
 	netif_stop_queue(dev);
 
-	spin_unlock_irq(&gp->lock);
-
 	/* Stop chip */
 	gem_stop(gp);
 
@@ -2220,6 +2396,8 @@
 	/* Bye, the pm timer will finish the job */
 	free_irq(gp->pdev->irq, (void *) dev);
 
+	spin_unlock_irq(&gp->lock);
+
 	/* Fire the PM timer that will shut us down in about 10 seconds */
 	gp->pm_timer.expires = jiffies + 10*HZ;
 	add_timer(&gp->pm_timer);
@@ -2245,21 +2423,21 @@
 	
 	/* If the driver is opened, we stop the DMA */
 	if (gp->opened) {
+		spin_lock_irq(&gp->lock);
+
 		/* Stop traffic, mark us closed */
 		netif_device_detach(dev);
 
-		spin_lock_irq(&gp->lock);
-
 		writel(0xffffffff, gp->regs + GREG_IMASK);
 
-		spin_unlock_irq(&gp->lock);
-
 		/* Stop chip */
 		gem_stop(gp);
 
 		/* Get rid of ring buffers */
 		gem_clean_rings(gp);
 
+		spin_unlock_irq(&gp->lock);
+
 		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			disable_irq(gp->pdev->irq);
 	}
@@ -2290,10 +2468,15 @@
 			gem_check_invariants(gp);
 		}
 #endif /* CONFIG_ALL_PPC */
+		spin_lock_irq(&gp->lock);
+
 		gem_stop(gp);
 		gp->hw_running = 1;
-		gem_init_rings(gp, 0);
+		gem_init_rings(gp);
 		gem_init_hw(gp, 1);
+
+		spin_unlock_irq(&gp->lock);
+
 		netif_device_attach(dev);
 		if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
 			enable_irq(gp->pdev->irq);
@@ -2309,6 +2492,8 @@
 	struct gem *gp = dev->priv;
 	struct net_device_stats *stats = &gp->net_stats;
 
+	spin_lock_irq(&gp->lock);
+
 	if (gp->hw_running) {
 		stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
 		writel(0, gp->regs + MAC_FCSERR);
@@ -2326,6 +2511,9 @@
 		writel(0, gp->regs + MAC_ECOLL);
 		writel(0, gp->regs + MAC_LCOLL);
 	}
+
+	spin_unlock_irq(&gp->lock);
+
 	return &gp->net_stats;
 }
 
@@ -2338,10 +2526,12 @@
 	if (!gp->hw_running)
 		return;
 		
+	spin_lock_irq(&gp->lock);
+
 	netif_stop_queue(dev);
 
 	rxcfg = readl(gp->regs + MAC_RXCFG);
-	rxcfg_new = gem_setup_multicast(gp);
+	gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp);
 	
 	writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
 	while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
@@ -2355,8 +2545,9 @@
 
 	writel(rxcfg, gp->regs + MAC_RXCFG);
 
-	/* Hrm... we may walk on the reset task here... */
 	netif_wake_queue(dev);
+
+	spin_unlock_irq(&gp->lock);
 }
 
 /* Eventually add support for changing the advertisement
@@ -2405,11 +2596,13 @@
 		ecmd.phy_address = 0; /* XXX fixed PHYAD */
 
 		/* Record PHY settings if HW is on. */
+		spin_lock_irq(&gp->lock);
 		if (gp->hw_running) {
 			bmcr = phy_read(gp, MII_BMCR);
 			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
 		} else
 			bmcr = 0;
+		spin_unlock_irq(&gp->lock);
 		if (bmcr & BMCR_ANENABLE) {
 			ecmd.autoneg = AUTONEG_ENABLE;
 			ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
@@ -2443,18 +2636,22 @@
 		      ecmd.duplex != DUPLEX_FULL)))
 			return -EINVAL;
 
-		/* Apply settings and restart link process */
-		if (gp->hw_running)
-			del_timer(&gp->link_timer);
+		/* Apply settings and restart link process. */
+		spin_lock_irq(&gp->lock);
 		gem_begin_auto_negotiation(gp, &ecmd);
+		spin_unlock_irq(&gp->lock);
+
 		return 0;
 
 	case ETHTOOL_NWAY_RST:
 		if ((gp->link_cntl & BMCR_ANENABLE) == 0)
 			return -EINVAL;
-		if (gp->hw_running)
-			del_timer(&gp->link_timer);
+
+		/* Restart link process. */
+		spin_lock_irq(&gp->lock);
 		gem_begin_auto_negotiation(gp, NULL);
+		spin_unlock_irq(&gp->lock);
+
 		return 0;
 
 	case ETHTOOL_GWOL:
@@ -2570,13 +2767,74 @@
 	return rc;
 }
 
+#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC))
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr)
+{
+	int this_offset;
+
+	for (this_offset = 0x20; this_offset < len; this_offset++) {
+		void *p = rom_base + this_offset;
+		int i;
+
+		if (readb(p + 0) != 0x90 ||
+		    readb(p + 1) != 0x00 ||
+		    readb(p + 2) != 0x09 ||
+		    readb(p + 3) != 0x4e ||
+		    readb(p + 4) != 0x41 ||
+		    readb(p + 5) != 0x06)
+			continue;
+
+		this_offset += 6;
+		p += 6;
+
+		for (i = 0; i < 6; i++)
+			dev_addr[i] = readb(p + i);
+		break;
+	}
+}
+
+static void get_gem_mac_nonobp(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+	u32 rom_reg_orig;
+	void *p;
+
+	if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+		if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+			goto use_random;
+	}
+
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+	pci_write_config_dword(pdev, pdev->rom_base_reg,
+			       rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+	p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+	if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+		find_eth_addr_in_vpd(p, (64 * 1024), dev_addr);
+
+	if (p != NULL)
+		iounmap(p);
+
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+	return;
+
+use_random:
+	/* Sun MAC prefix then 3 random bytes. */
+	dev_addr[0] = 0x08;
+	dev_addr[1] = 0x00;
+	dev_addr[2] = 0x20;
+	get_random_bytes(dev_addr, 3);
+	return;
+}
+#endif /* not Sparc and not PPC */
+
 static int __devinit gem_get_device_address(struct gem *gp)
 {
 #if defined(__sparc__) || defined(CONFIG_ALL_PPC)
 	struct net_device *dev = gp->dev;
 #endif
 
-#ifdef __sparc__
+#if defined(__sparc__)
 	struct pci_dev *pdev = gp->pdev;
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	int node = -1;
@@ -2591,8 +2849,7 @@
 	}
 	if (node == -1)
 		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
-#endif
-#ifdef CONFIG_ALL_PPC
+#elif defined(CONFIG_ALL_PPC)
 	unsigned char *addr;
 
 	addr = get_property(gp->of_node, "local-mac-address", NULL);
@@ -2602,6 +2859,8 @@
 		return -1;
 	}
 	memcpy(dev->dev_addr, addr, MAX_ADDR_LEN);
+#else
+	get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr);
 #endif
 	return 0;
 }
@@ -2664,21 +2923,21 @@
 		return -ENODEV;
 	}
 
-	dev = init_etherdev(NULL, sizeof(*gp));
+	dev = alloc_etherdev(sizeof(*gp));
 	if (!dev) {
-		printk(KERN_ERR PFX "Etherdev init failed, aborting.\n");
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
 
-	if (!request_mem_region(gemreg_base, gemreg_len, dev->name)) {
-		printk(KERN_ERR PFX "MMIO resource (0x%lx@0x%lx) unavailable, "
-		       "aborting.\n", gemreg_base, gemreg_len);
+	gp = dev->priv;
+
+	if (pci_request_regions(pdev, dev->name)) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+		       "aborting.\n");
 		goto err_out_free_netdev;
 	}
 
-	gp = dev->priv;
-
 	gp->pdev = pdev;
 	dev->base_addr = (long) pdev;
 	gp->dev = dev;
@@ -2711,7 +2970,7 @@
 	if (gp->regs == 0UL) {
 		printk(KERN_ERR PFX "Cannot map device registers, "
 		       "aborting.\n");
-		goto err_out_free_mmio_res;
+		goto err_out_free_res;
 	}
 
 	/* On Apple, we power the chip up now in order for check
@@ -2722,12 +2981,18 @@
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE)
 		gem_apple_powerup(gp);
 #endif
+	spin_lock_irq(&gp->lock);
 	gem_stop(gp);
+	spin_unlock_irq(&gp->lock);
+
 	if (gem_check_invariants(gp))
 		goto err_out_iounmap;
+
+	spin_lock_irq(&gp->lock);
 	gp->hw_running = 1;
 	gem_init_phy(gp);
 	gem_begin_auto_negotiation(gp, NULL);
+	spin_unlock_irq(&gp->lock);
 
 	/* It is guarenteed that the returned buffer will be at least
 	 * PAGE_SIZE aligned.
@@ -2741,22 +3006,28 @@
 		goto err_out_iounmap;
 	}
 
-	pci_set_drvdata(pdev, dev);
-
-	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
-	       dev->name);
-
 #ifdef CONFIG_ALL_PPC
 	gp->of_node = pci_device_to_OF_node(pdev);
 #endif	
 	if (gem_get_device_address(gp))
-		goto err_out_iounmap;
+		goto err_out_free_consistent;
+
+	if (register_netdev(dev)) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_free_consistent;
+	}
+
+	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
+	       dev->name);
 
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? ' ' : ':');
 	printk("\n");
 
+	pci_set_drvdata(pdev, dev);
+
 	dev->open = gem_open;
 	dev->stop = gem_close;
 	dev->hard_start_xmit = gem_start_xmit;
@@ -2780,6 +3051,12 @@
 
 	return 0;
 
+err_out_free_consistent:
+	pci_free_consistent(pdev,
+			    sizeof(struct gem_init_block),
+			    gp->init_block,
+			    gp->gblock_dvma);
+
 err_out_iounmap:
 	down(&gp->pm_sem);
 	/* Stop the PM timer & task */
@@ -2788,13 +3065,13 @@
 	if (gp->hw_running)
 		gem_shutdown(gp);
 	up(&gp->pm_sem);
+
 	iounmap((void *) gp->regs);
 
-err_out_free_mmio_res:
-	release_mem_region(gemreg_base, gemreg_len);
+err_out_free_res:
+	pci_release_regions(pdev);
 
 err_out_free_netdev:
-	unregister_netdev(dev);
 	kfree(dev);
 
 	return -ENODEV;
@@ -2823,8 +3100,7 @@
 				    gp->init_block,
 				    gp->gblock_dvma);
 		iounmap((void *) gp->regs);
-		release_mem_region(pci_resource_start(pdev, 0),
-				   pci_resource_len(pdev, 0));
+		pci_release_regions(pdev);
 		kfree(dev);
 
 		pci_set_drvdata(pdev, NULL);
diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h
--- a/drivers/net/sungem.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/sungem.h	Wed Apr  3 17:11:13 2002
@@ -94,6 +94,8 @@
 #define GREG_SWRST_TXRST	0x00000001	/* TX Software Reset		*/
 #define GREG_SWRST_RXRST	0x00000002	/* RX Software Reset		*/
 #define GREG_SWRST_RSTOUT	0x00000004	/* Force RST# pin active	*/
+#define GREG_SWRST_CACHESIZE	0x00ff0000	/* RIO only: cache line size	*/
+#define GREG_SWRST_CACHE_SHIFT	16
 
 /* TX DMA Registers */
 #define TXDMA_KICK	0x2000UL	/* TX Kick Register		*/
@@ -985,6 +987,9 @@
 	int			rx_pause_on;
 	int			mii_phy_addr;
 	int			gigabit_capable;
+
+	u32			mac_rx_cfg;
+	u32			swrst_base;
 
 	/* Autoneg & PHY control */
 	int			link_cntl;
diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/sunhme.c	Wed Apr  3 17:11:15 2002
@@ -3,7 +3,7 @@
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
- * Copyright (C) 1996, 1998, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002 David S. Miller (davem@redhat.com)
  *
  * Changes :
  * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -14,7 +14,7 @@
  */
 
 static char version[] =
-        "sunhme.c:v1.99 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+        "sunhme.c:v2.01 26/Mar/2002 David S. Miller (davem@redhat.com)\n";
 
 #include <linux/module.h>
 
@@ -34,6 +34,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/crc32.h>
+#include <linux/random.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -696,7 +697,7 @@
 	return 1;
 }
 
-static int happy_meal_init(struct happy_meal *hp, int from_irq);
+static int happy_meal_init(struct happy_meal *hp);
 
 static int is_lucent_phy(struct happy_meal *hp)
 {
@@ -707,12 +708,8 @@
 	mr2 = happy_meal_tcvr_read(hp, tregs, 2);
 	mr3 = happy_meal_tcvr_read(hp, tregs, 3);
 	if ((mr2 & 0xffff) == 0x0180 &&
-	    ((mr3 & 0xffff) >> 10) == 0x1d) {
-#if 0
-		printk("HMEDEBUG: Lucent PHY detected.\n");
-#endif
+	    ((mr3 & 0xffff) >> 10) == 0x1d)
 		ret = 1;
-	}
 
 	return ret;
 }
@@ -723,6 +720,8 @@
 	unsigned long tregs = hp->tcvregs;
 	int restart_timer = 0;
 
+	spin_lock_irq(&hp->happy_lock);
+
 	hp->timer_ticks++;
 	switch(hp->timer_state) {
 	case arbwait:
@@ -852,13 +851,13 @@
 					printk(KERN_NOTICE "%s: Link down, cable problem?\n",
 					       hp->dev->name);
 
-					ret = happy_meal_init(hp, 0);
+					ret = happy_meal_init(hp);
 					if (ret) {
 						/* ho hum... */
 						printk(KERN_ERR "%s: Error, cannot re-init the "
 						       "Happy Meal.\n", hp->dev->name);
 					}
-					return;
+					goto out;
 				}
 				if (!is_lucent_phy(hp)) {
 					hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
@@ -890,11 +889,15 @@
 		hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
 		add_timer(&hp->happy_timer);
 	}
+
+out:
+	spin_unlock_irq(&hp->happy_lock);
 }
 
 #define TX_RESET_TRIES     32
 #define RX_RESET_TRIES     32
 
+/* hp->happy_lock must be held */
 static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs)
 {
 	int tries = TX_RESET_TRIES;
@@ -914,6 +917,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_rx_reset(struct happy_meal *hp, unsigned long bregs)
 {
 	int tries = RX_RESET_TRIES;
@@ -935,6 +939,7 @@
 
 #define STOP_TRIES         16
 
+/* hp->happy_lock must be held */
 static void happy_meal_stop(struct happy_meal *hp, unsigned long gregs)
 {
 	int tries = STOP_TRIES;
@@ -954,6 +959,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_get_counters(struct happy_meal *hp, unsigned long bregs)
 {
 	struct net_device_stats *stats = &hp->net_stats;
@@ -976,53 +982,7 @@
 	hme_write32(hp, bregs + BMAC_LTCTR, 0);
 }
 
-#if 0
-static void happy_meal_poll_start(struct happy_meal *hp, unsigned long tregs)
-{
-	u32 tmp;
-	int speed;
-
-	ASD(("happy_meal_poll_start: "));
-	if (!(hp->happy_flags & HFLAG_POLLENABLE)) {
-		HMD(("polling disabled, return\n"));
-		return;
-	}
-
-	/* Start the MIF polling on the external transceiver. */
-	ASD(("polling on, "));
-	tmp = hme_read32(hp, tregs + TCVR_CFG);
-	tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
-	tmp |= ((hp->paddr & 0x1f) << 10);
-	tmp |= (TCV_PADDR_ETX << 3);
-	tmp |= TCV_CFG_PENABLE;
-	hme_write32(hp, tregs + TCVR_CFG, tmp);
-
-	/* Let the bits set. */
-	udelay(200);
-
-	/* We are polling now. */
-	ASD(("now polling, "));
-	hp->happy_flags |= HFLAG_POLL;
-
-	/* Clear the poll flags, get the basic status as of now. */
-	hp->poll_flag = 0;
-	hp->poll_data = hme_read32(hp, tregs + TCVR_STATUS) >> 16;
-
-	if (hp->happy_flags & HFLAG_AUTO)
-		speed = hp->auto_speed;
-	else
-		speed = hp->forced_speed;
-
-	/* Listen only for the MIF interrupts we want to hear. */
-	ASD(("mif ints on, "));
-	if (speed == 100)
-		hme_write32(hp, tregs + TCVR_IMASK, 0xfffb);
-	else
-		hme_write32(hp, tregs + TCVR_IMASK, 0xfff9);
-	ASD(("done\n"));
-}
-#endif
-
+/* hp->happy_lock must be held */
 static void happy_meal_poll_stop(struct happy_meal *hp, unsigned long tregs)
 {
 	ASD(("happy_meal_poll_stop: "));
@@ -1057,6 +1017,7 @@
 #define TCVR_RESET_TRIES       16 /* It should reset quickly        */
 #define TCVR_UNISOLATE_TRIES   32 /* Dis-isolation can take longer. */
 
+/* hp->happy_lock must be held */
 static int happy_meal_tcvr_reset(struct happy_meal *hp, unsigned long tregs)
 {
 	u32 tconfig;
@@ -1151,7 +1112,10 @@
 	return 0;
 }
 
-/* Figure out whether we have an internal or external transceiver. */
+/* Figure out whether we have an internal or external transceiver.
+ *
+ * hp->happy_lock must be held
+ */
 static void happy_meal_transceiver_check(struct happy_meal *hp, unsigned long tregs)
 {
 	unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG);
@@ -1303,14 +1267,12 @@
 	}
 }
 
-static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static void happy_meal_init_rings(struct happy_meal *hp)
 {
 	struct hmeal_init_block *hb = hp->happy_block;
 	struct net_device *dev = hp->dev;
-	int i, gfp_flags = GFP_KERNEL;
-
-	if (from_irq || in_interrupt())
-		gfp_flags = GFP_ATOMIC;
+	int i;
 
 	HMD(("happy_meal_init_rings: counters to zero, "));
 	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
@@ -1324,7 +1286,7 @@
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
 
-		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
 		if (!skb) {
 			hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0);
 			continue;
@@ -1347,6 +1309,7 @@
 	HMD(("done\n"));
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
 					      unsigned long tregs,
 					      struct ethtool_cmd *ep)
@@ -1470,7 +1433,8 @@
 	add_timer(&hp->happy_timer);
 }
 
-static int happy_meal_init(struct happy_meal *hp, int from_irq)
+/* hp->happy_lock must be held */
+static int happy_meal_init(struct happy_meal *hp)
 {
 	unsigned long gregs        = hp->gregs;
 	unsigned long etxregs      = hp->etxregs;
@@ -1501,7 +1465,7 @@
 
 	/* Alloc and reset the tx/rx descriptor chains. */
 	HMD(("happy_meal_init: to happy_meal_init_rings\n"));
-	happy_meal_init_rings(hp, from_irq);
+	happy_meal_init_rings(hp);
 
 	/* Shut up the MIF. */
 	HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ",
@@ -1618,6 +1582,17 @@
 	hme_write32(hp, etxregs + ETX_RING,
 		    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)));
 
+	/* Parity issues in the ERX unit of some HME revisions can cause some
+	 * registers to not be written unless their parity is even.  Detect such
+	 * lost writes and simply rewrite with a low bit set (which will be ignored
+	 * since the rxring needs to be 2K aligned).
+	 */
+	if (hme_read32(hp, erxregs + ERX_RING) !=
+	    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)))
+		hme_write32(hp, erxregs + ERX_RING,
+			    ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))
+			    | 0x4);
+
 	/* Set the supported burst sizes. */
 	HMD(("happy_meal_init: old[%08x] bursts<",
 	     hme_read32(hp, gregs + GREG_CFG)));
@@ -1698,7 +1673,7 @@
 	/* Enable Big Mac hash table filter. */
 	HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ",
 	     hme_read32(hp, bregs + BMAC_RXCFG)));
-	rxcfg = BIGMAC_RXCFG_HENABLE;
+	rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME;
 	if (hp->dev->flags & IFF_PROMISC)
 		rxcfg |= BIGMAC_RXCFG_PMISC;
 	hme_write32(hp, bregs + BMAC_RXCFG, rxcfg);
@@ -1711,7 +1686,14 @@
 	regtmp = 0;
 	if (hp->happy_flags & HFLAG_FULL)
 		regtmp |= BIGMAC_TXCFG_FULLDPLX;
-	hme_write32(hp, bregs + BMAC_TXCFG, regtmp | BIGMAC_TXCFG_DGIVEUP);
+
+	/* Don't turn on the "don't give up" bit for now.  It could cause hme
+	 * to deadlock with the PHY if a Jabber occurs.
+	 */
+	hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/);
+
+	/* Give up after 16 TX attempts. */
+	hme_write32(hp, bregs + BMAC_ALIMIT, 16);
 
 	/* Enable the output drivers no matter what. */
 	regtmp = BIGMAC_XCFG_ODENABLE;
@@ -1744,6 +1726,7 @@
 	return 0;
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
 {
 	unsigned long tregs	= hp->tcvregs;
@@ -1801,6 +1784,8 @@
 
 /* Once status is latched (by happy_meal_interrupt) it is cleared by
  * the hardware, so we cannot re-read it and get a correct value.
+ *
+ * hp->happy_lock must be held
  */
 static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
 {
@@ -1909,12 +1894,13 @@
 
 	if (reset) {
 		printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name);
-		happy_meal_init(hp, 1);
+		happy_meal_init(hp);
 		return 1;
 	}
 	return 0;
 }
 
+/* hp->happy_lock must be held */
 static void happy_meal_mif_interrupt(struct happy_meal *hp)
 {
 	unsigned long tregs = hp->tcvregs;
@@ -1948,6 +1934,7 @@
 #define TXD(x)
 #endif
 
+/* hp->happy_lock must be held */
 static void happy_meal_tx(struct happy_meal *hp)
 {
 	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
@@ -1955,8 +1942,6 @@
 	struct net_device *dev = hp->dev;
 	int elem;
 
-	spin_lock(&hp->happy_lock);
-
 	elem = hp->tx_old;
 	TXD(("TX<"));
 	while (elem != hp->tx_new) {
@@ -2000,10 +1985,8 @@
 	TXD((">"));
 
 	if (netif_queue_stopped(dev) &&
-	    TX_BUFFS_AVAIL(hp) > 0)
+	    TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))
 		netif_wake_queue(dev);
-
-	spin_unlock(&hp->happy_lock);
 }
 
 #ifdef RXDEBUG
@@ -2018,6 +2001,8 @@
  * with all of the packets it has DMA'd in.  So now I just drop the entire
  * ring when we cannot get a new skb and give them all back to the happy meal,
  * maybe things will be "happier" now.
+ *
+ * hp->happy_lock must be held
  */
 static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
 {
@@ -2127,10 +2112,12 @@
 
 	HMD(("happy_meal_interrupt: status=%08x ", happy_status));
 
+	spin_lock(&hp->happy_lock);
+
 	if (happy_status & GREG_STAT_ERRORS) {
 		HMD(("ERRORS "));
 		if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status))
-			return;
+			goto out;
 	}
 
 	if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2149,6 +2136,8 @@
 	}
 
 	HMD(("done\n"));
+out:
+	spin_unlock(&hp->happy_lock);
 }
 
 #ifdef CONFIG_SBUS
@@ -2170,10 +2159,12 @@
 				      GREG_STAT_RXTOHOST)))
 			continue;
 
+		spin_lock(&hp->happy_lock);
+
 		if (happy_status & GREG_STAT_ERRORS) {
 			HMD(("ERRORS "));
 			if (happy_meal_is_not_so_happy(hp, happy_status))
-				break;
+				goto next;
 		}
 
 		if (happy_status & GREG_STAT_MIFIRQ) {
@@ -2190,6 +2181,9 @@
 			HMD(("RXTOHOST "));
 			happy_meal_rx(hp, dev);
 		}
+
+	next:
+		spin_unlock(&hp->happy_lock);
 	}
 	HMD(("done\n"));
 }
@@ -2222,7 +2216,11 @@
 	}
 
 	HMD(("to happy_meal_init\n"));
-	res = happy_meal_init(hp, 0);
+
+	spin_lock_irq(&hp->happy_lock);
+	res = happy_meal_init(hp);
+	spin_unlock_irq(&hp->happy_lock);
+
 	if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO))
 		free_irq(dev->irq, dev);
 	return res;
@@ -2232,12 +2230,15 @@
 {
 	struct happy_meal *hp = dev->priv;
 
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_stop(hp, hp->gregs);
 	happy_meal_clean_rings(hp);
 
 	/* If auto-negotiation timer is running, kill it. */
 	del_timer(&hp->happy_timer);
 
+	spin_unlock_irq(&hp->happy_lock);
+
 	/* On Quattro QFE cards, all hme interrupts are concentrated
 	 * into a single source which we register handling at probe
 	 * time and never unregister.
@@ -2254,7 +2255,6 @@
 #define SXD(x)
 #endif
 
-#ifdef CONFIG_SBUS
 static void happy_meal_tx_timeout(struct net_device *dev)
 {
 	struct happy_meal *hp = dev->priv;
@@ -2265,10 +2265,13 @@
 		hme_read32(hp, hp->gregs + GREG_STAT),
 		hme_read32(hp, hp->etxregs + ETX_CFG),
 		hme_read32(hp, hp->bigmacregs + BMAC_TXCFG));
-	happy_meal_init(hp, 0);
+
+	spin_lock_irq(&hp->happy_lock);
+	happy_meal_init(hp);
+	spin_unlock_irq(&hp->happy_lock);
+
 	netif_wake_queue(dev);
 }
-#endif
 
 static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
@@ -2293,6 +2296,8 @@
  	if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) {
 		netif_stop_queue(dev);
 		spin_unlock_irq(&hp->happy_lock);
+		printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
 		return 1;
 	}
 
@@ -2345,7 +2350,7 @@
 
 	hp->tx_new = entry;
 
-	if (TX_BUFFS_AVAIL(hp) <= 0)
+	if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1))
 		netif_stop_queue(dev);
 
 	/* Get it going. */
@@ -2363,7 +2368,10 @@
 {
 	struct happy_meal *hp = dev->priv;
 
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_get_counters(hp, hp->bigmacregs);
+	spin_unlock_irq(&hp->happy_lock);
+
 	return &hp->net_stats;
 }
 
@@ -2376,7 +2384,8 @@
 	int i;
 	u32 crc;
 
-	/* Lock out others. */
+	spin_lock_irq(&hp->happy_lock);
+
 	netif_stop_queue(dev);
 
 	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
@@ -2410,8 +2419,9 @@
 		hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]);
 	}
 
-	/* Let us get going again. */
 	netif_wake_queue(dev);
+
+	spin_unlock_irq(&hp->happy_lock);
 }
 
 /* Ethtool support... */
@@ -2439,8 +2449,11 @@
 		ecmd.phy_address = 0; /* XXX fixed PHYAD */
 
 		/* Record PHY settings. */
+		spin_lock_irq(&hp->happy_lock);
 		hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
 		hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
+		spin_unlock_irq(&hp->happy_lock);
+
 		if (hp->sw_bmcr & BMCR_ANENABLE) {
 			ecmd.autoneg = AUTONEG_ENABLE;
 			ecmd.speed =
@@ -2482,10 +2495,12 @@
 			return -EINVAL;
 
 		/* Ok, do it to it. */
+		spin_lock_irq(&hp->happy_lock);
 		del_timer(&hp->happy_timer);
 		happy_meal_begin_auto_negotiation(hp,
 						  hp->tcvregs,
 						  &ecmd);
+		spin_unlock_irq(&hp->happy_lock);
 
 		return 0;
 	} else
@@ -2657,7 +2672,7 @@
 	}
 
 	err = -ENOMEM;
-	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	dev = alloc_etherdev(sizeof(struct happy_meal));
 	if (!dev)
 		goto err_out;
 	SET_MODULE_OWNER(dev);
@@ -2665,13 +2680,6 @@
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	if (qfe_slot != -1)
-		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
-		       dev->name, qfe_slot);
-	else
-		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
-		       dev->name);
-
 	/* If user did not specify a MAC address specifically, use
 	 * the Quattro local-mac-address property...
 	 */
@@ -2682,6 +2690,7 @@
 	if (i < 6) { /* a mac address was given */
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = macaddr[i];
+		macaddr[5]++;
 	} else if (qfe_slot != -1 &&
 		   prom_getproplen(sdev->prom_node,
 				   "local-mac-address") == 6) {
@@ -2691,11 +2700,6 @@
 		memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 	}
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",
-		       dev->dev_addr[i], i == 5 ? ' ' : ':');
-	printk("\n");
-
 	hp = dev->priv;
 	memset(hp, 0, sizeof(*hp));
 
@@ -2818,19 +2822,42 @@
 	/* Grrr, Happy Meal comes up by default not advertising
 	 * full duplex 100baseT capabilities, fix this.
 	 */
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_set_initial_advertisement(hp);
+	spin_unlock_irq(&hp->happy_lock);
 
-	ether_setup(dev);
+	if (register_netdev(hp->dev)) {
+		printk(KERN_ERR "happymeal: Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_free_consistent;
+	}
+
+	if (qfe_slot != -1)
+		printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
+		       dev->name, qfe_slot);
+	else
+		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
+		       dev->name);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c",
+		       dev->dev_addr[i], i == 5 ? ' ' : ':');
+	printk("\n");
 
 	/* We are home free at this point, link us in to the happy
 	 * device list.
 	 */
-	dev->ifindex = dev_new_index();
 	hp->next_module = root_happy_dev;
 	root_happy_dev = hp;
 
 	return 0;
 
+err_out_free_consistent:
+	sbus_free_consistent(hp->happy_dev,
+			     PAGE_SIZE,
+			     hp->happy_block,
+			     hp->hblock_dvma);
+
 err_out_iounmap:
 	if (hp->gregs)
 		sbus_iounmap(hp->gregs, GREG_REG_SIZE);
@@ -2844,7 +2871,6 @@
 		sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
 
 err_out_free_netdev:
-	unregister_netdev(dev);
 	kfree(dev);
 
 err_out:
@@ -2853,6 +2879,104 @@
 #endif
 
 #ifdef CONFIG_PCI
+#ifndef __sparc__
+static int is_quattro_p(struct pci_dev *pdev)
+{
+	struct pci_dev *busdev = pdev->bus->self;
+	struct list_head *tmp;
+	int n_hmes;
+
+	if (busdev->vendor != PCI_VENDOR_ID_DEC ||
+	    busdev->device != PCI_DEVICE_ID_DEC_21153)
+		return 0;
+
+	n_hmes = 0;
+	tmp = pdev->bus->devices.next;
+	while (tmp != &pdev->bus->devices) {
+		struct pci_dev *this_pdev = pci_dev_b(tmp);
+
+		if (this_pdev->vendor == PCI_VENDOR_ID_SUN &&
+		    this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL)
+			n_hmes++;
+
+		tmp = tmp->next;
+	}
+
+	if (n_hmes != 4)
+		return 0;
+
+	return 1;
+}
+
+/* Fetch MAC address from vital product data of PCI ROM. */
+static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr)
+{
+	int this_offset;
+
+	for (this_offset = 0x20; this_offset < len; this_offset++) {
+		void *p = rom_base + this_offset;
+
+		if (readb(p + 0) != 0x90 ||
+		    readb(p + 1) != 0x00 ||
+		    readb(p + 2) != 0x09 ||
+		    readb(p + 3) != 0x4e ||
+		    readb(p + 4) != 0x41 ||
+		    readb(p + 5) != 0x06)
+			continue;
+
+		this_offset += 6;
+		p += 6;
+
+		if (index == 0) {
+			int i;
+
+			for (i = 0; i < 6; i++)
+				dev_addr[i] = readb(p + i);
+			break;
+		}
+		index--;
+	}
+}
+
+static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
+{
+	u32 rom_reg_orig;
+	void *p;
+	int index;
+
+	index = 0;
+	if (is_quattro_p(pdev))
+		index = PCI_SLOT(pdev->devfn);
+
+	if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
+		if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
+			goto use_random;
+	}
+
+	pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
+	pci_write_config_dword(pdev, pdev->rom_base_reg,
+			       rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
+
+	p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
+	if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
+		find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
+
+	if (p != NULL)
+		iounmap(p);
+
+	pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
+	return;
+
+use_random:
+	/* Sun MAC prefix then 3 random bytes. */
+	dev_addr[0] = 0x08;
+	dev_addr[1] = 0x00;
+	dev_addr[2] = 0x20;
+	get_random_bytes(dev_addr, 3);
+	return;
+}
+#endif /* !(__sparc__) */
+
 static int __init happy_meal_pci_init(struct pci_dev *pdev)
 {
 	struct quattro *qp = NULL;
@@ -2878,8 +3002,10 @@
 	
 	prom_getstring(node, "name", prom_name, sizeof(prom_name));
 #else
-/* This needs to be corrected... -DaveM */
-	strcpy(prom_name, "qfe");
+	if (is_quattro_p(pdev))
+		strcpy(prom_name, "SUNW,qfe");
+	else
+		strcpy(prom_name, "SUNW,hme");
 #endif
 
 	err = -ENODEV;
@@ -2894,7 +3020,7 @@
 			goto err_out;
 	}
 
-	dev = init_etherdev(NULL, sizeof(struct happy_meal));
+	dev = alloc_etherdev(sizeof(struct happy_meal));
 	err = -ENOMEM;
 	if (!dev)
 		goto err_out;
@@ -2903,29 +3029,6 @@
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	if (!qfe_slot) {
-		struct pci_dev *qpdev = qp->quattro_dev;
-
-		prom_name[0] = 0;
-		if (!strncmp(dev->name, "eth", 3)) {
-			int i = simple_strtoul(dev->name + 3, NULL, 10);
-			sprintf(prom_name, "-%d", i + 3);
-		}
-		printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
-		if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
-		    qpdev->device == PCI_DEVICE_ID_DEC_21153)
-			printk("DEC 21153 PCI Bridge\n");
-		else
-			printk("unknown bridge %04x.%04x\n", 
-				qpdev->vendor, qpdev->device);
-	}
-	if (qfe_slot != -1)
-		printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
-		       dev->name, qfe_slot);
-	else
-		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
-		       dev->name);
-
 	dev->base_addr = (long) pdev;
 
 	hp = (struct happy_meal *)dev->priv;
@@ -2947,9 +3050,15 @@
 		printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n");
 		goto err_out_clear_quattro;
 	}
+	if (pci_request_regions(pdev, dev->name)) {
+		printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, "
+		       "aborting.\n");
+		goto err_out_clear_quattro;
+	}
+
 	if ((hpreg_base = (unsigned long) ioremap(hpreg_base, 0x8000)) == 0) {
 		printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n");
-		return -ENODEV;
+		goto err_out_free_res;
 	}
 
 	for (i = 0; i < 6; i++) {
@@ -2959,6 +3068,7 @@
 	if (i < 6) { /* a mac address was given */
 		for (i = 0; i < 6; i++)
 			dev->dev_addr[i] = macaddr[i];
+		macaddr[5]++;
 	} else {
 #ifdef __sparc__
 		if (qfe_slot != -1 &&
@@ -2969,15 +3079,10 @@
 			memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
 		}
 #else
-		memset(dev->dev_addr, 0, 6);
+		get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
 #endif
 	}
 	
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
-	printk("\n");
-
 	/* Layout registers. */
 	hp->gregs      = (hpreg_base + 0x0000UL);
 	hp->etxregs    = (hpreg_base + 0x2000UL);
@@ -3032,6 +3137,8 @@
 	dev->hard_start_xmit = &happy_meal_start_xmit;
 	dev->get_stats = &happy_meal_get_stats;
 	dev->set_multicast_list = &happy_meal_set_multicast;
+	dev->tx_timeout = &happy_meal_tx_timeout;
+	dev->watchdog_timeo = 5*HZ;
 	dev->do_ioctl = &happy_meal_ioctl;
 	dev->irq = pdev->irq;
 	dev->dma = 0;
@@ -3054,14 +3161,48 @@
 	/* Grrr, Happy Meal comes up by default not advertising
 	 * full duplex 100baseT capabilities, fix this.
 	 */
+	spin_lock_irq(&hp->happy_lock);
 	happy_meal_set_initial_advertisement(hp);
+	spin_unlock_irq(&hp->happy_lock);
+
+	if (register_netdev(hp->dev)) {
+		printk(KERN_ERR "happymeal(PCI): Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	if (!qfe_slot) {
+		struct pci_dev *qpdev = qp->quattro_dev;
 
-	ether_setup(dev);
+		prom_name[0] = 0;
+		if (!strncmp(dev->name, "eth", 3)) {
+			int i = simple_strtoul(dev->name + 3, NULL, 10);
+			sprintf(prom_name, "-%d", i + 3);
+		}
+		printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name);
+		if (qpdev->vendor == PCI_VENDOR_ID_DEC &&
+		    qpdev->device == PCI_DEVICE_ID_DEC_21153)
+			printk("DEC 21153 PCI Bridge\n");
+		else
+			printk("unknown bridge %04x.%04x\n", 
+				qpdev->vendor, qpdev->device);
+	}
+
+	if (qfe_slot != -1)
+		printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ",
+		       dev->name, qfe_slot);
+	else
+		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
+		       dev->name);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
+
+	printk("\n");
 
 	/* We are home free at this point, link us in to the happy
 	 * device list.
 	 */
-	dev->ifindex = dev_new_index();
 	hp->next_module = root_happy_dev;
 	root_happy_dev = hp;
 
@@ -3070,11 +3211,13 @@
 err_out_iounmap:
 	iounmap((void *)hp->gregs);
 
+err_out_free_res:
+	pci_release_regions(pdev);
+
 err_out_clear_quattro:
 	if (qp != NULL)
 		qp->happy_meals[qfe_slot] = NULL;
 
-	unregister_netdev(dev);
 	kfree(dev);
 
 err_out:
@@ -3125,6 +3268,7 @@
 				       PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
 		if (pci_enable_device(pdev))
 			continue;
+		pci_set_master(pdev);
 		cards++;
 		happy_meal_pci_init(pdev);
 	}
@@ -3165,12 +3309,18 @@
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
 		struct happy_meal *next = root_happy_dev->next_module;
+		struct net_device *dev = hp->dev;
+
+		/* Unregister netdev before unmapping registers as this
+		 * call can end up trying to access those registers.
+		 */
+		unregister_netdev(dev);
 
 #ifdef CONFIG_SBUS
 		if (!(hp->happy_flags & HFLAG_PCI)) {
 			if (hp->happy_flags & HFLAG_QUATTRO) {
 				if (hp->qfe_parent != last_seen_qfe) {
-					free_irq(hp->dev->irq, hp->qfe_parent);
+					free_irq(dev->irq, hp->qfe_parent);
 					last_seen_qfe = hp->qfe_parent;
 				}
 			}
@@ -3193,12 +3343,35 @@
 					    hp->happy_block,
 					    hp->hblock_dvma);
 			iounmap((void *)hp->gregs);
+			pci_release_regions(hp->happy_dev);
 		}
 #endif
-		unregister_netdev(hp->dev);
-		kfree(hp->dev);
+		kfree(dev);
+
 		root_happy_dev = next;
 	}
+
+	/* Now cleanup the quattro lists. */
+#ifdef CONFIG_SBUS
+	while (qfe_sbus_list) {
+		struct quattro *qfe = qfe_sbus_list;
+		struct quattro *next = qfe->next;
+
+		kfree(qfe);
+
+		qfe_sbus_list = next;
+	}
+#endif
+#ifdef CONFIG_PCI
+	while (qfe_pci_list) {
+		struct quattro *qfe = qfe_pci_list;
+		struct quattro *next = qfe->next;
+
+		kfree(qfe);
+
+		qfe_pci_list = next;
+	}
+#endif
 }
 
 module_init(happy_meal_probe);
diff -Nru a/drivers/net/sunhme.h b/drivers/net/sunhme.h
--- a/drivers/net/sunhme.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/sunhme.h	Wed Apr  3 17:11:15 2002
@@ -227,7 +227,7 @@
 #define BIGMAC_RXCFG_PMISC    0x00000040 /* Enable promiscous mode          */
 #define BIGMAC_RXCFG_DERR     0x00000080 /* Disable error checking          */
 #define BIGMAC_RXCFG_DCRCS    0x00000100 /* Disable CRC stripping           */
-#define BIGMAC_RXCFG_ME       0x00000200 /* Receive packets addressed to me */
+#define BIGMAC_RXCFG_REJME    0x00000200 /* Reject packets addressed to me  */
 #define BIGMAC_RXCFG_PGRP     0x00000400 /* Enable promisc group mode       */
 #define BIGMAC_RXCFG_HENABLE  0x00000800 /* Enable the hash filter          */
 #define BIGMAC_RXCFG_AENABLE  0x00001000 /* Enable the address filter       */
diff -Nru a/drivers/net/tc35815.c b/drivers/net/tc35815.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/tc35815.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,1779 @@
+/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc. 
+ *                ahennessy@mvista.com
+ *
+ * Based on skelton.c by Donald Becker.
+ * Copyright (C) 2000-2001 Toshiba 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  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.
+ */
+
+static const char *version =
+	"tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/byteorder.h>
+
+
+/*
+ * The name of the card. Is used for messages and in the requests for
+ * io regions, irqs and dma channels
+ */
+static const char* cardname = "TC35815CF";
+#define TC35815_PROC_ENTRY "net/tc35815"
+
+#define TC35815_MODULE_NAME "TC35815CF"
+#define TX_TIMEOUT (4*HZ)
+
+/* First, a few definitions that the brave might change. */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef TC35815_DEBUG
+#define TC35815_DEBUG 1
+#endif
+static unsigned int tc35815_debug = TC35815_DEBUG;
+
+#define GATHER_TXINT	/* On-Demand Tx Interrupt */
+
+#define vtonocache(p)	KSEG1ADDR(virt_to_phys(p))
+
+/*
+ * Registers
+ */
+struct tc35815_regs {
+	volatile __u32 DMA_Ctl;		/* 0x00 */
+	volatile __u32 TxFrmPtr;
+	volatile __u32 TxThrsh;
+	volatile __u32 TxPollCtr;
+	volatile __u32 BLFrmPtr;
+	volatile __u32 RxFragSize;
+	volatile __u32 Int_En;
+	volatile __u32 FDA_Bas;
+	volatile __u32 FDA_Lim;		/* 0x20 */
+	volatile __u32 Int_Src;
+	volatile __u32 unused0[2];
+	volatile __u32 PauseCnt;
+	volatile __u32 RemPauCnt;
+	volatile __u32 TxCtlFrmStat;
+	volatile __u32 unused1;
+	volatile __u32 MAC_Ctl;		/* 0x40 */
+	volatile __u32 CAM_Ctl;
+	volatile __u32 Tx_Ctl;
+	volatile __u32 Tx_Stat;
+	volatile __u32 Rx_Ctl;
+	volatile __u32 Rx_Stat;
+	volatile __u32 MD_Data;
+	volatile __u32 MD_CA;
+	volatile __u32 CAM_Adr;		/* 0x60 */
+	volatile __u32 CAM_Data;
+	volatile __u32 CAM_Ena;
+	volatile __u32 PROM_Ctl;
+	volatile __u32 PROM_Data;
+	volatile __u32 Algn_Cnt;
+	volatile __u32 CRC_Cnt;
+	volatile __u32 Miss_Cnt;
+};
+
+/*
+ * Bit assignments
+ */
+/* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_IntMask            0x00040000 /* 1:Interupt mask                 */
+#define DMA_SWIntReq           0x00020000 /* 1:Software Interrupt request    */
+#define DMA_TxWakeUp           0x00010000 /* 1:Transmit Wake Up              */
+#define DMA_RxBigE             0x00008000 /* 1:Receive Big Endian            */
+#define DMA_TxBigE             0x00004000 /* 1:Transmit Big Endian           */
+#define DMA_TestMode           0x00002000 /* 1:Test Mode                     */
+#define DMA_PowrMgmnt          0x00001000 /* 1:Power Management              */
+#define DMA_DmBurst_Mask       0x000001fc /* DMA Burst size                  */
+
+/* RxFragSize bit asign ---------------------------------------------------- */
+#define RxFrag_EnPack          0x00008000 /* 1:Enable Packing                */
+#define RxFrag_MinFragMask     0x00000ffc /* Minimum Fragment                */
+
+/* MAC_Ctl bit asign ------------------------------------------------------- */
+#define MAC_Link10             0x00008000 /* 1:Link Status 10Mbits           */
+#define MAC_EnMissRoll         0x00002000 /* 1:Enable Missed Roll            */
+#define MAC_MissRoll           0x00000400 /* 1:Missed Roll                   */
+#define MAC_Loop10             0x00000080 /* 1:Loop 10 Mbps                  */
+#define MAC_Conn_Auto          0x00000000 /*00:Connection mode (Automatic)   */
+#define MAC_Conn_10M           0x00000020 /*01:                (10Mbps endec)*/
+#define MAC_Conn_Mll           0x00000040 /*10:                (Mll clock)   */
+#define MAC_MacLoop            0x00000010 /* 1:MAC Loopback                  */
+#define MAC_FullDup            0x00000008 /* 1:Full Duplex 0:Half Duplex     */
+#define MAC_Reset              0x00000004 /* 1:Software Reset                */
+#define MAC_HaltImm            0x00000002 /* 1:Halt Immediate                */
+#define MAC_HaltReq            0x00000001 /* 1:Halt request                  */
+
+/* PROM_Ctl bit asign ------------------------------------------------------ */
+#define PROM_Busy              0x00008000 /* 1:Busy (Start Operation)        */
+#define PROM_Read              0x00004000 /*10:Read operation                */
+#define PROM_Write             0x00002000 /*01:Write operation               */
+#define PROM_Erase             0x00006000 /*11:Erase operation               */
+                                          /*00:Enable or Disable Writting,   */
+                                          /*      as specified in PROM_Addr. */
+#define PROM_Addr_Ena          0x00000030 /*11xxxx:PROM Write enable         */
+                                          /*00xxxx:           disable        */
+
+/* CAM_Ctl bit asign ------------------------------------------------------- */
+#define CAM_CompEn             0x00000010 /* 1:CAM Compare Enable            */
+#define CAM_NegCAM             0x00000008 /* 1:Reject packets CAM recognizes,*/
+                                          /*                    accept other */
+#define CAM_BroadAcc           0x00000004 /* 1:Broadcast assept              */
+#define CAM_GroupAcc           0x00000002 /* 1:Multicast assept              */
+#define CAM_StationAcc         0x00000001 /* 1:unicast accept                */
+
+/* CAM_Ena bit asign ------------------------------------------------------- */
+#define CAM_ENTRY_MAX                  21   /* CAM Data entry max count      */
+#define CAM_Ena_Mask ((1<<CAM_ENTRY_MAX)-1) /* CAM Enable bits (Max 21bits)  */
+#define CAM_Ena_Bit(index)         (1<<(index))
+#define CAM_ENTRY_DESTINATION	0
+#define CAM_ENTRY_SOURCE	1
+#define CAM_ENTRY_MACCTL	20
+
+/* Tx_Ctl bit asign -------------------------------------------------------- */
+#define Tx_En                  0x00000001 /* 1:Transmit enable               */
+#define Tx_TxHalt              0x00000002 /* 1:Transmit Halt Request         */
+#define Tx_NoPad               0x00000004 /* 1:Suppress Padding              */
+#define Tx_NoCRC               0x00000008 /* 1:Suppress Padding              */
+#define Tx_FBack               0x00000010 /* 1:Fast Back-off                 */
+#define Tx_EnUnder             0x00000100 /* 1:Enable Underrun               */
+#define Tx_EnExDefer           0x00000200 /* 1:Enable Excessive Deferral     */
+#define Tx_EnLCarr             0x00000400 /* 1:Enable Lost Carrier           */
+#define Tx_EnExColl            0x00000800 /* 1:Enable Excessive Collision    */
+#define Tx_EnLateColl          0x00001000 /* 1:Enable Late Collision         */
+#define Tx_EnTxPar             0x00002000 /* 1:Enable Transmit Parity        */
+#define Tx_EnComp              0x00004000 /* 1:Enable Completion             */
+
+/* Tx_Stat bit asign ------------------------------------------------------- */
+#define Tx_TxColl_MASK         0x0000000F /* Tx Collision Count              */
+#define Tx_ExColl              0x00000010 /* Excessive Collision             */
+#define Tx_TXDefer             0x00000020 /* Transmit Defered                */
+#define Tx_Paused              0x00000040 /* Transmit Paused                 */
+#define Tx_IntTx               0x00000080 /* Interrupt on Tx                 */
+#define Tx_Under               0x00000100 /* Underrun                        */
+#define Tx_Defer               0x00000200 /* Deferral                        */
+#define Tx_NCarr               0x00000400 /* No Carrier                      */
+#define Tx_10Stat              0x00000800 /* 10Mbps Status                   */
+#define Tx_LateColl            0x00001000 /* Late Collision                  */
+#define Tx_TxPar               0x00002000 /* Tx Parity Error                 */
+#define Tx_Comp                0x00004000 /* Completion                      */
+#define Tx_Halted              0x00008000 /* Tx Halted                       */
+#define Tx_SQErr               0x00010000 /* Signal Quality Error(SQE)       */
+
+/* Rx_Ctl bit asign -------------------------------------------------------- */
+#define Rx_EnGood              0x00004000 /* 1:Enable Good                   */
+#define Rx_EnRxPar             0x00002000 /* 1:Enable Receive Parity         */
+#define Rx_EnLongErr           0x00000800 /* 1:Enable Long Error             */
+#define Rx_EnOver              0x00000400 /* 1:Enable OverFlow               */
+#define Rx_EnCRCErr            0x00000200 /* 1:Enable CRC Error              */
+#define Rx_EnAlign             0x00000100 /* 1:Enable Alignment              */
+#define Rx_IgnoreCRC           0x00000040 /* 1:Ignore CRC Value              */
+#define Rx_StripCRC            0x00000010 /* 1:Strip CRC Value               */
+#define Rx_ShortEn             0x00000008 /* 1:Short Enable                  */
+#define Rx_LongEn              0x00000004 /* 1:Long Enable                   */
+#define Rx_RxHalt              0x00000002 /* 1:Receive Halt Request          */
+#define Rx_RxEn                0x00000001 /* 1:Receive Intrrupt Enable       */
+
+/* Rx_Stat bit asign ------------------------------------------------------- */
+#define Rx_Halted              0x00008000 /* Rx Halted                       */
+#define Rx_Good                0x00004000 /* Rx Good                         */
+#define Rx_RxPar               0x00002000 /* Rx Parity Error                 */
+                            /* 0x00001000    not use                         */
+#define Rx_LongErr             0x00000800 /* Rx Long Error                   */
+#define Rx_Over                0x00000400 /* Rx Overflow                     */
+#define Rx_CRCErr              0x00000200 /* Rx CRC Error                    */
+#define Rx_Align               0x00000100 /* Rx Alignment Error              */
+#define Rx_10Stat              0x00000080 /* Rx 10Mbps Status                */
+#define Rx_IntRx               0x00000040 /* Rx Interrupt                    */
+#define Rx_CtlRecd             0x00000020 /* Rx Control Receive              */
+
+#define Rx_Stat_Mask           0x0000EFC0 /* Rx All Status Mask              */
+
+/* Int_En bit asign -------------------------------------------------------- */
+#define Int_NRAbtEn            0x00000800 /* 1:Non-recoverable Abort Enable  */
+#define Int_TxCtlCmpEn         0x00000400 /* 1:Transmit Control Complete Enable */
+#define Int_DmParErrEn         0x00000200 /* 1:DMA Parity Error Enable       */
+#define Int_DParDEn            0x00000100 /* 1:Data Parity Error Enable      */
+#define Int_EarNotEn           0x00000080 /* 1:Early Notify Enable           */
+#define Int_DParErrEn          0x00000040 /* 1:Detected Parity Error Enable  */
+#define Int_SSysErrEn          0x00000020 /* 1:Signalled System Error Enable */
+#define Int_RMasAbtEn          0x00000010 /* 1:Received Master Abort Enable  */
+#define Int_RTargAbtEn         0x00000008 /* 1:Received Target Abort Enable  */
+#define Int_STargAbtEn         0x00000004 /* 1:Signalled Target Abort Enable */
+#define Int_BLExEn             0x00000002 /* 1:Buffer List Exhausted Enable  */
+#define Int_FDAExEn            0x00000001 /* 1:Free Descriptor Area          */
+                                          /*               Exhausted Enable  */
+
+/* Int_Src bit asign ------------------------------------------------------- */
+#define Int_NRabt              0x00004000 /* 1:Non Recoverable error         */
+#define Int_DmParErrStat       0x00002000 /* 1:DMA Parity Error & Clear      */
+#define Int_BLEx               0x00001000 /* 1:Buffer List Empty & Clear     */
+#define Int_FDAEx              0x00000800 /* 1:FDA Empty & Clear             */
+#define Int_IntNRAbt           0x00000400 /* 1:Non Recoverable Abort         */
+#define	Int_IntCmp             0x00000200 /* 1:MAC control packet complete   */
+#define Int_IntExBD            0x00000100 /* 1:Interrupt Extra BD & Clear    */
+#define Int_DmParErr           0x00000080 /* 1:DMA Parity Error & Clear      */
+#define Int_IntEarNot          0x00000040 /* 1:Receive Data write & Clear    */
+#define Int_SWInt              0x00000020 /* 1:Software request & Clear      */
+#define Int_IntBLEx            0x00000010 /* 1:Buffer List Empty & Clear     */
+#define Int_IntFDAEx           0x00000008 /* 1:FDA Empty & Clear             */
+#define Int_IntPCI             0x00000004 /* 1:PCI controller & Clear        */
+#define Int_IntMacRx           0x00000002 /* 1:Rx controller & Clear         */
+#define Int_IntMacTx           0x00000001 /* 1:Tx controller & Clear         */
+
+/* MD_CA bit asign --------------------------------------------------------- */
+#define MD_CA_PreSup           0x00001000 /* 1:Preamble Supress              */
+#define MD_CA_Busy             0x00000800 /* 1:Busy (Start Operation)        */
+#define MD_CA_Wr               0x00000400 /* 1:Write 0:Read                  */
+
+
+/* MII register offsets */
+#define MII_CONTROL             0x0000
+#define MII_STATUS              0x0001
+#define MII_PHY_ID0             0x0002
+#define MII_PHY_ID1             0x0003
+#define MII_ANAR                0x0004
+#define MII_ANLPAR              0x0005
+#define MII_ANER                0x0006
+/* MII Control register bit definitions. */
+#define MIICNTL_FDX             0x0100
+#define MIICNTL_RST_AUTO        0x0200
+#define MIICNTL_ISOLATE         0x0400
+#define MIICNTL_PWRDWN          0x0800
+#define MIICNTL_AUTO            0x1000
+#define MIICNTL_SPEED           0x2000
+#define MIICNTL_LPBK            0x4000
+#define MIICNTL_RESET           0x8000
+/* MII Status register bit significance. */
+#define MIISTAT_EXT             0x0001
+#define MIISTAT_JAB             0x0002
+#define MIISTAT_LINK            0x0004
+#define MIISTAT_CAN_AUTO        0x0008
+#define MIISTAT_FAULT           0x0010
+#define MIISTAT_AUTO_DONE       0x0020
+#define MIISTAT_CAN_T           0x0800
+#define MIISTAT_CAN_T_FDX       0x1000
+#define MIISTAT_CAN_TX          0x2000
+#define MIISTAT_CAN_TX_FDX      0x4000
+#define MIISTAT_CAN_T4          0x8000
+/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
+#define MII_AN_TX_FDX           0x0100
+#define MII_AN_TX_HDX           0x0080
+#define MII_AN_10_FDX           0x0040
+#define MII_AN_10_HDX           0x0020
+
+
+/*
+ * Descriptors
+ */
+
+/* Frame descripter */
+struct FDesc {
+	volatile __u32 FDNext;
+	volatile __u32 FDSystem;
+	volatile __u32 FDStat;
+	volatile __u32 FDCtl;
+};
+
+/* Buffer descripter */
+struct BDesc {
+	volatile __u32 BuffData;
+	volatile __u32 BDCtl;
+};
+
+#define FD_ALIGN	16
+
+/* Frame Descripter bit asign ---------------------------------------------- */
+#define FD_FDLength_MASK       0x0000FFFF /* Length MASK                     */
+#define FD_BDCnt_MASK          0x001F0000 /* BD count MASK in FD             */
+#define FD_FrmOpt_MASK         0x7C000000 /* Frame option MASK               */
+#define FD_FrmOpt_BigEndian    0x40000000 /* Tx/Rx */
+#define FD_FrmOpt_IntTx        0x20000000 /* Tx only */
+#define FD_FrmOpt_NoCRC        0x10000000 /* Tx only */
+#define FD_FrmOpt_NoPadding    0x08000000 /* Tx only */
+#define FD_FrmOpt_Packing      0x04000000 /* Rx only */
+#define FD_CownsFD             0x80000000 /* FD Controller owner bit         */
+#define FD_Next_EOL            0x00000001 /* FD EOL indicator                */
+#define FD_BDCnt_SHIFT         16
+
+/* Buffer Descripter bit asign --------------------------------------------- */
+#define BD_BuffLength_MASK     0x0000FFFF /* Recieve Data Size               */
+#define BD_RxBDID_MASK         0x00FF0000 /* BD ID Number MASK               */
+#define BD_RxBDSeqN_MASK       0x7F000000 /* Rx BD Sequence Number           */
+#define BD_CownsBD             0x80000000 /* BD Controller owner bit         */
+#define BD_RxBDID_SHIFT        16
+#define BD_RxBDSeqN_SHIFT      24
+
+
+/* Some useful constants. */
+#undef NO_CHECK_CARRIER	/* Does not check No-Carrier with TP */
+
+#ifdef NO_CHECK_CARRIER
+#define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+	Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7d01 */
+#else
+#define TX_CTL_CMD	(Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
+	Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+	Tx_En)	/* maybe  0x7f01 */
+#endif
+#define RX_CTL_CMD	(Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
+	| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn)	/* maybe 0x6f01 */
+
+#define INT_EN_CMD  (Int_NRAbtEn | \
+	 Int_DParDEn | Int_DParErrEn | \
+	Int_SSysErrEn  | Int_RMasAbtEn | Int_RTargAbtEn | \
+	Int_STargAbtEn | \
+	Int_BLExEn  | Int_FDAExEn) /* maybe 0xb7f*/
+
+/* Tuning parameters */
+#define DMA_BURST_SIZE	32
+#define TX_THRESHOLD	1024
+
+#define FD_PAGE_NUM 2
+#define FD_PAGE_ORDER 1
+/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
+#define RX_BUF_PAGES	8	/* >= 2 */
+#define RX_FD_NUM	250	/* >= 32 */
+#define TX_FD_NUM	128
+
+struct TxFD {
+	struct FDesc fd;
+	struct BDesc bd;
+	struct BDesc unused;
+};
+
+struct RxFD {
+	struct FDesc fd;
+	struct BDesc bd[0];	/* variable length */
+};
+
+struct FrFD {
+	struct FDesc fd;
+	struct BDesc bd[RX_BUF_PAGES];
+};
+
+
+extern unsigned long tc_readl(volatile __u32 *addr);
+extern void tc_writel(unsigned long data, volatile __u32 *addr);
+
+dma_addr_t priv_dma_handle;
+
+/* Information that need to be kept for each board. */
+struct tc35815_local {
+	struct net_device *next_module;
+
+	/* statistics */
+	struct net_device_stats stats;
+	struct {
+		int max_tx_qlen;
+		int tx_ints;
+		int rx_ints;
+	} lstats;
+
+	int tbusy;
+	int option;
+#define TC35815_OPT_AUTO	0x00
+#define TC35815_OPT_10M	0x01
+#define TC35815_OPT_100M	0x02
+#define TC35815_OPT_FULLDUP	0x04
+	int linkspeed;	/* 10 or 100 */
+	int fullduplex;
+
+	/*
+	 * Transmitting: Batch Mode.
+	 *	1 BD in 1 TxFD.
+	 * Receiving: Packing Mode.
+	 *	1 circular FD for Free Buffer List.
+	 *	RX_BUG_PAGES BD in Free Buffer FD.
+	 *	One Free Buffer BD has PAGE_SIZE data buffer.
+	 */
+        struct pci_dev *pdev;
+	dma_addr_t fd_buf_dma_handle;
+	void * fd_buf;	/* for TxFD, TxFD, FrFD */
+	struct TxFD *tfd_base;
+	int tfd_start;
+	int tfd_end;
+	struct RxFD *rfd_base;
+	struct RxFD *rfd_limit;
+	struct RxFD *rfd_cur;
+	struct FrFD *fbl_ptr;
+	unsigned char fbl_curid;
+	dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
+	void * data_buf[RX_BUF_PAGES];		/* packing */
+};
+
+/* Index to functions, as function prototypes. */
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+
+static int	tc35815_open(struct net_device *dev);
+static int	tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void     tc35815_tx_timeout(struct net_device *dev);
+static void	tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void	tc35815_rx(struct net_device *dev);
+static void	tc35815_txdone(struct net_device *dev);
+static int	tc35815_close(struct net_device *dev);
+static struct	net_device_stats *tc35815_get_stats(struct net_device *dev);
+static void	tc35815_set_multicast_list(struct net_device *dev);
+
+static void 	tc35815_chip_reset(struct net_device *dev);
+static void 	tc35815_chip_init(struct net_device *dev);
+static void 	tc35815_phy_chip_init(struct net_device *dev);
+static int 	tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
+
+/* A list of all installed tc35815 devices. */
+static struct net_device *root_tc35815_dev = NULL;
+
+/*
+ * PCI device identifiers for "new style" Linux PCI Device Drivers
+ */
+static struct pci_device_id tc35815_pci_tbl[] __devinitdata = {
+    { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+    { 0, }
+};
+
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+
+int
+tc35815_probe(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	static int called = 0;
+	int err = 0;
+	int ret;
+
+	if (called)
+		return -ENODEV;
+	called++;
+
+	if (!pci_present())
+		return -ENODEV;
+
+	if (pdev) {
+		unsigned int pci_memaddr;
+		unsigned int pci_irq_line;
+
+		printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+
+	        pci_memaddr = pci_resource_start (pdev, 1);
+
+	        printk(KERN_INFO "    pci_memaddr=%#08lx  resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+
+		if (!pci_memaddr) {
+			printk(KERN_WARNING "no PCI MEM resources, aborting\n");
+			return -ENODEV;
+		}
+		pci_irq_line = pdev->irq;
+		/* irq disabled. */
+		if (pci_irq_line == 0) {
+			printk(KERN_WARNING "no PCI irq, aborting\n");
+			return -ENODEV;
+		}
+
+		ret =  tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
+
+		if (!ret) {
+			if ((err = pci_enable_device(pdev)) < 0) {
+			    printk(KERN_ERR "tc35815_probe: failed to enable device -- err=%d\n", err);
+			    return err;
+			}
+			pci_set_master(pdev);
+		}
+
+		return ret;
+	}
+	return -ENODEV;
+}
+
+static int __init tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
+{
+	static unsigned version_printed = 0;
+	int i;
+	struct tc35815_local *lp;
+	struct tc35815_regs *tr;
+	struct net_device *dev;
+
+	/* Allocate a new 'dev' if needed. */
+	dev = init_etherdev(NULL, 0);
+	if (dev == NULL)
+		return -ENOMEM;
+
+	if (tc35815_debug  &&  version_printed++ == 0)
+		printk(KERN_DEBUG "%s", version);
+
+	printk(KERN_INFO "%s: %s found at %#x, irq %d\n",
+	       dev->name, cardname, base_addr, irq);
+
+	/* Fill in the 'dev' fields. */
+	dev->irq = irq;
+	dev->base_addr = (unsigned long)ioremap(base_addr,
+						sizeof(struct tc35815_regs));
+	tr = (struct tc35815_regs*)dev->base_addr;
+
+	tc35815_chip_reset(dev);
+
+	/* Retrieve and print the ethernet address. */
+	while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+		;
+	for (i = 0; i < 6; i += 2) {
+		unsigned short data;
+		tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+		while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+			;
+		data = tc_readl(&tr->PROM_Data);
+		dev->dev_addr[i] = data & 0xff;
+		dev->dev_addr[i+1] = data >> 8;
+	}
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i]);
+	printk("\n");
+
+	/* Initialize the device structure. */
+	if (dev->priv == NULL) {
+		dev->priv = kmalloc(sizeof(struct tc35815_local), GFP_KERNEL);
+		if (dev->priv == NULL)
+			return -ENODEV;
+	}
+	lp = dev->priv;
+
+	lp->pdev = pdev;
+
+	memset(lp, 0, sizeof(struct tc35815_local));
+
+	lp->next_module = root_tc35815_dev;
+	root_tc35815_dev = dev;
+
+	if (dev->mem_start > 0) {
+		lp->option = dev->mem_start;
+		if ((lp->option & TC35815_OPT_10M) &&
+		    (lp->option & TC35815_OPT_100M)) {
+			/* if both speed speficied, auto select. */
+			lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
+		}
+	}
+	//XXX fixme
+        lp->option |= TC35815_OPT_10M;
+
+	/* do auto negotiation */
+	tc35815_phy_chip_init(dev);
+	printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
+	       dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+
+	dev->open		= tc35815_open;
+	dev->stop		= tc35815_close;
+	dev->tx_timeout         = tc35815_tx_timeout;
+	dev->watchdog_timeo     = TX_TIMEOUT;
+	dev->hard_start_xmit	= tc35815_send_packet;
+	dev->get_stats		= tc35815_get_stats;
+	dev->set_multicast_list = tc35815_set_multicast_list;
+
+#if 0	/* XXX called in init_etherdev */
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+#endif
+
+	return 0;
+}
+
+
+static int
+tc35815_init_queues(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	int i;
+	unsigned long fd_addr;
+
+	if (!lp->fd_buf) {
+		if (sizeof(struct FDesc) +
+		    sizeof(struct BDesc) * RX_BUF_PAGES +
+		    sizeof(struct FDesc) * RX_FD_NUM +
+		    sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
+			printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
+			return -ENOMEM;
+		}
+
+		if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+			return -ENOMEM;
+		for (i = 0; i < RX_BUF_PAGES; i++) {
+			if ((lp->data_buf[i] = (void *)get_free_page(GFP_KERNEL)) == 0) {
+				while (--i >= 0) {
+					free_page((unsigned long)lp->data_buf[i]);
+					lp->data_buf[i] = 0;
+				}
+				free_page((unsigned long)lp->fd_buf);
+				lp->fd_buf = 0;
+				return -ENOMEM;
+			}
+#ifdef __mips__
+			dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
+#endif
+		}
+#ifdef __mips__
+		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+	} else {
+		clear_page(lp->fd_buf);
+#ifdef __mips__
+		dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+#endif
+	}
+#ifdef __mips__
+	fd_addr = (unsigned long)vtonocache(lp->fd_buf);  
+#else
+	fd_addr = (unsigned long)lp->fd_buf;
+#endif
+
+	/* Free Descriptors (for Receive) */
+	lp->rfd_base = (struct RxFD *)fd_addr;
+	fd_addr += sizeof(struct RxFD) * RX_FD_NUM;
+	for (i = 0; i < RX_FD_NUM; i++) {
+		lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
+	}
+	lp->rfd_cur = lp->rfd_base;
+	lp->rfd_limit = (struct RxFD *)(fd_addr -
+					sizeof(struct FDesc) -
+					sizeof(struct BDesc) * 30);
+
+	/* Transmit Descriptors */
+	lp->tfd_base = (struct TxFD *)fd_addr;
+	fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
+	for (i = 0; i < TX_FD_NUM; i++) {
+		lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
+	}
+	lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+	lp->tfd_start = 0;
+	lp->tfd_end = 0;
+
+	/* Buffer List (for Receive) */
+	lp->fbl_ptr = (struct FrFD *)fd_addr;
+	lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
+	lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
+	for (i = 0; i < RX_BUF_PAGES; i++) {
+		lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+		/* BDID is index of FrFD.bd[] */
+		lp->fbl_ptr->bd[i].BDCtl =
+			cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+	}
+	lp->fbl_curid = 0;
+
+	return 0;
+}
+
+static void
+tc35815_clear_queues(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	int i;
+
+	for (i = 0; i < TX_FD_NUM; i++) {
+		struct sk_buff *skb = (struct sk_buff *)
+			le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+		if (skb)
+			dev_kfree_skb_any(skb);
+		lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+	}
+
+	tc35815_init_queues(dev);
+}
+
+static void
+tc35815_free_queues(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	int i;
+
+	if (lp->tfd_base) {
+		for (i = 0; i < TX_FD_NUM; i++) {
+			struct sk_buff *skb = (struct sk_buff *)
+				le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+			if (skb)
+				dev_kfree_skb_any(skb);
+			lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+		}
+	}
+
+	lp->rfd_base = NULL;
+	lp->rfd_base = NULL;
+	lp->rfd_limit = NULL;
+	lp->rfd_cur = NULL;
+	lp->fbl_ptr = NULL;
+
+	for (i = 0; i < RX_BUF_PAGES; i++) {
+		if (lp->data_buf[i])
+			free_page((unsigned long)lp->data_buf[i]);
+		lp->data_buf[i] = 0;
+	}
+	if (lp->fd_buf)
+		__free_pages(lp->fd_buf, FD_PAGE_ORDER);
+	lp->fd_buf = NULL;
+}
+
+static void
+dump_txfd(struct TxFD *fd)
+{
+	printk("TxFD(%p): %08x %08x %08x %08x\n", fd,
+	       le32_to_cpu(fd->fd.FDNext),
+	       le32_to_cpu(fd->fd.FDSystem),
+	       le32_to_cpu(fd->fd.FDStat),
+	       le32_to_cpu(fd->fd.FDCtl));
+	printk("BD: ");
+	printk(" %08x %08x",
+	       le32_to_cpu(fd->bd.BuffData),
+	       le32_to_cpu(fd->bd.BDCtl));
+	printk("\n");
+}
+
+static int
+dump_rxfd(struct RxFD *fd)
+{
+	int i, bd_count = (le32_to_cpu(fd->fd.FDCtl) & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+	if (bd_count > 8)
+		bd_count = 8;
+	printk("RxFD(%p): %08x %08x %08x %08x\n", fd,
+	       le32_to_cpu(fd->fd.FDNext),
+	       le32_to_cpu(fd->fd.FDSystem),
+	       le32_to_cpu(fd->fd.FDStat),
+	       le32_to_cpu(fd->fd.FDCtl));
+	if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD)
+	    return 0;
+	printk("BD: ");
+	for (i = 0; i < bd_count; i++)
+		printk(" %08x %08x",
+		       le32_to_cpu(fd->bd[i].BuffData),
+		       le32_to_cpu(fd->bd[i].BDCtl));
+	printk("\n");
+	return bd_count;
+}
+
+static void
+dump_frfd(struct FrFD *fd)
+{
+	int i;
+	printk("FrFD(%p): %08x %08x %08x %08x\n", fd,
+	       le32_to_cpu(fd->fd.FDNext),
+	       le32_to_cpu(fd->fd.FDSystem),
+	       le32_to_cpu(fd->fd.FDStat),
+	       le32_to_cpu(fd->fd.FDCtl));
+	printk("BD: ");
+	for (i = 0; i < RX_BUF_PAGES; i++)
+		printk(" %08x %08x",
+		       le32_to_cpu(fd->bd[i].BuffData),
+		       le32_to_cpu(fd->bd[i].BDCtl));
+	printk("\n");
+}
+
+static void
+panic_queues(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	int i;
+
+	printk("TxFD base %p, start %d, end %d\n",
+	       lp->tfd_base, lp->tfd_start, lp->tfd_end);
+	printk("RxFD base %p limit %p cur %p\n",
+	       lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
+	printk("FrFD %p\n", lp->fbl_ptr);
+	for (i = 0; i < TX_FD_NUM; i++)
+		dump_txfd(&lp->tfd_base[i]);
+	for (i = 0; i < RX_FD_NUM; i++) {
+		int bd_count = dump_rxfd(&lp->rfd_base[i]);
+		i += (bd_count + 1) / 2;	/* skip BDs */
+	}
+	dump_frfd(lp->fbl_ptr);
+	panic("%s: Illegal queue state.", dev->name);
+}
+
+static void print_buf(char *add, int length)
+{
+	int i;
+	int len = length;
+
+	printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
+
+	if (len > 100)
+		len = 100;
+	for (i = 0; i < len; i++) {
+		printk(" %2.2X", (unsigned char) add[i]);
+		if (!(i % 16))
+			printk("\n");
+	}
+	printk("\n");
+}
+
+static void print_eth(char *add)
+{
+	int i;
+
+	printk("print_eth(%08x)\n", (unsigned int) add);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i + 6]);
+	printk(" =>");
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i]);
+	printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
+}
+
+/*
+ * Open/initialize the board. This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+tc35815_open(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	/*
+	 * This is used if the interrupt line can turned off (shared).
+	 * See 3c503.c for an example of selecting the IRQ at config-time.
+	 */
+
+	if (dev->irq == 0  ||
+	    request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) {
+		return -EAGAIN;
+	}
+
+	tc35815_chip_reset(dev);
+
+	if (tc35815_init_queues(dev) != 0) {
+		free_irq(dev->irq, dev);
+		return -EAGAIN;
+	}
+
+	/* Reset the hardware here. Don't forget to set the station address. */
+	tc35815_chip_init(dev);
+
+	lp->tbusy = 0;
+	netif_start_queue(dev);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+	int flags;
+
+	save_and_cli(flags);
+	printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+	       dev->name, tc_readl(&tr->Tx_Stat));
+	/* Try to restart the adaptor. */
+	tc35815_chip_reset(dev);
+	tc35815_clear_queues(dev);
+	tc35815_chip_init(dev);
+	lp->tbusy=0;
+	restore_flags(flags);
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
+
+	if (netif_queue_stopped(dev)) {
+		/*
+		 * If we get here, some higher level has decided we are broken.
+		 * There should really be a "kick me" function call instead.
+		 */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5)
+			return 1;
+		printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+		       dev->name, tc_readl(&tr->Tx_Stat));
+		/* Try to restart the adaptor. */
+		tc35815_chip_reset(dev);
+		tc35815_clear_queues(dev);
+		tc35815_chip_init(dev);
+		lp->tbusy=0;
+		dev->trans_start = jiffies;
+		netif_wake_queue(dev);
+	}
+
+	/*
+	 * Block a timer-based transmit from overlapping. This could better be
+	 * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+	 */
+	if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
+		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+		dev_kfree_skb_any(skb);
+	} else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = skb->data;
+		struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
+		int flags;
+		lp->stats.tx_bytes += skb->len;
+
+
+#ifdef __mips__
+		dma_cache_wback_inv((unsigned long)buf, length);
+#endif
+
+		save_and_cli(flags);
+
+		/* failsafe... */
+		if (lp->tfd_start != lp->tfd_end)
+			tc35815_txdone(dev);
+
+
+		txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
+
+		txfd->bd.BDCtl = cpu_to_le32(length);
+		txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
+		txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+		if (lp->tfd_start == lp->tfd_end) {
+			/* Start DMA Transmitter. */
+			txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+			txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+			if (tc35815_debug > 2) {
+				printk("%s: starting TxFD.\n", dev->name);
+				dump_txfd(txfd);
+				if (tc35815_debug > 3)
+					print_eth(buf);
+			}
+			tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+		} else {
+			txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+			if (tc35815_debug > 2) {
+				printk("%s: queueing TxFD.\n", dev->name);
+				dump_txfd(txfd);
+				if (tc35815_debug > 3)
+					print_eth(buf);
+			}
+		}
+		lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+
+		dev->trans_start = jiffies;
+
+		if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
+			/* we can send another packet */
+			lp->tbusy = 0;
+			netif_start_queue(dev);
+		} else {
+			netif_stop_queue(dev);
+			if (tc35815_debug > 1)
+				printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+		}
+		restore_flags(flags);
+	}
+
+	return 0;
+}
+
+#define FATAL_ERROR_INT \
+	(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+{
+	static int count;
+	printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
+	       dev->name, status);
+
+	if (status & Int_IntPCI)
+		printk(" IntPCI");
+	if (status & Int_DmParErr)
+		printk(" DmParErr");
+	if (status & Int_IntNRAbt)
+		printk(" IntNRAbt");
+	printk("\n");
+	if (count++ > 100)
+		panic("%s: Too many fatal errors.", dev->name);
+	printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+	/* Try to restart the adaptor. */
+	tc35815_chip_reset(dev);
+	tc35815_clear_queues(dev);
+	tc35815_chip_init(dev);
+}
+
+/*
+ * The typical workload of the driver:
+ *   Handle the network interface interrupts.
+ */
+static void tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct net_device *dev = dev_id;
+	struct tc35815_regs *tr;
+	struct tc35815_local *lp;
+	int status, boguscount = 0;
+
+	if (dev == NULL) {
+		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
+		return;
+	}
+
+	tr = (struct tc35815_regs*)dev->base_addr;
+	lp = (struct tc35815_local *)dev->priv;
+
+	do {
+		status = tc_readl(&tr->Int_Src);
+		if (status == 0)
+			break;
+		tc_writel(status, &tr->Int_Src);	/* write to clear */
+
+		/* Fatal errors... */
+		if (status & FATAL_ERROR_INT) {
+			tc35815_fatal_error_interrupt(dev, status);
+			break;
+		}
+		/* recoverable errors */
+		if (status & Int_IntFDAEx) {
+			/* disable FDAEx int. (until we make rooms...) */
+			tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+			printk(KERN_WARNING
+			       "%s: Free Descriptor Area Exhausted (%#x).\n",
+			       dev->name, status);
+			lp->stats.rx_dropped++;
+		}
+		if (status & Int_IntBLEx) {
+			/* disable BLEx int. (until we make rooms...) */
+			tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+			printk(KERN_WARNING
+			       "%s: Buffer List Exhausted (%#x).\n",
+			       dev->name, status);
+			lp->stats.rx_dropped++;
+		}
+		if (status & Int_IntExBD) {
+			printk(KERN_WARNING
+			       "%s: Excessive Buffer Descriptiors (%#x).\n",
+			       dev->name, status);
+			lp->stats.rx_length_errors++;
+		}
+		/* normal notification */
+		if (status & Int_IntMacRx) {
+			/* Got a packet(s). */
+			lp->lstats.rx_ints++;
+			tc35815_rx(dev);
+		}
+		if (status & Int_IntMacTx) {
+			lp->lstats.tx_ints++;
+			tc35815_txdone(dev);
+		}
+	} while (++boguscount < 20) ;
+
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+tc35815_rx(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	unsigned int fdctl;
+	int i;
+	int buf_free_count = 0;
+	int fd_free_count = 0;
+
+	while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
+		int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
+		int pkt_len = fdctl & FD_FDLength_MASK;
+		struct RxFD *next_rfd;
+		int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+
+		if (tc35815_debug > 2)
+			dump_rxfd(lp->rfd_cur);
+		if (status & Rx_Good) {
+			/* Malloc up new buffer. */
+			struct sk_buff *skb;
+			unsigned char *data;
+			int cur_bd, offset;
+
+			lp->stats.rx_bytes += pkt_len;
+			
+			skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
+			if (skb == NULL) {
+				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+				       dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb_reserve(skb, 2);   /* 16 bit alignment */
+			skb->dev = dev;
+
+			data = skb_put(skb, pkt_len);
+
+			/* copy from receive buffer */
+			cur_bd = 0;
+			offset = 0;
+			while (offset < pkt_len && cur_bd < bd_count) {
+				int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
+					BD_BuffLength_MASK;
+				void *rxbuf =
+					bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
+#ifdef __mips__
+				dma_cache_inv((unsigned long)rxbuf, len);
+#endif
+				memcpy(data + offset, rxbuf, len);
+				offset += len;
+				cur_bd++;
+			}
+	//		print_buf(data,pkt_len);
+			if (tc35815_debug > 3)
+				print_eth(data);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		} else {
+			lp->stats.rx_errors++;
+			/* WORKAROUND: LongErr and CRCErr means Overflow. */
+			if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
+				status &= ~(Rx_LongErr|Rx_CRCErr);
+				status |= Rx_Over;
+			}
+			if (status & Rx_LongErr) lp->stats.rx_length_errors++;
+			if (status & Rx_Over) lp->stats.rx_fifo_errors++;
+			if (status & Rx_CRCErr) lp->stats.rx_crc_errors++;
+			if (status & Rx_Align) lp->stats.rx_frame_errors++;
+		}
+
+		if (bd_count > 0) {
+			/* put Free Buffer back to controller */
+			int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
+			unsigned char id =
+				(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+			if (id >= RX_BUF_PAGES) {
+				printk("%s: invalid BDID.\n", dev->name);
+				panic_queues(dev);
+			}
+			/* free old buffers */
+			while (lp->fbl_curid != id) {
+				bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+				if (bdctl & BD_CownsBD) {
+					printk("%s: Freeing invalid BD.\n",
+					       dev->name);
+					panic_queues(dev);
+				}
+				/* pass BD to controler */
+				/* Note: BDLength was modified by chip. */
+				lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
+					cpu_to_le32(BD_CownsBD |
+						    (lp->fbl_curid << BD_RxBDID_SHIFT) |
+						    PAGE_SIZE);
+				lp->fbl_curid =
+					(lp->fbl_curid + 1) % RX_BUF_PAGES;
+				if (tc35815_debug > 2) {
+					printk("%s: Entering new FBD %d\n",
+					       dev->name, lp->fbl_curid);
+					dump_frfd(lp->fbl_ptr);
+				}
+				buf_free_count++;
+			}
+		}
+
+		/* put RxFD back to controller */
+		next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
+#ifdef __mips__
+		next_rfd = (struct RxFD *)vtonocache(next_rfd);
+#endif
+		if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
+			printk("%s: RxFD FDNext invalid.\n", dev->name);
+			panic_queues(dev);
+		}
+		for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
+			/* pass FD to controler */
+			lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);	/* for debug */
+			lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
+			lp->rfd_cur++;
+			fd_free_count++;
+		}
+
+		lp->rfd_cur = next_rfd;
+	}
+
+	/* re-enable BL/FDA Exhaust interupts. */
+	if (fd_free_count) {
+		tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+		if (buf_free_count)
+			tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+	}
+}
+
+#ifdef NO_CHECK_CARRIER
+#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#else
+#define TX_STA_ERR	(Tx_ExColl|Tx_Under|Tx_Defer|Tx_NCarr|Tx_LateColl|Tx_TxPar|Tx_SQErr)
+#endif
+
+static void
+tc35815_check_tx_stat(struct net_device *dev, int status)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	const char *msg = NULL;
+
+	/* count collisions */
+	if (status & Tx_ExColl)
+		lp->stats.collisions += 16;
+	if (status & Tx_TxColl_MASK)
+		lp->stats.collisions += status & Tx_TxColl_MASK;
+
+	/* WORKAROUND: ignore LostCrS in full duplex operation */
+	if (lp->fullduplex)
+		status &= ~Tx_NCarr;
+
+	if (!(status & TX_STA_ERR)) {
+		/* no error. */
+		lp->stats.tx_packets++;
+		return;
+	}
+
+	lp->stats.tx_errors++;
+	if (status & Tx_ExColl) {
+		lp->stats.tx_aborted_errors++;
+		msg = "Excessive Collision.";
+	}
+	if (status & Tx_Under) {
+		lp->stats.tx_fifo_errors++;
+		msg = "Tx FIFO Underrun.";
+	}
+	if (status & Tx_Defer) {
+		lp->stats.tx_fifo_errors++;
+		msg = "Excessive Deferral.";
+	}
+#ifndef NO_CHECK_CARRIER
+	if (status & Tx_NCarr) {
+		lp->stats.tx_carrier_errors++;
+		msg = "Lost Carrier Sense.";
+	}
+#endif
+	if (status & Tx_LateColl) {
+		lp->stats.tx_aborted_errors++;
+		msg = "Late Collision.";
+	}
+	if (status & Tx_TxPar) {
+		lp->stats.tx_fifo_errors++;
+		msg = "Transmit Parity Error.";
+	}
+	if (status & Tx_SQErr) {
+		lp->stats.tx_heartbeat_errors++;
+		msg = "Signal Quality Error.";
+	}
+	if (msg)
+		printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
+}
+
+static void
+tc35815_txdone(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	struct TxFD *txfd;
+	unsigned int fdctl;
+	int num_done = 0;
+
+	txfd = &lp->tfd_base[lp->tfd_end];
+	while (lp->tfd_start != lp->tfd_end &&
+	       !((fdctl = le32_to_cpu(txfd->fd.FDCtl)) & FD_CownsFD)) {
+		int status = le32_to_cpu(txfd->fd.FDStat);
+		struct sk_buff *skb;
+		unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+
+		if (tc35815_debug > 2) {
+			printk("%s: complete TxFD.\n", dev->name);
+			dump_txfd(txfd);
+		}
+		tc35815_check_tx_stat(dev, status);
+
+		skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+		if (skb) {
+			dev_kfree_skb_any(skb);
+		}
+		txfd->fd.FDSystem = cpu_to_le32(0);
+
+		num_done++;
+		lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
+		txfd = &lp->tfd_base[lp->tfd_end];
+		if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+			printk("%s: TxFD FDNext invalid.\n", dev->name);
+			panic_queues(dev);
+		}
+		if (fdnext & FD_Next_EOL) {
+			/* DMA Transmitter has been stopping... */
+			if (lp->tfd_end != lp->tfd_start) {
+				int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
+				struct TxFD* txhead = &lp->tfd_base[head];
+				int qlen = (lp->tfd_start + TX_FD_NUM
+					    - lp->tfd_end) % TX_FD_NUM;
+
+				if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
+					printk("%s: TxFD FDCtl invalid.\n", dev->name);
+					panic_queues(dev);
+				}
+				/* log max queue length */
+				if (lp->lstats.max_tx_qlen < qlen)
+					lp->lstats.max_tx_qlen = qlen;
+
+
+				/* start DMA Transmitter again */
+				txhead->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+#ifdef GATHER_TXINT
+				txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+#endif
+				if (tc35815_debug > 2) {
+					printk("%s: start TxFD on queue.\n",
+					       dev->name);
+					dump_txfd(txfd);
+				}
+				tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+			}
+			break;
+		}
+	}
+
+	if (num_done > 0 && lp->tbusy) {
+		lp->tbusy = 0;
+		netif_start_queue(dev);
+	}
+}
+
+/* The inverse routine to tc35815_open(). */
+static int
+tc35815_close(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+
+	lp->tbusy = 1;
+	netif_stop_queue(dev);
+
+	/* Flush the Tx and disable Rx here. */
+
+	tc35815_chip_reset(dev);
+	free_irq(dev->irq, dev);
+
+	tc35815_free_queues(dev);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	unsigned long flags;
+
+	if (netif_running(dev)) {
+		save_and_cli(flags);
+		/* Update the statistics from the device registers. */
+		lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
+		restore_flags(flags);
+	}
+
+	return &lp->stats;
+}
+
+static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+{
+	int cam_index = index * 6;
+	unsigned long cam_data;
+	unsigned long saved_addr;
+	saved_addr = tc_readl(&tr->CAM_Adr);
+
+	if (tc35815_debug > 1) {
+		int i;
+		printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+		for (i = 0; i < 6; i++)
+			printk(" %02x", addr[i]);
+		printk("\n");
+	}
+	if (index & 1) {
+		/* read modify write */
+		tc_writel(cam_index - 2, &tr->CAM_Adr);
+		cam_data = tc_readl(&tr->CAM_Data) & 0xffff0000;
+		cam_data |= addr[0] << 8 | addr[1];
+		tc_writel(cam_data, &tr->CAM_Data);
+		/* write whole word */
+		tc_writel(cam_index + 2, &tr->CAM_Adr);
+		cam_data = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
+		tc_writel(cam_data, &tr->CAM_Data);
+	} else {
+		/* write whole word */
+		tc_writel(cam_index, &tr->CAM_Adr);
+		cam_data = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
+		tc_writel(cam_data, &tr->CAM_Data);
+		/* read modify write */
+		tc_writel(cam_index + 4, &tr->CAM_Adr);
+		cam_data = tc_readl(&tr->CAM_Data) & 0x0000ffff;
+		cam_data |= addr[4] << 24 | (addr[5] << 16);
+		tc_writel(cam_data, &tr->CAM_Data);
+	}
+
+	if (tc35815_debug > 2) {
+		int i;
+		for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
+			tc_writel(i * 4, &tr->CAM_Adr);
+			printk("CAM 0x%x: %08x",
+			       i * 4, tc_readl(&tr->CAM_Data));
+		}
+	}
+	tc_writel(saved_addr, &tr->CAM_Adr);
+}
+
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets,
+ *			and do best-effort filtering.
+ */
+static void
+tc35815_set_multicast_list(struct net_device *dev)
+{
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+	if (dev->flags&IFF_PROMISC)
+	{
+		/* Enable promiscuous mode */
+		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
+	}
+	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3)
+	{
+		/* CAM 0, 1, 20 are reserved. */
+		/* Disable promiscuous mode, use normal mode. */
+		tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
+	}
+	else if(dev->mc_count)
+	{
+		struct dev_mc_list* cur_addr = dev->mc_list;
+		int i;
+		int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
+
+		tc_writel(0, &tr->CAM_Ctl);
+		/* Walk the address list, and load the filter */
+		for (i = 0; i < dev->mc_count; i++, cur_addr = cur_addr->next) {
+			if (!cur_addr)
+				break;
+			/* entry 0,1 is reserved. */
+			tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+			ena_bits |= CAM_Ena_Bit(i + 2);
+		}
+		tc_writel(ena_bits, &tr->CAM_Ena);
+		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+	}
+	else {
+		tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+		tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+	}
+}
+
+static unsigned long tc_phy_read(struct tc35815_regs *tr, int phy, int phy_reg)
+{
+	unsigned long data;
+	int flags;
+	save_and_cli(flags);
+	tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+		;
+	data = tc_readl(&tr->MD_Data);
+	restore_flags(flags);
+	return data;
+}
+
+static void tc_phy_write(unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+{
+	int flags;
+	save_and_cli(flags);
+	tc_writel(d, &tr->MD_Data);
+	tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
+	while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+		;
+	restore_flags(flags);
+}
+
+static void tc35815_phy_chip_init(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	static int first = 1;
+	unsigned short ctl;
+
+	if (first) {
+		unsigned short id0, id1;
+		int count;
+		first = 0;
+
+		/* first data written to the PHY will be an ID number */
+		tc_phy_write(0, tr, 0, MII_CONTROL);	/* ID:0 */
+#if 0
+		tc_phy_write(MIICNTL_RESET, tr, 0, MII_CONTROL);
+		printk(KERN_INFO "%s: Resetting PHY...", dev->name);
+		while (tc_phy_read(tr, 0, MII_CONTROL) & MIICNTL_RESET)
+			;
+		printk("\n");
+		tc_phy_write(MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
+			     MII_CONTROL);
+#endif
+		id0 = tc_phy_read(tr, 0, MII_PHY_ID0);
+		id1 = tc_phy_read(tr, 0, MII_PHY_ID1);
+		printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
+		       id0, id1);
+		if (lp->option & TC35815_OPT_10M) {
+			lp->linkspeed = 10;
+			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+		} else if (lp->option & TC35815_OPT_100M) {
+			lp->linkspeed = 100;
+			lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+		} else {
+			/* auto negotiation */
+			unsigned long neg_result;
+			tc_phy_write(MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
+			printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
+			count = 0;
+			while (!(tc_phy_read(tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
+				if (count++ > 5000) {
+					printk(" failed. Assume 10Mbps\n");
+					lp->linkspeed = 10;
+					lp->fullduplex = 0;
+					goto done;
+				}
+				if (count % 512 == 0)
+					printk(".");
+				mdelay(1);
+			}
+			printk(" done.\n");
+			neg_result = tc_phy_read(tr, 0, MII_ANLPAR);
+			if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
+				lp->linkspeed = 100;
+			else
+				lp->linkspeed = 10;
+			if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
+				lp->fullduplex = 1;
+			else
+				lp->fullduplex = 0;
+		done:
+			;
+		}
+	}
+
+	ctl = 0;
+	if (lp->linkspeed == 100)
+		ctl |= MIICNTL_SPEED;
+	if (lp->fullduplex)
+		ctl |= MIICNTL_FDX;
+	tc_phy_write(ctl, tr, 0, MII_CONTROL);
+
+	if (lp->fullduplex) {
+		tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+	}
+}
+
+static void tc35815_chip_reset(struct net_device *dev)
+{
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+
+	/* reset the controller */
+	tc_writel(MAC_Reset, &tr->MAC_Ctl);
+	while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
+		;
+
+	tc_writel(0, &tr->MAC_Ctl);
+
+	/* initialize registers to default value */
+	tc_writel(0, &tr->DMA_Ctl);
+	tc_writel(0, &tr->TxThrsh);
+	tc_writel(0, &tr->TxPollCtr);
+	tc_writel(0, &tr->RxFragSize);
+	tc_writel(0, &tr->Int_En);
+	tc_writel(0, &tr->FDA_Bas);
+	tc_writel(0, &tr->FDA_Lim);
+	tc_writel(0xffffffff, &tr->Int_Src);	/* Write 1 to clear */
+	tc_writel(0, &tr->CAM_Ctl);
+	tc_writel(0, &tr->Tx_Ctl);
+	tc_writel(0, &tr->Rx_Ctl);
+	tc_writel(0, &tr->CAM_Ena);
+	(void)tc_readl(&tr->Miss_Cnt);	/* Read to clear */
+
+}
+
+static void tc35815_chip_init(struct net_device *dev)
+{
+	struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+	struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+	int flags;
+	unsigned long txctl = TX_CTL_CMD;
+
+	tc35815_phy_chip_init(dev);
+
+	/* load station address to CAM */
+	tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+
+	/* Enable CAM (broadcast and unicast) */
+	tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
+	tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
+
+	save_and_cli(flags);
+
+	tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+
+	tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize);	/* Packing */
+	tc_writel(0, &tr->TxPollCtr);	/* Batch mode */
+	tc_writel(TX_THRESHOLD, &tr->TxThrsh);
+	tc_writel(INT_EN_CMD, &tr->Int_En);
+
+	/* set queues */
+	tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+	tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
+		  &tr->FDA_Lim);
+	/*
+	 * Activation method:
+	 * First, enable eht MAC Transmitter and the DMA Receive circuits.
+	 * Then enable the DMA Transmitter and the MAC Receive circuits.
+	 */
+	tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr);	/* start DMA receiver */
+	tc_writel(RX_CTL_CMD, &tr->Rx_Ctl);	/* start MAC receiver */
+	/* start MAC transmitter */
+	/* WORKAROUND: ignore LostCrS in full duplex operation */
+	if (lp->fullduplex)
+		txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+#ifdef GATHER_TXINT
+	txctl &= ~Tx_EnComp;	/* disable global tx completion int. */
+#endif
+	tc_writel(txctl, &tr->Tx_Ctl);
+#if 0	/* No need to polling */
+	tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr);	/* start DMA transmitter */
+#endif
+	restore_flags(flags);
+}
+
+static int tc35815_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+{
+	int len = 0;
+	off_t pos = 0;
+	off_t begin = 0;
+	struct net_device *dev;
+
+	len += sprintf(buffer, "TC35815 statistics:\n");
+	for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+		struct tc35815_local *lp = (struct tc35815_local *)dev->priv;
+		len += sprintf(buffer + len,
+			       "%s: tx_ints %d, rx_ints %d, max_tx_qlen %d\n",
+			       dev->name,
+			       lp->lstats.tx_ints,
+			       lp->lstats.rx_ints,
+			       lp->lstats.max_tx_qlen);
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+    
+		if (pos > offset+length) break;
+	}
+
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+  
+	if (len > length) len = length;
+  
+	return len;
+}
+
+/* XXX */
+void
+tc35815_killall(void)
+{
+	struct net_device *dev;
+
+	for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) {
+		if (dev->flags&IFF_UP){
+			dev->stop(dev);
+		}
+	}
+}
+
+static struct pci_driver tc35815_driver = {
+	name:  TC35815_MODULE_NAME,
+	probe: tc35815_probe,
+	remove: NULL,
+	id_table: tc35815_pci_tbl,
+};
+
+static int __init tc35815_init_module(void)
+{
+	int err;
+
+	if ((err = pci_module_init(&tc35815_driver)) < 0 )
+		       return err;      
+	else
+		return 0;
+}
+
+static void __exit tc35815_cleanup_module(void)
+{
+	struct net_device *next_dev;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_tc35815_dev) {
+		struct net_device *dev = root_tc35815_dev;
+		next_dev = ((struct tc35815_local *)dev->priv)->next_module;
+		kfree(dev->priv);
+		iounmap((void *)(dev->base_addr));
+		unregister_netdev(dev);
+		kfree(dev);
+		root_tc35815_dev = next_dev;
+	}
+}
+module_init(tc35815_init_module);
+module_exit(tc35815_cleanup_module);
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/tg3.c	Wed Apr  3 17:11:13 2002
@@ -1509,7 +1509,8 @@
 		if (unlikely(skb == NULL))
 			BUG();
 
-		pci_unmap_single(tp->pdev, ri->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(ri, mapping),
 				 (skb->len - skb->data_len),
 				 PCI_DMA_TODEVICE);
 
@@ -1526,7 +1527,7 @@
 				BUG();
 
 			pci_unmap_page(tp->pdev,
-				       ri->mapping,
+				       pci_unmap_addr(ri, mapping),
 				       skb_shinfo(skb)->frags[i].size,
 				       PCI_DMA_TODEVICE);
 
@@ -1614,7 +1615,7 @@
 				 PCI_DMA_FROMDEVICE);
 
 	map->skb = skb;
-	map->mapping = mapping;
+	pci_unmap_addr_set(map, mapping, mapping);
 
 	if (src_map != NULL)
 		src_map->skb = NULL;
@@ -1666,7 +1667,8 @@
 	};
 
 	dest_map->skb = src_map->skb;
-	dest_map->mapping = src_map->mapping;
+	pci_unmap_addr_set(dest_map, mapping,
+			   pci_unmap_addr(src_map, mapping));
 	dest_desc->addr_hi = src_desc->addr_hi;
 	dest_desc->addr_lo = src_desc->addr_lo;
 
@@ -1723,17 +1725,20 @@
 		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;
+			dma_addr = pci_unmap_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;
+			dma_addr = pci_unmap_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;
+			dma_addr = pci_unmap_addr(&tp->rx_mini_buffers[desc_idx],
+						  mapping);
 			skb = tp->rx_mini_buffers[desc_idx].skb;
 			post_ptr = &tp->rx_mini_ptr;
 		}
@@ -2072,8 +2077,9 @@
 		       NIC_SRAM_TX_BUFFER_DESC);
 		txd += (entry * TXD_SIZE);
 
-		writel(((u64) mapping >> 32),
-		       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
+		if (sizeof(dma_addr_t) != sizeof(u32))
+			writel(((u64) mapping >> 32),
+			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
 
 		writel(((u64) mapping & 0xffffffff),
 		       txd + TXD_ADDR + TG3_64BIT_REG_LOW);
@@ -2111,10 +2117,12 @@
 					frag->page, frag->page_offset,
 					guilty_len, PCI_DMA_TODEVICE);
 	}
-	pci_unmap_single(tp->pdev, tp->tx_buffers[guilty_entry].mapping,
+	pci_unmap_single(tp->pdev, pci_unmap_addr(&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;
+	pci_unmap_addr_set(&tp->tx_buffers[guilty_entry], mapping,
+			   new_addr);
 	*start = last_plus_one;
 #else
 	/* Oh well, no IOMMU, have to allocate a whole new SKB. */
@@ -2148,11 +2156,12 @@
 			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,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(&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;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, new_addr);
 		} else {
 			tp->tx_buffers[entry].skb = NULL;
 		}
@@ -2199,8 +2208,7 @@
 		txd += (entry * TXD_SIZE);
 
 		/* Save some PIOs */
-		if (((u64) tp->tx_buffers[entry].mapping >> 32) !=
-		    ((u64) mapping >> 32))
+		if (sizeof(dma_addr_t) != sizeof(u32))
 			writel(((u64) mapping >> 32),
 			       txd + TXD_ADDR + TG3_64BIT_REG_HIGH);
 
@@ -2257,9 +2265,12 @@
 	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
 	tp->tx_buffers[entry].skb = skb;
-	tp->tx_buffers[entry].mapping = mapping;
+	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
+
+	would_hit_hwbug = 0;
 
-	would_hit_hwbug = tg3_4g_overflow_test(mapping, len);
+	if (tg3_4g_overflow_test(mapping, len))
+		would_hit_hwbug = entry + 1;
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0));
@@ -2281,10 +2292,14 @@
 					       len, PCI_DMA_TODEVICE);
 
 			tp->tx_buffers[entry].skb = NULL;
-			tp->tx_buffers[entry].mapping = mapping;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
-			would_hit_hwbug |=
-				tg3_4g_overflow_test(mapping, len);
+			if (tg3_4g_overflow_test(mapping, len)) {
+				/* Only one should match. */
+				if (would_hit_hwbug)
+					BUG();
+				would_hit_hwbug = entry + 1;
+			}
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last));
@@ -2298,19 +2313,18 @@
 		u32 start;
 		unsigned int len = 0;
 
+		would_hit_hwbug -= 1;
 		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))
+			if (entry == would_hit_hwbug)
 				break;
 
 			i++;
@@ -2390,7 +2404,7 @@
 	mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
 
 	tp->tx_buffers[entry].skb = skb;
-	tp->tx_buffers[entry].mapping = mapping;
+	pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 	tg3_set_txd(tp, entry, mapping, len, base_flags,
 		    (skb_shinfo(skb)->nr_frags == 0));
@@ -2413,7 +2427,7 @@
 					       len, PCI_DMA_TODEVICE);
 
 			tp->tx_buffers[entry].skb = NULL;
-			tp->tx_buffers[entry].mapping = mapping;
+			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
 				    base_flags, (i == last));
@@ -2497,7 +2511,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2509,7 +2524,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2521,7 +2537,8 @@
 
 		if (rxp->skb == NULL)
 			continue;
-		pci_unmap_single(tp->pdev, rxp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(rxp, mapping),
 				 RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rxp->skb);
@@ -2541,7 +2558,8 @@
 			continue;
 		}
 
-		pci_unmap_single(tp->pdev, txp->mapping,
+		pci_unmap_single(tp->pdev,
+				 pci_unmap_addr(txp, mapping),
 				 (skb->len - skb->data_len),
 				 PCI_DMA_TODEVICE);
 		txp->skb = NULL;
@@ -2550,7 +2568,8 @@
 
 		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,
+			pci_unmap_page(tp->pdev,
+				       pci_unmap_addr(txp, mapping),
 				       skb_shinfo(skb)->frags[j].size,
 				       PCI_DMA_TODEVICE);
 			i++;
@@ -4770,6 +4789,7 @@
 		edata.data = netif_carrier_ok(tp->dev) ? 1 : 0;
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
+		return 0;
 	}
 	case ETHTOOL_GCOALESCE: {
 		struct ethtool_coalesce ecoal = { ETHTOOL_GCOALESCE };
@@ -5441,10 +5461,23 @@
 	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;
+	tp->pci_cacheline_sz = (cacheline_sz_reg >>  0) & 0xff;
+	tp->pci_lat_timer    = (cacheline_sz_reg >>  8) & 0xff;
+	tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
+	tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 &&
+	    tp->pci_lat_timer < 64) {
+		tp->pci_lat_timer = 64;
+
+		cacheline_sz_reg  = ((tp->pci_cacheline_sz & 0xff) <<  0);
+		cacheline_sz_reg |= ((tp->pci_lat_timer    & 0xff) <<  8);
+		cacheline_sz_reg |= ((tp->pci_hdr_type     & 0xff) << 16);
+		cacheline_sz_reg |= ((tp->pci_bist         & 0xff) << 24);
+
+		pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ,
+				       cacheline_sz_reg);
+	}
 
 	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
 			      &pci_state_reg);
@@ -5923,6 +5956,10 @@
 	tp->dma_rwctrl |= DMA_RWCTRL_USE_MEM_READ_MULT;
 
 	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
+		return 0;
 
 	ret = 0;
 	while (1) {
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/tg3.h	Wed Apr  3 17:11:14 2002
@@ -1654,7 +1654,7 @@
  */
 struct ring_info {
 	struct sk_buff			*skb;
-	dma_addr_t			mapping;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 struct tg3_config_info {
diff -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
--- a/drivers/net/tokenring/smctr.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/tokenring/smctr.c	Wed Apr  3 17:11:15 2002
@@ -3718,8 +3718,8 @@
         }
 
         tp = (struct net_local *)dev->priv;
-        dev->rmem_start = dev->mem_start = tp->ram_base;
-        dev->rmem_end = dev->mem_end = dev->mem_start + 0x10000;
+        dev->mem_start = tp->ram_base;
+        dev->mem_end = dev->mem_start + 0x10000;
         ram = (__u32 *)phys_to_virt(dev->mem_start);
         tp->ram_access = *(__u32 *)&ram;
 	tp->status = NOT_INITIALIZED;
diff -Nru a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c
--- a/drivers/net/wan/comx-hw-locomx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/wan/comx-hw-locomx.c	Wed Apr  3 17:11:15 2002
@@ -154,11 +154,9 @@
 		return -ENODEV;
 	}
 
-	if (check_region(dev->base_addr, hw->io_extent)) {
+	if (!request_region(dev->base_addr, hw->io_extent, dev->name)) {
 		return -EAGAIN;
 	}
-
-	request_region(dev->base_addr, hw->io_extent, dev->name);
 
 	hw->board.chanA.ctrlio=dev->base_addr + 5;
 	hw->board.chanA.dataio=dev->base_addr + 7;
diff -Nru a/drivers/net/wan/comx-hw-mixcom.c b/drivers/net/wan/comx-hw-mixcom.c
--- a/drivers/net/wan/comx-hw-mixcom.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/net/wan/comx-hw-mixcom.c	Wed Apr  3 17:11:15 2002
@@ -566,8 +566,6 @@
 
 	return 0;
 	
-err_restore_flags:
-	restore_flags(flags);
 err_release_region:
 	release_region(dev->base_addr, MIXCOM_IO_EXTENT);
 err_ret:
diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
--- a/drivers/net/wan/comx-hw-munich.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/wan/comx-hw-munich.c	Wed Apr  3 17:11:14 2002
@@ -1397,15 +1397,6 @@
     return;
 }
 
-void free_stuff(munich_board_t *board, struct comx_channel *ch)
-{
-/* Free CCB and the interrupt queues */
-    if (board->ccb) kfree((void *)board->ccb);
-    if (board->tiq) kfree((void *)board->tiq);
-    if (board->riq) kfree((void *)board->riq);
-    if (board->piq) kfree((void *)board->piq);
-}
-
 /* 
  * Hardware open routine.
  * Called by comx (upper) layer when the user wants to bring up the interface
@@ -1488,7 +1479,6 @@
 	if (board->tiq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->tiq, 0, MUNICH_INTQSIZE);
@@ -1497,7 +1487,6 @@
 	if (board->riq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->riq, 0, MUNICH_INTQSIZE);
@@ -1506,7 +1495,6 @@
 	if (board->piq == NULL)
 	{
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENOMEM;
 	}
 	memset((void *)board->piq, 0, MUNICH_PIQSIZE);
@@ -1527,7 +1515,6 @@
 		   board->pci->irq);
 	    /* TOD: free other resources (a sok malloc feljebb)                     */
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EAGAIN;
 	}
 	board->irq = board->pci->irq;	/* csak akkor legyen != 0, ha tenyleg le van foglalva nekunk */
@@ -1597,7 +1584,6 @@
 	    free_irq(board->irq, (void *)board);	/* TOD: free other resources too *//* maybe shut down hw? */
 	    board->irq = 0;
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EAGAIN;
 	}
 	else if (!(stat & STAT_PCMA))
@@ -1608,7 +1594,6 @@
 	    free_irq(board->irq, (void *)board);	/* TOD: free other resources too *//* maybe shut off the hw? */
 	    board->irq = 0;
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -EIO;
 	}
 
@@ -1670,7 +1655,7 @@
     spin_unlock_irqrestore(&mister_lock, flags);
 
     dev->irq = board->irq;	/* hogy szep legyen az ifconfig outputja */
-    ccb = board->ccb;		/* TOD: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
+    ccb = board->ccb;		/* TODO: ez igy csunya egy kicsit hogy benn is meg kinn is beletoltom :( */
 
     spin_lock_irqsave(&mister_lock, flags);
 
@@ -1680,13 +1665,12 @@
     /* Check if the selected timeslots aren't used already */
 
     for (i = 0; i < 32; i++)
-	if (((1 << i) & timeslots) && ccb->timeslot_spec[i].tti == 0)
+	if (((1 << i) & timeslots) && !ccb->timeslot_spec[i].tti)
 	{
 	    printk("MUNICH_open: %s: timeslot %d already used by %s\n",
 		   dev->name, i, board->twins[ccb->timeslot_spec[i].txchannel]->name);
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
-	    return -EBUSY;	/* TOD: lehet hogy valami mas errno kellene? */
+	    return -EBUSY;	/* TODO: lehet hogy valami mas errno kellene? */
 	}
 
     /* find a free channel: */
@@ -1700,7 +1684,6 @@
 		("MUNICH_open: %s: FATAL: can not find a free channel - this should not happen!\n",
 		 dev->name);
 	    spin_unlock_irqrestore(&mister_lock, flags);
-	    free_stuff(board, ch);
 	    return -ENODEV;
 	}
 	if (board->twins[channel] == NULL)
@@ -1998,7 +1981,7 @@
 
     spin_lock_irqsave(&mister_lock, flags);
 
-    board->use_count--;
+    if (board->use_count) board->use_count--;
 
     if (!board->use_count)	/* we were the last user of the board */
     {
@@ -2020,7 +2003,12 @@
 	    free_irq(board->irq, (void *)board);	/* Ha nem inicializalta magat, akkor meg nincs irq */
 	board->irq = 0;
 
-	free_stuff(board, ch);
+	/* Free CCB and the interrupt queues */
+	if (board->ccb) kfree((void *)board->ccb);
+	if (board->tiq) kfree((void *)board->tiq);
+	if (board->riq) kfree((void *)board->riq);
+	if (board->piq) kfree((void *)board->piq);
+	board->ccb = board->tiq = board->riq = board->piq = NULL;
     }
 
     /* Enable setting of hw parameters */
diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/net/wan/cosa.c	Wed Apr  3 17:11:13 2002
@@ -105,13 +105,6 @@
 #include <net/syncppp.h>
 #include "cosa.h"
 
-/* Linux version stuff */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
-typedef struct wait_queue *wait_queue_head_t;
-#define DECLARE_WAITQUEUE(wait, current) \
-	struct wait_queue wait = { current, NULL }
-#endif
-
 /* Maximum length of the identification string. */
 #define COSA_MAX_ID_STRING	128
 
diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
--- a/drivers/net/wan/dscc4.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/wan/dscc4.c	Wed Apr  3 17:11:14 2002
@@ -515,8 +515,9 @@
 		stats->rx_bytes += pkt_len;
 		skb->tail += pkt_len;
 		skb->len = pkt_len;
-       		if (netif_running(dev))
+       	if (netif_running(dev))
 			skb->protocol = htons(ETH_P_HDLC);
+		skb->dev->last_rx = jiffies;
 		netif_rx(skb);
 		try_get_rx_skb(dpriv, cur, dev);
 	} else {
diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
--- a/drivers/net/wan/hd6457x.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/wan/hd6457x.c	Wed Apr  3 17:11:14 2002
@@ -291,6 +291,7 @@
 #endif
 	port->hdlc.stats.rx_packets++;
 	port->hdlc.stats.rx_bytes += skb->len;
+	skb->dev->last_rx = jiffies;
 	skb->mac.raw = skb->data;
 	skb->dev = hdlc_to_dev(&port->hdlc);
 	skb->protocol = htons(ETH_P_HDLC);
diff -Nru a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
--- a/drivers/net/wan/sdla_ppp.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/wan/sdla_ppp.c	Wed Apr  3 17:11:14 2002
@@ -1463,11 +1463,11 @@
 {
         int cnt = 0;
 
-        tokens[0] = strtok(str, "/");
+        tokens[0] = strsep(&str, "/");
         while (tokens[cnt] && (cnt < 32 - 1))
         {
                 tokens[cnt] = strstrip(tokens[cnt], " \t");
-                tokens[++cnt] = strtok(NULL, "/");
+                tokens[++cnt] = strsep(&str, "/");
         }
 	return cnt;
 }
diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c
--- a/drivers/net/wd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/net/wd.c	Wed Apr  3 17:11:14 2002
@@ -97,7 +97,7 @@
 			return -EBUSY;
 		i = wd_probe1(dev, base_addr);
 		if (i != 0)  
-			release_resource(r);
+			release_region(base_addr, WD_IO_EXTENT);
 		else
 			r->name = dev->name;
 		return i;
@@ -114,7 +114,7 @@
 			r->name = dev->name;
 			return 0;
 		}
-		release_resource(r);
+		release_region(ioaddr, WD_IO_EXTENT);
 	}
 
 	return -ENODEV;
@@ -281,7 +281,7 @@
 	ei_status.rx_start_page = WD_START_PG + TX_PAGES;
 
 	/* Don't map in the shared memory until the board is actually opened. */
-	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
 
 	/* Some cards (eg WD8003EBT) can be jumpered for more (32k!) memory. */
 	if (dev->mem_end != 0) {
@@ -290,7 +290,7 @@
 		ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG;
 		dev->mem_end = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256;
 	}
-	dev->rmem_end = dev->mem_end;
+	ei_status.rmem_end = dev->mem_end;
 
 	printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n",
 		   model_name, dev->irq, dev->mem_start, dev->mem_end-1);
@@ -384,12 +384,12 @@
 	int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
 	unsigned long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8);
 
-	if (xfer_start + count > dev->rmem_end) {
+	if (xfer_start + count > ei_status.rmem_end) {
 		/* We must wrap the input move. */
-		int semi_count = dev->rmem_end - xfer_start;
+		int semi_count = ei_status.rmem_end - xfer_start;
 		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, dev->rmem_start, count);
+		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk -- we can copy + cksum. */
 		isa_eth_io_copy_and_sum(skb, xfer_start, count, 0);
diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
--- a/drivers/net/wireless/orinoco_plx.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/net/wireless/orinoco_plx.c	Wed Apr  3 17:11:16 2002
@@ -267,21 +267,28 @@
 	pci_set_drvdata(pdev, NULL);
 }
 
-
 static struct pci_device_id orinoco_plx_pci_id_table[] __devinitdata = {
-	{0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},
+	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */
+#if 0
+	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga */
+#endif
+	{0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},	/* SMC EZConnect SMC2602W,
+							   Eumitcom PCI WL11000,
+							   Addtron AWA-100*/
+	{0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},	/* Global Sun Tech GL24110P */
+	{0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},	/* Reported working, but unknown */
+	{0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},	/* Linksys WDT11 */
+	{0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},	/* USR 2415 */
+	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, 	/* Belkin F5D6000 */
 	{0,},
 };
-
 MODULE_DEVICE_TABLE(pci, orinoco_plx_pci_id_table);
 
 static struct pci_driver orinoco_plx_driver = {
-	name:"orinoco_plx",
-	id_table:orinoco_plx_pci_id_table,
-	probe:orinoco_plx_init_one,
-	remove:__devexit_p(orinoco_plx_remove_one),
-	suspend:0,
-	resume:0
+	name:		"orinoco_plx",
+	id_table:	orinoco_plx_pci_id_table,
+	probe:		orinoco_plx_init_one,
+	remove:		__devexit_p(orinoco_plx_remove_one),
 };
 
 static int __init orinoco_plx_init(void)
diff -Nru a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
--- a/drivers/parport/parport_mfc3.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/parport/parport_mfc3.c	Wed Apr  3 17:11:15 2002
@@ -408,6 +408,7 @@
 MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
 MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Paralllel Port");
 MODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port");
+MODULE_LICENSE("GPL");
 
 module_init(parport_mfc3_init)
 module_exit(parport_mfc3_exit)
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/pci/pci.c	Wed Apr  3 17:11:14 2002
@@ -893,7 +893,7 @@
 #endif /* !HAVE_ARCH_PCI_MWI */
 
 /**
- * pci_set_mwi - enables memory-write-validate PCI transaction
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
  * @dev: the PCI device for which MWI is enabled
  *
  * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Wed Apr  3 17:11:13 2002
+++ b/drivers/pci/pci.ids	Wed Apr  3 17:11:13 2002
@@ -824,6 +824,7 @@
 	0074  56k Voice Modem
 		1033 8014  RCV56ACF 56k Voice Modem
 	009b  Vrc5476
+	00a6  VRC5477 AC97
 	00e0  USB 2.0
 1034  Framatome Connectors USA Inc.
 1035  Comp. & Comm. Research Lab
@@ -1108,12 +1109,14 @@
 1059  Teknor Industrial Computers Inc
 105a  Promise Technology, Inc.
 	0d30  20265
+	1275  20275
 	4d30  20267
 	4d33  20246
 	4d38  20262
 	4d68  20268
 	6268  20268R
 	4d69  20269
+	5275  20276
 	5300  DC5300
 105b  Foxconn International, Inc.
 105c  Wipro Infotech Limited
@@ -1192,11 +1195,21 @@
 	0017  Paddington Mac I/O
 	0018  UniNorth FireWire
 	0019  KeyLargo USB
-	001e  UniNorth PCI
+	001e  UniNorth Internal PCI
 	001f  UniNorth PCI
 	0020  UniNorth AGP
-	0021  UniNorth GMAC
+	0021  UniNorth GMAC (Sun GEM)
 	0022  KeyLargo Mac I/O
+	0024  UniNorth/Pangea GMAC (Sun GEM)
+	0025  KeyLargo/Pangea Mac I/O
+	0026  KeyLargo/Pangea USB
+	0027  UniNorth/Pangea AGP
+	0028  UniNorth/Pangea PCI
+	0029  UniNorth/Pangea Internal PCI
+	002d  UniNorth 1.5 AGP
+	002e  UniNorth 1.5 PCI
+	002f  UniNorth 1.5 Internal PCI
+	0030  UniNorth/Pangea FireWire
 106c  Hyundai Electronics America
 	8801  Dual Pentium ISA/PCI Motherboard
 	8802  PowerPC ISA/PCI Motherboard
@@ -2620,6 +2633,8 @@
 	0005  ATP850UF
 	0006  ATP860 NO-BIOS
 	0007  ATP860
+	0008  ATP865 NO-ROM
+	0009  ATP865
 	8002  AEC6710 SCSI-2 Host Adapter
 	8010  AEC6712UW SCSI
 	8020  AEC6712U SCSI
@@ -3965,7 +3980,7 @@
 	9511  16PCI954 Function 1
 		15ed 2000  Macrolink MCCR Serial p4-7 of 8
 		15ed 2001  Macrolink MCCR Serial p4-15 of 16
-	9521  Oxford Semi OX16PCI952 PCI/dual 16950 UART
+	9521  16PCI952 PCI/dual 16950 UART
 1416  Multiwave Innovation pte Ltd
 1417  Convergenet Technologies Inc
 1418  Kyushu electronics systems Inc
diff -Nru a/drivers/pcmcia/Config.in b/drivers/pcmcia/Config.in
--- a/drivers/pcmcia/Config.in	Wed Apr  3 17:11:15 2002
+++ b/drivers/pcmcia/Config.in	Wed Apr  3 17:11:15 2002
@@ -24,6 +24,8 @@
       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
    fi
 fi
-dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+if [ "$CONFIG_ARM" = "y" ]; then
+   dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
+fi
 
 endmenu
diff -Nru a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
--- a/drivers/pcmcia/i82092.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/pcmcia/i82092.c	Wed Apr  3 17:11:15 2002
@@ -43,7 +43,7 @@
 	name:           "i82092aa",
 	id_table:       i82092aa_pci_ids,
 	probe:          i82092aa_pci_probe,
-	remove:         i82092aa_pci_remove,
+	remove:         __devexit_p(i82092aa_pci_remove),
 	suspend:        NULL,
 	resume:         NULL 
 };
@@ -168,7 +168,7 @@
 	return ret;			
 }
 
-static void __exit i82092aa_pci_remove(struct pci_dev *dev)
+static void __devexit i82092aa_pci_remove(struct pci_dev *dev)
 {
 	enter("i82092aa_pci_remove");
 	
diff -Nru a/drivers/pnp/pnpbios_core.c b/drivers/pnp/pnpbios_core.c
--- a/drivers/pnp/pnpbios_core.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/pnp/pnpbios_core.c	Wed Apr  3 17:11:13 2002
@@ -4,7 +4,7 @@
  * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
  * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
  * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
- * Modifications (c) 2001 by Thomas Hood <jdthood@mail.com>
+ * Modifications (c) 2001,2002 by Thomas Hood <jdthood@mail.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
@@ -190,8 +190,8 @@
 	/* If we get here and this is set then the PnP BIOS faulted on us. */
 	if(pnp_bios_is_utter_crap)
 	{
-		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
-		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably.\n");
+		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
+		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"nobiospnp\" option to operate stably\n");
 		printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
 	}
 
@@ -205,11 +205,16 @@
  *
  */
 
+static void pnpbios_warn_unexpected_status(const char * module, u16 status)
+{
+	printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status);
+}
+
 void *pnpbios_kmalloc(size_t size, int f)
 {
 	void *p = kmalloc( size, f );
 	if ( p == NULL )
-		printk(KERN_ERR "PnPBIOS: kmalloc() failed.\n");
+		printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
 	return p;
 }
 
@@ -251,7 +256,7 @@
 static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
 	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0);
@@ -263,7 +268,7 @@
 {
 	int status = __pnp_bios_dev_node_info( data );
 	if ( status )
-		printk(KERN_WARNING "PnPBIOS: dev_node_info: Unexpected status 0x%x\n", status);
+		pnpbios_warn_unexpected_status( "dev_node_info", status );
 	return status;
 }
 
@@ -284,7 +289,7 @@
 static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	if ( !boot & pnpbios_dont_use_current_config )
 		return PNP_FUNCTION_NOT_SUPPORTED;
@@ -299,7 +304,7 @@
 	int status;
 	status =  __pnp_bios_get_dev_node( nodenum, boot, data );
 	if ( status )
-		printk(KERN_WARNING "PnPBIOS: get_dev_node: Unexpected 0x%x\n", status);
+		pnpbios_warn_unexpected_status( "get_dev_node", status );
 	return status;
 }
 
@@ -313,7 +318,7 @@
 static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	if ( !boot & pnpbios_dont_use_current_config )
 		return PNP_FUNCTION_NOT_SUPPORTED;
@@ -327,17 +332,14 @@
 	int status;
 	status =  __pnp_bios_set_dev_node( nodenum, boot, data );
 	if ( status ) {
-		printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected set_dev_node status 0x%x\n", status);
+		pnpbios_warn_unexpected_status( "set_dev_node", status );
 		return status;
 	}
-	if ( !boot ) {
-		/* Update devlist */
+	if ( !boot ) { /* Update devlist */
 		u8 thisnodenum = nodenum;
-		status =  __pnp_bios_get_dev_node( &nodenum, boot, data );
-		if ( status ) {
-			printk(KERN_WARNING "PnPBIOS: set_dev_node: Unexpected get_dev_node status 0x%x\n", status);
+		status =  pnp_bios_get_dev_node( &nodenum, boot, data );
+		if ( status )
 			return status;
-		}
 		update_devlist( thisnodenum, data );
 	}
 	return status;
@@ -350,7 +352,7 @@
 static int pnp_bios_get_event(u16 *event)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
 	status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0);
@@ -365,7 +367,7 @@
 static int pnp_bios_send_message(u16 message)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0);
 	return status;
@@ -379,7 +381,7 @@
 static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
 	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -395,7 +397,7 @@
 static int pnp_bios_set_stat_res(char *info)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
 	status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
@@ -403,21 +405,28 @@
 }
 #endif
 
-#if needed
 /*
  * Call PnP BIOS with function 0x0a, "get statically allocated resource
  * information"
  */
-static int pnp_bios_get_stat_res(char *info)
+static int __pnp_bios_get_stat_res(char *info)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
 	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
 	return status;
 }
-#endif
+
+int pnp_bios_get_stat_res(char *info)
+{
+	int status;
+	status = __pnp_bios_get_stat_res( info );
+	if ( status )
+		pnpbios_warn_unexpected_status( "get_stat_res", status );
+	return status;
+}
 
 #if needed
 /*
@@ -426,7 +435,7 @@
 static int pnp_bios_apm_id_table(char *table, u16 *size)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, table, *size);
 	Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
@@ -435,45 +444,58 @@
 }
 #endif
 
-#if needed
 /*
  * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
  */
-static int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
 	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0);
 	return status;
 }
-#endif
 
-#if needed
+int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	int status;
+	status = __pnp_bios_isapnp_config( data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "isapnp_config", status );
+	return status;
+}
+
 /*
  * Call PnP BIOS with function 0x41, "get ESCD info"
  */
-static int pnp_bios_escd_info(struct escd_info_struc *data)
+static int __pnp_bios_escd_info(struct escd_info_struc *data)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return ESCD_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
 	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS);
 	return status;
 }
-#endif
 
-#if needed
+int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	int status;
+	status = __pnp_bios_escd_info( data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "escd_info", status );
+	return status;
+}
+
 /*
  * Call PnP BIOS function 0x42, "read ESCD"
  * nvram_base is determined by calling escd_info
  */
-static int pnp_bios_read_escd(char *data, u32 nvram_base)
+static int __pnp_bios_read_escd(char *data, u32 nvram_base)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return ESCD_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
 	set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -481,7 +503,15 @@
 	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0);
 	return status;
 }
-#endif
+
+int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	int status;
+	status = __pnp_bios_read_escd( data, nvram_base );
+	if ( status )
+		pnpbios_warn_unexpected_status( "read_escd", status );
+	return status;
+}
 
 #if needed
 /*
@@ -490,7 +520,7 @@
 static int pnp_bios_write_escd(char *data, u32 nvram_base)
 {
 	u16 status;
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return ESCD_FUNCTION_NOT_SUPPORTED;
 	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
 	set_base(gdt[PNP_TS2 >> 3], nvram_base);
@@ -574,13 +604,13 @@
 static int pnp_dock_thread(void * unused)
 {
 	static struct pnp_docking_station_info now;
-	int docked = -1, d;
+	int docked = -1, d = 0;
 	daemonize();
 	reparent_to_init();
-	strcpy(current->comm, "kpnpbios");
+	strcpy(current->comm, "kpnpbiosd");
 	while(!unloading && !signal_pending(current))
 	{
-		int err;
+		int status;
 		
 		/*
 		 * Poll every 2 seconds
@@ -590,9 +620,9 @@
 		if(signal_pending(current))
 			break;
 
-		err = pnp_bios_dock_station_info(&now);
+		status = pnp_bios_dock_station_info(&now);
 
-		switch(err)
+		switch(status)
 		{
 			/*
 			 * No dock to manage
@@ -606,7 +636,7 @@
 				d = 1;
 				break;
 			default:
-				printk(KERN_WARNING "PnPBIOS: pnp_dock_thread: Unexpected status 0x%x returned by BIOS.\n", err);
+				pnpbios_warn_unexpected_status( "pnp_dock_thread", status );
 				continue;
 		}
 		if(d != docked)
@@ -615,7 +645,7 @@
 			{
 				docked = d;
 #if 0
-				printk(KERN_INFO "PnPBIOS: Docking station %stached.\n", docked?"at":"de");
+				printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
 #endif
 			}
 		}
@@ -848,15 +878,14 @@
  */
 static void __init build_devlist(void)
 {
-	int i;
-	int nodenum;
-	int nodes_got = 0;
-	int devs = 0;
+	u8 nodenum;
+	unsigned int nodes_got = 0;
+	unsigned int devs = 0;
 	struct pnp_bios_node *node;
 	struct pnp_dev_node_info node_info;
 	struct pci_dev *dev;
 	
-	if (!pnp_bios_present ())
+	if (!pnp_bios_present())
 		return;
 
 	if (pnp_bios_dev_node_info(&node_info) != 0)
@@ -866,26 +895,20 @@
 	if (!node)
 		return;
 
-	for(i=0,nodenum=0; i<0xff && nodenum!=0xff; i++) {
-		int thisnodenum = nodenum;
-		/* For now we build the list from the "boot" config
-		 * because asking for the "current" config causes
-		 * some BIOSes to crash.                          */
-		if (pnp_bios_get_dev_node((u8 *)&nodenum, (char )1 , node)) {
-			printk(KERN_WARNING "PnPBIOS: PnP BIOS reported error on attempt to get dev node.\n");
-			break;
-		}
-		/* The BIOS returns with nodenum = the next node number */
-		if (nodenum < thisnodenum) {
-			printk(KERN_WARNING "PnPBIOS: Node number is out of sequence. Naughty BIOS!\n");
+	for(nodenum=0; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
+		/* We build the list from the "boot" config because
+		 * asking for the "current" config causes some
+		 * BIOSes to crash.
+		 */
+		if (pnp_bios_get_dev_node(&nodenum, (char )1 , node))
 			break;
-		}
 		nodes_got++;
 		dev =  pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
 		if (!dev)
 			break;
 		memset(dev,0,sizeof(struct pci_dev));
-		dev->devfn=thisnodenum;
+		dev->devfn = thisnodenum;
 		memcpy(dev->name,"PNPBIOS",8);
 		pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
 		node_resource_data_to_dev(node,dev);
@@ -893,10 +916,14 @@
 			kfree(dev);
 		else
 			devs++;
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			break;
+		}
 	}
 	kfree(node);
 
-	printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver.\n",
+	printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
 		nodes_got, nodes_got != 1 ? "s" : "", devs);
 }
 
@@ -1062,7 +1089,7 @@
 	regionid = pnpbios_kmalloc(16, GFP_KERNEL);
 	if ( regionid == NULL )
 		return;
-	sprintf(regionid, "PnPBIOS %s", pnpid);
+	snprintf(regionid, 16, "PnPBIOS %s", pnpid);
 	res = request_region(start,end-start+1,regionid);
 	if ( res == NULL )
 		kfree( regionid );
@@ -1074,7 +1101,7 @@
 	 * have double reservations.
 	 */
 	printk(KERN_INFO
-		"PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved.\n",
+		"PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n",
 		pnpid, start, end,
 		NULL != res ? "has been" : "could not be"
 	);
@@ -1193,14 +1220,14 @@
 {
 	union pnp_bios_expansion_header *check;
 	u8 sum;
-	int i, length;
+	int i, length, r;
 
 	spin_lock_init(&pnp_bios_lock);
 	spin_lock_init(&pnpbios_devices_lock);
 
 	if(pnpbios_disabled) {
-		printk(KERN_INFO "PnPBIOS: Disabled.\n");
-		return 0;
+		printk(KERN_INFO "PnPBIOS: Disabled\n");
+		return -ENODEV;
 	}
 
 	if ( is_sony_vaio_laptop )
@@ -1224,13 +1251,13 @@
 		if (sum)
 			continue;
 		if (check->fields.version < 0x10) {
-			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported.\n",
+			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
 			       check->fields.version >> 4,
 			       check->fields.version & 15);
 			continue;
 		}
-		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p.\n", check);
-		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x.\n",
+		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
                        check->fields.version >> 4, check->fields.version & 15,
 		       check->fields.pm16cseg, check->fields.pm16offset,
 		       check->fields.pm16dseg);
@@ -1242,12 +1269,21 @@
 		pnp_bios_hdr = check;
 		break;
 	}
+	if (!pnp_bios_present())
+		return -ENODEV;
 	build_devlist();
 	if ( ! dont_reserve_resources )
 		reserve_resources();
 #ifdef CONFIG_PROC_FS
-	pnpbios_proc_init();
+	r = pnpbios_proc_init();
+	if (r)
+		return r;
 #endif
+	return 0;
+}
+
+static int __init pnpbios_thread_init(void)
+{
 #ifdef CONFIG_HOTPLUG	
 	init_completion(&unload_sem);
 	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
@@ -1256,23 +1292,46 @@
 	return 0;
 }
 
-#ifdef MODULE
+#ifndef MODULE
+
+/* init/main.c calls pnpbios_init early */
+
+/* Start the kernel thread later: */
+module_init(pnpbios_thread_init);
+
+#else
+
+/*
+ * N.B.: Building pnpbios as a module hasn't been fully implemented
+ */
 
 MODULE_LICENSE("GPL");
 
-/* We have to run it early and not as a module. */
-module_init(pnpbios_init);
+static int __init pnpbios_init_all(void)
+{
+	int r;
+
+	r = pnpbios_init();
+	if (r)
+		return r;
+	r = pnpbios_thread_init();
+	if (r)
+		return r;
+	return 0;
+}
 
-#ifdef CONFIG_HOTPLUG
-static void pnpbios_exit(void)
+static void __exit pnpbios_exit(void)
 {
-	/* free_resources() ought to go here */
-	/* pnpbios_proc_done() */
+#ifdef CONFIG_HOTPLUG
 	unloading = 1;
 	wait_for_completion(&unload_sem);
+#endif
+	pnpbios_proc_exit();
+	/* We ought to free resources here */
+	return;
 }
 
+module_init(pnpbios_init_all);
 module_exit(pnpbios_exit);
 
-#endif
 #endif
diff -Nru a/drivers/pnp/pnpbios_proc.c b/drivers/pnp/pnpbios_proc.c
--- a/drivers/pnp/pnpbios_proc.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/pnp/pnpbios_proc.c	Wed Apr  3 17:11:16 2002
@@ -1,7 +1,21 @@
 /*
- * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ * /proc/bus/pnp interface for Plug and Play devices
  *
  * Written by David Hinds, dahinds@users.sourceforge.net
+ * Modified by Thomas Hood, jdthood@mail.com
+ *
+ * The .../devices and .../<node> and .../boot/<node> files are
+ * utilized by the lspnp and setpnp utilities, supplied with the
+ * pcmcia-cs package.
+ *     http://pcmcia-cs.sourceforge.net
+ *
+ * The .../escd file is utilized by the lsescd utility written by
+ * Gunther Mayer.
+ *     http://home.t-online.de/home/gunther.mayer/lsescd
+ *
+ * The .../legacy_device_resources file is not used yet.
+ *
+ * The other files are human-readable.
  */
 
 //#include <pcmcia/config.h>
@@ -19,30 +33,118 @@
 static struct proc_dir_entry *proc_pnp_boot = NULL;
 static struct pnp_dev_node_info node_info;
 
+static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
+                               int count, int *eof, void *data)
+{
+	struct pnp_isa_config_struc pnps;
+
+	if (pnp_bios_isapnp_config(&pnps))
+		return -EIO;
+	return snprintf(buf, count,
+		"structure_revision %d\n"
+		"number_of_CSNs %d\n"
+		"ISA_read_data_port 0x%x\n",
+		pnps.revision,
+		pnps.no_csns,
+		pnps.isa_rd_data_port
+	);
+}
+
+static int proc_read_escdinfo(char *buf, char **start, off_t pos,
+                              int count, int *eof, void *data)
+{
+	struct escd_info_struc escd;
+
+	if (pnp_bios_escd_info(&escd))
+		return -EIO;
+	return snprintf(buf, count,
+		"min_ESCD_write_size %d\n"
+		"ESCD_size %d\n"
+		"NVRAM_base 0x%x\n",
+		escd.min_escd_write_size,
+		escd.escd_size,
+		escd.nv_storage_base
+	);
+}
+
+static int proc_read_escd(char *buf, char **start, off_t pos,
+                          int count, int *eof, void *data)
+{
+	struct escd_info_struc escd;
+	char *tmpbuf;
+	int escd_size, escd_left_to_read, n;
+
+	if (pnp_bios_escd_info(&escd))
+		return -EIO;
+
+	/* sanity check */
+	if (escd.escd_size > (32*1024)) {
+		printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size is too great\n");
+		return -EFBIG;
+	}
+
+	tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+	if (!tmpbuf) return -ENOMEM;
+
+	if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base))
+		return -EIO;
+
+	escd_size = (unsigned char)(buf[0]) + (unsigned char)(buf[1])*256;
+	escd_left_to_read = escd_size - pos;
+	if (escd_left_to_read < 0) escd_left_to_read = 0;
+	if (escd_left_to_read == 0) *eof = 1;
+	n = min(count,escd_left_to_read);
+	memcpy(buf, tmpbuf + pos, n);
+	kfree(tmpbuf);
+	*start = buf;
+	return n;
+}
+
+static int proc_read_legacyres(char *buf, char **start, off_t pos,
+                               int count, int *eof, void *data)
+{
+	/* Assume that the following won't overflow the buffer */
+	if (pnp_bios_get_stat_res(buf)) 
+		return -EIO;
+
+	return count;  // FIXME: Return actual length
+}
+
 static int proc_read_devices(char *buf, char **start, off_t pos,
                              int count, int *eof, void *data)
 {
 	struct pnp_bios_node *node;
-	int i;
 	u8 nodenum;
 	char *p = buf;
 
-	if (pos != 0) {
-	    *eof = 1;
-	    return 0;
-	}
+	if (pos >= 0xff)
+		return 0;
+
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node) return -ENOMEM;
-	for (i=0,nodenum=0;i<0xff && nodenum!=0xff; i++) {
-		if ( pnp_bios_get_dev_node(&nodenum, 1, node) )
+
+	for (nodenum=pos; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
+		/* 26 = the number of characters per line sprintf'ed */
+		if ((p - buf + 26) > count)
+			break;
+		if (pnp_bios_get_dev_node(&nodenum, 1, node))
 			break;
 		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
 			     node->handle, node->eisa_id,
 			     node->type_code[0], node->type_code[1],
 			     node->type_code[2], node->flags);
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			*eof = 1;
+			break;
+		}
 	}
 	kfree(node);
-	return (p-buf);
+	if (nodenum == 0xff)
+		*eof = 1;
+	*start = (char *)((off_t)nodenum - pos);
+	return p - buf;
 }
 
 static int proc_read_node(char *buf, char **start, off_t pos,
@@ -53,13 +155,9 @@
 	u8 nodenum = (long)data;
 	int len;
 
-	if (pos != 0) {
-	    *eof = 1;
-	    return 0;
-	}
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node) return -ENOMEM;
-	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+	if (pnp_bios_get_dev_node(&nodenum, boot, node))
 		return -EIO;
 	len = node->size - sizeof(struct pnp_bios_node);
 	memcpy(buf, node->data, len);
@@ -92,25 +190,34 @@
  * work and the pnpbios_dont_use_current_config flag
  * should already have been set to the appropriate value
  */
-void pnpbios_proc_init( void )
+int __init pnpbios_proc_init( void )
 {
 	struct pnp_bios_node *node;
 	struct proc_dir_entry *ent;
 	char name[3];
-	int i;
 	u8 nodenum;
 
-	if (pnp_bios_dev_node_info(&node_info) != 0) return;
+	if (pnp_bios_dev_node_info(&node_info))
+		return -EIO;
 	
 	proc_pnp = proc_mkdir("pnp", proc_bus);
-	if (!proc_pnp) return;
+	if (!proc_pnp)
+		return -EIO;
 	proc_pnp_boot = proc_mkdir("boot", proc_pnp);
-	if (!proc_pnp_boot) return;
+	if (!proc_pnp_boot)
+		return -EIO;
 	create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
+	create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
+	create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
+	create_proc_read_entry("escd", 0, proc_pnp, proc_read_escd, NULL);
+	create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
 	
 	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
-	if (!node) return;
-	for (i=0,nodenum = 0; i<0xff && nodenum != 0xff; i++) {
+	if (!node)
+		return -ENOMEM;
+
+	for (nodenum=0; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
 		if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
 			break;
 		sprintf(name, "%02x", node->handle);
@@ -128,11 +235,17 @@
 			ent->write_proc = proc_write_node;
 			ent->data = (void *)(long)(node->handle+0x100);
 		}
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			break;
+		}
 	}
 	kfree(node);
+
+	return 0;
 }
 
-void pnpbios_proc_done(void)
+void __exit pnpbios_proc_exit(void)
 {
 	int i;
 	char name[3];
@@ -145,7 +258,13 @@
 			remove_proc_entry(name, proc_pnp);
 		remove_proc_entry(name, proc_pnp_boot);
 	}
-	remove_proc_entry("boot", proc_pnp);
+	remove_proc_entry("legacy_device_resources", proc_pnp);
+	remove_proc_entry("escd", proc_pnp);
+	remove_proc_entry("escd_info", proc_pnp);
+	remove_proc_entry("configuration_info", proc_pnp);
 	remove_proc_entry("devices", proc_pnp);
+	remove_proc_entry("boot", proc_pnp);
 	remove_proc_entry("pnp", proc_bus);
+
+	return;
 }
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/s390/block/dasd.c	Wed Apr  3 17:11:15 2002
@@ -2618,7 +2618,7 @@
 	}
         count = atomic_dec_return (&device->open_count);
         if ( count == 0) {
-                invalidate_buffers (inp->i_rdev);
+                invalidate_bdev (inp->i_bdev, 0);
                 if ( device->discipline->owner )
                         __MOD_DEC_USE_COUNT(device->discipline->owner);
                 MOD_DEC_USE_COUNT;
diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h	Wed Apr  3 17:11:16 2002
+++ b/drivers/s390/block/dasd_int.h	Wed Apr  3 17:11:16 2002
@@ -201,14 +201,14 @@
         debug_sprintf_event(d_device->debug_area,d_level,\
                     DASD_DEVICE_FORMAT_STRING d_str "\n",\
                     d_device, d_data);\
-} while(0);
+} while(0)
 #define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
 do {\
         if ( d_device->debug_area != NULL )\
         debug_sprintf_exception(d_device->debug_area,d_level,\
                         DASD_DEVICE_FORMAT_STRING d_str "\n",\
                         d_device, d_data);\
-} while(0);
+} while(0)
 
 #define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
 #define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
@@ -217,14 +217,14 @@
         debug_sprintf_event(dasd_debug_area, d_level,\
                     DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
                     d_fn, d_data);\
-} while(0);
+} while(0)
 #define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
 do {\
         if ( dasd_debug_area != NULL )\
         debug_sprintf_exception(dasd_debug_area, d_level,\
                         DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
                         d_fn, d_data);\
-} while(0);
+} while(0)
 
 struct dasd_device_t;
 struct request;
diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
--- a/drivers/s390/block/xpram.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/s390/block/xpram.c	Wed Apr  3 17:11:16 2002
@@ -655,7 +655,7 @@
 
 	case BLKFLSBUF: /* flush, 0x1261 */
 		fsync_bdev(inode->i_bdev);
-		if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
+		if ( capable(CAP_SYS_ADMIN) )invalidate_bdev(inode->i_bdev, 0);
 		return 0;
 
 	case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
diff -Nru a/drivers/s390/char/tapeblock.c b/drivers/s390/char/tapeblock.c
--- a/drivers/s390/char/tapeblock.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/s390/char/tapeblock.c	Wed Apr  3 17:11:15 2002
@@ -217,7 +217,7 @@
 	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	tapestate_set (ti, TS_UNUSED);
 	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	invalidate_buffers(inode->i_rdev);
+	invalidate_bdev(inode->i_bdev, 0);
 	return 0;
 }
 
diff -Nru a/drivers/sbus/audio/amd7930.c b/drivers/sbus/audio/amd7930.c
--- a/drivers/sbus/audio/amd7930.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/sbus/audio/amd7930.c	Wed Apr  3 17:11:16 2002
@@ -1619,7 +1619,6 @@
 	info->irq = irq.pri;
 	request_irq(info->irq, amd7930_interrupt,
 		    SA_INTERRUPT, "amd7930", drv);
-	enable_irq(info->irq);
 	amd7930_enable_ints(info);
 
 	/* Initalize the local copy of the MAP registers. */
@@ -1644,7 +1643,6 @@
 	err = register_sparcaudio_driver(drv, 1);
 	if (err < 0) {
 		printk(KERN_ERR "amd7930: unable to register\n");
-		disable_irq(info->irq);
 		free_irq(info->irq, drv);
 		sbus_iounmap(info->regs, info->regs_size);
 		kfree(drv->private);
@@ -1666,7 +1664,6 @@
 
 	unregister_sparcaudio_driver(drv, 1);
 	amd7930_idle(info);
-	disable_irq(info->irq);
 	free_irq(info->irq, drv);
 	sbus_iounmap(info->regs, info->regs_size);
 	kfree(drv->private);
diff -Nru a/drivers/sbus/audio/cs4231.c b/drivers/sbus/audio/cs4231.c
--- a/drivers/sbus/audio/cs4231.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/sbus/audio/cs4231.c	Wed Apr  3 17:11:16 2002
@@ -2210,7 +2210,6 @@
         /* Attach the interrupt handler to the audio interrupt. */
         cs4231_chip->irq = sdev->irqs[0];
         request_irq(cs4231_chip->irq, cs4231_interrupt, SA_SHIRQ, "cs4231", drv);
-        enable_irq(cs4231_chip->irq);
 
         cs4231_chip->nirqs = 1;
         cs4231_enable_interrupts(drv);
@@ -2224,7 +2223,6 @@
         if (err < 0) {
                 printk(KERN_ERR "cs4231: unable to register\n");
                 cs4231_disable_interrupts(drv);
-                disable_irq(cs4231_chip->irq);
                 free_irq(cs4231_chip->irq, drv);
                 sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
                 kfree(drv->private);
@@ -2312,9 +2310,7 @@
         bail:
                 printk(KERN_ERR "cs4231: unable to register\n");
                 cs4231_disable_interrupts(drv);
-                disable_irq(cs4231_chip->irq);
                 free_irq(cs4231_chip->irq, drv);
-                disable_irq(cs4231_chip->irq2);
                 free_irq(cs4231_chip->irq2, drv);
                 kfree(drv->private);
                 return -EIO;
@@ -2371,7 +2367,6 @@
 
 	cs4231_disable_interrupts(drv);
 	unregister_sparcaudio_driver(drv, 1);
-	disable_irq(cs4231_chip->irq);
 	free_irq(cs4231_chip->irq, drv);
 	if (!(cs4231_chip->status & CS_STATUS_IS_EBUS)) {
 		sbus_iounmap(cs4231_chip->regs, cs4231_chip->regs_size);
@@ -2380,7 +2375,6 @@
 		iounmap(cs4231_chip->regs);
 		iounmap(cs4231_chip->eb2p);
 		iounmap(cs4231_chip->eb2c);
-		disable_irq(cs4231_chip->irq2);
 		free_irq(cs4231_chip->irq2, drv);
 #endif
 	}
diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
--- a/drivers/sbus/char/aurora.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/sbus/char/aurora.c	Wed Apr  3 17:11:14 2002
@@ -179,7 +179,7 @@
 #ifdef AURORA_DEBUG
 	printk("aurora_long_delay: start\n");
 #endif
-	for (i = jiffies + delay; i > jiffies; ) ;
+	for (i = jiffies + delay; time_before(jiffies, i); ) ;
 #ifdef AURORA_DEBUG
 	printk("aurora_long_delay: end\n");
 #endif
diff -Nru a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
--- a/drivers/sbus/char/uctrl.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/sbus/char/uctrl.c	Wed Apr  3 17:11:16 2002
@@ -389,15 +389,11 @@
 	if(!driver->irq) 
 		driver->irq = tmp_irq[0].pri;
 
-	request_irq(driver->irq, uctrl_interrupt, 0, 
-		    "uctrl", driver);
-
-	enable_irq(driver->irq);
+	request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
 
 	if (misc_register(&uctrl_dev)) {
 		printk("%s: unable to get misc minor %d\n",
 		       __FUNCTION__, uctrl_dev.minor);
-		disable_irq(driver->irq);
 		free_irq(driver->irq, driver);
 		return -ENODEV;
 	}
@@ -414,10 +410,8 @@
 	struct uctrl_driver *driver = &drv;
 
 	misc_deregister(&uctrl_dev);
-	if (driver->irq) {
-		disable_irq(driver->irq);
+	if (driver->irq)
 		free_irq(driver->irq, driver);
-	}
 	if (driver->regs)
 		driver->regs = 0;
 }
diff -Nru a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
--- a/drivers/sbus/sbus.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/sbus/sbus.c	Wed Apr  3 17:11:15 2002
@@ -392,6 +392,10 @@
 		sbus_bus_ranges_init(iommund, sbus);
 
 		sbus_devs = prom_getchild(this_sbus);
+		if (!sbus_devs) {
+			sbus->devices = NULL;
+			goto next_bus;
+		}
 
 		sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
 
@@ -455,7 +459,7 @@
 		sbus_fixup_all_regs(sbus->devices);
 
 		dvma_init(sbus);
-
+	next_bus:
 		num_sbus++;
 		if(sparc_cpu_model == sun4u) {
 			this_sbus = prom_getsibling(this_sbus);
diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/scsi/3w-xxxx.c	Wed Apr  3 17:11:16 2002
@@ -133,6 +133,14 @@
                  some SMP systems.
    1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
                  pci_alloc/free_consistent().
+                 Better alignment checking in tw_allocate_memory().
+                 Cleanup tw_initialize_device_extension().
+   1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
+                 Improve handling of errors in tw_interrupt().
+                 Add handling/clearing of controller queue error.
+                 Empty stale responses before draining aen queue.
+                 Fix tw_scsi_eh_abort() to not reset on every io abort.
+                 Set can_queue in SHT to 255 to prevent hang from AEN.
 */
 
 #include <linux/module.h>
@@ -182,7 +190,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.020";
+char *tw_driver_version="1.02.00.021";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -284,6 +292,9 @@
 	}
 	tw_clear_attention_interrupt(tw_dev);
 
+	/* Empty response queue */
+	tw_empty_response_que(tw_dev);
+
 	/* Initialize command packet */
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
 		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
@@ -337,7 +348,7 @@
 			status_reg_value = inl(status_reg_addr);
 			if (tw_check_bits(status_reg_value)) {
 				dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n");
-				tw_decode_bits(tw_dev, status_reg_value);
+				tw_decode_bits(tw_dev, status_reg_value, 0);
 				return 1;
 			}
 			if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -451,7 +462,7 @@
 	status_reg_value = inl(status_reg_addr);
 	if (tw_check_bits(status_reg_value)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 1);
 		return 1;
 	}
 	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
@@ -571,13 +582,23 @@
 	status_reg_value = inl(status_reg_addr);
 
 	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 0);
 		return 1;
 	}
 
 	return 0;
 } /* End tw_check_errors() */
 
+/* This function will clear all interrupts on the controller */
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev)
+{
+	u32 control_reg_addr, control_reg_value;
+
+	control_reg_addr = tw_dev->registers.control_reg_addr;
+	control_reg_value = TW_STATUS_VALID_INTERRUPT;
+	outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_all_interrupts() */
+
 /* This function will clear the attention interrupt */
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
 {
@@ -632,30 +653,51 @@
 	}
 } /* End tw_copy_mem_info() */
 
-/* This function will print readable messages from statsu register errors */
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+/* This function will print readable messages from status register errors */
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
 {
+	char host[16];
+
 	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+	if (print_host)
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+	else
+		host[0] = '\0';
+
 	switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) {
 	case TW_STATUS_PCI_PARITY_ERROR:
-		printk(KERN_WARNING "3w-xxxx: PCI Parity Error: clearing.\n");
+		printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr);
 		break;
 	case TW_STATUS_MICROCONTROLLER_ERROR:
-		printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n");
-		break;
+		if (tw_dev->reset_print == 0) {
+			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+			tw_dev->reset_print = 1;
+		}
+		return 1;
 	case TW_STATUS_PCI_ABORT:
-		printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n");
+		printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
 		outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr);
 		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
 		break;
-  }
+	case TW_STATUS_QUEUE_ERROR:
+		printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr);
+		break;
+	case TW_STATUS_SBUF_WRITE_ERROR:
+		printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr);
+		break;
+	}
+	
+	return 0;
 } /* End tw_decode_bits() */
 
 /* This function will return valid sense buffer information for failed cmds */
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
 {
-	int i, found=0;
+	int i;
 	TW_Command *command;
 
         dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
@@ -668,7 +710,6 @@
 		if ((command->status == 0xc7) || (command->status == 0xcb)) {
 			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
 				if (command->flags == tw_sense_table[i][0]) {
-					found=1;
 
 					/* Valid bit and 'current errors' */
 					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
@@ -686,13 +727,16 @@
 					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
 
 					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+					return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
 				}
 			}
 		}
+
 		/* If no table match, error so we get a reset */
-		if (found == 0)
-			tw_dev->srb[request_id]->result = (DID_RESET << 16);
+		return 1;
 	}
+
+	return 0;
 } /* End tw_decode_sense() */
 
 /* This function will disable interrupts on the controller */  
@@ -706,7 +750,7 @@
 } /* End tw_disable_interrupts() */
 
 /* This function will empty the response que */
-int tw_empty_response_que(TW_Device_Extension *tw_dev) 
+void tw_empty_response_que(TW_Device_Extension *tw_dev) 
 {
 	u32 status_reg_addr, status_reg_value;
 	u32 response_que_addr, response_que_value;
@@ -716,22 +760,10 @@
   
 	status_reg_value = inl(status_reg_addr);
 
-	if (tw_check_bits(status_reg_value)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
-		return 1;
-	}
-  
 	while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
 		response_que_value = inl(response_que_addr);
 		status_reg_value = inl(status_reg_addr);
-		if (tw_check_bits(status_reg_value)) {
-			dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
-			return 1;
-		}
 	}
-	return 0;
 } /* End tw_empty_response_que() */
 
 /* This function will enable interrupts on the controller */
@@ -811,8 +843,8 @@
 
 			/* Check for errors and clear them */
 			status_reg_value = inl(tw_dev->registers.status_reg_addr);
-			if (TW_STATUS_ERRORS(status_reg_value)) 
-			  tw_decode_bits(tw_dev, status_reg_value);
+			if (TW_STATUS_ERRORS(status_reg_value))
+				tw_decode_bits(tw_dev, status_reg_value, 0);
 			
 			/* Poll status register for 60 secs for 'Controller Ready' flag */
 			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
@@ -843,14 +875,6 @@
 					continue;
 				}
 
-				/* Empty the response queue */
-				error = tw_empty_response_que(tw_dev);
-				if (error) {
-					printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards);
-					tries++;
-					continue;
-				}
-
 				/* Now the controller is in a good state */
 				break;
 			}
@@ -877,7 +901,7 @@
 			request_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
 			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+				printk(KERN_WARNING "3w-xxxx: No valid units for for card %d.\n", numcards);
 				release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
 				tw_free_device_extension(tw_dev);
 				kfree(tw_dev);
@@ -895,7 +919,7 @@
 
 			/* Calculate max cmds per lun, and setup queues */
 			if (tw_dev->num_units > 0) {
-				tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units;
+				/* Use SHT cmd_per_lun here */
 				tw_dev->free_head = TW_Q_START;
 				tw_dev->free_tail = TW_Q_LENGTH - 1;
 				tw_dev->free_wrap = TW_Q_LENGTH - 1;
@@ -1064,7 +1088,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 0);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1191,7 +1215,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 0);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
@@ -1251,51 +1275,52 @@
 	u32 response_que_addr;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
 	TW_Response_Queue response_que;
-	int error = 0;
-	int do_response_interrupt=0;
-	int do_attention_interrupt=0;
-	int do_host_interrupt=0;
-	int do_command_interrupt=0;
+	int error = 0, retval = 0;
 	unsigned long flags = 0;
 	TW_Command *command_packet;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
+
+	/* See if we are already running on another processor */
 	if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags))
 		return;
+
+	/* Get the host lock for io completions */
 	spin_lock_irqsave(tw_dev->host->host_lock, flags);
 
+	/* See if the interrupt matches this instance */
 	if (tw_dev->tw_pci_dev->irq == irq) {
+
+		/* Make sure io isn't queueing */
 		spin_lock(&tw_dev->tw_lock);
-		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n");
 
 		/* Read the registers */
 		status_reg_addr = tw_dev->registers.status_reg_addr;
 		response_que_addr = tw_dev->registers.response_que_addr;
 		status_reg_value = inl(status_reg_addr);
 
+		/* Check if this is our interrupt, otherwise bail */
+		if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+			goto tw_interrupt_bail;
+
+		/* Check controller for errors */
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+				tw_clear_all_interrupts(tw_dev);
+				goto tw_interrupt_bail;
+			}
 		}
 
-		/* Check which interrupt */
-		if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
-			do_host_interrupt=1;
-		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT)
-			do_attention_interrupt=1;
-		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT)
-			do_command_interrupt=1;
-		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT)
-			do_response_interrupt=1;
-
 		/* Handle host interrupt */
-		if (do_host_interrupt) {
+		if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
 			tw_clear_host_interrupt(tw_dev);
 		}
 
 		/* Handle attention interrupt */
-		if (do_attention_interrupt) {
+		if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
-			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
 			tw_clear_attention_interrupt(tw_dev);
 			tw_state_request_start(tw_dev, &request_id);
 			error = tw_aen_read_queue(tw_dev, request_id);
@@ -1307,7 +1332,7 @@
 		}
 
 		/* Handle command interrupt */
-		if (do_command_interrupt) {
+		if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
 			/* Drain as many pending commands as we can */
 			while (tw_dev->pending_request_count > 0) {
 				request_id = tw_dev->pending_queue[tw_dev->pending_head];
@@ -1323,6 +1348,7 @@
 					}
 					tw_dev->pending_request_count--;
 				} else {
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no);
 					break;
 				}
 			}
@@ -1332,40 +1358,40 @@
 		}
 
 		/* Handle response interrupt */
-		if (do_response_interrupt) {
+		if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
 			/* Drain the response queue from the board */
 			while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+				/* Read response queue register */
 				response_que.value = inl(response_que_addr);
 				request_id = response_que.u.response_id;
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
 				error = 0;
+
+				/* Check for bad response */
 				if (command_packet->status != 0) {
-					/* Bad response */
-					if (tw_dev->srb[request_id] != 0)
-						tw_decode_sense(tw_dev, request_id, 1);
-					error = 3;
+					/* If internal command, don't error, don't fill sense */
+					if (tw_dev->srb[request_id] == 0) {
+						tw_decode_sense(tw_dev, request_id, 0);
+					} else {
+						error = tw_decode_sense(tw_dev, request_id, 1);
+					}
 				}
+
+				/* Check for correct state */
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode);
 					error = 1;
 				}
-				if (TW_STATUS_ERRORS(status_reg_value)) {
-					tw_decode_bits(tw_dev, status_reg_value);
-					error = 1;
-				}
+
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
-				/* Check for internal command */
+
+				/* Check for internal command completion */
 				if (tw_dev->srb[request_id] == 0) {
 					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
-					error = tw_aen_complete(tw_dev, request_id);
-					if (error) {
+					retval = tw_aen_complete(tw_dev, request_id);
+					if (retval) {
 						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
 					}
-					status_reg_value = inl(status_reg_addr);
-					if (tw_check_bits(status_reg_value)) {
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-						tw_decode_bits(tw_dev, status_reg_value);
-					}
 				} else {
 				switch (tw_dev->srb[request_id]->cmnd[0]) {
 					case READ_10:
@@ -1389,20 +1415,22 @@
 						error = tw_ioctl_complete(tw_dev, request_id);
 						break;
 					default:
-						printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]);
-						tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
-						tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
-					}
-					if (error == 1) {
-						/* Tell scsi layer there was an error */
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-						tw_dev->srb[request_id]->result = (DID_RESET << 16);
+						printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+						error = 1;
 					}
+
+					/* If no error command was a success */
 					if (error == 0) {
-						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
 					}
-					if (error != 2) {
+
+					/* If error, command failed */
+					if (error == 1) {
+						tw_dev->srb[request_id]->result = (DID_RESET << 16);
+					}
+
+					/* Now complete the io */
+					if ((error != TW_ISR_DONT_COMPLETE)) {
 						tw_dev->state[request_id] = TW_S_COMPLETED;
 						tw_state_request_finish(tw_dev, request_id);
 						tw_dev->posted_request_count--;
@@ -1410,16 +1438,24 @@
 
 						tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
 					}
-					status_reg_value = inl(status_reg_addr);
-					if (tw_check_bits(status_reg_value)) {
-						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
-						tw_decode_bits(tw_dev, status_reg_value);
+				}
+				
+				/* Check for valid status after each drain */
+				status_reg_value = inl(status_reg_addr);
+				if (tw_check_bits(status_reg_value)) {
+					dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+					if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+						tw_clear_all_interrupts(tw_dev);
+						goto tw_interrupt_bail;
 					}
 				}
 			}
 		}
+tw_interrupt_bail:
 		spin_unlock(&tw_dev->tw_lock);
-	}
+	} else
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n");
+
 	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
 	clear_bit(TW_IN_INTR, &tw_dev->flags);
 } /* End tw_interrupt() */
@@ -1782,7 +1818,7 @@
 			break;
 		case TW_CMD_PACKET_WITH_DATA:
 			dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n");
-			return 2; /* Special case for isr to not complete io */
+			return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */
 		default:
 			memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
 			param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
@@ -1852,7 +1888,7 @@
 
 	if (tw_check_bits(status_reg_value)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 0);
 	}
 		
 	while ((status_reg_value & flag) != flag) {
@@ -1860,7 +1896,7 @@
 
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 0);
 		}
 
 		do_gettimeofday(&timeout);
@@ -1887,7 +1923,7 @@
 
 	if (tw_check_bits(status_reg_value)) {
 		dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
-		tw_decode_bits(tw_dev, status_reg_value);
+		tw_decode_bits(tw_dev, status_reg_value, 1);
 	}
 
 	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
@@ -1941,7 +1977,6 @@
 		    (tw_dev->state[i] != TW_S_COMPLETED)) {
 			srb = tw_dev->srb[i];
 			if (srb != NULL) {
-				srb = tw_dev->srb[i];
 				srb->result = (DID_RESET << 16);
 				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
 				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
@@ -1960,6 +1995,7 @@
 	tw_dev->pending_request_count = 0;
 	tw_dev->pending_head = TW_Q_START;
 	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
 
 	return 0;
 } /* End tw_reset_device_extension() */
@@ -1991,14 +2027,6 @@
 			continue;
 		}
 
-		/* Empty the response queue again */
-		error = tw_empty_response_que(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no);
-			tries++;
-			continue;
-		}
-
 		/* Now the controller is in a good state */
 		break;
 	}
@@ -2086,11 +2114,6 @@
 		return (FAILED);
 	}
 
-	/* We have to let AEN requests through before the reset */
-	spin_unlock_irq(tw_dev->host->host_lock);
-	mdelay(TW_AEN_WAIT_TIME);
-	spin_lock_irq(tw_dev->host->host_lock);
-
 	spin_lock(&tw_dev->tw_lock);
 	tw_dev->num_aborts++;
 
@@ -2117,18 +2140,26 @@
 				spin_unlock(&tw_dev->tw_lock);
 				return (SUCCESS);
 			}
+			if (tw_dev->state[i] == TW_S_POSTED) {
+				/* If the command has already been posted, we have to reset the card */
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
+				/* We have to let AEN requests through before the reset */
+				spin_unlock(&tw_dev->tw_lock);
+				spin_unlock_irq(tw_dev->host->host_lock);
+				mdelay(TW_AEN_WAIT_TIME);
+				spin_lock_irq(tw_dev->host->host_lock);
+				spin_lock(&tw_dev->tw_lock);
+
+				if (tw_reset_device_extension(tw_dev)) {
+					dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
+					spin_unlock(&tw_dev->tw_lock);
+					return (FAILED);
+				}
+			}
 		}
 	}
 
-	/* If the command has already been posted, we have to reset the card */
-	printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt);
-	if (tw_reset_device_extension(tw_dev)) {
-		dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no);
-		spin_unlock(&tw_dev->tw_lock);
-		return (FAILED);
-	}
 	spin_unlock(&tw_dev->tw_lock);
-
 	return (SUCCESS);
 } /* End tw_scsi_eh_abort() */
 
@@ -2593,7 +2624,7 @@
 	}
 
 	command_packet->byte0.sgl_offset = 3;
-	command_packet->size = 5;
+	command_packet->size = 3;
 	command_packet->request_id = request_id;
 	command_packet->byte3.unit = srb->target;
 	command_packet->byte3.host_id = 0;
@@ -2628,6 +2659,7 @@
 		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
 		command_packet->byte8.io.sgl[0].address = buffaddr;
 		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+		command_packet->size+=2;
 	}
 
 	/* Do this if we have multiple sg list entries */
@@ -2638,8 +2670,6 @@
 			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
 			command_packet->size+=2;
 		}
-		if (tw_dev->srb[request_id]->use_sg >= 1)
-			command_packet->size-=2;
 	}
 
 	/* Update SG statistics */
@@ -2754,7 +2784,7 @@
 		status_reg_value = inl(status_reg_addr);
 		if (tw_check_bits(status_reg_value)) {
 			dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n");
-			tw_decode_bits(tw_dev, status_reg_value);
+			tw_decode_bits(tw_dev, status_reg_value, 1);
 			return 1;
 		}
 		if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
--- a/drivers/scsi/3w-xxxx.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/3w-xxxx.h	Wed Apr  3 17:11:14 2002
@@ -92,10 +92,11 @@
 	"Verify failed: Port #",                // 0x02A
 	"Verify complete: Unit #",              // 0x02B
 	"Overwrote bad sector during rebuild: Port #",  //0x2C
-	"Encountered bad sector during rebuild: Port #" //0x2D
+	"Encountered bad sector during rebuild: Port #", //0x2D
+	"Replacement drive is too small: Port #" //0x2E
 };
 
-#define TW_AEN_STRING_MAX                      0x02E
+#define TW_AEN_STRING_MAX                      0x02F
 
 /*
    Sense key lookup table
@@ -134,7 +135,9 @@
 #define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
 #define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
 #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
 #define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
 
 /* Status register bit definitions */
 #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
@@ -154,7 +157,9 @@
 #define TW_STATUS_ALL_INTERRUPTS	       0x000F0000
 #define TW_STATUS_CLEARABLE_BITS	       0x00D00000
 #define TW_STATUS_EXPECTED_BITS		       0x00002000
-#define TW_STATUS_UNEXPECTED_BITS	       0x00F80000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
 
 /* RESPONSE QUEUE BIT DEFINITIONS */
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
@@ -214,7 +219,7 @@
 #define TW_MAX_PCI_BUSES		      255
 #define TW_MAX_RESET_TRIES		      3
 #define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
-#define TW_MAX_CMDS_PER_LUN		      (TW_Q_LENGTH-2)/TW_MAX_UNITS
+#define TW_MAX_CMDS_PER_LUN		      255
 #define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
 #define TW_IOCTL                              0x80
 #define TW_MAX_AEN_TRIES                      100
@@ -223,6 +228,8 @@
 #define TW_MAX_SECTORS                        256
 #define TW_AEN_WAIT_TIME                      1000
 #define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
 
 /* Macros */
 #define TW_STATUS_ERRORS(x) \
@@ -235,7 +242,7 @@
 #ifdef TW_DEBUG
 #define dprintk(msg...) printk(msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 /* Scatter Gather List Entry */
@@ -402,8 +409,9 @@
 	unsigned short		aen_queue[TW_Q_LENGTH];
 	unsigned char		aen_head;
 	unsigned char		aen_tail;
-	long			flags; /* long req'd for set_bit --RR */
+	volatile long		flags; /* long req'd for set_bit --RR */
 	char			*ioctl_data[TW_Q_LENGTH];
+	int			reset_print;
 } TW_Device_Extension;
 
 /* Function prototypes */
@@ -413,12 +421,13 @@
 int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which);
 int tw_check_bits(u32 status_reg_value);
 int tw_check_errors(TW_Device_Extension *tw_dev);
+void tw_clear_all_interrupts(TW_Device_Extension *tw_dev);
 void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
 void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
-void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value);
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
+int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host);
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
 void tw_disable_interrupts(TW_Device_Extension *tw_dev);
-int tw_empty_response_que(TW_Device_Extension *tw_dev);
+void tw_empty_response_que(TW_Device_Extension *tw_dev);
 void tw_enable_interrupts(TW_Device_Extension *tw_dev);
 void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev);
 int tw_findcards(Scsi_Host_Template *tw_host);
@@ -478,7 +487,7 @@
 	reset : NULL,					\
 	slave_attach : NULL,				\
 	bios_param : tw_scsi_biosparam,			\
-	can_queue : TW_Q_LENGTH,			\
+	can_queue : TW_Q_LENGTH-1,			\
 	this_id: -1,					\
 	sg_tablesize : TW_MAX_SGL_LENGTH,		\
 	cmd_per_lun: TW_MAX_CMDS_PER_LUN,		\
diff -Nru a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
--- a/drivers/scsi/53c7,8xx.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/53c7,8xx.c	Wed Apr  3 17:11:14 2002
@@ -1869,7 +1869,7 @@
 	 */
 
 	timeout = jiffies + 5 * HZ / 10;
-	while ((hostdata->test_completed == -1) && jiffies < timeout) {
+	while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
 		barrier();
 		cpu_relax();
 	}
@@ -1955,7 +1955,7 @@
 	    restore_flags(flags);
 
 	    timeout = jiffies + 5 * HZ;	/* arbitrary */
-	    while ((hostdata->test_completed == -1) && jiffies < timeout) {
+	    while ((hostdata->test_completed == -1) && time_before(jiffies, timeout)) {
 	    	barrier();
 		cpu_relax();
 	    }
diff -Nru a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
--- a/drivers/scsi/53c7xx.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/scsi/53c7xx.c	Wed Apr  3 17:11:15 2002
@@ -1627,7 +1627,7 @@
 	 */
 
 	timeout = jiffies + 5 * HZ / 10;
-	while ((hostdata->test_completed == -1) && jiffies < timeout)
+	while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
 		barrier();
 
 	failed = 1;
@@ -1713,7 +1713,7 @@
 	    restore_flags(flags);
 
 	    timeout = jiffies + 5 * HZ;	/* arbitrary */
-	    while ((hostdata->test_completed == -1) && jiffies < timeout)
+	    while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
 	    	barrier();
 
 	    NCR53c7x0_write32 (DSA_REG, 0);
diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
--- a/drivers/scsi/NCR53C9x.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/NCR53C9x.c	Wed Apr  3 17:11:14 2002
@@ -3615,3 +3615,5 @@
 	esps_running = esps_in_use;
 }
 #endif
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
--- a/drivers/scsi/a2091.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/scsi/a2091.c	Wed Apr  3 17:11:13 2002
@@ -248,3 +248,5 @@
 #endif
 	return 1;
 }
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c	Wed Apr  3 17:11:15 2002
@@ -906,7 +906,7 @@
 }
 
 static void
-ahc_linux_setup_tag_info(char *p, char *end)
+ahc_linux_setup_tag_info(char *p, char *end, char *s)
 {
 	char	*base;
 	char	*tok;
@@ -986,7 +986,7 @@
 		}
 	}
 	while ((p != base) && (p != NULL))
-		p = strtok(NULL, ",.");
+		p = strsep(&s, ",.");
 }
 
 /*
@@ -1018,7 +1018,8 @@
 
 	end = strchr(s, '\0');
 
-	for (p = strtok(s, ",."); p; p = strtok(NULL, ",.")) {
+	while ((p = strsep(&s, ",.")) != NULL) {
+		if (!*p) continue;
 		for (i = 0; i < NUM_ELEMENTS(options); i++) {
 			n = strlen(options[i].name);
 
@@ -1026,7 +1027,7 @@
 				continue;
 
 			if (strncmp(p, "tag_info", n) == 0) {
-				ahc_linux_setup_tag_info(p + n, end);
+				ahc_linux_setup_tag_info(p + n, end, s);
 			} else if (p[n] == ':') {
 				*(options[i].flag) =
 				    simple_strtoul(p + n + 1, NULL, 0);
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/scsi/aic7xxx_old.c	Wed Apr  3 17:11:15 2002
@@ -1443,7 +1443,7 @@
 
   end = strchr(s, '\0');
 
-  for (p = strtok(s, ",."); p; p = strtok(NULL, ",."))
+  while ((p = strsep(&s, ",.")) != NULL)
   {
     for (i = 0; i < NUMBER(options); i++)
     {
@@ -1525,7 +1525,7 @@
               }
             }
             while((p != base) && (p != NULL))
-              p = strtok(NULL, ",.");
+              p = strsep(&s, ",.");
           }
         }
         else if (p[n] == ':')
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/eata.c	Wed Apr  3 17:11:14 2002
@@ -311,7 +311,7 @@
  *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
  *
  *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
- *  address on more then a single DPT PCI board, so in this case you have to
+ *  address on more than a single DPT PCI board, so in this case you have to
  *  let the PCI BIOS assign the addresses.
  *
  *  The sequence of detection probes is:
diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
--- a/drivers/scsi/fdomain.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/fdomain.c	Wed Apr  3 17:11:14 2002
@@ -78,7 +78,7 @@
  Please note that the drive ordering that Future Domain implemented in BIOS
  versions 3.4 and 3.5 is the opposite of the order (currently) used by the
  rest of the SCSI industry.  If you have BIOS version 3.4 or 3.5, and have
- more then one drive, then the drive ordering will be the reverse of that
+ more than one drive, then the drive ordering will be the reverse of that
  which you see under DOS.  For example, under DOS SCSI ID 0 will be D: and
  SCSI ID 1 will be C: (the boot device).  Under Linux, SCSI ID 0 will be
  /dev/sda and SCSI ID 1 will be /dev/sdb.  The Linux ordering is consistent
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/scsi/ide-scsi.c	Wed Apr  3 17:11:13 2002
@@ -331,7 +331,7 @@
 		printk ("ide-scsi: %s: DMA complete\n", drive->name);
 #endif /* IDESCSI_DEBUG_LOG */
 		pc->actually_transferred=pc->request_transfer;
-		(void) (HWIF(drive)->dmaproc(ide_dma_end, drive));
+		(void) drive->channel->dmaproc(ide_dma_end, drive);
 	}
 
 	status = GET_STAT();						/* Clear the interrupt */
@@ -434,9 +434,9 @@
 	bcount = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
 
 	if (drive->using_dma && rq->bio)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+		dma_ok = !drive->channel->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
 
-	SELECT_DRIVE(HWIF(drive), drive);
+	SELECT_DRIVE(drive->channel, drive);
 	if (IDE_CONTROL_REG)
 		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);
 	OUT_BYTE (dma_ok,IDE_FEATURE_REG);
@@ -444,8 +444,8 @@
 	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);
 
 	if (dma_ok) {
-		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) drive->channel->dmaproc(ide_dma_begin, drive);
 	}
 	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);
@@ -508,7 +508,7 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
-	ata_ops(drive)->busy++;
+	MOD_INC_USE_COUNT;
 
 	idescsi_drives[id] = drive;
 	drive->driver_data = scsi;
@@ -629,8 +629,9 @@
 
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {
 		drive = idescsi_drives[id];
-		if (drive)
-			ata_ops(drive)->busy--;
+		if (drive) {
+			MOD_DEC_USE_COUNT;
+		}
 	}
 	return 0;
 }
diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
--- a/drivers/scsi/ppa.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/scsi/ppa.c	Wed Apr  3 17:11:13 2002
@@ -702,7 +702,7 @@
 	 * change things for "normal" hardware since generally 
 	 * the 6th bit is always high.
 	 * This makes the CPU load higher on some hardware 
-	 * but otherwise we can not get more then 50K/secs 
+	 * but otherwise we can not get more than 50K/secs 
 	 * on this problem hardware.
 	 */
 	if ((r & 0xc0) != 0xc0) {
diff -Nru a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
--- a/drivers/scsi/sun3x_esp.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/sun3x_esp.c	Wed Apr  3 17:11:14 2002
@@ -376,3 +376,5 @@
 static Scsi_Host_Template driver_template = SCSI_SUN3X_ESP;
 
 #include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
--- a/drivers/scsi/tmscsim.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/scsi/tmscsim.c	Wed Apr  3 17:11:15 2002
@@ -2468,68 +2468,68 @@
  * '-' means no change
  *******************************************************************/
 
-static int dc390_scanf (char** p1, char** p2, int* var)
+static int dc390_scanf (char** buffer, char** pos, char** p0, int* var)
 {
-   *p2 = *p1;
-   *var = simple_strtoul (*p2, p1, 10);
-   if (*p2 == *p1) return -1;
-   *p1 = strtok (0, " \t\n:=,;.");
+   *p0 = *pos;
+   *var = simple_strtoul (*p0, pos, 10);
+   if (*p0 == *pos) return -1;
+   *pos = strsep (buffer, " \t\n:=,;.");
    return 0;
 };
 
-#define SCANF(p1, p2, var, min, max)		\
-if (dc390_scanf (&p1, &p2, &var)) goto einv;	\
+#define SCANF(buffer, pos, p0, var, min, max)		\
+if (dc390_scanf (&buffer, &pos, &p0, &var)) goto einv;	\
 else if (var<min || var>max) goto einv2
 
-static int dc390_yesno (char** p, char* var, char bmask)
+static int dc390_yesno (char** buffer, char** pos, char* var, char bmask)
 {
-   switch (**p)
+   switch (**pos)
      {
       case 'Y': *var |= bmask; break;
       case 'N': *var &= ~bmask; break;
       case '-': break;
       default: return -1;
      }
-   *p = strtok (0, " \t\n:=,;");
+   *pos = strsep (buffer, " \t\n:=,;");
    return 0;
 };
 
-#define YESNO(p, var, bmask)			\
-if (dc390_yesno (&p, &var, bmask)) goto einv;	\
+#define YESNO(buffer, pos, var, bmask)			\
+if (dc390_yesno (&buffer, &pos, &var, bmask)) goto einv;	\
 else dc390_updateDCB (pACB, pDCB);		\
 if (!p) goto ok
 
-static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
+static int dc390_search (char** buffer, char** pos, char** p0, char* var, char* txt, int max, int scale, char* ign)
 {
    int dum;
-   if (! memcmp (*p1, txt, strlen(txt)))
+   if (! memcmp (*pos, txt, strlen(txt)))
      {
-	*p2 = strtok (0, " \t\n:=,;");
-	if (!*p2) return -1;
-	dum = simple_strtoul (*p2, p1, 10);
-	if (*p2 == *p1) return -1;
+	*p0 = strsep (buffer, " \t\n:=,;");
+	if (!*p0) return -1;
+	dum = simple_strtoul (*p0, pos, 10);
+	if (*p0 == *pos) return -1;
 	if (dum >= 0 && dum <= max) 
 	  { *var = (dum * 100) / scale; }
 	else return -2;
-	*p1 = strtok (0, " \t\n:=,;");
-	if (*ign && *p1 && strlen(*p1) >= strlen(ign) && 
-	    !(memcmp (*p1, ign, strlen(ign)))) 
-		*p1 = strtok (0, " \t\n:=,;");
+	*pos = strsep (buffer, " \t\n:=,;");
+	if (*ign && *pos && strlen(*pos) >= strlen(ign) && 
+	    !(memcmp (*pos, ign, strlen(ign)))) 
+		*pos = strsep (buffer, " \t\n:=,;");
 
      }
    return 0;
 };
 
-#define SEARCH(p1, p2, var, txt, max)						\
-if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2;	\
+#define SEARCH(buffer, pos, p0, var, txt, max)						\
+if (dc390_search (&buffer, &pos, &p0, (PUCHAR)(&var), txt, max, 100, "")) goto einv2;	\
 else if (!p1) goto ok2
 
-#define SEARCH2(p1, p2, var, txt, max, scale)					\
-if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; 		\
+#define SEARCH2(buffer, pos, p0, var, txt, max, scale)					\
+if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; 		\
 else if (!p1) goto ok2
 
-#define SEARCH3(p1, p2, var, txt, max, scale, ign)				\
-if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2;		\
+#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign)				\
+if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2;		\
 else if (!p1) goto ok2
 
 
@@ -2565,12 +2565,9 @@
   while (*pos) 
     { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
   
-  /* We should protect __strtok ! */
-  /* spin_lock (strtok_lock); */
-
   /* Remove WS */
-  pos = strtok (buffer, " \t:\n=,;");
-  if (!pos) goto ok;
+  pos = strsep (&buffer, " \t:\n=,;");
+  if (!*pos) goto ok;
    
  next:
   if (!memcmp (pos, "RESET", 5)) goto reset;
@@ -2586,10 +2583,10 @@
       int dev, id, lun; char* pdec;
       char olddevmode;
       
-      SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
-      if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
-      if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
-      if (!pos) goto einv;
+      SCANF (buffer, pos, p0, dev, 0, pACB->DCBCnt-1);
+      if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+      if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
+      if (!*pos) goto einv;
       
       PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
       pDCB = pACB->pLinkDCB;
@@ -2610,20 +2607,20 @@
       };
 	  
       olddevmode = pDCB->DevMode;
-      YESNO (pos, pDCB->DevMode, PARITY_CHK_);
+      YESNO (buffer, pos, pDCB->DevMode, PARITY_CHK_);
       needs_inquiry++;
-      YESNO (pos, pDCB->DevMode, SYNC_NEGO_);
+      YESNO (buffer, pos, pDCB->DevMode, SYNC_NEGO_);
       if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--;
       needs_inquiry++;
-      YESNO (pos, pDCB->DevMode, EN_DISCONNECT_);
+      YESNO (buffer, pos, pDCB->DevMode, EN_DISCONNECT_);
       if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--;
-      YESNO (pos, pDCB->DevMode, SEND_START_);
+      YESNO (buffer, pos, pDCB->DevMode, SEND_START_);
       needs_inquiry++;
-      YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
+      YESNO (buffer, pos, pDCB->DevMode, TAG_QUEUEING_);
       if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
 
       dc390_updateDCB (pACB, pDCB);
-      if (!pos) goto ok;
+      if (!*pos) goto ok;
        
       olddevmode = pDCB->NegoPeriod;
       /* Look for decimal point (Speed) */
@@ -2632,22 +2629,22 @@
       /* NegoPeriod */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 72, 800); 
+	  SCANF (buffer, pos, p0, dum, 72, 800); 
 	  pDCB->NegoPeriod = dum >> 2;
 	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 	  if (!pos) goto ok;
-	  if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
+	  if (memcmp (pos, "NS", 2) == 0) pos = strsep (*pos, " \t\n:=,;.");
 	}
-      else pos = strtok (0, " \t\n:=,;.");
-      if (!pos) goto ok;
+      else pos = strsep (*pos, " \t\n:=,;.");
+      if (!*pos) goto ok;
       
       /* Sync Speed in MHz */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 1, 13); 
+	  SCANF (buffer, pos, p0, dum, 1, 13); 
 	  pDCB->NegoPeriod = (1000/dum) >> 2;
 	  if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++;
-	  if (!pos) goto ok;
+	  if (!*pos) goto ok;
 	  /* decimal */
 	  if (pos-1 == pdec)
 	     {
@@ -2656,38 +2653,38 @@
 		for (; p0-pos > 1; p0--) dum /= 10;
 		pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
 		if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
-		pos = strtok (0, " \t\n:=,;");
-		if (!pos) goto ok;
+		pos = strsep (*pos, " \t\n:=,;");
+		if (!*pos) goto ok;
 	     };
-	  if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+	  if (*pos == 'M') pos = strsep (*pos, " \t\n:=,;");
 	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 	}
-      else pos = strtok (0, " \t\n:=,;");
+      else pos = strsep (*pos, " \t\n:=,;");
       /* dc390_updateDCB (pACB, pDCB); */
-      if (!pos) goto ok;
+      if (!*pos) goto ok;
 
       olddevmode = pDCB->SyncOffset;
       /* SyncOffs */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 0, 0x0f); 
+	  SCANF (buffer, pos, p0, dum, 0, 0x0f); 
 	  pDCB->SyncOffset = dum;
 	  if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
 	}
-      else pos = strtok (0, " \t\n:=,;");
-      if (!pos) goto ok;
+      else pos = strsep (*pos, " \t\n:=,;");
+      if (!*pos) goto ok;
       dc390_updateDCB (pACB, pDCB);
 
       //olddevmode = pDCB->MaxCommand;
       /* MaxCommand (Tags) */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
+	  SCANF (buffer, pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
 	  if (pDCB->SyncMode & EN_TAG_QUEUEING)
 		pDCB->MaxCommand = dum;
 	  else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
 	}
-      else pos = strtok (0, " \t\n:=,;");
+      else pos = strsep (*pos, " \t\n:=,;");
 
     }
   else
@@ -2696,14 +2693,14 @@
       PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
       dum = GLITCH_TO_NS (pACB->glitch_cfg);
       /* Adapter setting */
-      SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
-      SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
-      SEARCH (pos, p0, newadaptid, "ADAPTERID", 7);
-      SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
-      SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
-      SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
-      SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
-      SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
+      SEARCH (buffer, pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
+      SEARCH (buffer, pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
+      SEARCH (buffer, pos, p0, newadaptid, "ADAPTERID", 7);
+      SEARCH (buffer, pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
+      SEARCH (buffer, pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
+      SEARCH3 (buffer, pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
+      SEARCH3 (buffer, pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+      SEARCH3 (buffer, pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
     ok2:
       pACB->glitch_cfg = NS_TO_GLITCH (dum);
       if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
@@ -2719,10 +2716,9 @@
       // All devs should be INQUIRED now
       if (pos == p1) goto einv;
     }
-  if (pos) goto next;
+  if (*pos) goto next;
       
  ok:
-  /* spin_unlock (strtok_lock); */
   DC390_UNLOCK_ACB;
   if (needs_inquiry) 
      { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); };
@@ -2732,7 +2728,6 @@
  einv2:
   pos = p0;
  einv:
-  /* spin_unlock (strtok_lock); */
   DC390_UNLOCK_ACB;
   DC390_UNLOCK_IO(pACB.pScsiHost);
   printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL"));
@@ -2758,7 +2753,7 @@
 	
  inquiry:
      {
-	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+	pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
 	dev = simple_strtoul (pos, &p0, 10);
 	if (dev >= pACB->DCBCnt) goto einv_dev;
 	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2772,7 +2767,7 @@
 
  remove:
      {
-	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
+	pos = strsep (*pos, " \t\n.:;="); if (!*pos) goto einv;
 	dev = simple_strtoul (pos, &p0, 10);
 	if (dev >= pACB->DCBCnt) goto einv_dev;
 	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
@@ -2788,9 +2783,9 @@
  add:
      {
 	int id, lun;
-	pos = strtok (0, " \t\n.:;=");
-	if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
-	if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+	pos = strsep (*pos, " \t\n.:;=");
+	if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+	if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
 	pDCB = dc390_findDCB (pACB, id, lun);
 	if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; };
 	dc390_initDCB (pACB, &pDCB, id, lun);
@@ -2803,9 +2798,9 @@
  start:
      {
 	int id, lun;
-	pos = strtok (0, " \t\n.:;=");
-	if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
-	if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+	pos = strsep (*pos, " \t\n.:;=");
+	if (*pos) { SCANF (buffer, pos, p0, id, 0, 7); } else goto einv;
+	if (*pos) { SCANF (buffer, pos, p0, lun, 0, 7); } else goto einv;
 	pDCB = dc390_findDCB (pACB, id, lun);
 	if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
 	else dc390_initDCB (pACB, &pDCB, id, lun);
diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
--- a/drivers/scsi/u14-34f.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/scsi/u14-34f.c	Wed Apr  3 17:11:14 2002
@@ -171,7 +171,7 @@
  *          Auto detects if U14F boards have an old firmware revision.
  *          Max number of scatter/gather lists set to 16 for all boards
  *          (most installation run fine using 33 sglists, while other
- *          has problems when using more then 16).
+ *          has problems when using more than 16).
  *
  *      16 Jan 1995 rev. 1.13 for linux 1.1.81
  *          Display a message if check_region detects a port address
@@ -279,7 +279,7 @@
  *
  *  For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01),
  *  the latest firmware prom is 28008-006. Older firmware 28008-005 has
- *  problems when using more then 16 scatter/gather lists.
+ *  problems when using more than 16 scatter/gather lists.
  *
  *  The list of i/o ports to be probed can be totally replaced by the
  *  boot command line option: "u14-34f=port0,port1,port2,...", where the
diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/tc/zs.c	Wed Apr  3 17:11:14 2002
@@ -1472,7 +1472,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -Nru a/drivers/usb/Config.help b/drivers/usb/Config.help
--- a/drivers/usb/Config.help	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/Config.help	Wed Apr  3 17:11:15 2002
@@ -94,9 +94,13 @@
 CONFIG_USB_HID
   Say Y here if you want full HID support to connect keyboards,
   mice, joysticks, graphic tablets, or any other HID based devices
-  to your computer via USB. You can't use this driver and the
-  HIDBP (Boot Protocol) keyboard and mouse drivers at the same time.
-  More information is available: <file:Documentation/input/input.txt>.
+  to your computer via USB. You also need to select HID Input layer
+  support (below) if you want to use keyboards, mice, joysticks and
+  the like.
+
+  You can't use this driver and the HIDBP (Boot Protocol) keyboard
+  and mouse drivers at the same time. More information is available:
+  <file:Documentation/input/input.txt>.
 
   If unsure, say Y.
 
@@ -105,6 +109,13 @@
   The module will be called hid.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_HIDINPUT
+  Say Y here if you want to use a USB keyboard, mouse or joystick,
+  or any other HID input device. You also need Input layer support, 
+  (CONFIG_INPUT) which you select under "Input core support".
+
+  If unsure, say Y.
+
 CONFIG_USB_HIDDEV
   Say Y here if you want to support HID devices (from the USB
   specification standpoint) that aren't strictly user interface
@@ -114,31 +125,35 @@
   event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
   This driver requires CONFIG_USB_HID.
 
-  If unsure, say N.
+  If unsure, say Y.
 
 CONFIG_USB_KBD
-  Say Y here if you don't want to use the generic HID driver for your
-  USB keyboard and prefer to use the keyboard in its limited Boot
-  Protocol mode instead. This driver is much smaller than the HID one.
+  Say Y here only if you are absolutely sure that you don't want
+  to use the generic HID driver for your USB keyboard and prefer
+  to use the keyboard in its limited Boot Protocol mode instead.
+
+  This is almost certainly not what you want.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called usbkbd.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-  If unsure, say N.
+  If even remotely unsure, say N.
 
 CONFIG_USB_MOUSE
-  Say Y here if you don't want to use the generic HID driver for your
-  USB mouse and prefer to use the mouse in its limited Boot Protocol
-  mode instead. This driver is much smaller than the HID one.
+  Say Y here only if you are absolutely sure that you don't want
+  to use the generic HID driver for your USB keyboard and prefer
+  to use the keyboard in its limited Boot Protocol mode instead.
+
+  This is almost certainly not what you want.
 
   This code is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called usbmouse.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
-  If unsure, say N.
+  If even remotely unsure, say N.
 
 CONFIG_USB_WACOM
   Say Y here if you want to use the USB version of the Wacom Intuos
@@ -332,7 +347,7 @@
   If in doubt then look at linux/drivers/usb/pegasus.h for the complete
   list of supported devices.
   If your particular adapter is not in the list and you are _sure_ it
-  is Pegasus or Pegasus II based then send me (pmanolov@users.sourceforge.net)
+  is Pegasus or Pegasus II based then send me (petkan@users.sourceforge.net)
   vendor and device IDs.
 
   This code is also available as a module ( = code which can be
@@ -340,6 +355,16 @@
   The module will be called pegasus.o. If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_RTL8150
+  Say Y here if you have RTL8150 based usb-ethernet adapter.
+  Send me (petkan@users.sourceforge.net) any comments you may have.
+  You can also check for updates at http://pegasus2.sourceforge.net/
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called rtl8150.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 CONFIG_USB_KAWETH
   Say Y here if you want to use one of the following 10Mbps only
   USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
@@ -626,3 +651,21 @@
   The module will be called bluetooth.o. If you want to compile it as
   a module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_TIGL
+  If you own a Texas Instruments graphing calculator and use a 
+  TI-GRAPH LINK USB cable (aka SilverLink), then you might be 
+  interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tiglusb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  If you don't know what the SilverLink cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
diff -Nru a/drivers/usb/Config.in b/drivers/usb/Config.in
--- a/drivers/usb/Config.in	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/Config.in	Wed Apr  3 17:11:15 2002
@@ -49,18 +49,19 @@
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
 
    comment 'USB Human Interface Devices (HID)'
+   dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB
    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
+      comment '    Input core support is needed for USB HID input layer or HIDBP support'
    fi
+   dep_mbool '    HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID
+   dep_mbool '    /dev/hiddev raw HID device support' 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
+ 
    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
@@ -88,6 +89,7 @@
       comment '  Networking support is needed for USB Networking device support'
    else
       dep_tristate '  USB Pegasus/Pegasus-II based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+      dep_tristate '  USB RTL8150 based ethernet device support (EXPERIMENTAL)' CONFIG_USB_RTL8150 $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
@@ -101,6 +103,7 @@
    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
+   dep_tristate '  Texas Instruments Graph Link USB (aka SilverLink) cable support' CONFIG_USB_TIGL $CONFIG_USB
 
 fi
 endmenu
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/Makefile	Wed Apr  3 17:11:16 2002
@@ -2,8 +2,6 @@
 # Makefile for the kernel USB device drivers.
 #
 
-# Subdirs.
-
 # The target object and module list name.
 
 O_TARGET	:= usbdrv.o
@@ -14,9 +12,8 @@
 
 # Multipart objects.
 
-list-multi		:= usbcore.o hid.o pwc.o
 usbcore-objs		:= usb.o usb-debug.o hub.o hcd.o
-hid-objs		:= hid-core.o hid-input.o
+hid-objs		:= hid-core.o
 pwc-objs		:= pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o
 
 
@@ -30,6 +27,10 @@
 	hid-objs	+= hiddev.o
 endif
 
+ifeq ($(CONFIG_USB_HIDINPUT),y)
+	hid-objs	+= hid-input.o
+endif
+
 # Object file lists.
 
 obj-y	:=
@@ -76,6 +77,7 @@
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
+obj-$(CONFIG_USB_RTL8150)	+= rtl8150.o
 obj-$(CONFIG_USB_CATC)		+= catc.o
 obj-$(CONFIG_USB_KAWETH)        += kaweth.o
 obj-$(CONFIG_USB_CDCETHER)	+= CDCEther.o
@@ -86,6 +88,7 @@
 obj-$(CONFIG_USB_BLUETOOTH)	+= bluetooth.o
 obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 obj-$(CONFIG_USB_AUERSWALD)	+= auerswald.o
+obj-$(CONFIG_USB_TIGL)		+= tiglusb.o
 
 # Object files in subdirectories
 mod-subdirs	:= serial hcd
@@ -104,14 +107,3 @@
 endif
 
 include $(TOPDIR)/Rules.make
-
-# Link rules for multi-part drivers.
-
-usbcore.o: $(usbcore-objs)
-	$(LD) -r -o $@ $(usbcore-objs)
-
-hid.o: $(hid-objs)
-	$(LD) -r -o $@ $(hid-objs)
-
-pwc.o: $(pwc-objs)
-	$(LD) -r -o $@ $(pwc-objs)
diff -Nru a/drivers/usb/audio.c b/drivers/usb/audio.c
--- a/drivers/usb/audio.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/audio.c	Wed Apr  3 17:11:15 2002
@@ -839,6 +839,7 @@
 		urb->iso_frame_desc[i].length = maxsize;
 		urb->iso_frame_desc[i].offset = offs;
 	}
+	urb->interval = 1;
 	return 0;
 }
 
@@ -938,6 +939,7 @@
 		cp[1] = u->freqn >> 8;
 		cp[2] = u->freqn >> 16;
 	}
+	urb->interval = 1;
 	return 0;
 }
 
diff -Nru a/drivers/usb/catc.c b/drivers/usb/catc.c
--- a/drivers/usb/catc.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/catc.c	Wed Apr  3 17:11:15 2002
@@ -476,7 +476,7 @@
 {
 	struct catc *catc = urb->context;
 	struct ctrl_queue *q;
-	long flags;
+	unsigned long flags;
 
 	if (urb->status)
 		dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length);
@@ -510,7 +510,7 @@
 {
 	struct ctrl_queue *q;
 	int retval = 0;
-	long flags;
+	unsigned long flags;
 
 	spin_lock_irqsave(&catc->ctrl_lock, flags);
 	
diff -Nru a/drivers/usb/devices.c b/drivers/usb/devices.c
--- a/drivers/usb/devices.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/devices.c	Wed Apr  3 17:11:15 2002
@@ -105,8 +105,8 @@
   "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static char *format_endpt =
-/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms */
-  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%3dms\n";
+/* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
+  "E:  Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
 
 
 /*
@@ -166,24 +166,71 @@
 	return (clas_info[ix].class_name);
 }
 
-static char *usb_dump_endpoint_descriptor(char *start, char *end, const struct usb_endpoint_descriptor *desc)
-{
-	char *EndpointType [4] = {"Ctrl", "Isoc", "Bulk", "Int."};
+static char *usb_dump_endpoint_descriptor (
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_endpoint_descriptor *desc
+)
+{
+	char dir, unit, *type;
+	unsigned interval, in, bandwidth = 1;
 
 	if (start > end)
 		return start;
-	start += sprintf(start, format_endpt, desc->bEndpointAddress,
-			 (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL
-			 	? 'B' :			/* bidirectional */
-			 (desc->bEndpointAddress & USB_DIR_IN) ? 'I' : 'O',
-			 desc->bmAttributes, EndpointType[desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK],
-			 desc->wMaxPacketSize, desc->bInterval);
-	return start;
-}
+	in = (desc->bEndpointAddress & USB_DIR_IN);
+	dir = in ? 'I' : 'O';
+	if (speed == USB_SPEED_HIGH) {
+		switch (desc->wMaxPacketSize & (0x03 << 11)) {
+		case 1 << 11:	bandwidth = 2; break;
+		case 2 << 11:	bandwidth = 3; break;
+		}
+	}
 
-static char *usb_dump_endpoint(char *start, char *end, const struct usb_endpoint_descriptor *endpoint)
-{
-	return usb_dump_endpoint_descriptor(start, end, endpoint);
+	/* this isn't checking for illegal values */
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		type = "Ctrl";
+		if (speed == USB_SPEED_HIGH) 	/* uframes per NAK */
+			interval = desc->bInterval;
+		else
+			interval = 0;
+		dir = 'B';			/* ctrl is bidirectional */
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		type = "Isoc";
+		interval = 1 << (desc->bInterval - 1);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		type = "Bulk";
+		if (speed == USB_SPEED_HIGH && !in)	/* uframes per NAK */
+			interval = desc->bInterval;
+		else
+			interval = 0;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		type = "Int.";
+		if (speed == USB_SPEED_HIGH) {
+			interval = 1 << (desc->bInterval - 1);
+		} else
+			interval = desc->bInterval;
+		break;
+	default:	/* "can't happen" */
+		return start;
+	}
+	interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000;
+	if (interval % 1000)
+		unit = 'u';
+	else {
+		unit = 'm';
+		interval /= 1000;
+	}
+
+	start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
+			 desc->bmAttributes, type,
+			 (desc->wMaxPacketSize & 0x07ff) * bandwidth,
+			 interval, unit);
+	return start;
 }
 
 static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
@@ -204,8 +251,13 @@
 	return start;
 }
 
-static char *usb_dump_interface(char *start, char *end, const struct usb_interface *iface, int setno)
-{
+static char *usb_dump_interface(
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_interface *iface,
+	int setno
+) {
 	struct usb_interface_descriptor *desc = &iface->altsetting[setno];
 	int i;
 
@@ -213,7 +265,8 @@
 	for (i = 0; i < desc->bNumEndpoints; i++) {
 		if (start > end)
 			return start;
-		start = usb_dump_endpoint(start, end, desc->endpoint + i);
+		start = usb_dump_endpoint_descriptor(speed,
+				start, end, desc->endpoint + i);
 	}
 	return start;
 }
@@ -238,7 +291,13 @@
 	return start;
 }
 
-static char *usb_dump_config(char *start, char *end, const struct usb_config_descriptor *config, int active)
+static char *usb_dump_config (
+	int speed,
+	char *start,
+	char *end,
+	const struct usb_config_descriptor *config,
+	int active
+)
 {
 	int i, j;
 	struct usb_interface *interface;
@@ -255,7 +314,8 @@
 		for (j = 0; j < interface->num_altsetting; j++) {
 			if (start > end)
 				return start;
-			start = usb_dump_interface(start, end, interface, j);
+			start = usb_dump_interface(speed,
+					start, end, interface, j);
 		}
 	}
 	return start;
@@ -336,8 +396,10 @@
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (start > end)
 			return start;
-		start = usb_dump_config(start, end, dev->config + i,
-					(dev->config + i) == dev->actconfig); /* active ? */
+		start = usb_dump_config(dev->speed,
+				start, end, dev->config + i,
+				/* active ? */
+				(dev->config + i) == dev->actconfig);
 	}
 	return start;
 }
@@ -429,16 +491,27 @@
 	 * count = device count at this level
 	 */
 	/* If this is the root hub, display the bandwidth information */
-	    /* FIXME high speed reserves 20% frametime for non-periodic,
-	     * while full/low speed reserves only 10% ... so this is wrong
-	     * for high speed busses.  also, change how bandwidth is recorded.
-	     */
-	if (level == 0)
-		data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated,
-				FRAME_TIME_MAX_USECS_ALLOC,
-				(100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC,
-			         bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs);
+	if (level == 0) {
+		int	max;
+
+		/* high speed reserves 80%, full/low reserves 90% */
+		if (usbdev->speed == USB_SPEED_HIGH)
+			max = 800;
+		else
+			max = FRAME_TIME_MAX_USECS_ALLOC;
+
+		/* report "average" periodic allocation over a microsecond.
+		 * the schedules are actually bursty, HCDs need to deal with
+		 * that and just compute/report this average.
+		 */
+		data_end += sprintf(data_end, format_bandwidth,
+				bus->bandwidth_allocated, max,
+				(100 * bus->bandwidth_allocated + max / 2)
+					/ max,
+			         bus->bandwidth_int_reqs,
+				 bus->bandwidth_isoc_reqs);
 	
+	}
 	data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev);
 	
 	if (data_end > (pages_start + (2 * PAGE_SIZE) - 256))
diff -Nru a/drivers/usb/hcd/ehci-hcd.c b/drivers/usb/hcd/ehci-hcd.c
--- a/drivers/usb/hcd/ehci-hcd.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hcd/ehci-hcd.c	Wed Apr  3 17:11:15 2002
@@ -89,12 +89,6 @@
 // #define EHCI_VERBOSE_DEBUG
 // #define have_split_iso
 
-#ifdef	CONFIG_DEBUG_SLAB
-#	define	EHCI_SLAB_FLAGS		(SLAB_POISON)
-#else
-#	define	EHCI_SLAB_FLAGS		0
-#endif
-
 /* magic numbers that can affect system performance */
 #define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
 #define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
@@ -197,7 +191,7 @@
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
 	 */
 	ehci->periodic_size = DEFAULT_I_TDPS;
-	if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0)
+	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
 		return retval;
 	hcc_params = readl (&ehci->caps->hcc_params);
 
@@ -214,6 +208,7 @@
 	/* controller state:  unknown --> reset */
 
 	/* EHCI spec section 4.1 */
+	// FIXME require STS_HALT before reset...
 	ehci_reset (ehci);
 	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
@@ -221,16 +216,17 @@
 	/*
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
 	 * be used; it constrains QH/ITD/SITD and QTD locations.
-	 * By default, pci_alloc_consistent() won't hand out addresses
-	 * above 4GB (via pdev->dma_mask) so we know this value.
-	 *
-	 * NOTE:  that pdev->dma_mask setting means that all DMA mappings
-	 * for I/O buffers will have the same restriction, though it's
-	 * neither necessary nor desirable in that case.
+	 * pci_pool consistent memory always uses segment zero.
 	 */
 	if (HCC_64BIT_ADDR (hcc_params)) {
 		writel (0, &ehci->regs->segment);
-		info ("using segment 0 for 64bit DMA addresses ...");
+		/*
+		 * FIXME Enlarge pci_set_dma_mask() when possible.  The DMA
+		 * mapping API spec now says that'll affect only single shot
+		 * mappings, and the pci_pool data will stay safe in seg 0.
+		 * That's what we want:  no extra copies for USB transfers.
+		 */
+		info ("restricting 64bit DMA mappings to segment 0 ...");
 	}
 
 	/* clear interrupt enables, set irq latency */
@@ -240,6 +236,9 @@
 	temp |= 1 << (16 + log2_irq_thresh);
 	// keeping default periodic framelist size
 	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+	// Philips, Intel, and maybe others need CMD_RUN before the
+	// root hub will detect new devices (why?); NEC doesn't
+	temp |= CMD_RUN;
 	writel (temp, &ehci->regs->command);
 	dbg_cmd (ehci, "init", temp);
 
@@ -266,7 +265,7 @@
 	readl (&ehci->regs->command);	/* unblock posted write */
 
         /* PCI Serial Bus Release Number is at 0x60 offset */
-	pci_read_config_byte(hcd->pdev, 0x60, &tempbyte);
+	pci_read_config_byte (hcd->pdev, 0x60, &tempbyte);
 	temp = readw (&ehci->caps->hci_version);
 	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
 	      ((tempbyte & 0xf0)>>4),
@@ -393,6 +392,8 @@
 // restore pci FLADJ value
 	// khubd and drivers will set HC running, if needed;
 	hcd->state = USB_STATE_READY;
+	// FIXME Philips/Intel/... etc don't really have a "READY"
+	// state ... turn on CMD_RUN too
 	for (i = 0; i < ports; i++) {
 		int	temp = readl (&ehci->regs->port_status [i]);
 
diff -Nru a/drivers/usb/hcd/ehci-hub.c b/drivers/usb/hcd/ehci-hub.c
--- a/drivers/usb/hcd/ehci-hub.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hcd/ehci-hub.c	Wed Apr  3 17:11:15 2002
@@ -309,13 +309,6 @@
 					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 -Nru a/drivers/usb/hcd/ehci-mem.c b/drivers/usb/hcd/ehci-mem.c
--- a/drivers/usb/hcd/ehci-mem.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hcd/ehci-mem.c	Wed Apr  3 17:11:15 2002
@@ -224,8 +224,7 @@
 		ehci->periodic [i] = EHCI_LIST_END;
 
 	/* software shadow of hardware table */
-	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *),
-		flags & ~EHCI_SLAB_FLAGS);
+	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *), flags);
 	if (ehci->pshadow == 0) {
 		dbg ("no shadow periodic table");
 		ehci_mem_cleanup (ehci);
diff -Nru a/drivers/usb/hcd/ehci-q.c b/drivers/usb/hcd/ehci-q.c
--- a/drivers/usb/hcd/ehci-q.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/hcd/ehci-q.c	Wed Apr  3 17:11:14 2002
@@ -436,14 +436,6 @@
 
 	if (usb_pipecontrol (urb->pipe)) {
 		/* control request data is passed in the "setup" pid */
-
-		/* NOTE:  this isn't smart about 64bit DMA, since it uses the
-		 * default (32bit) mask rather than using the whole address
-		 * space.  we could set pdev->dma_mask to all-ones while
-		 * getting this mapping, locking it and restoring before
-		 * allocating qtd/qh/... or maybe only do that for the main
-		 * data phase (below).
-		 */
 		qtd->buf_dma = pci_map_single (
 					ehci->hcd.pdev,
 					urb->setup_packet,
@@ -472,7 +464,6 @@
 	 */
 	len = urb->transfer_buffer_length;
 	if (likely (len > 0)) {
-		/* NOTE:  sub-optimal mapping with 64bit DMA (see above) */
 		buf = map_buf = pci_map_single (ehci->hcd.pdev,
 			urb->transfer_buffer, len,
 			usb_pipein (urb->pipe)
diff -Nru a/drivers/usb/hcd/ohci-dbg.c b/drivers/usb/hcd/ohci-dbg.c
--- a/drivers/usb/hcd/ohci-dbg.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/hcd/ohci-dbg.c	Wed Apr  3 17:11:14 2002
@@ -5,7 +5,7 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-dbg.c,v 1.2 2002/01/19 00:15:45 dbrownell Exp $
+ * $Id: ohci-dbg.c,v 1.4 2002/03/27 20:40:40 dbrownell Exp $
  */
  
 /*-------------------------------------------------------------------------*/
@@ -52,7 +52,7 @@
 		int i, len;
 
 		if (usb_pipecontrol (pipe)) {
-			printk (KERN_DEBUG __FILE__ ": cmd(8):");
+			printk (KERN_DEBUG __FILE__ ": setup(8):");
 			for (i = 0; i < 8 ; i++) 
 				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
 			printk ("\n");
diff -Nru a/drivers/usb/hcd/ohci-hcd.c b/drivers/usb/hcd/ohci-hcd.c
--- a/drivers/usb/hcd/ohci-hcd.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/hcd/ohci-hcd.c	Wed Apr  3 17:11:14 2002
@@ -56,7 +56,7 @@
  * v1.0 1999/04/27 initial release
  *
  * This file is licenced under the GPL.
- * $Id: ohci-hcd.c,v 1.7 2002/01/19 00:20:56 dbrownell Exp $
+ * $Id: ohci-hcd.c,v 1.9 2002/03/27 20:41:57 dbrownell Exp $
  */
  
 #include <linux/config.h>
@@ -106,7 +106,7 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "$Revision: 1.7 $"
+#define DRIVER_VERSION "$Revision: 1.9 $"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -153,10 +153,8 @@
 #endif
 	
 	/* every endpoint has a ed, locate and fill it */
-	if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags))) {
-		usb_dec_dev_use (urb->dev);	
+	if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags)))
 		return -ENOMEM;
-	}
 
 	/* for the private part of the URB we need the number of TDs (size) */
 	switch (usb_pipetype (pipe)) {
@@ -181,10 +179,8 @@
 			break;
 		case PIPE_ISOCHRONOUS: /* number of packets from URB */
 			size = urb->number_of_packets;
-			if (size <= 0) {
-				usb_dec_dev_use (urb->dev);	
+			if (size <= 0)
 				return -EINVAL;
-			}
 			for (i = 0; i < urb->number_of_packets; i++) {
   				urb->iso_frame_desc [i].actual_length = 0;
   				urb->iso_frame_desc [i].status = -EXDEV;
@@ -198,10 +194,8 @@
 	/* allocate the private part of the URB */
 	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
 			mem_flags);
-	if (!urb_priv) {
-		usb_dec_dev_use (urb->dev);	
+	if (!urb_priv)
 		return -ENOMEM;
-	}
 	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
 	
 	/* fill the private part of the URB */
@@ -216,7 +210,6 @@
 			urb_priv->length = i;
 			urb_free_priv (ohci, urb_priv);
 			spin_unlock_irqrestore (&ohci->lock, flags);
-			usb_dec_dev_use (urb->dev);	
 			return -ENOMEM;
 		}
 	}	
@@ -242,7 +235,6 @@
 			if (bustime < 0) {
 				urb_free_priv (ohci, urb_priv);
 				spin_unlock_irqrestore (&ohci->lock, flags);
-				usb_dec_dev_use (urb->dev);	
 				return bustime;
 			}
 			usb_claim_bandwidth (urb->dev, urb,
@@ -356,9 +348,6 @@
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 
-#ifdef	OHCI_VERBOSE_DEBUG
-	dbg ("%s: ohci_get_frame", hcd->bus_name);
-#endif
 	return le16_to_cpu (ohci->hcca->frame_no);
 }
 
@@ -445,7 +434,7 @@
  	writel (ohci->hc_control, &ohci->regs->control);
  
 	/* Choose the interrupts we care about now, others later on demand */
-	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
+	mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
 	writel (mask, &ohci->regs->intrstatus);
 	writel (mask, &ohci->regs->intrenable);
 
@@ -517,10 +506,7 @@
 		writel (OHCI_INTR_WDH, &regs->intrenable); 
 	}
   
-	if (ints & OHCI_INTR_SO) {
-		dbg ("USB Schedule overrun");
-		writel (OHCI_INTR_SO, &regs->intrenable); 	 
-	}
+	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
 	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
 	if (ints & OHCI_INTR_SF) { 
diff -Nru a/drivers/usb/hcd/ohci-hub.c b/drivers/usb/hcd/ohci-hub.c
--- a/drivers/usb/hcd/ohci-hub.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/hcd/ohci-hub.c	Wed Apr  3 17:11:14 2002
@@ -5,7 +5,7 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under GPL
- * $Id: ohci-hub.c,v 1.2 2002/01/19 00:21:49 dbrownell Exp $
+ * $Id: ohci-hub.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
  */
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/hcd/ohci-mem.c b/drivers/usb/hcd/ohci-mem.c
--- a/drivers/usb/hcd/ohci-mem.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hcd/ohci-mem.c	Wed Apr  3 17:11:15 2002
@@ -5,7 +5,7 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-mem.c,v 1.2 2002/01/19 00:22:13 dbrownell Exp $
+ * $Id: ohci-mem.c,v 1.3 2002/03/22 16:04:54 dbrownell Exp $
  */
 
 /*-------------------------------------------------------------------------*/
@@ -42,12 +42,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef	CONFIG_DEBUG_SLAB
-#	define OHCI_MEM_FLAGS	SLAB_POISON
-#else
-#	define OHCI_MEM_FLAGS	0
-#endif
- 
 #ifndef CONFIG_PCI
 #	error "usb-ohci currently requires PCI-based controllers"
 	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
@@ -169,14 +163,14 @@
 		sizeof (struct td),
 		32 /* byte alignment */,
 		0 /* no page-crossing issues */,
-		GFP_KERNEL | OHCI_MEM_FLAGS);
+		GFP_KERNEL);
 	if (!ohci->td_cache)
 		return -ENOMEM;
 	ohci->ed_cache = pci_pool_create ("ohci_ed", ohci->hcd.pdev,
 		sizeof (struct ed),
 		16 /* byte alignment */,
 		0 /* no page-crossing issues */,
-		GFP_KERNEL | OHCI_MEM_FLAGS);
+		GFP_KERNEL);
 	if (!ohci->ed_cache) {
 		pci_pool_destroy (ohci->td_cache);
 		return -ENOMEM;
diff -Nru a/drivers/usb/hcd/ohci-q.c b/drivers/usb/hcd/ohci-q.c
--- a/drivers/usb/hcd/ohci-q.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/hcd/ohci-q.c	Wed Apr  3 17:11:16 2002
@@ -5,7 +5,7 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci-q.c,v 1.6 2002/01/19 00:23:15 dbrownell Exp $
+ * $Id: ohci-q.c,v 1.8 2002/03/27 20:57:01 dbrownell Exp $
  */
 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
@@ -54,124 +54,81 @@
 
 /*
  * URB goes back to driver, and isn't reissued.
- * It's completely gone from HC data structures, so no locking
- * is needed ... or desired! (Giveback can call back to hcd.)
+ * It's completely gone from HC data structures.
+ * PRECONDITION:  no locks held  (Giveback can call into HCD.)
  */
-static inline void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+static void finish_urb (struct ohci_hcd *ohci, struct urb *urb)
 {
-	if (urb->hcpriv) {
-		urb_free_priv (ohci, urb->hcpriv);
-		urb->hcpriv = NULL;
-	}
-	usb_hcd_giveback_urb (&ohci->hcd, urb);
-}
-
-static void td_submit_urb (struct urb *urb);
-
-/*
- * URB is reported to driver, is reissued if it's periodic.
- */
-static int return_urb (struct ohci_hcd *hc, struct urb *urb)
-{
-	urb_priv_t	*urb_priv = urb->hcpriv;
-	struct urb	*urbt;
 	unsigned long	flags;
-	int		i;
 
 #ifdef DEBUG
-	if (!urb_priv) {
+	if (!urb->hcpriv) {
 		err ("already unlinked!");
 		BUG ();
 	}
-
-	/* just to be sure */
-	if (!urb->complete) {
-		err ("no completion!");
-		BUG ();
-	}
 #endif
 
+	urb_free_priv (ohci, urb->hcpriv);
+	urb->hcpriv = NULL;
+
+	spin_lock_irqsave (&urb->lock, flags);
+	if (likely (urb->status == -EINPROGRESS))
+		urb->status = 0;
+	spin_unlock_irqrestore (&urb->lock, flags);
+
 #ifdef OHCI_VERBOSE_DEBUG
 	urb_print (urb, "RET", usb_pipeout (urb->pipe));
 #endif
+	usb_hcd_giveback_urb (&ohci->hcd, urb);
+}
+
+static void td_submit_urb (struct urb *urb);
+
+/* Report interrupt transfer completion, maybe reissue */
+static void intr_resub (struct ohci_hcd *hc, struct urb *urb)
+{
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	unsigned long	flags;
 
-	switch (usb_pipetype (urb->pipe)) {
-  		case PIPE_INTERRUPT:
 #ifdef CONFIG_PCI
 // FIXME rewrite this resubmit path.  use pci_dma_sync_single()
 // and requeue more cheaply, and only if needed.
-			pci_unmap_single (hc->hcd.pdev,
-				urb_priv->td [0]->data_dma,
-				urb->transfer_buffer_length,
-				usb_pipeout (urb->pipe)
-					? PCI_DMA_TODEVICE
-					: PCI_DMA_FROMDEVICE);
-#endif
-			/* FIXME: MP race.  If another CPU partially unlinks
-			 * this URB (urb->status was updated, hasn't yet told
-			 * us to dequeue) before we call complete() here, an
-			 * extra "unlinked" completion will be reported...
-			 */
-			urb->complete (urb);
+// Better yet ... abolish the notion of automagic resubmission.
+	pci_unmap_single (hc->hcd.pdev,
+		urb_priv->td [0]->data_dma,
+		urb->transfer_buffer_length,
+		usb_pipeout (urb->pipe)
+			? PCI_DMA_TODEVICE
+			: PCI_DMA_FROMDEVICE);
+#endif
+	/* FIXME: MP race.  If another CPU partially unlinks
+	 * this URB (urb->status was updated, hasn't yet told
+	 * us to dequeue) before we call complete() here, an
+	 * extra "unlinked" completion will be reported...
+	 */
 
-			/* always requeued, but ED_SKIP if complete() unlinks.
-			 * removed from periodic table only at SOF intr.
-			 */
-  			urb->actual_length = 0;
-			if (urb_priv->state != URB_DEL)
-				urb->status = -EINPROGRESS;
-			spin_lock_irqsave (&hc->lock, flags);
-			td_submit_urb (urb);
-			spin_unlock_irqrestore (&hc->lock, flags);
-  			break;
+	spin_lock_irqsave (&urb->lock, flags);
+	if (likely (urb->status == -EINPROGRESS))
+		urb->status = 0;
+	spin_unlock_irqrestore (&urb->lock, flags);
 
-		case PIPE_ISOCHRONOUS:
-			for (urbt = urb->next;
-					urbt && (urbt != urb);
-					urbt = urbt->next)
-				continue;
-			if (urbt) { /* send the reply and requeue URB */	
-#ifdef CONFIG_PCI
-// FIXME rewrite this resubmit path too
-				pci_unmap_single (hc->hcd.pdev,
-					urb_priv->td [0]->data_dma,
-					urb->transfer_buffer_length,
-					usb_pipeout (urb->pipe)
-						? PCI_DMA_TODEVICE
-						: PCI_DMA_FROMDEVICE);
-#endif
-				urb->complete (urb);
-				spin_lock_irqsave (&hc->lock, flags);
-				urb->actual_length = 0;
-  				urb->status = -EINPROGRESS;
-  				urb->start_frame = urb_priv->ed->last_iso + 1;
-  				if (urb_priv->state != URB_DEL) {
-  					for (i = 0; i < urb->number_of_packets;
-							i++) {
-  						urb->iso_frame_desc [i]
-							.actual_length = 0;
-  						urb->iso_frame_desc [i]
-							.status = -EXDEV;
-  					}
-  					td_submit_urb (urb);
-  				}
-// FIXME if not deleted, should have been "finished"
-  				spin_unlock_irqrestore (&hc->lock, flags);
-
-  			} else { /* not reissued */
-				finish_urb (hc, urb);
-			}		
-			break;
+#ifdef OHCI_VERBOSE_DEBUG
+	urb_print (urb, "INTR", usb_pipeout (urb->pipe));
+#endif
+	urb->complete (urb);
 
-		/*
-		 * C/B requests that get here are never reissued.
-		 */
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			finish_urb (hc, urb);
-			break;
-	}
-	return 0;
+	/* always requeued, but ED_SKIP if complete() unlinks.
+	 * EDs are removed from periodic table only at SOF intr.
+	 */
+	urb->actual_length = 0;
+	spin_lock_irqsave (&urb->lock, flags);
+	if (urb_priv->state != URB_DEL)
+		urb->status = -EINPROGRESS;
+	spin_unlock (&urb->lock);
+
+	spin_lock (&hc->lock);
+	td_submit_urb (urb);
+	spin_unlock_irqrestore (&hc->lock, flags);
 }
 
 
@@ -329,6 +286,26 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+	struct ohci_hcd	*ohci,
+	struct ed	*ed,
+	unsigned	index,
+	unsigned	period
+) {
+	for (; index < NUM_INTS; index += period) {
+		__u32	*ed_p = &ohci->hcca->int_table [index];
+
+		while (*ed_p != 0) {
+			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+				*ed_p = ed->hwNextED;		
+				break;
+			}
+			ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED);
+		}
+	}	
+}
+
 /* unlink an ed from one of the HC chains. 
  * just the link to the ed is unlinked.
  * the link from the ed still points to another operational ed or 0
@@ -336,11 +313,7 @@
  */
 static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) 
 {
-	int	int_branch;
 	int	i;
-	int	inter;
-	int	interval;
-	__u32	*ed_p;
 
 	ed->hwINFO |= ED_SKIP;
 
@@ -384,22 +357,9 @@
 		break;
 
 	case PIPE_INTERRUPT:
-		int_branch = ed->int_branch;
-		interval = ed->int_interval;
-
-		for (i = 0; i < ep_rev (6, interval); i += inter) {
-			for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]), inter = 1; 
-				 (*ed_p != 0) && (*ed_p != ed->hwNextED); 
-				ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED), 
-				inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {				
-					if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-			  			*ed_p = ed->hwNextED;		
-			  			break;
-			  		}
-			  }
-		}
-		for (i = int_branch; i < NUM_INTS; i += interval)
-		    ohci->ohci_int_load [i] -= ed->int_load;
+		periodic_unlink (ohci, ed, ed->int_branch, ed->int_interval);
+		for (i = ed->int_branch; i < NUM_INTS; i += ed->int_interval)
+			ohci->ohci_int_load [i] -= ed->int_load;
 #ifdef OHCI_VERBOSE_DEBUG
 		ohci_dump_periodic (ohci, "UNLINK_INT");
 #endif
@@ -412,21 +372,10 @@
 			(dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
 		    		->ed_prev = ed->ed_prev;
 
-		if (ed->ed_prev != NULL) {
+		if (ed->ed_prev != NULL)
 			ed->ed_prev->hwNextED = ed->hwNextED;
-		} else {
-			for (i = 0; i < NUM_INTS; i++) {
-				for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]); 
-						*ed_p != 0; 
-						ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
-					// inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-					if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-						*ed_p = ed->hwNextED;		
-						break;
-					}
-				}
-			}	
-		}	
+		else
+			periodic_unlink (ohci, ed, 0, 1);
 #ifdef OHCI_VERBOSE_DEBUG
 		ohci_dump_periodic (ohci, "UNLINK_ISO");
 #endif
@@ -584,6 +533,12 @@
 		return;
 	}
 
+#if 0
+	/* no interrupt needed except for URB's last TD */
+	if (index != (urb_priv->length - 1))
+		info |= TD_DI;
+#endif
+
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
 	td_pt->hwNextTD = 0;
@@ -660,6 +615,9 @@
 	} else
 		data = 0;
 
+	/* NOTE:  TD_CC is set so we can tell which TDs the HC processed by
+	 * using TD_CC_GET, as well as by seeing them on the done list.
+	 */
 	switch (usb_pipetype (urb->pipe)) {
 		case PIPE_BULK:
 			info = usb_pipeout (urb->pipe)
@@ -726,8 +684,14 @@
 
 		case PIPE_ISOCHRONOUS:
 			for (cnt = 0; cnt < urb->number_of_packets; cnt++) {
-				td_fill (ohci, TD_CC | TD_ISO
-					| ((urb->start_frame + cnt) & 0xffff), 
+				int	frame = urb->start_frame;
+
+				// FIXME scheduling should handle frame counter
+				// roll-around ... exotic case (and OHCI has
+				// a 2^16 iso range, vs other HCs max of 2^10)
+				frame += cnt * urb->interval;
+				frame &= 0xffff;
+				td_fill (ohci, TD_CC | TD_ISO | frame,
 				    data + urb->iso_frame_desc [cnt].offset, 
 				    urb->iso_frame_desc [cnt].length, urb, cnt); 
 			}
@@ -741,50 +705,77 @@
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length (struct td *td)
+/* calculate transfer length/status and update the urb
+ * PRECONDITION:  irqsafe (only for urb->status locking)
+ */
+static void td_done (struct urb *urb, struct td *td)
 {
-	__u32		tdINFO, tdBE, tdCBP;
- 	__u16		tdPSW;
- 	struct urb	*urb = td->urb;
- 	urb_priv_t	*urb_priv = urb->hcpriv;
-	int		dlen = 0;
-	int		cc = 0;
-
-	tdINFO = le32_to_cpup (&td->hwINFO);
-  	tdBE   = le32_to_cpup (&td->hwBE);
-  	tdCBP  = le32_to_cpup (&td->hwCBP);
+	u32	tdINFO = le32_to_cpup (&td->hwINFO);
+	int	cc = 0;
 
 
+	/* ISO ... drivers see per-TD length/status */
   	if (tdINFO & TD_ISO) {
- 		tdPSW = le16_to_cpu (td->hwPSW [0]);
+ 		u16	tdPSW = le16_to_cpu (td->hwPSW [0]);
+		int	dlen = 0;
+
  		cc = (tdPSW >> 12) & 0xF;
-		if (cc < 0xE)  {
-			if (usb_pipeout (urb->pipe)) {
-				dlen = urb->iso_frame_desc [td->index].length;
-			} else {
-				dlen = tdPSW & 0x3ff;
-			}
-			urb->actual_length += dlen;
-			urb->iso_frame_desc [td->index].actual_length = dlen;
-			if (! (urb->transfer_flags & USB_DISABLE_SPD)
-					&& (cc == TD_DATAUNDERRUN))
-				cc = TD_CC_NOERROR;
-
-			urb->iso_frame_desc [td->index].status
-				= cc_to_error [cc];
-		}
-	} else { /* BULK, INT, CONTROL DATA */
-		if (! (usb_pipetype (urb->pipe) == PIPE_CONTROL && 
-				 ((td->index == 0)
-				 || (td->index == urb_priv->length - 1)))) {
- 			if (tdBE != 0) {
-				urb->actual_length += (td->hwCBP == 0)
-					? (tdBE - td->data_dma + 1)
-					: (tdCBP - td->data_dma);
-			}
-  		}
+		if (! ((urb->transfer_flags & USB_DISABLE_SPD)
+				&& (cc == TD_DATAUNDERRUN)))
+			cc = TD_CC_NOERROR;
+
+		if (usb_pipeout (urb->pipe))
+			dlen = urb->iso_frame_desc [td->index].length;
+		else
+			dlen = tdPSW & 0x3ff;
+		urb->actual_length += dlen;
+		urb->iso_frame_desc [td->index].actual_length = dlen;
+		urb->iso_frame_desc [td->index].status = cc_to_error [cc];
+
+		if (cc != 0)
+			dbg ("  urb %p iso TD %d len %d CC %d",
+				urb, td->index, dlen, cc);
+
+	/* BULK, INT, CONTROL ... drivers see aggregate length/status,
+	 * except that "setup" bytes aren't counted and "short" transfers
+	 * might not be reported as errors.
+	 */
+	} else {
+		int	type = usb_pipetype (urb->pipe);
+		u32	tdBE = le32_to_cpup (&td->hwBE);
+
+  		cc = TD_CC_GET (tdINFO);
+
+		/* control endpoints only have soft stalls */
+  		if (type != PIPE_CONTROL && cc == TD_CC_STALL)
+			usb_endpoint_halt (urb->dev,
+				usb_pipeendpoint (urb->pipe),
+				usb_pipeout (urb->pipe));
+
+		/* update packet status if needed (short may be ok) */
+		if (((urb->transfer_flags & USB_DISABLE_SPD) != 0
+				&& cc == TD_DATAUNDERRUN))
+			cc = TD_CC_NOERROR;
+		if (cc != TD_CC_NOERROR) {
+			spin_lock (&urb->lock);
+			if (urb->status == -EINPROGRESS)
+				urb->status = cc_to_error [cc];
+			spin_unlock (&urb->lock);
+		}
+
+		/* count all non-empty packets except control SETUP packet */
+		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
+			if (td->hwCBP == 0)
+				urb->actual_length += tdBE - td->data_dma + 1;
+			else
+				urb->actual_length +=
+					  le32_to_cpup (&td->hwCBP)
+					- td->data_dma;
+		}
+
+		if (cc != 0)
+			dbg ("  urb %p TD %d CC %d, len=%d",
+				urb, td->index, cc, urb->actual_length);
   	}
 }
 
@@ -811,13 +802,16 @@
 
 		if (TD_CC_GET (le32_to_cpup (&td_list->hwINFO))) {
 			urb_priv = (urb_priv_t *) td_list->urb->hcpriv;
-			dbg (" USB-error/status: %x : %p", 
-				TD_CC_GET (le32_to_cpup (&td_list->hwINFO)),
-				td_list);
-			/* typically the endpoint halted too */
+			/* typically the endpoint halts on error; un-halt,
+			 * and maybe dequeue other TDs from this urb
+			 */
 			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
+					dbg ("urb %p TD %d of %d, patch ED",
+						td_list->urb,
+						1 + td_list->index,
+						urb_priv->length);
 					td_list->ed->hwHeadP = 
 			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
 				    & __constant_cpu_to_le32 (TD_MASK))
@@ -870,16 +864,19 @@
 				le32_to_cpup (&td->hwNextTD));
 			if ((urb_priv->state == URB_DEL)) {
 				tdINFO = le32_to_cpup (&td->hwINFO);
+				/* HC may have partly processed this TD */
 				if (TD_CC_GET (tdINFO) < 0xE)
-					dl_transfer_length (td);
+					td_done (urb, td);
 				*td_p = td->hwNextTD | (*td_p
 					& __constant_cpu_to_le32 (0x3));
 
 				/* URB is done; clean up */
-				if (++ (urb_priv->td_cnt) == urb_priv->length)
-// FIXME:  we shouldn't hold ohci->lock here, else the
-// completion function can't talk to this hcd ...
+				if (++ (urb_priv->td_cnt) == urb_priv->length) {
+     					spin_unlock_irqrestore (&ohci->lock,
+						flags);
 					finish_urb (ohci, urb);
+					spin_lock_irqsave (&ohci->lock, flags);
+				}
 			} else {
 				td_p = &td->hwNextTD;
 			}
@@ -931,71 +928,52 @@
 /*-------------------------------------------------------------------------*/
 
 /*
- * process normal completions (error or success) and some unlinked eds
- * this is the main path for handing urbs back to drivers
+ * Process normal completions (error or success) and clean the schedules.
+ *
+ * This is the main path for handing urbs back to drivers.  The only other
+ * path is dl_del_list(), which unlinks URBs by scanning EDs, instead of
+ * scanning the (re-reversed) donelist as this does.
  */
-static void dl_done_list (struct ohci_hcd *ohci, struct td *td_list)
+static void dl_done_list (struct ohci_hcd *ohci, struct td *td)
 {
-  	struct td	*td_list_next = NULL;
-	struct ed	*ed;
-	int		cc = 0;
-	struct urb	*urb;
-	urb_priv_t	*urb_priv;
- 	__u32		tdINFO;
-
- 	unsigned long flags;
-
-  	while (td_list) {
-   		td_list_next = td_list->next_dl_td;
-
-  		urb = td_list->urb;
-  		urb_priv = urb->hcpriv;
-  		tdINFO = le32_to_cpup (&td_list->hwINFO);
-
-   		ed = td_list->ed;
-
-   		dl_transfer_length (td_list);
+	unsigned long	flags;
 
-  		/* error code of transfer */
-  		cc = TD_CC_GET (tdINFO);
-  		if (cc == TD_CC_STALL)
-			usb_endpoint_halt (urb->dev,
-				usb_pipeendpoint (urb->pipe),
-				usb_pipeout (urb->pipe));
+  	spin_lock_irqsave (&ohci->lock, flags);
+  	while (td) {
+		struct td	*td_next = td->next_dl_td;
+		struct urb	*urb = td->urb;
+		urb_priv_t	*urb_priv = urb->hcpriv;
+		struct ed	*ed = td->ed;
+
+		/* update URB's length and status from TD */
+   		td_done (urb, td);
+  		urb_priv->td_cnt++;
+
+		/* If all this urb's TDs are done, call complete().
+		 * Interrupt transfers are the only special case:
+		 * they're reissued, until "deleted" by usb_unlink_urb
+		 * (real work done in a SOF intr, by dl_del_list).
+		 */
+  		if (urb_priv->td_cnt == urb_priv->length) {
+			int	resubmit;
 
-  		if (! (urb->transfer_flags & USB_DISABLE_SPD)
-				&& (cc == TD_DATAUNDERRUN))
-			cc = TD_CC_NOERROR;
+			resubmit = usb_pipeint (urb->pipe)
+					&& (urb_priv->state != URB_DEL);
 
-  		if (++ (urb_priv->td_cnt) == urb_priv->length) {
-			/*
-			 * Except for periodic transfers, both branches do
-			 * the same thing.  Periodic urbs get reissued until
-			 * they're "deleted" (in SOF intr) by usb_unlink_urb.
-			 */
-			if ((ed->state & (ED_OPER | ED_UNLINK))
-					&& (urb_priv->state != URB_DEL)) {
-				spin_lock (&urb->lock);
-				if (urb->status == -EINPROGRESS)
-  					urb->status = cc_to_error [cc];
-				spin_unlock (&urb->lock);
-  				return_urb (ohci, urb);
-  			} else
+     			spin_unlock_irqrestore (&ohci->lock, flags);
+			if (resubmit)
+  				intr_resub (ohci, urb);
+  			else
   				finish_urb (ohci, urb);
+  			spin_lock_irqsave (&ohci->lock, flags);
   		}
 
-  		spin_lock_irqsave (&ohci->lock, flags);
-  		if (ed->state != ED_NEW) { 
-  			u32 edHeadP = ed->hwHeadP;
-
-			/* unlink eds if they are not busy */
-			edHeadP &= __constant_cpu_to_le32 (ED_MASK);
-     			if ((edHeadP == ed->hwTailP) && (ed->state == ED_OPER)) 
-     				ep_unlink (ohci, ed);
-     		}	
-     		spin_unlock_irqrestore (&ohci->lock, flags);
-
-    		td_list = td_list_next;
+		/* clean schedule:  unlink EDs that are no longer busy */
+		if ((ed->hwHeadP & __constant_cpu_to_le32 (TD_MASK))
+					== ed->hwTailP
+				&& (ed->state == ED_OPER)) 
+			ep_unlink (ohci, ed);
+    		td = td_next;
   	}  
+	spin_unlock_irqrestore (&ohci->lock, flags);
 }
-
diff -Nru a/drivers/usb/hcd/ohci.h b/drivers/usb/hcd/ohci.h
--- a/drivers/usb/hcd/ohci.h	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/hcd/ohci.h	Wed Apr  3 17:11:16 2002
@@ -5,7 +5,7 @@
  * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * This file is licenced under the GPL.
- * $Id: ohci.h,v 1.5 2002/01/19 00:24:01 dbrownell Exp $
+ * $Id: ohci.h,v 1.6 2002/03/22 16:04:54 dbrownell Exp $
  */
  
 /*
diff -Nru a/drivers/usb/hcd.c b/drivers/usb/hcd.c
--- a/drivers/usb/hcd.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hcd.c	Wed Apr  3 17:11:15 2002
@@ -37,6 +37,7 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
+#include <linux/completion.h>
 #include <linux/uts.h>			/* for UTS_SYSNAME */
 
 
@@ -169,9 +170,9 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* Configuration descriptor for all our root hubs */
+/* Configuration descriptors for our root hubs */
 
-static const u8 rh_config_descriptor [] = {
+static const u8 fs_rh_config_descriptor [] = {
 
 	/* one configuration */
 	0x09,       /*  __u8  bLength; */
@@ -215,7 +216,54 @@
 	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
  	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
  	0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
-	0x0c        /*  __u8  ep_bInterval; (12ms -- usb 2.0 spec) */
+	0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const u8 hs_rh_config_descriptor [] = {
+
+	/* one configuration */
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19, 0x00, /*  __u16 wTotalLength; */
+	0x01,       /*  __u8  bNumInterfaces; (1) */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+				 Bit 7: Bus-powered,
+				     6: Self-powered,
+				     5 Remote-wakwup,
+				     4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* USB 1.1:
+	 * USB 2.0, single TT organization (mandatory):
+	 *	one interface, protocol 0
+	 *
+	 * USB 2.0, multiple TT organization (optional):
+	 *	two interfaces, protocols 1 (like single TT)
+	 *	and 2 (multiple TT mode) ... config is
+	 *	sometimes settable
+	 *	NOT IMPLEMENTED
+	 */
+
+	/* one interface */
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* one endpoint (status change endpoint) */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+	0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
 };
 
 /*-------------------------------------------------------------------------*/
@@ -333,8 +381,13 @@
 			len = 18;
 			break;
 		case USB_DT_CONFIG << 8:
-			bufp = rh_config_descriptor;
-			len = sizeof rh_config_descriptor;
+			if (hcd->driver->flags & HCD_USB2) {
+				bufp = hs_rh_config_descriptor;
+				len = sizeof hs_rh_config_descriptor;
+			} else {
+				bufp = fs_rh_config_descriptor;
+				len = sizeof fs_rh_config_descriptor;
+			}
 			break;
 		case USB_DT_STRING << 8:
 			urb->actual_length = rh_string (
@@ -428,10 +481,8 @@
 	init_timer (&hcd->rh_timer);
 	hcd->rh_timer.function = rh_report_status;
 	hcd->rh_timer.data = (unsigned long) urb;
-	hcd->rh_timer.expires = jiffies
-		+ (HZ * (urb->interval < 30
-				? 30
-				: urb->interval)) / 1000;
+	/* USB 2.0 spec says 256msec; this is close enough */
+	hcd->rh_timer.expires = jiffies + HZ/4;
 	add_timer (&hcd->rh_timer);
 	return 0;
 }
@@ -1256,8 +1307,29 @@
 
 /*-------------------------------------------------------------------------*/
 
+static void urb_unlink (struct urb *urb)
+{
+	unsigned long		flags;
+	struct usb_device	*dev;
+
+	/* Release any periodic transfer bandwidth */
+	if (urb->bandwidth)
+		usb_release_bandwidth (urb->dev, urb,
+			usb_pipeisoc (urb->pipe));
+
+	/* clear all state linking urb to this dev (and hcd) */
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_del_init (&urb->urb_list);
+	dev = urb->dev;
+	urb->dev = NULL;
+	usb_dec_dev_use (dev);
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+}
+
+
 /* may be called in any context with a valid urb->dev usecount */
-/* caller surrenders "ownership" of urb (and chain at urb->next).  */
+/* caller surrenders "ownership" of urb */
 
 static int hcd_submit_urb (struct urb *urb, int mem_flags)
 {
@@ -1265,13 +1337,14 @@
 	struct usb_hcd		*hcd;
 	struct hcd_dev		*dev;
 	unsigned long		flags;
-	int			pipe, temp;
+	int			pipe, temp, max;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
 
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
+	urb->bandwidth = 0;
 	INIT_LIST_HEAD (&urb->urb_list);
 
 	if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
@@ -1290,7 +1363,62 @@
 			usb_pipeout (pipe)))
 		return -EPIPE;
 
+	/* FIXME there should be a sharable lock protecting us against
+	 * config/altsetting changes and disconnects, kicking in here.
+	 */
+
+	/* Sanity check, so HCDs can rely on clean data */
+	max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+	if (max <= 0) {
+		err ("bogus endpoint (bad maxpacket)");
+		return -EINVAL;
+	}
+
+	/* "high bandwidth" mode, 1-3 packets/uframe? */
+	if (urb->dev->speed == USB_SPEED_HIGH) {
+		int	mult;
+		switch (temp) {
+		case PIPE_ISOCHRONOUS:
+		case PIPE_INTERRUPT:
+			mult = 1 + ((max >> 11) & 0x03);
+			max &= 0x03ff;
+			max *= mult;
+		}
+	}
+
+	/* periodic transfers limit size per frame/uframe */
+	switch (temp) {
+	case PIPE_ISOCHRONOUS: {
+		int	n, len;
+
+		if (urb->number_of_packets <= 0)		    
+			return -EINVAL;
+		for (n = 0; n < urb->number_of_packets; n++) {
+			len = urb->iso_frame_desc [n].length;
+			if (len < 0 || len > max) 
+				return -EINVAL;
+		}
+
+		}
+		break;
+	case PIPE_INTERRUPT:
+		if (urb->transfer_buffer_length > max)
+			return -EINVAL;
+	}
+
+	/* the I/O buffer must usually be mapped/unmapped */
+	if (urb->transfer_buffer_length < 0)
+		return -EINVAL;
+
+	if (urb->next) {
+		warn ("use explicit queuing not urb->next");
+		return -EINVAL;
+	}
+
 #ifdef DEBUG
+	/* stuff that drivers shouldn't do, but which shouldn't
+	 * cause problems in HCDs if they get it wrong.
+	 */
 	{
 	unsigned int	orig_flags = urb->transfer_flags;
 	unsigned int	allowed;
@@ -1315,10 +1443,12 @@
 	}
 	urb->transfer_flags &= allowed;
 
-	/* warn if submitter gave bogus flags */
-	if (urb->transfer_flags != orig_flags)
+	/* fail if submitter gave bogus flags */
+	if (urb->transfer_flags != orig_flags) {
 		err ("BOGUS urb flags, %x --> %x",
 			orig_flags, urb->transfer_flags);
+		return -EINVAL;
+	}
 	}
 #endif
 	/*
@@ -1356,6 +1486,7 @@
 				// NOTE usb and ohci handle up to 2^15
 				temp = 1024;
 			}
+			break;
 		default:
 			return -EINVAL;
 		}
@@ -1365,6 +1496,7 @@
 		urb->interval = temp;
 	}
 
+
 	/*
 	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
 	 * as simple as possible.
@@ -1374,7 +1506,7 @@
 	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
 	// It would catch submission paths for all urbs.
 
-	/* increment the reference count of the urb, as we now also control it. */
+	/* increment urb's reference count, we now control it. */
 	urb = usb_get_urb(urb);
 
 	/*
@@ -1395,20 +1527,22 @@
 		status = -ESHUTDOWN;
 	}
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
+	if (status)
+		return status;
 
-	if (!status) {
-		if (urb->dev == hcd->bus->root_hub)
-			status = rh_urb_enqueue (hcd, urb);
-		else
-			status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	}
-	if (status) {
-		if (urb->dev) {
-			urb->status = status;
-			usb_hcd_giveback_urb (hcd, urb);
-		}
-	}
-	return 0;
+	/* temporarily up refcount while queueing it in the HCD,
+	 * since we report some queuing/setup errors ourselves
+	 */
+	urb = usb_get_urb (urb);
+	if (urb->dev == hcd->bus->root_hub)
+		status = rh_urb_enqueue (hcd, urb);
+	else
+		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+	/* urb->dev got nulled if hcd called giveback for us */
+	if (status && urb->dev)
+		urb_unlink (urb);
+	usb_put_urb (urb);
+	return status;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1424,7 +1558,7 @@
 
 struct completion_splice {		// modified urb context:
 	/* did we complete? */
-	int			done;
+	struct completion	done;
 
 	/* original urb data */
 	void			(*complete)(struct urb *);
@@ -1442,7 +1576,8 @@
 	urb->context = splice->context;
 	urb->complete (urb);
 
-	splice->done = 1;
+	/* then let the synchronous unlink call complete */
+	complete (&splice->done);
 }
 
 /*
@@ -1509,7 +1644,7 @@
 	case PIPE_CONTROL:
 	case PIPE_BULK:
 		if (urb->status != -EINPROGRESS) {
-			retval = 0;
+			retval = -EINVAL;
 			goto done;
 		}
 	}
@@ -1524,7 +1659,7 @@
 			goto done;
 		}
 		/* synchronous unlink: block till we see the completion */
-		splice.done = 0;
+		init_completion (&splice.done);
 		splice.complete = urb->complete;
 		splice.context = urb->context;
 		urb->complete = unlink_complete;
@@ -1550,12 +1685,9 @@
 	if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
 			&& HCD_IS_RUNNING (hcd->state)
 			&& !retval) {
-		while (!splice.done) {
-			set_current_state (TASK_UNINTERRUPTIBLE);
-			schedule_timeout ((2/*msec*/ * HZ) / 1000);
-			dbg ("%s: wait for giveback urb %p",
-				hcd->bus_name, urb);
-		}
+		dbg ("%s: wait for giveback urb %p",
+			hcd->bus_name, urb);
+		wait_for_completion (&splice.done);
 	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
 		return -EINPROGRESS;
 	}
@@ -1656,27 +1788,13 @@
  * and will be reissued.  They should just call their completion handlers
  * until the urb is returned to the device driver by unlinking.
  *
- * In common cases, urb->next will be submitted before the completion
- * function gets called.  That's not done if the URB includes error
- * status (including unlinking).
+ * NOTE that no urb->next processing is done, even for isochronous URBs.
+ * ISO streaming functionality can be achieved by having completion handlers
+ * re-queue URBs.  Such explicit queuing doesn't discard error reports.
  */
 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
 {
-	unsigned long		flags;
-	struct usb_device	*dev;
-
-	/* Release periodic transfer bandwidth */
-	if (urb->bandwidth)
-		usb_release_bandwidth (urb->dev, urb,
-			usb_pipeisoc (urb->pipe));
-
-	/* clear all state linking urb to this dev (and hcd) */
-
-	spin_lock_irqsave (&hcd_data_lock, flags);
-	list_del_init (&urb->urb_list);
-	dev = urb->dev;
-	urb->dev = NULL;
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
+	urb_unlink (urb);
 
 	// NOTE:  a generic device/urb monitoring hook would go here.
 	// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
@@ -1688,24 +1806,7 @@
 		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) {
-		int 	status;
-
-		status = usb_submit_urb (urb->next, GFP_ATOMIC);
-		if (status) {
-			dbg ("urb %p chain fail, %d", urb->next, status);
-			urb->next->status = -ENOTCONN;
-		}
-
-		/* HCDs never modify the urb->next chain, and only use it here,
-		 * so that if urb->complete sees an URB there with -ENOTCONN,
-		 * it knows the driver chained it but it couldn't be submitted.
-		 */
-	}
-
 	/* pass ownership to the completion handler */
-	usb_dec_dev_use (dev);
 	urb->complete (urb);
 	usb_put_urb (urb);
 }
diff -Nru a/drivers/usb/hid-core.c b/drivers/usb/hid-core.c
--- a/drivers/usb/hid-core.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hid-core.c	Wed Apr  3 17:11:15 2002
@@ -46,9 +46,7 @@
 #include <linux/usb.h>
 
 #include "hid.h"
-#ifdef CONFIG_USB_HIDDEV
 #include <linux/hiddev.h>
-#endif
 
 /*
  * Version Information
@@ -1441,10 +1439,8 @@
 
 	if (!hidinput_connect(hid))
 		hid->claimed |= HID_CLAIMED_INPUT;
-#ifdef CONFIG_USB_HIDDEV
 	if (!hiddev_connect(hid))
 		hid->claimed |= HID_CLAIMED_HIDDEV;
-#endif
 
 	if (!hid->claimed) {
 		hid_free_device(hid);
@@ -1483,13 +1479,10 @@
 	usb_unlink_urb(hid->urbout);
 	usb_unlink_urb(hid->urbctrl);
 
-
 	if (hid->claimed & HID_CLAIMED_INPUT)
 		hidinput_disconnect(hid);
-#ifdef CONFIG_USB_HIDDEV
 	if (hid->claimed & HID_CLAIMED_HIDDEV)
 		hiddev_disconnect(hid);
-#endif
 
 	usb_free_urb(hid->urbin);
 	usb_free_urb(hid->urbctrl);
@@ -1516,9 +1509,7 @@
 
 static int __init hid_init(void)
 {
-#ifdef CONFIG_USB_HIDDEV
 	hiddev_init();
-#endif
 	usb_register(&hid_driver);
 	info(DRIVER_VERSION ":" DRIVER_DESC);
 
@@ -1527,9 +1518,7 @@
 
 static void __exit hid_exit(void)
 {
-#ifdef CONFIG_USB_HIDDEV
 	hiddev_exit();
-#endif
 	usb_deregister(&hid_driver);
 }
 
diff -Nru a/drivers/usb/hid.h b/drivers/usb/hid.h
--- a/drivers/usb/hid.h	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/hid.h	Wed Apr  3 17:11:13 2002
@@ -389,10 +389,6 @@
 	struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
-void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_connect(struct hid_device *);
-void hidinput_disconnect(struct hid_device *);
-
 #ifdef DEBUG
 #include "hid-debug.h"
 #else
@@ -403,9 +399,19 @@
 
 #endif
 
+#ifdef CONFIG_USB_HIDINPUT
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
+extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+extern int hidinput_connect(struct hid_device *);
+extern void hidinput_disconnect(struct hid_device *);
+#else
+#define IS_INPUT_APPLICATION(a) (0)
+static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
+static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
+static inline void hidinput_disconnect(struct hid_device *hid) { }
+#endif
 
 int hid_open(struct hid_device *);
 void hid_close(struct hid_device *);
diff -Nru a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c
--- a/drivers/usb/hiddev.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hiddev.c	Wed Apr  3 17:11:15 2002
@@ -341,9 +341,6 @@
 	return 0;
 }
 
-#define GET_TIMEOUT 3
-#define SET_TIMEOUT 3
-
 /*
  * "ioctl" file op
  */
@@ -529,36 +526,12 @@
 		return copy_to_user((void *) arg, &uref, sizeof(uref));
 
 	case HIDIOCGUSAGE:
-		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
-			return -EFAULT;
-
-		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
-			field = hiddev_lookup_usage(hid, &uref);
-			if (field == NULL)
-				return -EINVAL;
-		} else {
-			rinfo.report_type = uref.report_type;
-			rinfo.report_id = uref.report_id;
-			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
-				return -EINVAL;
-
-			if (uref.field_index >= report->maxfield)
-				return -EINVAL;
-
-			field = report->field[uref.field_index];
-			if (uref.usage_index >= field->maxusage)
-				return -EINVAL;
-		}
-
-		uref.value = field->value[uref.usage_index];
-
-		return copy_to_user((void *) arg, &uref, sizeof(uref));
-
 	case HIDIOCSUSAGE:
 		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
 			return -EFAULT;
 
-		if (uref.report_type == HID_REPORT_TYPE_INPUT)
+		if (cmd == HIDIOCSUSAGE &&
+		    uref.report_type != HID_REPORT_TYPE_OUTPUT)
 			return -EINVAL;
 
 		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
@@ -579,7 +552,12 @@
 				return -EINVAL;
 		}
 
-		field->value[uref.usage_index] = uref.value;
+		if (cmd == HIDIOCGUSAGE) {
+			uref.value = field->value[uref.usage_index];
+			return copy_to_user((void *) arg, &uref, sizeof(uref));
+		} else {
+			field->value[uref.usage_index] = uref.value;
+		}
 
 		return 0;
 
diff -Nru a/drivers/usb/hpusbscsi.c b/drivers/usb/hpusbscsi.c
--- a/drivers/usb/hpusbscsi.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/hpusbscsi.c	Wed Apr  3 17:11:16 2002
@@ -129,6 +129,9 @@
 	if (scsi_register_host(&new->ctempl))
 		goto err_out;
 
+	new->sense_command[0] = REQUEST_SENSE;
+	new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
+
 	/* adding to list for module unload */
 	list_add (&hpusbscsi_devices, &new->lh);
 
@@ -379,6 +382,7 @@
 static void  control_interrupt_callback (struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+	u8 scsi_state;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
 	if(unlikely(u->status < 0)) {
@@ -386,10 +390,23 @@
                         handle_usb_error(hpusbscsi);
 		return;
 	}
-	hpusbscsi->srb->result &= SCSI_ERR_MASK;
-	hpusbscsi->srb->result |= hpusbscsi->scsi_state_byte;
 
-	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT)
+	scsi_state = hpusbscsi->scsi_state_byte;
+	if (hpusbscsi->state != HP_STATE_ERROR) {
+		hpusbscsi->srb->result &= SCSI_ERR_MASK;
+		hpusbscsi->srb->result |= scsi_state;
+	}
+
+	if (scsi_state == CHECK_CONDITION << 1) {
+		if (hpusbscsi->state == HP_STATE_WAIT) {
+			issue_request_sense(hpusbscsi);
+		} else {
+			/* we request sense after an eventual data transfer */
+			hpusbscsi->state = HP_STATE_ERROR;
+		}
+	}
+
+	if (hpusbscsi->scallback != NULL && hpusbscsi->state == HP_STATE_WAIT && scsi_state != CHECK_CONDITION <<1 )
 		/* we do a callback to the scsi layer if and only if all data has been transfered */
 		hpusbscsi->scallback(hpusbscsi->srb);
 
@@ -404,6 +421,8 @@
 		hpusbscsi->state = HP_STATE_PREMATURE;
 	TRACE_STATE;
 		break;
+	case HP_STATE_ERROR:
+		break;
 	default:
 		printk(KERN_ERR"hpusbscsi: Unexpected status report.\n");
 	TRACE_STATE;
@@ -432,32 +451,6 @@
 	}
 }
 
-static void request_sense_callback (struct urb *u)
-{
-	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-
-	if (unlikely(u->status<0)) {
-		handle_usb_error(hpusbscsi);
-		return;
-        }
-
-	FILL_BULK_URB(
-		u,
-		hpusbscsi->dev,
-		hpusbscsi->current_data_pipe,
-		hpusbscsi->srb->sense_buffer,
-		SCSI_SENSE_BUFFERSIZE,
-		simple_done,
-		hpusbscsi
-	);
-
-	if (unlikely(0 > usb_submit_urb(u, GFP_ATOMIC))) {
-		handle_usb_error(hpusbscsi);
-		return;
-	}
-	hpusbscsi->state = HP_STATE_WORKING;
-}
-
 static void scatter_gather_callback(struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
@@ -494,7 +487,7 @@
 
         res = usb_submit_urb(u, GFP_ATOMIC);
         if (unlikely(res))
-                hpusbscsi->state = HP_STATE_ERROR;
+                handle_usb_error(hpusbscsi);
 	TRACE_STATE;
 }
 
@@ -509,11 +502,15 @@
         DEBUG("Data transfer done\n");
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (unlikely(u->status < 0))
-			hpusbscsi->state = HP_STATE_ERROR;
-		else
-			hpusbscsi->state = HP_STATE_WAIT;
-		TRACE_STATE;
+		if (unlikely(u->status < 0)) {
+			handle_usb_error(hpusbscsi);
+		} else {
+			if (hpusbscsi->state != HP_STATE_ERROR) {
+				hpusbscsi->state = HP_STATE_WAIT;
+			} else {
+				issue_request_sense(hpusbscsi);
+			}			
+		}
 	} else {
 		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
@@ -550,12 +547,52 @@
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
 		hpusbscsi->state = HP_STATE_WORKING;
 	TRACE_STATE;
-	} else {
-		if (likely(hpusbscsi->scallback != NULL))
-			hpusbscsi->scallback(hpusbscsi->srb);
-		hpusbscsi->state = HP_STATE_FREE;
-	TRACE_STATE;
+	} 
+}
+
+static void request_sense_callback (struct urb *u)
+{
+	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
+
+	if (u->status<0) {
+                handle_usb_error(hpusbscsi);
+		return;
+        }
+
+	FILL_BULK_URB(
+		u,
+		hpusbscsi->dev,
+		hpusbscsi->current_data_pipe,
+		hpusbscsi->srb->sense_buffer,
+		SCSI_SENSE_BUFFERSIZE,
+		simple_done,
+		hpusbscsi
+	);
+
+	if (0 > usb_submit_urb(u, GFP_ATOMIC)) {
+		handle_usb_error(hpusbscsi);
+		return;
 	}
+	if (hpusbscsi->state != HP_STATE_PREMATURE && hpusbscsi->state != HP_STATE_ERROR)
+		hpusbscsi->state = HP_STATE_WORKING;
 }
 
+static void issue_request_sense (struct hpusbscsi *hpusbscsi)
+{
+	FILL_BULK_URB(
+		hpusbscsi->dataurb,
+		hpusbscsi->dev,
+		usb_sndbulkpipe(hpusbscsi->dev, hpusbscsi->ep_out),
+		&hpusbscsi->sense_command,
+		SENSE_COMMAND_SIZE,
+		request_sense_callback,
+		hpusbscsi
+	);
+
+	hpusbscsi->current_data_pipe = usb_rcvbulkpipe(hpusbscsi->dev, hpusbscsi->ep_in);
+
+	if (0 > usb_submit_urb(hpusbscsi->dataurb, GFP_ATOMIC)) {
+		handle_usb_error(hpusbscsi);
+	}
+}
 
diff -Nru a/drivers/usb/hpusbscsi.h b/drivers/usb/hpusbscsi.h
--- a/drivers/usb/hpusbscsi.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/hpusbscsi.h	Wed Apr  3 17:11:14 2002
@@ -4,9 +4,14 @@
 /* large parts based on or taken from code by John Fremlin and Matt Dharm */
 /* this file is licensed under the GPL */
 
+/* A big thanks to Jose for untiring testing */
+
 typedef void (*usb_urb_callback) (struct urb *);
 typedef void (*scsi_callback)(Scsi_Cmnd *);
 
+#define SENSE_COMMAND_SIZE 6
+#define HPUSBSCSI_SENSE_LENGTH 0x16
+
 struct hpusbscsi
 {
         struct list_head lh;
@@ -19,8 +24,9 @@
         struct Scsi_Host *host;
         Scsi_Host_Template ctempl;
         int number;
-       scsi_callback scallback;
-       Scsi_Cmnd *srb;
+	scsi_callback scallback;
+	Scsi_Cmnd *srb;
+	u8 sense_command[SENSE_COMMAND_SIZE];
 
         int use_count;
         wait_queue_head_t pending;
@@ -57,6 +63,7 @@
 static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback);
 static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
 static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
+static void issue_request_sense (struct hpusbscsi *hpusbscsi);
 
 static Scsi_Host_Template hpusbscsi_scsi_host_template = {
 	name:           "hpusbscsi",
@@ -84,5 +91,6 @@
 #define HP_STATE_ERROR             3  /* error has been reported */
 #define HP_STATE_WAIT                 4  /* waiting for status transfer */
 #define HP_STATE_PREMATURE              5 /* status prematurely reported */
+
 
 
diff -Nru a/drivers/usb/hub.c b/drivers/usb/hub.c
--- a/drivers/usb/hub.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/hub.c	Wed Apr  3 17:11:15 2002
@@ -655,11 +655,11 @@
  * Not covered by the spec - but easy to deal with.
  *
  * This implementation uses 400ms minimum debounce timeout and checks
- * every 10ms for transient disconnects to restart the delay.
+ * every 100ms for transient disconnects to restart the delay.
  */
 
 #define HUB_DEBOUNCE_TIMEOUT	400
-#define HUB_DEBOUNCE_STEP	10
+#define HUB_DEBOUNCE_STEP	100
 
 /* return: -1 on error, 0 on success, 1 on disconnect.  */
 static int usb_hub_port_debounce(struct usb_device *hub, int port)
diff -Nru a/drivers/usb/inode.c b/drivers/usb/inode.c
--- a/drivers/usb/inode.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/inode.c	Wed Apr  3 17:11:14 2002
@@ -64,9 +64,9 @@
 {
 	char *curopt = NULL, *value;
 
-	if (data)
-		curopt = strtok(data, ",");
-	for (; curopt; curopt = strtok(NULL, ",")) {
+	while ((curopt = strsep(&data, ",")) != NULL) {
+		if (!*curopt)
+			continue;
 		if ((value = strchr(curopt, '=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(curopt, "devuid")) {
diff -Nru a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
--- a/drivers/usb/kaweth.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/kaweth.c	Wed Apr  3 17:11:16 2002
@@ -124,6 +124,7 @@
 	{ USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ 
 	{ USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ 
 	{ USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
+	{ USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */
 	{ USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ 
 	{ USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
 	{ USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
diff -Nru a/drivers/usb/konicawc.c b/drivers/usb/konicawc.c
--- a/drivers/usb/konicawc.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/konicawc.c	Wed Apr  3 17:11:13 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: konicawc.c,v 1.12 2002/02/07 23:18:53 spse Exp $
+ * $Id$
  *
  * konicawc.c - konica webcam driver
  *
@@ -18,17 +18,18 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
-#define DEBUG
-
 #include "usbvideo.h"
 
 #define MAX_BRIGHTNESS	108
 #define MAX_CONTRAST	108
 #define MAX_SATURATION	108
 #define MAX_SHARPNESS	108
-#define MAX_WHITEBAL	363
+#define MAX_WHITEBAL	372
+#define MAX_SPEED	6
+#define MAX_CAMERAS	1
 
-#define MAX_CAMERAS 1
+#define DRIVER_VERSION	"v1.1"
+#define DRIVER_DESC	"Konica Webcam driver"
 
 enum ctrl_req {
 	SetWhitebal	= 0x01,
@@ -40,7 +41,7 @@
 
 
 enum frame_sizes {
-	SIZE_160X130	= 0,
+	SIZE_160X136	= 0,
 	SIZE_176X144	= 1,
 	SIZE_320X240	= 2,
 };
@@ -53,12 +54,30 @@
 
 static int debug;
 static enum frame_sizes size;	
+static int speed = 6;		/* Speed (fps) 0 (slowest) to 6 (fastest) */
 static int brightness =	MAX_BRIGHTNESS/2;
 static int contrast =	MAX_CONTRAST/2;
 static int saturation =	MAX_SATURATION/2;
 static int sharpness =	MAX_SHARPNESS/2;
 static int whitebal =	3*(MAX_WHITEBAL/4);
 
+static int speed_to_interface[] = { 1, 0, 3, 2, 4, 5, 6 };
+
+/* These FPS speeds are from the windows config box. They are
+ * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
+ * real fps.
+ */
+
+static int speed_to_fps[3][7] = { { 24, 40, 48, 60, 72, 80, 100 },
+				  { 18, 30, 36, 45, 54, 60, 75  },
+				  { 6,  10, 12, 15, 18, 20, 25  } };
+
+
+static int camera_sizes[][2] = { { 160, 136 },
+				 { 176, 144 },
+				 { 320, 240 },
+				 { } /* List terminator */
+};
 
 struct konicawc {
 	u8 brightness;		/* camera uses 0 - 9, x11 for real value */
@@ -66,12 +85,12 @@
 	u8 saturation;		/* as above */
 	u8 sharpness;		/* as above */
 	u8 white_bal;		/* 0 - 33, x11 for real value */
-	u8 fps;			/* Stored as fps * 3 */
+	u8 speed;		/* Stored as 0 - 6, used as index in speed_to_* (above) */
 	u8 size;		/* Frame Size */
 	int height;
 	int width;
-	struct urb *sts_urb[USBVIDEO_NUMFRAMES];
-	u8 sts_buf[USBVIDEO_NUMFRAMES][FRAMES_PER_DESC];
+	struct urb *sts_urb[USBVIDEO_NUMSBUF];
+	u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
 	struct urb *last_data_urb;
 	int lastframe;
 };
@@ -97,19 +116,19 @@
 
 	konicawc_set_misc(uvd, 0x2, 0, 0x0b);
 	dbg("setting brightness to %d (%d)", cam->brightness,
-	    cam->brightness*11);
+	    cam->brightness * 11);
 	konicawc_set_value(uvd, cam->brightness, SetBrightness);
 	dbg("setting white balance to %d (%d)", cam->white_bal,
-	    cam->white_bal*11);
+	    cam->white_bal * 11);
 	konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
 	dbg("setting contrast to %d (%d)", cam->contrast,
-	    cam->contrast*11);
-	konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	    cam->contrast * 11);
+	konicawc_set_value(uvd, cam->contrast, SetContrast);
 	dbg("setting saturation to %d (%d)", cam->saturation,
-	    cam->saturation*11);
+	    cam->saturation * 11);
 	konicawc_set_value(uvd, cam->saturation, SetSaturation);
 	dbg("setting sharpness to %d (%d)", cam->sharpness,
-	    cam->sharpness*11);
+	    cam->sharpness * 11);
 	konicawc_set_value(uvd, cam->sharpness, SetSharpness);
 	dbg("setting size %d", cam->size);
 	switch(cam->size) {
@@ -131,6 +150,30 @@
 }
 
 
+static void konicawc_adjust_picture(uvd_t *uvd)
+{
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	dbg("new brightness: %d", uvd->vpic.brightness);
+	uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
+	if(cam->brightness != uvd->vpic.brightness / 11) {
+	   cam->brightness = uvd->vpic.brightness / 11;
+	   dbg("setting brightness to %d (%d)", cam->brightness,
+	       cam->brightness * 11);
+	   konicawc_set_value(uvd, cam->brightness, SetBrightness);
+	}
+
+	dbg("new contrast: %d", uvd->vpic.contrast);
+	uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
+	if(cam->contrast != uvd->vpic.contrast / 11) {
+		cam->contrast = uvd->vpic.contrast / 11;
+		dbg("setting contrast to %d (%d)", cam->contrast,
+		    cam->contrast * 11);
+		konicawc_set_value(uvd, cam->contrast, SetContrast);
+	}
+}
+
+
 static int konicawc_compress_iso(uvd_t *uvd, struct urb *dataurb, struct urb *stsurb)
 {
 	char *cdata;
@@ -138,7 +181,7 @@
 	unsigned char *status = stsurb->transfer_buffer;
 	int keep = 0, discard = 0, bad = 0;
 	static int buttonsts = 0;
-	
+
 	for (i = 0; i < dataurb->number_of_packets; i++) {
 		int button = buttonsts;
 		unsigned char sts;
@@ -228,7 +271,7 @@
 	int i, len = 0;
 	uvd_t *uvd = urb->context;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
- 
+
 	/* We don't want to do anything if we are about to be removed! */
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return;
@@ -236,7 +279,6 @@
 	if (urb->actual_length > 32) {
 		cam->last_data_urb = urb;
 		return;
-
 	}
 
 	if (!uvd->streaming) {
@@ -244,7 +286,7 @@
 			info("Not streaming, but interrupt!");
 		return;
 	}
-	
+
 	uvd->stats.urb_count++;
 	if (urb->actual_length <= 0)
 		goto urb_done_with;
@@ -329,7 +371,8 @@
 		}
 	}
 
-
+	cam->last_data_urb = NULL;
+	
 	/* Link URBs into a ring so that they invoke each other infinitely */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		if ((i+1) < USBVIDEO_NUMSBUF) {
@@ -362,11 +405,14 @@
 static void konicawc_stop_data(uvd_t *uvd)
 {
 	int i, j;
-	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+	struct konicawc *cam;
 
 	if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
 		return;
 
+	cam = (struct konicawc *)uvd->user_data;
+	cam->last_data_urb = NULL;
+
 	/* Unschedule all of the iso td's */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		j = usb_unlink_urb(uvd->sbuf[i].urb);
@@ -476,9 +522,9 @@
 static int konicawc_calculate_fps(uvd_t *uvd)
 {
 	struct konicawc *t = uvd->user_data;
-	dbg("");
+	dbg("fps = %d", speed_to_fps[t->size][t->speed]/3);
 
-	return (t->fps)/3;
+	return speed_to_fps[t->size][t->speed]/3;
 }
 
 
@@ -515,10 +561,10 @@
 	uvd->vcap.type = VID_TYPE_CAPTURE;
 	uvd->vcap.channels = 1;
 	uvd->vcap.audios = 0;
-	uvd->vcap.maxwidth = cam->width;
-	uvd->vcap.maxheight = cam->height;
-	uvd->vcap.minwidth = cam->width;
-	uvd->vcap.minheight = cam->height;
+	uvd->vcap.minwidth = camera_sizes[cam->size][0];
+	uvd->vcap.minheight = camera_sizes[cam->size][1];
+	uvd->vcap.maxwidth = camera_sizes[cam->size][0];
+	uvd->vcap.maxheight = camera_sizes[cam->size][1];
 
 	memset(&uvd->vchan, 0, sizeof(uvd->vchan));
 	uvd->vchan.flags = 0 ;
@@ -540,7 +586,7 @@
 }
 
 
-static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum ,const struct usb_device_id *devid)
+static void *konicawc_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *devid)
 {
 	uvd_t *uvd = NULL;
 	int i, nas;
@@ -555,6 +601,7 @@
 		return NULL;
 
 	info("Konica Webcam (rev. 0x%04x)", dev->descriptor.bcdDevice);
+	RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
 
 	/* Validate found interface: must have one ISO endpoint */
 	nas = dev->actconfig->interface[ifnum].num_altsetting;
@@ -600,56 +647,58 @@
 				return NULL;
 			}
 		} else {
-			if (actInterface < 0) {
+			if (i == speed_to_interface[speed]) {
+				/* This one is the requested one */
 				actInterface = i;
 				maxPS = endpoint->wMaxPacketSize;
-				if (debug > 0)
-					info("Active setting=%d. maxPS=%d.",
+				if (debug > 0) {
+					info("Selecting requested active setting=%d. maxPS=%d.",
 					     i, maxPS);
-			} else {
-				/* Got another active alt. setting */
-				if (maxPS < endpoint->wMaxPacketSize) {
-					/* This one is better! */
-					actInterface = i;
-					maxPS = endpoint->wMaxPacketSize;
-					if (debug > 0) {
-						info("Even better active setting=%d. maxPS=%d.",
-						     i, maxPS);
-					}
 				}
 			}
 		}
 	}
+	if(actInterface == -1) {
+		err("Cant find required endpoint");
+		return NULL;
+	}
+
 
 	/* Code below may sleep, need to lock module while we are here */
 	MOD_INC_USE_COUNT;
 	uvd = usbvideo_AllocateDevice(cams);
 	if (uvd != NULL) {
-		struct konicawc *konicawc_data = (struct konicawc *)(uvd->user_data);
+		struct konicawc *cam = (struct konicawc *)(uvd->user_data);
 		/* Here uvd is a fully allocated uvd_t object */
-
 		for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
-			konicawc_data->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+			cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
+			if(cam->sts_urb[i] == NULL) {
+				while(i--) {
+					usb_free_urb(cam->sts_urb[i]);
+				}
+				err("cant allocate urbs");
+				return NULL;
+			}
 		}
-
+		cam->speed = speed;
 		switch(size) {
-		case SIZE_160X130:
+		case SIZE_160X136:
 		default:
-			konicawc_data->height = 136;
-			konicawc_data->width = 160;
-			konicawc_data->size = SIZE_160X130;
+			cam->height = 136;
+			cam->width = 160;
+			cam->size = SIZE_160X136;
 			break;
 
 		case SIZE_176X144:
-			konicawc_data->height = 144;
-			konicawc_data->width = 176;
-			konicawc_data->size = SIZE_176X144;
+			cam->height = 144;
+			cam->width = 176;
+			cam->size = SIZE_176X144;
 			break;
 
 		case SIZE_320X240:
-			konicawc_data->height = 240;
-			konicawc_data->width = 320;
-			konicawc_data->size = SIZE_320X240;
+			cam->height = 240;
+			cam->width = 320;
+			cam->size = SIZE_320X240;
 			break;
 		}
 
@@ -663,14 +712,14 @@
 		uvd->iso_packet_len = maxPS;
 		uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
 		uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
-		uvd->canvas = VIDEOSIZE(konicawc_data->width, konicawc_data->height);
+		uvd->canvas = VIDEOSIZE(cam->width, cam->height);
 		uvd->videosize = uvd->canvas;
 
 		/* Initialize konicawc specific data */
 		konicawc_configure_video(uvd);
 
 		i = usbvideo_RegisterVideoDevice(uvd);
-		uvd->max_frame_size = (konicawc_data->width * konicawc_data->height * 3)/2;
+		uvd->max_frame_size = (cam->width * cam->height * 3)/2;
 		if (i != 0) {
 			err("usbvideo_RegisterVideoDevice() failed.");
 			uvd = NULL;
@@ -681,9 +730,28 @@
 }
 
 
+static void konicawc_free_uvd(uvd_t *uvd)
+{
+	int i;
+	struct konicawc *cam = (struct konicawc *)uvd->user_data;
+
+	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+		usb_free_urb(cam->sts_urb[i]);
+		cam->sts_urb[i] = NULL;
+	}
+}
+
+
+static struct usb_device_id id_table[] = {
+	{ USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
+	{ }  /* Terminating entry */
+};
+
+
 static int __init konicawc_init(void)
 {
 	usbvideo_cb_t cbTbl;
+	info(DRIVER_DESC " " DRIVER_VERSION);
 	memset(&cbTbl, 0, sizeof(cbTbl));
 	cbTbl.probe = konicawc_probe;
 	cbTbl.setupOnOpen = konicawc_setup_on_open;
@@ -691,6 +759,8 @@
 	cbTbl.getFPS = konicawc_calculate_fps;
 	cbTbl.startDataPump = konicawc_start_data;
 	cbTbl.stopDataPump = konicawc_stop_data;
+	cbTbl.adjustPicture = konicawc_adjust_picture;
+	cbTbl.userFree = konicawc_free_uvd;
 	return usbvideo_register(
 		&cams,
 		MAX_CAMERAS,
@@ -706,19 +776,14 @@
 	usbvideo_Deregister(&cams);
 }
 
-#if defined(usb_device_id_ver)
-
-static __devinitdata struct usb_device_id id_table[] = {
-	{ USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
-	{ }  /* Terminating entry */
-};
 
 MODULE_DEVICE_TABLE(usb, id_table);
-#endif /* defined(usb_device_id_ver) */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION("Konica Webcam driver");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(speed, "i");
+MODULE_PARM_DESC(speed, "FPS speed: 0 (slowest) - 6 (fastest)");
 MODULE_PARM(size, "i");
 MODULE_PARM_DESC(size, "Frame Size 0: 160x136 1: 176x144 2: 320x240");
 MODULE_PARM(brightness, "i");
diff -Nru a/drivers/usb/pegasus.c b/drivers/usb/pegasus.c
--- a/drivers/usb/pegasus.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/pegasus.c	Wed Apr  3 17:11:16 2002
@@ -59,7 +59,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.5.1 (2002/03/06)"
+#define DRIVER_VERSION "v0.5.2 (2002/03/21)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
@@ -487,10 +487,10 @@
 	pegasus_t *pegasus = dev->priv;
 
 
-	if ( read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) 
-		return 1;
-	if ( !(bmsr & 0x20) && !loopback ) 
-		warn( "%s: link NOT established (0x%x) - check the cable.",
+	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &bmsr);
+	if ( !(bmsr & 4) && !loopback )
+		warn( "%s: link NOT established (%04x) - check the cable.",
 			dev->name, bmsr );
 	if ( read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart) )
 		return 2;
@@ -741,6 +741,7 @@
 	pegasus_t *pegasus = (pegasus_t *)net->priv;
 	int	res;
 
+	down(&pegasus->sem);
 	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
@@ -759,11 +760,15 @@
 	pegasus->flags |= PEGASUS_RUNNING;
 	if ( (res = enable_net_traffic(net, pegasus->usb)) ) {
 		err("can't enable_net_traffic() - %d", res);
-		return -EIO;
+		res = -EIO;
+		goto exit;
 	}
 	set_carrier(net);
+	res = 0;
+exit:
+	up(&pegasus->sem);
 
-	return 0;
+	return res;
 }
 
 
@@ -771,6 +776,7 @@
 {
 	pegasus_t	*pegasus = net->priv;
 
+	down(&pegasus->sem);
 	pegasus->flags &= ~PEGASUS_RUNNING;
 	netif_stop_queue( net );
 	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
@@ -782,6 +788,7 @@
 #ifdef	PEGASUS_USE_INTR
 	usb_unlink_urb( pegasus->intr_urb );
 #endif
+	up(&pegasus->sem);
 
 	return 0;
 }
@@ -868,23 +875,32 @@
 {
 	__u16 *data = (__u16 *)&rq->ifr_data;
 	pegasus_t	*pegasus = net->priv;
+	int	res;
 
+	down(&pegasus->sem);
 	switch(cmd) {
 	case SIOCETHTOOL:
-		return pegasus_ethtool_ioctl(net, rq->ifr_data);
+		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
+		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
 	case SIOCDEVPRIVATE+1:
 		read_mii_word(pegasus, data[0], data[1]&0x1f, &data[3]);
-		return 0;
+		res = 0;
+		break;
 	case SIOCDEVPRIVATE+2:
-		if ( !capable(CAP_NET_ADMIN) )
+		if ( !capable(CAP_NET_ADMIN) ) {
+			up(&pegasus->sem);
 			return -EPERM;
+		}
 		write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]);
-		return 0;
+		res = 0;
+		break;
 	default:
-		return -EOPNOTSUPP;
+		res = -EOPNOTSUPP;
 	}
+	up(&pegasus->sem);
+	return res;
 }
 
 
@@ -953,7 +969,6 @@
 		err("usb_set_configuration() failed");
 		return NULL;
 	}
-
 	if(!(pegasus = kmalloc(sizeof(struct pegasus), GFP_KERNEL))) {
 		err("out of memory allocating device structure");
 		return NULL;
@@ -997,9 +1012,11 @@
 		usb_free_urb (pegasus->rx_urb);
 		usb_free_urb (pegasus->ctrl_urb);
 		kfree( pegasus );
-		return	NULL;
+		return NULL;
 	}
-	
+
+	init_MUTEX(&pegasus->sem);
+	down(&pegasus->sem);
 	pegasus->usb = dev;
 	pegasus->net = net;
 	SET_MODULE_OWNER(net);
@@ -1027,7 +1044,7 @@
 		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
-		return NULL;
+		goto exit;
 	}
 
 	info( "%s: %s", net->name, usb_dev_id[dev_index].name );
@@ -1044,7 +1061,8 @@
 		warn( "can't locate MII phy, using default" );
 		pegasus->phy = 1;
 	}
-
+exit:
+	up(&pegasus->sem);
 	return pegasus;
 }
 
diff -Nru a/drivers/usb/pegasus.h b/drivers/usb/pegasus.h
--- a/drivers/usb/pegasus.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/pegasus.h	Wed Apr  3 17:11:15 2002
@@ -101,7 +101,7 @@
 	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
-	struct semaphore	ctrl_sem;
+	struct semaphore	sem;
 	unsigned char		rx_buff[PEGASUS_MAX_MTU];
 	unsigned char		tx_buff[PEGASUS_MAX_MTU];
 	unsigned char		intr_buff[8];
diff -Nru a/drivers/usb/printer.c b/drivers/usb/printer.c
--- a/drivers/usb/printer.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/printer.c	Wed Apr  3 17:11:14 2002
@@ -193,7 +193,14 @@
 	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
 	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
 	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+	{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
+	{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */   
+	{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */   
+	{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
 	{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
+	{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
+	{ 0x0409, 0xf0be, USBLP_QUIRK_BIDIR }, /* NEC Picty920 (HP OEM) */
+	{ 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */
 	{ 0, 0 }
 };
 
diff -Nru a/drivers/usb/rtl8150.c b/drivers/usb/rtl8150.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/rtl8150.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2002 Petko Manolov (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 the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.5.0 (2002/03/28)"
+#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
+#define DRIVER_DESC "rtl8150 based usb-ethernet driver"
+
+
+#define	IRD			0x0120
+#define	MAR			0x0126
+#define	CR			0x012e
+#define	TCR			0x012f
+#define	RCR			0x0130
+#define	TSR			0x0132
+#define	RSR			0x0133
+#define	CON0			0x0135
+#define	CON1			0x0136
+#define	MSR			0x0137
+#define	PHYADD			0x0138
+#define	PHYDAT			0x0139
+#define	PHYCNT			0x013b
+#define	GPPC			0x013d
+#define	BMCR			0x0140
+#define	BMSR			0x0142
+#define	ANAR			0x0144
+#define	ANLP			0x0146
+#define	AER			0x0148
+
+#define	PHY_READ		0
+#define	PHY_WRITE		0x20
+#define	PHY_GO			0x40
+
+#define	RTL8150_REQT_READ	0xc0
+#define	RTL8150_REQT_WRITE	0x40
+#define	RTL8150_REQ_GET_REGS	0x05
+#define	RTL8150_REQ_SET_REGS	0x05
+
+#define	RTL8150_MTU		1500
+#define	RTL8150_MAX_MTU		1536
+
+#define	RTL8150_TX_TIMEOUT	(HZ)
+
+/* rtl8150 flags */
+#define	RTL8150_FLAG_HWCRC	0
+#define	RX_REG_SET		1
+#define	RTL8150_UNPLUG		2
+
+
+/* Define these values to match your device */
+#define VENDOR_ID_REALTEK		0x0bda
+#define PRODUCT_ID_RTL8150		0x8150
+
+/* table of devices that work with this driver */
+static struct usb_device_id rtl8150_table [] = {
+	{ USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8150) },
+	{ }				
+};
+
+MODULE_DEVICE_TABLE (usb, rtl8150_table);
+
+
+struct rtl8150 {
+	unsigned int		flags;
+	struct usb_device	*udev;
+	struct usb_interface	*interface;
+	struct semaphore	sem;
+	struct net_device_stats	stats;
+	struct net_device	*netdev;
+	struct urb		*rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+	struct usb_ctrlrequest	dr;
+	int			intr_interval;
+	u16			rx_creg;
+	u8			rx_buff[RTL8150_MAX_MTU];
+	u8			tx_buff[RTL8150_MAX_MTU];
+	u8			intr_buff[8];
+	u8			phy;
+};
+
+typedef	struct rtl8150	rtl8150_t;
+
+
+/* the global usb devfs handle */
+extern devfs_handle_t usb_devfs_handle;
+unsigned long multicast_filter_limit = 32;
+
+
+static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
+static void * rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id);
+
+
+static struct usb_driver rtl8150_driver = {
+	name:		"rtl8150",
+	probe:		rtl8150_probe,
+	disconnect:	rtl8150_disconnect,
+	id_table:	rtl8150_table,
+};
+
+
+
+/*
+**
+**	device related part of the code
+**
+*/
+static int get_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+	return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev,0),
+				RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
+				indx, 0, data, size, HZ/2);
+}
+
+
+static int set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+	return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev,0),
+				RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
+				indx, 0, data, size, HZ/2);
+}
+
+
+static void ctrl_callback(struct urb *urb)
+{
+	rtl8150_t	*dev;
+	
+	switch (urb->status) {
+	case 0:
+		break;
+	case -EINPROGRESS:
+		break;
+	case -ENOENT:
+		break;
+	default:
+		warn("ctrl urb status %d", urb->status);
+	}
+	dev = urb->context;
+	clear_bit(RX_REG_SET, &dev->flags);
+}
+
+
+static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, void *data)
+{
+	int	ret;
+
+	if (test_bit(RX_REG_SET, &dev->flags))
+		return -EAGAIN;
+	
+	dev->dr.bRequestType = RTL8150_REQT_WRITE;
+	dev->dr.bRequest = RTL8150_REQ_SET_REGS;
+	dev->dr.wValue = cpu_to_le16(indx);
+	dev->dr.wIndex = 0;
+	dev->dr.wLength = cpu_to_le16(size);
+	dev->ctrl_urb->transfer_buffer_length = size;
+	FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev,0),
+	                 (char*)&dev->dr, &dev->rx_creg, size,
+	                 ctrl_callback, dev);
+	if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+		err("control request submission failed: %d", ret);
+	else
+		set_bit(RX_REG_SET, &dev->flags);
+
+	return ret;
+}
+
+
+static int read_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 *reg)
+{
+	int	i;
+	u8	data[3], tmp;
+
+	data[0] = phy;
+	data[1] = data[2] = 0;
+	tmp = indx | PHY_READ | PHY_GO;
+	i = 0;
+
+	set_registers(dev, PHYADD, sizeof(data), data);
+	set_registers(dev, PHYCNT, 1, &tmp);
+	do {
+		get_registers(dev, PHYCNT, 1, data);
+	} while ((data[0] & PHY_GO) && (i++ < HZ));
+
+	if (i < HZ) {
+		get_registers(dev, PHYDAT, 2, data);
+		*reg = le16_to_cpup(data);
+		return 0;
+	} else
+		return 1;
+}
+
+
+static int write_mii_word(rtl8150_t *dev, u8 phy, __u8 indx, u16 reg)
+{
+	int	i;
+	u8	data[3], tmp;
+
+	data[0] = phy;
+	*(data + 1) = cpu_to_le16p(&reg);
+	tmp = indx | PHY_WRITE | PHY_GO;
+	i = 0;
+
+	set_registers(dev, PHYADD, sizeof(data), data);
+	set_registers(dev, PHYCNT, 1, &tmp);
+	do {
+		get_registers(dev, PHYCNT, 1, data);
+	} while((data[0] & PHY_GO) && (i++ < HZ));
+
+	if (i < HZ)
+		return 0;
+	else
+		return 1;
+}
+
+
+static inline void set_ethernet_addr(rtl8150_t *dev)
+{
+	u8	node_id[6];
+
+	get_registers(dev, IRD, sizeof(node_id), node_id);
+	memcpy(dev->netdev->dev_addr, node_id, sizeof(node_id));
+}
+
+
+static int rtl8150_reset(rtl8150_t *dev)
+{
+	u8	data=0x10;
+	int	i=HZ;
+
+	set_registers(dev, CR, 1, &data);
+	do {
+		get_registers(dev, CR, 1, &data);
+	} while ((data & 0x10) && --i);
+	
+	return (i > 0) ? 0 : -1;
+}
+
+
+static int alloc_all_urbs(rtl8150_t *dev)
+{
+	dev->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->rx_urb)
+		return 0;
+	dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->tx_urb) {
+		usb_free_urb(dev->rx_urb);
+		return 0;
+	}
+	dev->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->intr_urb) {
+		usb_free_urb(dev->rx_urb);
+		usb_free_urb(dev->tx_urb);
+		return 0;
+	}
+	dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!dev->intr_urb) {
+		usb_free_urb(dev->rx_urb);
+		usb_free_urb(dev->tx_urb);
+		usb_free_urb(dev->intr_urb);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void free_all_urbs(rtl8150_t *dev)
+{
+	usb_free_urb(dev->rx_urb);
+	usb_free_urb(dev->tx_urb);
+	usb_free_urb(dev->intr_urb);
+	usb_free_urb(dev->ctrl_urb);
+}
+
+
+static void unlink_all_urbs(rtl8150_t *dev)
+{
+	usb_unlink_urb(dev->rx_urb);
+	usb_unlink_urb(dev->tx_urb);
+	usb_unlink_urb(dev->intr_urb);
+	usb_unlink_urb(dev->ctrl_urb);
+}
+
+
+static void read_bulk_callback(struct urb *urb)
+{
+	rtl8150_t	*dev;
+	unsigned	pkt_len, res;
+	struct sk_buff	*skb;
+	struct net_device *netdev;
+	u16		rx_stat;
+
+	dev = urb->context;
+	if (!dev) {
+		warn("!dev");
+		return;
+	}
+	netdev = dev->netdev;
+	if (!netif_device_present(netdev)) {
+		warn("netdev is not present");
+		return;
+	}
+	switch (urb->status) {
+	case 0:
+		break;
+	case -ENOENT:
+		return;
+	case -ETIMEDOUT:
+		warn("reset needed may be?..");
+		goto goon;
+	default:
+		warn("Rx status %d", urb->status);
+		goto goon;
+	}
+
+	res = urb->actual_length;
+	rx_stat = le16_to_cpu(*(short*)(dev->rx_buff + res - 4));
+	pkt_len = res - 4;
+
+	if (!(skb = dev_alloc_skb(pkt_len + 2))) 
+		goto goon;
+	skb->dev = netdev;
+	skb_reserve(skb, 2);
+	eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0);
+	skb_put(skb, pkt_len);
+	skb->protocol = eth_type_trans(skb, netdev);
+	netif_rx(skb);
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += pkt_len;
+goon:
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
+	              dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res=usb_submit_urb(dev->rx_urb, GFP_ATOMIC)))
+		warn("%s: Rx urb submission failed %d", netdev->name, res);
+}
+
+
+static void write_bulk_callback(struct urb *urb)
+{
+	rtl8150_t	*dev;
+
+	dev = urb->context;
+	if (!dev)
+		return;
+	if (!netif_device_present(dev->netdev))
+		return;
+	if (urb->status)
+		info("%s: Tx status %d", dev->netdev->name, urb->status);
+	dev->netdev->trans_start = jiffies;
+	netif_wake_queue(dev->netdev);
+}
+
+
+void intr_callback(struct urb *urb)
+{
+	rtl8150_t	*dev;
+
+	dev = urb->context;
+	if (!dev)
+		return;
+	switch (urb->status) {
+		case 0:
+			break;
+		case -ENOENT:
+			return;
+		default:
+			info("%s: intr status %d", dev->netdev->name,
+			     urb->status);
+	}
+}
+
+
+/*
+**
+**	network related part of the code
+**
+*/
+
+
+static int enable_net_traffic(rtl8150_t *dev)
+{
+	u8	cr, tcr, rcr, msr;
+
+	if (rtl8150_reset(dev)) {
+		warn("%s - device reset failed", __FUNCTION__);
+	}
+	dev->rx_creg = rcr = 0x9e;	/* bit7=1 attach Rx info at the end */
+	tcr = 0xd8;		/* bit0=1 no CRC at the end of the frame */
+	cr = 0x0c;
+	set_registers(dev, RCR, 1, &rcr);
+	set_registers(dev, TCR, 1, &tcr);
+	set_registers(dev, CR, 1, &cr);
+	get_registers(dev, MSR, 1, &msr);
+
+	return 0;
+}
+
+
+static void disable_net_traffic(rtl8150_t *dev)
+{
+	u8	cr;
+
+	get_registers(dev, CR, 1, &cr);
+	cr &= 0xf3;
+	set_registers(dev, CR, 1, &cr);
+}
+
+
+static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
+{
+	return &((rtl8150_t *)dev->priv)->stats;
+}
+
+
+static void rtl8150_tx_timeout(struct net_device *netdev)
+{
+	rtl8150_t	*dev;
+
+	dev = netdev->priv;
+	if (!dev)
+		return;
+	warn("%s: Tx timeout.", netdev->name);
+	dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb(dev->tx_urb);
+	dev->stats.tx_errors++;
+}
+
+
+static void rtl8150_set_multicast(struct net_device *netdev)
+{
+	rtl8150_t	*dev;
+
+	dev = netdev->priv;
+	netif_stop_queue(netdev);
+	if (netdev->flags & IFF_PROMISC) {
+		dev->rx_creg |= 0x0001;
+		info("%s: promiscuous mode", netdev->name);
+	} else if ((netdev->mc_count > multicast_filter_limit) ||
+	           (netdev->flags & IFF_ALLMULTI)) {
+		dev->rx_creg &= 0xfffe;
+		dev->rx_creg |= 0x0002;
+		info("%s: allmulti set", netdev->name);
+	} else {
+		/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
+		dev->rx_creg &= 0x00fc;
+	}
+	async_set_registers(dev, RCR, 2, &dev->rx_creg);
+	netif_wake_queue(netdev);
+}
+
+
+static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	rtl8150_t	*dev;
+	int		count, res;
+
+	netif_stop_queue(netdev);
+	dev = netdev->priv;
+	count = (skb->len < 60) ? 60 : skb->len;
+	count = (count & 0x3f) ? count : count + 1;
+	memcpy(dev->tx_buff, skb->data, skb->len);
+	FILL_BULK_URB(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev,2),
+		      dev->tx_buff, RTL8150_MAX_MTU, write_bulk_callback, dev);
+	dev->tx_urb->transfer_buffer_length = count;
+
+	if ((res = usb_submit_urb(dev->tx_urb, GFP_KERNEL))) {
+		warn("failed tx_urb %d\n", res);
+		dev->stats.tx_errors++;
+		netif_start_queue(netdev);
+	} else {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+		netdev->trans_start = jiffies;
+	}
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+
+static int rtl8150_open(struct net_device *netdev)
+{
+	rtl8150_t	*dev;
+	int		res;
+	
+	dev = netdev->priv;
+	if (dev == NULL) {
+		return -ENODEV;
+	}
+
+	down(&dev->sem);
+	FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev,1),
+			dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev);
+	if ((res=usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+		warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+	FILL_INT_URB(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev,3),
+			dev->intr_buff, sizeof(dev->intr_buff), intr_callback,
+			dev, dev->intr_interval);
+	if ((res=usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+		warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
+	netif_start_queue(netdev);
+	enable_net_traffic(dev);
+	up(&dev->sem);
+
+	return res;
+}
+
+
+static int rtl8150_close(struct net_device *netdev)
+{
+	rtl8150_t *dev;
+	int res = 0;
+
+	dev = netdev->priv;
+	if (!dev)
+		return -ENODEV;
+
+	down(&dev->sem);
+	if (!test_bit(RTL8150_UNPLUG, &dev->flags))
+		disable_net_traffic(dev);
+	unlink_all_urbs(dev);
+	netif_stop_queue(netdev);
+	up(&dev->sem);
+
+
+	return res;
+}
+
+
+static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
+{
+	rtl8150_t	*dev;
+	int		cmd;
+	char		tmp[128];
+
+	dev = netdev->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", dev->udev->bus->busnum,
+		        dev->udev->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 = dev->phy;
+		get_registers(dev, BMCR, 2, &bmcr);
+		get_registers(dev, ANLP, 2, &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 -ENOTSUPP;
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+
+		edata.data = netif_carrier_ok(netdev);
+		if (copy_to_user(uaddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+
+static int rtl8150_ioctl (struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	rtl8150_t *dev;
+	u16	*data;
+	int	res;
+
+	dev = netdev->priv;
+	data = (u16 *)&rq->ifr_data;
+	res = 0;
+
+	down(&dev->sem);
+	switch (cmd) {
+	case SIOCETHTOOL:
+		res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
+		break;
+	case SIOCDEVPRIVATE:
+		data[0] = dev->phy;
+	case SIOCDEVPRIVATE+1:
+		read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]);
+		break;
+	case SIOCDEVPRIVATE+2:
+		if (!capable(CAP_NET_ADMIN)) {
+			up(&dev->sem);
+			return -EPERM;
+		}
+		write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]);
+		break;
+	default:
+		res = -EOPNOTSUPP;
+	}
+	up(&dev->sem);
+	return res;
+}
+
+
+static void * rtl8150_probe(struct usb_device *udev, unsigned int ifnum,
+			    const struct usb_device_id *id)
+{
+	rtl8150_t *dev;
+	struct net_device *netdev;
+
+	udev->config[0].bConfigurationValue = 1;
+	if (usb_set_configuration(udev, udev->config[0].bConfigurationValue)) {
+		err("usb_set_configuration() failed");
+		return NULL;
+	}
+	if ((udev->descriptor.idVendor != VENDOR_ID_REALTEK) ||
+	    (udev->descriptor.idProduct != PRODUCT_ID_RTL8150)) {
+	    	err("Not the one we are interested about");
+		return NULL;
+	}
+	dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
+	if (!dev) {
+		err ("Out of memory");
+		goto exit;
+	} else
+		memset(dev, 0, sizeof(rtl8150_t));
+
+	netdev = init_etherdev(NULL, 0);
+	if (!netdev) {
+		kfree(dev);
+		err("Oh boy, out of memory again?!?");
+		dev = NULL;
+		goto exit;
+	}
+		
+	init_MUTEX(&dev->sem);
+	dev->udev = udev;
+	dev->netdev = netdev;
+	SET_MODULE_OWNER(netdev);
+	netdev->priv = dev;
+	netdev->open = rtl8150_open;
+	netdev->stop = rtl8150_close;
+	netdev->do_ioctl = rtl8150_ioctl;
+	netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
+	netdev->tx_timeout = rtl8150_tx_timeout;
+	netdev->hard_start_xmit = rtl8150_start_xmit;
+	netdev->set_multicast_list = rtl8150_set_multicast;
+	netdev->get_stats = rtl8150_netdev_stats;
+	netdev->mtu = RTL8150_MTU;
+	dev->intr_interval = 100;	/* 100ms */
+
+	if (rtl8150_reset(dev) || !alloc_all_urbs(dev)) {
+		err("couldn't reset the device");
+		free_all_urbs(dev);
+		unregister_netdev(dev->netdev);
+		kfree(netdev);
+		kfree(dev);
+		dev = NULL;
+		goto exit;
+	}
+
+	set_ethernet_addr(dev);
+	info("%s: rtl8150 is detected", netdev->name);
+exit:
+	return dev;
+}
+
+
+static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
+{
+	rtl8150_t *dev;
+
+	dev = ptr;
+	set_bit(RTL8150_UNPLUG, &dev->flags);
+	unregister_netdev(dev->netdev);
+	unlink_all_urbs(dev);
+	free_all_urbs(dev);
+	kfree(dev->netdev);
+	kfree(dev);
+	dev->netdev = NULL;
+	dev = NULL;
+}
+
+
+
+static int __init usb_rtl8150_init(void)
+{
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return usb_register(&rtl8150_driver);
+}
+
+
+static void __exit usb_rtl8150_exit(void)
+{
+	usb_deregister(&rtl8150_driver);
+}
+
+
+module_init(usb_rtl8150_init);
+module_exit(usb_rtl8150_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/serial/Config.help b/drivers/usb/serial/Config.help
--- a/drivers/usb/serial/Config.help	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/Config.help	Wed Apr  3 17:11:15 2002
@@ -12,6 +12,26 @@
   The module will be called usbserial.o. If you want to compile it
   as a module, say M here and read <file:Documentation/modules.txt>.
 
+CONFIG_USB_SERIAL_CONSOLE
+  If you say Y here, it will be possible to use a USB to serial
+  converter port as the system console (the system console is the
+  device which receives all kernel messages and warnings and which
+  allows logins in single user mode). This could be useful if some
+  terminal or printer is connected to that serial port.
+
+  Even if you say Y here, the currently visible virtual console
+  (/dev/tty0) will still be used as the system console by default, but
+  you can alter that using a kernel command line option such as
+  "console=ttyUSB0". (Try "man bootparam" or see the documentation of
+  your boot loader (lilo or loadlin) about how to pass options to the
+  kernel at boot time.)
+
+  If you don't have a VGA card installed and you say Y here, the
+  kernel will automatically use the first USB to serial converter
+  port, /dev/ttyUSB0, as system console.
+
+  If unsure, say N.
+
 CONFIG_USB_SERIAL_GENERIC
   Say Y here if you want to use the generic USB serial driver.  Please
   read <file:Documentation/usb/usb-serial.txt> for more information on
diff -Nru a/drivers/usb/serial/Config.in b/drivers/usb/serial/Config.in
--- a/drivers/usb/serial/Config.in	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/serial/Config.in	Wed Apr  3 17:11:13 2002
@@ -7,19 +7,20 @@
 dep_tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
 if [ "$CONFIG_USB_SERIAL" = "y" ]; then
   dep_mbool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
+  dep_mbool '  USB Serial Console device support (EXPERIMENTAL)' CONFIG_USB_SERIAL_CONSOLE $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 fi
 dep_mbool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
-dep_tristate '  USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Belkin and Peracom Single Port Serial Driver' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
+dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
 dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
-dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Empeg empeg-car Mark I/II Driver' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL
 dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
 dep_tristate '  USB Compaq iPAQ / HP Jornada Driver' CONFIG_USB_SERIAL_IPAQ $CONFIG_USB_SERIAL
 dep_tristate '  USB IR Dongle Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_IR $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Inside Out Edgeport Serial Driver' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL
+dep_tristate '  USB Keyspan PDA Single Port Serial Driver' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
+dep_tristate '  USB Keyspan USA-xxx Serial Driver' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
    dep_mbool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28 $CONFIG_USB_SERIAL_KEYSPAN
    dep_mbool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X $CONFIG_USB_SERIAL_KEYSPAN
    dep_mbool '    USB Keyspan USA-28XA Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28XA $CONFIG_USB_SERIAL_KEYSPAN
@@ -28,11 +29,13 @@
    dep_mbool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X $CONFIG_USB_SERIAL_KEYSPAN
    dep_mbool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W $CONFIG_USB_SERIAL_KEYSPAN
    dep_mbool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W $CONFIG_USB_SERIAL_KEYSPAN
-dep_tristate '  USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 dep_tristate '  USB KL5KUSB105 (Palmconnect) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KLSI $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Prolific 2303 Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB MCT Single Port Serial Driver' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL
+dep_tristate '  USB Prolific 2303 Single Port Serial Driver' CONFIG_USB_SERIAL_PL2303 $CONFIG_USB_SERIAL
+dep_tristate '  USB Safe Serial (Encapsulated) Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+   dep_mbool '  USB Secure Encapsulated Driver - Padded (EXPERIMENTAL)' CONFIG_USB_SERIAL_SAFE_PADDED $CONFIG_USB_SERIAL_SAFE
 dep_tristate '  USB REINER SCT cyberJack pinpad/e-com chipcard reader (EXPERIMENTAL)' CONFIG_USB_SERIAL_CYBERJACK $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-dep_tristate '  USB Xircom / Entregra Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+dep_tristate '  USB Xircom / Entregra Single Port Serial Driver' CONFIG_USB_SERIAL_XIRCOM $CONFIG_USB_SERIAL
 dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
 
 endmenu
diff -Nru a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/Makefile	Wed Apr  3 17:11:14 2002
@@ -24,6 +24,7 @@
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_IR)			+= ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
+obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
 
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/serial/belkin_sa.c	Wed Apr  3 17:11:13 2002
@@ -191,9 +191,6 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			belkin_sa_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -207,26 +204,22 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		/*Start reading from the device*/
-		/* TODO: Look at possibility of submitting mulitple URBs to device to
-		 *       enhance buffering.  Win trace shows 16 initial read URBs.
-		 */
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (retval) {
-			err("usb_submit_urb(read bulk) failed");
-			goto exit;
-		}
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-		if (retval)
-			err(" usb_submit_urb(read int) failed");
+	/*Start reading from the device*/
+	/* TODO: Look at possibility of submitting mulitple URBs to device to
+	 *       enhance buffering.  Win trace shows 16 initial read URBs.
+	 */
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (retval) {
+		err("usb_submit_urb(read bulk) failed");
+		goto exit;
 	}
-	
+
+	port->interrupt_in_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (retval)
+		err(" usb_submit_urb(read int) failed");
+
 exit:
 	return retval;
 } /* belkin_sa_open */
@@ -245,16 +238,11 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk reads and writes */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->open_count = 0;
+	if (serial->dev) {
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
 } /* belkin_sa_close */
 
@@ -336,12 +324,31 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
-	unsigned int iflag = port->tty->termios->c_iflag;
-	unsigned int cflag = port->tty->termios->c_cflag;
-	unsigned int old_iflag = old_termios->c_iflag;
-	unsigned int old_cflag = old_termios->c_cflag;
+	unsigned int iflag;
+	unsigned int cflag;
+	unsigned int old_iflag = 0;
+	unsigned int old_cflag = 0;
 	__u16 urb_value = 0; /* Will hold the new flags */
 	
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg ("%s - no tty or termios structure", __FUNCTION__);
+		return;
+	}
+
+	iflag = port->tty->termios->c_iflag;
+	cflag = port->tty->termios->c_cflag;
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg("%s - nothing to change...", __FUNCTION__);
+			return;
+		}
+		old_iflag = old_termios->c_iflag;
+		old_cflag = old_termios->c_cflag;
+	}
+
 	/* Set the baud rate */
 	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
 		/* reassert DTR and (maybe) RTS on transition from B0 */
diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/serial/cyberjack.c	Wed Apr  3 17:11:16 2002
@@ -130,11 +130,7 @@
 	
 	dbg (__FUNCTION__);
 
-	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			cyberjack_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -151,31 +147,27 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		/* force low_latency on so that our tty_push actually forces
-		 * the data through, otherwise it is scheduled, and with high
-		 * data rates (like with OHCI) data can get lost.
-		 */
-		port->tty->low_latency = 1;
-
-		priv = (struct cyberjack_private *)port->private;
-		priv->rdtodo = 0;
-		priv->wrfilled = 0;
-		priv->wrsent = 0;
-
-		/* shutdown any bulk reads that might be going on */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		usb_unlink_urb (port->interrupt_in_urb);
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-		if (result)
-			err(" usb_submit_urb(read int) failed");
-		dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
-	}
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through, otherwise it is scheduled, and with high
+	 * data rates (like with OHCI) data can get lost.
+	 */
+	port->tty->low_latency = 1;
+
+	priv = (struct cyberjack_private *)port->private;
+	priv->rdtodo = 0;
+	priv->wrfilled = 0;
+	priv->wrsent = 0;
+
+	/* shutdown any bulk reads that might be going on */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	usb_unlink_urb (port->interrupt_in_urb);
+
+	port->interrupt_in_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (result)
+		err(" usb_submit_urb(read int) failed");
+	dbg(__FUNCTION__ " - usb_submit_urb(int urb)");
 
 	return result;
 }
@@ -184,16 +176,11 @@
 {
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (port->serial->dev) {
-			/* shutdown any bulk reads that might be going on */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->open_count = 0;
+	if (port->serial->dev) {
+		/* shutdown any bulk reads that might be going on */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
 }
 
diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
--- a/drivers/usb/serial/digi_acceleport.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/digi_acceleport.c	Wed Apr  3 17:11:15 2002
@@ -1490,28 +1490,17 @@
 		return( -EAGAIN );
 	}
 
-	/* inc module use count before sleeping to wait for closes */
-	++port->open_count;
-
 	/* wait for a close in progress to finish */
 	while( priv->dp_in_close ) {
 		cond_wait_interruptible_timeout_irqrestore(
 			&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
 			&priv->dp_port_lock, flags );
 		if( signal_pending(current) ) {
-			--port->open_count;
 			return( -EINTR );
 		}
 		spin_lock_irqsave( &priv->dp_port_lock, flags );
 	}
 
-	/* if port is already open, just return */
-	/* be sure exactly one open proceeds */
-	if( port->open_count != 1)  {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return( 0 );
-	}
-
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
  
 	/* read modem signals automatically whenever they change */
@@ -1557,14 +1546,6 @@
 
 	/* do cleanup only after final close on this port */
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
-	if( port->open_count > 1 ) {
-		--port->open_count;
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return;
-	} else if( port->open_count <= 0 ) {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return;
-	}
 	priv->dp_in_close = 1;
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
@@ -1637,7 +1618,6 @@
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
 	priv->dp_write_urb_in_use = 0;
 	priv->dp_in_close = 0;
-	--port->open_count;
 	wake_up_interruptible( &priv->dp_close_wait );
 	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 
@@ -1765,8 +1745,6 @@
 {
 
 	int i;
-	struct digi_port *priv;
-	unsigned long flags;
 
 
 dbg( "digi_shutdown: TOP, in_interrupt()=%d", in_interrupt() );
@@ -1775,16 +1753,6 @@
 	for( i=0; i<serial->type->num_ports+1; i++ ) {
 		usb_unlink_urb( serial->port[i].read_urb );
 		usb_unlink_urb( serial->port[i].write_urb );
-	}
-
-	/* dec module use count */
-	for( i=0; i<serial->type->num_ports; i++ ) {
-		priv = serial->port[i].private;
-		spin_lock_irqsave( &priv->dp_port_lock, flags );
-		while( serial->port[i].open_count > 0 ) {
-			--serial->port[i].open_count;
-		}
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
 	}
 
 	/* free the private data structures for all ports */
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/empeg.c	Wed Apr  3 17:11:15 2002
@@ -157,35 +157,29 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	++port->open_count;
+	/* Force default termio settings */
+	empeg_set_termios (port, NULL) ;
 
-	if (port->open_count == 1) {
+	bytes_in = 0;
+	bytes_out = 0;
 
-		/* Force default termio settings */
-		empeg_set_termios (port, NULL) ;
-
-		bytes_in = 0;
-		bytes_out = 0;
-
-		/* Start reading from the device */
-		FILL_BULK_URB(
-			port->read_urb,
-			serial->dev, 
-			usb_rcvbulkpipe(serial->dev,
-				port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			empeg_read_bulk_callback,
-			port);
-
-		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+	/* Start reading from the device */
+	FILL_BULK_URB(
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev,
+			port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		empeg_read_bulk_callback,
+		port);
 
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 
-	}
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
 	return result;
 }
@@ -204,16 +198,10 @@
 	if (!serial)
 		return;
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
-		}
-		port->open_count = 0;
+	if (serial->dev) {
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
-
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 }
@@ -491,17 +479,7 @@
 
 static void empeg_shutdown (struct usb_serial *serial)
 {
-	int i;
-
 	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			empeg_close (&serial->port[i], NULL);
-		}
-	}
-
 }
 
 
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/ftdi_sio.c	Wed Apr  3 17:11:14 2002
@@ -294,14 +294,8 @@
 
 static void ftdi_sio_shutdown (struct usb_serial *serial)
 {
-	
 	dbg (__FUNCTION__);
 
-
-	/* stop reads and writes on all ports */
-	while (serial->port[0].open_count > 0) {
-	        ftdi_sio_close (&serial->port[0], NULL);
-	}
 	if (serial->port[0].private){
 		kfree(serial->port[0].private);
 		serial->port[0].private = NULL;
@@ -319,45 +313,41 @@
 
 	dbg(__FUNCTION__);
 
-	++port->open_count;
-
-	if (port->open_count == 1){
-		/* This will push the characters through immediately rather 
-		   than queue a task to deliver them */
-		port->tty->low_latency = 1;
-
-		/* No error checking for this (will get errors later anyway) */
-		/* See ftdi_sio.h for description of what is reset */
-		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-				FTDI_SIO_RESET_SIO, 
-				0, buf, 0, WDR_TIMEOUT);
-
-		/* Setup termios defaults. According to tty_io.c the 
-		   settings are driver specific */
-		port->tty->termios->c_cflag =
-			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-
-		/* ftdi_sio_set_termios  will send usb control messages */
-		ftdi_sio_set_termios(port, &tmp_termios);	
-
-		/* Turn on RTS and DTR since we are not flow controlling by default */
-		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
-			err(__FUNCTION__ " Error from DTR HIGH urb");
-		}
-		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
-			err(__FUNCTION__ " Error from RTS HIGH urb");
-		}
-	
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ftdi_sio_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	/* This will push the characters through immediately rather 
+	   than queue a task to deliver them */
+	port->tty->low_latency = 1;
+
+	/* No error checking for this (will get errors later anyway) */
+	/* See ftdi_sio.h for description of what is reset */
+	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+			FTDI_SIO_RESET_SIO, 
+			0, buf, 0, WDR_TIMEOUT);
+
+	/* Setup termios defaults. According to tty_io.c the 
+	   settings are driver specific */
+	port->tty->termios->c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+	/* ftdi_sio_set_termios  will send usb control messages */
+	ftdi_sio_set_termios(port, &tmp_termios);	
+
+	/* Turn on RTS and DTR since we are not flow controlling by default */
+	if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+		err(__FUNCTION__ " Error from DTR HIGH urb");
 	}
+	if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+		err(__FUNCTION__ " Error from RTS HIGH urb");
+	}
+
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ftdi_sio_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
 	return result;
 } /* ftdi_sio_open */
@@ -371,41 +361,31 @@
 
 	dbg( __FUNCTION__);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			if (c_cflag & HUPCL){
-				/* Disable flow control */
-				if (usb_control_msg(serial->dev, 
-						    usb_sndctrlpipe(serial->dev, 0),
-						    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
-						    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-						    0, 0, buf, 0, WDR_TIMEOUT) < 0) {
-					err("error from flowcontrol urb");
-				}	    
-
-				/* drop DTR */
-				if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
-					err("Error from DTR LOW urb");
-				}
-				/* drop RTS */
-				if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
-					err("Error from RTS LOW urb");
-				}	
-			} /* Note change no line is hupcl is off */
-
-			/* shutdown our bulk reads and writes */
-			/* ***CHECK*** behaviour when there is nothing queued */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-		}
-		port->open_count = 0;
-	} else {  
-		/* Send a HUP if necessary */
-		if (!(port->tty->termios->c_cflag & CLOCAL)){
-			tty_hangup(port->tty);
-		}
+	if (serial->dev) {
+		if (c_cflag & HUPCL){
+			/* Disable flow control */
+			if (usb_control_msg(serial->dev, 
+					    usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+					    0, 0, buf, 0, WDR_TIMEOUT) < 0) {
+				err("error from flowcontrol urb");
+			}	    
+
+			/* drop DTR */
+			if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+				err("Error from DTR LOW urb");
+			}
+			/* drop RTS */
+			if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+				err("Error from RTS LOW urb");
+			}	
+		} /* Note change no line is hupcl is off */
+
+		/* shutdown our bulk reads and writes */
+		/* ***CHECK*** behaviour when there is nothing queued */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
 	}
 } /* ftdi_sio_close */
 
diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
--- a/drivers/usb/serial/io_edgeport.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/io_edgeport.c	Wed Apr  3 17:11:14 2002
@@ -274,7 +274,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
 #define DRIVER_DESC "Edgeport USB Serial Driver"
 
@@ -811,7 +811,8 @@
 						dbg(__FUNCTION__" - txcredits for port%d = %d", portNumber, edge_port->txCredits);
 
 						/* tell the tty driver that something has changed */
-						wake_up_interruptible(&edge_port->port->tty->write_wait);
+						if (edge_port->port->tty)
+							wake_up_interruptible(&edge_port->port->tty->write_wait);
 
 						// Since we have more credit, check if more data can be sent
 						send_more_port_data(edge_serial, edge_port);
@@ -898,13 +899,15 @@
 
 	tty = edge_port->port->tty;
 
-	/* let the tty driver wakeup if it has a special write_wakeup function */
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-		(tty->ldisc.write_wakeup)(tty);
-	}
+	if (tty) {
+		/* let the tty driver wakeup if it has a special write_wakeup function */
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
+			(tty->ldisc.write_wakeup)(tty);
+		}
 
-	/* tell the tty driver that something has changed */
-	wake_up_interruptible(&tty->write_wait);
+		/* tell the tty driver that something has changed */
+		wake_up_interruptible(&tty->write_wait);
+	}
 
 	// Release the Write URB
 	edge_port->write_in_progress = FALSE;
@@ -953,7 +956,8 @@
 	tty = edge_port->port->tty;
 
 	/* tell the tty driver that something has changed */
-	wake_up_interruptible(&tty->write_wait);
+	if (tty)
+		wake_up_interruptible(&tty->write_wait);
 
 	/* we have completed the command */
 	edge_port->commandPending = FALSE;
@@ -987,124 +991,118 @@
 	if (edge_port == NULL)
 		return -ENODEV;
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates (like with OHCI) data
+	   can get lost. */
+	if (port->tty)
 		port->tty->low_latency = 1;
+
+	/* see if we've set up our endpoint info yet (can't set it up in edge_startup
+	   as the structures were not set up at that time.) */
+	serial = port->serial;
+	edge_serial = (struct edgeport_serial *)serial->private;
+	if (edge_serial == NULL) {
+		return -ENODEV;
+	}
+	if (edge_serial->interrupt_in_buffer == NULL) {
+		struct usb_serial_port *port0 = &serial->port[0];
+		
+		/* not set up yet, so do it now */
+		edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
+		edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
+		edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
+		edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
+		edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
+		edge_serial->read_urb = port0->read_urb;
+		edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
 	
-		/* see if we've set up our endpoint info yet (can't set it up in edge_startup
-		   as the structures were not set up at that time.) */
-		serial = port->serial;
-		edge_serial = (struct edgeport_serial *)serial->private;
-		if (edge_serial == NULL) {
-			port->open_count = 0;
-			return -ENODEV;
-		}
-		if (edge_serial->interrupt_in_buffer == NULL) {
-			struct usb_serial_port *port0 = &serial->port[0];
-			
-			/* not set up yet, so do it now */
-			edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer;
-			edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress;
-			edge_serial->interrupt_read_urb = port0->interrupt_in_urb;
-			edge_serial->bulk_in_buffer = port0->bulk_in_buffer;
-			edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress;
-			edge_serial->read_urb = port0->read_urb;
-			edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress;
+		/* set up our interrupt urb */
+		FILL_INT_URB(edge_serial->interrupt_read_urb,
+			     serial->dev,
+			     usb_rcvintpipe(serial->dev,
+					    port0->interrupt_in_endpointAddress),
+			     port0->interrupt_in_buffer,
+			     edge_serial->interrupt_read_urb->transfer_buffer_length,
+			     edge_interrupt_callback, edge_serial,
+			     edge_serial->interrupt_read_urb->interval);
 		
-			/* set up our interrupt urb */
-			FILL_INT_URB(edge_serial->interrupt_read_urb,
-				     serial->dev,
-				     usb_rcvintpipe(serial->dev,
-					            port0->interrupt_in_endpointAddress),
-				     port0->interrupt_in_buffer,
-				     edge_serial->interrupt_read_urb->transfer_buffer_length,
-				     edge_interrupt_callback, edge_serial,
-				     edge_serial->interrupt_read_urb->interval);
-			
-			/* set up our bulk in urb */
-			FILL_BULK_URB(edge_serial->read_urb, serial->dev,
-				      usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
-				      port0->bulk_in_buffer,
-				      edge_serial->read_urb->transfer_buffer_length,
-				      edge_bulk_in_callback, edge_serial);
-
-			/* start interrupt read for this edgeport
-			 * this interrupt will continue as long as the edgeport is connected */
-			response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
-			if (response) {
-				err(__FUNCTION__" - Error %d submitting control urb", response);
-			}
+		/* set up our bulk in urb */
+		FILL_BULK_URB(edge_serial->read_urb, serial->dev,
+			      usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
+			      port0->bulk_in_buffer,
+			      edge_serial->read_urb->transfer_buffer_length,
+			      edge_bulk_in_callback, edge_serial);
+
+		/* start interrupt read for this edgeport
+		 * this interrupt will continue as long as the edgeport is connected */
+		response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL);
+		if (response) {
+			err(__FUNCTION__" - Error %d submitting control urb", response);
 		}
-		
-		/* initialize our wait queues */
-		init_waitqueue_head(&edge_port->wait_open);
-		init_waitqueue_head(&edge_port->wait_chase);
-		init_waitqueue_head(&edge_port->delta_msr_wait);
-		init_waitqueue_head(&edge_port->wait_command);
-
-		/* initialize our icount structure */
-		memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
-
-		/* initialize our port settings */
-		edge_port->txCredits            = 0;			/* Can't send any data yet */
-		edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
-		edge_port->chaseResponsePending = FALSE;
+	}
+	
+	/* initialize our wait queues */
+	init_waitqueue_head(&edge_port->wait_open);
+	init_waitqueue_head(&edge_port->wait_chase);
+	init_waitqueue_head(&edge_port->delta_msr_wait);
+	init_waitqueue_head(&edge_port->wait_command);
+
+	/* initialize our icount structure */
+	memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount));
+
+	/* initialize our port settings */
+	edge_port->txCredits            = 0;			/* Can't send any data yet */
+	edge_port->shadowMCR            = MCR_MASTER_IE;	/* Must always set this bit to enable ints! */
+	edge_port->chaseResponsePending = FALSE;
+
+	/* send a open port command */
+	edge_port->openPending = TRUE;
+	edge_port->open        = FALSE;
+	response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
 
-		/* send a open port command */
-		edge_port->openPending = TRUE;
-		edge_port->open        = FALSE;
-		response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0);
+	if (response < 0) {
+		err(__FUNCTION__" - error sending open port command");
+		edge_port->openPending = FALSE;
+		return -ENODEV;
+	}
 
-		if (response < 0) {
-			err(__FUNCTION__" - error sending open port command");
-			edge_port->openPending = FALSE;
-			port->open_count = 0;
-			return -ENODEV;
-		}
-
-		/* now wait for the port to be completly opened */
-		timeout = OPEN_TIMEOUT;
-		while (timeout && edge_port->openPending == TRUE) {
-			timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
-		}
-
-		if (edge_port->open == FALSE) {
-			/* open timed out */
-			dbg(__FUNCTION__" - open timedout");
-			edge_port->openPending = FALSE;
-			port->open_count = 0;
-			return -ENODEV;
-		}
-
-		/* create the txfifo */
-		edge_port->txfifo.head	= 0;
-		edge_port->txfifo.tail	= 0;
-		edge_port->txfifo.count	= 0;
-		edge_port->txfifo.size	= edge_port->maxTxCredits;
-		edge_port->txfifo.fifo	= kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
-
-		if (!edge_port->txfifo.fifo) {
-			dbg(__FUNCTION__" - no memory");
-			edge_close (port, filp);
-			return -ENOMEM;
-		}
+	/* now wait for the port to be completly opened */
+	timeout = OPEN_TIMEOUT;
+	while (timeout && edge_port->openPending == TRUE) {
+		timeout = interruptible_sleep_on_timeout (&edge_port->wait_open, timeout);
+	}
 
-		/* Allocate a URB for the write */
-		edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+	if (edge_port->open == FALSE) {
+		/* open timed out */
+		dbg(__FUNCTION__" - open timedout");
+		edge_port->openPending = FALSE;
+		return -ENODEV;
+	}
 
-		if (!edge_port->write_urb) {
-			dbg(__FUNCTION__" - no memory");
-			edge_close (port, filp);
-			return -ENOMEM;
-		}
+	/* create the txfifo */
+	edge_port->txfifo.head	= 0;
+	edge_port->txfifo.tail	= 0;
+	edge_port->txfifo.count	= 0;
+	edge_port->txfifo.size	= edge_port->maxTxCredits;
+	edge_port->txfifo.fifo	= kmalloc (edge_port->maxTxCredits, GFP_KERNEL);
+
+	if (!edge_port->txfifo.fifo) {
+		dbg(__FUNCTION__" - no memory");
+		edge_close (port, filp);
+		return -ENOMEM;
+	}
 
-		dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+	/* Allocate a URB for the write */
+	edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL);
+
+	if (!edge_port->write_urb) {
+		dbg(__FUNCTION__" - no memory");
+		edge_close (port, filp);
+		return -ENOMEM;
 	}
 
+	dbg(__FUNCTION__"(%d) - Initialize TX fifo to %d bytes", port->number, edge_port->maxTxCredits);
+
 	dbg(__FUNCTION__" exited");
 
 	return 0;
@@ -1234,52 +1232,47 @@
 	if ((edge_serial == NULL) || (edge_port == NULL))
 		return;
 	
-	--port->open_count;
+	if (serial->dev) {
+		// block until tx is empty
+		block_until_tx_empty(edge_port);
+
+		edge_port->closePending = TRUE;
+
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
+
+		dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			// block until tx is empty
-			block_until_tx_empty(edge_port);
-
-			edge_port->closePending = TRUE;
-
-			/* flush and chase */
-			edge_port->chaseResponsePending = TRUE;
-
-			dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT");
-			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-			if (status == 0) {
-				// block until chase finished
-				block_until_chase_response(edge_port);
-			} else {
-				edge_port->chaseResponsePending = FALSE;
-			}
+		/* close the port */
+		dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
 
-			/* close the port */
-			dbg(__FUNCTION__" - Sending IOSP_CMD_CLOSE_PORT");
-			send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
-
-			//port->close = TRUE;
-			edge_port->closePending = FALSE;
-			edge_port->open = FALSE;
-			edge_port->openPending = FALSE;
+		//port->close = TRUE;
+		edge_port->closePending = FALSE;
+		edge_port->open = FALSE;
+		edge_port->openPending = FALSE;
 
-			if (edge_port->write_urb) {
-				usb_unlink_urb (edge_port->write_urb);
-			}
-		}
-	
 		if (edge_port->write_urb) {
-			/* if this urb had a transfer buffer already (old transfer) free it */
-			if (edge_port->write_urb->transfer_buffer != NULL) {
-				kfree(edge_port->write_urb->transfer_buffer);
-			}
-			usb_free_urb   (edge_port->write_urb);
+			usb_unlink_urb (edge_port->write_urb);
 		}
-		if (edge_port->txfifo.fifo) {
-			kfree(edge_port->txfifo.fifo);
+	}
+
+	if (edge_port->write_urb) {
+		/* if this urb had a transfer buffer already (old transfer) free it */
+		if (edge_port->write_urb->transfer_buffer != NULL) {
+			kfree(edge_port->write_urb->transfer_buffer);
 		}
-		port->open_count = 0;
+		usb_free_urb   (edge_port->write_urb);
+	}
+	if (edge_port->txfifo.fifo) {
+		kfree(edge_port->txfifo.fifo);
 	}
 
 	dbg(__FUNCTION__" exited");
@@ -1580,6 +1573,10 @@
 	}
 
 	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
 
 	/* if we are implementing XON/XOFF, send the stop character */
 	if (I_IXOFF(tty)) {
@@ -1625,6 +1622,10 @@
 	}
 
 	tty = port->tty;
+	if (!tty) {
+		dbg ("%s - no tty available", __FUNCTION__);
+		return;
+	}
 
 	/* if we are implementing XON/XOFF, send the start character */
 	if (I_IXOFF(tty)) {
@@ -1656,15 +1657,14 @@
 {
 	struct edgeport_port *edge_port = (struct edgeport_port *)(port->private);
 	struct tty_struct *tty = port->tty;
-	unsigned int cflag = tty->termios->c_cflag;
+	unsigned int cflag;
 
-	dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x", 
-	    tty->termios->c_cflag,
-	    old_termios->c_cflag,
-	    RELEVANT_IFLAG(tty->termios->c_iflag),
-	    RELEVANT_IFLAG(old_termios->c_iflag)
-	   );
+	if (!port->tty || !port->tty->termios) {
+		dbg ("%s - no tty or termios", __FUNCTION__);
+		return;
+	}
 
+	cflag = tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
@@ -1674,6 +1674,15 @@
 		}
 	}
 
+	dbg("%s - clfag %08x iflag %08x", __FUNCTION__, 
+	    tty->termios->c_cflag,
+	    RELEVANT_IFLAG(tty->termios->c_iflag));
+	if (old_termios) {
+		dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+		    old_termios->c_cflag,
+		    RELEVANT_IFLAG(old_termios->c_iflag));
+	}
+
 	dbg(__FUNCTION__" - port %d", port->number);
 
 	if (edge_port == NULL)
@@ -1721,6 +1730,9 @@
 	unsigned int result = 0;
 	struct tty_struct *tty = edge_port->port->tty;
 
+	if (!tty)
+		return -ENOIOCTLCMD;
+
 	result = tty->read_cnt;
 
 	dbg(__FUNCTION__"(%d) = %d",  edge_port->port->number, result);
@@ -2148,7 +2160,8 @@
 		handle_new_msr (edge_port, byte2);
 
 		/* send the current line settings to the port so we are in sync with any further termios calls */
-		change_port_settings (edge_port, edge_port->port->tty->termios);
+		if (edge_port->port->tty)
+			change_port_settings (edge_port, edge_port->port->tty->termios);
 
 		/* we have completed the open */
 		edge_port->openPending = FALSE;
@@ -2259,7 +2272,7 @@
 	}
 
 	/* Place LSR data byte into Rx buffer */
-	if (lsrData) {
+	if (lsrData && edge_port->port->tty) {
 		tty_insert_flip_char(edge_port->port->tty, data, 0);
 		tty_flip_buffer_push(edge_port->port->tty);
 	}
@@ -3027,9 +3040,6 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			edge_close (&serial->port[i], NULL);
-		}
 		kfree (serial->port[i].private);
 		serial->port[i].private = NULL;
 	}
diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
--- a/drivers/usb/serial/ipaq.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/ipaq.c	Wed Apr  3 17:11:14 2002
@@ -9,6 +9,10 @@
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
  *
+ * (19/3/2002) ganesh
+ *	Don't submit urbs while holding spinlocks. Not strictly necessary
+ *	in 2.5.x.
+ *
  * (8/3/2002) ganesh
  * 	The ipaq sometimes emits a '\0' before the CLIENT string. At this
  * 	point of time, the ppp ldisc is not yet attached to the tty, so
@@ -65,7 +69,7 @@
 		       int count);
 static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
 			   int count);
-static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_write_gather(struct usb_serial_port *port);
 static void ipaq_read_bulk_callback (struct urb *urb);
 static void ipaq_write_bulk_callback(struct urb *urb);
 static int ipaq_write_room(struct usb_serial_port *port);
@@ -119,93 +123,89 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		bytes_in = 0;
-		bytes_out = 0;
-		priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
-		if (priv == NULL) {
-			err(__FUNCTION__ " - Out of memory");
-			return -ENOMEM;
-		}
-		port->private = (void *)priv;
-		priv->active = 0;
-		priv->queue_len = 0;
-		INIT_LIST_HEAD(&priv->queue);
-		INIT_LIST_HEAD(&priv->freelist);
-
-		for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
-			pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
-			if (pkt == NULL) {
-				goto enomem;
-			}
-			pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
-			if (pkt->data == NULL) {
-				kfree(pkt);
-				goto enomem;
-			}
-			pkt->len = 0;
-			pkt->written = 0;
-			INIT_LIST_HEAD(&pkt->list);
-			list_add(&pkt->list, &priv->freelist);
-			priv->free_len += PACKET_SIZE;
-		}
-
-		/*
-		 * Force low latency on. This will immediately push data to the line
-		 * discipline instead of queueing.
-		 */
-
-		port->tty->low_latency = 1;
-		port->tty->raw = 1;
-		port->tty->real_raw = 1;
-
-		/*
-		 * Lose the small buffers usbserial provides. Make larger ones.
-		 */
-
-		kfree(port->bulk_in_buffer);
-		kfree(port->bulk_out_buffer);
-		port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-		if (port->bulk_in_buffer == NULL) {
+	bytes_in = 0;
+	bytes_out = 0;
+	priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+	if (priv == NULL) {
+		err(__FUNCTION__ " - Out of memory");
+		return -ENOMEM;
+	}
+	port->private = (void *)priv;
+	priv->active = 0;
+	priv->queue_len = 0;
+	INIT_LIST_HEAD(&priv->queue);
+	INIT_LIST_HEAD(&priv->freelist);
+
+	for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+		pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+		if (pkt == NULL) {
 			goto enomem;
 		}
-		port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
-		if (port->bulk_out_buffer == NULL) {
-			kfree(port->bulk_in_buffer);
+		pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+		if (pkt->data == NULL) {
+			kfree(pkt);
 			goto enomem;
 		}
-		port->read_urb->transfer_buffer = port->bulk_in_buffer;
-		port->write_urb->transfer_buffer = port->bulk_out_buffer;
-		port->read_urb->transfer_buffer_length = URBDATA_SIZE;
-		port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
-		
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      ipaq_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-		}
+		pkt->len = 0;
+		pkt->written = 0;
+		INIT_LIST_HEAD(&pkt->list);
+		list_add(&pkt->list, &priv->freelist);
+		priv->free_len += PACKET_SIZE;
+	}
+
+	/*
+	 * Force low latency on. This will immediately push data to the line
+	 * discipline instead of queueing.
+	 */
+
+	port->tty->low_latency = 1;
+	port->tty->raw = 1;
+	port->tty->real_raw = 1;
+
+	/*
+	 * Lose the small buffers usbserial provides. Make larger ones.
+	 */
+
+	kfree(port->bulk_in_buffer);
+	kfree(port->bulk_out_buffer);
+	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+	if (port->bulk_in_buffer == NULL) {
+		goto enomem;
+	}
+	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+	if (port->bulk_out_buffer == NULL) {
+		kfree(port->bulk_in_buffer);
+		goto enomem;
+	}
+	port->read_urb->transfer_buffer = port->bulk_in_buffer;
+	port->write_urb->transfer_buffer = port->bulk_out_buffer;
+	port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+	port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+	
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ipaq_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	}
 
-		/*
-		 * Send out two control messages observed in win98 sniffs. Not sure what
-		 * they do.
-		 */
-
-		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
-				0x1, 0, NULL, 0, 5 * HZ);
-		if (result < 0) {
-			err(__FUNCTION__ " - failed doing control urb, error %d", result);
-		}
-		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
-				0x1, 0, NULL, 0, 5 * HZ);
-		if (result < 0) {
-			err(__FUNCTION__ " - failed doing control urb, error %d", result);
-		}
+	/*
+	 * Send out two control messages observed in win98 sniffs. Not sure what
+	 * they do.
+	 */
+
+	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+			0x1, 0, NULL, 0, 5 * HZ);
+	if (result < 0) {
+		err(__FUNCTION__ " - failed doing control urb, error %d", result);
+	}
+	result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+			0x1, 0, NULL, 0, 5 * HZ);
+	if (result < 0) {
+		err(__FUNCTION__ " - failed doing control urb, error %d", result);
 	}
 	
 	return result;
@@ -233,22 +233,16 @@
 	if (!serial)
 		return;
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
+	/*
+	 * shut down bulk read and write
+	 */
 
-		/*
-		 * shut down bulk read and write
-		 */
-
-		usb_unlink_urb(port->write_urb);
-		usb_unlink_urb(port->read_urb);
-		ipaq_destroy_lists(port);
-		kfree(priv);
-		port->private = NULL;
-		port->open_count = 0;
+	usb_unlink_urb(port->write_urb);
+	usb_unlink_urb(port->read_urb);
+	ipaq_destroy_lists(port);
+	kfree(priv);
+	port->private = NULL;
 
-	}
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 }
@@ -367,17 +361,23 @@
 	priv->queue_len += count;
 	if (priv->active == 0) {
 		priv->active = 1;
-		result = ipaq_write_flush(port);
+		ipaq_write_gather(port);
+		spin_unlock_irqrestore(&write_list_lock, flags);
+		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		}
+	} else {
+		spin_unlock_irqrestore(&write_list_lock, flags);
 	}
-	spin_unlock_irqrestore(&write_list_lock, flags);
 	return result;
 }
 
-static int ipaq_write_flush(struct usb_serial_port *port)
+static void ipaq_write_gather(struct usb_serial_port *port)
 {
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 	struct usb_serial	*serial = port->serial;
-	int			count, room, result;
+	int			count, room;
 	struct ipaq_packet	*pkt;
 	struct urb		*urb = port->write_urb;
 	struct list_head	*tmp;
@@ -385,7 +385,7 @@
 	if (urb->status == -EINPROGRESS) {
 		/* Should never happen */
 		err(__FUNCTION__ " - flushing while urb is active !");
-		return -EAGAIN;
+		return;
 	}
 	room = URBDATA_SIZE;
 	for (tmp = priv->queue.next; tmp != &priv->queue;) {
@@ -412,11 +412,7 @@
 		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
 		      port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
 		      port);
-	result = usb_submit_urb(urb, GFP_ATOMIC);
-	if (result) {
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
-	}
-	return result;
+	return;
 }
 
 static void ipaq_write_bulk_callback(struct urb *urb)
@@ -424,6 +420,7 @@
 	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
 	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
 	unsigned long		flags;
+	int			result;
 
 	if (port_paranoia_check (port, __FUNCTION__)) {
 		return;
@@ -437,11 +434,16 @@
 
 	spin_lock_irqsave(&write_list_lock, flags);
 	if (!list_empty(&priv->queue)) {
-		ipaq_write_flush(port);
+		ipaq_write_gather(port);
+		spin_unlock_irqrestore(&write_list_lock, flags);
+		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		}
 	} else {
 		priv->active = 0;
+		spin_unlock_irqrestore(&write_list_lock, flags);
 	}
-	spin_unlock_irqrestore(&write_list_lock, flags);
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 	
@@ -495,16 +497,7 @@
 
 static void ipaq_shutdown(struct usb_serial *serial)
 {
-	int i;
-
 	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			ipaq_close(&serial->port[i], NULL);
-		}
-	}
 }
 
 static int __init ipaq_init(void)
diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/ir-usb.c	Wed Apr  3 17:11:15 2002
@@ -283,45 +283,42 @@
 	
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		if (buffer_size) {
-			/* override the default buffer sizes */
-			buffer = kmalloc (buffer_size, GFP_KERNEL);
-			if (!buffer) {
-				err ("%s - out of memory.", __FUNCTION__);
-				return -ENOMEM;
-			}
-			kfree (port->read_urb->transfer_buffer);
-			port->read_urb->transfer_buffer = buffer;
-			port->read_urb->transfer_buffer_length = buffer_size;
-
-			buffer = kmalloc (buffer_size, GFP_KERNEL);
-			if (!buffer) {
-				err ("%s - out of memory.", __FUNCTION__);
-				return -ENOMEM;
-			}
-			kfree (port->write_urb->transfer_buffer);
-			port->write_urb->transfer_buffer = buffer;
-			port->write_urb->transfer_buffer_length = buffer_size;
-			port->bulk_out_size = buffer_size;
+	if (buffer_size) {
+		/* override the default buffer sizes */
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
 		}
-
-		/* Start reading from the device */
-		usb_fill_bulk_urb (
-			port->read_urb,
-			serial->dev, 
-			usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			ir_read_bulk_callback,
-			port);
-		port->read_urb->transfer_flags = USB_QUEUE_BULK;
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+		kfree (port->read_urb->transfer_buffer);
+		port->read_urb->transfer_buffer = buffer;
+		port->read_urb->transfer_buffer_length = buffer_size;
+
+		buffer = kmalloc (buffer_size, GFP_KERNEL);
+		if (!buffer) {
+			err ("%s - out of memory.", __FUNCTION__);
+			return -ENOMEM;
+		}
+		kfree (port->write_urb->transfer_buffer);
+		port->write_urb->transfer_buffer = buffer;
+		port->write_urb->transfer_buffer_length = buffer_size;
+		port->bulk_out_size = buffer_size;
 	}
+
+	/* Start reading from the device */
+	usb_fill_bulk_urb (
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		ir_read_bulk_callback,
+		port);
+	port->read_urb->transfer_flags = USB_QUEUE_BULK;
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result)
+		err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+
 	return result;
 }
 
@@ -338,15 +335,9 @@
 	if (!serial)
 		return;
 	
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
-		}
-		port->open_count = 0;
-
+	if (serial->dev) {
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
 }
 
diff -Nru a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
--- a/drivers/usb/serial/keyspan.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/keyspan.c	Wed Apr  3 17:11:14 2002
@@ -852,7 +852,7 @@
 	struct keyspan_serial_private 	*s_priv;
 	struct usb_serial 		*serial = port->serial;
 	const struct keyspan_device_details	*d_details;
-	int				i, already_active, err;
+	int				i, err;
 	struct urb			*urb;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
@@ -861,12 +861,6 @@
 	
 	dbg("keyspan_open called for port%d.\n", port->number); 
 
-	already_active = port->open_count;
-	++port->open_count;
-
-	if (already_active)
-		return 0;
-
 	p_priv = (struct keyspan_port_private *)(port->private);
 	
 	/* Set some sane defaults */
@@ -924,19 +918,16 @@
 	p_priv->out_flip = 0;
 	p_priv->in_flip = 0;
 
-	if (--port->open_count <= 0) {
-		if (serial->dev) {
-			/* Stop reading/writing urbs */
-			stop_urb(p_priv->inack_urb);
-			stop_urb(p_priv->outcont_urb);
-			for (i = 0; i < 2; i++) {
-				stop_urb(p_priv->in_urbs[i]);
-				stop_urb(p_priv->out_urbs[i]);
-			}
+	if (serial->dev) {
+		/* Stop reading/writing urbs */
+		stop_urb(p_priv->inack_urb);
+		stop_urb(p_priv->outcont_urb);
+		for (i = 0; i < 2; i++) {
+			stop_urb(p_priv->in_urbs[i]);
+			stop_urb(p_priv->out_urbs[i]);
 		}
-		port->open_count = 0;
-		port->tty = 0;
 	}
+	port->tty = 0;
 }
 
 
@@ -1762,9 +1753,6 @@
 	/* Now free per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = &serial->port[i];
-		while (port->open_count > 0) {
-			--port->open_count;
-		}
 		kfree(port->private);
 	}
 }
diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
--- a/drivers/usb/serial/keyspan_pda.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/keyspan_pda.c	Wed Apr  3 17:11:15 2002
@@ -662,52 +662,45 @@
 	int rc = 0;
 	struct keyspan_pda_private *priv;
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		/* find out how much room is in the Tx ring */
-		rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-				     6, /* write_room */
-				     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
-				     | USB_DIR_IN,
-				     0, /* value */
-				     0, /* index */
-				     &room,
-				     1,
-				     2*HZ);
-		if (rc < 0) {
-			dbg(__FUNCTION__" - roomquery failed");
-			goto error;
-		}
-		if (rc == 0) {
-			dbg(__FUNCTION__" - roomquery returned 0 bytes");
-			rc = -EIO;
-			goto error;
-		}
-		priv = (struct keyspan_pda_private *)(port->private);
-		priv->tx_room = room;
-		priv->tx_throttled = room ? 0 : 1;
-
-		/* the normal serial device seems to always turn on DTR and RTS here,
-		   so do the same */
-		if (port->tty->termios->c_cflag & CBAUD)
-			keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
-		else
-			keyspan_pda_set_modem_info(serial, 0);
-
-		/*Start reading from the device*/
-		port->interrupt_in_urb->dev = serial->dev;
-		rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-		if (rc) {
-			dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
-			goto error;
-		}
-
+	/* find out how much room is in the Tx ring */
+	rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     6, /* write_room */
+			     USB_TYPE_VENDOR | USB_RECIP_INTERFACE
+			     | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     &room,
+			     1,
+			     2*HZ);
+	if (rc < 0) {
+		dbg(__FUNCTION__" - roomquery failed");
+		goto error;
+	}
+	if (rc == 0) {
+		dbg(__FUNCTION__" - roomquery returned 0 bytes");
+		rc = -EIO;
+		goto error;
+	}
+	priv = (struct keyspan_pda_private *)(port->private);
+	priv->tx_room = room;
+	priv->tx_throttled = room ? 0 : 1;
+
+	/* the normal serial device seems to always turn on DTR and RTS here,
+	   so do the same */
+	if (port->tty->termios->c_cflag & CBAUD)
+		keyspan_pda_set_modem_info(serial, (1<<7) | (1<<2) );
+	else
+		keyspan_pda_set_modem_info(serial, 0);
+
+	/*Start reading from the device*/
+	port->interrupt_in_urb->dev = serial->dev;
+	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (rc) {
+		dbg(__FUNCTION__" - usb_submit_urb(read int) failed");
+		goto error;
 	}
 
-	return rc;
 error:
-	--port->open_count;
 	return rc;
 }
 
@@ -716,19 +709,14 @@
 {
 	struct usb_serial *serial = port->serial;
 
-	--port->open_count;
+	if (serial->dev) {
+		/* the normal serial device seems to always shut off DTR and RTS now */
+		if (port->tty->termios->c_cflag & HUPCL)
+			keyspan_pda_set_modem_info(serial, 0);
 
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* the normal serial device seems to always shut off DTR and RTS now */
-			if (port->tty->termios->c_cflag & HUPCL)
-				keyspan_pda_set_modem_info(serial, 0);
-
-			/* shutdown our bulk reads and writes */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->open_count = 0;
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
 }
 
@@ -805,9 +793,6 @@
 {
 	dbg (__FUNCTION__);
 	
-	while (serial->port[0].open_count > 0) {
-		keyspan_pda_close (&serial->port[0], NULL);
-	}
 	kfree(serial->port[0].private);
 }
 
diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/serial/kl5kusb105.c	Wed Apr  3 17:11:13 2002
@@ -317,9 +317,6 @@
 		struct klsi_105_private *priv = 
 			(struct klsi_105_private*) serial->port[i].private;
 		unsigned long flags;
-		while (serial->port[i].open_count > 0) {
-			klsi_105_close (&serial->port[i], NULL);
-		}
 
 		if (priv) {
 			/* kill our write urb pool */
@@ -355,85 +352,80 @@
 	struct usb_serial *serial = port->serial;
 	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
 	int retval = 0;
+	int rc;
+	int i;
+	unsigned long line_state;
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		int rc;
-		int i;
-		unsigned long line_state;
-
-		/* force low_latency on so that our tty_push actually forces
-		 * the data through
-		 * port->tty->low_latency = 1; */
-
-		/* Do a defined restart:
-		 * Set up sane default baud rate and send the 'READ_ON'
-		 * vendor command. 
-		 * FIXME: set modem line control (how?)
-		 * Then read the modem line control and store values in
-		 * priv->line_state.
-		 */
-		priv->cfg.pktlen   = 5;
-		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
-		priv->cfg.databits = kl5kusb105a_dtb_8;
-		priv->cfg.unknown1 = 0;
-		priv->cfg.unknown2 = 1;
-		klsi_105_chg_port_settings(serial, &(priv->cfg));
-		
-		/* set up termios structure */
-		priv->termios.c_iflag = port->tty->termios->c_iflag;
-		priv->termios.c_oflag = port->tty->termios->c_oflag;
-		priv->termios.c_cflag = port->tty->termios->c_cflag;
-		priv->termios.c_lflag = port->tty->termios->c_lflag;
-		for (i=0; i<NCCS; i++)
-			priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
-
-
-		/* READ_ON and urb submission */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev,
-					      port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer,
-			      port->read_urb->transfer_buffer_length,
-			      klsi_105_read_bulk_callback,
-			      port);
-		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
-
-		rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (rc) {
-			err(__FUNCTION__ 
-			    " - failed submitting read urb, error %d", rc);
-			retval = rc;
-			goto exit;
-		}
-
-		rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
-				     KL5KUSB105A_SIO_CONFIGURE,
-				     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
-				     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
-				     0, /* index */
-				     NULL,
-				     0,
-				     KLSI_TIMEOUT);
-		if (rc < 0) {
-			err("Enabling read failed (error = %d)", rc);
-			retval = rc;
-		} else 
-			dbg(__FUNCTION__ " - enabled reading");
-
-		rc = klsi_105_get_line_state(serial, &line_state);
-		if (rc >= 0) {
-			priv->line_state = line_state;
-			dbg(__FUNCTION__ 
-			    " - read line state 0x%lx", line_state);
-			retval = 0;
-		} else
-			retval = rc;
+	/* force low_latency on so that our tty_push actually forces
+	 * the data through
+	 * port->tty->low_latency = 1; */
+
+	/* Do a defined restart:
+	 * Set up sane default baud rate and send the 'READ_ON'
+	 * vendor command. 
+	 * FIXME: set modem line control (how?)
+	 * Then read the modem line control and store values in
+	 * priv->line_state.
+	 */
+	priv->cfg.pktlen   = 5;
+	priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+	priv->cfg.databits = kl5kusb105a_dtb_8;
+	priv->cfg.unknown1 = 0;
+	priv->cfg.unknown2 = 1;
+	klsi_105_chg_port_settings(serial, &(priv->cfg));
+	
+	/* set up termios structure */
+	priv->termios.c_iflag = port->tty->termios->c_iflag;
+	priv->termios.c_oflag = port->tty->termios->c_oflag;
+	priv->termios.c_cflag = port->tty->termios->c_cflag;
+	priv->termios.c_lflag = port->tty->termios->c_lflag;
+	for (i=0; i<NCCS; i++)
+		priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
+
+
+	/* READ_ON and urb submission */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev,
+				      port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer,
+		      port->read_urb->transfer_buffer_length,
+		      klsi_105_read_bulk_callback,
+		      port);
+	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+	rc = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (rc) {
+		err(__FUNCTION__ 
+		    " - failed submitting read urb, error %d", rc);
+		retval = rc;
+		goto exit;
 	}
 
+	rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+			     KL5KUSB105A_SIO_CONFIGURE,
+			     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+			     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+			     0, /* index */
+			     NULL,
+			     0,
+			     KLSI_TIMEOUT);
+	if (rc < 0) {
+		err("Enabling read failed (error = %d)", rc);
+		retval = rc;
+	} else 
+		dbg(__FUNCTION__ " - enabled reading");
+
+	rc = klsi_105_get_line_state(serial, &line_state);
+	if (rc >= 0) {
+		priv->line_state = line_state;
+		dbg(__FUNCTION__ 
+		    " - read line state 0x%lx", line_state);
+		retval = 0;
+	} else
+		retval = rc;
+
 exit:
 	return retval;
 } /* klsi_105_open */
@@ -444,6 +436,7 @@
 	struct usb_serial *serial;
 	struct klsi_105_private *priv 
 		= (struct klsi_105_private *)port->private;
+	int rc;
 	dbg(__FUNCTION__" port %d", port->number);
 
 	serial = get_usb_serial (port, __FUNCTION__);
@@ -451,31 +444,26 @@
 	if(!serial)
 		return;
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		/* send READ_OFF */
-		int rc = usb_control_msg(serial->dev,
-					 usb_sndctrlpipe(serial->dev, 0),
-					 KL5KUSB105A_SIO_CONFIGURE,
-					 USB_TYPE_VENDOR | USB_DIR_OUT,
-					 KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
-					 0, /* index */
-					 NULL, 0,
-					 KLSI_TIMEOUT);
-		if (rc < 0)
-			    err("Disabling read failed (error = %d)", rc);
-
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		/* unlink our write pool */
-		/* FIXME */
-		/* wgg - do I need this? I think so. */
-		usb_unlink_urb (port->interrupt_in_urb);
-		port->open_count = 0;
-		info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
-	}
+	/* send READ_OFF */
+	rc = usb_control_msg (serial->dev,
+			      usb_sndctrlpipe(serial->dev, 0),
+			      KL5KUSB105A_SIO_CONFIGURE,
+			      USB_TYPE_VENDOR | USB_DIR_OUT,
+			      KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+			      0, /* index */
+			      NULL, 0,
+			      KLSI_TIMEOUT);
+	if (rc < 0)
+		    err("Disabling read failed (error = %d)", rc);
+
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
+	/* unlink our write pool */
+	/* FIXME */
+	/* wgg - do I need this? I think so. */
+	usb_unlink_urb (port->interrupt_in_urb);
+	info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
 } /* klsi_105_close */
 
 
diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/mct_u232.c	Wed Apr  3 17:11:15 2002
@@ -324,9 +324,6 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			mct_u232_close (&serial->port[i], NULL);
-		}
 		/* My special items, the standard routines free my urbs */
 		if (serial->port[i].private)
 			kfree(serial->port[i].private);
@@ -341,60 +338,55 @@
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		/* Compensate for a hardware bug: although the Sitecom U232-P25
-		 * device reports a maximum output packet size of 32 bytes,
-		 * it seems to be able to accept only 16 bytes (and that's what
-		 * SniffUSB says too...)
-		 */
-		if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
-			port->bulk_out_size = 16;
-
-		/* Do a defined restart: the normal serial device seems to 
-		 * always turn on DTR and RTS here, so do the same. I'm not
-		 * sure if this is really necessary. But it should not harm
-		 * either.
-		 */
-		if (port->tty->termios->c_cflag & CBAUD)
-			priv->control_state = TIOCM_DTR | TIOCM_RTS;
-		else
-			priv->control_state = 0;
-		mct_u232_set_modem_ctrl(serial, priv->control_state);
-		
-		priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
-				  MCT_U232_PARITY_NONE |
-				  MCT_U232_STOP_BITS_1);
-		mct_u232_set_line_ctrl(serial, priv->last_lcr);
-
-		/* Read modem status and update control state */
-		mct_u232_get_modem_stat(serial, &priv->last_msr);
-		mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
-
-		{
-			/* Puh, that's dirty */
-			struct usb_serial_port *rport;	
-			rport = &serial->port[1];
-			rport->tty = port->tty;
-			rport->private = port->private;
-			port->read_urb = rport->interrupt_in_urb;
-		}
-
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (retval) {
-			err("usb_submit_urb(read bulk) failed");
-			goto exit;
-		}
-
-		port->interrupt_in_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-		if (retval)
-			err(" usb_submit_urb(read int) failed");
+	/* Compensate for a hardware bug: although the Sitecom U232-P25
+	 * device reports a maximum output packet size of 32 bytes,
+	 * it seems to be able to accept only 16 bytes (and that's what
+	 * SniffUSB says too...)
+	 */
+	if (serial->dev->descriptor.idProduct == MCT_U232_SITECOM_PID)
+		port->bulk_out_size = 16;
+
+	/* Do a defined restart: the normal serial device seems to 
+	 * always turn on DTR and RTS here, so do the same. I'm not
+	 * sure if this is really necessary. But it should not harm
+	 * either.
+	 */
+	if (port->tty->termios->c_cflag & CBAUD)
+		priv->control_state = TIOCM_DTR | TIOCM_RTS;
+	else
+		priv->control_state = 0;
+	mct_u232_set_modem_ctrl(serial, priv->control_state);
+	
+	priv->last_lcr = (MCT_U232_DATA_BITS_8 | 
+			  MCT_U232_PARITY_NONE |
+			  MCT_U232_STOP_BITS_1);
+	mct_u232_set_line_ctrl(serial, priv->last_lcr);
+
+	/* Read modem status and update control state */
+	mct_u232_get_modem_stat(serial, &priv->last_msr);
+	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+
+	{
+		/* Puh, that's dirty */
+		struct usb_serial_port *rport;	
+		rport = &serial->port[1];
+		rport->tty = port->tty;
+		rport->private = port->private;
+		port->read_urb = rport->interrupt_in_urb;
+	}
 
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (retval) {
+		err("usb_submit_urb(read bulk) failed");
+		goto exit;
 	}
 
+	port->interrupt_in_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+	if (retval)
+		err(" usb_submit_urb(read int) failed");
+
 exit:
 	return 0;
 } /* mct_u232_open */
@@ -404,16 +396,11 @@
 {
 	dbg(__FUNCTION__" port %d", port->number);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (port->serial->dev) {
-			/* shutdown our urbs */
-			usb_unlink_urb (port->write_urb);
-			usb_unlink_urb (port->read_urb);
-			usb_unlink_urb (port->interrupt_in_urb);
-		}
-		port->open_count = 0;
+	if (port->serial->dev) {
+		/* shutdown our urbs */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		usb_unlink_urb (port->interrupt_in_urb);
 	}
 } /* mct_u232_close */
 
diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
--- a/drivers/usb/serial/omninet.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/omninet.c	Wed Apr  3 17:11:14 2002
@@ -157,29 +157,24 @@
 	if (!serial)
 		return -ENODEV;
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
-		if( !od ) {
-			err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
-			port->open_count = 0;
-			return -ENOMEM;
-		}
+	od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+	if( !od ) {
+		err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct omninet_data));
+		return -ENOMEM;
+	}
 
-		port->private = od;
-		wport = &serial->port[1];
-		wport->tty = port->tty;
+	port->private = od;
+	wport = &serial->port[1];
+	wport->tty = port->tty;
 
-		/* Start reading from the device */
-		FILL_BULK_URB(port->read_urb, serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
-			      omninet_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-	}
+	/* Start reading from the device */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      omninet_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
 	return result;
 }
@@ -199,20 +194,15 @@
 	if (!serial)
 		return;
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			wport = &serial->port[1];
-			usb_unlink_urb (wport->write_urb);
-			usb_unlink_urb (port->read_urb);
-		}
-
-		port->open_count = 0;
-		od = (struct omninet_data *)port->private;
-		if (od)
-			kfree(od);
+	if (serial->dev) {
+		wport = &serial->port[1];
+		usb_unlink_urb (wport->write_urb);
+		usb_unlink_urb (port->read_urb);
 	}
+
+	od = (struct omninet_data *)port->private;
+	if (od)
+		kfree(od);
 }
 
 
@@ -377,10 +367,6 @@
 static void omninet_shutdown (struct usb_serial *serial)
 {
 	dbg (__FUNCTION__);
-
-	while (serial->port[0].open_count > 0) {
-		omninet_close (&serial->port[0], NULL);
-	}
 }
 
 
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/pl2303.c	Wed Apr  3 17:11:15 2002
@@ -1,7 +1,7 @@
 /*
  * Prolific PL2303 USB to serial adaptor driver
  *
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  * Original driver for 2.2.x by anonymous
  *
@@ -12,6 +12,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Mar_26 gkh
+ *	allowed driver to work properly if there is no tty assigned to a port
+ *	(this happens for serial console devices.)
+ *
  * 2001_Oct_06 gkh
  *	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
  *
@@ -173,11 +177,6 @@
 
 	dbg (__FUNCTION__ " - port %d, %d bytes", port->number, count);
 
-	if (!port->tty) {
-		err (__FUNCTION__ " - no tty???");
-		return 0;
-	}
-
 	if (port->write_urb->status == -EINPROGRESS) {
 		dbg (__FUNCTION__ " - already writing");
 		return 0;
@@ -367,56 +366,54 @@
 		
 	dbg (__FUNCTION__ " -  port %d", port->number);
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-#define FISH(a,b,c,d)									\
-		result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
-				       b, a, c, d, buf, 1, 100);			\
-		dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d)									\
-		result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
-				       b, a, c, d, NULL, 0, 100);			\
-		dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
-
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
-		FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
-		SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
+#define FISH(a,b,c,d)								\
+	result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0),	\
+			       b, a, c, d, buf, 1, 100);			\
+	dbg("0x%x:0x%x:0x%x:0x%x  %d - %x",a,b,c,d,result,buf[0]);
+
+#define SOUP(a,b,c,d)								\
+	result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),	\
+			       b, a, c, d, NULL, 0, 100);			\
+	dbg("0x%x:0x%x:0x%x:0x%x  %d",a,b,c,d,result);
+
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
+	FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0xc0);
+	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 4);
 
-		/* Setup termios */
+	/* Setup termios */
+	if (port->tty) {
 		*(port->tty->termios) = tty_std_termios;
 		port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
 
 		pl2303_set_termios (port, &tmp_termios);
+	}
 
-		//FIXME: need to assert RTS and DTR if CRTSCTS off
-
-		dbg (__FUNCTION__ " - submitting read urb");
-		port->read_urb->dev = serial->dev;
-		result = usb_submit_urb (port->read_urb, GFP_KERNEL);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-			pl2303_close (port, NULL);
-			return -EPROTO;
-		}
+	//FIXME: need to assert RTS and DTR if CRTSCTS off
 
-		dbg (__FUNCTION__ " - submitting interrupt urb");
-		port->interrupt_in_urb->dev = serial->dev;
-		result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
-		if (result) {
-			err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
-			pl2303_close (port, NULL);
-			return -EPROTO;
-		}
+	dbg (__FUNCTION__ " - submitting read urb");
+	port->read_urb->dev = serial->dev;
+	result = usb_submit_urb (port->read_urb, GFP_KERNEL);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+		pl2303_close (port, NULL);
+		return -EPROTO;
+	}
+
+	dbg (__FUNCTION__ " - submitting interrupt urb");
+	port->interrupt_in_urb->dev = serial->dev;
+	result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting interrupt urb, error %d", result);
+		pl2303_close (port, NULL);
+		return -EPROTO;
 	}
 	return 0;
 }
@@ -437,9 +434,8 @@
 	
 	dbg (__FUNCTION__ " - port %d", port->number);
 
-	--port->open_count;
-	if (port->open_count <= 0) {
-		if (serial->dev) {
+	if (serial->dev) {
+		if (port->tty) {
 			c_cflag = port->tty->termios->c_cflag;
 			if (c_cflag & HUPCL) {
 				/* drop DTR and RTS */
@@ -448,28 +444,27 @@
 				set_control_lines (port->serial->dev,
 						   priv->line_control);
 			}
-
-			/* shutdown our urbs */
-			dbg (__FUNCTION__ " - shutting down urbs");
-			result = usb_unlink_urb (port->write_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(write_urb) failed with reason: %d",
-				     result);
-
-			result = usb_unlink_urb (port->read_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(read_urb) failed with reason: %d",
-				     result);
-
-			result = usb_unlink_urb (port->interrupt_in_urb);
-			if (result)
-				dbg (__FUNCTION__ " - usb_unlink_urb "
-				     "(interrupt_in_urb) failed with reason: %d",
-				     result);
 		}
-		port->open_count = 0;
+
+		/* shutdown our urbs */
+		dbg (__FUNCTION__ " - shutting down urbs");
+		result = usb_unlink_urb (port->write_urb);
+		if (result)
+			dbg (__FUNCTION__ " - usb_unlink_urb "
+			     "(write_urb) failed with reason: %d",
+			     result);
+
+		result = usb_unlink_urb (port->read_urb);
+		if (result)
+			dbg (__FUNCTION__ " - usb_unlink_urb "
+			     "(read_urb) failed with reason: %d",
+			     result);
+
+		result = usb_unlink_urb (port->interrupt_in_urb);
+		if (result)
+			dbg (__FUNCTION__ " - usb_unlink_urb "
+			     "(interrupt_in_urb) failed with reason: %d",
+			     result);
 	}
 }
 
@@ -577,12 +572,8 @@
 
 	dbg (__FUNCTION__);
 
-	/* stop everything on all ports */
 	for (i = 0; i < serial->num_ports; ++i)
-		while (serial->port[i].open_count > 0) {
-			pl2303_close (&serial->port[i], NULL);
-			kfree (serial->port[i].private);
-		}
+		kfree (serial->port[i].private);
 }
 
 
@@ -655,7 +646,7 @@
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length; ++i) {
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				tty_flip_buffer_push(tty);
diff -Nru a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/serial/safe_serial.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,449 @@
+/*
+ * Safe Encapsulated USB Serial Driver
+ *
+ *      Copyright (c) 2001 Lineo
+ *      Copyright (c) 2001 Hewlett-Packard
+ *
+ *	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.
+ *
+ * By:
+ *      Stuart Lynne <sl@lineo.com>, Tom Rushworth <tbr@lineo.com>
+ */
+
+/* 
+ * The encapsultaion is designed to overcome difficulties with some USB hardware.
+ *
+ * While the USB protocol has a CRC over the data while in transit, i.e. while
+ * being carried over the bus, there is no end to end protection. If the hardware
+ * has any problems getting the data into or out of the USB transmit and receive
+ * FIFO's then data can be lost. 
+ *
+ * This protocol adds a two byte trailer to each USB packet to specify the number
+ * of bytes of valid data and a 10 bit CRC that will allow the receiver to verify
+ * that the entire USB packet was received without error.
+ *
+ * Because in this case the sender and receiver are the class and function drivers
+ * there is now end to end protection.
+ *
+ * There is an additional option that can be used to force all transmitted packets
+ * to be padded to the maximum packet size. This provides a work around for some
+ * devices which have problems with small USB packets.
+ *
+ * Assuming a packetsize of N:
+ *
+ *      0..N-2  data and optional padding
+ *
+ *      N-2     bits 7-2 - number of bytes of valid data
+ *              bits 1-0 top two bits of 10 bit CRC
+ *      N-1     bottom 8 bits of 10 bit CRC
+ *
+ *
+ *      | Data Length       | 10 bit CRC                                |
+ *      + 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 | 7 . 6 . 5 . 4 . 3 . 2 . 1 . 0 +
+ *
+ * The 10 bit CRC is computed across the sent data, followed by the trailer with
+ * the length set and the CRC set to zero. The CRC is then OR'd into the trailer.
+ *
+ * When received a 10 bit CRC is computed over the entire frame including the trailer
+ * and should be equal to zero.
+ *
+ * Two module parameters are used to control the encapsulation, if both are
+ * turned of the module works as a simple serial device with NO
+ * encapsulation.
+ *
+ * See linux/drivers/usbd/serial_fd for a device function driver
+ * implementation of this.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+
+#ifndef CONFIG_USB_SERIAL_DEBUG
+#define CONFIG_USB_SERIAL_DEBUG 0
+#endif
+#ifndef CONFIG_USB_SAFE_PADDED
+#define CONFIG_USB_SAFE_PADDED 0
+#endif
+
+static int debug = CONFIG_USB_SERIAL_DEBUG;
+#include "usb-serial.h"		// must follow the declaration of debug
+
+static int safe = 1;
+static int padded = CONFIG_USB_SAFE_PADDED;
+
+#define DRIVER_VERSION "v0.0b"
+#define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
+#define DRIVER_DESC "USB Safe Encapsulated Serial"
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+
+#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
+#abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
+#endif
+
+#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
+static __u16 vendor;		// no default
+static __u16 product;		// no default
+MODULE_PARM (vendor, "i");
+MODULE_PARM (product, "i");
+MODULE_PARM_DESC (vendor, "User specified USB idVendor (required)");
+MODULE_PARM_DESC (product, "User specified USB idProduct (required)");
+#endif
+
+MODULE_PARM (debug, "i");
+MODULE_PARM (safe, "i");
+MODULE_PARM (padded, "i");
+
+MODULE_PARM_DESC (debug, "Debug enabled or not");
+MODULE_PARM_DESC (safe, "Turn Safe Encapsulation On/Off");
+MODULE_PARM_DESC (padded, "Pad to full wMaxPacketSize On/Off");
+
+#define CDC_DEVICE_CLASS                        0x02
+
+#define CDC_INTERFACE_CLASS                     0x02
+#define CDC_INTERFACE_SUBCLASS                  0x06
+
+#define LINEO_INTERFACE_CLASS                   0xff
+
+#define LINEO_INTERFACE_SUBCLASS_SAFENET        0x01
+#define LINEO_SAFENET_CRC                       0x01
+#define LINEO_SAFENET_CRC_PADDED                0x02
+
+#define LINEO_INTERFACE_SUBCLASS_SAFESERIAL     0x02
+#define LINEO_SAFESERIAL_CRC                    0x01
+#define LINEO_SAFESERIAL_CRC_PADDED             0x02
+
+
+#define MY_USB_DEVICE(vend,prod,dc,ic,isc) \
+        match_flags: USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS | \
+                USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
+        idVendor: (vend), \
+        idProduct: (prod),\
+        bDeviceClass: (dc),\
+        bInterfaceClass: (ic), \
+        bInterfaceSubClass: (isc),
+
+static __devinitdata struct usb_device_id id_table[] = {
+	{MY_USB_DEVICE (0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Itsy
+	{MY_USB_DEVICE (0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Calypso
+	{MY_USB_DEVICE (0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Iris 
+	{MY_USB_DEVICE (0x4dd, 0x8002, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
+	{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
+	{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
+	{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Sharp tmp
+#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
+	{MY_USB_DEVICE
+	 (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
+	  LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
+#endif
+	// extra null entry for module 
+	// vendor/produc parameters
+	{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
+	{}			// terminating entry 
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+static __u16 crc10_table[256] = {
+	0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
+	0x031, 0x202, 0x264, 0x057, 0x2a8, 0x09b, 0x0fd, 0x2ce, 0x330, 0x103, 0x165, 0x356, 0x1a9, 0x39a, 0x3fc, 0x1cf,
+	0x062, 0x251, 0x237, 0x004, 0x2fb, 0x0c8, 0x0ae, 0x29d, 0x363, 0x150, 0x136, 0x305, 0x1fa, 0x3c9, 0x3af, 0x19c,
+	0x053, 0x260, 0x206, 0x035, 0x2ca, 0x0f9, 0x09f, 0x2ac, 0x352, 0x161, 0x107, 0x334, 0x1cb, 0x3f8, 0x39e, 0x1ad,
+	0x0c4, 0x2f7, 0x291, 0x0a2, 0x25d, 0x06e, 0x008, 0x23b, 0x3c5, 0x1f6, 0x190, 0x3a3, 0x15c, 0x36f, 0x309, 0x13a,
+	0x0f5, 0x2c6, 0x2a0, 0x093, 0x26c, 0x05f, 0x039, 0x20a, 0x3f4, 0x1c7, 0x1a1, 0x392, 0x16d, 0x35e, 0x338, 0x10b,
+	0x0a6, 0x295, 0x2f3, 0x0c0, 0x23f, 0x00c, 0x06a, 0x259, 0x3a7, 0x194, 0x1f2, 0x3c1, 0x13e, 0x30d, 0x36b, 0x158,
+	0x097, 0x2a4, 0x2c2, 0x0f1, 0x20e, 0x03d, 0x05b, 0x268, 0x396, 0x1a5, 0x1c3, 0x3f0, 0x10f, 0x33c, 0x35a, 0x169,
+	0x188, 0x3bb, 0x3dd, 0x1ee, 0x311, 0x122, 0x144, 0x377, 0x289, 0x0ba, 0x0dc, 0x2ef, 0x010, 0x223, 0x245, 0x076,
+	0x1b9, 0x38a, 0x3ec, 0x1df, 0x320, 0x113, 0x175, 0x346, 0x2b8, 0x08b, 0x0ed, 0x2de, 0x021, 0x212, 0x274, 0x047,
+	0x1ea, 0x3d9, 0x3bf, 0x18c, 0x373, 0x140, 0x126, 0x315, 0x2eb, 0x0d8, 0x0be, 0x28d, 0x072, 0x241, 0x227, 0x014,
+	0x1db, 0x3e8, 0x38e, 0x1bd, 0x342, 0x171, 0x117, 0x324, 0x2da, 0x0e9, 0x08f, 0x2bc, 0x043, 0x270, 0x216, 0x025,
+	0x14c, 0x37f, 0x319, 0x12a, 0x3d5, 0x1e6, 0x180, 0x3b3, 0x24d, 0x07e, 0x018, 0x22b, 0x0d4, 0x2e7, 0x281, 0x0b2,
+	0x17d, 0x34e, 0x328, 0x11b, 0x3e4, 0x1d7, 0x1b1, 0x382, 0x27c, 0x04f, 0x029, 0x21a, 0x0e5, 0x2d6, 0x2b0, 0x083,
+	0x12e, 0x31d, 0x37b, 0x148, 0x3b7, 0x184, 0x1e2, 0x3d1, 0x22f, 0x01c, 0x07a, 0x249, 0x0b6, 0x285, 0x2e3, 0x0d0,
+	0x11f, 0x32c, 0x34a, 0x179, 0x386, 0x1b5, 0x1d3, 0x3e0, 0x21e, 0x02d, 0x04b, 0x278, 0x087, 0x2b4, 0x2d2, 0x0e1,
+};
+
+#define CRC10_INITFCS     0x000	// Initial FCS value
+#define CRC10_GOODFCS     0x000	// Good final FCS value
+#define CRC10_FCS(fcs, c) ( (((fcs) << 8) & 0x3ff) ^ crc10_table[((fcs) >> 2) & 0xff] ^ (c))
+
+/**     
+ * fcs_compute10 - memcpy and calculate 10 bit CRC across buffer
+ * @sp: pointer to buffer
+ * @len: number of bytes
+ * @fcs: starting FCS
+ *
+ * Perform a memcpy and calculate fcs using ppp 10bit CRC algorithm. Return
+ * new 10 bit FCS.
+ */
+static __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs)
+{
+	for (; len-- > 0; fcs = CRC10_FCS (fcs, *sp++));
+	return fcs;
+}
+
+static void safe_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	unsigned char *data = urb->transfer_buffer;
+	unsigned char length = urb->actual_length;
+	int i;
+	int result;
+
+	dbg ("%s", __FUNCTION__);
+
+	if (!serial) {
+		dbg (__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg (__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	dbg ("safe_read_bulk_callback length: %d", port->read_urb->actual_length);
+#ifdef ECHO_RCV
+	{
+		int i;
+		unsigned char *cp = port->read_urb->transfer_buffer;
+		for (i = 0; i < port->read_urb->actual_length; i++) {
+			if ((i % 32) == 0) {
+				printk ("\nru[%02x] ", i);
+			}
+			printk ("%02x ", *cp++);
+		}
+		printk ("\n");
+	}
+#endif
+	if (safe) {
+		__u16 fcs;
+		if (!(fcs = fcs_compute10 (data, length, CRC10_INITFCS))) {
+
+			int actual_length = data[length - 2] >> 2;
+
+			if (actual_length <= (length - 2)) {
+
+				info (__FUNCTION__ " - actual: %d", actual_length);
+
+				for (i = 0; i < actual_length; i++) {
+					tty_insert_flip_char (port->tty, data[i], 0);
+				}
+				tty_flip_buffer_push (port->tty);
+			} else {
+				err (__FUNCTION__ " - inconsistant lengths %d:%d", actual_length,
+				     length);
+			}
+		} else {
+			err (__FUNCTION__ " - bad CRC %x", fcs);
+		}
+	} else {
+		for (i = 0; i < length; i++) {
+			tty_insert_flip_char (port->tty, data[i], 0);
+		}
+		tty_flip_buffer_push (port->tty);
+	}
+
+	/* Continue trying to always read  */
+	FILL_BULK_URB (urb, serial->dev,
+		       usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress),
+		       urb->transfer_buffer, urb->transfer_buffer_length,
+		       safe_read_bulk_callback, port);
+
+	if ((result = usb_submit_urb (urb, GFP_ATOMIC))) {
+		err (__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+	}
+}
+
+static int safe_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned char *data;
+	int result;
+	int i;
+	int packet_length;
+
+	dbg ("safe_write port: %p %d urb: %p count: %d", port, port->number, port->write_urb,
+	     count);
+
+	if (!port->write_urb) {
+		dbg (__FUNCTION__ " - write urb NULL");
+		return (0);
+	}
+
+	dbg ("safe_write write_urb: %d transfer_buffer_length",
+	     port->write_urb->transfer_buffer_length);
+
+	if (!port->write_urb->transfer_buffer_length) {
+		dbg (__FUNCTION__ " - write urb transfer_buffer_length zero");
+		return (0);
+	}
+	if (count == 0) {
+		dbg (__FUNCTION__ " - write request of 0 bytes");
+		return (0);
+	}
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " - already writing");
+		return (0);
+	}
+
+	packet_length = port->bulk_out_size;	// get max packetsize
+
+	i = packet_length - (safe ? 2 : 0);	// get bytes to send
+	count = (count > i) ? i : count;
+
+
+	// get the data into the transfer buffer
+	data = port->write_urb->transfer_buffer;
+	memset (data, '0', packet_length);
+
+	if (from_user) {
+		copy_from_user (data, buf, count);
+	} else {
+		memcpy (data, buf, count);
+	}
+
+	if (safe) {
+		__u16 fcs;
+
+		// pad if necessary
+		if (!padded) {
+			packet_length = count + 2;
+		}
+		// set count
+		data[packet_length - 2] = count << 2;
+		data[packet_length - 1] = 0;
+
+		// compute fcs and insert into trailer
+		fcs = fcs_compute10 (data, packet_length, CRC10_INITFCS);
+		data[packet_length - 2] |= fcs >> 8;
+		data[packet_length - 1] |= fcs & 0xff;
+
+		// set length to send
+		port->write_urb->transfer_buffer_length = packet_length;
+	} else {
+		port->write_urb->transfer_buffer_length = count;
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer);
+#ifdef ECHO_TX
+	{
+		int i;
+		unsigned char *cp = port->write_urb->transfer_buffer;
+		for (i = 0; i < port->write_urb->transfer_buffer_length; i++) {
+			if ((i % 32) == 0) {
+				printk ("\nsu[%02x] ", i);
+			}
+			printk ("%02x ", *cp++);
+		}
+		printk ("\n");
+	}
+#endif
+	port->write_urb->dev = serial->dev;
+	if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+		err (__FUNCTION__ " - failed submitting write urb, error %d", result);
+		return 0;
+	}
+	dbg (__FUNCTION__ " urb: %p submitted", port->write_urb);
+
+	return (count);
+}
+
+static int safe_write_room (struct usb_serial_port *port)
+{
+	int room = 0;		// Default: no room
+
+	dbg ("%s", __FUNCTION__);
+
+	if (port->write_urb->status != -EINPROGRESS)
+		room = port->bulk_out_size - (safe ? 2 : 0);
+
+	if (room) {
+		dbg ("safe_write_room returns %d", room);
+	}
+
+	return (room);
+}
+
+static int safe_startup (struct usb_serial *serial)
+{
+	switch (serial->interface->altsetting->bInterfaceProtocol) {
+	case LINEO_SAFESERIAL_CRC:
+		break;
+	case LINEO_SAFESERIAL_CRC_PADDED:
+		padded = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static struct usb_serial_device_type safe_device = {
+	owner:			THIS_MODULE,
+	name:			"Safe",
+	id_table:		id_table,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		1,
+	write:			safe_write,
+	write_room:		safe_write_room,
+	read_bulk_callback:	safe_read_bulk_callback,
+	startup:		safe_startup,
+};
+
+static int __init safe_init (void)
+{
+	int i;
+
+	info (DRIVER_VERSION " " DRIVER_AUTHOR);
+	info (DRIVER_DESC);
+	info ("vendor: %x product: %x safe: %d padded: %d\n", vendor, product, safe, padded);
+
+	// if we have vendor / product parameters patch them into id list
+	if (vendor || product) {
+		info ("vendor: %x product: %x\n", vendor, product);
+
+		for (i = 0; i < (sizeof (id_table) / sizeof (struct usb_device_id)); i++) {
+			if (!id_table[i].idVendor && !id_table[i].idProduct) {
+				id_table[i].idVendor = vendor;
+				id_table[i].idProduct = product;
+				break;
+			}
+		}
+	}
+
+	usb_serial_register (&safe_device);
+
+	return 0;
+}
+
+static void __exit safe_exit (void)
+{
+	usb_serial_deregister (&safe_device);
+}
+
+module_init (safe_init);
+module_exit (safe_exit);
diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/usb-serial.h	Wed Apr  3 17:11:15 2002
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *	Copyright (C) 1999 - 2001
+ *	Copyright (C) 1999 - 2002
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (03/26/2002) gkh
+ *	removed the port->tty check from port_paranoia_check() due to serial
+ *	consoles not having a tty device assigned to them.
+ *
  * (12/03/2001) gkh
  *	removed active from the port structure.
  *	added documentation to the usb_serial_device_type structure
@@ -224,10 +228,6 @@
 	}
 	if (!port->serial) {
 		dbg("%s - port->serial == NULL", function);
-		return -1;
-	}
-	if (!port->tty) {
-		dbg("%s - port->tty == NULL", function);
 		return -1;
 	}
 
diff -Nru a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/usbserial.c	Wed Apr  3 17:11:15 2002
@@ -15,6 +15,19 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (03/27/2002) gkh
+ *	Got USB serial console code working properly and merged into the main
+ *	version of the tree.  Thanks to Randy Dunlap for the initial version
+ *	of this code, and for pushing me to finish it up.
+ *	The USB serial console works with any usb serial driver device.
+ *
+ * (03/21/2002) gkh
+ *	Moved all manipulation of port->open_count into the core.  Now the
+ *	individual driver's open and close functions are called only when the
+ *	first open() and last close() is called.  Making the drivers a bit
+ *	smaller and simpler.
+ *	Fixed a bug if a driver didn't have the owner field set.
+ *
  * (02/26/2002) gkh
  *	Moved all locking into the main serial_* functions, instead of having 
  *	the individual drivers have to grab the port semaphore.  This should
@@ -307,6 +320,14 @@
 #include <linux/smp_lock.h>
 #include <linux/usb.h>
 
+#ifdef MODULE
+#undef CONFIG_USB_SERIAL_CONSOLE
+#endif
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/serial.h>
+#endif
+
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
 #else
@@ -395,6 +416,16 @@
 static struct usb_serial	*serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
 static LIST_HEAD(usb_serial_driver_list);
 
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+struct usbcons_info {
+	int			magic;
+	int			break_flag;
+	struct usb_serial_port	*port;
+};
+
+static struct usbcons_info usbcons_info;
+static struct console usbcons;
+#endif /* CONFIG_USB_SERIAL_CONSOLE */
 
 static struct usb_serial *get_serial_by_minor (unsigned int minor)
 {
@@ -500,7 +531,7 @@
 	struct usb_serial *serial;
 	struct usb_serial_port *port;
 	unsigned int portNumber;
-	int retval;
+	int retval = 0;
 	
 	dbg(__FUNCTION__);
 
@@ -525,19 +556,48 @@
 	if (serial->type->owner)
 		__MOD_INC_USE_COUNT(serial->type->owner);
 
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->open)
-		retval = serial->type->open(port, filp);
-	else
-		retval = generic_open(port, filp);
+	++port->open_count;
+	if (port->open_count == 1) {
+		/* only call the device specific open if this 
+		 * is the first time the port is opened */
+		if (serial->type->open)
+			retval = serial->type->open(port, filp);
+		else
+			retval = generic_open(port, filp);
+	}
 
-	if (retval)
-		__MOD_DEC_USE_COUNT(serial->type->owner);
+	if (retval) {
+		port->open_count = 0;
+		if (serial->type->owner)
+			__MOD_DEC_USE_COUNT(serial->type->owner);
+	}
 
 	up (&port->sem);
 	return retval;
 }
 
+static void __serial_close(struct usb_serial_port *port, struct file *filp)
+{
+	if (!port->open_count) {
+		dbg (__FUNCTION__ " - port not opened");
+		return;
+	}
+
+	--port->open_count;
+	if (port->open_count <= 0) {
+		/* only call the device specific close if this 
+		 * port is being closed by the last owner */
+		if (port->serial->type->close)
+			port->serial->type->close(port, filp);
+		else
+			generic_close(port, filp);
+		port->open_count = 0;
+	}
+
+	if (port->serial->type->owner)
+		__MOD_DEC_USE_COUNT(port->serial->type->owner);
+}
+
 static void serial_close(struct tty_struct *tty, struct file * filp)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *) tty->driver_data;
@@ -550,26 +610,11 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	if (tty->driver_data == NULL) {
-		/* disconnect beat us to the punch here, so handle it gracefully */
-		goto exit;
-	}
-	if (!port->open_count) {
-		dbg (__FUNCTION__ " - port not opened");
-		goto exit_no_mod_dec;
+	/* if disconnect beat us to the punch here, there's nothing to do */
+	if (tty->driver_data) {
+		__serial_close(port, filp);
 	}
 
-	/* pass on to the driver specific version of this function if it is available */
-	if (serial->type->close)
-		serial->type->close(port, filp);
-	else
-		generic_close(port, filp);
-
-exit:
-	if (serial->type->owner)
-		__MOD_DEC_USE_COUNT(serial->type->owner);
-
-exit_no_mod_dec:
 	up (&port->sem);
 }
 
@@ -791,6 +836,8 @@
 
 static void serial_shutdown (struct usb_serial *serial)
 {
+	dbg(__FUNCTION__);
+
 	if (serial->type->shutdown)
 		serial->type->shutdown(serial);
 	else
@@ -810,54 +857,52 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	++port->open_count;
-
-	if (port->open_count == 1) {
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	   otherwise it is scheduled, and with high data rates (like with OHCI) data
+	   can get lost. */
+	if (port->tty)
 		port->tty->low_latency = 1;
 
-		/* if we have a bulk interrupt, start reading from it */
-		if (serial->num_bulk_in) {
-			/* Start reading from the device */
-			usb_fill_bulk_urb (port->read_urb, serial->dev,
-					   usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-					   port->read_urb->transfer_buffer,
-					   port->read_urb->transfer_buffer_length,
-					   ((serial->type->read_bulk_callback) ?
-					     serial->type->read_bulk_callback :
-					     generic_read_bulk_callback),
-					   port);
-			result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-			if (result)
-				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
-		}
+	/* if we have a bulk interrupt, start reading from it */
+	if (serial->num_bulk_in) {
+		/* Start reading from the device */
+		usb_fill_bulk_urb (port->read_urb, serial->dev,
+				   usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+				   port->read_urb->transfer_buffer,
+				   port->read_urb->transfer_buffer_length,
+				   ((serial->type->read_bulk_callback) ?
+				     serial->type->read_bulk_callback :
+				     generic_read_bulk_callback),
+				   port);
+		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+		if (result)
+			err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	}
 
 	return result;
 }
 
-static void generic_close (struct usb_serial_port *port, struct file * filp)
+static void generic_cleanup (struct usb_serial_port *port)
 {
 	struct usb_serial *serial = port->serial;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* shutdown any bulk reads that might be going on */
-			if (serial->num_bulk_out)
-				usb_unlink_urb (port->write_urb);
-			if (serial->num_bulk_in)
-				usb_unlink_urb (port->read_urb);
-		}
-		port->open_count = 0;
+	if (serial->dev) {
+		/* shutdown any bulk reads that might be going on */
+		if (serial->num_bulk_out)
+			usb_unlink_urb (port->write_urb);
+		if (serial->num_bulk_in)
+			usb_unlink_urb (port->read_urb);
 	}
 }
 
+static void generic_close (struct usb_serial_port *port, struct file * filp)
+{
+	dbg(__FUNCTION__ " - port %d", port->number);
+	generic_cleanup (port);
+}
+
 static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
 {
 	struct usb_serial *serial = port->serial;
@@ -968,7 +1013,7 @@
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -1025,10 +1070,7 @@
 
 	/* stop reads and writes on all ports */
 	for (i=0; i < serial->num_ports; ++i) {
-		down (&serial->port[i].sem);
-		while (serial->port[i].open_count > 0)
-			generic_close (&serial->port[i], NULL);
-		up (&serial->port[i].sem);
+		generic_cleanup (&serial->port[i]);
 	}
 }
 
@@ -1040,11 +1082,13 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 	
-	if (!serial) {
+	if (!serial)
 		return;
-	}
 
 	tty = port->tty;
+	if (!tty)
+		return;
+
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
 		dbg(__FUNCTION__ " - write wakeup call.");
 		(tty->ldisc.write_wakeup)(tty);
@@ -1294,6 +1338,26 @@
 		     type->name, serial->port[i].number, serial->port[i].number);
 	}
 
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+	if (minor == 0) {
+		/* 
+		 * Call register_console() if this is the first device plugged
+		 * in.  If we call it earlier, then the callback to
+		 * console_setup() will fail, as there is not a device seen by
+		 * the USB subsystem yet.
+		 */
+		/*
+		 * Register console.
+		 * NOTES:
+		 * console_setup() is called (back) immediately (from register_console).
+		 * console_write() is called immediately from register_console iff
+		 * CON_PRINTBUFFER is set in flags.
+		 */
+		dbg ("registering the USB serial console.");
+		register_console(&usbcons);
+	}
+#endif
+
 	return serial; /* success */
 
 
@@ -1334,13 +1398,19 @@
 	struct usb_serial_port *port;
 	int i;
 
+	dbg(__FUNCTION__);
 	if (serial) {
 		/* fail all future close/read/write/ioctl/etc calls */
 		for (i = 0; i < serial->num_ports; ++i) {
-			down (&serial->port[i].sem);
-			if (serial->port[i].tty != NULL)
-				serial->port[i].tty->driver_data = NULL;
-			up (&serial->port[i].sem);
+			port = &serial->port[i];
+			down (&port->sem);
+			if (port->tty != NULL) {
+				while (port->open_count > 0) {
+					__serial_close(port, NULL);
+				}
+				port->tty->driver_data = NULL;
+			}
+			up (&port->sem);
 		}
 
 		serial->dev = NULL;
@@ -1466,6 +1536,9 @@
 
 static void __exit usb_serial_exit(void)
 {
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+	unregister_console(&usbcons);
+#endif
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	/* remove our generic driver */
@@ -1515,7 +1588,7 @@
 
 
 
-/* If the usb-serial core is build into the core, the usb-serial drivers
+/* If the usb-serial core is built into the core, the usb-serial drivers
    need these symbols to load properly as modules. */
 EXPORT_SYMBOL(usb_serial_register);
 EXPORT_SYMBOL(usb_serial_deregister);
@@ -1523,6 +1596,241 @@
 	EXPORT_SYMBOL(ezusb_writememory);
 	EXPORT_SYMBOL(ezusb_set_reset);
 #endif
+
+
+#ifdef CONFIG_USB_SERIAL_CONSOLE
+/*
+ * ------------------------------------------------------------
+ * USB Serial console driver
+ *
+ * Much of the code here is copied from drivers/char/serial.c
+ * and implements a phony serial console in the same way that
+ * serial.c does so that in case some software queries it,
+ * it will get the same results.
+ *
+ * Things that are different from the way the serial port code
+ * does things, is that we call the lower level usb-serial
+ * driver code to initialize the device, and we set the initial
+ * console speeds based on the command line arguments.
+ * ------------------------------------------------------------
+ */
+
+#if 0
+static kdev_t usb_console_device(struct console *co)
+{
+	return MKDEV(SERIAL_TTY_MAJOR, co->index);	/* TBD */
+}
+#endif
+
+/*
+ * The parsing of the command line works exactly like the
+ * serial.c code, except that the specifier is "ttyUSB" instead
+ * of "ttyS".
+ */
+static int __init usb_console_setup(struct console *co, char *options)
+{
+	struct usbcons_info *info = &usbcons_info;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int doflow = 0;
+	int cflag = CREAD | HUPCL | CLOCAL;
+	char *s;
+	struct usb_serial *serial;
+	struct usb_serial_port *port;
+	int retval = 0;
+	struct tty_struct *tty;
+	struct termios *termios;
+
+	dbg ("%s", __FUNCTION__);
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while (*s >= '0' && *s <= '9')
+			s++;
+		if (*s)	parity = *s++;
+		if (*s)	bits   = *s++ - '0';
+		if (*s)	doflow = (*s++ == 'r');
+	}
+
+	/* build a cflag setting */
+	switch (baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			/*
+			 * Set this to a sane value to prevent a divide error
+			 */
+			baud  = 9600;
+			break;
+	}
+	switch (bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch (parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	/* grab the first serial port that happens to be connected */
+	serial = get_serial_by_minor (0);
+	if (serial_paranoia_check (serial, __FUNCTION__)) {
+		/* no device is connected yet, sorry :( */
+		err ("No USB device connected to ttyUSB0");
+		return -ENODEV;
+	}
+
+	port = &serial->port[0];
+	down (&port->sem);
+	port->tty = NULL;
+
+	info->port = port;
+	 
+	++port->open_count;
+	if (port->open_count == 1) {
+		/* only call the device specific open if this 
+		 * is the first time the port is opened */
+		if (serial->type->open)
+			retval = serial->type->open(port, NULL);
+		else
+			retval = generic_open(port, NULL);
+		if (retval)
+			port->open_count = 0;
+	}
+
+	up (&port->sem);
+
+	if (retval) {
+		err ("could not open USB console port");
+		return retval;
+	}
+
+	if (serial->type->set_termios) {
+		/* build up a fake tty structure so that the open call has something
+		 * to look at to get the cflag value */
+		tty = kmalloc (sizeof (*tty), GFP_KERNEL);
+		if (!tty) {
+			err ("no more memory");
+			return -ENOMEM;
+		}
+		termios = kmalloc (sizeof (*termios), GFP_KERNEL);
+		if (!termios) {
+			err ("no more memory");
+			kfree (tty);
+			return -ENOMEM;
+		}
+		memset (tty, 0x00, sizeof(*tty));
+		memset (termios, 0x00, sizeof(*termios));
+		termios->c_cflag = cflag;
+		tty->termios = termios;
+		port->tty = tty;
+
+		/* set up the initial termios settings */
+		serial->type->set_termios(port, NULL);
+		port->tty = NULL;
+		kfree (termios);
+		kfree (tty);
+	}
+
+	return retval;
+}
+
+static void usb_console_write(struct console *co, const char *buf, unsigned count)
+{
+	static struct usbcons_info *info = &usbcons_info;
+	struct usb_serial_port *port = info->port;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	int retval = -ENODEV;
+
+	if (!serial || !port)
+		return;
+
+	if (count == 0)
+		return;
+
+	down (&port->sem);
+
+	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
+
+	if (!port->open_count) {
+		dbg (__FUNCTION__ " - port not opened");
+		goto exit;
+	}
+
+	/* pass on to the driver specific version of this function if it is available */
+	if (serial->type->write)
+		retval = serial->type->write(port, 0, buf, count);
+	else
+		retval = generic_write(port, 0, buf, count);
+
+exit:
+	up (&port->sem);
+	dbg("%s - return value (if we had one): %d", __FUNCTION__, retval);
+}
+
+#if 0
+/*
+ * Receive character from the serial port
+ */
+static int usb_console_wait_key(struct console *co)
+{
+	static struct usbcons_info *info = &usbcons_info;
+	int c = 0;
+
+	dbg("%s", __FUNCTION__);
+
+	/* maybe use generic_read_bulk_callback ??? */
+
+	return c;
+}
+#endif
+
+static struct console usbcons = {
+	name:		"ttyUSB",			/* only [8] */
+	write:		usb_console_write,
+#if 0
+	device:		usb_console_device,		/* TBD */
+	wait_key:	usb_console_wait_key,		/* TBD */
+#endif
+	setup:		usb_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+#endif /* CONFIG_USB_SERIAL_CONSOLE */
 
 
 /* Module information */
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/visor.c	Wed Apr  3 17:11:14 2002
@@ -11,7 +11,19 @@
  *	(at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
+ *
+ * (03/27/2002) gkh
+ *	Removed assumptions that port->tty was always valid (is not true
+ *	for usb serial console devices.)
+ *
+ * (03/23/2002) gkh
+ *	Added support for the Palm i705 device, thanks to Thomas Riemer
+ *	<tom@netmech.com> for the information.
+ *
+ * (03/21/2002) gkh
+ *	Added support for the Palm m130 device, thanks to Udo Eisenbarth
+ *	<udo.eisenbarth@web.de> for the information.
+ *
  * (02/27/2002) gkh
  *	Reworked the urb handling logic.  We have no more pool, but dynamically
  *	allocate the urb and the transfer buffer on the fly.  In testing this
@@ -169,6 +181,8 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -186,6 +200,8 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M515_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_S360_ID) },
@@ -262,32 +278,32 @@
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (!port->read_urb) {
+		/* this is needed for some brain dead Sony devices */
 		err ("Device lied about number of ports, please use a lower one.");
 		return -ENODEV;
 	}
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		bytes_in = 0;
-		bytes_out = 0;
-
-		/* force low_latency on so that our tty_push actually forces the data through, 
-		   otherwise it is scheduled, and with high data rates (like with OHCI) data
-		   can get lost. */
+	bytes_in = 0;
+	bytes_out = 0;
+
+	/*
+	 * Force low_latency on so that our tty_push actually forces the data
+	 * through, otherwise it is scheduled, and with high data rates (like
+	 * with OHCI) data can get lost.
+	 */
+	if (port->tty)
 		port->tty->low_latency = 1;
-		
-		/* Start reading from the device */
-		usb_fill_bulk_urb (port->read_urb, serial->dev,
-				   usb_rcvbulkpipe (serial->dev, 
-						    port->bulk_in_endpointAddress),
-				   port->read_urb->transfer_buffer,
-				   port->read_urb->transfer_buffer_length,
-				   visor_read_bulk_callback, port);
-		result = usb_submit_urb(port->read_urb, GFP_KERNEL);
-		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
-	}
+	
+	/* Start reading from the device */
+	usb_fill_bulk_urb (port->read_urb, serial->dev,
+			   usb_rcvbulkpipe (serial->dev, 
+					    port->bulk_in_endpointAddress),
+			   port->read_urb->transfer_buffer,
+			   port->read_urb->transfer_buffer_length,
+			   visor_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	
 	return result;
 }
@@ -307,28 +323,23 @@
 	if (!serial)
 		return;
 	
-	--port->open_count;
-
-	if (port->open_count <= 0) {
-		if (serial->dev) {
-			/* only send a shutdown message if the 
-			 * device is still here */
-			transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
-			if (!transfer_buffer) {
-				err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
-			} else {
-				/* send a shutdown message to the device */
-				usb_control_msg (serial->dev,
-						 usb_rcvctrlpipe(serial->dev, 0),
-						 VISOR_CLOSE_NOTIFICATION, 0xc2,
-						 0x0000, 0x0000, 
-						 transfer_buffer, 0x12, 300);
-				kfree (transfer_buffer);
-			}
-			/* shutdown our bulk read */
-			usb_unlink_urb (port->read_urb);
+	if (serial->dev) {
+		/* only send a shutdown message if the 
+		 * device is still here */
+		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+		if (!transfer_buffer) {
+			err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+		} else {
+			/* send a shutdown message to the device */
+			usb_control_msg (serial->dev,
+					 usb_rcvctrlpipe(serial->dev, 0),
+					 VISOR_CLOSE_NOTIFICATION, 0xc2,
+					 0x0000, 0x0000, 
+					 transfer_buffer, 0x12, 300);
+			kfree (transfer_buffer);
 		}
-		port->open_count = 0;
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
 	}
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
@@ -390,7 +401,7 @@
 	usb_free_urb (urb);
 
 	return count;
-} 
+}
 
 
 static int visor_write_room (struct usb_serial_port *port)
@@ -471,7 +482,7 @@
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	tty = port->tty;
-	if (urb->actual_length) {
+	if (tty && urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
 			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
@@ -481,8 +492,8 @@
 			tty_insert_flip_char(tty, data[i], 0);
 		}
 		tty_flip_buffer_push(tty);
-		bytes_in += urb->actual_length;
 	}
+	bytes_in += urb->actual_length;
 
 	/* Continue trying to always read  */
 	usb_fill_bulk_urb (port->read_urb, serial->dev,
@@ -649,15 +660,8 @@
 
 static void visor_shutdown (struct usb_serial *serial)
 {
-	int i;
-
 	dbg (__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i)
-		serial->port[i].open_count = 0;
 }
-
 
 static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/serial/visor.h	Wed Apr  3 17:11:14 2002
@@ -24,7 +24,9 @@
 #define PALM_M500_ID			0x0001
 #define PALM_M505_ID			0x0002
 #define PALM_M515_ID			0x0003
+#define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
+#define PALM_M130_ID			0x0050
 
 #define SONY_VENDOR_ID			0x054C
 #define SONY_CLIE_3_5_ID		0x0038
diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/serial/whiteheat.c	Wed Apr  3 17:11:15 2002
@@ -306,58 +306,49 @@
 
 	dbg(__FUNCTION__" - port %d", port->number);
 
-	++port->open_count;
-	
-	if (port->open_count == 1) {
-		/* set up some stuff for our command port */
-		command_port = &port->serial->port[COMMAND_PORT];
-		if (command_port->private == NULL) {
-			info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
-			if (info == NULL) {
-				err(__FUNCTION__ " - out of memory");
-				retval = -ENOMEM;
-				goto error_exit;
-			}
-			
-			init_waitqueue_head(&info->wait_command);
-			command_port->private = info;
-			command_port->write_urb->complete = command_port_write_callback;
-			command_port->read_urb->complete = command_port_read_callback;
-			command_port->read_urb->dev = port->serial->dev;
-			command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
-			retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
-			if (retval) {
-				err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
-				goto error_exit;
-			}
+	/* set up some stuff for our command port */
+	command_port = &port->serial->port[COMMAND_PORT];
+	if (command_port->private == NULL) {
+		info = (struct whiteheat_private *)kmalloc (sizeof(struct whiteheat_private), GFP_KERNEL);
+		if (info == NULL) {
+			err(__FUNCTION__ " - out of memory");
+			retval = -ENOMEM;
+			goto exit;
 		}
 		
-		/* Start reading from the device */
-		port->read_urb->dev = port->serial->dev;
-		retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+		init_waitqueue_head(&info->wait_command);
+		command_port->private = info;
+		command_port->write_urb->complete = command_port_write_callback;
+		command_port->read_urb->complete = command_port_read_callback;
+		command_port->read_urb->dev = port->serial->dev;
+		command_port->tty = port->tty;		/* need this to "fake" our our sanity check macros */
+		retval = usb_submit_urb (command_port->read_urb, GFP_KERNEL);
 		if (retval) {
 			err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
-			goto error_exit;
+			goto exit;
 		}
+	}
 	
-		/* send an open port command */
-		/* firmware uses 1 based port numbering */
-		open_command.port = port->number - port->serial->minor + 1;
-		retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
-		if (retval)
-			goto error_exit;
-	
-		/* Need to do device specific setup here (control lines, baud rate, etc.) */
-		/* FIXME!!! */
+	/* Start reading from the device */
+	port->read_urb->dev = port->serial->dev;
+	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
+	if (retval) {
+		err(__FUNCTION__ " - failed submitting read urb, error %d", retval);
+		goto exit;
 	}
 
-	dbg(__FUNCTION__ " - exit");
-	return retval;
+	/* send an open port command */
+	/* firmware uses 1 based port numbering */
+	open_command.port = port->number - port->serial->minor + 1;
+	retval = whiteheat_send_cmd (port->serial, WHITEHEAT_OPEN, (__u8 *)&open_command, sizeof(open_command));
+	if (retval)
+		goto exit;
 
-error_exit:
-	--port->open_count;
+	/* Need to do device specific setup here (control lines, baud rate, etc.) */
+	/* FIXME!!! */
 
-	dbg(__FUNCTION__ " - error_exit");
+exit:
+	dbg(__FUNCTION__ " - exit, retval = %d", retval);
 	return retval;
 }
 
@@ -368,22 +359,17 @@
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 	
-	--port->open_count;
+	/* send a close command to the port */
+	/* firmware uses 1 based port numbering */
+	close_command.port = port->number - port->serial->minor + 1;
+	whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
 
-	if (port->open_count <= 0) {
-		/* send a close command to the port */
-		/* firmware uses 1 based port numbering */
-		close_command.port = port->number - port->serial->minor + 1;
-		whiteheat_send_cmd (port->serial, WHITEHEAT_CLOSE, (__u8 *)&close_command, sizeof(close_command));
+	/* Need to change the control lines here */
+	/* FIXME */
 	
-		/* Need to change the control lines here */
-		/* FIXME */
-		
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		port->open_count = 0;
-	}
+	/* shutdown our bulk reads and writes */
+	usb_unlink_urb (port->write_urb);
+	usb_unlink_urb (port->read_urb);
 }
 
 
@@ -641,17 +627,9 @@
 
 static void whiteheat_real_shutdown (struct usb_serial *serial)
 {
-	struct usb_serial_port 		*command_port;
-	int i;
+	struct usb_serial_port *command_port;
 
 	dbg(__FUNCTION__);
-
-	/* stop reads and writes on all ports */
-	for (i=0; i < serial->num_ports; ++i) {
-		while (serial->port[i].open_count > 0) {
-			whiteheat_close (&serial->port[i], NULL);
-		}
-	}
 
 	/* free up our private data for our command port */
 	command_port = &serial->port[COMMAND_PORT];
diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
--- a/drivers/usb/storage/transport.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/storage/transport.h	Wed Apr  3 17:11:15 2002
@@ -112,7 +112,7 @@
 #define US_BULK_GET_MAX_LUN	0xfe
 
 /*
- * us_bulk_transfer() return codes
+ * usb_stor_transfer() return codes
  */
 #define US_BULK_TRANSFER_GOOD		0  /* good transfer                 */
 #define US_BULK_TRANSFER_SHORT		1  /* transfered less than expected */
diff -Nru a/drivers/usb/tiglusb.c b/drivers/usb/tiglusb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/tiglusb.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,495 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
+ * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ *      
+ * Copyright (C) 2001-2002: 
+ *   Romain Lievin <roms@lpg.ticalc.org>
+ *   Julien BLACHE <jb@technologeek.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Based on dabusb.c, printer.c & scanner.c
+ *
+ * Please see the file: linux/Documentation/usb/SilverLink.txt 
+ * and the website at:  http://lpg.ticalc.org/prj_usb/
+ * for more info.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/usb.h>
+#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <linux/ticable.h>
+#include "tiglusb.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.02"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org> & Julien Blache <jb@jblache.org>"
+#define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
+#define DRIVER_LICENSE "GPL"
+
+
+/* ----- global variables --------------------------------------------- */
+
+static tiglusb_t tiglusb[MAXTIGL];
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+
+/*---------- misc functions ------------------------------------------- */
+
+/* Unregister device */
+static void usblp_cleanup (tiglusb_t * s)
+{
+	devfs_unregister (s->devfs);
+	//memset(tiglusb[s->minor], 0, sizeof(tiglusb_t));
+	info ("tiglusb%d removed", s->minor);
+}
+
+/* Re-initialize device */
+static int clear_device (struct usb_device *dev)
+{
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		printk ("tiglusb: clear_device failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Clear input & output pipes (endpoints) */
+static int clear_pipes (struct usb_device *dev)
+{
+	unsigned int pipe;
+
+	pipe = usb_sndbulkpipe (dev, 1);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		printk ("tiglusb: clear_pipe (r), request failed\n");
+		return -1;
+	}
+
+	pipe = usb_sndbulkpipe (dev, 2);
+	if (usb_clear_halt (dev, usb_pipeendpoint (pipe))) {
+		printk ("tiglusb: clear_pipe (w), request failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int tiglusb_open (struct inode *inode, struct file *file)
+{
+	int devnum = minor (inode->i_rdev);
+	ptiglusb_t s;
+
+	if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
+		return -EIO;
+
+	s = &tiglusb[devnum - TIUSB_MINOR];
+
+	down (&s->mutex);
+
+	while (!s->dev || s->opened) {
+		up (&s->mutex);
+
+		if (file->f_flags & O_NONBLOCK) {
+			return -EBUSY;
+		}
+		schedule_timeout (HZ / 2);
+
+		if (signal_pending (current)) {
+			return -EAGAIN;
+		}
+		down (&s->mutex);
+	}
+
+	s->opened = 1;
+	up (&s->mutex);
+
+	file->f_pos = 0;
+	file->private_data = s;
+
+	return 0;
+}
+
+static int tiglusb_release (struct inode *inode, struct file *file)
+{
+	ptiglusb_t s = (ptiglusb_t) file->private_data;
+
+	lock_kernel ();
+	down (&s->mutex);
+	s->state = _stopped;
+	up (&s->mutex);
+
+	if (!s->remove_pending)
+		clear_device (s->dev);
+	else
+		wake_up (&s->remove_ok);
+
+	s->opened = 0;
+	unlock_kernel ();
+
+	return 0;
+}
+
+static ssize_t tiglusb_read (struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	ptiglusb_t s = (ptiglusb_t) file->private_data;
+	ssize_t ret = 0;
+	int bytes_to_read = 0;
+	int bytes_read = 0;
+	int result = 0;
+	char buffer[BULK_RCV_MAX];
+	unsigned int pipe;
+
+	if (*ppos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
+
+	pipe = usb_rcvbulkpipe (s->dev, 1);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
+			       &bytes_read, HZ / (timeout / 10));
+	if (result == -ETIMEDOUT) {	/* NAK */
+		ret = result;
+		if (!bytes_read) {
+			printk ("quirk !\n");
+		}
+		warn ("tiglusb_read, NAK received.");
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("CLEAR_FEATURE request to remove STALL condition.\n");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			warn ("send_packet, request failed\n");
+		//clear_device(s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		warn ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (copy_to_user (buf, buffer, bytes_read)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+      out:
+	return ret ? ret : bytes_read;
+}
+
+static ssize_t tiglusb_write (struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	ptiglusb_t s = (ptiglusb_t) file->private_data;
+	ssize_t ret = 0;
+	int bytes_to_write = 0;
+	int bytes_written = 0;
+	int result = 0;
+	char buffer[BULK_SND_MAX];
+	unsigned int pipe;
+
+	if (*ppos)
+		return -ESPIPE;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	if (!s->dev)
+		return -EIO;
+
+	bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
+	if (copy_from_user (buffer, buf, bytes_to_write)) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	pipe = usb_sndbulkpipe (s->dev, 2);
+	result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
+			       &bytes_written, HZ / (timeout / 10));
+
+	if (result == -ETIMEDOUT) {	/* NAK */
+		warn ("tiglusb_write, NAK received.");
+		ret = result;
+		goto out;
+	} else if (result == -EPIPE) {	/* STALL -- shouldn't happen */
+		warn ("CLEAR_FEATURE request to remove STALL condition.");
+		if (usb_clear_halt (s->dev, usb_pipeendpoint (pipe)))
+			warn ("send_packet, request failed\n");
+		//clear_device(s->dev);
+		ret = result;
+		goto out;
+	} else if (result < 0) {	/* We should not get any I/O errors */
+		warn ("funky result: %d. Please notify maintainer.", result);
+		ret = -EIO;
+		goto out;
+	}
+
+	if (bytes_written != bytes_to_write) {
+		ret = -EIO;
+		goto out;
+	}
+
+      out:
+	return ret ? ret : bytes_written;
+}
+
+static int tiglusb_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	ptiglusb_t s = (ptiglusb_t) file->private_data;
+	int ret = 0;
+
+	if (s->remove_pending)
+		return -EIO;
+
+	down (&s->mutex);
+
+	if (!s->dev) {
+		up (&s->mutex);
+		return -EIO;
+	}
+
+	switch (cmd) {
+	case IOCTL_TIUSB_TIMEOUT:
+		timeout = arg;	// timeout value in tenth of seconds
+		break;
+	case IOCTL_TIUSB_RESET_DEVICE:
+		printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_DEVICE\n");
+		if (clear_device (s->dev))
+			ret = -EIO;
+		break;
+	case IOCTL_TIUSB_RESET_PIPES:
+		printk (KERN_DEBUG "IOCTL_TIGLUSB_RESET_PIPES\n");
+		if (clear_pipes (s->dev))
+			ret = -EIO;
+		break;
+	default:
+		ret = -ENOTTY;
+		break;
+	}
+
+	up (&s->mutex);
+
+	return ret;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tiglusb_fops = {
+	owner:		THIS_MODULE,
+	llseek:		no_llseek,
+	read:		tiglusb_read,
+	write:		tiglusb_write,
+	ioctl:		tiglusb_ioctl,
+	open:		tiglusb_open,
+	release:	tiglusb_release,
+};
+
+static int tiglusb_find_struct (void)
+{
+	int u;
+
+	for (u = 0; u < MAXTIGL; u++) {
+		ptiglusb_t s = &tiglusb[u];
+		if (!s->dev)
+			return u;
+	}
+
+	return -1;
+}
+
+/* --- initialisation code ------------------------------------- */
+
+static void *tiglusb_probe (struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id)
+{
+	int minor;
+	ptiglusb_t s;
+	char name[8];
+
+	printk ("tiglusb: probing vendor id 0x%x, device id 0x%x ifnum:%d\n",
+		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+
+	/* 
+	 * We don't handle multiple configurations. As of version 0x0103 of 
+	 * the TIGL hardware, there's only 1 configuration. 
+	 */
+
+	if (dev->descriptor.bNumConfigurations != 1)
+		return NULL;
+
+	if ((dev->descriptor.idProduct != 0xe001) && (dev->descriptor.idVendor != 0x451))
+		return NULL;
+
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		printk ("tiglusb_probe: set_configuration failed\n");
+		return NULL;
+	}
+
+	minor = tiglusb_find_struct ();
+	if (minor == -1)
+		return NULL;
+
+	s = &tiglusb[minor];
+
+	down (&s->mutex);
+	s->remove_pending = 0;
+	s->dev = dev;
+	up (&s->mutex);
+	dbg ("bound to interface: %d", ifnum);
+
+	sprintf (name, "%d", s->minor);
+	printk ("tiglusb: registering to devfs : major = %d, minor = %d, node = %s\n", TIUSB_MAJOR,
+		(TIUSB_MINOR + s->minor), name);
+	s->devfs =
+	    devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
+			    TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO, &tiglusb_fops,
+			    NULL);
+
+	/* Display firmware version */
+	printk ("tiglusb: link cable version %i.%02x\n",
+		dev->descriptor.bcdDevice >> 8, dev->descriptor.bcdDevice & 0xff);
+
+	return s;
+}
+
+static void tiglusb_disconnect (struct usb_device *dev, void *drv_context)
+{
+	ptiglusb_t s = (ptiglusb_t) drv_context;
+
+	if (!s || !s->dev)
+		printk ("bogus disconnect");
+
+	s->remove_pending = 1;
+	wake_up (&s->wait);
+	if (s->state == _started)
+		sleep_on (&s->remove_ok);
+	s->dev = NULL;
+	s->opened = 0;
+
+	/* cleanup now or later, on close */
+	if (!s->opened)
+		usblp_cleanup (s);
+	else
+		up (&s->mutex);
+
+	/* unregister device */
+	devfs_unregister (s->devfs);
+	s->devfs = NULL;
+	printk ("tiglusb: device disconnected\n");
+}
+
+static struct usb_device_id tiglusb_ids[] = {
+	{USB_DEVICE (0x0451, 0xe001)},
+	{}
+};
+
+MODULE_DEVICE_TABLE (usb, tiglusb_ids);
+
+static struct usb_driver tiglusb_driver = {
+	owner:		THIS_MODULE,
+	name:		"tiglusb",
+	probe:		tiglusb_probe,
+	disconnect:	tiglusb_disconnect,
+	id_table:	tiglusb_ids,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init tiglusb_setup (char *str)
+{
+	int ints[2];
+
+	str = get_options (str, ARRAY_SIZE (ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+	}
+
+	return 1;
+}
+#endif
+
+static int __init tiglusb_init (void)
+{
+	unsigned u;
+	int result;
+
+	/* initialize struct */
+	for (u = 0; u < MAXTIGL; u++) {
+		ptiglusb_t s = &tiglusb[u];
+		memset (s, 0, sizeof (tiglusb_t));
+		init_MUTEX (&s->mutex);
+		s->dev = NULL;
+		s->minor = u;
+		s->opened = 0;
+		init_waitqueue_head (&s->wait);
+		init_waitqueue_head (&s->remove_ok);
+	}
+
+	/* register device */
+	if (devfs_register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
+		printk ("tiglusb: unable to get major %d\n", TIUSB_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs, tree: /dev/ticables/usb/[0..3] */
+	devfs_handle = devfs_mk_dir (NULL, "ticables/usb", NULL);
+
+	/* register USB module */
+	result = usb_register (&tiglusb_driver);
+	if (result < 0) {
+		devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+		return -1;
+	}
+
+	info (DRIVER_DESC ", " DRIVER_VERSION);
+
+	return 0;
+}
+
+static void __exit tiglusb_cleanup (void)
+{
+	usb_deregister (&tiglusb_driver);
+	devfs_unregister (devfs_handle);
+	devfs_unregister_chrdev (TIUSB_MAJOR, "tiglusb");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup ("tipar=", tiglusb_setup);
+module_init (tiglusb_init);
+module_exit (tiglusb_cleanup);
+
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_LICENSE (DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM (timeout, "i");
+MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)");
+
+/* --------------------------------------------------------------------- */
diff -Nru a/drivers/usb/tiglusb.h b/drivers/usb/tiglusb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/tiglusb.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,55 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tiglusb - low level driver for SilverLink cable
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TIGLUSB_H
+#define _TIGLUSB_H
+
+/*
+ * Max. number of devices supported
+ */
+#define MAXTIGL		16
+
+/*
+ * Max. packetsize for IN and OUT pipes
+ */
+#define BULK_RCV_MAX	32
+#define BULK_SND_MAX	32
+
+/*
+ * The driver context...
+ */
+
+typedef enum { _stopped=0, _started } driver_state_t;
+
+typedef struct
+{
+	struct usb_device	*dev;		/* USB device handle */
+	struct semaphore	mutex;		/* locks this struct */
+	struct semaphore	sem;
+
+	wait_queue_head_t	wait;		/* for timed waits */
+	wait_queue_head_t	remove_ok;
+
+	int		minor;			/* which minor dev #? */
+	devfs_handle_t	devfs;			/* devfs device */
+
+	driver_state_t	state;			/* started/stopped */
+	int		opened;			/* tru if open */
+	int	remove_pending;
+
+	char	rd_buf[BULK_RCV_MAX];		/* read  buffer */
+	char	wr_buf[BULK_SND_MAX];		/* write buffer */
+
+} tiglusb_t, *ptiglusb_t;
+
+extern devfs_handle_t usb_devfs_handle;		/* /dev/usb dir. */
+
+#endif
diff -Nru a/drivers/usb/uhci.c b/drivers/usb/uhci.c
--- a/drivers/usb/uhci.c	Wed Apr  3 17:11:16 2002
+++ b/drivers/usb/uhci.c	Wed Apr  3 17:11:16 2002
@@ -337,6 +337,7 @@
 	qh->link = UHCI_PTR_TERM;
 
 	qh->dev = dev;
+	qh->urbp = NULL;
 
 	INIT_LIST_HEAD(&qh->list);
 	INIT_LIST_HEAD(&qh->remove_list);
@@ -411,20 +412,19 @@
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-static void uhci_remove_qh(struct uhci *uhci, struct urb *urb)
+static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
 {
-	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	unsigned long flags;
-	struct uhci_qh *qh = urbp->qh, *pqh;
+	struct uhci_qh *pqh;
 
 	if (!qh)
 		return;
 
+	qh->urbp = NULL;
+
 	/* Only go through the hoops if it's actually linked in */
 	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 	if (!list_empty(&qh->list)) {
-		qh->urbp = NULL;
-
 		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
 		if (pqh->urbp) {
@@ -619,7 +619,7 @@
 {
 	struct urb_priv *urbp;
 
-	urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+	urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC);
 	if (!urbp) {
 		err("uhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
 		return NULL;
@@ -1043,7 +1043,7 @@
 	urbp->short_control_packet = 1;
 
 	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urb);
+	uhci_remove_qh(uhci, urbp->qh);
 
 	/* Delete all of the TD's except for the status TD at the end */
 	head = &urbp->td_list;
@@ -1264,20 +1264,29 @@
 			data);
 
 		data += pktsze;
-		len -= pktsze;
+		len -= maxsze;
 
 		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			usb_pipeout(urb->pipe));
 	} while (len > 0);
 
+	/*
+	 * USB_ZERO_PACKET means adding a 0-length packet, if
+	 * direction is OUT and the transfer_length was an
+	 * exact multiple of maxsze, hence
+	 * (len = transfer_length - N * maxsze) == 0
+	 * however, if transfer_length == 0, the zero packet
+	 * was already prepared above.
+	 */
 	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
-	   urb->transfer_buffer_length) {
+	   !len && urb->transfer_buffer_length) {
 		td = uhci_alloc_td(uhci, urb->dev);
 		if (!td)
 			return -ENOMEM;
 
 		uhci_add_td_to_urb(urb, td);
-		uhci_fill_td(td, status, destination | UHCI_NULL_DATA_SIZE |
+		uhci_fill_td(td, status, destination |
+			(UHCI_NULL_DATA_SIZE << 21) |
 			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE),
 			data);
@@ -1594,7 +1603,9 @@
 	spin_unlock(&urb->lock);
 	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
 
-	uhci_call_completion(urb);
+	/* Only call completion if it was successful */
+	if (!ret)
+		uhci_call_completion(urb);
 
 	return ret;
 }
@@ -1660,6 +1671,7 @@
 		/* Interrupts are an exception */
 		if (urb->interval) {
 			uhci_add_complete(urb);
+			spin_unlock_irqrestore(&urb->lock, flags);
 			return;		/* <-- note return */
 		}
 
@@ -1734,7 +1746,8 @@
 	uhci_delete_queued_urb(uhci, urb);
 
 	/* The interrupt loop will reclaim the QH's */
-	uhci_remove_qh(uhci, urb);
+	uhci_remove_qh(uhci, urbp->qh);
+	urbp->qh = NULL;
 }
 
 static int uhci_unlink_urb(struct urb *urb)
@@ -2357,15 +2370,15 @@
 	urb->dev = NULL;
 	spin_unlock_irqrestore(&urb->lock, flags);
 
-	if (urb->complete) {
+	if (urb->complete)
 		urb->complete(urb);
 
+	if (resubmit_interrupt)
 		/* Recheck the status. The completion handler may have */
 		/*  unlinked the resubmitting interrupt URB */
 		killed = (urb->status == -ENOENT ||
 			  urb->status == -ECONNABORTED ||
 			  urb->status == -ECONNRESET);
-	}
 
 	if (resubmit_interrupt && !killed) {
 		urb->dev = dev;
@@ -2373,7 +2386,7 @@
 	} else {
 		if (is_ring && !killed) {
 			urb->dev = dev;
-			uhci_submit_urb(urb, GFP_KERNEL);
+			uhci_submit_urb(urb, GFP_ATOMIC);
 		} else {
 			/* We decrement the usage count after we're done */
 			/*  with everything */
diff -Nru a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
--- a/drivers/usb/usb-ohci.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/usb-ohci.c	Wed Apr  3 17:11:14 2002
@@ -2,7 +2,7 @@
  * URB OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * [ Initialisation is based on Linus'  ]
  * [ uhci code and gregs ohci fragments ]
@@ -11,6 +11,11 @@
  * 
  * 
  * History:
+ *
+ * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
+ *	load failure (Matthew Frederickson)
+ * 2002/01/20 async unlink fixes:  return -EINPROGRESS (per spec) and
+ *	make interrupt unlink-in-completion work (db)
  * 
  * 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
  * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
@@ -489,8 +494,7 @@
 			/* implicitly requeued */
   			urb->actual_length = 0;
   			urb->status = -EINPROGRESS;
-  			if (urb_priv->state != URB_DEL)
-  				td_submit_urb (urb);
+ 			td_submit_urb (urb);
   			break;
   			
 		case PIPE_ISOCHRONOUS:
@@ -800,6 +804,7 @@
 				/* usb_dec_dev_use done in dl_del_list() */
 				urb->status = -EINPROGRESS;
 				spin_unlock_irqrestore (&usb_ed_lock, flags);
+				return -EINPROGRESS;
 			}
 		} else {
 			urb_rm_priv (urb);
@@ -1083,6 +1088,28 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+	struct ohci	*ohci,
+	struct ed	*ed,
+	unsigned	index,
+	unsigned	period
+) {
+	for (; index < NUM_INTS; index += period) {
+		__u32	*ed_p = &ohci->hcca->int_table [index];
+
+		/* ED might have been unlinked through another path */
+		while (*ed_p != 0) {
+			if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+				*ed_p = ed->hwNextED;		
+				break;
+			}
+			ed_p = & ((dma_to_ed (ohci,
+				le32_to_cpup (ed_p)))->hwNextED);
+		}
+	}	
+}
+
 /* unlink an ed from one of the HC chains. 
  * just the link to the ed is unlinked.
  * the link from the ed still points to another operational ed or 0
@@ -1090,11 +1117,7 @@
 
 static int ep_unlink (ohci_t * ohci, ed_t * ed) 
 {
-	int int_branch;
 	int i;
-	int inter;
-	int interval;
-	__u32 * ed_p;
 
 	ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
 
@@ -1134,21 +1157,8 @@
 		break;
       
 	case PIPE_INTERRUPT:
-		int_branch = ed->int_branch;
-		interval = ed->int_interval;
-
-		for (i = 0; i < ep_rev (6, interval); i += inter) {
-			for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]), inter = 1; 
-				(*ed_p != 0) && (*ed_p != ed->hwNextED); 
-				ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED), 
-				inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval)) {				
-					if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-			  			*ed_p = ed->hwNextED;		
-			  			break;
-			  		}
-			  }
-		}
-		for (i = int_branch; i < 32; i += interval)
+		periodic_unlink (ohci, ed, 0, 1);
+		for (i = ed->int_branch; i < 32; i += ed->int_interval)
 		    ohci->ohci_int_load[i] -= ed->int_load;
 #ifdef DEBUG
 		ep_print_int_eds (ohci, "UNLINK_INT");
@@ -1159,23 +1169,13 @@
 		if (ohci->ed_isotail == ed)
 			ohci->ed_isotail = ed->ed_prev;
 		if (ed->hwNextED != 0) 
-		    (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev;
+		    (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+		    	->ed_prev = ed->ed_prev;
 				    
-		if (ed->ed_prev != NULL) {
+		if (ed->ed_prev != NULL)
 			ed->ed_prev->hwNextED = ed->hwNextED;
-		} else {
-			for (i = 0; i < 32; i++) {
-				for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]); 
-						*ed_p != 0; 
-						ed_p = &((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) {
-					// inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
-					if((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
-						*ed_p = ed->hwNextED;		
-						break;
-					}
-				}
-			}	
-		}	
+		else
+			periodic_unlink (ohci, ed, 0, 1);
 #ifdef DEBUG
 		ep_print_int_eds (ohci, "UNLINK_ISO");
 #endif
@@ -2363,7 +2363,6 @@
 static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
 {
 	ohci_t * ohci;
-	struct usb_bus * bus;
 
 	ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
 	if (!ohci)
@@ -2392,14 +2391,15 @@
 
 	INIT_LIST_HEAD (&ohci->timeout_list);
 
-	bus = usb_alloc_bus (&sohci_device_operations);
-	if (!bus) {
+	ohci->bus = usb_alloc_bus (&sohci_device_operations);
+	if (!ohci->bus) {
+		pci_set_drvdata (dev, NULL);
+		pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+				ohci->hcca, ohci->hcca_dma);
 		kfree (ohci);
 		return NULL;
 	}
-
-	ohci->bus = bus;
-	bus->hcpriv = (void *) ohci;
+	ohci->bus->hcpriv = (void *) ohci;
 
 	return ohci;
 } 
@@ -2425,9 +2425,11 @@
 		ohci->irq = -1;
 	}
 	pci_set_drvdata(ohci->ohci_dev, NULL);
-
-	usb_deregister_bus (ohci->bus);
-	usb_free_bus (ohci->bus);
+	if (ohci->bus) {
+		if (ohci->bus->busnum)
+			usb_deregister_bus (ohci->bus);
+		usb_free_bus (ohci->bus);
+	}
 
 	list_del (&ohci->ohci_hcd_list);
 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
@@ -2575,12 +2577,14 @@
 {
 	unsigned long mem_resource, mem_len;
 	void *mem_base;
+	int status;
 
 	if (pci_enable_device(dev) < 0)
 		return -ENODEV;
 
         if (!dev->irq) {
         	err("found OHCI device with no IRQ assigned. check BIOS settings!");
+		pci_disable_device (dev);
    	        return -ENODEV;
         }
 	
@@ -2589,19 +2593,28 @@
 	mem_len = pci_resource_len(dev, 0);
 	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
 		dbg ("controller already in use");
+		pci_disable_device (dev);
 		return -EBUSY;
 	}
 
 	mem_base = ioremap_nocache (mem_resource, mem_len);
 	if (!mem_base) {
 		err("Error mapping OHCI memory");
+		release_mem_region (mem_resource, mem_len);
+		pci_disable_device (dev);
 		return -EFAULT;
 	}
 
 	/* controller writes into our memory */
 	pci_set_master (dev);
 
-	return hc_found_ohci (dev, dev->irq, mem_base, id);
+	status = hc_found_ohci (dev, dev->irq, mem_base, id);
+	if (status < 0) {
+		iounmap (mem_base);
+		release_mem_region (mem_resource, mem_len);
+		pci_disable_device (dev);
+	}
+	return status;
 } 
 
 /*-------------------------------------------------------------------------*/
@@ -2639,6 +2652,7 @@
 	hc_release_ohci (ohci);
 
 	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+	pci_disable_device (dev);
 }
 
 
diff -Nru a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h
--- a/drivers/usb/usb-ohci.h	Wed Apr  3 17:11:14 2002
+++ b/drivers/usb/usb-ohci.h	Wed Apr  3 17:11:14 2002
@@ -454,7 +454,7 @@
 
 
 /* Recover a TD/ED using its collision chain */
-static inline void *
+static void *
 dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
 {
 	struct hash_t * scan = entry->head;
@@ -465,14 +465,14 @@
 	return scan->virt;
 }
 
-static inline struct ed *
+static struct ed *
 dma_to_ed (struct ohci * hc, dma_addr_t ed_dma)
 {
 	return (struct ed *) dma_to_ed_td(&(hc->ed_hash[ED_HASH_FUNC(ed_dma)]),
 				      ed_dma);
 }
 
-static inline struct td *
+static struct td *
 dma_to_td (struct ohci * hc, dma_addr_t td_dma)
 {
 	return (struct td *) dma_to_ed_td(&(hc->td_hash[TD_HASH_FUNC(td_dma)]),
@@ -480,7 +480,7 @@
 }
 
 /* Add a hash entry for a TD/ED; return true on success */
-static inline int
+static int
 hash_add_ed_td(struct hash_list_t * entry, void * virt, dma_addr_t dma)
 {
 	struct hash_t * scan;
@@ -502,14 +502,14 @@
 	return 1;
 }
 
-static inline int
+static int
 hash_add_ed (struct ohci * hc, struct ed * ed)
 {
 	return hash_add_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]),
 			ed, ed->dma);
 }
 
-static inline int
+static int
 hash_add_td (struct ohci * hc, struct td * td)
 {
 	return hash_add_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]),
@@ -517,7 +517,7 @@
 }
 
 
-static inline void
+static void
 hash_free_ed_td (struct hash_list_t * entry, void * virt)
 {
 	struct hash_t *scan, *prev;
@@ -543,13 +543,13 @@
 	}
 }
 
-static inline void
+static void
 hash_free_ed (struct ohci * hc, struct ed * ed)
 {
 	hash_free_ed_td (&(hc->ed_hash[ED_HASH_FUNC(ed->dma)]), ed);
 }
 
-static inline void
+static void
 hash_free_td (struct ohci * hc, struct td * td)
 {
 	hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td);
@@ -588,7 +588,7 @@
 }
 
 /* TDs ... */
-static inline struct td *
+static struct td *
 td_alloc (struct ohci *hc, int mem_flags)
 {
 	dma_addr_t	dma;
@@ -616,7 +616,7 @@
 
 
 /* DEV + EDs ... only the EDs need to be consistent */
-static inline struct ohci_device *
+static struct ohci_device *
 dev_alloc (struct ohci *hc, int mem_flags)
 {
 	dma_addr_t		dma;
diff -Nru a/drivers/usb/usb-uhci.c b/drivers/usb/usb-uhci.c
--- a/drivers/usb/usb-uhci.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/usb-uhci.c	Wed Apr  3 17:11:15 2002
@@ -171,7 +171,7 @@
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 _static void enable_desc_loop(uhci_t *s, struct urb *urb)
 {
-	int flags;
+	unsigned long flags;
 
 	if (urb->transfer_flags & USB_NO_FSBR)
 		return;
@@ -186,7 +186,7 @@
 /*-------------------------------------------------------------------*/
 _static void disable_desc_loop(uhci_t *s, struct urb *urb)
 {
-	int flags;
+	unsigned long flags;
 
 	if (urb->transfer_flags & USB_NO_FSBR)
 		return;
diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c
--- a/drivers/usb/usb.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/usb.c	Wed Apr  3 17:11:15 2002
@@ -791,9 +791,22 @@
 
 // usbcore-internal ...
 // but usb_dec_dev_use() is #defined to this, and that's public!!
+// FIXME the public call should BUG() whenever count goes to zero,
+// the usbcore-internal one should do so _unless_ it does so...
 void usb_free_dev(struct usb_device *dev)
 {
 	if (atomic_dec_and_test(&dev->refcnt)) {
+		/* Normally only goes to zero in usb_disconnect(), from
+		 * khubd or from roothub shutdown (rmmod/apmd/... thread).
+		 * Abnormally, roothub init errors can happen, so HCDs
+		 * call this directly.
+		 *
+		 * Otherwise this is a nasty device driver bug, often in
+		 * disconnect processing.
+		 */
+		if (in_interrupt ())
+			BUG ();
+
 		dev->bus->op->deallocate(dev);
 		usb_destroy_configuration(dev);
 
diff -Nru a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
--- a/drivers/usb/usbnet.c	Wed Apr  3 17:11:13 2002
+++ b/drivers/usb/usbnet.c	Wed Apr  3 17:11:13 2002
@@ -989,9 +989,8 @@
 			|| skb->len > FRAMED_SIZE (dev->net.mtu)) {
 		dev->stats.rx_frame_errors++;
 		dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
-			MIN_FRAMED, FRAMED_SIZE (dev->net.mtu),
-			dev->net.mtu
-			);
+			(int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu),
+			dev->net.mtu);
 		return 0;
 	}
 
diff -Nru a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c
--- a/drivers/usb/usbvideo.c	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/usbvideo.c	Wed Apr  3 17:11:15 2002
@@ -1020,7 +1020,7 @@
 	release:  usbvideo_v4l_close,
 	read:     usbvideo_v4l_read,
 	mmap:     usbvideo_v4l_mmap,
-	ioctl:    video_generic_ioctl,
+	ioctl:    usbvideo_v4l_ioctl,
 	llseek:   no_llseek,
 };
 static struct video_device usbvideo_template = {
@@ -1028,7 +1028,6 @@
 	type:         VID_TYPE_CAPTURE,
 	hardware:     VID_HARDWARE_CPIA,
 	fops:         &usbvideo_fops,
-	kernel_ioctl: usbvideo_v4l_ioctl,
 };
 
 uvd_t *usbvideo_AllocateDevice(usbvideo_t *cams)
@@ -1349,8 +1348,8 @@
  * History:
  * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
  */
-int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, void *arg)
+static int usbvideo_v4l_do_ioctl(struct inode *inode, struct file *file,
+				 unsigned int cmd, void *arg)
 {
 	uvd_t *uvd = file->private_data;
 
@@ -1553,6 +1552,12 @@
 			return -ENOIOCTLCMD;
 	}
 	return 0;
+}
+
+int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg)
+{
+	return video_usercopy(inode, file, cmd, arg, usbvideo_v4l_do_ioctl);
 }
 
 /*
diff -Nru a/drivers/usb/usbvideo.h b/drivers/usb/usbvideo.h
--- a/drivers/usb/usbvideo.h	Wed Apr  3 17:11:15 2002
+++ b/drivers/usb/usbvideo.h	Wed Apr  3 17:11:15 2002
@@ -350,7 +350,7 @@
 int usbvideo_v4l_close(struct inode *inode, struct file *file);
 int usbvideo_v4l_initialize(struct video_device *dev);
 int usbvideo_v4l_ioctl(struct inode *inode, struct file *file,
-		       unsigned int ioctlnr, void *arg);
+		       unsigned int cmd, unsigned long arg);
 int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma);
 int usbvideo_v4l_open(struct inode *inode, struct file *file);
 int usbvideo_v4l_read(struct file *file, char *buf,
diff -Nru a/drivers/video/amifb.c b/drivers/video/amifb.c
--- a/drivers/video/amifb.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/video/amifb.c	Wed Apr  3 17:11:14 2002
@@ -1132,7 +1132,6 @@
 static void amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
 static u_long chipalloc(u_long size);
 static void chipfree(void);
-static char *strtoke(char *s,const char *ct);
 
 	/*
 	 * Hardware routines
@@ -1224,22 +1223,22 @@
 	 * <H*> horizontal freq. in kHz
 	 */
 
-		if (!(p = strtoke(mcap_spec, ";")) || !*p)
+		if (!(p = strsep(&mcap_spec, ";")) || !*p)
 			goto cap_invalid;
 		vmin = simple_strtoul(p, NULL, 10);
 		if (vmin <= 0)
 			goto cap_invalid;
-		if (!(p = strtoke(NULL, ";")) || !*p)
+		if (!(p = strsep(&mcap_spec, ";")) || !*p)
 			goto cap_invalid;
 		vmax = simple_strtoul(p, NULL, 10);
 		if (vmax <= 0 || vmax <= vmin)
 			goto cap_invalid;
-		if (!(p = strtoke(NULL, ";")) || !*p)
+		if (!(p = strsep(&mcap_spec, ";")) || !*p)
 			goto cap_invalid;
 		hmin = 1000 * simple_strtoul(p, NULL, 10);
 		if (hmin <= 0)
 			goto cap_invalid;
-		if (!(p = strtoke(NULL, "")) || !*p)
+		if (!(p = strsep(&mcap_spec, "")) || !*p)
 			goto cap_invalid;
 		hmax = 1000 * simple_strtoul(p, NULL, 10);
 		if (hmax <= 0 || hmax <= hmin)
@@ -1913,29 +1912,6 @@
 		ami_reinit_copper();
 		do_vmode_full = 0;
 	}
-}
-
-	/*
-	 * A strtok which returns empty strings, too
-	 */
-
-static char __init *strtoke(char *s,const char *ct)
-{
-	char *sbegin, *send;
-	static char *ssave = NULL;
-
-	sbegin  = s ? s : ssave;
-	if (!sbegin)
-		return NULL;
-	if (*sbegin == '\0') {
-		ssave = NULL;
-		return NULL;
-	}
-	send = strpbrk(sbegin, ct);
-	if (send && *send != '\0')
-		*send++ = '\0';
-	ssave = send;
-	return sbegin;
 }
 
 /* --------------------------- Hardware routines --------------------------- */
diff -Nru a/drivers/video/atafb.c b/drivers/video/atafb.c
--- a/drivers/video/atafb.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/video/atafb.c	Wed Apr  3 17:11:14 2002
@@ -2860,28 +2860,6 @@
 	return 0;
 }
 
-/* a strtok which returns empty strings, too */
-
-static char * strtoke(char * s,const char * ct)
-{
-  char *sbegin, *send;
-  static char *ssave = NULL;
-  
-  sbegin  = s ? s : ssave;
-  if (!sbegin) {
-	  return NULL;
-  }
-  if (*sbegin == '\0') {
-    ssave = NULL;
-    return NULL;
-  }
-  send = strpbrk(sbegin, ct);
-  if (send && *send != '\0')
-    *send++ = '\0';
-  ssave = send;
-  return sbegin;
-}
-
 int __init atafb_setup( char *options )
 {
     char *this_opt;
@@ -2956,18 +2934,18 @@
 	int xres;
 	char *p;
 
-	if (!(p = strtoke(int_str, ";")) ||!*p) goto int_invalid;
+	if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
 	xres = simple_strtoul(p, NULL, 10);
-	if (!(p = strtoke(NULL, ";")) || !*p) goto int_invalid;
+	if (!(p = strsep(&int_str, ";")) || !*p) goto int_invalid;
 	sttt_xres=xres;
 	tt_yres=st_yres=simple_strtoul(p, NULL, 10);
-	if ((p=strtoke(NULL, ";")) && *p) {
+	if ((p=strsep(&int_str, ";")) && *p) {
 		sttt_xres_virtual=simple_strtoul(p, NULL, 10);
 	}
-	if ((p=strtoke(NULL, ";")) && *p) {
+	if ((p=strsep(&int_str, ";")) && *p) {
 		sttt_yres_virtual=simple_strtoul(p, NULL, 0);
 	}
-	if ((p=strtoke(NULL, ";")) && *p) {
+	if ((p=strsep(&int_str, ";")) && *p) {
 		ovsc_offset=simple_strtoul(p, NULL, 0);
 	}
 
@@ -2993,20 +2971,20 @@
 	 *
 	 * Even xres_virtual is available, we neither support panning nor hw-scrolling!
 	 */
-	if (!(p = strtoke(ext_str, ";")) ||!*p) goto ext_invalid;
+	if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
 	xres_virtual = xres = simple_strtoul(p, NULL, 10);
 	if (xres <= 0) goto ext_invalid;
 
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+	if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
 	yres = simple_strtoul(p, NULL, 10);
 	if (yres <= 0) goto ext_invalid;
 
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+	if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
 	depth = simple_strtoul(p, NULL, 10);
 	if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
 		depth != 16 && depth != 24) goto ext_invalid;
 
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+	if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
 	if (*p == 'i')
 		planes = FB_TYPE_INTERLEAVED_PLANES;
 	else if (*p == 'p')
@@ -3019,19 +2997,19 @@
 		goto ext_invalid;
 
 
-	if (!(p = strtoke(NULL, ";")) ||!*p) goto ext_invalid;
+	if (!(p = strsep(&ext_str, ";")) || !*p) goto ext_invalid;
 	addr = simple_strtoul(p, NULL, 0);
 
-	if (!(p = strtoke(NULL, ";")) ||!*p)
+	if (!(p = strsep(&ext_str, ";")) || !*p)
 		len = xres*yres*depth/8;
 	else
 		len = simple_strtoul(p, NULL, 0);
 
-	if ((p = strtoke(NULL, ";")) && *p) {
+	if ((p = strsep(&ext_str, ";")) && *p) {
 		external_vgaiobase=simple_strtoul(p, NULL, 0);
 	}
 
-	if ((p = strtoke(NULL, ";")) && *p) {
+	if ((p = strsep(&ext_str, ";")) && *p) {
 		external_bitspercol = simple_strtoul(p, NULL, 0);
 		if (external_bitspercol > 8)
 			external_bitspercol = 8;
@@ -3039,14 +3017,14 @@
 			external_bitspercol = 1;
 	}
 	
-	if ((p = strtoke(NULL, ";")) && *p) {
+	if ((p = strsep(&ext_str, ";")) && *p) {
 		if (!strcmp(p, "vga"))
 			external_card_type = IS_VGA;
 		if (!strcmp(p, "mv300"))
 			external_card_type = IS_MV300;
 	}
 
-	if ((p = strtoke(NULL, ";")) && *p) {
+	if ((p = strsep(&ext_str, ";")) && *p) {
 		xres_virtual = simple_strtoul(p, NULL, 10);
 		if (xres_virtual < xres)
 			xres_virtual = xres;
@@ -3089,16 +3067,16 @@
 	 * <V*> vertical freq. in Hz
 	 * <H*> horizontal freq. in kHz
 	 */
-	if (!(p = strtoke(mcap_spec, ";")) || !*p) goto cap_invalid;
+	if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
 	vmin = simple_strtoul(p, NULL, 10);
 	if (vmin <= 0) goto cap_invalid;
-	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+	if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
 	vmax = simple_strtoul(p, NULL, 10);
 	if (vmax <= 0 || vmax <= vmin) goto cap_invalid;
-	if (!(p = strtoke(NULL, ";")) || !*p) goto cap_invalid;
+	if (!(p = strsep(&mcap_spec, ";")) || !*p) goto cap_invalid;
 	hmin = 1000 * simple_strtoul(p, NULL, 10);
 	if (hmin <= 0) goto cap_invalid;
-	if (!(p = strtoke(NULL, "")) || !*p) goto cap_invalid;
+	if (!(p = strsep(&mcap_spec, "")) || !*p) goto cap_invalid;
 	hmax = 1000 * simple_strtoul(p, NULL, 10);
 	if (hmax <= 0 || hmax <= hmin) goto cap_invalid;
 
@@ -3117,11 +3095,11 @@
 		char *p;
 		int xres, yres, depth, temp;
 
-		if (!(p = strtoke(user_mode, ";")) || !*p) goto user_invalid;
+		if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
 		xres = simple_strtoul(p, NULL, 10);
-		if (!(p = strtoke(NULL, ";")) || !*p) goto user_invalid;
+		if (!(p = strsep(&user_mode, ";")) || !*p) goto user_invalid;
 		yres = simple_strtoul(p, NULL, 10);
-		if (!(p = strtoke(NULL, "")) || !*p) goto user_invalid;
+		if (!(p = strsep(&user_mode, "")) || !*p) goto user_invalid;
 		depth = simple_strtoul(p, NULL, 10);
 		if ((temp=get_video_mode("user0"))) {
 			default_par=temp;
diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
--- a/drivers/video/aty/atyfb_base.c	Wed Apr  3 17:11:14 2002
+++ b/drivers/video/aty/atyfb_base.c	Wed Apr  3 17:11:14 2002
@@ -178,7 +178,6 @@
 static int aty_init(struct fb_info_aty *info, const char *name);
 #ifdef CONFIG_ATARI
 static int store_video_par(char *videopar, unsigned char m64_num);
-static char *strtoke(char *s, const char *ct);
 #endif
 
 static void aty_set_crtc(const struct fb_info_aty *info,
@@ -2595,13 +2594,13 @@
 
     printk("store_video_par() '%s' \n", video_str);
 
-    if (!(p = strtoke(video_str, ";")) || !*p)
+    if (!(p = strsep(&video_str, ";")) || !*p)
 	goto mach64_invalid;
     vmembase = simple_strtoul(p, NULL, 0);
-    if (!(p = strtoke(NULL, ";")) || !*p)
+    if (!(p = strsep(&video_str, ";")) || !*p)
 	goto mach64_invalid;
     size = simple_strtoul(p, NULL, 0);
-    if (!(p = strtoke(NULL, ";")) || !*p)
+    if (!(p = strsep(&video_str, ";")) || !*p)
 	goto mach64_invalid;
     guiregbase = simple_strtoul(p, NULL, 0);
 
@@ -2615,25 +2614,6 @@
 mach64_invalid:
     phys_vmembase[m64_num]   = 0;
     return -1;
-}
-
-static char __init *strtoke(char *s, const char *ct)
-{
-    static char *ssave = NULL;
-    char *sbegin, *send;
-
-    sbegin  = s ? s : ssave;
-    if (!sbegin)
-	return NULL;
-    if (*sbegin == '\0') {
-	ssave = NULL;
-	return NULL;
-    }
-    send = strpbrk(sbegin, ct);
-    if (send && *send != '\0')
-	*send++ = '\0';
-    ssave = send;
-    return sbegin;
 }
 #endif /* CONFIG_ATARI */
 
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Wed Apr  3 17:11:13 2002
+++ b/fs/Makefile	Wed Apr  3 17:11:13 2002
@@ -16,12 +16,6 @@
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o
 
-ifeq ($(CONFIG_QUOTA),y)
-obj-y += dquot.o
-else
-obj-y += noquot.o
-endif
-
 ifneq ($(CONFIG_NFSD),n)
 ifneq ($(CONFIG_NFSD),)
 obj-y += nfsctl.o
@@ -84,6 +78,8 @@
 obj-y				+= binfmt_script.o
 
 obj-$(CONFIG_BINFMT_ELF)	+= binfmt_elf.o
+
+obj-$(CONFIG_QUOTA) += dquot.o
 
 # persistent filesystems
 obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o))
diff -Nru a/fs/adfs/super.c b/fs/adfs/super.c
--- a/fs/adfs/super.c	Wed Apr  3 17:11:13 2002
+++ b/fs/adfs/super.c	Wed Apr  3 17:11:13 2002
@@ -171,7 +171,9 @@
 	if (!options)
 		return 0;
 
-	for (opt = strtok(options, ","); opt != NULL; opt = strtok(NULL, ",")) {
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
 		value = strchr(opt, '=');
 		if (value)
 			*value++ = '\0';
diff -Nru a/fs/affs/super.c b/fs/affs/super.c
--- a/fs/affs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/affs/super.c	Wed Apr  3 17:11:15 2002
@@ -161,7 +161,9 @@
 	*mount_opts = 0;
 	if (!options)
 		return 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		f = 0;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
@@ -291,7 +293,7 @@
 
 	sb->s_magic             = AFFS_SUPER_MAGIC;
 	sb->s_op                = &affs_sops;
-	
+
 	sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
diff -Nru a/fs/autofs/inode.c b/fs/autofs/inode.c
--- a/fs/autofs/inode.c	Wed Apr  3 17:11:16 2002
+++ b/fs/autofs/inode.c	Wed Apr  3 17:11:16 2002
@@ -60,7 +60,9 @@
 	*pipefd = -1;
 
 	if ( !options ) return 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*value)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(this_char,"fd")) {
@@ -119,9 +121,10 @@
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
 
-	sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
+	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if ( !sbi )
 		goto fail_unlock;
+	memset(sbi, 0, sizeof(*sbi));
 	DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
 	s->u.generic_sbp = sbi;
diff -Nru a/fs/autofs4/inode.c b/fs/autofs4/inode.c
--- a/fs/autofs4/inode.c	Wed Apr  3 17:11:16 2002
+++ b/fs/autofs4/inode.c	Wed Apr  3 17:11:16 2002
@@ -110,7 +110,9 @@
 	*pipefd = -1;
 
 	if ( !options ) return 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(this_char,"fd")) {
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Wed Apr  3 17:11:15 2002
+++ b/fs/binfmt_elf.c	Wed Apr  3 17:11:15 2002
@@ -138,6 +138,21 @@
 	} else
 		u_platform = p;
 
+#if defined(__i386__) && defined(CONFIG_SMP)
+	/*
+	 * In some cases (e.g. Hyper-Threading), we want to avoid L1 evictions
+	 * by the processes running on the same package. One thing we can do
+	 * is to shuffle the initial stack for them.
+	 *
+	 * The conditionals here are unneeded, but kept in to make the
+	 * code behaviour the same as pre change unless we have hyperthreaded
+	 * processors. This should be cleaned up before 2.6
+	 */
+	 
+	if(smp_num_siblings > 1)
+		u_platform = u_platform - ((current->pid % 64) << 7);
+#endif	
+
 	/*
 	 * Force 16 byte _final_ alignment here for generality.
 	 */
@@ -552,7 +567,6 @@
 		/* Executables without an interpreter also need a personality  */
 		SET_PERSONALITY(elf_ex, ibcs2_interpreter);
 	}
-
 
 	/* OK, we are done with that, now set up the arg stuff,
 	   and then start this sucker up */
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Wed Apr  3 17:11:14 2002
+++ b/fs/bio.c	Wed Apr  3 17:11:14 2002
@@ -328,7 +328,7 @@
  * ll_rw_kio - submit a &struct kiobuf for I/O
  * @rw:   %READ or %WRITE
  * @kio:   the kiobuf to do I/O on
- * @dev:   target device
+ * @bdev:   target device
  * @sector:   start location on disk
  *
  * Description:
@@ -336,11 +336,12 @@
  *   &struct bio and queue them for I/O. The kiobuf given must describe
  *   a continous range of data, and must be fully prepared for I/O.
  **/
-void ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t sector)
+void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector)
 {
 	int i, offset, size, err, map_i, total_nr_pages, nr_pages;
 	struct bio_vec *bvec;
 	struct bio *bio;
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
 
 	err = 0;
 	if ((rw & WRITE) && is_read_only(dev)) {
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Wed Apr  3 17:11:13 2002
+++ b/fs/buffer.c	Wed Apr  3 17:11:13 2002
@@ -795,8 +795,11 @@
 	unlock_buffer(bh);
 	tmp = bh->b_this_page;
 	while (tmp != bh) {
-		if (buffer_async(tmp) && buffer_locked(tmp))
-			goto still_busy;
+		if (buffer_locked(tmp)) {
+			if (buffer_async(tmp))
+				goto still_busy;
+		} else if (!buffer_uptodate(tmp))
+			SetPageError(page);
 		tmp = tmp->b_this_page;
 	}
 
@@ -1716,7 +1719,7 @@
 		if (!buffer_mapped(bh)) {
 			if (iblock < lblock) {
 				if (get_block(inode, iblock, bh, 0))
-					continue;
+					SetPageError(page);
 			}
 			if (!buffer_mapped(bh)) {
 				memset(kmap(page) + i*blocksize, 0, blocksize);
@@ -1736,10 +1739,11 @@
 
 	if (!nr) {
 		/*
-		 * all buffers are uptodate - we can set the page
-		 * uptodate as well.
+		 * All buffers are uptodate - we can set the page uptodate
+		 * as well. But not if get_block() returned an error.
 		 */
-		SetPageUptodate(page);
+		if (!PageError(page))
+			SetPageUptodate(page);
 		UnlockPage(page);
 		return 0;
 	}
@@ -2122,7 +2126,7 @@
 	}
 
 	/* This does not understand multi-device filesystems currently */
-	retval = brw_kiovec(rw, 1, &iobuf, inode->i_dev, blocks, blocksize);
+	retval = brw_kiovec(rw, 1, &iobuf, inode->i_sb->s_bdev, blocks, blocksize);
 
  out:
 	return retval;
@@ -2138,8 +2142,8 @@
  * It is up to the caller to make sure that there are enough blocks
  * passed in to completely map the iobufs to disk.
  */
-int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], kdev_t dev, sector_t b[],
-	       int size)
+int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
+	       struct block_device *bdev, sector_t b[], int size)
 {
 	int		transferred;
 	int		i;
@@ -2167,7 +2171,7 @@
 		iobuf = iovec[i];
 		iobuf->errno = 0;
 
-		ll_rw_kio(rw, iobuf, dev, b[i] * (size >> 9));
+		ll_rw_kio(rw, iobuf, bdev, b[i] * (size >> 9));
 	}
 
 	/*
diff -Nru a/fs/devpts/inode.c b/fs/devpts/inode.c
--- a/fs/devpts/inode.c	Wed Apr  3 17:11:14 2002
+++ b/fs/devpts/inode.c	Wed Apr  3 17:11:14 2002
@@ -66,9 +66,9 @@
 	char *this_char, *value;
 
 	this_char = NULL;
-	if ( options )
-		this_char = strtok(options,",");
-	for ( ; this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(this_char,"uid")) {
@@ -123,9 +123,10 @@
 	struct inode * inode;
 	struct devpts_sb_info *sbi;
 
-	sbi = (struct devpts_sb_info *) kmalloc(sizeof(struct devpts_sb_info), GFP_KERNEL);
+	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if ( !sbi )
 		goto fail;
+	memset(sbi, 0, sizeof(*sbi));
 
 	sbi->magic  = DEVPTS_SBI_MAGIC;
 	sbi->max_ptys = unix98_max_ptys;
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Wed Apr  3 17:11:14 2002
+++ b/fs/dquot.c	Wed Apr  3 17:11:14 2002
@@ -59,6 +59,7 @@
 #include <linux/tty.h>
 #include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
@@ -1240,9 +1241,22 @@
 	return ret;
 }
 
+static ctl_table fs_table[] = {
+	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
+	 0444, NULL, &proc_dointvec},
+	{},
+};
+
+static ctl_table dquot_table[] = {
+	{CTL_FS, "fs", NULL, 0, 0555, fs_table},
+	{},
+};
+
 static int __init dquot_init(void)
 {
 	int i;
+
+	register_sysctl_table(dquot_table, 0);
 
 	for (i = 0; i < NR_DQHASH; i++)
 		INIT_LIST_HEAD(dquot_hash + i);
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/ext2/super.c	Wed Apr  3 17:11:15 2002
@@ -221,9 +221,9 @@
 
 	if (!options)
 		return 1;
-	for (this_char = strtok (options, ",");
-	     this_char != NULL;
-	     this_char = strtok (NULL, ",")) {
+	while ((this_char = strsep (&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
 		if (!strcmp (this_char, "bsddf"))
@@ -465,11 +465,11 @@
 	int db_count;
 	int i, j;
 
-	sbi = kmalloc(sizeof(struct ext2_super_block), GFP_KERNEL);
+	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
 	if (!sbi)
 		return -ENOMEM;
 	sb->u.generic_sbp = sbi;
-	memset(sbi, 0, sizeof(struct ext2_super_block));
+	memset(sbi, 0, sizeof(*sbi));
 
 	/*
 	 * See what the current blocksize for the device is, and
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Wed Apr  3 17:11:16 2002
+++ b/fs/ext3/super.c	Wed Apr  3 17:11:16 2002
@@ -554,9 +554,9 @@
 
 	if (!options)
 		return 1;
-	for (this_char = strtok (options, ",");
-	     this_char != NULL;
-	     this_char = strtok (NULL, ",")) {
+	while ((this_char = strsep (&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
 		if (!strcmp (this_char, "bsddf"))
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Wed Apr  3 17:11:15 2002
+++ b/fs/fat/inode.c	Wed Apr  3 17:11:15 2002
@@ -177,7 +177,6 @@
 		fat_clusters_flush(sb);
 	}
 	fat_cache_inval_dev(sb);
-	set_blocksize (sb->s_dev,BLOCK_SIZE);
 	if (sbi->nls_disk) {
 		unload_nls(sbi->nls_disk);
 		sbi->nls_disk = NULL;
@@ -225,8 +224,9 @@
 		goto out;
 	save = 0;
 	savep = NULL;
-	for (this_char = strtok(options,","); this_char;
-	     this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL) {
 			save = *value;
 			savep = value;
diff -Nru a/fs/filesystems.c b/fs/filesystems.c
--- a/fs/filesystems.c	Wed Apr  3 17:11:16 2002
+++ b/fs/filesystems.c	Wed Apr  3 17:11:16 2002
@@ -6,10 +6,9 @@
  *  table of configured filesystems
  */
 
-#include <linux/config.h>
+#include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
-#define __NO_VERSION__
 #include <linux/module.h>
 #include <asm/uaccess.h>
 
diff -Nru a/fs/hfs/super.c b/fs/hfs/super.c
--- a/fs/hfs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/hfs/super.c	Wed Apr  3 17:11:15 2002
@@ -32,6 +32,8 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
+MODULE_LICENSE("GPL");
+
 /*================ Forward declarations ================*/
 
 static void hfs_read_inode(struct inode *);
@@ -176,9 +178,6 @@
 	/* release the MDB's resources */
 	hfs_mdb_put(mdb, sb->s_flags & MS_RDONLY);
 
-	/* restore default blocksize for the device */
-	set_blocksize(sb->s_dev, BLOCK_SIZE);
-
 	kfree(sb->u.generic_sbp);
 	sb->u.generic_sbp = NULL;
 }
@@ -240,8 +239,9 @@
 	if (!options) {
 		goto done;
 	}
-	for (this_char = strtok(options,","); this_char;
-	     this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL) {
 			*value++ = 0;
 		}
@@ -449,7 +449,6 @@
 	struct hfs_sb_info *sbi;
 	struct hfs_mdb *mdb;
 	struct hfs_cat_key key;
-	kdev_t dev = s->s_dev;
 	hfs_s32 part_size, part_start;
 	struct inode *root_inode;
 	int part;
@@ -462,7 +461,7 @@
 
 	if (!parse_options((char *)data, sbi, &part)) {
 		hfs_warn("hfs_fs: unable to parse mount options.\n");
-		goto bail3;
+		goto bail2;
 	}
 
 	/* set the device driver to 512-byte blocks */
@@ -530,10 +529,8 @@
 bail1:
 	hfs_mdb_put(mdb, s->s_flags & MS_RDONLY);
 bail2:
-	set_blocksize(dev, BLOCK_SIZE);
-bail3:
 	kfree(sbi);
-	sb->u.generic_sbp = NULL;
+	s->u.generic_sbp = NULL;
 	return -EINVAL;	
 }
 
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/hpfs/super.c	Wed Apr  3 17:11:15 2002
@@ -3,7 +3,7 @@
  *
  *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
  *
- *  mouning, unmounting, error handling
+ *  mounting, unmounting, error handling
  */
 
 #include <linux/string.h>
@@ -222,7 +222,9 @@
 
 	/*printk("Parsing opts: '%s'\n",opts);*/
 
-	for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) {
+	while ((p = strsep(&opts, ",")) != NULL) {
+		if (!*p)
+			continue;
 		if ((rhs = strchr(p, '=')) != 0)
 			*rhs++ = '\0';
 		if (!strcmp(p, "help")) return 2;
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Wed Apr  3 17:11:15 2002
+++ b/fs/inode.c	Wed Apr  3 17:11:15 2002
@@ -657,10 +657,14 @@
 int invalidate_device(kdev_t dev, int do_sync)
 {
 	struct super_block *sb;
+	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
 	int res;
 
+	if (!bdev)
+		return 0;
+
 	if (do_sync)
-		fsync_dev(dev);
+		fsync_bdev(bdev);
 
 	res = 0;
 	sb = get_super(dev);
@@ -675,7 +679,8 @@
 		res = invalidate_inodes(sb);
 		drop_super(sb);
 	}
-	invalidate_buffers(dev);
+	invalidate_bdev(bdev, 0);
+	bdput(bdev);
 	return res;
 }
 
@@ -1191,6 +1196,8 @@
  
 void update_atime (struct inode *inode)
 {
+	if (inode->i_atime == CURRENT_TIME)
+		return;
 	if ( IS_NOATIME (inode) ) return;
 	if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return;
 	if ( IS_RDONLY (inode) ) return;
diff -Nru a/fs/intermezzo/super.c b/fs/intermezzo/super.c
--- a/fs/intermezzo/super.c	Wed Apr  3 17:11:16 2002
+++ b/fs/intermezzo/super.c	Wed Apr  3 17:11:16 2002
@@ -120,12 +120,12 @@
         store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0"); 
 
         CDEBUG(D_SUPER, "parsing options\n");
-        for (this_char = strtok (options, ",");
-             this_char != NULL;
-             this_char = strtok (NULL, ",")) {
+        while ((this_char = strsep (&options, ",")) != NULL) {
                 char *opt;
                 CDEBUG(D_SUPER, "this_char %s\n", this_char);
 
+        	if (!*this_char)
+        		continue;
                 if ( (opt = read_opt("fileset", this_char)) ) {
                         store_opt(fileset, opt, NULL);
                         continue;
diff -Nru a/fs/iobuf.c b/fs/iobuf.c
--- a/fs/iobuf.c	Wed Apr  3 17:11:14 2002
+++ b/fs/iobuf.c	Wed Apr  3 17:11:14 2002
@@ -28,11 +28,14 @@
 
 static void kiobuf_init(struct kiobuf *iobuf)
 {
-	memset(iobuf, 0, sizeof(*iobuf));
 	init_waitqueue_head(&iobuf->wait_queue);
 	atomic_set(&iobuf->io_count, 0);
 	iobuf->array_len = KIO_STATIC_PAGES;
 	iobuf->maplist   = iobuf->map_array;
+	iobuf->nr_pages   = 0;
+	iobuf->locked   = 0;
+	iobuf->io_count.counter   = 0;
+	iobuf->end_io = NULL;
 }
 
 int alloc_kiovec(int nr, struct kiobuf **bufp)
diff -Nru a/fs/isofs/inode.c b/fs/isofs/inode.c
--- a/fs/isofs/inode.c	Wed Apr  3 17:11:16 2002
+++ b/fs/isofs/inode.c	Wed Apr  3 17:11:16 2002
@@ -341,7 +341,9 @@
 	popt->session=-1;
 	popt->sbsector=-1;
 	if (!options) return 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 	        if (strncmp(this_char,"norock",6) == 0) {
 		  popt->rock = 'n';
 		  continue;
diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c
--- a/fs/jbd/journal.c	Wed Apr  3 17:11:14 2002
+++ b/fs/jbd/journal.c	Wed Apr  3 17:11:14 2002
@@ -894,7 +894,7 @@
 		__brelse(bh);
 	}
 
-	fsync_dev(to_kdev_t(journal->j_dev->bd_dev));
+	fsync_bdev(journal->j_dev);
 	jbd_debug(1, "JBD: journal cleared.\n");
 
 	/* OK, fill in the initial static fields in the new superblock */
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Wed Apr  3 17:11:15 2002
+++ b/fs/jfs/jfs_logmgr.c	Wed Apr  3 17:11:15 2002
@@ -66,6 +66,7 @@
 #include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
+#include <linux/completion.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
@@ -1594,7 +1595,7 @@
 		return rc;
 
 	logsuper = (logsuper_t *) bpsuper->l_ldata;
-	bit = MINOR(fsdev);
+	bit = minor(fsdev);
 	word = bit / 32;
 	bit -= 32 * word;
 	if (activate)
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Wed Apr  3 17:11:14 2002
+++ b/fs/jfs/jfs_txnmgr.c	Wed Apr  3 17:11:14 2002
@@ -47,6 +47,7 @@
 #include <linux/locks.h>
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
+#include <linux/completion.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
 #include "jfs_metapage.h"
@@ -2777,6 +2778,7 @@
 	complete(&jfsIOwait);
 
 	do {
+		LAZY_LOCK(flags);
 restart:
 		WorkDone = 0;
 		while ((tblk = TxAnchor.unlock_queue)) {
@@ -2788,7 +2790,6 @@
 			 */
 			WorkDone = 1;
 
-			LAZY_LOCK(flags);
 			/*
 			 * Remove first transaction from queue
 			 */
@@ -2808,11 +2809,13 @@
 				current->state = TASK_RUNNING;
 				schedule();
 			}
+			LAZY_LOCK(flags);
 		}
 
 		if (WorkDone)
 			goto restart;
-		
+
+		LAZY_UNLOCK(flags);
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
 	} while (!jfs_thread_stopped());
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/jfs/super.c	Wed Apr  3 17:11:15 2002
@@ -22,6 +22,7 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/completion.h>
 #include <asm/uaccess.h>
 #include "jfs_incore.h"
 #include "jfs_filsys.h"
@@ -170,9 +171,9 @@
 
 	if (!options)
 		return 1;
-	for (this_char = strtok (options, ",");
-	     this_char != NULL;
-	     this_char = strtok (NULL, ",")) {
+	while ((this_char = strsep (&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
 		if (!strcmp (this_char, "iocharset")) {
@@ -268,10 +269,7 @@
 	/*
 	 * Initialize blocksize to 4K.
 	 */
-	sb->s_blocksize = PSIZE;
-	sb->s_blocksize_bits = L2PSIZE;
-	set_blocksize(sb->s_dev, PSIZE);
-
+	sb_set_blocksize(sb, PSIZE);
 	sb->s_op = &jfs_sops;
 	/*
 	 * Initialize direct-mapping inode/address-space
diff -Nru a/fs/minix/bitmap.c b/fs/minix/bitmap.c
--- a/fs/minix/bitmap.c	Wed Apr  3 17:11:14 2002
+++ b/fs/minix/bitmap.c	Wed Apr  3 17:11:14 2002
@@ -11,10 +11,8 @@
 
 /* bitmap.c contains the code that handles the inode and block bitmaps */
 
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/locks.h>
-
+#include "minix.h"
+#include <linux/smp_lock.h>
 #include <asm/bitops.h>
 
 static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
@@ -56,12 +54,7 @@
 	struct buffer_head * bh;
 	unsigned int bit,zone;
 
-	if (!sb) {
-		printk("trying to free block on nonexistent device\n");
-		return;
-	}
-	if (block < sbi->s_firstdatazone ||
-	    block >= sbi->s_nzones) {
+	if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
 		printk("trying to free block not in datazone\n");
 		return;
 	}
@@ -73,49 +66,41 @@
 		return;
 	}
 	bh = sbi->s_zmap[zone];
+	lock_kernel();
 	if (!minix_test_and_clear_bit(bit,bh->b_data))
 		printk("free_block (%s:%d): bit already cleared\n",
 		       sb->s_id, block);
+	unlock_kernel();
 	mark_buffer_dirty(bh);
 	return;
 }
 
 int minix_new_block(struct inode * inode)
 {
-	struct super_block * sb = inode->i_sb;
-	struct minix_sb_info * sbi = minix_sb(sb);
-	struct buffer_head * bh;
-	int i,j;
+	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
+	int i;
 
-	if (!sb) {
-		printk("trying to get new block from nonexistent device\n");
-		return 0;
-	}
-repeat:
-	j = 8192;
-	bh = NULL;
 	for (i = 0; i < sbi->s_zmap_blocks; i++) {
-		bh = sbi->s_zmap[i];
-		if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
-			break;
-	}
-	if (!bh || j >= 8192)
-		return 0;
-	if (minix_test_and_set_bit(j,bh->b_data)) {
-		printk("new_block: bit already set");
-		goto repeat;
+		struct buffer_head *bh = sbi->s_zmap[i];
+		int j;
+
+		lock_kernel();
+		if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) {
+			minix_set_bit(j,bh->b_data);
+			unlock_kernel();
+			mark_buffer_dirty(bh);
+			j += i*8192 + sbi->s_firstdatazone-1;
+			if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
+				break;
+			return j;
+		}
+		unlock_kernel();
 	}
-	mark_buffer_dirty(bh);
-	j += i*8192 + sbi->s_firstdatazone-1;
-	if (j < sbi->s_firstdatazone ||
-	    j >= sbi->s_nzones)
-		return 0;
-	return j;
+	return 0;
 }
 
-unsigned long minix_count_free_blocks(struct super_block *sb)
+unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
 {
-	struct minix_sb_info *sbi = minix_sb(sb);
 	return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
 		sbi->s_nzones - sbi->s_firstdatazone + 1)
 		<< sbi->s_log_zone_size);
@@ -198,36 +183,38 @@
 
 void minix_free_inode(struct inode * inode)
 {
+	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
 	struct buffer_head * bh;
 	unsigned long ino;
 
-	if (inode->i_ino < 1 || inode->i_ino > minix_sb(inode->i_sb)->s_ninodes) {
+	if (inode->i_ino < 1 || inode->i_ino > sbi->s_ninodes) {
 		printk("free_inode: inode 0 or nonexistent inode\n");
 		return;
 	}
 	ino = inode->i_ino;
-	if ((ino >> 13) >= minix_sb(inode->i_sb)->s_imap_blocks) {
+	if ((ino >> 13) >= sbi->s_imap_blocks) {
 		printk("free_inode: nonexistent imap in superblock\n");
 		return;
 	}
 
-	bh = minix_sb(inode->i_sb)->s_imap[ino >> 13];
+	bh = sbi->s_imap[ino >> 13];
 	minix_clear_inode(inode);
 	clear_inode(inode);
+	lock_kernel();
 	if (!minix_test_and_clear_bit(ino & 8191, bh->b_data))
 		printk("free_inode: bit %lu already cleared.\n",ino);
+	unlock_kernel();
 	mark_buffer_dirty(bh);
 }
 
 struct inode * minix_new_inode(const struct inode * dir, int * error)
 {
-	struct super_block * sb;
-	struct inode * inode;
+	struct super_block *sb = dir->i_sb;
+	struct minix_sb_info *sbi = minix_sb(sb);
+	struct inode *inode = new_inode(sb);
 	struct buffer_head * bh;
 	int i,j;
 
-	sb = dir->i_sb;
-	inode = new_inode(sb);
 	if (!inode) {
 		*error = -ENOMEM;
 		return NULL;
@@ -235,28 +222,28 @@
 	j = 8192;
 	bh = NULL;
 	*error = -ENOSPC;
-	lock_super(sb);
-	for (i = 0; i < minix_sb(sb)->s_imap_blocks; i++) {
-		bh = minix_sb(inode->i_sb)->s_imap[i];
+	lock_kernel();
+	for (i = 0; i < sbi->s_imap_blocks; i++) {
+		bh = sbi->s_imap[i];
 		if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192)
 			break;
 	}
 	if (!bh || j >= 8192) {
+		unlock_kernel();
 		iput(inode);
-		unlock_super(sb);
 		return NULL;
 	}
 	if (minix_test_and_set_bit(j,bh->b_data)) {	/* shouldn't happen */
 		printk("new_inode: bit already set");
+		unlock_kernel();
 		iput(inode);
-		unlock_super(sb);
 		return NULL;
 	}
+	unlock_kernel();
 	mark_buffer_dirty(bh);
 	j += i*8192;
-	if (!j || j > minix_sb(inode->i_sb)->s_ninodes) {
+	if (!j || j > sbi->s_ninodes) {
 		iput(inode);
-		unlock_super(sb);
 		return NULL;
 	}
 	inode->i_uid = current->fsuid;
@@ -268,13 +255,11 @@
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
-	unlock_super(sb);
 	*error = 0;
 	return inode;
 }
 
-unsigned long minix_count_free_inodes(struct super_block *sb)
+unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
 {
-	return count_free(minix_sb(sb)->s_imap, minix_sb(sb)->s_imap_blocks,
-		minix_sb(sb)->s_ninodes + 1);
+	return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
 }
diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c
--- a/fs/minix/dir.c	Wed Apr  3 17:11:14 2002
+++ b/fs/minix/dir.c	Wed Apr  3 17:11:14 2002
@@ -6,9 +6,7 @@
  *  minix directory handling functions
  */
 
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/pagemap.h>
+#include "minix.h"
 
 typedef struct minix_dir_entry minix_dirent;
 
diff -Nru a/fs/minix/file.c b/fs/minix/file.c
--- a/fs/minix/file.c	Wed Apr  3 17:11:15 2002
+++ b/fs/minix/file.c	Wed Apr  3 17:11:15 2002
@@ -6,8 +6,7 @@
  *  minix regular file handling primitives
  */
 
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
 
 /*
  * We have mostly NULLs here: the current defaults are OK for
diff -Nru a/fs/minix/inode.c b/fs/minix/inode.c
--- a/fs/minix/inode.c	Wed Apr  3 17:11:15 2002
+++ b/fs/minix/inode.c	Wed Apr  3 17:11:15 2002
@@ -10,15 +10,11 @@
  */
 
 #include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
 #include <linux/slab.h>
 #include <linux/locks.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/highuid.h>
-#include <linux/blkdev.h>
 
 static void minix_read_inode(struct inode * inode);
 static void minix_write_inode(struct inode * inode, int wait);
@@ -29,32 +25,9 @@
 {
 	inode->i_size = 0;
 	minix_truncate(inode);
-	lock_kernel();
 	minix_free_inode(inode);
-	unlock_kernel();
-}
-
-static void minix_commit_super(struct super_block * sb)
-{
-	mark_buffer_dirty(minix_sb(sb)->s_sbh);
-	sb->s_dirt = 0;
-}
-
-static void minix_write_super(struct super_block * sb)
-{
-	struct minix_super_block * ms;
-
-	if (!(sb->s_flags & MS_RDONLY)) {
-		ms = minix_sb(sb)->s_ms;
-
-		if (ms->s_state & MINIX_VALID_FS)
-			ms->s_state &= ~MINIX_VALID_FS;
-		minix_commit_super(sb);
-	}
-	sb->s_dirt = 0;
 }
 
-
 static void minix_put_super(struct super_block *sb)
 {
 	int i;
@@ -125,7 +98,6 @@
 	write_inode:	minix_write_inode,
 	delete_inode:	minix_delete_inode,
 	put_super:	minix_put_super,
-	write_super:	minix_write_super,
 	statfs:		minix_statfs,
 	remount_fs:	minix_remount,
 };
@@ -145,15 +117,11 @@
 		/* Mounting a rw partition read-only. */
 		ms->s_state = sbi->s_mount_state;
 		mark_buffer_dirty(sbi->s_sbh);
-		sb->s_dirt = 1;
-		minix_commit_super(sb);
-	}
-	else {
+	} else {
 	  	/* Mount a partition which is read-only, read-write. */
 		sbi->s_mount_state = ms->s_state;
 		ms->s_state &= ~MINIX_VALID_FS;
 		mark_buffer_dirty(sbi->s_sbh);
-		sb->s_dirt = 1;
 
 		if (!(sbi->s_mount_state & MINIX_VALID_FS))
 			printk ("MINIX-fs warning: remounting unchecked fs, "
@@ -272,7 +240,6 @@
 	if (!(s->s_flags & MS_RDONLY)) {
 		ms->s_state &= ~MINIX_VALID_FS;
 		mark_buffer_dirty(bh);
-		s->s_dirt = 1;
 	}
 	if (!(sbi->s_mount_state & MINIX_VALID_FS))
 		printk ("MINIX-fs: mounting unchecked file system, "
@@ -332,10 +299,10 @@
 	buf->f_type = sb->s_magic;
 	buf->f_bsize = sb->s_blocksize;
 	buf->f_blocks = (sbi->s_nzones - sbi->s_firstdatazone) << sbi->s_log_zone_size;
-	buf->f_bfree = minix_count_free_blocks(sb);
+	buf->f_bfree = minix_count_free_blocks(sbi);
 	buf->f_bavail = buf->f_bfree;
 	buf->f_files = sbi->s_ninodes;
-	buf->f_ffree = minix_count_free_inodes(sb);
+	buf->f_ffree = minix_count_free_inodes(sbi);
 	buf->f_namelen = sbi->s_namelen;
 	return 0;
 }
@@ -526,12 +493,7 @@
 
 static void minix_write_inode(struct inode * inode, int wait)
 {
-	struct buffer_head *bh;
-
-	lock_kernel();
-	bh = minix_update_inode(inode);
-	unlock_kernel();
-	brelse(bh);
+	brelse(minix_update_inode(inode));
 }
 
 int minix_sync_inode(struct inode * inode)
@@ -562,12 +524,10 @@
  */
 void minix_truncate(struct inode * inode)
 {
-	lock_kernel();
 	if (INODE_VERSION(inode) == MINIX_V1)
 		V1_minix_truncate(inode);
 	else
 		V2_minix_truncate(inode);
-	unlock_kernel();
 }
 
 static struct super_block *minix_get_sb(struct file_system_type *fs_type,
diff -Nru a/fs/minix/itree_common.c b/fs/minix/itree_common.c
--- a/fs/minix/itree_common.c	Wed Apr  3 17:11:14 2002
+++ b/fs/minix/itree_common.c	Wed Apr  3 17:11:14 2002
@@ -6,6 +6,8 @@
 	struct buffer_head *bh;
 } Indirect;
 
+static rwlock_t pointers_lock = RW_LOCK_UNLOCKED;
+
 static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v)
 {
 	p->key = *(p->p = v);
@@ -43,17 +45,18 @@
 		bh = sb_bread(sb, block_to_cpu(p->key));
 		if (!bh)
 			goto failure;
-		/* Reader: pointers */
+		read_lock(&pointers_lock);
 		if (!verify_chain(chain, p))
 			goto changed;
 		add_chain(++p, bh, (block_t *)bh->b_data + *++offsets);
-		/* Reader: end */
+		read_unlock(&pointers_lock);
 		if (!p->key)
 			goto no_block;
 	}
 	return NULL;
 
 changed:
+	read_unlock(&pointers_lock);
 	*err = -EAGAIN;
 	goto no_block;
 failure:
@@ -108,18 +111,15 @@
 {
 	int i;
 
-	/* Verify that place we are splicing to is still there and vacant */
+	write_lock(&pointers_lock);
 
-	/* Writer: pointers */
+	/* Verify that place we are splicing to is still there and vacant */
 	if (!verify_chain(chain, where-1) || *where->p)
-		/* Writer: end */
 		goto changed;
 
-	/* That's it */
-
 	*where->p = where->key;
 
-	/* Writer: end */
+	write_unlock(&pointers_lock);
 
 	/* We are done with atomic stuff, now do the rest of housekeeping */
 
@@ -133,6 +133,7 @@
 	return 0;
 
 changed:
+	write_unlock(&pointers_lock);
 	for (i = 1; i < num; i++)
 		bforget(where[i].bh);
 	for (i = 0; i < num; i++)
@@ -153,7 +154,6 @@
 	if (depth == 0)
 		goto out;
 
-	lock_kernel();
 reread:
 	partial = get_branch(inode, depth, offsets, chain, &err);
 
@@ -173,7 +173,6 @@
 			brelse(partial->bh);
 			partial--;
 		}
-		unlock_kernel();
 out:
 		return err;
 	}
@@ -226,12 +225,14 @@
 	for (k = depth; k > 1 && !offsets[k-1]; k--)
 		;
 	partial = get_branch(inode, k, offsets, chain, &err);
-	/* Writer: pointers */
+
+	write_lock(&pointers_lock);
 	if (!partial)
 		partial = chain + k-1;
-	if (!partial->key && *partial->p)
-		/* Writer: end */
+	if (!partial->key && *partial->p) {
+		write_unlock(&pointers_lock);
 		goto no_top;
+	}
 	for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--)
 		;
 	if (p == chain + k - 1 && p > chain) {
@@ -240,7 +241,7 @@
 		*top = *p->p;
 		*p->p = 0;
 	}
-	/* Writer: end */
+	write_unlock(&pointers_lock);
 
 	while(partial > p)
 	{
diff -Nru a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
--- a/fs/minix/itree_v1.c	Wed Apr  3 17:11:15 2002
+++ b/fs/minix/itree_v1.c	Wed Apr  3 17:11:15 2002
@@ -1,7 +1,5 @@
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
 #include <linux/locks.h>
-#include <linux/smp_lock.h>
 
 enum {DEPTH = 3, DIRECT = 7};	/* Only double indirect */
 
diff -Nru a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
--- a/fs/minix/itree_v2.c	Wed Apr  3 17:11:14 2002
+++ b/fs/minix/itree_v2.c	Wed Apr  3 17:11:14 2002
@@ -1,7 +1,5 @@
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
+#include "minix.h"
 #include <linux/locks.h>
-#include <linux/smp_lock.h>
 
 enum {DIRECT = 7, DEPTH = 4};	/* Have triple indirect */
 
diff -Nru a/fs/minix/minix.h b/fs/minix/minix.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/minix/minix.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,91 @@
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/minix_fs.h>
+
+/*
+ * change the define below to 0 if you want names > info->s_namelen chars to be
+ * truncated. Else they will be disallowed (ENAMETOOLONG).
+ */
+#define NO_TRUNCATE 1
+
+#define INODE_VERSION(inode)	minix_sb(inode->i_sb)->s_version
+
+#define MINIX_V1		0x0001		/* original minix fs */
+#define MINIX_V2		0x0002		/* minix V2 fs */
+
+/*
+ * minix fs inode data in memory
+ */
+struct minix_inode_info {
+	union {
+		__u16 i1_data[16];
+		__u32 i2_data[16];
+	} u;
+	struct inode vfs_inode;
+};
+
+/*
+ * minix super-block data in memory
+ */
+struct minix_sb_info {
+	unsigned long s_ninodes;
+	unsigned long s_nzones;
+	unsigned long s_imap_blocks;
+	unsigned long s_zmap_blocks;
+	unsigned long s_firstdatazone;
+	unsigned long s_log_zone_size;
+	unsigned long s_max_size;
+	int s_dirsize;
+	int s_namelen;
+	int s_link_max;
+	struct buffer_head ** s_imap;
+	struct buffer_head ** s_zmap;
+	struct buffer_head * s_sbh;
+	struct minix_super_block * s_ms;
+	unsigned short s_mount_state;
+	unsigned short s_version;
+};
+
+extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
+extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
+extern struct inode * minix_new_inode(const struct inode * dir, int * error);
+extern void minix_free_inode(struct inode * inode);
+extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi);
+extern int minix_new_block(struct inode * inode);
+extern void minix_free_block(struct inode * inode, int block);
+extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
+
+extern void V1_minix_truncate(struct inode *);
+extern void V2_minix_truncate(struct inode *);
+extern void minix_truncate(struct inode *);
+extern int minix_sync_inode(struct inode *);
+extern void minix_set_inode(struct inode *, dev_t);
+extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
+extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
+
+extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
+extern int minix_add_link(struct dentry*, struct inode*);
+extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
+extern int minix_make_empty(struct inode*, struct inode*);
+extern int minix_empty_dir(struct inode*);
+extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
+extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
+extern ino_t minix_inode_by_name(struct dentry*);
+
+extern int minix_sync_file(struct file *, struct dentry *, int);
+
+extern struct inode_operations minix_file_inode_operations;
+extern struct inode_operations minix_dir_inode_operations;
+extern struct file_operations minix_file_operations;
+extern struct file_operations minix_dir_operations;
+extern struct dentry_operations minix_dentry_operations;
+
+static inline struct minix_sb_info *minix_sb(struct super_block *sb)
+{
+	return sb->u.generic_sbp;
+}
+
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+	return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
diff -Nru a/fs/minix/namei.c b/fs/minix/namei.c
--- a/fs/minix/namei.c	Wed Apr  3 17:11:15 2002
+++ b/fs/minix/namei.c	Wed Apr  3 17:11:15 2002
@@ -4,9 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
-#include <linux/fs.h>
-#include <linux/minix_fs.h>
-#include <linux/pagemap.h>
+#include "minix.h"
 
 static inline void inc_count(struct inode *inode)
 {
diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
--- a/fs/nfs/nfsroot.c	Wed Apr  3 17:11:16 2002
+++ b/fs/nfs/nfsroot.c	Wed Apr  3 17:11:16 2002
@@ -202,8 +202,9 @@
 
 	if ((options = strchr(name, ','))) {
 		*options++ = 0;
-		cp = strtok(options, ",");
-		while (cp) {
+		while ((cp = strsep(&options, ",")) != NULL) {
+			if (!*cp)
+				continue;
 			if ((val = strchr(cp, '='))) {
 				struct nfs_int_opts *opts = root_int_opts;
 				*val++ = '\0';
@@ -220,7 +221,6 @@
 					nfs_data.flags |= opts->or_mask;
 				}
 			}
-			cp = strtok(NULL, ",");
 		}
 	}
 	if (name[0] && strcmp(name, "default")) {
diff -Nru a/fs/nls/Config.help b/fs/nls/Config.help
--- a/fs/nls/Config.help	Wed Apr  3 17:11:16 2002
+++ b/fs/nls/Config.help	Wed Apr  3 17:11:16 2002
@@ -224,6 +224,15 @@
   say Y here if you want to include the DOS codepage for Traditional
   Chinese(Big5).
 
+CONFIG_NLS_CODEPAGE_1250
+  If you want to display filenames with native language characters
+  from the Microsoft FAT file system family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Windows CP-1250
+  character set, which works for most Latin-written Slavic and Central
+  European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
+  Slovak, Slovene.
+
 CONFIG_NLS_ISO8859_1
   If you want to display filenames with native language characters
   from the Microsoft FAT file system family or from JOLIET CD-ROMs
diff -Nru a/fs/nls/Config.in b/fs/nls/Config.in
--- a/fs/nls/Config.in	Wed Apr  3 17:11:15 2002
+++ b/fs/nls/Config.in	Wed Apr  3 17:11:15 2002
@@ -43,6 +43,7 @@
   tristate 'Korean charset (CP949, EUC-KR)'        CONFIG_NLS_CODEPAGE_949
   tristate 'Thai charset (CP874, TIS-620)'         CONFIG_NLS_CODEPAGE_874
   tristate 'Hebrew charsets (ISO-8859-8, CP1255)'  CONFIG_NLS_ISO8859_8
+  tristate 'Windows CP1250 (Slavic/Central European Languages)' CONFIG_NLS_CODEPAGE_1250
   tristate 'Windows CP1251 (Bulgarian, Belarusian)' CONFIG_NLS_CODEPAGE_1251
   tristate 'NLS ISO 8859-1  (Latin 1; Western European Languages)' CONFIG_NLS_ISO8859_1
   tristate 'NLS ISO 8859-2  (Latin 2; Slavic/Central European Languages)' CONFIG_NLS_ISO8859_2
diff -Nru a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nls/nls_cp1250.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,365 @@
+/*
+ * linux/fs/nls_cp1250.c
+ *
+ * Charset cp1250 translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/errno.h>
+
+static wchar_t charset2uni[256] = {
+	/* 0x00*/
+	0x0000, 0x0001, 0x0002, 0x0003, 
+	0x0004, 0x0005, 0x0006, 0x0007, 
+	0x0008, 0x0009, 0x000a, 0x000b, 
+	0x000c, 0x000d, 0x000e, 0x000f, 
+	/* 0x10*/
+	0x0010, 0x0011, 0x0012, 0x0013, 
+	0x0014, 0x0015, 0x0016, 0x0017, 
+	0x0018, 0x0019, 0x001a, 0x001b, 
+	0x001c, 0x001d, 0x001e, 0x001f, 
+	/* 0x20*/
+	0x0020, 0x0021, 0x0022, 0x0023, 
+	0x0024, 0x0025, 0x0026, 0x0027, 
+	0x0028, 0x0029, 0x002a, 0x002b, 
+	0x002c, 0x002d, 0x002e, 0x002f, 
+	/* 0x30*/
+	0x0030, 0x0031, 0x0032, 0x0033, 
+	0x0034, 0x0035, 0x0036, 0x0037, 
+	0x0038, 0x0039, 0x003a, 0x003b, 
+	0x003c, 0x003d, 0x003e, 0x003f, 
+	/* 0x40*/
+	0x0040, 0x0041, 0x0042, 0x0043, 
+	0x0044, 0x0045, 0x0046, 0x0047, 
+	0x0048, 0x0049, 0x004a, 0x004b, 
+	0x004c, 0x004d, 0x004e, 0x004f, 
+	/* 0x50*/
+	0x0050, 0x0051, 0x0052, 0x0053, 
+	0x0054, 0x0055, 0x0056, 0x0057, 
+	0x0058, 0x0059, 0x005a, 0x005b, 
+	0x005c, 0x005d, 0x005e, 0x005f, 
+	/* 0x60*/
+	0x0060, 0x0061, 0x0062, 0x0063, 
+	0x0064, 0x0065, 0x0066, 0x0067, 
+	0x0068, 0x0069, 0x006a, 0x006b, 
+	0x006c, 0x006d, 0x006e, 0x006f, 
+	/* 0x70*/
+	0x0070, 0x0071, 0x0072, 0x0073, 
+	0x0074, 0x0075, 0x0076, 0x0077, 
+	0x0078, 0x0079, 0x007a, 0x007b, 
+	0x007c, 0x007d, 0x007e, 0x007f, 
+	/* 0x80*/
+	0x20ac, 0x0000, 0x201a, 0x0000, 
+	0x201e, 0x2026, 0x2020, 0x2021, 
+	0x0000, 0x2030, 0x0160, 0x2039, 
+	0x015a, 0x0164, 0x017d, 0x0179, 
+	/* 0x90*/
+	0x0000, 0x2018, 0x2019, 0x201c, 
+	0x201d, 0x2022, 0x2013, 0x2014, 
+	0x0000, 0x2122, 0x0161, 0x203a, 
+	0x015b, 0x0165, 0x017e, 0x017a, 
+	/* 0xa0*/
+	0x00a0, 0x02c7, 0x02d8, 0x0141, 
+	0x00a4, 0x0104, 0x00a6, 0x00a7, 
+	0x00a8, 0x00a9, 0x015e, 0x00ab, 
+	0x00ac, 0x00ad, 0x00ae, 0x017b, 
+	/* 0xb0*/
+	0x00b0, 0x00b1, 0x02db, 0x0142, 
+	0x00b4, 0x00b5, 0x00b6, 0x00b7, 
+	0x00b8, 0x0105, 0x015f, 0x00bb, 
+	0x013d, 0x02dd, 0x013e, 0x017c, 
+	/* 0xc0*/
+	0x0154, 0x00c1, 0x00c2, 0x0102, 
+	0x00c4, 0x0139, 0x0106, 0x00c7, 
+	0x010c, 0x00c9, 0x0118, 0x00cb, 
+	0x011a, 0x00cd, 0x00ce, 0x010e, 
+	/* 0xd0*/
+	0x0110, 0x0143, 0x0147, 0x00d3, 
+	0x00d4, 0x0150, 0x00d6, 0x00d7, 
+	0x0158, 0x016e, 0x00da, 0x0170, 
+	0x00dc, 0x00dd, 0x0162, 0x00df, 
+	/* 0xe0*/
+	0x0155, 0x00e1, 0x00e2, 0x0103, 
+	0x00e4, 0x013a, 0x0107, 0x00e7, 
+	0x010d, 0x00e9, 0x0119, 0x00eb, 
+	0x011b, 0x00ed, 0x00ee, 0x010f, 
+	/* 0xf0*/
+	0x0111, 0x0144, 0x0148, 0x00f3, 
+	0x00f4, 0x0151, 0x00f6, 0x00f7, 
+	0x0159, 0x016f, 0x00fa, 0x0171, 
+	0x00fc, 0x00fd, 0x0163, 0x02d9, 
+	};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */
+	0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */
+	0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */
+	0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */
+	};
+
+static unsigned char page01[256] = {
+	0x00, 0x00, 0xc3, 0xe3, 0xa5, 0xb9, 0xc6, 0xe6, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */
+	0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0xc5, 0xe5, 0x00, 0x00, 0xbc, 0xbe, 0x00, /* 0x38-0x3f */
+	0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */
+	0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */
+	0xd8, 0xf8, 0x8c, 0x9c, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */
+	0x8a, 0x9a, 0xde, 0xfe, 0x8d, 0x9d, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */
+	0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x8f, 0x9f, 0xaf, 0xbf, 0x8e, 0x9e, 0x00, /* 0x78-0x7f */
+
+	};
+
+static unsigned char page02[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */
+	};
+
+static unsigned char page20[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */
+	0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	};
+
+static unsigned char page21[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	};
+
+static unsigned char *page_uni2charset[256] = {
+	page00,	page01,	page02,	NULL,	NULL,	NULL,	NULL,	NULL,
+	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
+	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
+	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
+	page20,	page21,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
+	};
+
+static unsigned char charset2lower[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */
+	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x00, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */
+	0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xb3, 0xa4, 0xb9, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbe, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+	};
+
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */
+	0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x00, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x00, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xa3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xa5, 0xaa, 0xbb, 0xbc, 0xbd, 0xbc, 0xaf, /* 0xb8-0xbf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */
+	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */
+	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */
+	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */
+	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */
+	};
+
+static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
+{
+        unsigned char *uni2charset;
+        unsigned char cl = uni & 0x00ff;
+        unsigned char ch = (uni & 0xff00) >> 8;
+
+        if (boundlen <= 0)
+                return -ENAMETOOLONG;
+
+        uni2charset = page_uni2charset[ch];
+        if (uni2charset && uni2charset[cl])
+                out[0] = uni2charset[cl];
+        else
+                return -EINVAL;
+        return 1;
+}
+
+static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
+{
+        *uni = charset2uni[*rawstring];
+        if (*uni == 0x0000)
+                return -EINVAL;
+        return 1;
+}
+
+static struct nls_table table = {
+	charset:	"cp1250",
+	uni2char:	uni2char,
+	char2uni:	char2uni,
+	charset2lower:	charset2lower,
+	charset2upper:	charset2upper,
+	owner:		THIS_MODULE,
+};
+
+static int __init init_nls_cp1250(void)
+{
+        return register_nls(&table);
+}
+static void __exit exit_nls_cp1250(void)
+{
+        unregister_nls(&table);
+}
+
+module_init(init_nls_cp1250)
+module_exit(exit_nls_cp1250)
+
+MODULE_LICENSE("BSD without advertising clause");
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
+
diff -Nru a/fs/noquot.c b/fs/noquot.c
--- a/fs/noquot.c	Wed Apr  3 17:11:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-/* noquot.c: Quota stubs necessary for when quotas are not
- *           compiled into the kernel.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-
-int nr_dquots, nr_free_dquots;
-int max_dquots;
-
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return(-ENOSYS);
-}
diff -Nru a/fs/ntfs/fs.c b/fs/ntfs/fs.c
--- a/fs/ntfs/fs.c	Wed Apr  3 17:11:14 2002
+++ b/fs/ntfs/fs.c	Wed Apr  3 17:11:14 2002
@@ -360,10 +360,13 @@
 	int use_utf8 = -1;	/* If no NLS specified and loading the default
 				   NLS failed use utf8. */
 	int mft_zone_mul = -1;	/* 1 */
+	char *opts = opt;
 
 	if (!opt)
 		goto done;
-	for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) {
+	while ((opt = strsep(&opts, ",")) != NULL) {
+		if (!*opt)
+			continue;
 		if ((value = strchr(opt, '=')) != NULL)
 			*value ++= '\0';
 		if (strcmp(opt, "uid") == 0) {
diff -Nru a/fs/partitions/Config.help b/fs/partitions/Config.help
--- a/fs/partitions/Config.help	Wed Apr  3 17:11:15 2002
+++ b/fs/partitions/Config.help	Wed Apr  3 17:11:15 2002
@@ -115,6 +115,11 @@
   Say Y here if you would like to be able to read the hard disk
   partition table format used by SGI machines.
 
+CONFIG_EFI_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using EFI GPT.  Presently only useful on the
+  IA-64 platform.
+
 CONFIG_ULTRIX_PARTITION
   Say Y here if you would like to be able to read the hard disk
   partition table format used by DEC (now Compaq) Ultrix machines.
diff -Nru a/fs/partitions/Config.in b/fs/partitions/Config.in
--- a/fs/partitions/Config.in	Wed Apr  3 17:11:14 2002
+++ b/fs/partitions/Config.in	Wed Apr  3 17:11:14 2002
@@ -32,6 +32,7 @@
    bool '  SGI partition support' CONFIG_SGI_PARTITION
    bool '  Ultrix partition table support' CONFIG_ULTRIX_PARTITION
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
+   bool '  EFI GUID Partition support' CONFIG_EFI_PARTITION
 else
    if [ "$ARCH" = "alpha" ]; then
       define_bool CONFIG_OSF_PARTITION y
diff -Nru a/fs/partitions/Makefile b/fs/partitions/Makefile
--- a/fs/partitions/Makefile	Wed Apr  3 17:11:15 2002
+++ b/fs/partitions/Makefile	Wed Apr  3 17:11:15 2002
@@ -24,6 +24,7 @@
 obj-$(CONFIG_SUN_PARTITION) += sun.o
 obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
 obj-$(CONFIG_IBM_PARTITION) += ibm.o
+obj-$(CONFIG_EFI_PARTITION) += efi.o
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Wed Apr  3 17:11:15 2002
+++ b/fs/partitions/check.c	Wed Apr  3 17:11:15 2002
@@ -35,6 +35,7 @@
 #include "sun.h"
 #include "ibm.h"
 #include "ultrix.h"
+#include "efi.h"
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
@@ -42,6 +43,9 @@
 			   unsigned long first_sect, int first_minor) = {
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
+#endif
+#ifdef CONFIG_EFI_PARTITION
+	efi_partition,		/* this must come before msdos */
 #endif
 #ifdef CONFIG_LDM_PARTITION
 	ldm_partition,		/* this must come before msdos */
diff -Nru a/fs/partitions/efi.c b/fs/partitions/efi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/partitions/efi.c	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,828 @@
+/************************************************************
+ * EFI GUID Partition Table handling
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ * efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
+ *   Copyright 2000,2001,2002 Dell Computer Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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
+ *
+ *
+ * TODO:
+ *
+ * Changelog:
+ * Mon  Jan 14 2002 Matt Domsch <Matt_Domsch@dell.com>
+ * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied
+ *
+ * Thu Dec 6 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Added compare_gpts().
+ * - moved le_efi_guid_to_cpus() back into this file.  GPT is the only
+ *   thing that keeps EFI GUIDs on disk.
+ * - Changed gpt structure names and members to be simpler and more Linux-like.
+ * 
+ * Wed Oct 17 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck
+ *
+ * Wed Oct 10 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Changed function comments to DocBook style per Andreas Dilger suggestion.
+ *
+ * Mon Oct 08 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Change read_lba() to use the page cache per Al Viro's work.
+ * - print u64s properly on all architectures
+ * - fixed debug_printk(), now Dprintk()
+ *
+ * Mon Oct 01 2001 Matt Domsch <Matt_Domsch@dell.com>
+ * - Style cleanups
+ * - made most functions static
+ * - Endianness addition
+ * - remove test for second alternate header, as it's not per spec,
+ *   and is unnecessary.  There's now a method to read/write the last
+ *   sector of an odd-sized disk from user space.  No tools have ever
+ *   been released which used this code, so it's effectively dead.
+ * - Per Asit Mallick of Intel, added a test for a valid PMBR.
+ * - Added kernel command line option 'gpt' to override valid PMBR test.
+ *
+ * Wed Jun  6 2001 Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com>
+ * - added devfs volume UUID support (/dev/volumes/uuids) for
+ *   mounting file systems by the partition GUID. 
+ *
+ * Tue Dec  5 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Moved crc32() to linux/lib, added efi_crc32().
+ *
+ * Thu Nov 30 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Replaced Intel's CRC32 function with an equivalent
+ *   non-license-restricted version.
+ *
+ * Wed Oct 25 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Fixed the last_lba() call to return the proper last block
+ *
+ * Thu Oct 12 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Thanks to Andries Brouwer for his debugging assistance.
+ * - Code works, detects all the partitions.
+ *
+ ************************************************************/
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include "check.h"
+#include "efi.h"
+
+#if CONFIG_BLK_DEV_MD
+extern void md_autodetect_dev(kdev_t dev);
+#endif
+
+/* Handle printing of 64-bit values */
+/* Borrowed from /usr/include/inttypes.h */
+# if BITS_PER_LONG == 64 
+#  define __PRI64_PREFIX	"l"
+#  define __PRIPTR_PREFIX	"l"
+# else
+#  define __PRI64_PREFIX	"ll"
+#  define __PRIPTR_PREFIX
+# endif
+# define PRIx64		__PRI64_PREFIX "x"
+
+
+#undef EFI_DEBUG
+#ifdef EFI_DEBUG
+#define Dprintk(x...) printk(KERN_DEBUG x)
+#else
+#define Dprintk(x...)
+#endif
+
+/* This allows a kernel command line option 'gpt' to override
+ * the test for invalid PMBR.  Not __initdata because reloading
+ * the partition tables happens after init too.
+ */
+static int forcegpt;
+static int __init
+force_gpt(char *str)
+{
+	forcegpt = 1;
+	return 1;
+}
+
+__setup("gpt", force_gpt);
+
+/**
+ * le_efi_guid_to_cpus()
+ * @guid
+ *
+ * Description: modifies @guid in situ
+ *
+ * This function converts a little endian efi_guid_t to the
+ * native cpu representation.  The EFI Spec. declares that all 
+ * on-disk structures are stored in little endian format.
+ */
+static void
+le_efi_guid_to_cpus(efi_guid_t *guid)
+{
+	le32_to_cpus(guid->data1);
+	le16_to_cpus(guid->data2);
+	le16_to_cpus(guid->data3);
+	/* no need to change the rest. It's already an array of chars */
+	return;
+}
+
+/**
+ * efi_crc32() - EFI version of crc32 function
+ * @buf: buffer to calculate crc32 of
+ * @len - length of buf
+ *
+ * Description: Returns EFI-style CRC32 value for @buf
+ * 
+ * This function uses the little endian Ethernet polynomial
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ * Note, the EFI Specification, v1.02, has a reference to
+ * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
+ */
+static inline u32
+efi_crc32(const void *buf, unsigned long len)
+{
+	return (crc32(~0L, buf, len) ^ ~0L);
+}
+
+/**
+ * le_part_attributes_to_cpus(): converts LE attributes to CPU type in situ
+ * @attributes - ptr to partition attributes
+ * 
+ * Description:  modifies attributes in situ, returns nothing.
+ * Converts a little endian partition attributes struct to the
+ * native cpu representation.  Good for reading attributes off of a disk.
+ */
+static void
+le_part_attributes_to_cpus(gpt_entry_attributes * a)
+{
+	u64 *b = (u64 *) a;
+	*b = le64_to_cpu(*b);
+}
+
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ *
+ * Description: Returns 1 if PMBR is valid, 0 otherwise.
+ * Validity depends on two things:
+ *  1) MSDOS signature is in the last two bytes of the MBR
+ *  2) One partition of type 0xEE is found
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr)
+{
+	int i, found = 0, signature = 0;
+	if (!mbr)
+		return 0;
+	signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+	for (i = 0; signature && i < 4; i++) {
+		if (mbr->partition_record[i].sys_ind == EFI_PMBR_OSTYPE_EFI_GPT) {
+			found = 1;
+			break;
+		}
+	}
+	return (signature && found);
+}
+
+/**
+ * last_lba(): return number of last logical block of device
+ * @hd: gendisk with partition list
+ * @bdev: block device
+ * 
+ * Description: Returns last LBA value on success, 0 on error.
+ * This is stored (by sd and ide-geometry) in
+ *  the part[0] entry for this disk, and is the number of
+ *  physical sectors available on the disk.
+ */
+static u64
+last_lba(struct gendisk *hd, struct block_device *bdev)
+{
+	if (!hd || !hd->part || !bdev)
+		return 0;
+	return hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects - 1;
+}
+
+/**
+ * read_lba(): Read bytes from disk, starting at given LBA
+ * @hd
+ * @bdev
+ * @lba
+ * @buffer
+ * @size_t
+ *
+ * Description:  Reads @count bytes from @bdev into @buffer.
+ * Returns number of bytes read on success, 0 on error.
+ */
+static size_t
+read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba,
+	 u8 * buffer, size_t count)
+{
+
+	size_t totalreadcount = 0, bytesread = 0;
+	unsigned long blocksize;
+	int i;
+	Sector sect;
+	unsigned char *data = NULL;
+
+	if (!hd || !bdev || !buffer || !count)
+		return 0;
+
+	blocksize = get_hardsect_size(to_kdev_t(bdev->bd_dev));
+	if (!blocksize)
+		blocksize = 512;
+
+	for (i = 0; count > 0; i++) {
+		data = read_dev_sector(bdev, lba, &sect);
+		if (!data)
+			return totalreadcount;
+
+		bytesread =
+		    PAGE_CACHE_SIZE - (data -
+				       (unsigned char *) page_address(sect.v));
+		bytesread = min(bytesread, count);
+		memcpy(buffer, data, bytesread);
+		put_dev_sector(sect);
+
+		buffer += bytesread;
+		totalreadcount += bytesread;
+		count -= bytesread;
+		lba += (bytesread / blocksize);
+	}
+	return totalreadcount;
+}
+
+/**
+ * print_gpt_header(): unparses gpt header to console
+ * @gpt: gpt header
+ */
+static void
+print_gpt_header(gpt_header *gpt)
+{
+	Dprintk("GUID Partition Table Header\n");
+	if (!gpt)
+		return;
+	Dprintk("signature                   : %" PRIx64 "\n", gpt->signature);
+	Dprintk("revision                    : %x\n", gpt->revision);
+	Dprintk("header_size                 : %x\n", gpt->header_size);
+	Dprintk("header_crc32                : %x\n", gpt->header_crc32);
+	Dprintk("my_lba                      : %" PRIx64 "\n", gpt->my_lba);
+	Dprintk("alternate_lba               : %" PRIx64 "\n",
+		gpt->alternate_lba);
+	Dprintk("first_usable_lba            : %" PRIx64 "\n",
+		gpt->first_usable_lba);
+	Dprintk("last_usable_lba             : %" PRIx64 "\n",
+		gpt->last_usable_lba);
+	Dprintk("partition_entry_lba         : %" PRIx64 "\n",
+		gpt->partition_entry_lba);
+	Dprintk("num_partition_entries       : %x\n",
+		gpt->num_partition_entries);
+	Dprintk("sizeof_partition_entry      : %x\n",
+		gpt->sizeof_partition_entry);
+	Dprintk("partition_entry_array_crc32 : %x\n",
+		gpt->partition_entry_array_crc32);
+	return;
+}
+
+/**
+ * alloc_read_gpt_entries(): reads partition entries from disk
+ * @hd
+ * @bdev
+ * @gpt - GPT header
+ * 
+ * Description: Returns ptes on success,  NULL on error.
+ * Allocates space for PTEs based on information found in @gpt.
+ * Notes: remember to free pte when you're done!
+ */
+static gpt_entry *
+alloc_read_gpt_entries(struct gendisk *hd,
+		       struct block_device *bdev, gpt_header *gpt)
+{
+	u32 i, j;
+	size_t count;
+	gpt_entry *pte;
+	if (!hd || !bdev || !gpt)
+		return NULL;
+
+	count = gpt->num_partition_entries * gpt->sizeof_partition_entry;
+	if (!count)
+		return NULL;
+	pte = kmalloc(count, GFP_KERNEL);
+	if (!pte)
+		return NULL;
+	memset(pte, 0, count);
+
+	if (read_lba(hd, bdev, gpt->partition_entry_lba, (u8 *) pte,
+		     count) < count) {
+		kfree(pte);
+		return NULL;
+	}
+	/* Fixup endianness */
+	for (i = 0; i < gpt->num_partition_entries; i++) {
+		le_efi_guid_to_cpus(&pte[i].partition_type_guid);
+		le_efi_guid_to_cpus(&pte[i].unique_partition_guid);
+		le64_to_cpus(pte[i].starting_lba);
+		le64_to_cpus(pte[i].ending_lba);
+		le_part_attributes_to_cpus(&pte[i].attributes);
+		for (j = 0; j < (72 / sizeof (efi_char16_t)); j++) {
+			le16_to_cpus((u16) (pte[i].partition_name[j]));
+		}
+	}
+
+	return pte;
+}
+
+/**
+ * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
+ * @hd
+ * @bdev
+ * @lba is the Logical Block Address of the partition table
+ * 
+ * Description: returns GPT header on success, NULL on error.   Allocates
+ * and fills a GPT header starting at @ from @bdev.
+ * Note: remember to free gpt when finished with it.
+ */
+static gpt_header *
+alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba)
+{
+	gpt_header *gpt;
+	if (!hd || !bdev)
+		return NULL;
+
+	gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
+	if (!gpt)
+		return NULL;
+	memset(gpt, 0, sizeof (gpt_header));
+
+	if (read_lba(hd, bdev, lba, (u8 *) gpt,
+		     sizeof (gpt_header)) < sizeof (gpt_header)) {
+		kfree(gpt);
+		return NULL;
+	}
+
+	/* Fixup endianness */
+	le64_to_cpus(gpt->signature);
+	le32_to_cpus(gpt->revision);
+	le32_to_cpus(gpt->header_size);
+	le32_to_cpus(gpt->header_crc32);
+	le32_to_cpus(gpt->reserved1);
+	le64_to_cpus(gpt->my_lba);
+	le64_to_cpus(gpt->alternate_lba);
+	le64_to_cpus(gpt->first_usable_lba);
+	le64_to_cpus(gpt->last_usable_lba);
+	le_efi_guid_to_cpus(&gpt->disk_guid);
+	le64_to_cpus(gpt->partition_entry_lba);
+	le32_to_cpus(gpt->num_partition_entries);
+	le32_to_cpus(gpt->sizeof_partition_entry);
+	le32_to_cpus(gpt->partition_entry_array_crc32);
+
+	print_gpt_header(gpt);
+
+	return gpt;
+}
+
+/**
+ * is_gpt_valid() - tests one GPT header and PTEs for validity
+ * @hd
+ * @bdev
+ * @lba is the logical block address of the GPT header to test
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ *
+ * Description: returns 1 if valid,  0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ */
+static int
+is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba,
+	     gpt_header **gpt, gpt_entry **ptes)
+{
+	u32 crc, origcrc;
+
+	if (!hd || !bdev || !gpt || !ptes)
+		return 0;
+	if (!(*gpt = alloc_read_gpt_header(hd, bdev, lba)))
+		return 0;
+
+	/* Check the GUID Partition Table signature */
+	if ((*gpt)->signature != GPT_HEADER_SIGNATURE) {
+		Dprintk("GUID Partition Table Header signature is wrong: %"
+			PRIx64 " != %" PRIx64 "\n", (*gpt)->signature,
+			GPT_HEADER_SIGNATURE);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Table CRC */
+	origcrc = (*gpt)->header_crc32;
+	(*gpt)->header_crc32 = 0;
+	crc = efi_crc32((const unsigned char *) (*gpt), (*gpt)->header_size);
+
+	if (crc != origcrc) {
+		Dprintk
+		    ("GUID Partition Table Header CRC is wrong: %x != %x\n",
+		     (*gpt)->header_crc32, origcrc);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+	(*gpt)->header_crc32 = origcrc;
+
+	/* Check that the my_lba entry points to the LBA that contains
+	 * the GUID Partition Table */
+	if ((*gpt)->my_lba != lba) {
+		Dprintk("GPT my_lba incorrect: %" PRIx64 " != %" PRIx64 "\n",
+			(*gpt)->my_lba, lba);
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	if (!(*ptes = alloc_read_gpt_entries(hd, bdev, *gpt))) {
+		kfree(*gpt);
+		*gpt = NULL;
+		return 0;
+	}
+
+	/* Check the GUID Partition Entry Array CRC */
+	crc = efi_crc32((const unsigned char *) (*ptes),
+			(*gpt)->num_partition_entries *
+			(*gpt)->sizeof_partition_entry);
+
+	if (crc != (*gpt)->partition_entry_array_crc32) {
+		Dprintk("GUID Partitition Entry Array CRC check failed.\n");
+		kfree(*gpt);
+		*gpt = NULL;
+		kfree(*ptes);
+		*ptes = NULL;
+		return 0;
+	}
+
+	/* We're done, all's well */
+	return 1;
+}
+
+/**
+ * compare_gpts() - Search disk for valid GPT headers and PTEs
+ * @pgpt is the primary GPT header
+ * @agpt is the alternate GPT header
+ * @lastlba is the last LBA number
+ * Description: Returns nothing.  Sanity checks pgpt and agpt fields
+ * and prints warnings on discrepancies.
+ * 
+ */
+static void
+compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
+{
+	int error_found = 0;
+	if (!pgpt || !agpt)
+		return;
+	if (pgpt->my_lba != agpt->alternate_lba) {
+		printk(KERN_WARNING
+		       "GPT:Primary header LBA != Alt. header alternate_lba\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       pgpt->my_lba, agpt->alternate_lba);
+		error_found++;
+	}
+	if (pgpt->alternate_lba != agpt->my_lba) {
+		printk(KERN_WARNING
+		       "GPT:Primary header alternate_lba != Alt. header my_lba\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       pgpt->alternate_lba, agpt->my_lba);
+		error_found++;
+	}
+	if (pgpt->first_usable_lba != agpt->first_usable_lba) {
+		printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       pgpt->first_usable_lba, agpt->first_usable_lba);
+		error_found++;
+	}
+	if (pgpt->last_usable_lba != agpt->last_usable_lba) {
+		printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       pgpt->last_usable_lba, agpt->last_usable_lba);
+		error_found++;
+	}
+	if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
+		printk(KERN_WARNING "GPT:disk_guids don't match.\n");
+		error_found++;
+	}
+	if (pgpt->num_partition_entries != agpt->num_partition_entries) {
+		printk(KERN_WARNING "GPT:num_partition_entries don't match: "
+		       "0x%x != 0x%x\n",
+		       pgpt->num_partition_entries,
+		       agpt->num_partition_entries);
+		error_found++;
+	}
+	if (pgpt->sizeof_partition_entry != agpt->sizeof_partition_entry) {
+		printk(KERN_WARNING
+		       "GPT:sizeof_partition_entry values don't match: "
+		       "0x%x != 0x%x\n", pgpt->sizeof_partition_entry,
+		       agpt->sizeof_partition_entry);
+		error_found++;
+	}
+	if (pgpt->partition_entry_array_crc32 !=
+	    agpt->partition_entry_array_crc32) {
+		printk(KERN_WARNING
+		       "GPT:partition_entry_array_crc32 values don't match: "
+		       "0x%x != 0x%x\n", pgpt->partition_entry_array_crc32,
+		       agpt->partition_entry_array_crc32);
+		error_found++;
+	}
+	if (pgpt->alternate_lba != lastlba) {
+		printk(KERN_WARNING
+		       "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       pgpt->alternate_lba, lastlba);
+		error_found++;
+	}
+
+	if (agpt->my_lba != lastlba) {
+		printk(KERN_WARNING
+		       "GPT:Alternate GPT header not at the end of the disk.\n");
+		printk(KERN_WARNING "GPT:%" PRIx64 " != %" PRIx64 "\n",
+		       agpt->my_lba, lastlba);
+		error_found++;
+	}
+
+	if (error_found)
+		printk(KERN_WARNING
+		       "GPT: Use GNU Parted to correct GPT errors.\n");
+	return;
+}
+
+/**
+ * find_valid_gpt() - Search disk for valid GPT headers and PTEs
+ * @hd
+ * @bdev
+ * @gpt is a GPT header ptr, filled on return.
+ * @ptes is a PTEs ptr, filled on return.
+ * Description: Returns 1 if valid, 0 on error.
+ * If valid, returns pointers to newly allocated GPT header and PTEs.
+ * Validity depends on finding either the Primary GPT header and PTEs valid,
+ * or the Alternate GPT header and PTEs valid, and the PMBR valid.
+ */
+static int
+find_valid_gpt(struct gendisk *hd, struct block_device *bdev,
+	       gpt_header **gpt, gpt_entry **ptes)
+{
+	int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
+	gpt_header *pgpt = NULL, *agpt = NULL;
+	gpt_entry *pptes = NULL, *aptes = NULL;
+	legacy_mbr *legacymbr = NULL;
+	u64 lastlba;
+	if (!hd || !bdev || !gpt || !ptes)
+		return 0;
+
+	lastlba = last_lba(hd, bdev);
+	/* Check the Primary GPT */
+	good_pgpt = is_gpt_valid(hd, bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
+				 &pgpt, &pptes);
+	if (good_pgpt) {
+		/* Primary GPT is OK, check the alternate and warn if bad */
+		good_agpt = is_gpt_valid(hd, bdev, pgpt->alternate_lba,
+					 &agpt, &aptes);
+		if (!good_agpt) {
+			printk(KERN_WARNING
+			       "Alternate GPT is invalid, using primary GPT.\n");
+		}
+
+		compare_gpts(pgpt, agpt, lastlba);
+
+		*gpt = pgpt;
+		*ptes = pptes;
+		if (agpt) {
+			kfree(agpt);
+			agpt = NULL;
+		}
+		if (aptes) {
+			kfree(aptes);
+			aptes = NULL;
+		}
+	} /* if primary is valid */
+	else {
+		/* Primary GPT is bad, check the Alternate GPT */
+		good_agpt = is_gpt_valid(hd, bdev, lastlba, &agpt, &aptes);
+		if (good_agpt) {
+			/* Primary is bad, alternate is good.
+			   Return values from the alternate and warn.
+			 */
+			printk(KERN_WARNING
+			       "Primary GPT is invalid, using alternate GPT.\n");
+			*gpt = agpt;
+			*ptes = aptes;
+		}
+	}
+
+	/* Now test for valid PMBR */
+	/* This will be added to the EFI Spec. per Intel after v1.02. */
+	if (good_pgpt || good_agpt) {
+		legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+		if (legacymbr) {
+			memset(legacymbr, 0, sizeof (*legacymbr));
+			read_lba(hd, bdev, 0, (u8 *) legacymbr,
+				 sizeof (*legacymbr));
+			good_pmbr = is_pmbr_valid(legacymbr);
+			kfree(legacymbr);
+		}
+		if (good_pmbr)
+			return 1;
+		if (!forcegpt) {
+			printk
+			    (" Warning: Disk has a valid GPT signature but invalid PMBR.\n");
+			printk(KERN_WARNING
+			       "  Assuming this disk is *not* a GPT disk anymore.\n");
+			printk(KERN_WARNING
+			       "  Use gpt kernel option to override.  Use GNU Parted to correct disk.\n");
+		} else {
+			printk(KERN_WARNING
+			       "  Warning: Disk has a valid GPT signature but invalid PMBR.\n");
+			printk(KERN_WARNING
+			       "  Use GNU Parted to correct disk.\n");
+			printk(KERN_WARNING
+			       "  gpt option taken, disk treated as GPT.\n");
+			return 1;
+		}
+	}
+
+	/* Both primary and alternate GPTs are bad, and/or PMBR is invalid.
+	 * This isn't our disk, return 0.
+	 */
+	if (pgpt) {
+		kfree(pgpt);
+		pgpt = NULL;
+	}
+	if (agpt) {
+		kfree(agpt);
+		agpt = NULL;
+	}
+	if (pptes) {
+		kfree(pptes);
+		pptes = NULL;
+	}
+	if (aptes) {
+		kfree(aptes);
+		aptes = NULL;
+	}
+	*gpt = NULL;
+	*ptes = NULL;
+	return 0;
+}
+
+/**
+ * add_gpt_partitions(struct gendisk *hd, struct block_device *bdev,
+ * @hd
+ * @bdev
+ *
+ * Description: Create devices for each entry in the GUID Partition Table
+ * Entries.
+ *
+ * We do not create a Linux partition for GPT, but
+ * only for the actual data partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ *
+ */
+static int
+add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, int nextminor)
+{
+	gpt_header *gpt = NULL;
+	gpt_entry *ptes = NULL;
+	u32 i, nummade = 0;
+	int max_p; 
+
+	efi_guid_t unusedGuid = UNUSED_ENTRY_GUID;
+#if CONFIG_BLK_DEV_MD
+	efi_guid_t raidGuid = PARTITION_LINUX_RAID_GUID;
+#endif
+
+	if (!hd || !bdev)
+		return -1;
+
+	if (!find_valid_gpt(hd, bdev, &gpt, &ptes) || !gpt || !ptes) {
+		if (gpt)
+			kfree(gpt);
+		if (ptes)
+			kfree(ptes);
+		return 0;
+	}
+
+	Dprintk("GUID Partition Table is valid!  Yea!\n");
+
+	max_p = (1 << hd->minor_shift) - 1;
+	for (i = 0; i < gpt->num_partition_entries && nummade < max_p; i++) {
+		if (!efi_guidcmp(unusedGuid, ptes[i].partition_type_guid))
+			continue;
+
+		add_gd_partition(hd, nextminor, ptes[i].starting_lba,
+				 (ptes[i].ending_lba - ptes[i].starting_lba +
+				  1));
+
+		/* If there's this is a RAID volume, tell md */
+#if CONFIG_BLK_DEV_MD
+		if (!efi_guidcmp(raidGuid, ptes[i].partition_type_guid)) {
+			md_autodetect_dev(mk_kdev(hd->major,
+                                                  nextminor));
+		}
+#endif
+		nummade++;
+		nextminor++;
+
+	}
+	kfree(ptes);
+	kfree(gpt);
+	printk("\n");
+	return 1;
+}
+
+/**
+ * efi_partition(): EFI GPT partition handling entry function
+ * @hd
+ * @bdev
+ * @first_sector: unused
+ * @first_part_minor: minor number assigned to first GPT partition found
+ *
+ * Description: called from check.c, if the disk contains GPT
+ * partitions, sets up partition entries in the kernel.
+ *
+ * If the first block on the disk is a legacy MBR,
+ * it will get handled by msdos_partition().
+ * If it's a Protective MBR, we'll handle it here.
+ *
+ * set_blocksize() calls are necessary to be able to read
+ * a disk with an odd number of 512-byte sectors, as the
+ * default BLOCK_SIZE of 1024 bytes won't let that last
+ * sector be read otherwise.
+ *
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partitoin table
+ *  1 if successful
+ */
+int
+efi_partition(struct gendisk *hd, struct block_device *bdev,
+	      unsigned long first_sector, int first_part_minor)
+{
+
+	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	int hardblocksize = get_hardsect_size(dev);
+	int orig_blksize_size = BLOCK_SIZE;
+	int rc = 0;
+
+	/* Need to change the block size that the block layer uses */
+	if (blksize_size[major(dev)]) {
+		orig_blksize_size = blksize_size[major(dev)][minor(dev)];
+	}
+
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, hardblocksize);
+
+	rc = add_gpt_partitions(hd, bdev, first_part_minor);
+
+	/* change back */
+	if (orig_blksize_size != hardblocksize)
+		set_blocksize(dev, orig_blksize_size);
+
+	return rc;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -Nru a/fs/partitions/efi.h b/fs/partitions/efi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/partitions/efi.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,133 @@
+/************************************************************
+ * EFI GUID Partition Table
+ * Per Intel EFI Specification v1.02
+ * http://developer.intel.com/technology/efi/efi.htm
+ *
+ * By Matt Domsch <Matt_Domsch@dell.com>  Fri Sep 22 22:15:56 CDT 2000  
+ *   Copyright 2000,2001 Dell Computer Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ * 
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  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
+ * 
+ ************************************************************/
+
+#ifndef FS_PART_EFI_H_INCLUDED
+#define FS_PART_EFI_H_INCLUDED
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+/*
+ * Yes, specifying asm-ia64 is ugly, but this lets it build on
+ * other platforms too, until efi.h moves to include/linux.
+ */
+#include <asm-ia64/efi.h>
+
+#define MSDOS_MBR_SIGNATURE 0xaa55
+#define EFI_PMBR_OSTYPE_EFI 0xEF
+#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
+
+#define GPT_BLOCK_SIZE 512
+#define GPT_HEADER_SIGNATURE 0x5452415020494645L
+#define GPT_HEADER_REVISION_V1 0x00010000
+#define GPT_PRIMARY_PARTITION_TABLE_LBA 1
+
+#define UNUSED_ENTRY_GUID    \
+    ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+((efi_guid_t) { 0xC12A7328, 0xF81F, 0x11d2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define LEGACY_MBR_PARTITION_GUID \
+    ((efi_guid_t) { 0x024DEE41, 0x33E7, 0x11d3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+    ((efi_guid_t) { 0xE3C9E316, 0x0B5C, 0x4DB8, { 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_BASIC_DATA_GUID \
+    ((efi_guid_t) { 0xEBD0A0A2, 0xB9E5, 0x4433, { 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_LINUX_RAID_GUID \
+    ((efi_guid_t) { 0xa19d880f, 0x05fc, 0x4d3b, { 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e  }})
+#define PARTITION_LINUX_SWAP_GUID \
+    ((efi_guid_t) { 0x0657fd6d, 0xa4ab, 0x43c4, { 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f  }})
+#define PARTITION_LINUX_LVM_GUID \
+    ((efi_guid_t) { 0xe6d6d379, 0xf507, 0x44c2, { 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+
+typedef struct _gpt_header {
+	u64 signature;
+	u32 revision;
+	u32 header_size;
+	u32 header_crc32;
+	u32 reserved1;
+	u64 my_lba;
+	u64 alternate_lba;
+	u64 first_usable_lba;
+	u64 last_usable_lba;
+	efi_guid_t disk_guid;
+	u64 partition_entry_lba;
+	u32 num_partition_entries;
+	u32 sizeof_partition_entry;
+	u32 partition_entry_array_crc32;
+	u8 reserved2[GPT_BLOCK_SIZE - 92];
+} __attribute__ ((packed)) gpt_header;
+
+typedef struct _gpt_entry_attributes {
+	u64 required_to_function:1;
+	u64 reserved:47;
+        u64 type_guid_specific:16;
+} __attribute__ ((packed)) gpt_entry_attributes;
+
+typedef struct _gpt_entry {
+	efi_guid_t partition_type_guid;
+	efi_guid_t unique_partition_guid;
+	u64 starting_lba;
+	u64 ending_lba;
+	gpt_entry_attributes attributes;
+	efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
+} __attribute__ ((packed)) gpt_entry;
+
+typedef struct _legacy_mbr {
+	u8 boot_code[440];
+	u32 unique_mbr_signature;
+	u16 unknown;
+	struct partition partition_record[4];
+	u16 signature;
+} __attribute__ ((packed)) legacy_mbr;
+
+/* Functions */
+extern int
+ efi_partition(struct gendisk *hd, struct block_device *bdev,
+	      unsigned long first_sector, int first_part_minor);
+
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * --------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -Nru a/fs/partitions/msdos.c b/fs/partitions/msdos.c
--- a/fs/partitions/msdos.c	Wed Apr  3 17:11:14 2002
+++ b/fs/partitions/msdos.c	Wed Apr  3 17:11:14 2002
@@ -41,6 +41,7 @@
 
 #include "check.h"
 #include "msdos.h"
+#include "efi.h"
 
 #if CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(kdev_t dev);
@@ -536,6 +537,16 @@
 		return 0;
 	}
 	p = (struct partition *) (data + 0x1be);
+#ifdef CONFIG_EFI_PARTITION
+	for (i=1 ; i<=4 ; i++,p++) {
+		/* If this is an EFI GPT disk, msdos should ignore it. */
+		if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
+			put_dev_sector(sect);
+			return 0;
+		}
+	}
+	p = (struct partition *) (data + 0x1be);
+#endif
 
 	/*
 	 * Look for partitions in two passes:
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Wed Apr  3 17:11:14 2002
+++ b/fs/proc/array.c	Wed Apr  3 17:11:14 2002
@@ -227,6 +227,7 @@
 	sigemptyset(ign);
 	sigemptyset(catch);
 
+	spin_lock_irq(&p->sigmask_lock);
 	if (p->sig) {
 		k = p->sig->action;
 		for (i = 1; i <= _NSIG; ++i, ++k) {
@@ -236,6 +237,7 @@
 				sigaddset(catch, i);
 		}
 	}
+	spin_unlock_irq(&p->sigmask_lock);
 }
 
 static inline char * task_sig(struct task_struct *p, char *buffer)
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Wed Apr  3 17:11:15 2002
+++ b/fs/proc/inode.c	Wed Apr  3 17:11:15 2002
@@ -133,8 +133,11 @@
 
 	*uid = current->uid;
 	*gid = current->gid;
-	if (!options) return 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	if (!options)
+		return 1;
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
 		if (!strcmp(this_char,"uid")) {
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Wed Apr  3 17:11:14 2002
+++ b/fs/proc/proc_misc.c	Wed Apr  3 17:11:14 2002
@@ -51,7 +51,6 @@
  * wrappers, but this needs further analysis wrt potential overflows.
  */
 extern int get_device_list(char *);
-extern int get_partition_list(char *, char **, off_t, int);
 extern int get_filesystem_list(char *);
 extern int get_exec_domain_list(char *);
 extern int get_dma_list(char *);
@@ -199,6 +198,18 @@
 	release:	seq_release,
 };
 
+extern struct seq_operations partitions_op;
+static int partitions_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &partitions_op);
+}
+static struct file_operations proc_partitions_operations = {
+	open:		partitions_open,
+	read:		seq_read,
+	llseek:		seq_lseek,
+	release:	seq_release,
+};
+
 #ifdef CONFIG_MODULES
 extern struct seq_operations modules_op;
 static int modules_open(struct inode *inode, struct file *file)
@@ -323,14 +334,6 @@
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
-static int partitions_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
-{
-	int len = get_partition_list(page, start, off, count);
-	if (len < count) *eof = 1;
-	return len;
-}
-
 static void *single_start(struct seq_file *p, loff_t *pos)
 {
 	return NULL + (*pos == 0);
@@ -538,7 +541,6 @@
 		{"version",	version_read_proc},
 		{"stat",	kstat_read_proc},
 		{"devices",	devices_read_proc},
-		{"partitions",	partitions_read_proc},
 		{"filesystems",	filesystems_read_proc},
 		{"dma",		dma_read_proc},
 		{"ioports",	ioports_read_proc},
@@ -562,6 +564,7 @@
 	if (entry)
 		entry->proc_fops = &proc_kmsg_operations;
 	create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+	create_seq_entry("partitions", 0, &proc_partitions_operations);
 	create_seq_entry("interrupts", 0, &proc_interrupts_operations);
 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
 #ifdef CONFIG_MODULES
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c	Wed Apr  3 17:11:14 2002
+++ b/fs/reiserfs/journal.c	Wed Apr  3 17:11:14 2002
@@ -1958,8 +1958,7 @@
       		SB_ONDISK_JOURNAL_DEVICE( super ) ?
 		to_kdev_t(SB_ONDISK_JOURNAL_DEVICE( super )) : super -> s_dev;	
 	/* there is no "jdev" option and journal is on separate device */
-	if( ( !jdev_name || !jdev_name[ 0 ] ) && 
-	    SB_ONDISK_JOURNAL_DEVICE( super ) ) {
+	if( ( !jdev_name || !jdev_name[ 0 ] ) ) {
 		journal -> j_dev_bd = bdget( kdev_t_to_nr( jdev ) );
 		if( journal -> j_dev_bd )
 			result = blkdev_get( journal -> j_dev_bd, 
@@ -1974,9 +1973,6 @@
 		return result;
 	}
 
-	/* no "jdev" option and journal is on the host device */
-	if( !jdev_name || !jdev_name[ 0 ] )
-		return 0;
 	journal -> j_dev_file = filp_open( jdev_name, 0, 0 );
 	if( !IS_ERR( journal -> j_dev_file ) ) {
 		struct inode *jdev_inode;
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/reiserfs/super.c	Wed Apr  3 17:11:15 2002
@@ -508,7 +508,9 @@
 	/* use default configuration: create tails, journaling on, no
            conversion to newest format */
 	return 1;
-    for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) {
+    while ((this_char = strsep (&options, ",")) != NULL) {
+	if (!*this_char)
+	    continue;
 	if ((value = strchr (this_char, '=')) != NULL)
 	    *value++ = 0;
 	if (!strcmp (this_char, "notail")) {
@@ -991,7 +993,6 @@
 //
 static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
 {
-    int size;
     struct inode *root_inode;
     int j;
     struct reiserfs_transaction_handle th ;
@@ -1013,9 +1014,6 @@
 	return -EINVAL;
     }	
 
-    size = block_size(s->s_dev);
-    sb_set_blocksize(s, size);
-    
     /* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
     if (!read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES)) 
       old_format = 1;
diff -Nru a/fs/romfs/inode.c b/fs/romfs/inode.c
--- a/fs/romfs/inode.c	Wed Apr  3 17:11:15 2002
+++ b/fs/romfs/inode.c	Wed Apr  3 17:11:15 2002
@@ -536,7 +536,51 @@
 	}
 }
 
+static kmem_cache_t * romfs_inode_cachep;
+
+static struct inode *romfs_alloc_inode(struct super_block *sb)
+{
+	struct romfs_inode_info *ei;
+	ei = (struct romfs_inode_info *)kmem_cache_alloc(romfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void romfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct romfs_inode_info *ei = (struct romfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
+					     sizeof(struct romfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (romfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(romfs_inode_cachep))
+		printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations romfs_ops = {
+	alloc_inode:	romfs_alloc_inode,
+	destroy_inode:	romfs_destroy_inode,
 	read_inode:	romfs_read_inode,
 	statfs:		romfs_statfs,
 };
@@ -557,12 +601,23 @@
 
 static int __init init_romfs_fs(void)
 {
-	return register_filesystem(&romfs_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+        err = register_filesystem(&romfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_romfs_fs(void)
 {
 	unregister_filesystem(&romfs_fs_type);
+	destroy_inodecache();
 }
 
 /* Yes, works even as a module... :) */
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/super.c	Wed Apr  3 17:11:15 2002
@@ -26,6 +26,7 @@
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/acct.h>
+#include <linux/blkdev.h>
 #include <asm/uaccess.h>
 
 void get_filesystem(struct file_system_type *fs);
@@ -513,6 +514,8 @@
 	} else {
 		s->s_flags = flags;
 		strncpy(s->s_id, bdevname(dev), sizeof(s->s_id));
+		s->s_old_blocksize = block_size(dev);
+		sb_set_blocksize(s, s->s_old_blocksize);
 		error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
 		if (error) {
 			up_write(&s->s_umount);
@@ -535,6 +538,7 @@
 {
 	struct block_device *bdev = sb->s_bdev;
 	generic_shutdown_super(sb);
+	set_blocksize(to_kdev_t(bdev->bd_dev), sb->s_old_blocksize);
 	bd_release(bdev);
 	blkdev_put(bdev, BDEV_FS);
 }
diff -Nru a/fs/udf/super.c b/fs/udf/super.c
--- a/fs/udf/super.c	Wed Apr  3 17:11:15 2002
+++ b/fs/udf/super.c	Wed Apr  3 17:11:15 2002
@@ -286,8 +286,9 @@
 	if (!options)
 		return 1;
 
-	for (opt = strtok(options, ","); opt; opt = strtok(NULL, ","))
-	{
+	while ((opt = strsep(&options, ",")) != NULL) {
+		if (!*opt)
+			continue;
 		/* Make "opt=val" into two strings */
 		val = strchr(opt, '=');
 		if (val)
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Wed Apr  3 17:11:13 2002
+++ b/fs/ufs/super.c	Wed Apr  3 17:11:13 2002
@@ -257,11 +257,10 @@
 	
 	if (!options)
 		return 1;
-		
-	for (this_char = strtok (options, ",");
-	     this_char != NULL;
-	     this_char = strtok (NULL, ",")) {
-	     
+
+	while ((this_char = strsep (&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr (this_char, '=')) != NULL)
 			*value++ = 0;
 		if (!strcmp (this_char, "ufstype")) {
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Wed Apr  3 17:11:14 2002
+++ b/fs/vfat/namei.c	Wed Apr  3 17:11:14 2002
@@ -115,7 +115,9 @@
 	save = 0;
 	savep = NULL;
 	ret = 1;
-	for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options,",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL) {
 			save = *value;
 			savep = value;
diff -Nru a/include/asm-arm/arch-cl7500/system.h b/include/asm-arm/arch-cl7500/system.h
--- a/include/asm-arm/arch-cl7500/system.h	Wed Apr  3 17:11:16 2002
+++ b/include/asm-arm/arch-cl7500/system.h	Wed Apr  3 17:11:16 2002
@@ -18,6 +18,6 @@
 	do {					\
 		iomd_writeb(0, IOMD_ROMCR0);	\
 		cpu_reset(0);			\
-	} while (0);
+	} while (0)
 
 #endif
diff -Nru a/include/asm-arm/arch-sa1100/keyboard.h b/include/asm-arm/arch-sa1100/keyboard.h
--- a/include/asm-arm/arch-sa1100/keyboard.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-arm/arch-sa1100/keyboard.h	Wed Apr  3 17:11:15 2002
@@ -10,8 +10,8 @@
 #include <asm/mach-types.h>
 #include <asm/arch/assabet.h>
 
-#define kbd_disable_irq()	do { } while(0);
-#define kbd_enable_irq()	do { } while(0);
+#define kbd_disable_irq()	do { } while(0)
+#define kbd_enable_irq()	do { } while(0)
 
 extern int sa1111_kbd_init_hw(void);
 extern void gc_kbd_init_hw(void);
diff -Nru a/include/asm-i386/apic.h b/include/asm-i386/apic.h
--- a/include/asm-i386/apic.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/apic.h	Wed Apr  3 17:11:15 2002
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <linux/pm.h>
+#include <asm/fixmap.h>
 #include <asm/apicdef.h>
 #include <asm/system.h>
 
diff -Nru a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
--- a/include/asm-i386/apicdef.h	Wed Apr  3 17:11:13 2002
+++ b/include/asm-i386/apicdef.h	Wed Apr  3 17:11:13 2002
@@ -71,6 +71,7 @@
 #define			GET_APIC_DEST_FIELD(x)	(((x)>>24)&0xFF)
 #define			SET_APIC_DEST_FIELD(x)	((x)<<24)
 #define		APIC_LVTT	0x320
+#define		APIC_LVTTHMR	0x330
 #define		APIC_LVTPC	0x340
 #define		APIC_LVT0	0x350
 #define			APIC_LVT_TIMER_BASE_MASK	(0x3<<18)
@@ -280,7 +281,16 @@
 		u32 __reserved_4[3];
 	} lvt_timer;
 
-/*330*/	struct { u32 __reserved[4]; } __reserved_15;
+/*330*/	struct { /* LVT - Thermal Sensor */
+		u32  vector		:  8,
+			delivery_mode	:  3,
+			__reserved_1	:  1,
+			delivery_status	:  1,
+			__reserved_2	:  3,
+			mask		:  1,
+			__reserved_3	: 15;
+		u32 __reserved_4[3];
+	} lvt_thermal;
 
 /*340*/	struct { /* LVT - Performance Counter */
 		u32   vector		:  8,
diff -Nru a/include/asm-i386/checksum.h b/include/asm-i386/checksum.h
--- a/include/asm-i386/checksum.h	Wed Apr  3 17:11:16 2002
+++ b/include/asm-i386/checksum.h	Wed Apr  3 17:11:16 2002
@@ -1,6 +1,7 @@
 #ifndef _I386_CHECKSUM_H
 #define _I386_CHECKSUM_H
 
+#include <linux/in6.h>
 
 /*
  * computes the checksum of a memory block at buff, length len,
diff -Nru a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
--- a/include/asm-i386/hw_irq.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/hw_irq.h	Wed Apr  3 17:11:15 2002
@@ -43,6 +43,7 @@
 #define RESCHEDULE_VECTOR	0xfc
 #define CALL_FUNCTION_VECTOR	0xfb
 
+#define THERMAL_APIC_VECTOR	0xf0
 /*
  * Local APIC timer IRQ vector is on a different priority level,
  * to work around the 'lost local interrupt if more than 2 IRQ
diff -Nru a/include/asm-i386/io.h b/include/asm-i386/io.h
--- a/include/asm-i386/io.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/io.h	Wed Apr  3 17:11:15 2002
@@ -57,15 +57,37 @@
   #define __io_virt(x) ((void *)(x))
 #endif
 
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
+/**
+ *	virt_to_phys	-	map virtual addresses to physical
+ *	@address: address to remap
+ *
+ *	The returned physical address is the physical (CPU) mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses directly mapped or allocated via kmalloc. 
+ *
+ *	This function does not give bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
  */
+ 
 static inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
+/**
+ *	phys_to_virt	-	map physical address to virtual
+ *	@address: address to remap
+ *
+ *	The returned virtual address is a current CPU mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses that have a kernel mapping
+ *
+ *	This function does not handle bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
+ */
+
 static inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
@@ -74,20 +96,51 @@
 /*
  * Change "struct page" to physical address.
  */
+#ifdef CONFIG_HIGHMEM64G
+#define page_to_phys(page)	((u64)(page - mem_map) << PAGE_SHIFT)
+#else
 #define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#endif
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
+/**
+ * ioremap     -   map bus memory into CPU space
+ * @offset:    bus address of the memory
+ * @size:      size of the resource to map
+ *
+ * ioremap performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address. 
+ */
+
 static inline void * ioremap (unsigned long offset, unsigned long size)
 {
 	return __ioremap(offset, size, 0);
 }
 
-/*
- * This one maps high address device memory and turns off caching for that area.
- * it's useful if some control registers are in such an area and write combining
- * or read caching is not desirable:
+/**
+ * ioremap_nocache     -   map bus memory into CPU space
+ * @offset:    bus address of the memory
+ * @size:      size of the resource to map
+ *
+ * ioremap_nocache performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address. 
+ *
+ * This version of ioremap ensures that the memory is marked uncachable
+ * on the CPU as well as honouring existing caching rules from things like
+ * the PCI bus. Note that there are other caches and buffers on many 
+ * busses. In paticular driver authors should read up on PCI writes
+ *
+ * It's useful if some control registers are in such an area and
+ * write combining or read caching is not desirable:
  */
+
 static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, _PAGE_PCD);
@@ -172,6 +225,17 @@
 #define eth_io_copy_and_sum(a,b,c,d)		eth_copy_and_sum((a),__io_virt(b),(c),(d))
 #define isa_eth_io_copy_and_sum(a,b,c,d)	eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d))
 
+/**
+ *	check_signature		-	find BIOS signatures
+ *	@io_addr: mmio address to check 
+ *	@signature:  signature block
+ *	@length: length of signature
+ *
+ *	Perform a signature comparison with the mmio address io_addr. This
+ *	address should have been obtained by ioremap.
+ *	Returns 1 on a match.
+ */
+ 
 static inline int check_signature(unsigned long io_addr,
 	const unsigned char *signature, int length)
 {
@@ -187,6 +251,20 @@
 out:
 	return retval;
 }
+
+/**
+ *	isa_check_signature		-	find BIOS signatures
+ *	@io_addr: mmio address to check 
+ *	@signature:  signature block
+ *	@length: length of signature
+ *
+ *	Perform a signature comparison with the ISA mmio address io_addr.
+ *	Returns 1 on a match.
+ *
+ *	This function is deprecated. New drivers should use ioremap and
+ *	check_signature.
+ */
+ 
 
 static inline int isa_check_signature(unsigned long io_addr,
 	const unsigned char *signature, int length)
diff -Nru a/include/asm-i386/irq.h b/include/asm-i386/irq.h
--- a/include/asm-i386/irq.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-i386/irq.h	Wed Apr  3 17:11:14 2002
@@ -11,6 +11,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/sched.h>
 
 #define TIMER_IRQ 0
 
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h	Wed Apr  3 17:11:13 2002
+++ b/include/asm-i386/msr.h	Wed Apr  3 17:11:13 2002
@@ -48,8 +48,8 @@
 #define MSR_IA32_UCODE_WRITE		0x79
 #define MSR_IA32_UCODE_REV		0x8b
 
-#define MSR_IA32_PERFCTR0		0xc1
-#define MSR_IA32_PERFCTR1		0xc2
+#define MSR_P6_PERFCTR0		0xc1
+#define MSR_P6_PERFCTR1		0xc2
 
 #define MSR_IA32_BBL_CR_CTL		0x119
 
@@ -57,8 +57,13 @@
 #define MSR_IA32_MCG_STATUS		0x17a
 #define MSR_IA32_MCG_CTL		0x17b
 
-#define MSR_IA32_EVNTSEL0		0x186
-#define MSR_IA32_EVNTSEL1		0x187
+#define MSR_P6_EVNTSEL0		0x186
+#define MSR_P6_EVNTSEL1		0x187
+
+#define MSR_IA32_THERM_CONTROL		0x19a
+#define MSR_IA32_THERM_INTERRUPT	0x19b
+#define MSR_IA32_THERM_STATUS		0x19c
+#define MSR_IA32_MISC_ENABLE		0x1a0
 
 #define MSR_IA32_DEBUGCTLMSR		0x1d9
 #define MSR_IA32_LASTBRANCHFROMIP	0x1db
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-i386/processor.h	Wed Apr  3 17:11:14 2002
@@ -59,6 +59,7 @@
 #define X86_VENDOR_CENTAUR 5
 #define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NSC 8
 #define X86_VENDOR_UNKNOWN 0xff
 
 /*
@@ -216,7 +217,7 @@
 }
 
 /*
- *      Cyrix CPU configuration register indexes
+ *      NSC/Cyrix CPU configuration register indexes
  */
 #define CX86_CCR0 0xc0
 #define CX86_CCR1 0xc1
@@ -232,7 +233,7 @@
 #define CX86_RCR_BASE 0xdc
 
 /*
- *      Cyrix CPU indexed register access macros
+ *      NSC/Cyrix CPU indexed register access macros
  */
 
 #define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
diff -Nru a/include/asm-i386/rwsem.h b/include/asm-i386/rwsem.h
--- a/include/asm-i386/rwsem.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/rwsem.h	Wed Apr  3 17:11:15 2002
@@ -164,7 +164,7 @@
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending __up_read\n"
-		: "+m"(sem->count), "+d"(tmp)
+		: /*"+m"(sem->count),*/ "+d"(tmp)
 		: "a"(sem)
 		: "memory", "cc");
 }
diff -Nru a/include/asm-i386/string-486.h b/include/asm-i386/string-486.h
--- a/include/asm-i386/string-486.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/string-486.h	Wed Apr  3 17:11:15 2002
@@ -5,7 +5,7 @@
  * This string-include defines all string functions as inline
  * functions. Use gcc. It also assumes ds=es=data space, this should be
  * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
  * very easy to understand. Everything is done entirely within the register
  * set, making the functions fast and clean. 
  *
diff -Nru a/include/asm-i386/string.h b/include/asm-i386/string.h
--- a/include/asm-i386/string.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-i386/string.h	Wed Apr  3 17:11:15 2002
@@ -20,7 +20,7 @@
  * This string-include defines all string functions as inline
  * functions. Use gcc. It also assumes ds=es=data space, this should be
  * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strtok,strstr,str[c]spn. They should work, but are not
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
  * very easy to understand. Everything is done entirely within the register
  * set, making the functions fast and clean. String instructions have been
  * used through-out, making for "slightly" unclear code :-)
diff -Nru a/include/asm-i386/timex.h b/include/asm-i386/timex.h
--- a/include/asm-i386/timex.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-i386/timex.h	Wed Apr  3 17:11:14 2002
@@ -9,7 +9,12 @@
 #include <linux/config.h>
 #include <asm/msr.h>
 
-#define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
+#ifdef CONFIG_MELAN
+#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
+#else
+#  define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#endif
+
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
diff -Nru a/include/asm-m68k/string.h b/include/asm-m68k/string.h
--- a/include/asm-m68k/string.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-m68k/string.h	Wed Apr  3 17:11:15 2002
@@ -117,29 +117,6 @@
 }
 #endif
 
-#if 0
-#define __HAVE_ARCH_STRTOK
-extern inline char * strtok(char * s,const char * ct)
-{
-  char *sbegin, *send;
-  
-  sbegin  = s ? s : ___strtok;
-  if (!sbegin) {
-	  return NULL;
-  }
-  sbegin += strspn(sbegin,ct);
-  if (*sbegin == '\0') {
-    ___strtok = NULL;
-    return( NULL );
-  }
-  send = strpbrk( sbegin, ct);
-  if (send && *send != '\0')
-    *send++ = '\0';
-  ___strtok = send;
-  return (sbegin);
-}
-#endif
-
 /* strstr !! */
 
 #define __HAVE_ARCH_STRLEN
diff -Nru a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
--- a/include/asm-mips/spinlock.h	Wed Apr  3 17:11:16 2002
+++ b/include/asm-mips/spinlock.h	Wed Apr  3 17:11:16 2002
@@ -19,10 +19,10 @@
 
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
-#define spin_lock_init(x)	do { (x)->lock = 0; } while(0);
+#define spin_lock_init(x)	do { (x)->lock = 0; } while(0)
 
 #define spin_is_locked(x)	((x)->lock != 0)
-#define spin_unlock_wait(x)	({ do { barrier(); } while ((x)->lock); })
+#define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
diff -Nru a/include/asm-mips64/spinlock.h b/include/asm-mips64/spinlock.h
--- a/include/asm-mips64/spinlock.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-mips64/spinlock.h	Wed Apr  3 17:11:15 2002
@@ -19,10 +19,10 @@
 
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 
-#define spin_lock_init(x)	do { (x)->lock = 0; } while(0);
+#define spin_lock_init(x)	do { (x)->lock = 0; } while(0)
 
 #define spin_is_locked(x)	((x)->lock != 0)
-#define spin_unlock_wait(x)	({ do { barrier(); } while ((x)->lock); })
+#define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
diff -Nru a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
--- a/include/asm-parisc/pgalloc.h	Wed Apr  3 17:11:16 2002
+++ b/include/asm-parisc/pgalloc.h	Wed Apr  3 17:11:16 2002
@@ -123,7 +123,7 @@
 #define flush_tlb() do { \
         flush_data_tlb(); \
 	flush_instruction_tlb(); \
-} while(0);
+} while(0)
 
 #define flush_tlb_all() 	flush_tlb()	/* XXX p[id]tlb */
 
diff -Nru a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h
--- a/include/asm-sparc/elf.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-sparc/elf.h	Wed Apr  3 17:11:14 2002
@@ -41,7 +41,7 @@
 	dest[34] = src->npc;				\
 	dest[35] = src->y;				\
 	dest[36] = dest[37] = 0; /* XXX */		\
-} while(0);
+} while(0)
 
 typedef struct {
 	union {
diff -Nru a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
--- a/include/asm-sparc/pgtable.h	Wed Apr  3 17:11:13 2002
+++ b/include/asm-sparc/pgtable.h	Wed Apr  3 17:11:13 2002
@@ -293,6 +293,9 @@
 #define page_pte_prot(page, prot)	mk_pte(page, prot)
 #define page_pte(page)			page_pte_prot(page, __pgprot(0))
 
+/* Permanent address of a page. */
+#define page_address(page)  ((page)->virtual)
+
 BTFIXUPDEF_CALL(struct page *, pte_page, pte_t)
 #define pte_page(pte) BTFIXUP_CALL(pte_page)(pte)
 
diff -Nru a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h
--- a/include/asm-sparc/sbus.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-sparc/sbus.h	Wed Apr  3 17:11:14 2002
@@ -94,7 +94,8 @@
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-	for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+		for ((device) = (bus)->devices; (device); (device) = (device)->next)
 
 /* Driver DVMA interfaces. */
 #define sbus_can_dma_64bit(sdev)	(0) /* actually, sparc_cpu_model==sun4d */
diff -Nru a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
--- a/include/asm-sparc64/pgalloc.h	Wed Apr  3 17:11:15 2002
+++ b/include/asm-sparc64/pgalloc.h	Wed Apr  3 17:11:15 2002
@@ -10,13 +10,6 @@
 #include <asm/spitfire.h>
 #include <asm/pgtable.h>
 
-#define VPTE_BASE_SPITFIRE	0xfffffffe00000000
-#if 1
-#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
-#else
-#define VPTE_BASE_CHEETAH	0xffe0000000000000
-#endif
-
 static __inline__ void flush_tlb_pgtables(struct mm_struct *mm, unsigned long start,
 					  unsigned long end)
 {
@@ -42,8 +35,6 @@
 				vpte_base + (e >> (PAGE_SHIFT - 3)));
 	}
 }
-#undef VPTE_BASE_SPITFIRE
-#undef VPTE_BASE_CHEETAH
 
 /* Page table allocation/freeing. */
 #ifdef CONFIG_SMP
diff -Nru a/include/asm-sparc64/processor.h b/include/asm-sparc64/processor.h
--- a/include/asm-sparc64/processor.h	Wed Apr  3 17:11:13 2002
+++ b/include/asm-sparc64/processor.h	Wed Apr  3 17:11:13 2002
@@ -39,8 +39,24 @@
  * address that the kernel will allocate out.
  */
 #define VA_BITS		44
+#ifndef __ASSEMBLY__
 #define VPTE_SIZE	(1UL << (VA_BITS - PAGE_SHIFT + 3))
+#else
+#define VPTE_SIZE	(1 << (VA_BITS - PAGE_SHIFT + 3))
+#endif
 #define TASK_SIZE	((unsigned long)-VPTE_SIZE)
+
+/*
+ * The vpte base must be able to hold the entire vpte, half
+ * of which lives above, and half below, the base. And it
+ * is placed as close to the highest address range as possible.
+ */
+#define VPTE_BASE_SPITFIRE	(-(VPTE_SIZE/2))
+#if 1
+#define VPTE_BASE_CHEETAH	VPTE_BASE_SPITFIRE
+#else
+#define VPTE_BASE_CHEETAH	0xffe0000000000000
+#endif
 
 #ifndef __ASSEMBLY__
 
diff -Nru a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h
--- a/include/asm-sparc64/sbus.h	Wed Apr  3 17:11:14 2002
+++ b/include/asm-sparc64/sbus.h	Wed Apr  3 17:11:14 2002
@@ -87,7 +87,8 @@
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-	for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+	for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
+		for ((device) = (bus)->devices; (device); (device) = (device)->next)
 
 /* Driver DVMA interfaces. */
 #define sbus_can_dma_64bit(sdev)	(1)
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/device.h	Wed Apr  3 17:11:15 2002
@@ -83,7 +83,7 @@
 					   device */
 	void		*driver_data;	/* data private to the driver */
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
-					   BIOS data relevant to device */
+					   BIOS data relevant to device) */
 
 	u32		current_state;  /* Current operating state. In
 					   ACPI-speak, this is D0-D3, D0
diff -Nru a/include/linux/ethtool.h b/include/linux/ethtool.h
--- a/include/linux/ethtool.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/ethtool.h	Wed Apr  3 17:11:14 2002
@@ -36,7 +36,8 @@
 	char	bus_info[ETHTOOL_BUSINFO_LEN];	/* Bus info for this IF. */
 				/* For PCI devices, use pci_dev->slot_name. */
 	char	reserved1[32];
-	char	reserved2[24];
+	char	reserved2[20];
+	u32	testinfo_len;
 	u32	eedump_len;	/* Size of data from ETHTOOL_GEEPROM (bytes) */
 	u32	regdump_len;	/* Size of data from ETHTOOL_GREGS (bytes) */
 };
@@ -210,6 +211,34 @@
 	u32	tx_pause;
 };
 
+#define ETH_GSTRING_LEN		32
+enum ethtool_stringset {
+	ETH_SS_TEST		= 0,
+	ETH_SS_STATS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+	u32	cmd;		/* ETHTOOL_GSTRINGS */
+	u32	string_set;	/* string set id e.c. ETH_SS_TEST, etc*/
+	u32	len;		/* number of strings in the string set */
+	u8	data[0];
+};
+
+enum ethtool_test_flags {
+	ETH_TEST_FL_OFFLINE	= (1 << 0),	/* online / offline */
+	ETH_TEST_FL_FAILED	= (1 << 1),	/* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+	u32	cmd;		/* ETHTOOL_TEST */
+	u32	flags;		/* ETH_TEST_FL_xxx */
+	u32	reserved;
+	u32	len;		/* result length, in number of u64 elements */
+	u64	data[0];
+};
+
 /* CMDs currently supported */
 #define ETHTOOL_GSET		0x00000001 /* Get settings. */
 #define ETHTOOL_SSET		0x00000002 /* Set settings, privileged. */
@@ -222,13 +251,13 @@
 #define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation, priv. */
 #define ETHTOOL_GLINK		0x0000000a /* Get link status (ethtool_value) */
 #define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data */
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data, priv. */
 #define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
-#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config */
+#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config, priv. */
 #define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
-#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters */
+#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters, priv. */
 #define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
-#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters */
+#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters, priv. */
 #define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
 #define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
 #define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
@@ -236,7 +265,9 @@
 #define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
 					    * (ethtool_value) */
 #define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
-					    * (ethtool_value) */
+					    * (ethtool_value), priv. */
+#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test, priv. */
+#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET		ETHTOOL_GSET
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/fs.h	Wed Apr  3 17:11:14 2002
@@ -664,6 +664,7 @@
 	kdev_t			s_dev;
 	unsigned long		s_blocksize;
 	unsigned char		s_blocksize_bits;
+	unsigned long		s_old_blocksize;
 	unsigned char		s_dirt;
 	unsigned long long	s_maxbytes;	/* Max file size */
 	struct file_system_type	*s_type;
diff -Nru a/include/linux/hdreg.h b/include/linux/hdreg.h
--- a/include/linux/hdreg.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/hdreg.h	Wed Apr  3 17:11:15 2002
@@ -54,16 +54,9 @@
  *	HDIO_DRIVE_CMD and HDIO_DRIVE_TASK
  */
 
-#if 0
-#include <asm/hdreg.h>
-typedef ide_ioreg_t task_ioreg_t;
-#else
-typedef unsigned char task_ioreg_t;
-#endif
-
-#define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
-#define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
-#define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
+#define HDIO_DRIVE_CMD_HDR_SIZE		(4 * sizeof(u8))
+#define HDIO_DRIVE_TASK_HDR_SIZE	(8 * sizeof(u8))
+#define HDIO_DRIVE_HOB_HDR_SIZE		(8 * sizeof(u8))
 
 #define IDE_DRIVE_TASK_INVALID		-1
 #define IDE_DRIVE_TASK_NO_DATA		0
@@ -74,57 +67,27 @@
 #define IDE_DRIVE_TASK_OUT		3
 #define IDE_DRIVE_TASK_RAW_WRITE	4
 
-struct hd_drive_cmd_hdr {
-	task_ioreg_t command;
-	task_ioreg_t sector_number;
-	task_ioreg_t feature;
-	task_ioreg_t sector_count;
-};
-
-typedef struct hd_drive_task_hdr {
-	task_ioreg_t data;
-	task_ioreg_t feature;
-	task_ioreg_t sector_count;
-	task_ioreg_t sector_number;
-	task_ioreg_t low_cylinder;
-	task_ioreg_t high_cylinder;
-	task_ioreg_t device_head;
-	task_ioreg_t command;
-} task_struct_t;
-
-typedef struct hd_drive_hob_hdr {
-	task_ioreg_t data;
-	task_ioreg_t feature;
-	task_ioreg_t sector_count;
-	task_ioreg_t sector_number;
-	task_ioreg_t low_cylinder;
-	task_ioreg_t high_cylinder;
-	task_ioreg_t device_head;
-	task_ioreg_t control;
-} hob_struct_t;
-
-typedef union ide_reg_valid_s {
-	unsigned all				: 16;
-	struct {
-		unsigned data			: 1;
-		unsigned error_feature		: 1;
-		unsigned sector			: 1;
-		unsigned nsector		: 1;
-		unsigned lcyl			: 1;
-		unsigned hcyl			: 1;
-		unsigned select			: 1;
-		unsigned status_command		: 1;
-
-		unsigned data_hob		: 1;
-		unsigned error_feature_hob	: 1;
-		unsigned sector_hob		: 1;
-		unsigned nsector_hob		: 1;
-		unsigned lcyl_hob		: 1;
-		unsigned hcyl_hob		: 1;
-		unsigned select_hob		: 1;
-		unsigned control_hob		: 1;
-	} b;
-} ide_reg_valid_t;
+struct hd_drive_task_hdr {
+	u8 data;
+	u8 feature;
+	u8 sector_count;
+	u8 sector_number;
+	u8 low_cylinder;
+	u8 high_cylinder;
+	u8 device_head;
+	u8 command;
+} __attribute__((packed));
+
+struct hd_drive_hob_hdr {
+	u8 data;
+	u8 feature;
+	u8 sector_count;
+	u8 sector_number;
+	u8 low_cylinder;
+	u8 high_cylinder;
+	u8 device_head;
+	u8 control;
+} __attribute__((packed));
 
 /*
  * Define standard taskfile in/out register
@@ -134,23 +97,6 @@
 #define IDE_HOB_STD_OUT_FLAGS		0xC0
 #define IDE_HOB_STD_IN_FLAGS		0xC0
 
-typedef struct ide_task_request_s {
-	task_ioreg_t	io_ports[8];
-	task_ioreg_t	hob_ports[8];
-	ide_reg_valid_t	out_flags;
-	ide_reg_valid_t	in_flags;
-	int		data_phase;
-	int		req_cmd;
-	unsigned long	out_size;
-	unsigned long	in_size;
-} ide_task_request_t;
-
-typedef struct ide_ioctl_request_s {
-	ide_task_request_t	*task_request;
-	unsigned char		*out_buffer;
-	unsigned char		*in_buffer;
-} ide_ioctl_request_t;
-
 #define TASKFILE_INVALID		0x7fff
 #define TASKFILE_48			0x8000
 
@@ -212,7 +158,7 @@
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
 #define WIN_QUEUED_SERVICE		0xA2
 #define WIN_SMART			0xB0 /* self-monitoring and reporting */
-#define CFA_ERASE_SECTORS       	0xC0
+#define CFA_ERASE_SECTORS		0xC0
 #define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
 #define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
@@ -221,12 +167,12 @@
 #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */
 #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_GETMEDIASTATUS		0xDA
 #define WIN_DOORLOCK			0xDE /* lock door on removable drives */
 #define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */
 #define WIN_STANDBYNOW1			0xE0
 #define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */
+#define WIN_STANDBY			0xE2 /* Set device in Standby Mode */
 #define WIN_SETIDLE1			0xE3
 #define WIN_READ_BUFFER			0xE4 /* force read only 1 sector */
 #define WIN_CHECKPOWERMODE1		0xE5
@@ -268,7 +214,7 @@
 
 #define SMART_LCYL_PASS			0x4F
 #define SMART_HCYL_PASS			0xC2
-		
+
 /* WIN_SETFEATURES sub-commands */
 
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
@@ -638,8 +584,5 @@
  */
 #define IDE_NICE_DSC_OVERLAP	(0)	/* per the DSC overlap protocol */
 #define IDE_NICE_ATAPI_OVERLAP	(1)	/* not supported yet */
-#define IDE_NICE_0		(2)	/* when sure that it won't affect us */
-#define IDE_NICE_1		(3)	/* when probably won't affect us much */
-#define IDE_NICE_2		(4)	/* when we know it's on our expense */
 
 #endif	/* _LINUX_HDREG_H */
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/hiddev.h	Wed Apr  3 17:11:14 2002
@@ -119,13 +119,17 @@
 	__s32 value;
 };
 
+/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags
+ * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has
+ * been sent by the device 
+ */
 #define HID_FIELD_INDEX_NONE 0xffffffff
 
 /*
  * Protocol version.
  */
 
-#define HID_VERSION		0x010002
+#define HID_VERSION		0x010003
 
 /*
  * IOCTLs (0x00 - 0x7f)
@@ -139,20 +143,20 @@
 #define HIDIOCGNAME(len)	_IOC(_IOC_READ, 'H', 0x06, len)
 #define HIDIOCGREPORT		_IOW('H', 0x07, struct hiddev_report_info)
 #define HIDIOCSREPORT		_IOW('H', 0x08, struct hiddev_report_info)
-#define HIDIOCGREPORTINFO       _IOWR('H', 0x09, struct hiddev_report_info)
-#define HIDIOCGFIELDINFO        _IOWR('H', 0x0A, struct hiddev_field_info)
-#define HIDIOCGUSAGE            _IOWR('H', 0x0B, struct hiddev_usage_ref)
-#define HIDIOCSUSAGE            _IOW('H', 0x0C, struct hiddev_usage_ref)
-#define HIDIOCGUCODE            _IOWR('H', 0x0D, struct hiddev_usage_ref)
-#define HIDIOCGFLAG             _IOR('H', 0x0E, int)
-#define HIDIOCSFLAG             _IOW('H', 0x0F, int)
+#define HIDIOCGREPORTINFO	_IOWR('H', 0x09, struct hiddev_report_info)
+#define HIDIOCGFIELDINFO	_IOWR('H', 0x0A, struct hiddev_field_info)
+#define HIDIOCGUSAGE		_IOWR('H', 0x0B, struct hiddev_usage_ref)
+#define HIDIOCSUSAGE		_IOW('H', 0x0C, struct hiddev_usage_ref)
+#define HIDIOCGUCODE		_IOWR('H', 0x0D, struct hiddev_usage_ref)
+#define HIDIOCGFLAG		_IOR('H', 0x0E, int)
+#define HIDIOCSFLAG		_IOW('H', 0x0F, int)
 
 /* 
  * Flags to be used in HIDIOCSFLAG
  */
-#define HIDDEV_FLAG_UREF     0x1
-#define HIDDEV_FLAG_REPORT   0x2
-#define HIDDEV_FLAGS         0x3
+#define HIDDEV_FLAG_UREF	0x1
+#define HIDDEV_FLAG_REPORT	0x2
+#define HIDDEV_FLAGS		0x3
 
 /* To traverse the input report descriptor info for a HID device, perform the 
  * following:
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/ide.h	Wed Apr  3 17:11:14 2002
@@ -68,8 +68,8 @@
  */
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
 
-#define HWIF(drive)		((drive)->hwif)
-#define HWGROUP(drive)		(HWIF(drive)->hwgroup)
+#define HWIF(drive)		((drive)->channel)
+#define HWGROUP(drive)		(drive->channel->hwgroup)
 
 /*
  * Definitions for accessing IDE controller registers
@@ -90,37 +90,16 @@
 #define IDE_FEATURE_OFFSET	IDE_ERROR_OFFSET
 #define IDE_COMMAND_OFFSET	IDE_STATUS_OFFSET
 
-#define IDE_DATA_OFFSET_HOB	(0)
-#define IDE_ERROR_OFFSET_HOB	(1)
-#define IDE_NSECTOR_OFFSET_HOB	(2)
-#define IDE_SECTOR_OFFSET_HOB	(3)
-#define IDE_LCYL_OFFSET_HOB	(4)
-#define IDE_HCYL_OFFSET_HOB	(5)
-#define IDE_SELECT_OFFSET_HOB	(6)
-#define IDE_CONTROL_OFFSET_HOB	(7)
-
-#define IDE_FEATURE_OFFSET_HOB	IDE_ERROR_OFFSET_HOB
-
-#define IDE_DATA_REG		(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG		(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG		(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG		(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG		(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG		(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG		(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG		(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG		(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
-#define IDE_IRQ_REG		(HWIF(drive)->io_ports[IDE_IRQ_OFFSET])
-
-#define IDE_DATA_REG_HOB	(HWIF(drive)->io_ports[IDE_DATA_OFFSET])
-#define IDE_ERROR_REG_HOB	(HWIF(drive)->io_ports[IDE_ERROR_OFFSET])
-#define IDE_NSECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_NSECTOR_OFFSET])
-#define IDE_SECTOR_REG_HOB	(HWIF(drive)->io_ports[IDE_SECTOR_OFFSET])
-#define IDE_LCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_LCYL_OFFSET])
-#define IDE_HCYL_REG_HOB	(HWIF(drive)->io_ports[IDE_HCYL_OFFSET])
-#define IDE_SELECT_REG_HOB	(HWIF(drive)->io_ports[IDE_SELECT_OFFSET])
-#define IDE_STATUS_REG_HOB	(HWIF(drive)->io_ports[IDE_STATUS_OFFSET])
-#define IDE_CONTROL_REG_HOB	(HWIF(drive)->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_DATA_REG		(drive->channel->io_ports[IDE_DATA_OFFSET])
+#define IDE_ERROR_REG		(drive->channel->io_ports[IDE_ERROR_OFFSET])
+#define IDE_NSECTOR_REG		(drive->channel->io_ports[IDE_NSECTOR_OFFSET])
+#define IDE_SECTOR_REG		(drive->channel->io_ports[IDE_SECTOR_OFFSET])
+#define IDE_LCYL_REG		(drive->channel->io_ports[IDE_LCYL_OFFSET])
+#define IDE_HCYL_REG		(drive->channel->io_ports[IDE_HCYL_OFFSET])
+#define IDE_SELECT_REG		(drive->channel->io_ports[IDE_SELECT_OFFSET])
+#define IDE_STATUS_REG		(drive->channel->io_ports[IDE_STATUS_OFFSET])
+#define IDE_CONTROL_REG		(drive->channel->io_ports[IDE_CONTROL_OFFSET])
+#define IDE_IRQ_REG		(drive->channel->io_ports[IDE_IRQ_OFFSET])
 
 #define IDE_FEATURE_REG		IDE_ERROR_REG
 #define IDE_COMMAND_REG		IDE_STATUS_REG
@@ -175,24 +154,24 @@
 #define WAIT_CMD	(10*HZ)		/* 10sec  - maximum wait for an IRQ to happen */
 #define WAIT_MIN_SLEEP	(2*HZ/100)	/* 20msec - minimum sleep time */
 
-#define SELECT_DRIVE(hwif,drive)				\
+#define SELECT_DRIVE(channel, drive)				\
 {								\
-	if (hwif->selectproc)					\
-		hwif->selectproc(drive);			\
-	OUT_BYTE((drive)->select.all, hwif->io_ports[IDE_SELECT_OFFSET]); \
+	if (channel->selectproc)				\
+		channel->selectproc(drive);			\
+	OUT_BYTE((drive)->select.all, channel->io_ports[IDE_SELECT_OFFSET]); \
 }
 
-#define SELECT_MASK(hwif,drive,mask)				\
+#define SELECT_MASK(channel, drive, mask)			\
 {								\
-	if (hwif->maskproc)					\
-		hwif->maskproc(drive,mask);			\
+	if (channel->maskproc)					\
+		channel->maskproc(drive,mask);			\
 }
 
 /*
  * Check for an interrupt and acknowledge the interrupt status
  */
-struct hwif_s;
-typedef int (ide_ack_intr_t)(struct hwif_s *);
+struct ata_channel;
+typedef int (ide_ack_intr_t)(struct ata_channel *);
 
 #ifndef NO_DMA
 # define NO_DMA  255
@@ -235,7 +214,6 @@
 	int		irq;			/* our irq number */
 	int		dma;			/* our dma entry */
 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
-	void		*priv;			/* interface specific data */
 	hwif_chipset_t  chipset;
 } hw_regs_t;
 
@@ -291,20 +269,28 @@
 struct ide_settings_s;
 
 typedef struct ide_drive_s {
-	unsigned int	usage;		/* current "open()" count for drive */
+	struct ata_channel *channel;	/* parent pointer to the channel we are attached to  */
+
+	unsigned int usage;		/* current "open()" count for drive */
 	char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */
 
 	/* NOTE: If we had proper separation between channel and host chip, we
 	 * could move this to the chanell and many sync problems would
 	 * magically just go away.
 	 */
-	request_queue_t		 queue;	/* per device request queue */
+	request_queue_t	queue;	/* per device request queue */
 
 	struct ide_drive_s	*next;	/* circular list of hwgroup drives */
-	unsigned long sleep;		/* sleep until this time */
-	unsigned long service_start;	/* time we started last request */
-	unsigned long service_time;	/* service time of last request */
-	unsigned long timeout;		/* max time to wait for irq */
+
+	/* Those are directly injected jiffie values. They should go away and
+	 * we should use generic timers instead!!!
+	 */
+
+	unsigned long PADAM_sleep;		/* sleep until this time */
+	unsigned long PADAM_service_start;	/* time we started last request */
+	unsigned long PADAM_service_time;	/* service time of last request */
+	unsigned long PADAM_timeout;		/* max time to wait for irq */
+
 	special_t	special;	/* special action flags */
 	byte     keep_settings;		/* restore settings after drive reset */
 	byte     using_dma;		/* disk is using dma for read/write */
@@ -314,11 +300,13 @@
 	byte     slow;			/* flag: slow data port */
 	byte     bswap;			/* flag: byte swap data */
 	byte     dsc_overlap;		/* flag: DSC overlap */
-	byte     nice1;			/* flag: give potential excess bandwidth */
+
 	unsigned waiting_for_dma: 1;	/* dma currently in progress */
+	unsigned busy		: 1;	/* currently doing revalidate_disk() */
+	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
+
 	unsigned present	: 1;	/* drive is physically present */
 	unsigned noprobe	: 1;	/* from:  hdx=noprobe */
-	unsigned busy		: 1;	/* currently doing revalidate_disk() */
 	unsigned removable	: 1;	/* 1 if need to do check_media_change */
 	unsigned forced_geom	: 1;	/* 1 if hdx=c,h,s was given at boot */
 	unsigned no_unmask	: 1;	/* disallow setting unmask bit */
@@ -326,21 +314,18 @@
 	unsigned nobios		: 1;	/* flag: do not probe bios for drive */
 	unsigned revalidate	: 1;	/* request revalidation */
 	unsigned atapi_overlap	: 1;	/* flag: ATAPI overlap (not supported) */
-	unsigned nice0		: 1;	/* flag: give obvious excess bandwidth */
-	unsigned nice2		: 1;	/* flag: give a share in our own bandwidth */
 	unsigned doorlocking	: 1;	/* flag: for removable only: door lock/unlock works */
 	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
-	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
 	unsigned	addressing;	/* : 2; 0=28-bit, 1=48-bit, 2=64-bit */
 	byte		scsi;		/* 0=default, 1=skip current ide-subdriver for ide-scsi emulation */
 	select_t	select;		/* basic drive/head select reg value */
 	byte		ctl;		/* "normal" value for IDE_CONTROL_REG */
 	byte		ready_stat;	/* min status value for drive ready */
 	byte		mult_count;	/* current multiple sector setting */
-	byte 		mult_req;	/* requested multiple sector setting */
-	byte 		tune_req;	/* requested drive tuning setting */
+	byte		mult_req;	/* requested multiple sector setting */
+	byte		tune_req;	/* requested drive tuning setting */
 	byte		io_32bit;	/* 0=16-bit, 1=32-bit, 2/3=32bit+sync */
 	byte		bad_wstat;	/* used for ignoring WRERR_STAT */
 	byte		nowerr;		/* used for ignoring WRERR_STAT */
@@ -354,20 +339,25 @@
 	unsigned long	capacity;	/* total number of sectors */
 	unsigned long long capacity48;	/* total number of sectors */
 	unsigned int	drive_data;	/* for use by tuneproc/selectproc as needed */
-	struct hwif_s   *hwif;		/* parent pointer to the interface we are attached to  */
+
 	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
+
 	struct hd_driveid *id;		/* drive model identification info */
 	struct hd_struct  *part;	/* drive partition table */
+
 	char		name[4];	/* drive name, such as "hda" */
 	struct ata_operations *driver;
+
 	void		*driver_data;	/* extra driver data */
 	devfs_handle_t	de;		/* directory for device */
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	struct ide_settings_s *settings;    /* /proc/ide/ drive settings */
 	char		driver_req[10];	/* requests specific driver */
+
 	int		last_lun;	/* last logical unit */
 	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
+
 	int		crc_count;	/* crc counter to reduce drive speed */
 	byte		quirk_list;	/* drive is considered quirky if set for a specific host */
 	byte		suspend_reset;	/* drive suspend mode flag, soft-reset recovers */
@@ -409,7 +399,7 @@
  *
  * If it is not defined for a controller, standard-code is used from ide.c.
  *
- * Controllers which are not memory-mapped in the standard way need to 
+ * Controllers which are not memory-mapped in the standard way need to
  * override that mechanism using this function to work.
  *
  */
@@ -448,11 +438,18 @@
  */
 typedef int (ide_busproc_t) (ide_drive_t *, int);
 
-typedef struct hwif_s {
-	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
+struct ata_channel {
+	struct device	dev;		/* device handle */
+	int		unit;		/* channel number */
+
+	struct ata_channel *next;	/* for linked-list in ide_hwgroup_t */
 	struct hwgroup_s *hwgroup;	/* actually (ide_hwgroup_t *) */
+
 	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
 	hw_regs_t	hw;		/* Hardware info */
+#ifdef CONFIG_BLK_DEV_IDEPCI
+	struct pci_dev	*pci_dev;	/* for pci chipsets */
+#endif
 	ide_drive_t	drives[MAX_DRIVES];	/* drive info */
 	struct gendisk	*gd;		/* gendisk structure */
 	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
@@ -470,7 +467,7 @@
 	struct scatterlist *sg_table;	/* Scatter-gather list used to build the above */
 	int sg_nents;			/* Current number of entries in it */
 	int sg_dma_direction;		/* dma transfer direction */
-	struct hwif_s	*mate;		/* other hwif from same PCI chip */
+	struct ata_channel *mate;	/* other hwif from same PCI chip */
 	unsigned long	dma_base;	/* base addr for dma ports */
 	unsigned	dma_extra;	/* extra addr for dma ports */
 	unsigned long	config_data;	/* for use by chipset-specific code */
@@ -478,7 +475,7 @@
 	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
 	int		irq;		/* our irq number */
 	int		major;		/* our major number */
-	char		name[80];	/* name of interface */
+	char		name[8];	/* name of interface */
 	int		index;		/* 0 for ide0; 1 for ide1; ... */
 	hwif_chipset_t	chipset;	/* sub-module for tuning.. */
 	unsigned	noprobe    : 1;	/* don't probe for this interface */
@@ -489,24 +486,19 @@
 	unsigned	autodma    : 1;	/* automatically try to enable DMA at boot */
 	unsigned	udma_four  : 1;	/* 1=ATA-66 capable, 0=default */
 	unsigned	highmem	   : 1; /* can do full 32-bit dma */
-	byte		channel;	/* for dual-port chips: 0=primary, 1=secondary */
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	struct pci_dev	*pci_dev;	/* for pci chipsets */
-#endif
 #if (DISK_RECOVERY_TIME > 0)
 	unsigned long	last_time;	/* time when previous rq was done */
 #endif
 	byte		straight8;	/* Alan's straight 8 check */
 	ide_busproc_t	*busproc;	/* driver soft-power interface */
 	byte		bus_state;	/* power state of the IDE bus */
-	struct device	device;		/* global device tree handle */
-} ide_hwif_t;
+};
 
 /*
  * Register new hardware with ide
  */
-extern int ide_register_hw(hw_regs_t *hw, struct hwif_s **hwifp);
-extern void ide_unregister(ide_hwif_t *hwif);
+extern int ide_register_hw(hw_regs_t *hw, struct ata_channel **hwifp);
+extern void ide_unregister(struct ata_channel *hwif);
 
 /*
  * Status returned from various ide_ functions
@@ -536,7 +528,7 @@
 	ide_handler_t		*handler;/* irq handler, if active */
 	unsigned long		flags;	/* BUSY, SLEEPING */
 	ide_drive_t		*drive;	/* current drive */
-	ide_hwif_t		*hwif;	/* ptr to current hwif in linked-list */
+	struct ata_channel	*hwif;	/* ptr to current hwif in linked-list */
 	struct request		*rq;	/* current request */
 	struct timer_list	timer;	/* failsafe timer */
 	struct request		wrq;	/* local copy of current write rq */
@@ -595,7 +587,7 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
-void destroy_proc_ide_drives(ide_hwif_t *);
+void destroy_proc_ide_drives(struct ata_channel *);
 void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
@@ -630,7 +622,6 @@
 
 struct ata_operations {
 	struct module *owner;
-	unsigned busy: 1; /* FIXME: this will go soon away... */
 	int (*cleanup)(ide_drive_t *);
 	int (*standby)(ide_drive_t *);
 	ide_startstop_t	(*do_request)(ide_drive_t *, struct request *, unsigned long);
@@ -645,6 +636,7 @@
 	void (*pre_reset)(ide_drive_t *);
 	unsigned long (*capacity)(ide_drive_t *);
 	ide_startstop_t	(*special)(ide_drive_t *);
+
 	ide_proc_entry_t *proc;
 };
 
@@ -670,15 +662,7 @@
 
 #define ata_ops(drive)		((drive)->driver)
 
-/*
- * ide_hwifs[] is the master data structure used to keep track
- * of just about everything in ide.c.  Whenever possible, routines
- * should be using pointers to a drive (ide_drive_t *) or
- * pointers to a hwif (ide_hwif_t *), rather than indexing this
- * structure directly (the allocation/layout may change!).
- *
- */
-extern struct hwif_s ide_hwifs[];		/* master data repository */
+extern struct ata_channel ide_hwifs[];		/* master data repository */
 extern int noautodma;
 
 /*
@@ -771,35 +755,7 @@
  */
 #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
-#define task_rq_offset(rq) \
-	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
-
-/*
- * This function issues a special IDE device request
- * onto the request queue.
- *
- * If action is ide_wait, then the rq is queued at the end of the
- * request queue, and the function sleeps until it has been processed.
- * This is for use when invoked from an ioctl handler.
- *
- * If action is ide_preempt, then the rq is queued at the head of
- * the request queue, displacing the currently-being-processed
- * request and this function returns immediately without waiting
- * for the new rq to be completed.  This is VERY DANGEROUS, and is
- * intended for careful use by the ATAPI tape/cdrom driver code.
- *
- * If action is ide_next, then the rq is queued immediately after
- * the currently-being-processed-request (if any), and the function
- * returns without waiting for the new rq to be completed.  As above,
- * This is VERY DANGEROUS, and is intended for careful use by the
- * ATAPI tape/cdrom driver code.
- *
- * If action is ide_end, then the rq is queued at the end of the
- * request queue, and the function returns immediately without waiting
- * for the new rq to be completed. This is again intended for careful
- * use by the ATAPI tape/cdrom driver code.
- */
-int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
+extern int ide_do_drive_cmd(ide_drive_t *drive, struct request *rq, ide_action_t action);
 
 /*
  * Clean up after success/failure of an explicit drive cmd.
@@ -807,17 +763,11 @@
 void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err);
 
 typedef struct ide_task_s {
-	task_ioreg_t		tfRegister[8];
-	task_ioreg_t		hobRegister[8];
-	ide_reg_valid_t		tf_out_flags;
-	ide_reg_valid_t		tf_in_flags;
-	int			data_phase;
+	struct hd_drive_task_hdr taskfile;
+	struct hd_drive_hob_hdr  hobfile;
 	int			command_type;
 	ide_pre_handler_t	*prehandler;
 	ide_handler_t		*handler;
-	void			*special;	/* valid_t generally */
-	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
 } ide_task_t;
 
 void ata_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
@@ -827,15 +777,12 @@
 void taskfile_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
 void taskfile_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
 
-/*
- * taskfile io for disks for now...
- */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
-
-/*
- * Builds request from ide_ioctl
- */
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+extern ide_startstop_t ata_taskfile(ide_drive_t *drive,
+		struct hd_drive_task_hdr *taskfile,
+		struct hd_drive_hob_hdr *hobfile,
+		ide_handler_t *handler,
+		ide_pre_handler_t *prehandler,
+		struct request *rq);
 
 /*
  * Special Flagged Register Validation Caller
@@ -871,7 +818,7 @@
  * idedisk_input_data() is a wrapper around ide_input_data() which copes
  * with byte-swapping the input data if required.
  */
-inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
+extern void idedisk_input_data(ide_drive_t *drive, void *buffer, unsigned int wcount);
 
 /*
  * ide_stall_queue() can be used by a drive to give excess bandwidth back
@@ -939,15 +886,14 @@
 void __init ide_scan_pcibus(int scan_direction);
 #endif
 #ifdef CONFIG_BLK_DEV_IDEDMA
-# define BAD_DMA_DRIVE		0
-# define GOOD_DMA_DRIVE		1
 int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func);
 void ide_destroy_dmatable (ide_drive_t *drive);
 ide_startstop_t ide_dma_intr (ide_drive_t *drive);
 int check_drive_lists (ide_drive_t *drive, int good_bad);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-extern void ide_release_dma(ide_hwif_t *hwif);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
+extern void ide_release_dma(struct ata_channel *hwif);
+extern void ide_setup_dma(struct ata_channel *hwif,
+		unsigned long dmabase, unsigned int num_ports) __init;
 #endif
 
 extern spinlock_t ide_lock;
diff -Nru a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/inetdevice.h	Wed Apr  3 17:11:14 2002
@@ -18,6 +18,7 @@
 	int	mc_forwarding;
 	int	tag;
 	int     arp_filter;
+	int	medium_id;
 	void	*sysctl;
 };
 
@@ -48,6 +49,7 @@
 #define IN_DEV_TX_REDIRECTS(in_dev)	(ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
 #define IN_DEV_SEC_REDIRECTS(in_dev)	(ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
 #define IN_DEV_IDTAG(in_dev)		((in_dev)->cnf.tag)
+#define IN_DEV_MEDIUM_ID(in_dev)	((in_dev)->cnf.medium_id)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -Nru a/include/linux/iobuf.h b/include/linux/iobuf.h
--- a/include/linux/iobuf.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/iobuf.h	Wed Apr  3 17:11:14 2002
@@ -80,9 +80,9 @@
 /* fs/buffer.c */
 
 int	brw_kiovec(int rw, int nr, struct kiobuf *iovec[], 
-		   kdev_t dev, sector_t [], int size);
+		   struct block_device *bdev, sector_t [], int size);
 
 /* fs/bio.c */
-void	ll_rw_kio(int rw, struct kiobuf *kio, kdev_t dev, sector_t block);
+void	ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t block);
 
 #endif /* __LINUX_IOBUF_H */
diff -Nru a/include/linux/minix_fs.h b/include/linux/minix_fs.h
--- a/include/linux/minix_fs.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/minix_fs.h	Wed Apr  3 17:11:14 2002
@@ -29,11 +29,6 @@
 #define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
 #define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode)))
 
-#define MINIX_V1		0x0001		/* original minix fs */
-#define MINIX_V2		0x0002		/* minix V2 fs */
-
-#define INODE_VERSION(inode)	minix_sb(inode->i_sb)->s_version
-
 /*
  * This is the original minix inode layout on disk.
  * Note the 8-bit gid and atime and ctime.
@@ -86,62 +81,5 @@
 	__u16 inode;
 	char name[0];
 };
-
-#ifdef __KERNEL__
-
-#include <linux/minix_fs_i.h>
-#include <linux/minix_fs_sb.h>
-
-/*
- * change the define below to 0 if you want names > info->s_namelen chars to be
- * truncated. Else they will be disallowed (ENAMETOOLONG).
- */
-#define NO_TRUNCATE 1
-
-extern struct minix_inode * minix_V1_raw_inode(struct super_block *, ino_t, struct buffer_head **);
-extern struct minix2_inode * minix_V2_raw_inode(struct super_block *, ino_t, struct buffer_head **);
-extern struct inode * minix_new_inode(const struct inode * dir, int * error);
-extern void minix_free_inode(struct inode * inode);
-extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(struct inode * inode);
-extern void minix_free_block(struct inode * inode, int block);
-extern unsigned long minix_count_free_blocks(struct super_block *sb);
-
-extern void V1_minix_truncate(struct inode *);
-extern void V2_minix_truncate(struct inode *);
-extern void minix_truncate(struct inode *);
-extern int minix_sync_inode(struct inode *);
-extern void minix_set_inode(struct inode *, dev_t);
-extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int);
-extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int);
-
-extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**);
-extern int minix_add_link(struct dentry*, struct inode*);
-extern int minix_delete_entry(struct minix_dir_entry*, struct page*);
-extern int minix_make_empty(struct inode*, struct inode*);
-extern int minix_empty_dir(struct inode*);
-extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*);
-extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**);
-extern ino_t minix_inode_by_name(struct dentry*);
-
-extern int minix_sync_file(struct file *, struct dentry *, int);
-
-extern struct inode_operations minix_file_inode_operations;
-extern struct inode_operations minix_dir_inode_operations;
-extern struct file_operations minix_file_operations;
-extern struct file_operations minix_dir_operations;
-extern struct dentry_operations minix_dentry_operations;
-
-static inline struct minix_sb_info *minix_sb(struct super_block *sb)
-{
-	return sb->u.generic_sbp;
-}
-
-static inline struct minix_inode_info *minix_i(struct inode *inode)
-{
-	return list_entry(inode, struct minix_inode_info, vfs_inode);
-}
-
-#endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/linux/minix_fs_i.h b/include/linux/minix_fs_i.h
--- a/include/linux/minix_fs_i.h	Wed Apr  3 17:11:14 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-#ifndef _MINIX_FS_I
-#define _MINIX_FS_I
-
-/*
- * minix fs inode data in memory
- */
-struct minix_inode_info {
-	union {
-		__u16 i1_data[16];
-		__u32 i2_data[16];
-	} u;
-	struct inode vfs_inode;
-};
-
-#endif
diff -Nru a/include/linux/minix_fs_sb.h b/include/linux/minix_fs_sb.h
--- a/include/linux/minix_fs_sb.h	Wed Apr  3 17:11:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-#ifndef _MINIX_FS_SB
-#define _MINIX_FS_SB
-
-/*
- * minix super-block data in memory
- */
-struct minix_sb_info {
-			unsigned long s_ninodes;
-			unsigned long s_nzones;
-			unsigned long s_imap_blocks;
-			unsigned long s_zmap_blocks;
-			unsigned long s_firstdatazone;
-			unsigned long s_log_zone_size;
-			unsigned long s_max_size;
-			int s_dirsize;
-			int s_namelen;
-			int s_link_max;
-			struct buffer_head ** s_imap;
-			struct buffer_head ** s_zmap;
-			struct buffer_head * s_sbh;
-			struct minix_super_block * s_ms;
-			unsigned short s_mount_state;
-			unsigned short s_version;
-};
-
-#endif
diff -Nru a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h
--- a/include/linux/mtd/compatmac.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/mtd/compatmac.h	Wed Apr  3 17:11:14 2002
@@ -190,8 +190,8 @@
 
 #if LINUX_VERSION_CODE < 0x20300
 #include <linux/interrupt.h>
-#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0);
-#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0);
+#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0)
+#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0)
 #else
 #include <asm/softirq.h>
 #include <linux/spinlock.h>
diff -Nru a/include/linux/nbd.h b/include/linux/nbd.h
--- a/include/linux/nbd.h	Wed Apr  3 17:11:16 2002
+++ b/include/linux/nbd.h	Wed Apr  3 17:11:16 2002
@@ -70,7 +70,7 @@
 	struct file * file; 		/* If == NULL, device is not ready, yet	*/
 	int magic;			/* FIXME: not if debugging is off	*/
 	struct list_head queue_head;	/* Requests are added here...			*/
-	struct semaphore queue_lock;
+	struct semaphore tx_lock;
 };
 #endif
 
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Wed Apr  3 17:11:16 2002
+++ b/include/linux/netdevice.h	Wed Apr  3 17:11:16 2002
@@ -246,8 +246,6 @@
 	 *	I/O specific fields
 	 *	FIXME: Merge these and struct ifmap into one
 	 */
-	unsigned long		rmem_end;	/* shmem "recv" end	*/
-	unsigned long		rmem_start;	/* shmem "recv" start	*/
 	unsigned long		mem_end;	/* shared mem end	*/
 	unsigned long		mem_start;	/* shared mem start	*/
 	unsigned long		base_addr;	/* device I/O address	*/
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h	Wed Apr  3 17:11:15 2002
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <asm/atomic.h>
 
 enum ip_conntrack_info
 {
@@ -62,27 +63,58 @@
 #define IP_NF_ASSERT(x)
 #endif
 
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+#include <linux/netfilter_ipv4/ip_nat.h>
+#endif
+
+/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+
 struct ip_conntrack_expect
 {
-	/* Internal linked list */
+	/* Internal linked list (global expectation list) */
 	struct list_head list;
 
+	/* expectation list for this master */
+	struct list_head expected_list;
+
+	/* The conntrack of the master connection */
+	struct ip_conntrack *expectant;
+
+	/* The conntrack of the sibling connection, set after
+	 * expectation arrived */
+	struct ip_conntrack *sibling;
+
+	/* Tuple saved for conntrack */
+	struct ip_conntrack_tuple ct_tuple;
+
+	/* Timer function; deletes the expectation. */
+	struct timer_list timeout;
+
+	/* Data filled out by the conntrack helpers follow: */
+
 	/* We expect this tuple, with the following mask */
 	struct ip_conntrack_tuple tuple, mask;
 
 	/* Function to call after setup and insertion */
 	int (*expectfn)(struct ip_conntrack *new);
 
-	/* The conntrack we are part of (set iff we're live) */
-	struct ip_conntrack *expectant;
-};
-
+	/* At which sequence number did this expectation occur */
+	u_int32_t seq;
+  
+	union {
+		/* insert conntrack helper private data (expect) here */
+		struct ip_ct_ftp_expect exp_ftp_info;
+		struct ip_ct_irc_expect exp_irc_info;
+  
 #ifdef CONFIG_IP_NF_NAT_NEEDED
-#include <linux/netfilter_ipv4/ip_nat.h>
+ 		union {
+			/* insert nat helper private data (expect) here */
+		} nat;
 #endif
-
-#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
-#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+	} help;
+};
 
 struct ip_conntrack
 {
@@ -101,10 +133,13 @@
 
 	/* If we're expecting another related connection, this will be
            in expected linked list */
-	struct ip_conntrack_expect expected;
+	struct list_head sibling_list;
+	
+	/* Current number of expected connections */
+	unsigned int expecting;
 
-	/* If we were expected by another connection, this will be it */
-	struct nf_ct_info master;
+	/* If we were expected by an expectation, this will be it */
+	struct ip_conntrack_expect *master;
 
 	/* Helper, if any. */
 	struct ip_conntrack_helper *helper;
@@ -121,8 +156,9 @@
 	} proto;
 
 	union {
-		struct ip_ct_ftp ct_ftp_info;
-		struct ip_ct_irc ct_irc_info;
+		/* insert conntrack helper private data (master) here */
+		struct ip_ct_ftp_master ct_ftp_info;
+		struct ip_ct_irc_master ct_irc_info;
 	} help;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
@@ -139,6 +175,9 @@
 #endif /* CONFIG_IP_NF_NAT_NEEDED */
 
 };
+
+/* get master conntrack via master expectation */
+#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL)
 
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h	Wed Apr  3 17:11:16 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h	Wed Apr  3 17:11:16 2002
@@ -15,7 +15,7 @@
 extern void ip_conntrack_cleanup(void);
 
 struct ip_conntrack_protocol;
-extern struct ip_conntrack_protocol *find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
 /* Like above, but you already have conntrack read lock. */
 extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_ftp.h	Wed Apr  3 17:11:15 2002
@@ -11,6 +11,8 @@
 /* Protects ftp part of conntracks */
 DECLARE_LOCK_EXTERN(ip_ftp_lock);
 
+#define FTP_PORT	21
+
 enum ip_ct_ftp_type
 {
 	/* PORT command from client */
@@ -23,18 +25,20 @@
 	IP_CT_FTP_EPSV,
 };
 
-/* We record seq number and length of ftp ip/port text here: all in
-   host order. */
-struct ip_ct_ftp
+/* This structure is per expected connection */
+struct ip_ct_ftp_expect
 {
-	/* This tells NAT that this is an ftp connection */
-	int is_ftp;
-	u_int32_t seq;
-	/* 0 means not found yet */
-	u_int32_t len;
-	enum ip_ct_ftp_type ftptype;
-	/* Port that was to be used */
-	u_int16_t port;
+	/* We record seq number and length of ftp ip/port text here: all in
+	 * host order. */
+
+ 	/* sequence number of IP address in packet is in ip_conntrack_expect */
+	u_int32_t len;			/* length of IP address */
+	enum ip_ct_ftp_type ftptype;	/* PORT or PASV ? */
+	u_int16_t port; 		/* TCP port that was to be used */
+};
+
+/* This structure exists only once per master */
+struct ip_ct_ftp_master {
 	/* Next valid seq position for cmd matching after newline */
 	u_int32_t seq_aft_nl[IP_CT_DIR_MAX];
 	/* 0 means seq_match_aft_nl not set */
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_helper.h b/include/linux/netfilter_ipv4/ip_conntrack_helper.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_helper.h	Wed Apr  3 17:11:14 2002
@@ -5,10 +5,19 @@
 
 struct module;
 
+/* Reuse expectation when max_expected reached */
+#define IP_CT_HELPER_F_REUSE_EXPECT	0x01
+
 struct ip_conntrack_helper
 {	
-	/* Internal use. */
-	struct list_head list;
+	struct list_head list; 		/* Internal use. */
+
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	unsigned int max_expected;	/* Maximum number of concurrent 
+					 * expected connections */
+	unsigned int timeout;		/* timeout for expecteds */
 
 	/* Mask of things we will help (compared against server response) */
 	struct ip_conntrack_tuple tuple;
@@ -24,11 +33,13 @@
 extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
 extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
 
-/* Add an expected connection: can only have one per connection */
+extern struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple);
+
+/* Add an expected connection: can have more than one per connection */
 extern int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				       const struct ip_conntrack_tuple *tuple,
-				       const struct ip_conntrack_tuple *mask,
-				       int (*expectfn)(struct ip_conntrack *));
-extern void ip_conntrack_unexpect_related(struct ip_conntrack *related_to);
+				       struct ip_conntrack_expect *exp);
+extern int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+				      struct ip_conntrack_tuple *newtuple);
+extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
 
 #endif /*_IP_CONNTRACK_HELPER_H*/
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_irc.h b/include/linux/netfilter_ipv4/ip_conntrack_irc.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_irc.h	Wed Apr  3 17:11:15 2002
@@ -20,7 +20,7 @@
 
 #include <linux/netfilter_ipv4/lockhelp.h>
 
-#define IP_CONNTR_IRC	2
+#define IRC_PORT	6667
 
 struct dccproto {
 	char* match;
@@ -32,16 +32,18 @@
 
 /* We record seq number and length of irc ip/port text here: all in
    host order. */
-struct ip_ct_irc
+
+/* This structure is per expected connection */
+struct ip_ct_irc_expect
 {
-	/* This tells NAT that this is an IRC connection */
-	int is_irc;
-	/* sequence number where address part of DCC command begins */
-	u_int32_t seq;
-	/* 0 means not found yet */
+	/* length of IP address */
 	u_int32_t len;
 	/* Port that was to be used */
 	u_int16_t port;
+};
+
+/* This structure exists only once per master */
+struct ip_ct_irc_master {
 };
 
 #endif /* _IP_CONNTRACK_IRC_H */
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Wed Apr  3 17:11:16 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_protocol.h	Wed Apr  3 17:11:16 2002
@@ -42,6 +42,13 @@
 	int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,
 		   size_t len);
 
+	/* Called when a conntrack entry is destroyed */
+	void (*destroy)(struct ip_conntrack *conntrack);
+
+	/* Has to decide if a expectation matches one packet or not */
+	int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
diff -Nru a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h
--- a/include/linux/netfilter_ipv4/ip_nat_helper.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/netfilter_ipv4/ip_nat_helper.h	Wed Apr  3 17:11:14 2002
@@ -6,23 +6,37 @@
 
 struct sk_buff;
 
+/* Flags */
+/* NAT helper must be called on every packet (for TCP) */
+#define IP_NAT_HELPER_F_ALWAYS		0x01
+/* Standalone NAT helper, without a conntrack part */
+#define IP_NAT_HELPER_F_STANDALONE	0x02
+
 struct ip_nat_helper
 {
-	/* Internal use */
-	struct list_head list;
+	struct list_head list;		/* Internal use */
 
+	const char *name;		/* name of the module */
+	unsigned char flags;		/* Flags (see above) */
+	struct module *me;		/* pointer to self */
+	
 	/* Mask of things we will help: vs. tuple from server */
 	struct ip_conntrack_tuple tuple;
 	struct ip_conntrack_tuple mask;
 	
 	/* Helper function: returns verdict */
 	unsigned int (*help)(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
 			     struct ip_nat_info *info,
 			     enum ip_conntrack_info ctinfo,
 			     unsigned int hooknum,
 			     struct sk_buff **pskb);
 
-	const char *name;
+	/* Returns verdict and sets up NAT for this connection */
+	unsigned int (*expect)(struct sk_buff **pskb,
+			       unsigned int hooknum,
+			       struct ip_conntrack *ct,
+			       struct ip_nat_info *info);
 };
 
 extern struct list_head helpers;
@@ -39,5 +53,5 @@
 extern int ip_nat_seq_adjust(struct sk_buff *skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph);
+extern void ip_nat_delete_sack(struct sk_buff *skb);
 #endif
diff -Nru a/include/linux/netfilter_ipv4/ip_nat_rule.h b/include/linux/netfilter_ipv4/ip_nat_rule.h
--- a/include/linux/netfilter_ipv4/ip_nat_rule.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/netfilter_ipv4/ip_nat_rule.h	Wed Apr  3 17:11:15 2002
@@ -5,24 +5,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 
 #ifdef __KERNEL__
-/* Want to be told when we first NAT an expected packet for a conntrack? */
-struct ip_nat_expect
-{
-	struct list_head list;
 
-	/* Returns 1 (and sets verdict) if it has setup NAT for this
-           connection */
-	int (*expect)(struct sk_buff **pskb,
-		      unsigned int hooknum,
-		      struct ip_conntrack *ct,
-		      struct ip_nat_info *info,
-		      struct ip_conntrack *master,
-		      struct ip_nat_info *masterinfo,
-		      unsigned int *verdict);
-};
-
-extern int ip_nat_expect_register(struct ip_nat_expect *expect);
-extern void ip_nat_expect_unregister(struct ip_nat_expect *expect);
 extern int ip_nat_rule_init(void) __init;
 extern void ip_nat_rule_cleanup(void);
 extern int ip_nat_rule_find(struct sk_buff **pskb,
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/pci_ids.h	Wed Apr  3 17:11:15 2002
@@ -355,6 +355,7 @@
 
 #define PCI_VENDOR_ID_WD		0x101c
 #define PCI_DEVICE_ID_WD_7197		0x3296
+#define PCI_DEVICE_ID_WD_90C		0xc24a
 
 #define PCI_VENDOR_ID_AMI		0x101e
 #define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
@@ -445,6 +446,7 @@
 #define PCI_DEVICE_ID_NEC_PCX2		0x0046
 #define PCI_DEVICE_ID_NEC_NILE4		0x005a
 #define PCI_DEVICE_ID_NEC_VRC5476       0x009b
+#define PCI_DEVICE_ID_NEC_VRC5477_AC97  0x00a6
 
 #define PCI_VENDOR_ID_FD		0x1036
 #define PCI_DEVICE_ID_FD_36C70		0x0000
@@ -537,10 +539,6 @@
 #define PCI_DEVICE_ID_ELSA_MICROLINK	0x1000
 #define PCI_DEVICE_ID_ELSA_QS3000	0x3000
 
-#define PCI_VENDOR_ID_ELSA		0x1048
-#define PCI_DEVICE_ID_ELSA_MICROLINK	0x1000
-#define PCI_DEVICE_ID_ELSA_QS3000	0x3000
-
 #define PCI_VENDOR_ID_SGS		0x104a
 #define PCI_DEVICE_ID_SGS_2000		0x0008
 #define PCI_DEVICE_ID_SGS_1764		0x0009
@@ -597,6 +595,7 @@
 #define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
 #define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
 #define PCI_DEVICE_ID_MOTOROLA_FALCON	0x4802
+#define PCI_DEVICE_ID_MOTOROLA_HAWK	0x4803
 #define PCI_DEVICE_ID_MOTOROLA_CPX8216	0x4806
 
 #define PCI_VENDOR_ID_PROMISE		0x105a
@@ -608,6 +607,7 @@
 #define PCI_DEVICE_ID_PROMISE_20268R	0x6268
 #define PCI_DEVICE_ID_PROMISE_20269	0x4d69
 #define PCI_DEVICE_ID_PROMISE_20275	0x1275
+#define PCI_DEVICE_ID_PROMISE_20276	0x5275
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
 #define PCI_VENDOR_ID_N9		0x105d
@@ -649,6 +649,12 @@
 #define PCI_DEVICE_ID_APPLE_KL_USB	0x0019
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP	0x0020
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC	0x0021
+#define PCI_DEVICE_ID_APPLE_KEYLARGO	0x0022
+#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP	0x0024
+#define PCI_DEVICE_ID_APPLE_KEYLARGO_P	0x0025
+#define PCI_DEVICE_ID_APPLE_KL_USB_P	0x0026
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P	0x0027
+#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15	0x002d
 #define PCI_DEVICE_ID_APPLE_UNI_N_FW2	0x0030
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073
@@ -860,12 +866,18 @@
 #define PCI_DEVICE_ID_NVIDIA_QUADRO		0x0103
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX	0x0110
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2	0x0111
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO	0x0112
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR	0x0113
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS	0x0150
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2	0x0151
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
+#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
+#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
+#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC		0x0203
 
 #define PCI_VENDOR_ID_IMS		0x10e0
 #define PCI_DEVICE_ID_IMS_8849		0x8849
@@ -1106,6 +1118,11 @@
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95	0x060a
 #define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
 
+#define PCI_VENDOR_ID_TOSHIBA_2		0x102f
+#define PCI_DEVICE_ID_TOSHIBA_TX3927	0x000a
+#define PCI_DEVICE_ID_TOSHIBA_TC35815CF	0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TX4927	0x0180
+
 #define PCI_VENDOR_ID_RICOH		0x1180
 #define PCI_DEVICE_ID_RICOH_RL5C465	0x0465
 #define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
@@ -1118,6 +1135,8 @@
 #define PCI_DEVICE_ID_ARTOP_ATP850UF	0x0005
 #define PCI_DEVICE_ID_ARTOP_ATP860	0x0006
 #define PCI_DEVICE_ID_ARTOP_ATP860R	0x0007
+#define PCI_DEVICE_ID_ARTOP_ATP865	0x0008
+#define PCI_DEVICE_ID_ARTOP_ATP865R	0x0009
 #define PCI_DEVICE_ID_ARTOP_AEC7610	0x8002
 #define PCI_DEVICE_ID_ARTOP_AEC7612UW	0x8010
 #define PCI_DEVICE_ID_ARTOP_AEC7612U	0x8020
@@ -1279,13 +1298,8 @@
 #define PCI_VENDOR_ID_ITE		0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G	0x8172
 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
-
-#define PCI_VENDOR_ID_ITE		0x1283
-#define PCI_DEVICE_ID_ITE_IT8172G	0x8172
-
-#define PCI_VENDOR_ID_ITE			0x1283
 #define PCI_DEVICE_ID_ITE_8872		0x8872
-
+#define PCI_DEVICE_ID_ITE_IT8330G_0	0xe886
 
 /* formerly Platform Tech */
 #define PCI_VENDOR_ID_ESS_OLD		0x1285
@@ -1450,6 +1464,8 @@
 #define PCI_DEVICE_ID_LAVA_DSERIAL	0x0100 /* 2x 16550 */
 #define PCI_DEVICE_ID_LAVA_QUATRO_A	0x0101 /* 2x 16550, half of 4 port */
 #define PCI_DEVICE_ID_LAVA_QUATRO_B	0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_A	0x0180 /* 4x 16550A, half of 8 port */
+#define PCI_DEVICE_ID_LAVA_OCTO_B	0x0181 /* 4x 16550A, half of 8 port */
 #define PCI_DEVICE_ID_LAVA_PORT_PLUS	0x0200 /* 2x 16650 */
 #define PCI_DEVICE_ID_LAVA_QUAD_A	0x0201 /* 2x 16650, half of 4 port */
 #define PCI_DEVICE_ID_LAVA_QUAD_B	0x0202 /* 2x 16650, half of 4 port */
@@ -1639,16 +1655,6 @@
 #define PCI_DEVICE_ID_INTEL_82801BA_2	0x2443
 #define PCI_DEVICE_ID_INTEL_82801BA_3	0x2444
 #define PCI_DEVICE_ID_INTEL_82801BA_4	0x2445
-#define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
-#define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
-#define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
-#define PCI_DEVICE_ID_INTEL_82801CA_4	0x2484
-#define PCI_DEVICE_ID_INTEL_82801CA_5	0x2485
-#define PCI_DEVICE_ID_INTEL_82801CA_6	0x2486
-#define PCI_DEVICE_ID_INTEL_82801CA_7	0x2487
-#define PCI_DEVICE_ID_INTEL_82801CA_10	0x248a
-#define PCI_DEVICE_ID_INTEL_82801CA_11	0x248b
-#define PCI_DEVICE_ID_INTEL_82801CA_12	0x248c
 #define PCI_DEVICE_ID_INTEL_82801BA_5	0x2446
 #define PCI_DEVICE_ID_INTEL_82801BA_6	0x2448
 #define PCI_DEVICE_ID_INTEL_82801BA_7	0x2449
diff -Nru a/include/linux/pnpbios.h b/include/linux/pnpbios.h
--- a/include/linux/pnpbios.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/pnpbios.h	Wed Apr  3 17:11:15 2002
@@ -143,20 +143,21 @@
 extern int  pnpbios_dont_use_current_config;
 extern void *pnpbios_kmalloc(size_t size, int f);
 extern int pnpbios_init (void);
-extern void pnpbios_proc_init (void);
+extern int pnpbios_proc_init (void);
+extern void pnpbios_proc_exit (void);
 
 extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
 extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
 extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
 #if needed
 extern int pnp_bios_get_event (u16 *message);
 extern int pnp_bios_send_message (u16 message);
 extern int pnp_bios_set_stat_res (char *info);
-extern int pnp_bios_get_stat_res (char *info);
 extern int pnp_bios_apm_id_table (char *table, u16 *size);
-extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info (struct escd_info_struc *data);
-extern int pnp_bios_read_escd (char *data, u32 nvram_base);
 extern int pnp_bios_write_escd (char *data, u32 nvram_base);
 #endif
 
diff -Nru a/include/linux/quota.h b/include/linux/quota.h
--- a/include/linux/quota.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/quota.h	Wed Apr  3 17:11:14 2002
@@ -144,7 +144,6 @@
 
 #ifdef __KERNEL__
 
-extern int nr_dquots, nr_free_dquots;
 extern int dquot_root_squash;
 
 #define NR_DQHASH 43            /* Just an arbitrary number */
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/raid/md.h	Wed Apr  3 17:11:14 2002
@@ -18,8 +18,6 @@
 #ifndef _MD_H
 #define _MD_H
 
-#include <linux/mm.h>
-#include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <asm/semaphore.h>
 #include <linux/major.h>
diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
--- a/include/linux/rtnetlink.h	Wed Apr  3 17:11:16 2002
+++ b/include/linux/rtnetlink.h	Wed Apr  3 17:11:16 2002
@@ -589,7 +589,7 @@
 
 #define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0)  { up(&rtnl_sem); \
 printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
-		   } while(0);
+		   } while(0)
 #define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
 
 
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/sched.h	Wed Apr  3 17:11:14 2002
@@ -79,7 +79,6 @@
 extern int last_pid;
 extern unsigned long nr_running(void);
 
-#include <linux/fs.h>
 #include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
diff -Nru a/include/linux/securebits.h b/include/linux/securebits.h
--- a/include/linux/securebits.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/securebits.h	Wed Apr  3 17:11:14 2002
@@ -6,7 +6,7 @@
 extern unsigned securebits;
 
 /* When set UID 0 has no special privileges. When unset, we support
-   inheritance of root-permissions and suid-root executablew under
+   inheritance of root-permissions and suid-root executable under
    compatibility mode. We raise the effective and inheritable bitmasks
    *of the executable file* if the effective uid of the new process is
    0. If the real uid is 0, we raise the inheritable bitmask of the
diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h	Wed Apr  3 17:11:13 2002
+++ b/include/linux/skbuff.h	Wed Apr  3 17:11:13 2002
@@ -16,7 +16,6 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/cache.h>
 
diff -Nru a/include/linux/smb_fs.h b/include/linux/smb_fs.h
--- a/include/linux/smb_fs.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/smb_fs.h	Wed Apr  3 17:11:15 2002
@@ -12,6 +12,7 @@
 #include <linux/smb.h>
 #include <linux/smb_fs_i.h>
 #include <linux/smb_fs_sb.h>
+#include <linux/fs.h>
 
 /*
  * ioctl commands
diff -Nru a/include/linux/sonypi.h b/include/linux/sonypi.h
--- a/include/linux/sonypi.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/sonypi.h	Wed Apr  3 17:11:15 2002
@@ -73,11 +73,28 @@
 #define SONYPI_EVENT_BACK_PRESSED		35
 #define SONYPI_EVENT_LID_CLOSED			36
 #define SONYPI_EVENT_LID_OPENED			37
+#define SONYPI_EVENT_BLUETOOTH_ON		38
+#define SONYPI_EVENT_BLUETOOTH_OFF		39
 
+/* get/set brightness */
+#define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
+#define SONYPI_IOCSBRT		_IOW('v', 0, __u8)
 
-/* brightness etc. ioctls */
-#define SONYPI_IOCGBRT	_IOR('v', 0, __u8)
-#define SONYPI_IOCSBRT	_IOW('v', 0, __u8)
+/* get battery full capacity/remaining capacity */
+#define SONYPI_IOCGBAT1CAP	_IOR('v', 2, __u16)
+#define SONYPI_IOCGBAT1REM	_IOR('v', 3, __u16)
+#define SONYPI_IOCGBAT2CAP	_IOR('v', 4, __u16)
+#define SONYPI_IOCGBAT2REM	_IOR('v', 5, __u16)
+
+/* get battery flags: battery1/battery2/ac adapter present */
+#define SONYPI_BFLAGS_B1	0x01
+#define SONYPI_BFLAGS_B2	0x02
+#define SONYPI_BFLAGS_AC	0x04
+#define SONYPI_IOCGBATFLAGS	_IOR('v', 7, __u8)
+
+/* get/set bluetooth subsystem state on/off */
+#define SONYPI_IOCGBLUE		_IOR('v', 8, __u8)
+#define SONYPI_IOCSBLUE		_IOW('v', 9, __u8)
 
 #ifdef __KERNEL__
 
diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h
--- a/include/linux/spinlock.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/spinlock.h	Wed Apr  3 17:11:15 2002
@@ -204,7 +204,7 @@
 
 #else
 
-#define preempt_get_count()	do { } while (0)
+#define preempt_get_count()	(0)
 #define preempt_disable()	do { } while (0)
 #define preempt_enable_no_resched()	do {} while(0)
 #define preempt_enable()	do { } while (0)
diff -Nru a/include/linux/string.h b/include/linux/string.h
--- a/include/linux/string.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/string.h	Wed Apr  3 17:11:15 2002
@@ -12,9 +12,7 @@
 extern "C" {
 #endif
 
-extern char * ___strtok;
 extern char * strpbrk(const char *,const char *);
-extern char * strtok(char *,const char *);
 extern char * strsep(char **,const char *);
 extern __kernel_size_t strspn(const char *,const char *);
 
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Wed Apr  3 17:11:13 2002
+++ b/include/linux/sysctl.h	Wed Apr  3 17:11:13 2002
@@ -288,7 +288,8 @@
 	NET_TCP_ADV_WIN_SCALE=87,
 	NET_IPV4_NONLOCAL_BIND=88,
 	NET_IPV4_ICMP_RATELIMIT=89,
-	NET_IPV4_ICMP_RATEMASK=90
+	NET_IPV4_ICMP_RATEMASK=90,
+	NET_TCP_TW_REUSE=91
 };
 
 enum {
@@ -333,7 +334,8 @@
 	NET_IPV4_CONF_BOOTP_RELAY=10,
 	NET_IPV4_CONF_LOG_MARTIANS=11,
 	NET_IPV4_CONF_TAG=12,
-	NET_IPV4_CONF_ARPFILTER=13
+	NET_IPV4_CONF_ARPFILTER=13,
+	NET_IPV4_CONF_MEDIUM_ID=14,
 };
 
 /* /proc/sys/net/ipv6 */
diff -Nru a/include/linux/ticable.h b/include/linux/ticable.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/ticable.h	Wed Apr  3 17:11:16 2002
@@ -0,0 +1,42 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar/tiser/tiusb - low level driver for handling link cables
+ * designed for Texas Instruments graphing calculators.
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _TICABLE_H 
+#define _TICABLE_H 1
+
+/* Internal default constants for the kernel module */
+#define TIMAXTIME 15      /* 1.5 seconds       */
+#define IO_DELAY  10      /* 10 micro-seconds  */
+
+/* Major & minor number for character devices */
+#define TIPAR_MAJOR  115 /* 0 to 7 */
+#define TIPAR_MINOR    0
+
+#define TISER_MAJOR  115 /* 8 to 15 */
+#define TISER_MINOR    8
+
+#define TIUSB_MAJOR  115  /* 16 to 31 */
+#define TIUSB_MINOR   16
+
+/*
+ * Request values for the 'ioctl' function.
+ */
+#define IOCTL_TIPAR_DELAY     _IOW('p', 0xa8, int) /* set delay   */
+#define IOCTL_TIPAR_TIMEOUT   _IOW('p', 0xa9, int) /* set timeout */
+
+#define IOCTL_TISER_DELAY     _IOW('p', 0xa0, int) /* set delay   */
+#define IOCTL_TISER_TIMEOUT   _IOW('p', 0xa1, int) /* set timeout */
+
+#define IOCTL_TIUSB_TIMEOUT        _IOW('N', 0x20, int) /* set timeout */
+#define IOCTL_TIUSB_RESET_DEVICE   _IOW('N', 0x21, int) /* reset device */
+#define IOCTL_TIUSB_RESET_PIPES    _IOW('N', 0x22, int) /* reset both pipes*/
+
+#endif /* TICABLE_H */
diff -Nru a/include/linux/udf_fs.h b/include/linux/udf_fs.h
--- a/include/linux/udf_fs.h	Wed Apr  3 17:11:14 2002
+++ b/include/linux/udf_fs.h	Wed Apr  3 17:11:14 2002
@@ -34,6 +34,10 @@
 #ifndef _UDF_FS_H
 #define _UDF_FS_H 1
 
+#include <linux/config.h>
+
+#include <linux/config.h>
+
 #define UDF_PREALLOCATE
 #define UDF_DEFAULT_PREALLOC_BLOCKS	8
 
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/usb.h	Wed Apr  3 17:11:15 2002
@@ -588,7 +588,7 @@
 /**
  * struct urb - USB Request Block
  * @urb_list: For use by current owner of the URB.
- * @next: Used primarily to link ISO requests into rings.
+ * @next: Used to link ISO requests into rings.
  * @pipe: Holds endpoint number, direction, type, and max packet size.
  *	Create these values with the eight macros available;
  *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the type is "ctrl"
@@ -627,8 +627,9 @@
  * @start_frame: Returns the initial frame for interrupt or isochronous
  *	transfers.
  * @number_of_packets: Lists the number of ISO transfer buffers.
- * @interval: Specifies the polling interval for interrupt transfers, in
- *	milliseconds.
+ * @interval: Specifies the polling interval for interrupt or isochronous
+ *	transfers.  The units are frames (milliseconds) for for full and low
+ *	speed devices, and microframes (1/8 millisecond) for highspeed ones.
  * @error_count: Returns the number of ISO transfers that reported errors.
  * @context: For use in completion functions.  This normally points to
  *	request-specific driver context.
@@ -668,12 +669,16 @@
  *
  * Control URBs must provide a setup_packet.
  *
- * Interupt UBS must provide an interval, saying how often (in milliseconds)
+ * Interrupt UBS must provide an interval, saying how often (in milliseconds
+ * or, for highspeed devices, 125 microsecond units)
  * to poll for transfers.  After the URB has been submitted, the interval
  * and start_frame fields reflect how the transfer was actually scheduled.
  * The polling interval may be more frequent than requested.
  * For example, some controllers have a maximum interval of 32 microseconds,
  * while others support intervals of up to 1024 microseconds.
+ * Isochronous URBs also have transfer intervals.  (Note that for isochronous
+ * endpoints, as well as high speed interrupt endpoints, the encoding of
+ * the transfer interval in the endpoint descriptor is logarithmic.)
  *
  * Isochronous URBs normally use the USB_ISO_ASAP transfer flag, telling
  * the host controller to schedule the transfer as soon as bandwidth
@@ -682,8 +687,8 @@
  * and handle the case where the transfer can't begin then.  However, drivers
  * won't know how bandwidth is currently allocated, and while they can
  * find the current frame using usb_get_current_frame_number () they can't
- * know the range for that frame number.  (Common ranges for the frame
- * counter include 256, 512, and 1024 frames.)
+ * know the range for that frame number.  (Ranges for frame counter values
+ * are HC-specific, and can go from 256 to 65536 frames from "now".)
  *
  * Isochronous URBs have a different data transfer model, in part because
  * the quality of service is only "best effort".  Callers provide specially
@@ -734,7 +739,7 @@
 	unsigned char *setup_packet;	/* (in) setup packet (control only) */
 	int start_frame;		/* (modify) start frame (INT/ISO) */
 	int number_of_packets;		/* (in) number of ISO packets */
-	int interval;                   /* (in) polling interval (INT only) */
+	int interval;                   /* (in) transfer interval (INT/ISO) */
 	int error_count;		/* (return) number of ISO errors */
 	int timeout;			/* (in) timeout, in jiffies */
 	void *context;			/* (in) context for completion */
diff -Nru a/include/linux/videodev.h b/include/linux/videodev.h
--- a/include/linux/videodev.h	Wed Apr  3 17:11:15 2002
+++ b/include/linux/videodev.h	Wed Apr  3 17:11:15 2002
@@ -37,8 +37,6 @@
  	 * video_generic_ioctl() does the userspace copying of the
  	 * ioctl arguments */
  	struct file_operations *fops;
- 	int (*kernel_ioctl)(struct inode *inode, struct file *file,
- 			    unsigned int cmd, void *arg);
 	void *priv;		/* Used to be 'private' but that upsets C++ */
 
 	/* for videodev.c intenal usage -- don't touch */
@@ -60,8 +58,10 @@
 
 extern int video_exclusive_open(struct inode *inode, struct file *file);
 extern int video_exclusive_release(struct inode *inode, struct file *file);
-extern int video_generic_ioctl(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg);
+extern int video_usercopy(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg,
+			  int (*func)(struct inode *inode, struct file *file,
+				      unsigned int cmd, void *arg));
 #endif /* __KERNEL__ */
 
 #define VID_TYPE_CAPTURE	1	/* Can capture */
diff -Nru a/include/net/ndisc.h b/include/net/ndisc.h
--- a/include/net/ndisc.h	Wed Apr  3 17:11:16 2002
+++ b/include/net/ndisc.h	Wed Apr  3 17:11:16 2002
@@ -42,11 +42,7 @@
 struct nd_msg {
         struct icmp6hdr	icmph;
         struct in6_addr	target;
-        struct {
-                __u8	opt_type;
-                __u8	opt_len;
-                __u8	link_addr[MAX_ADDR_LEN];
-        } opt;
+	__u8		opt[0];
 };
 
 struct ra_msg {
diff -Nru a/include/net/pkt_sched.h b/include/net/pkt_sched.h
--- a/include/net/pkt_sched.h	Wed Apr  3 17:11:14 2002
+++ b/include/net/pkt_sched.h	Wed Apr  3 17:11:14 2002
@@ -358,8 +358,8 @@
 #define PSCHED_TDIFF(tv1, tv2) (long)((tv1) - (tv2))
 #define PSCHED_TDIFF_SAFE(tv1, tv2, bound, guard) \
 ({ \
-	   long __delta = (tv1) - (tv2); \
-	   if ( __delta > (bound)) {  __delta = (bound); guard; } \
+	   long long __delta = (tv1) - (tv2); \
+	   if ( __delta > (long long)(bound)) {  __delta = (bound); guard; } \
 	   __delta; \
 })
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Wed Apr  3 17:11:14 2002
+++ b/include/net/sock.h	Wed Apr  3 17:11:14 2002
@@ -80,7 +80,7 @@
 do {	spin_lock_init(&((__sk)->lock.slock)); \
 	(__sk)->lock.users = 0; \
 	init_waitqueue_head(&((__sk)->lock.wq)); \
-} while(0);
+} while(0)
 
 struct sock {
 	/* Begin of struct sock/struct tcp_tw_bucket shared layout */
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Wed Apr  3 17:11:14 2002
+++ b/include/net/tcp.h	Wed Apr  3 17:11:14 2002
@@ -78,7 +78,7 @@
  */
 struct tcp_bind_bucket {
 	unsigned short		port;
-	unsigned short		fastreuse;
+	signed short		fastreuse;
 	struct tcp_bind_bucket	*next;
 	struct sock		*owners;
 	struct tcp_bind_bucket	**pprev;
@@ -469,6 +469,7 @@
 extern int sysctl_tcp_rmem[3];
 extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
+extern int sysctl_tcp_tw_reuse;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -507,7 +508,7 @@
 	__u16			rmt_port;
 	__u16			mss;
 	__u8			retrans;
-	__u8			index;
+	__u8			__pad;
 	__u16	snd_wscale : 4, 
 		rcv_wscale : 4, 
 		tstamp_ok : 1,
@@ -577,9 +578,7 @@
 							 struct sk_buff *skb,
 							 struct open_request *req,
 							 struct dst_entry *dst);
-	
-	int			(*hash_connecting)	(struct sock *sk);
-
+    
 	int			(*remember_stamp)	(struct sock *sk);
 
 	__u16			net_header_len;
@@ -781,8 +780,7 @@
 					       struct sockaddr *uaddr,
 					       int addr_len);
 
-extern int			tcp_connect(struct sock *sk,
-					    struct sk_buff *skb);
+extern int			tcp_connect(struct sock *sk);
 
 extern struct sk_buff *		tcp_make_synack(struct sock *sk,
 						struct dst_entry *dst,
@@ -1834,6 +1832,6 @@
 	return 1;
 }
 
-#define TCP_CHECK_TIMER(sk) do { } while (0);
+#define TCP_CHECK_TIMER(sk) do { } while (0)
 
 #endif	/* _TCP_H */
diff -Nru a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c	Wed Apr  3 17:11:15 2002
+++ b/init/do_mounts.c	Wed Apr  3 17:11:15 2002
@@ -826,7 +826,7 @@
 
 	create_dev("/dev/root", ROOT_DEV, NULL);
 	if (mount_initrd) {
-		if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
+		if (initrd_load() && !kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
 			handle_initrd();
 			goto out;
 		}
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Wed Apr  3 17:11:15 2002
+++ b/ipc/sem.c	Wed Apr  3 17:11:15 2002
@@ -62,6 +62,7 @@
 #include <linux/spinlock.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -995,6 +996,8 @@
 	struct sem_array *sma;
 	int nsems, i;
 
+	lock_kernel();
+
 	/* If the current process was sleeping for a semaphore,
 	 * remove it from the queue.
 	 */
@@ -1051,6 +1054,8 @@
 		sem_unlock(semid);
 	}
 	current->semundo = NULL;
+
+	unlock_kernel();
 }
 
 #ifdef CONFIG_PROC_FS
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	Wed Apr  3 17:11:15 2002
+++ b/ipc/shm.c	Wed Apr  3 17:11:15 2002
@@ -674,16 +674,19 @@
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *shmd, *shmdnext;
+	int retval = -EINVAL;
 
 	down_write(&mm->mmap_sem);
 	for (shmd = mm->mmap; shmd; shmd = shmdnext) {
 		shmdnext = shmd->vm_next;
 		if (shmd->vm_ops == &shm_vm_ops
-		    && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr)
+		    && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) {
 			do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start);
+			retval = 0;
+		}
 	}
 	up_write(&mm->mmap_sem);
-	return 0;
+	return retval;
 }
 
 #ifdef CONFIG_PROC_FS
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Wed Apr  3 17:11:14 2002
+++ b/kernel/Makefile	Wed Apr  3 17:11:14 2002
@@ -14,12 +14,13 @@
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
-	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
+	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o context.o futex.o
 
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff -Nru a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c	Wed Apr  3 17:11:15 2002
+++ b/kernel/acct.c	Wed Apr  3 17:11:15 2002
@@ -44,17 +44,11 @@
  */
 
 #include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-
-#ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/acct.h>
-#include <linux/smp_lock.h>
 #include <linux/file.h>
 #include <linux/tty.h>
-
 #include <asm/uaccess.h>
 
 /*
@@ -397,15 +391,3 @@
 		spin_unlock(&acct_globals.lock);
 	return 0;
 }
-
-#else
-/*
- * Dummy system call when BSD process accounting is not configured
- * into the kernel.
- */
-
-asmlinkage long sys_acct(const char * filename)
-{
-	return -ENOSYS;
-}
-#endif
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Wed Apr  3 17:11:14 2002
+++ b/kernel/exit.c	Wed Apr  3 17:11:14 2002
@@ -14,9 +14,7 @@
 #include <linux/personality.h>
 #include <linux/tty.h>
 #include <linux/namespace.h>
-#ifdef CONFIG_BSD_PROCESS_ACCT
 #include <linux/acct.h>
-#endif
 #include <linux/file.h>
 #include <linux/binfmts.h>
 
@@ -492,13 +490,15 @@
 	tsk->flags |= PF_EXITING;
 	del_timer_sync(&tsk->real_timer);
 
+	if (unlikely(preempt_get_count()))
+		printk(KERN_ERR "error: %s[%d] exited with preempt_count %d\n",
+				current->comm, current->pid,
+				preempt_get_count());
+
 fake_volatile:
-#ifdef CONFIG_BSD_PROCESS_ACCT
 	acct_process(code);
-#endif
 	__exit_mm(tsk);
 
-	lock_kernel();
 	sem_exit();
 	__exit_files(tsk);
 	__exit_fs(tsk);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Wed Apr  3 17:11:13 2002
+++ b/kernel/ksyms.c	Wed Apr  3 17:11:13 2002
@@ -107,7 +107,7 @@
 EXPORT_SYMBOL(kfree);
 EXPORT_SYMBOL(vfree);
 EXPORT_SYMBOL(__vmalloc);
-EXPORT_SYMBOL_GPL(vmalloc_to_page);
+EXPORT_SYMBOL(vmalloc_to_page);
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(remap_page_range);
 EXPORT_SYMBOL(max_mapnr);
@@ -537,7 +537,6 @@
 EXPORT_SYMBOL(file_fsync);
 EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
-EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(__get_hash_table);
 EXPORT_SYMBOL(new_inode);
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Wed Apr  3 17:11:14 2002
+++ b/kernel/sys.c	Wed Apr  3 17:11:14 2002
@@ -173,6 +173,18 @@
 	return -ENOSYS;
 }
 
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on sparc64, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
+cond_syscall(sys_nfsservctl)
+cond_syscall(sys_quotactl)
+cond_syscall(sys_acct)
+
 static int proc_sel(struct task_struct *p, int which, int who)
 {
 	if(p->pid)
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Wed Apr  3 17:11:14 2002
+++ b/kernel/sysctl.c	Wed Apr  3 17:11:14 2002
@@ -284,8 +284,6 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
-	 0444, NULL, &proc_dointvec},
 	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
@@ -476,11 +474,11 @@
 }
 
 /**
- * register_sysctl_table - register a sysctl heirarchy
+ * register_sysctl_table - register a sysctl hierarchy
  * @table: the top-level table structure
  * @insert_at_head: whether the entry should be inserted in front or at the end
  *
- * Register a sysctl table heirarchy. @table should be a filled in ctl_table
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
  * array. An entry with a ctl_name of 0 terminates the table. 
  *
  * The members of the &ctl_table structure are used as follows:
@@ -564,7 +562,7 @@
 }
 
 /**
- * unregister_sysctl_table - unregister a sysctl table heirarchy
+ * unregister_sysctl_table - unregister a sysctl table hierarchy
  * @header: the header returned from register_sysctl_table
  *
  * Unregisters the sysctl table and all children. proc entries may not
diff -Nru a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile	Wed Apr  3 17:11:14 2002
+++ b/lib/Makefile	Wed Apr  3 17:11:14 2002
@@ -8,7 +8,7 @@
 
 L_TARGET := lib.a
 
-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o crc32.o rbtree.o
 
 obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
 
diff -Nru a/lib/rbtree.c b/lib/rbtree.c
--- a/lib/rbtree.c	Wed Apr  3 17:11:14 2002
+++ b/lib/rbtree.c	Wed Apr  3 17:11:14 2002
@@ -20,6 +20,7 @@
 */
 
 #include <linux/rbtree.h>
+#include <linux/module.h>
 
 static void __rb_rotate_left(rb_node_t * node, rb_root_t * root)
 {
@@ -125,6 +126,7 @@
 
 	root->rb_node->rb_color = RB_BLACK;
 }
+EXPORT_SYMBOL(rb_insert_color);
 
 static void __rb_erase_color(rb_node_t * node, rb_node_t * parent,
 			     rb_root_t * root)
@@ -291,3 +293,4 @@
 	if (color == RB_BLACK)
 		__rb_erase_color(child, parent, root);
 }
+EXPORT_SYMBOL(rb_erase);
diff -Nru a/lib/string.c b/lib/string.c
--- a/lib/string.c	Wed Apr  3 17:11:14 2002
+++ b/lib/string.c	Wed Apr  3 17:11:14 2002
@@ -13,6 +13,10 @@
  * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
  * -  Added strsep() which will replace strtok() soon (because strsep() is
  *    reentrant and should be faster). Use only strsep() in new code, please.
+ *
+ * * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
+ *                    Matthew Hawkins <matt@mh.dropbear.id.au>
+ * -  Kissed strtok() goodbye
  */
  
 #include <linux/types.h>
@@ -52,8 +56,6 @@
 }
 #endif
 
-char * ___strtok;
-
 #ifndef __HAVE_ARCH_STRCPY
 /**
  * strcpy - Copy a %NUL terminated string
@@ -290,35 +292,6 @@
 }
 #endif
 
-#ifndef __HAVE_ARCH_STRTOK
-/**
- * strtok - Split a string into tokens
- * @s: The string to be searched
- * @ct: The characters to search for
- *
- * WARNING: strtok is deprecated, use strsep instead.
- */
-char * strtok(char * s,const char * ct)
-{
-	char *sbegin, *send;
-
-	sbegin  = s ? s : ___strtok;
-	if (!sbegin) {
-		return NULL;
-	}
-	sbegin += strspn(sbegin,ct);
-	if (*sbegin == '\0') {
-		___strtok = NULL;
-		return( NULL );
-	}
-	send = strpbrk( sbegin, ct);
-	if (send && *send != '\0')
-		*send++ = '\0';
-	___strtok = send;
-	return (sbegin);
-}
-#endif
-
 #ifndef __HAVE_ARCH_STRSEP
 /**
  * strsep - Split a string into tokens
@@ -452,7 +425,7 @@
 int memcmp(const void * cs,const void * ct,size_t count)
 {
 	const unsigned char *su1, *su2;
-	signed char res = 0;
+	int res = 0;
 
 	for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
 		if ((res = *su1 - *su2) != 0)
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Wed Apr  3 17:11:15 2002
+++ b/mm/filemap.c	Wed Apr  3 17:11:15 2002
@@ -742,26 +742,6 @@
 }
 
 /*
- * Knuth recommends primes in approximately golden ratio to the maximum
- * integer representable by a machine word for multiplicative hashing.
- * Chuck Lever verified the effectiveness of this technique:
- * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf
- *
- * These primes are chosen to be bit-sparse, that is operations on
- * them can use shifts and additions instead of multiplications for
- * machines where multiplications are slow.
- */
-#if BITS_PER_LONG == 32
-/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e370001UL
-#elif BITS_PER_LONG == 64
-/*  2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL
-#else
-#error Define GOLDEN_RATIO_PRIME for your wordsize.
-#endif
-
-/*
  * In order to wait for pages to become available there must be
  * waitqueues associated with pages. By using a hash table of
  * waitqueues where the bucket discipline is to maintain all
diff -Nru a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c	Wed Apr  3 17:11:14 2002
+++ b/mm/mempool.c	Wed Apr  3 17:11:14 2002
@@ -34,6 +34,9 @@
 	mempool_t *pool;
 	int i;
 
+	BUG_ON(!alloc_fn);
+	BUG_ON(!free_fn);
+
 	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
 	if (!pool)
 		return NULL;
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Wed Apr  3 17:11:15 2002
+++ b/mm/shmem.c	Wed Apr  3 17:11:15 2002
@@ -1203,10 +1203,9 @@
 {
 	char *this_char, *value, *rest;
 
-	this_char = NULL;
-	if ( options )
-		this_char = strtok(options,",");
-	for ( ; this_char; this_char = strtok(NULL,",")) {
+	while ((this_char = strsep(&options, ",")) != NULL) {
+		if (!*this_char)
+			continue;
 		if ((value = strchr(this_char,'=')) != NULL) {
 			*value++ = 0;
 		} else {
diff -Nru a/net/atm/pppoatm.c b/net/atm/pppoatm.c
--- a/net/atm/pppoatm.c	Wed Apr  3 17:11:14 2002
+++ b/net/atm/pppoatm.c	Wed Apr  3 17:11:14 2002
@@ -363,3 +363,4 @@
 
 MODULE_AUTHOR("Mitchell Blank Jr <mitch@sfgoth.com>");
 MODULE_DESCRIPTION("RFC2364 PPP over ATM/AAL5");
+MODULE_LICENSE("GPL");
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Wed Apr  3 17:11:16 2002
+++ b/net/atm/resources.c	Wed Apr  3 17:11:16 2002
@@ -31,95 +31,107 @@
 struct atm_vcc *nodev_vccs = NULL;
 extern spinlock_t atm_dev_lock;
 
-
-static struct atm_dev *alloc_atm_dev(const char *type)
+/* Caller must hold atm_dev_lock. */
+static struct atm_dev *__alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
 
-	dev = kmalloc(sizeof(*dev),GFP_KERNEL);
-	if (!dev) return NULL;
-	memset(dev,0,sizeof(*dev));
+	dev = kmalloc(sizeof(*dev), GFP_ATOMIC);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
 	dev->next = NULL;
 
-	spin_lock(&atm_dev_lock);
-
 	dev->prev = last_dev;
 
-	if (atm_devs) last_dev->next = dev;
-	else atm_devs = dev;
+	if (atm_devs)
+		last_dev->next = dev;
+	else
+		atm_devs = dev;
 	last_dev = dev;
-	spin_unlock(&atm_dev_lock);
+
 	return dev;
 }
 
-
-static void free_atm_dev(struct atm_dev *dev)
+/* Caller must hold atm_dev_lock. */
+static void __free_atm_dev(struct atm_dev *dev)
 {
-	spin_lock (&atm_dev_lock);
-	
-	if (dev->prev) dev->prev->next = dev->next;
-	else atm_devs = dev->next;
-	if (dev->next) dev->next->prev = dev->prev;
-	else last_dev = dev->prev;
+	if (dev->prev)
+		dev->prev->next = dev->next;
+	else
+		atm_devs = dev->next;
+	if (dev->next)
+		dev->next->prev = dev->prev;
+	else
+		last_dev = dev->prev;
 	kfree(dev);
-	
-	spin_unlock (&atm_dev_lock);
 }
 
-
+/* Caller must hold atm_dev_lock. */
 struct atm_dev *atm_find_dev(int number)
 {
 	struct atm_dev *dev;
 
 	for (dev = atm_devs; dev; dev = dev->next)
-		if (dev->ops && dev->number == number) return dev;
+		if (dev->ops && dev->number == number)
+			return dev;
 	return NULL;
 }
 
 
-struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
-    int number,atm_dev_flags_t *flags)
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+				 int number, atm_dev_flags_t *flags)
 {
 	struct atm_dev *dev;
 
-	dev = alloc_atm_dev(type);
+	spin_lock(&atm_dev_lock);
+
+	dev = __alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
 		    type);
-		return NULL;
+		goto done;
 	}
 	if (number != -1) {
 		if (atm_find_dev(number)) {
-			free_atm_dev(dev);
-			return NULL;
+			__free_atm_dev(dev);
+			dev = NULL;
+			goto done;
 		}
 		dev->number = number;
-	}
-	else {
+	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number)) dev->number++;
+		while (atm_find_dev(dev->number))
+			dev->number++;
 	}
 	dev->vccs = dev->last = NULL;
 	dev->dev_data = NULL;
 	barrier();
 	dev->ops = ops;
-	if (flags) dev->flags = *flags;
-	else memset(&dev->flags,0,sizeof(dev->flags));
-	memset((void *) &dev->stats,0,sizeof(dev->stats));
+	if (flags)
+		dev->flags = *flags;
+	else
+		memset(&dev->flags, 0, sizeof(dev->flags));
+	memset(&dev->stats, 0, sizeof(dev->stats));
+
 #ifdef CONFIG_PROC_FS
-	if (ops->proc_read)
+	if (ops->proc_read) {
 		if (atm_proc_dev_register(dev) < 0) {
 			printk(KERN_ERR "atm_dev_register: "
-			    "atm_proc_dev_register failed for dev %s\n",type);
-			spin_unlock (&atm_dev_lock);		
-			free_atm_dev(dev);
-			return NULL;
+			       "atm_proc_dev_register failed for dev %s\n",
+			       type);
+			__free_atm_dev(dev);
+			dev = NULL;
+			goto done;
 		}
+	}
 #endif
-	spin_unlock (&atm_dev_lock);		
+
+done:
+	spin_unlock(&atm_dev_lock);
 	return dev;
 }
 
@@ -127,19 +139,22 @@
 void atm_dev_deregister(struct atm_dev *dev)
 {
 #ifdef CONFIG_PROC_FS
-	if (dev->ops->proc_read) atm_proc_dev_deregister(dev);
+	if (dev->ops->proc_read)
+		atm_proc_dev_deregister(dev);
 #endif
-	free_atm_dev(dev);
+	spin_lock(&atm_dev_lock);
+	__free_atm_dev(dev);
+	spin_unlock(&atm_dev_lock);
 }
 
-
 void shutdown_atm_dev(struct atm_dev *dev)
 {
 	if (dev->vccs) {
-		set_bit(ATM_DF_CLOSE,&dev->flags);
+		set_bit(ATM_DF_CLOSE, &dev->flags);
 		return;
 	}
-	if (dev->ops->dev_close) dev->ops->dev_close(dev);
+	if (dev->ops->dev_close)
+		dev->ops->dev_close(dev);
 	atm_dev_deregister(dev);
 }
 
@@ -149,16 +164,18 @@
 	struct atm_vcc *vcc;
 
 	sk = sk_alloc(family, GFP_KERNEL, 1, NULL);
-	if (!sk) return NULL;
+	if (!sk)
+		return NULL;
 	vcc = atm_sk(sk) = kmalloc(sizeof(*vcc), GFP_KERNEL);
 	if (!vcc) {
 		sk_free(sk);
 		return NULL;
 	}
-	sock_init_data(NULL,sk);
-	memset(vcc,0,sizeof(*vcc));
+	sock_init_data(NULL, sk);
+	memset(vcc, 0, sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs) nodev_vccs->prev = vcc;
+	if (nodev_vccs)
+		nodev_vccs->prev = vcc;
 	vcc->prev = NULL;
 	vcc->next = nodev_vccs;
 	nodev_vccs = vcc;
@@ -168,11 +185,16 @@
 
 static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
 {
-	if (vcc->prev) vcc->prev->next = vcc->next;
-	else if (vcc->dev) vcc->dev->vccs = vcc->next;
-	    else nodev_vccs = vcc->next;
-	if (vcc->next) vcc->next->prev = vcc->prev;
-	else if (vcc->dev) vcc->dev->last = vcc->prev;
+	if (vcc->prev)
+		vcc->prev->next = vcc->next;
+	else if (vcc->dev)
+		vcc->dev->vccs = vcc->next;
+	else
+		nodev_vccs = vcc->next;
+	if (vcc->next)
+		vcc->next->prev = vcc->prev;
+	else if (vcc->dev)
+		vcc->dev->last = vcc->prev;
 	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
 	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
 		shutdown_atm_dev(vcc->dev);
@@ -185,7 +207,6 @@
 	sk_free(sk);
 }
 
-
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
 	unlink_vcc(vcc,dev);
@@ -193,18 +214,19 @@
 	if (dev) {
 		vcc->next = NULL;
 		vcc->prev = dev->last;
-		if (dev->vccs) dev->last->next = vcc;
-		else dev->vccs = vcc;
+		if (dev->vccs)
+			dev->last->next = vcc;
+		else
+			dev->vccs = vcc;
 		dev->last = vcc;
-	}
-	else {
-		if (nodev_vccs) nodev_vccs->prev = vcc;
+	} else {
+		if (nodev_vccs)
+			nodev_vccs->prev = vcc;
 		vcc->next = nodev_vccs;
 		vcc->prev = NULL;
 		nodev_vccs = vcc;
 	}
 }
-
 
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c	Wed Apr  3 17:11:16 2002
+++ b/net/ax25/af_ax25.c	Wed Apr  3 17:11:16 2002
@@ -1889,6 +1889,7 @@
 
 MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");
+MODULE_LICENSE("GPL");
 
 static void __exit ax25_exit(void)
 {
diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c	Wed Apr  3 17:11:14 2002
+++ b/net/core/neighbour.c	Wed Apr  3 17:11:14 2002
@@ -1239,6 +1239,7 @@
 	read_lock(&neigh_tbl_lock);
 	for (tbl=neigh_tables; tbl; tbl = tbl->next) {
 		int err = 0;
+		int override = 1;
 		struct neighbour *n;
 
 		if (tbl->family != ndm->ndm_family)
@@ -1266,6 +1267,7 @@
 		if (n) {
 			if (nlh->nlmsg_flags&NLM_F_EXCL)
 				err = -EEXIST;
+			override = nlh->nlmsg_flags&NLM_F_REPLACE;
 		} else if (!(nlh->nlmsg_flags&NLM_F_CREATE))
 			err = -ENOENT;
 		else {
@@ -1278,7 +1280,7 @@
 		if (err == 0) {
 			err = neigh_update(n, nda[NDA_LLADDR-1] ? RTA_DATA(nda[NDA_LLADDR-1]) : NULL,
 					   ndm->ndm_state,
-					   nlh->nlmsg_flags&NLM_F_REPLACE, 0);
+					   override, 0);
 		}
 		if (n)
 			neigh_release(n);
diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c	Wed Apr  3 17:11:14 2002
+++ b/net/core/skbuff.c	Wed Apr  3 17:11:14 2002
@@ -748,7 +748,7 @@
 			if (skb_cloned(skb)) {
 				if (!realloc)
 					BUG();
-				if (!pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
 					return -ENOMEM;
 			}
 			if (len <= offset) {
diff -Nru a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c	Wed Apr  3 17:11:16 2002
+++ b/net/core/sock.c	Wed Apr  3 17:11:16 2002
@@ -108,6 +108,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/tcp.h>
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c	Wed Apr  3 17:11:15 2002
+++ b/net/econet/af_econet.c	Wed Apr  3 17:11:15 2002
@@ -1133,3 +1133,5 @@
 
 module_init(econet_proto_init);
 module_exit(econet_proto_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/af_inet.c	Wed Apr  3 17:11:14 2002
@@ -627,7 +627,6 @@
 			int addr_len, int flags)
 {
 	struct sock *sk=sock->sk;
-	struct inet_opt *inet = inet_sk(sk);
 	int err;
 	long timeo;
 
@@ -654,13 +653,6 @@
 		err = -EISCONN;
 		if (sk->state != TCP_CLOSE) 
 			goto out;
-
-		err = -EAGAIN;
-		if (!inet->num) {
-			if (sk->prot->get_port(sk, 0) != 0)
-				goto out;
-			inet->sport = htons(inet->num);
-		}
 
 		err = sk->prot->connect(sk, uaddr, addr_len);
 		if (err < 0)
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/arp.c	Wed Apr  3 17:11:14 2002
@@ -450,6 +450,32 @@
 }
 
 /*
+ * Check if we can use proxy ARP for this path
+ */
+
+static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
+{
+	struct in_device *out_dev;
+	int imi, omi = -1;
+
+	if (!IN_DEV_PROXY_ARP(in_dev))
+		return 0;
+
+	if ((imi = IN_DEV_MEDIUM_ID(in_dev)) == 0)
+		return 1;
+	if (imi == -1)
+		return 0;
+
+	/* place to check for proxy_arp for routes */
+
+	if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+		omi = IN_DEV_MEDIUM_ID(out_dev);
+		in_dev_put(out_dev);
+	}
+	return (omi != imi && omi != -1);
+}
+
+/*
  *	Interface to link layer: send routine and receive handler.
  */
 
@@ -755,7 +781,7 @@
 		} else if (IN_DEV_FORWARD(in_dev)) {
 			if ((rt->rt_flags&RTCF_DNAT) ||
 			    (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
-			     (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
+			     (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
 				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 				if (n)
 					neigh_release(n);
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/devinet.c	Wed Apr  3 17:11:14 2002
@@ -1032,7 +1032,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[14];
+	ctl_table devinet_vars[15];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1065,6 +1065,9 @@
          &proc_dointvec},
 	{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
          &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
+         &proc_dointvec},
+	{NET_IPV4_CONF_MEDIUM_ID, "medium_id",
+         &ipv4_devconf.medium_id, sizeof(int), 0644, NULL,
          &proc_dointvec},
 	{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
          &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
--- a/net/ipv4/fib_frontend.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/fib_frontend.c	Wed Apr  3 17:11:15 2002
@@ -579,6 +579,9 @@
 	switch (event) {
 	case NETDEV_UP:
 		fib_add_ifaddr(ifa);
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+		fib_sync_up(ifa->ifa_dev->dev);
+#endif
 		rt_cache_flush(-1);
 		break;
 	case NETDEV_DOWN:
diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/fib_semantics.c	Wed Apr  3 17:11:14 2002
@@ -56,6 +56,8 @@
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
 
+static spinlock_t fib_multipath_lock = SPIN_LOCK_UNLOCKED;
+
 #define for_nexthops(fi) { int nhsel; const struct fib_nh * nh; \
 for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
 
@@ -869,8 +871,14 @@
 					 nh->nh_scope != scope) {
 					nh->nh_flags |= RTNH_F_DEAD;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
+					spin_lock_bh(&fib_multipath_lock);
 					fi->fib_power -= nh->nh_power;
 					nh->nh_power = 0;
+					spin_unlock_bh(&fib_multipath_lock);
+					if (force && nh->nh_dev) {
+						dev_put(nh->nh_dev);
+						nh->nh_dev = NULL;
+					}
 #endif
 					dead++;
 				}
@@ -906,13 +914,19 @@
 				alive++;
 				continue;
 			}
+			if (nh->nh_dev == NULL && nh->nh_oif == dev->ifindex) {
+				dev_hold(dev);
+				nh->nh_dev = dev;
+			}
 			if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
 				continue;
 			if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
 				continue;
 			alive++;
+			spin_lock_bh(&fib_multipath_lock);
 			nh->nh_power = 0;
 			nh->nh_flags &= ~RTNH_F_DEAD;
+			spin_unlock_bh(&fib_multipath_lock);
 		} endfor_nexthops(fi)
 
 		if (alive > 0) {
@@ -933,6 +947,7 @@
 	struct fib_info *fi = res->fi;
 	int w;
 
+	spin_lock_bh(&fib_multipath_lock);
 	if (fi->fib_power <= 0) {
 		int power = 0;
 		change_nexthops(fi) {
@@ -942,12 +957,12 @@
 			}
 		} endfor_nexthops(fi);
 		fi->fib_power = power;
-#if 1
 		if (power <= 0) {
-			printk(KERN_CRIT "impossible 777\n");
+			spin_unlock_bh(&fib_multipath_lock);
+			/* Race condition: route has just become dead. */
+			res->nh_sel = 0;
 			return;
 		}
-#endif
 	}
 
 
@@ -963,15 +978,15 @@
 				nh->nh_power--;
 				fi->fib_power--;
 				res->nh_sel = nhsel;
+				spin_unlock_bh(&fib_multipath_lock);
 				return;
 			}
 		}
 	} endfor_nexthops(fi);
 
-#if 1
-	printk(KERN_CRIT "impossible 888\n");
-#endif
-	return;
+	/* Race condition: route has just become dead. */
+	res->nh_sel = 0;
+	spin_unlock_bh(&fib_multipath_lock);
 }
 #endif
 
diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/icmp.c	Wed Apr  3 17:11:15 2002
@@ -139,6 +139,8 @@
   { EHOSTUNREACH,	1 }	/*	ICMP_PREC_CUTOFF	*/
 };
 
+extern int sysctl_ip_default_ttl;
+
 /* Control parameters for ECHO replies. */
 int sysctl_icmp_echo_ignore_all;
 int sysctl_icmp_echo_ignore_broadcasts;
@@ -354,6 +356,7 @@
 	icmp_out_count(icmp_param->data.icmph.type);
 
 	inet->tos = skb->nh.iph->tos;
+	inet->ttl = sysctl_ip_default_ttl;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
 	if (icmp_param->replyopts.optlen) {
@@ -498,6 +501,7 @@
 	icmp_param.offset=skb_in->nh.raw - skb_in->data;
 	icmp_out_count(icmp_param.data.icmph.type);
 	inet_sk(icmp_socket->sk)->tos = tos;
+	inet_sk(icmp_socket->sk)->ttl = sysctl_ip_default_ttl;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
 	if (icmp_param.replyopts.srr) {
@@ -876,7 +880,7 @@
  
 int icmp_rcv(struct sk_buff *skb)
 {
-	struct icmphdr *icmph = skb->h.icmph;
+	struct icmphdr *icmph;
 	struct rtable *rt = (struct rtable*)skb->dst;
 
 	ICMP_INC_STATS_BH(IcmpInMsgs);
@@ -894,6 +898,8 @@
 
 	if (!pskb_pull(skb, sizeof(struct icmphdr)))
 		goto error;
+
+	icmph = skb->h.icmph;
 
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/ip_gre.c	Wed Apr  3 17:11:16 2002
@@ -760,7 +760,10 @@
 	}
 
 	df = tiph->frag_off;
-	mtu = rt->u.dst.pmtu - tunnel->hlen;
+	if (df)
+		mtu = rt->u.dst.pmtu - tunnel->hlen;
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
 
 	if (skb->protocol == __constant_htons(ETH_P_IP)) {
 		if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68)
diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/ip_input.c	Wed Apr  3 17:11:14 2002
@@ -224,8 +224,6 @@
 	nf_debug_ip_local_deliver(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
-	if (!pskb_may_pull(skb, ihl))
-		goto out;
 	__skb_pull(skb, ihl);
 
 #ifdef CONFIG_NETFILTER
@@ -279,7 +277,6 @@
 			sock_put(raw_sk);
 		} else if (!flag) {		/* Free and report errors */
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);	
-out:
 			kfree_skb(skb);
 		}
 	}
@@ -346,7 +343,6 @@
 			goto drop;
 		iph = skb->nh.iph;
 
-		skb->ip_summed = 0;
 		if (ip_options_compile(NULL, skb))
 			goto inhdr_error;
 
diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/ipip.c	Wed Apr  3 17:11:15 2002
@@ -572,7 +572,11 @@
 		goto tx_error;
 	}
 
-	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	if (tiph->frag_off)
+		mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
 		ip_rt_put(rt);
diff -Nru a/net/ipv4/netfilter/Config.help b/net/ipv4/netfilter/Config.help
--- a/net/ipv4/netfilter/Config.help	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/netfilter/Config.help	Wed Apr  3 17:11:16 2002
@@ -160,6 +160,17 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+CONFIG_IP_NF_NAT_LOCAL
+  This option enables support for NAT of locally originated connections. 
+  Enable this if you need to use destination NAT on connections
+  originating from local processes on the nat box itself.
+
+  Please note that you will need a recent version (>= 1.2.6a)
+  of the iptables userspace program in order to use this feature.
+  See http://www.iptables.org/ for download instructions.
+
+  If unsure, say 'N'.
+
 CONFIG_IP_NF_TARGET_MASQUERADE
   Masquerading is a special case of NAT: all outgoing connections are
   changed to seem to come from a particular interface's address, and
diff -Nru a/net/ipv4/netfilter/Config.in b/net/ipv4/netfilter/Config.in
--- a/net/ipv4/netfilter/Config.in	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/Config.in	Wed Apr  3 17:11:15 2002
@@ -47,7 +47,7 @@
       define_bool CONFIG_IP_NF_NAT_NEEDED y
       dep_tristate '    MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
       dep_tristate '    REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
-      bool '    NAT of local connections' CONFIG_IP_NF_NAT_LOCAL
+      bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
       fi
diff -Nru a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
--- a/net/ipv4/netfilter/Makefile	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/Makefile	Wed Apr  3 17:11:14 2002
@@ -9,18 +9,18 @@
 
 O_TARGET := netfilter.o
 
-export-objs = ip_conntrack_standalone.o ip_conntrack_ftp.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
+export-objs = ip_conntrack_standalone.o ip_fw_compat.o ip_nat_standalone.o ip_tables.o arp_tables.o
 
 # Multipart objects.
 list-multi		:= ip_conntrack.o iptable_nat.o ipfwadm.o ipchains.o
 
 # objects for the conntrack and NAT core (used by standalone and backw. compat)
 ip_nf_conntrack-objs	:= ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
-ip_nf_nat-objs		:= ip_nat_core.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
+ip_nf_nat-objs		:= ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
 
 # objects for the standalone - connection tracking / NAT
 ip_conntrack-objs	:= ip_conntrack_standalone.o $(ip_nf_conntrack-objs)
-iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o ip_nat_helper.o $(ip_nf_nat-objs)
+iptable_nat-objs	:= ip_nat_standalone.o ip_nat_rule.o $(ip_nf_nat-objs)
 
 # objects for backwards compatibility mode
 ip_nf_compat-objs	:= ip_fw_compat.o ip_fw_compat_redir.o ip_fw_compat_masq.o $(ip_nf_conntrack-objs) $(ip_nf_nat-objs)
@@ -33,7 +33,14 @@
 
 # connection tracking helpers
 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ifdef CONFIG_IP_NF_NAT_FTP
+	export-objs += ip_conntrack_ftp.o
+endif
+
 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ifdef CONFIG_IP_NF_NAT_IRC
+	export-objs += ip_conntrack_irc.o
+endif
 
 # NAT helpers 
 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv4/netfilter/ip_conntrack_core.c	Wed Apr  3 17:11:13 2002
@@ -3,7 +3,12 @@
    extension. */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence. 
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * */
 
 #ifdef MODULE
 #define __NO_VERSION__
@@ -38,6 +43,8 @@
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
+#define IP_CONNTRACK_VERSION	"2.0"
+
 #if 0
 #define DEBUGP printk
 #else
@@ -45,6 +52,7 @@
 #endif
 
 DECLARE_RWLOCK(ip_conntrack_lock);
+DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
 
 void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
 LIST_HEAD(expect_list);
@@ -77,7 +85,7 @@
 	return p;
 }
 
-struct ip_conntrack_protocol *find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
 {
 	struct ip_conntrack_protocol *p;
 
@@ -151,9 +159,58 @@
 	return protocol->invert_tuple(inverse, orig);
 }
 
+/* remove one specific expectation from all lists and free it */
+static void unexpect_related(struct ip_conntrack_expect *expect)
+{
+	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
+	DEBUGP("unexpect_related(%p)\n", expect);
+	/* delete from global and local lists */
+	list_del(&expect->list);
+	list_del(&expect->expected_list);
+	if (!expect->sibling)
+		expect->expectant->expecting--;
+	kfree(expect);
+}
+
+/* delete all expectations for this conntrack */
+static void destroy_expectations(struct ip_conntrack *ct)
+{
+	struct list_head *exp_entry, *next;
+	struct ip_conntrack_expect *exp;
+
+	DEBUGP("destroy_expectations(%p)\n", ct);
+
+	for (exp_entry = ct->sibling_list.next;
+	     exp_entry != &ct->sibling_list; exp_entry = next) {
+		next = exp_entry->next;
+		exp = list_entry(exp_entry, struct ip_conntrack_expect,
+				 expected_list);
+
+		/* we skip established expectations, as we want to delete
+		 * the un-established ones only */
+		if (exp->sibling) {
+			DEBUGP("destroy_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			continue;
+		}
+
+		IP_NF_ASSERT(list_inlist(&expect_list, exp));
+		IP_NF_ASSERT(exp->expectant == ct);
+
+		if (exp->expectant->helper->timeout
+		    && ! del_timer(&exp->timeout)) {
+		    	DEBUGP("destroy_expectations: skipping dying expectation %p of %p\n", exp, ct);
+		    	continue;
+		}
+		
+		/* delete expectation from global and private lists */
+		unexpect_related(exp);
+	}
+}
+
 static void
 clean_from_lists(struct ip_conntrack *ct)
 {
+	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
 	/* Remove from both hash lists: must not NULL out next ptrs,
            otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
@@ -164,27 +221,45 @@
 	LIST_DELETE(&ip_conntrack_hash
 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)],
 		    &ct->tuplehash[IP_CT_DIR_REPLY]);
-	/* If our expected is in the list, take it out. */
-	if (ct->expected.expectant) {
-		IP_NF_ASSERT(list_inlist(&expect_list, &ct->expected));
-		IP_NF_ASSERT(ct->expected.expectant == ct);
-		LIST_DELETE(&expect_list, &ct->expected);
-	}
+
+	/* Destroy all un-established, pending expectations */
+	destroy_expectations(ct);
 }
 
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
 	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+	struct ip_conntrack_protocol *proto;
 
+	DEBUGP("destroy_conntrack(%p)\n", ct);
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
-	if (ct->master.master)
-		nf_conntrack_put(&ct->master);
+	if (ct->master && master_ct(ct))
+		ip_conntrack_put(master_ct(ct));
+
+	/* To make sure we don't get any weird locking issues here:
+	 * destroy_conntrack() MUST NOT be called with a write lock
+	 * to ip_conntrack_lock!!! -HW */
+	proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
+	if (proto && proto->destroy)
+		proto->destroy(ct);
 
 	if (ip_conntrack_destroyed)
 		ip_conntrack_destroyed(ct);
+
+	WRITE_LOCK(&ip_conntrack_lock);
+	/* Delete our master expectation from the local list
+	 * and destroy it, if we've been expected */
+	if (ct->master) {
+		list_del(&ct->master->expected_list);
+		kfree(ct->master);
+	}
+	WRITE_UNLOCK(&ip_conntrack_lock);
+
+	
+	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
 }
@@ -382,7 +457,7 @@
 		return NULL;
 	}
 
-	innerproto = find_proto(inner->protocol);
+	innerproto = ip_ct_find_proto(inner->protocol);
 	/* Are they talking about one of our connections? */
 	if (inner->ihl * 4 + 8 > datalen
 	    || !get_tuple(inner, datalen, &origtuple, innerproto)) {
@@ -462,10 +537,18 @@
 	return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
 }
 
+struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
+{
+	return LIST_FIND(&helpers, helper_cmp,
+			 struct ip_conntrack_helper *,
+			 tuple);
+}
+
 /* Compare parts depending on mask. */
 static inline int expect_cmp(const struct ip_conntrack_expect *i,
 			     const struct ip_conntrack_tuple *tuple)
 {
+	MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
 	return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
 }
 
@@ -514,7 +597,7 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
-	memset(conntrack, 0, sizeof(struct ip_conntrack));
+	memset(conntrack, 0, sizeof(*conntrack));
 	atomic_set(&conntrack->ct_general.use, 1);
 	conntrack->ct_general.destroy = destroy_conntrack;
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
@@ -533,31 +616,44 @@
 	conntrack->timeout.data = (unsigned long)conntrack;
 	conntrack->timeout.function = death_by_timeout;
 
+	INIT_LIST_HEAD(&conntrack->sibling_list);
+
 	/* Mark clearly that it's not in the hash table. */
 	conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list.next = NULL;
 
-	/* Write lock required for deletion of expected.  Without
-           this, a read-lock would do. */
 	WRITE_LOCK(&ip_conntrack_lock);
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      &repl_tuple);
 	/* Need finding and deleting of expected ONLY if we win race */
+	READ_LOCK(&ip_conntrack_expect_tuple_lock);
 	expected = LIST_FIND(&expect_list, expect_cmp,
 			     struct ip_conntrack_expect *, tuple);
+	READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
+
+	/* Look up the conntrack helper for master connections only */
+	if (!expected)
+		conntrack->helper = ip_ct_find_helper(&repl_tuple);
+
+	/* If the expectation is dying, then this is a looser. */
+	if (expected
+	    && expected->expectant->helper->timeout
+	    && ! del_timer(&expected->timeout))
+		expected = NULL;
+
 	/* If master is not in hash table yet (ie. packet hasn't left
 	   this machine yet), how can other end know about expected?
 	   Hence these are not the droids you are looking for (if
 	   master ct never got confirmed, we'd hold a reference to it
 	   and weird things would happen to future packets). */
 	if (expected && is_confirmed(expected->expectant)) {
+		DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
+			conntrack, expected);
 		/* Welcome, Mr. Bond.  We've been expecting you... */
+		IP_NF_ASSERT(master_ct(conntrack));
 		conntrack->status = IPS_EXPECTED;
-		conntrack->master.master = &expected->expectant->ct_general;
-		IP_NF_ASSERT(conntrack->master.master);
+		conntrack->master = expected;
+		expected->sibling = conntrack;
 		LIST_DELETE(&expect_list, expected);
-		expected->expectant = NULL;
-		nf_conntrack_get(&conntrack->master);
+		expected->expectant->expecting--;
+		nf_conntrack_get(&master_ct(conntrack)->infos[0]);
 	}
 	atomic_inc(&ip_conntrack_count);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -662,7 +758,7 @@
 			return NF_STOLEN;
 	}
 
-	proto = find_proto((*pskb)->nh.iph->protocol);
+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
 
 	/* It may be an icmp error... */
 	if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
@@ -706,66 +802,210 @@
 int invert_tuplepr(struct ip_conntrack_tuple *inverse,
 		   const struct ip_conntrack_tuple *orig)
 {
-	return invert_tuple(inverse, orig, find_proto(orig->dst.protonum));
+	return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
 }
 
-static void unexpect_related(struct ip_conntrack *related_to)
-{
-	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	list_del(&related_to->expected.list);
-	related_to->expected.expectant = NULL;
+static inline int resent_expect(const struct ip_conntrack_expect *i,
+			        const struct ip_conntrack_tuple *tuple,
+			        const struct ip_conntrack_tuple *mask)
+{
+	DEBUGP("resent_expect\n");
+	DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
+	DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
+	DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
+	return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
+	         || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
+		&& ip_ct_tuple_equal(&i->mask, mask));
 }
 
 /* Would two expected things clash? */
 static inline int expect_clash(const struct ip_conntrack_expect *i,
-			       const struct ip_conntrack_expect *new)
+			       const struct ip_conntrack_tuple *tuple,
+			       const struct ip_conntrack_tuple *mask)
 {
 	/* Part covered by intersection of masks must be unequal,
            otherwise they clash */
 	struct ip_conntrack_tuple intersect_mask
-		= { { i->mask.src.ip & new->mask.src.ip,
-		      { i->mask.src.u.all & new->mask.src.u.all } },
-		    { i->mask.dst.ip & new->mask.dst.ip,
-		      { i->mask.dst.u.all & new->mask.dst.u.all },
-		      i->mask.dst.protonum & new->mask.dst.protonum } };
+		= { { i->mask.src.ip & mask->src.ip,
+		      { i->mask.src.u.all & mask->src.u.all } },
+		    { i->mask.dst.ip & mask->dst.ip,
+		      { i->mask.dst.u.all & mask->dst.u.all },
+		      i->mask.dst.protonum & mask->dst.protonum } };
+
+	return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
+}
+
+void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
+{
+	WRITE_LOCK(&ip_conntrack_lock);
+	unexpect_related(expect);
+	WRITE_UNLOCK(&ip_conntrack_lock);
+}
+	
+static void expectation_timed_out(unsigned long ul_expect)
+{
+	struct ip_conntrack_expect *expect = (void *) ul_expect;
 
-	return ip_ct_tuple_mask_cmp(&i->tuple, &new->tuple, &intersect_mask);
+	DEBUGP("expectation %p timed out\n", expect);	
+	ip_conntrack_unexpect_related(expect);
 }
 
 /* Add a related connection. */
 int ip_conntrack_expect_related(struct ip_conntrack *related_to,
-				const struct ip_conntrack_tuple *tuple,
-				const struct ip_conntrack_tuple *mask,
-				int (*expectfn)(struct ip_conntrack *))
+				struct ip_conntrack_expect *expect)
 {
-	WRITE_LOCK(&ip_conntrack_lock);
-	if (related_to->expected.expectant)
-		unexpect_related(related_to);
+	struct ip_conntrack_expect *new;
+	int ret = 0;
 
-	related_to->expected.tuple = *tuple;
-	related_to->expected.mask = *mask;
-	related_to->expected.expectfn = expectfn;
+	WRITE_LOCK(&ip_conntrack_lock);
+	/* Because of the write lock, no reader can walk the lists,
+	 * so there is no need to use the tuple lock too */
 
-	if (LIST_FIND(&expect_list, expect_clash,
-		      struct ip_conntrack_expect *, &related_to->expected)) {
+	DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+	DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
+
+	new = LIST_FIND(&expect_list, resent_expect,
+		        struct ip_conntrack_expect *, &expect->tuple, &expect->mask);
+	if (new) {
+		/* Helper private data may contain offsets but no pointers
+		   pointing into the payload - otherwise we should have to copy 
+		   the data filled out by the helper over the old one */
+		DEBUGP("expect_related: resent packet\n");
+		if (related_to->helper->timeout) {
+			/* Refresh timer, if possible... */
+			if (del_timer(&new->timeout)) {
+				new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
+				add_timer(&new->timeout);
+				WRITE_UNLOCK(&ip_conntrack_lock);
+				return -EEXIST;
+			}
+			/* ... otherwise expectation is dying. Fall over and create a new one. */
+			new = NULL;
+		} else {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EEXIST;
+		}
+	} else if (related_to->helper->max_expected
+	    	   && related_to->expecting >= related_to->helper->max_expected) {
+	    	if (net_ratelimit())
+		    	printk(KERN_WARNING 
+		    	       "ip_conntrack: max number of expected connections %i of %s reached for %u.%u.%u.%u->%u.%u.%u.%u%s\n",
+		    	       related_to->helper->max_expected, 
+		    	       related_to->helper->name,
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
+		    	       NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip),
+		    	       related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT ?
+		    	       ", reusing" : "");
+	    	if (related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT) {
+		    	struct list_head *cur_item;
+
+		    	/* Let's choose the the oldest expectation to overwrite */
+			list_for_each(cur_item, &related_to->sibling_list) { 
+				new = list_entry(cur_item, struct ip_conntrack_expect,
+						 expected_list);
+				if (new->sibling == NULL)
+					break;
+			}
+			IP_NF_ASSERT(new);
+			if (related_to->helper->timeout 
+			    &&  !del_timer(&new->timeout)) {
+				/* Expectation is dying. Fall over and create a new one */
+				new = NULL;
+			} else {
+				list_del(&new->list);
+				list_del(&new->expected_list);
+				related_to->expecting--;
+				ret = -EPERM;
+			}
+		} else {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			return -EPERM;
+		}
+	} else if (LIST_FIND(&expect_list, expect_clash,
+		      struct ip_conntrack_expect *, &expect->tuple, &expect->mask)) {
 		WRITE_UNLOCK(&ip_conntrack_lock);
+		DEBUGP("expect_related: busy!\n");
 		return -EBUSY;
 	}
+	
+	if (!new) {
+		new = (struct ip_conntrack_expect *) 
+		      kmalloc(sizeof(*expect), GFP_ATOMIC);
+		if (!new) {
+			WRITE_UNLOCK(&ip_conntrack_lock);
+			DEBUGP("expect_relaed: OOM allocating expect\n");
+			return -ENOMEM;
+		}
+	}
+	
+	/* Zero out the new structure, then fill out it with the data */
+	DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
+	memset(new, 0, sizeof(*expect));
+	INIT_LIST_HEAD(&new->list);
+	INIT_LIST_HEAD(&new->expected_list);
+	memcpy(new, expect, sizeof(*expect));
+	new->expectant = related_to;
+	new->sibling = NULL;
+	
+	/* add to expected list for this connection */	
+	list_add(&new->expected_list, &related_to->sibling_list);
+	/* add to global list of expectations */
+	list_prepend(&expect_list, &new->list);
+	/* add and start timer if required */
+	if (related_to->helper->timeout) {
+		init_timer(&new->timeout);
+		new->timeout.data = (unsigned long)new;
+		new->timeout.function = expectation_timed_out;
+		new->timeout.expires = jiffies + related_to->helper->timeout * HZ;
+		add_timer(&new->timeout);
+	}
+	related_to->expecting++;
 
-	list_prepend(&expect_list, &related_to->expected);
-	related_to->expected.expectant = related_to;
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
-	return 0;
+	return ret;
 }
 
-void ip_conntrack_unexpect_related(struct ip_conntrack *related_to)
+/* Change tuple in an existing expectation */
+int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
+			       struct ip_conntrack_tuple *newtuple)
 {
-	WRITE_LOCK(&ip_conntrack_lock);
-	unexpect_related(related_to);
-	WRITE_UNLOCK(&ip_conntrack_lock);
-}
+	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+
+	DEBUGP("change_expect:\n");
+	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+	DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
+	DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
+	if (expect->ct_tuple.dst.protonum == 0) {
+		/* Never seen before */
+		DEBUGP("change expect: never seen before\n");
+		if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
+		    && LIST_FIND(&expect_list, expect_clash,
+			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+			/* Force NAT to find an unused tuple */
+			return -1;
+		} else {
+			WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+			memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
+			memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
+			WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
+			return 0;
+		}
+	} else {
+		/* Resent packet */
+		DEBUGP("change expect: resent packet\n");
+		if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
+			return 0;
+		} else {
+			/* Force NAT to choose again the same port */
+			return -1;
+		}
+	}
 	
+	return -1;
+}
+
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
    return 0 and don't do alteration. */
 int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
@@ -783,10 +1023,12 @@
 	DUMP_TUPLE(newreply);
 
 	conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
-	conntrack->helper = LIST_FIND(&helpers, helper_cmp,
-				      struct ip_conntrack_helper *,
-				      newreply);
+	if (!conntrack->master)
+		conntrack->helper = LIST_FIND(&helpers, helper_cmp,
+					      struct ip_conntrack_helper *,
+					      newreply);
 	WRITE_UNLOCK(&ip_conntrack_lock);
+
 	return 1;
 }
 
@@ -805,14 +1047,10 @@
 			 const struct ip_conntrack_helper *me)
 {
 	if (i->ctrack->helper == me) {
-		i->ctrack->helper = NULL;
 		/* Get rid of any expected. */
-		if (i->ctrack->expected.expectant) {
-			IP_NF_ASSERT(i->ctrack->expected.expectant
-				     == i->ctrack);
-			LIST_DELETE(&expect_list, &i->ctrack->expected);
-			i->ctrack->expected.expectant = NULL;
-		}
+		destroy_expectations(i->ctrack);
+		/* And *then* set helper to NULL */
+		i->ctrack->helper = NULL;
 	}
 	return 0;
 }
@@ -1096,8 +1334,10 @@
 	}
 	ip_conntrack_max = 8 * ip_conntrack_htable_size;
 
-	printk("ip_conntrack (%u buckets, %d max)\n",
-	       ip_conntrack_htable_size, ip_conntrack_max);
+	printk("ip_conntrack version %s (%u buckets, %d max)"
+	       " - %d bytes per conntrack\n", IP_CONNTRACK_VERSION,
+	       ip_conntrack_htable_size, ip_conntrack_max,
+	       sizeof(struct ip_conntrack));
 
 	ret = nf_register_sockopt(&so_getorigdst);
 	if (ret != 0)
diff -Nru a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c	Wed Apr  3 17:11:16 2002
@@ -1,4 +1,5 @@
 /* FTP extension for IP connection tracking. */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -242,8 +243,10 @@
 	u_int32_t array[6] = { 0 };
 	int dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff;
-	struct ip_conntrack_tuple t, mask;
-	struct ip_ct_ftp *info = &ct->help.ct_ftp_info;
+	struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_ftp_expect *exp_ftp_info = &exp->help.exp_ftp_info;
+
 	unsigned int i;
 	int found = 0;
 
@@ -271,8 +274,8 @@
 	}
 
 	LOCK_BH(&ip_ftp_lock);
-	old_seq_aft_nl_set = info->seq_aft_nl_set[dir];
-	old_seq_aft_nl = info->seq_aft_nl[dir];
+	old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
+	old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
 
 	DEBUGP("conntrack_ftp: datalen %u\n", datalen);
 	if ((datalen > 0) && (data[datalen-1] == '\n')) {
@@ -281,8 +284,9 @@
 		    || after(ntohl(tcph->seq) + datalen, old_seq_aft_nl)) {
 			DEBUGP("conntrack_ftp: updating nl to %u\n",
 			       ntohl(tcph->seq) + datalen);
-			info->seq_aft_nl[dir] = ntohl(tcph->seq) + datalen;
-			info->seq_aft_nl_set[dir] = 1;
+			ct_ftp_info->seq_aft_nl[dir] = 
+						ntohl(tcph->seq) + datalen;
+			ct_ftp_info->seq_aft_nl_set[dir] = 1;
 		}
 	}
 	UNLOCK_BH(&ip_ftp_lock);
@@ -330,16 +334,17 @@
 	DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
 	       (int)matchlen, data + matchoff,
 	       matchlen, ntohl(tcph->seq) + matchoff);
+	       
+	memset(&expect, 0, sizeof(expect));
 
 	/* Update the ftp info */
 	LOCK_BH(&ip_ftp_lock);
 	if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
 	    == ct->tuplehash[dir].tuple.src.ip) {
-		info->is_ftp = 21;
-		info->seq = ntohl(tcph->seq) + matchoff;
-		info->len = matchlen;
-		info->ftptype = search[i].ftptype;
-		info->port = array[4] << 8 | array[5];
+		exp->seq = ntohl(tcph->seq) + matchoff;
+		exp_ftp_info->len = matchlen;
+		exp_ftp_info->ftptype = search[i].ftptype;
+		exp_ftp_info->port = array[4] << 8 | array[5];
 	} else {
 		/* Enrico Scholz's passive FTP to partially RNAT'd ftp
 		   server: it really wants us to connect to a
@@ -356,18 +361,21 @@
 		if (!loose) goto out;
 	}
 
-	t = ((struct ip_conntrack_tuple)
+	exp->tuple = ((struct ip_conntrack_tuple)
 		{ { ct->tuplehash[!dir].tuple.src.ip,
 		    { 0 } },
 		  { htonl((array[0] << 24) | (array[1] << 16)
 			  | (array[2] << 8) | array[3]),
 		    { htons(array[4] << 8 | array[5]) },
 		    IPPROTO_TCP }});
-	mask = ((struct ip_conntrack_tuple)
+	exp->mask = ((struct ip_conntrack_tuple)
 		{ { 0xFFFFFFFF, { 0 } },
 		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+	exp->expectfn = NULL;
+
 	/* Ignore failure; should only happen with NAT */
-	ip_conntrack_expect_related(ct, &t, &mask, NULL);
+	ip_conntrack_expect_related(ct, &expect);
  out:
 	UNLOCK_BH(&ip_ftp_lock);
 
@@ -375,6 +383,7 @@
 }
 
 static struct ip_conntrack_helper ftp[MAX_PORTS];
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
@@ -390,9 +399,10 @@
 static int __init init(void)
 {
 	int i, ret;
+	char *tmpname;
 
 	if (ports[0] == 0)
-		ports[0] = 21;
+		ports[0] = FTP_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
 		memset(&ftp[i], 0, sizeof(struct ip_conntrack_helper));
@@ -400,7 +410,19 @@
 		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
 		ftp[i].mask.src.u.tcp.port = 0xFFFF;
 		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].max_expected = 1;
+		ftp[i].timeout = 0;
+		ftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		ftp[i].me = ip_conntrack_ftp;
 		ftp[i].help = help;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", ports[i]);
+		ftp[i].name = tmpname;
+
 		DEBUGP("ip_ct_ftp: registering helper for port %d\n", 
 				ports[i]);
 		ret = ip_conntrack_helper_register(&ftp[i]);
@@ -414,10 +436,10 @@
 	return 0;
 }
 
-
+#ifdef CONFIG_IP_NF_NAT_NEEDED
 EXPORT_SYMBOL(ip_ftp_lock);
-EXPORT_SYMBOL(ip_conntrack_ftp);
-MODULE_LICENSE("GPL");
+#endif
 
+MODULE_LICENSE("GPL");
 module_init(init);
 module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
--- a/net/ipv4/netfilter/ip_conntrack_irc.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c	Wed Apr  3 17:11:16 2002
@@ -11,12 +11,18 @@
  **
  *	Module load syntax:
  * 	insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
+ *			    max_dcc_channels=n dcc_timeout=secs
  *	
  * 	please give the ports of all IRC servers You wish to connect to.
- *	If You don't specify ports, the default will be port 6667
+ *	If You don't specify ports, the default will be port 6667.
+ *	With max_dcc_channels you can define the maximum number of not
+ *	yet answered DCC channels per IRC session (default 8).
+ *	With dcc_timeout you can specify how long the system waits for 
+ *	an expected DCC channel (default 300 seconds).
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
@@ -30,6 +36,8 @@
 #define MAX_PORTS 8
 static int ports[MAX_PORTS];
 static int ports_n_c = 0;
+static int max_dcc_channels = 8;
+static unsigned int dcc_timeout = 300;
 
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking module");
@@ -37,6 +45,10 @@
 #ifdef MODULE_PARM
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
+MODULE_PARM(max_dcc_channels, "i");
+MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
+MODULE_PARM(dcc_timeout, "i");
+MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
 #endif
 
 #define NUM_DCCPROTO 	5
@@ -103,23 +115,15 @@
 	u_int32_t tcplen = len - iph->ihl * 4;
 	u_int32_t datalen = tcplen - tcph->doff * 4;
 	int dir = CTINFO2DIR(ctinfo);
-	struct ip_conntrack_tuple t, mask;
+	struct ip_conntrack_expect expect, *exp = &expect;
+	struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info;
 
 	u_int32_t dcc_ip;
 	u_int16_t dcc_port;
 	int i;
 	char *addr_beg_p, *addr_end_p;
 
-	struct ip_ct_irc *info = &ct->help.ct_irc_info;
-
-	mask = ((struct ip_conntrack_tuple)
-		{ { 0, { 0 } },
-		  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
-
 	DEBUGP("entered\n");
-	/* Can't track connections formed before we registered */
-	if (!info)
-		return NF_ACCEPT;
 
 	/* If packet is coming from IRC server */
 	if (dir == IP_CT_DIR_REPLY)
@@ -189,33 +193,37 @@
 
 				continue;
 			}
+			
+			memset(&expect, 0, sizeof(expect));
 
 			LOCK_BH(&ip_irc_lock);
 
 			/* save position of address in dcc string,
 			 * neccessary for NAT */
-			info->is_irc = IP_CONNTR_IRC;
 			DEBUGP("tcph->seq = %u\n", tcph->seq);
-			info->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
-			info->len = (addr_end_p - addr_beg_p);
-			info->port = dcc_port;
+			exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data);
+			exp_irc_info->len = (addr_end_p - addr_beg_p);
+			exp_irc_info->port = dcc_port;
 			DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
-				info->seq, (addr_end_p - _data), info->len);
+				exp->seq, (addr_end_p - _data), exp_irc_info->len);
+
+			exp->tuple = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { htonl(dcc_ip), { htons(dcc_port) },
+				    IPPROTO_TCP }});
+			exp->mask = ((struct ip_conntrack_tuple)
+				{ { 0, { 0 } },
+				  { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
 
-			memset(&t, 0, sizeof(t));
-			t.src.ip = 0;
-			t.src.u.tcp.port = 0;
-			t.dst.ip = htonl(dcc_ip);
-			t.dst.u.tcp.port = htons(info->port);
-			t.dst.protonum = IPPROTO_TCP;
+			exp->expectfn = NULL;
 
 			DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
-				NIPQUAD(t.src.ip),
-				ntohs(t.src.u.tcp.port),
-				NIPQUAD(t.dst.ip),
-				ntohs(t.dst.u.tcp.port));
+				NIPQUAD(exp->tuple.src.ip),
+				ntohs(exp->tuple.src.u.tcp.port),
+				NIPQUAD(exp->tuple.dst.ip),
+				ntohs(exp->tuple.dst.u.tcp.port));
 
-			ip_conntrack_expect_related(ct, &t, &mask, NULL);
+			ip_conntrack_expect_related(ct, &expect);
 			UNLOCK_BH(&ip_irc_lock);
 
 			return NF_ACCEPT;
@@ -226,29 +234,53 @@
 }
 
 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
+static char irc_names[MAX_PORTS][10];
 
 static void fini(void);
 
 static int __init init(void)
 {
 	int i, ret;
+	struct ip_conntrack_helper *hlpr;
+	char *tmpname;
 
+	if (max_dcc_channels < 1) {
+		printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
+		return -EBUSY;
+	}
+	if (dcc_timeout < 0) {
+		printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
+		return -EBUSY;
+	}
+	
 	/* If no port given, default to standard irc port */
 	if (ports[0] == 0)
-		ports[0] = 6667;
+		ports[0] = IRC_PORT;
 
 	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-		memset(&irc_helpers[i], 0,
+		hlpr = &irc_helpers[i];
+		memset(hlpr, 0,
 		       sizeof(struct ip_conntrack_helper));
-		irc_helpers[i].tuple.src.u.tcp.port = htons(ports[i]);
-		irc_helpers[i].tuple.dst.protonum = IPPROTO_TCP;
-		irc_helpers[i].mask.src.u.tcp.port = 0xFFFF;
-		irc_helpers[i].mask.dst.protonum = 0xFFFF;
-		irc_helpers[i].help = help;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->max_expected = max_dcc_channels;
+		hlpr->timeout = dcc_timeout;
+		hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		hlpr->me = ip_conntrack_irc;
+		hlpr->help = help;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
 
 		DEBUGP("port #%d: %d\n", i, ports[i]);
 
-		ret = ip_conntrack_helper_register(&irc_helpers[i]);
+		ret = ip_conntrack_helper_register(hlpr);
 
 		if (ret) {
 			printk("ip_conntrack_irc: ERROR registering port %d\n",
@@ -272,6 +304,10 @@
 		ip_conntrack_helper_unregister(&irc_helpers[i]);
 	}
 }
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(ip_irc_lock);
+#endif
 
 module_init(init);
 module_exit(fini);
diff -Nru a/net/ipv4/netfilter/ip_conntrack_proto_generic.c b/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_conntrack_proto_generic.c	Wed Apr  3 17:11:15 2002
@@ -57,5 +57,5 @@
 struct ip_conntrack_protocol ip_conntrack_generic_protocol
 = { { NULL, NULL }, 0, "unknown",
     generic_pkt_to_tuple, generic_invert_tuple, generic_print_tuple,
-    generic_print_conntrack, established, new, NULL };
+    generic_print_conntrack, established, new, NULL, NULL, NULL };
 
diff -Nru a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	Wed Apr  3 17:11:13 2002
@@ -113,4 +113,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_icmp
 = { { NULL, NULL }, IPPROTO_ICMP, "icmp",
     icmp_pkt_to_tuple, icmp_invert_tuple, icmp_print_tuple,
-    icmp_print_conntrack, icmp_packet, icmp_new, NULL };
+    icmp_print_conntrack, icmp_packet, icmp_new, NULL, NULL, NULL };
diff -Nru a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Wed Apr  3 17:11:15 2002
@@ -7,6 +7,9 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+
+#include <net/tcp.h>
+
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/lockhelp.h>
@@ -227,7 +230,19 @@
 	return 1;
 }
 
+static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
+			       struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	unsigned int datalen;
+
+	datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
+
+	return between(exp->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
+}
+
 struct ip_conntrack_protocol ip_conntrack_protocol_tcp
 = { { NULL, NULL }, IPPROTO_TCP, "tcp",
     tcp_pkt_to_tuple, tcp_invert_tuple, tcp_print_tuple, tcp_print_conntrack,
-    tcp_packet, tcp_new, NULL };
+    tcp_packet, tcp_new, NULL, tcp_exp_matches_pkt, NULL };
diff -Nru a/net/ipv4/netfilter/ip_conntrack_proto_udp.c b/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- a/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Wed Apr  3 17:11:13 2002
@@ -71,4 +71,4 @@
 struct ip_conntrack_protocol ip_conntrack_protocol_udp
 = { { NULL, NULL }, IPPROTO_UDP, "udp",
     udp_pkt_to_tuple, udp_invert_tuple, udp_print_tuple, udp_print_conntrack,
-    udp_packet, udp_new, NULL };
+    udp_packet, udp_new, NULL, NULL, NULL };
diff -Nru a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c	Wed Apr  3 17:11:15 2002
@@ -62,7 +62,13 @@
 {
 	unsigned int len;
 
-	len = sprintf(buffer, "EXPECTING: proto=%u ",
+	if (expect->expectant->helper->timeout)
+		len = sprintf(buffer, "EXPECTING: %lu ",
+			      timer_pending(&expect->timeout)
+			      ? (expect->timeout.expires - jiffies)/HZ : 0);
+	else
+		len = sprintf(buffer, "EXPECTING: - ");
+	len += sprintf(buffer + len, "proto=%u ",
 		      expect->tuple.dst.protonum);
 	len += print_tuple(buffer + len, &expect->tuple,
 			   __find_proto(expect->tuple.dst.protonum));
@@ -314,7 +320,7 @@
 {
 	WRITE_LOCK(&ip_conntrack_lock);
 
-	/* find_proto() returns proto_generic in case there is no protocol 
+	/* ip_ct_find_proto() returns proto_generic in case there is no protocol 
 	 * helper. So this should be enough - HW */
 	LIST_DELETE(&protocol_list, proto);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -353,8 +359,12 @@
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh);
+EXPORT_SYMBOL(ip_ct_find_proto);
+EXPORT_SYMBOL(ip_ct_find_helper);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
+EXPORT_SYMBOL(ip_conntrack_change_expect);
 EXPORT_SYMBOL(ip_conntrack_unexpect_related);
 EXPORT_SYMBOL(ip_conntrack_tuple_taken);
 EXPORT_SYMBOL(ip_ct_gather_frags);
 EXPORT_SYMBOL(ip_conntrack_htable_size);
+EXPORT_SYMBOL(ip_conntrack_lock);
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c	Wed Apr  3 17:11:14 2002
@@ -130,7 +130,7 @@
 	struct ip_conntrack *ct;
 	int ret;
 
-	protocol = find_proto(iph->protocol);
+	protocol = ip_ct_find_proto(iph->protocol);
 
 	/* We don't feed packets to conntrack system unless we know
            they're part of an connection already established by an
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_redir.c b/net/ipv4/netfilter/ip_fw_compat_redir.c
--- a/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Apr  3 17:11:15 2002
@@ -43,7 +43,7 @@
 		   netplay... */					 \
 		printk("ASSERT: %s:%i(%s)\n",				 \
 		       __FILE__, __LINE__, __FUNCTION__);		 \
-} while(0);
+} while(0)
 #else
 #define IP_NF_ASSERT(x)
 #endif
diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_nat_core.c	Wed Apr  3 17:11:14 2002
@@ -21,10 +21,14 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/listhelp.h>
 
 #if 0
@@ -34,6 +38,7 @@
 #endif
 
 DECLARE_RWLOCK(ip_nat_lock);
+DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
 
 /* Calculated at init based on memory size */
 static unsigned int ip_nat_htable_size;
@@ -628,8 +633,9 @@
 	}
 
 	/* If there's a helper, assign it; based on new tuple. */
-	info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
-				 &reply);
+	if (!conntrack->master)
+		info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
+					 &reply);
 
 	/* It's done. */
 	info->initialized |= (1 << HOOK2MANIP(hooknum));
@@ -724,6 +730,21 @@
 #endif
 }
 
+static inline int exp_for_packet(struct ip_conntrack_expect *exp,
+			         struct sk_buff **pskb)
+{
+	struct ip_conntrack_protocol *proto;
+	int ret = 1;
+
+	READ_LOCK(&ip_conntrack_lock);
+	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+	if (proto->exp_matches_pkt)
+		ret = proto->exp_matches_pkt(exp, pskb);
+	READ_UNLOCK(&ip_conntrack_lock);
+
+	return ret;
+}
+
 /* Do packet manipulations according to binding. */
 unsigned int
 do_bindings(struct ip_conntrack *ct,
@@ -735,6 +756,7 @@
 	unsigned int i;
 	struct ip_nat_helper *helper;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
 
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
@@ -773,11 +795,66 @@
 	READ_UNLOCK(&ip_nat_lock);
 
 	if (helper) {
+		struct ip_conntrack_expect *exp = NULL;
+		struct list_head *cur_item;
+		int ret = NF_ACCEPT;
+
+		DEBUGP("do_bindings: helper existing for (%p)\n", ct);
+
 		/* Always defragged for helpers */
 		IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
 			       & __constant_htons(IP_MF|IP_OFFSET)));
-		return helper->help(ct, info, ctinfo, hooknum, pskb);
-	} else return NF_ACCEPT;
+
+		/* Have to grab read lock before sibling_list traversal */
+		READ_LOCK(&ip_conntrack_lock);
+		list_for_each(cur_item, &ct->sibling_list) { 
+			exp = list_entry(cur_item, struct ip_conntrack_expect, 
+					 expected_list);
+					 
+			/* if this expectation is already established, skip */
+			if (exp->sibling)
+				continue;
+
+			if (exp_for_packet(exp, pskb)) {
+				/* FIXME: May be true multiple times in the case of UDP!! */
+				DEBUGP("calling nat helper (exp=%p) for packet\n",
+					exp);
+				ret = helper->help(ct, exp, info, ctinfo, 
+						   hooknum, pskb);
+				if (ret != NF_ACCEPT) {
+					READ_UNLOCK(&ip_conntrack_lock);
+					return ret;
+				}
+			}
+		}
+		/* Helper might want to manip the packet even when there is no expectation */
+		if (!exp && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
+			DEBUGP("calling nat helper for packet without expectation\n");
+			ret = helper->help(ct, NULL, info, ctinfo, 
+					   hooknum, pskb);
+			if (ret != NF_ACCEPT) {
+				READ_UNLOCK(&ip_conntrack_lock);
+				return ret;
+			}
+		}
+		READ_UNLOCK(&ip_conntrack_lock);
+		
+		/* Adjust sequence number only once per packet 
+		 * (helper is called at all hooks) */
+		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
+			       || hooknum == NF_IP_LOCAL_IN)) {
+			DEBUGP("ip_nat_core: adjusting sequence number\n");
+			/* future: put this in a l4-proto specific function,
+			 * and call this function here. */
+			ip_nat_seq_adjust(*pskb, ct, ctinfo);
+		}
+
+		return ret;
+
+	} else 
+		return NF_ACCEPT;
+
+	/* not reached */
 }
 
 unsigned int
diff -Nru a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
--- a/net/ipv4/netfilter/ip_nat_ftp.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_nat_ftp.c	Wed Apr  3 17:11:14 2002
@@ -28,38 +28,30 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 ftp_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo,
-		 unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_ftp *ftpinfo;
+	struct ip_ct_ftp_expect *exp_ftp_info;
 
+	struct ip_conntrack *master = master_ct(ct);
+	
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
-	/* Master must be an ftp connection */
-	ftpinfo = &master->help.ct_ftp_info;
+	exp_ftp_info = &ct->master->help.exp_ftp_info;
 
 	LOCK_BH(&ip_ftp_lock);
-	if (ftpinfo->is_ftp != 21) {
-		UNLOCK_BH(&ip_ftp_lock);
-		DEBUGP("nat_expected: master not ftp\n");
-		return 0;
-	}
 
-	if (ftpinfo->ftptype == IP_CT_FTP_PORT
-	    || ftpinfo->ftptype == IP_CT_FTP_EPRT) {
+	if (exp_ftp_info->ftptype == IP_CT_FTP_PORT
+	    || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) {
 		/* PORT command: make connection go to the client. */
 		newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 		newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
@@ -92,11 +84,9 @@
 		mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
 		mr.range[0].min = mr.range[0].max
 			= ((union ip_conntrack_manip_proto)
-				{ htons(ftpinfo->port) });
+				{ htons(exp_ftp_info->port) });
 	}
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
 static int
@@ -176,27 +166,22 @@
     [IP_CT_FTP_EPSV] mangle_epsv_packet
 };
 
-static int ftp_data_fixup(const struct ip_ct_ftp *ct_ftp_info,
+static int ftp_data_fixup(const struct ip_ct_ftp_expect *ct_ftp_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	u_int16_t port;
-	struct ip_conntrack_tuple tuple;
-	/* Don't care about source port */
-	const struct ip_conntrack_tuple mask
-		= { { 0xFFFFFFFF, { 0 } },
-		    { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF } };
+	struct ip_conntrack_tuple newtuple;
 
-	memset(&tuple, 0, sizeof(tuple));
 	MUST_BE_LOCKED(&ip_ftp_lock);
-	DEBUGP("FTP_NAT: seq %u + %u in %u + %u\n",
-	       ct_ftp_info->seq, ct_ftp_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("FTP_NAT: seq %u + %u in %u\n",
+	       expect->seq, ct_ftp_info->len,
+	       ntohl(tcph->seq));
 
 	/* Change address inside packet to match way we're mapping
 	   this connection. */
@@ -206,29 +191,34 @@
 		   is */
 		newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 		/* Expect something from client->server */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
 	} else {
 		/* PORT command: must be where server thinks client is */
 		newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 		/* Expect something from server->client */
-		tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
-		tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+		newtuple.src.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+		newtuple.dst.ip = 
+			ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 	}
-	tuple.dst.protonum = IPPROTO_TCP;
+	newtuple.dst.protonum = IPPROTO_TCP;
+	newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
 
 	/* Try to get same port: if not, try to change it. */
 	for (port = ct_ftp_info->port; port != 0; port++) {
-		tuple.dst.u.tcp.port = htons(port);
+		newtuple.dst.u.tcp.port = htons(port);
 
-		if (ip_conntrack_expect_related(ct, &tuple, &mask, NULL) == 0)
+		if (ip_conntrack_change_expect(expect, &newtuple) == 0)
 			break;
 	}
 	if (port == 0)
 		return 0;
 
 	if (!mangle[ct_ftp_info->ftptype](pskb, newip, port,
-					  ct_ftp_info->seq - ntohl(tcph->seq),
+					  expect->seq - ntohl(tcph->seq),
 					  ct_ftp_info->len, ct, ctinfo))
 		return 0;
 
@@ -236,6 +226,7 @@
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int hooknum,
@@ -245,13 +236,12 @@
 	struct tcphdr *tcph = (void *)iph + iph->ihl*4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_ftp *ct_ftp_info
-		= &ct->help.ct_ftp_info;
-
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	struct ip_ct_ftp_expect *ct_ftp_info;
+
+	if (!exp)
+		DEBUGP("ip_nat_ftp: no exp!!");
+
+	ct_ftp_info = &exp->help.exp_ftp_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -267,50 +257,34 @@
 	}
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_ftp_lock);
-	if (ct_ftp_info->len) {
-		/* If it's in the right range... */
-		score += between(ct_ftp_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_ftp_info->seq + ct_ftp_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
-				       ct_ftp_info->seq, ct_ftp_info->len,
-				       ntohl(tcph->seq),
-				       ntohl(tcph->seq) + datalen);
-			}
+	/* If it's in the right range... */
+	if (between(exp->seq + ct_ftp_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!ftp_data_fixup(ct_ftp_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_ftp_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			if (!ftp_data_fixup(ct_ftp_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_ftp_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *)iph + iph->ihl*4;
 		}
+	} else {
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk("FTP_NAT: partial packet %u/%u in %u/%u\n",
+			       exp->seq, ct_ftp_info->len,
+			       ntohl(tcph->seq),
+			       ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_ftp_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_ftp_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ftp[MAX_PORTS];
-static char ftp_names[MAX_PORTS][6];
-
-static struct ip_nat_expect ftp_expect
-= { { NULL, NULL }, ftp_nat_expected };
+static char ftp_names[MAX_PORTS][10];
 
 /* Not __exit: called from init() */
 static void fini(void)
@@ -321,49 +295,49 @@
 		DEBUGP("ip_nat_ftp: unregistering port %d\n", ports[i]);
 		ip_nat_helper_unregister(&ftp[i]);
 	}
-
-	ip_nat_expect_unregister(&ftp_expect);
 }
 
 static int __init init(void)
 {
-	int i, ret;
+	int i, ret = 0;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&ftp_expect);
-	if (ret == 0) {
-		if (ports[0] == 0)
-			ports[0] = 21;
-
-		for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
-
-			memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
-
-			ftp[i].tuple.dst.protonum = IPPROTO_TCP;
-			ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
-			ftp[i].mask.dst.protonum = 0xFFFF;
-			ftp[i].mask.src.u.tcp.port = 0xFFFF;
-			ftp[i].help = help;
-
-			tmpname = &ftp_names[i][0];
-			sprintf(tmpname, "ftp%2.2d", i);
-			ftp[i].name = tmpname;
-
-			DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
-					ports[i]);
-			ret = ip_nat_helper_register(&ftp[i]);
-
-			if (ret) {
-				printk("ip_nat_ftp: error registering helper for port %d\n", ports[i]);
-				fini();
-				return ret;
-			}
-			ports_c++;
-		}
+	if (ports[0] == 0)
+		ports[0] = FTP_PORT;
 
-	} else {
-		ip_nat_expect_unregister(&ftp_expect);
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+
+		memset(&ftp[i], 0, sizeof(struct ip_nat_helper));
+
+		ftp[i].tuple.dst.protonum = IPPROTO_TCP;
+		ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
+		ftp[i].mask.dst.protonum = 0xFFFF;
+		ftp[i].mask.src.u.tcp.port = 0xFFFF;
+		ftp[i].help = help;
+		ftp[i].me = THIS_MODULE;
+		ftp[i].flags = 0;
+		ftp[i].expect = ftp_nat_expected;
+
+		tmpname = &ftp_names[i][0];
+		if (ports[i] == FTP_PORT)
+			sprintf(tmpname, "ftp");
+		else
+			sprintf(tmpname, "ftp-%d", i);
+		ftp[i].name = tmpname;
+
+		DEBUGP("ip_nat_ftp: Trying to register for port %d\n",
+				ports[i]);
+		ret = ip_nat_helper_register(&ftp[i]);
+
+		if (ret) {
+			printk("ip_nat_ftp: error registering "
+			       "helper for port %d\n", ports[i]);
+			fini();
+			return ret;
+		}
+		ports_c++;
 	}
+
 	return ret;
 }
 
diff -Nru a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
--- a/net/ipv4/netfilter/ip_nat_helper.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_nat_helper.c	Wed Apr  3 17:11:14 2002
@@ -1,11 +1,18 @@
 /* ip_nat_mangle.c - generic support functions for NAT helpers 
  *
- * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
  *
  * distributed under the terms of GNU GPL
+ *
+ * 	14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- add support for SACK adjustment 
+ *	14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
+ *		- merge SACK support into newnat API
  */
 #include <linux/version.h>
+#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/skbuff.h>
@@ -19,6 +26,8 @@
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
 
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
@@ -32,7 +41,7 @@
 #define DEBUGP(format, args...)
 #define DUMP_OFFSET(x)
 #endif
-	
+
 DECLARE_LOCK(ip_nat_seqofs_lock);
 			 
 static inline int 
@@ -199,6 +208,103 @@
 	return 1;
 }
 
+/* Adjust one found SACK option including checksum correction */
+static void
+sack_adjust(struct tcphdr *tcph, 
+	    unsigned char *ptr, 
+	    struct ip_nat_seq *natseq)
+{
+	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
+	int i;
+
+	for (i = 0; i < num_sacks; i++, sp++) {
+		u_int32_t new_start_seq, new_end_seq;
+
+		if (after(ntohl(sp->start_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_after;
+		else
+			new_start_seq = ntohl(sp->start_seq) 
+					- natseq->offset_before;
+		new_start_seq = htonl(new_start_seq);
+
+		if (after(ntohl(sp->end_seq) - natseq->offset_before,
+			  natseq->correction_pos))
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_after;
+		else
+			new_end_seq = ntohl(sp->end_seq)
+				      - natseq->offset_before;
+		new_end_seq = htonl(new_end_seq);
+
+		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+			ntohl(sp->start_seq), new_start_seq,
+			ntohl(sp->end_seq), new_end_seq);
+
+		tcph->check = 
+			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
+					   ip_nat_cheat_check(~sp->end_seq, 
+						   	      new_end_seq,
+							      tcph->check));
+
+		sp->start_seq = new_start_seq;
+		sp->end_seq = new_end_seq;
+	}
+}
+			
+
+/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
+static inline int
+ip_nat_sack_adjust(struct sk_buff *skb,
+			struct ip_conntrack *ct,
+			enum ip_conntrack_info ctinfo)
+{
+	struct iphdr *iph;
+	struct tcphdr *tcph;
+	unsigned char *ptr;
+	int length, dir, sack_adjusted = 0;
+
+	iph = skb->nh.iph;
+	tcph = (void *)iph + iph->ihl*4;
+	length = (tcph->doff*4)-sizeof(struct tcphdr);
+	ptr = (unsigned char *)(tcph+1);
+
+	dir = CTINFO2DIR(ctinfo);
+
+	while (length > 0) {
+		int opcode = *ptr++;
+		int opsize;
+
+		switch (opcode) {
+		case TCPOPT_EOL:
+			return !sack_adjusted;
+		case TCPOPT_NOP:
+			length--;
+			continue;
+		default:
+			opsize = *ptr++;
+			if (opsize > length) /* no partial opts */
+				return !sack_adjusted;
+			if (opcode == TCPOPT_SACK) {
+				/* found SACK */
+				if((opsize >= (TCPOLEN_SACK_BASE
+					       +TCPOLEN_SACK_PERBLOCK)) &&
+				   !((opsize - TCPOLEN_SACK_BASE)
+				     % TCPOLEN_SACK_PERBLOCK))
+					sack_adjust(tcph, ptr-2,
+						    &ct->nat.info.seq[!dir]);
+				
+				sack_adjusted = 1;
+			}
+			ptr += opsize-2;
+			length -= opsize;
+		}
+	}
+	return !sack_adjusted;
+}
+
 /* TCP sequence number adjustment */
 int 
 ip_nat_seq_adjust(struct sk_buff *skb, 
@@ -243,51 +349,9 @@
 	tcph->seq = newseq;
 	tcph->ack_seq = newack;
 
-	return 0;
-}
-
-/* Grrr... SACK.  Fuck me even harder.  Don't want to fix it on the
-   fly, so blow it away. */
-void
-ip_nat_delete_sack(struct sk_buff *skb, struct tcphdr *tcph)
-{
-	unsigned int i;
-	u_int8_t *opt = (u_int8_t *)tcph;
-
-	DEBUGP("Seeking SACKPERM in SYN packet (doff = %u).\n",
-	       tcph->doff * 4);
-	for (i = sizeof(struct tcphdr); i < tcph->doff * 4;) {
-		DEBUGP("%u ", opt[i]);
-		switch (opt[i]) {
-		case TCPOPT_NOP:
-		case TCPOPT_EOL:
-			i++;
-			break;
+	ip_nat_sack_adjust(skb, ct, ctinfo);
 
-		case TCPOPT_SACK_PERM:
-			goto found_opt;
-
-		default:
-			/* Worst that can happen: it will take us over. */
-			i += opt[i+1] ?: 1;
-		}
-	}
-	DEBUGP("\n");
-	return;
-
- found_opt:
-	DEBUGP("\n");
-	DEBUGP("Found SACKPERM at offset %u.\n", i);
-
-	/* Must be within TCP header, and valid SACK perm. */
-	if (i + opt[i+1] <= tcph->doff*4 && opt[i+1] == 2) {
-		/* Replace with NOPs. */
-		tcph->check
-			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
-					     (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
-		opt[i] = opt[i+1] = TCPOPT_NOP;
-	}
-	else DEBUGP("Something wrong with SACK_PERM.\n");
+	return 0;
 }
 
 static inline int
@@ -297,10 +361,51 @@
 	return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
 }
 
+#define MODULE_MAX_NAMELEN		32
+
 int ip_nat_helper_register(struct ip_nat_helper *me)
 {
 	int ret = 0;
 
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_INC_USE_COUNT(ct_helper->me);
+		} else {
+
+			/* We are a NAT helper for protocol X.  If we need
+			 * respective conntrack helper for protoccol X, compute
+			 * conntrack helper name and try to load module */
+			char name[MODULE_MAX_NAMELEN];
+			const char *tmp = me->me->name;
+			
+			if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
+				printk(__FUNCTION__ ": unable to "
+				       "compute conntrack helper name "
+				       "from %s\n", tmp);
+				return -EBUSY;
+			}
+			tmp += 6;
+			sprintf(name, "ip_conntrack%s", tmp);
+#ifdef CONFIG_KMOD
+			if (!request_module(name)
+			    && (ct_helper = ip_ct_find_helper(&me->tuple))
+			    && ct_helper->me) {
+				__MOD_INC_USE_COUNT(ct_helper->me);
+			} else {
+				printk("unable to load module %s\n", name);
+				return -EBUSY;
+			}
+#else
+			printk("unable to load module %s automatically "
+			       "because kernel was compiled without kernel "
+			       "module loader support\n", name);
+			return -EBUSY;
+#endif
+		}
+	}
 	WRITE_LOCK(&ip_nat_lock);
 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
 		ret = -EBUSY;
@@ -327,8 +432,14 @@
 
 void ip_nat_helper_unregister(struct ip_nat_helper *me)
 {
+	int found = 0;
+	
 	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&helpers, me);
+	/* Autoloading conntrack helper might have failed */
+	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
+		LIST_DELETE(&helpers, me);
+		found = 1;
+	}
 	WRITE_UNLOCK(&ip_nat_lock);
 
 	/* Someone could be still looking at the helper in a bh. */
@@ -344,5 +455,19 @@
 	   worse. --RR */
 	ip_ct_selective_cleanup(kill_helper, me);
 
-	MOD_DEC_USE_COUNT;
+	if (found)
+		MOD_DEC_USE_COUNT;
+
+	/* If we are no standalone NAT helper, we need to decrement usage count
+	 * on our conntrack helper */
+	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
+		struct ip_conntrack_helper *ct_helper;
+		
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))
+		    && ct_helper->me) {
+			__MOD_DEC_USE_COUNT(ct_helper->me);
+		} else 
+			printk(__FUNCTION__ ": unable to decrement usage count"
+			       " of conntrack helper %s\n", me->me->name);
+	}
 }
diff -Nru a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c
--- a/net/ipv4/netfilter/ip_nat_irc.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/netfilter/ip_nat_irc.c	Wed Apr  3 17:11:16 2002
@@ -51,42 +51,29 @@
 
 /* FIXME: Time out? --RR */
 
-static int
+static unsigned int
 irc_nat_expected(struct sk_buff **pskb,
 		 unsigned int hooknum,
 		 struct ip_conntrack *ct,
-		 struct ip_nat_info *info,
-		 struct ip_conntrack *master,
-		 struct ip_nat_info *masterinfo, unsigned int *verdict)
+		 struct ip_nat_info *info)
 {
 	struct ip_nat_multi_range mr;
 	u_int32_t newdstip, newsrcip, newip;
-	struct ip_ct_irc *ircinfo;
+
+	struct ip_conntrack *master = master_ct(ct);
 
 	IP_NF_ASSERT(info);
 	IP_NF_ASSERT(master);
-	IP_NF_ASSERT(masterinfo);
 
 	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
 
 	DEBUGP("nat_expected: We have a connection!\n");
 
-	/* Master must be an irc connection */
-	ircinfo = &master->help.ct_irc_info;
-	LOCK_BH(&ip_irc_lock);
-	if (ircinfo->is_irc != IP_CONNTR_IRC) {
-		UNLOCK_BH(&ip_irc_lock);
-		DEBUGP("nat_expected: master not irc\n");
-		return 0;
-	}
-
 	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
 	DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
 	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
 
-	UNLOCK_BH(&ip_irc_lock);
-
 	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
 		newip = newsrcip;
 	else
@@ -99,16 +86,14 @@
 	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
 	mr.range[0].min_ip = mr.range[0].max_ip = newip;
 
-	*verdict = ip_nat_setup_info(ct, &mr, hooknum);
-
-	return 1;
+	return ip_nat_setup_info(ct, &mr, hooknum);
 }
 
-static int irc_data_fixup(const struct ip_ct_irc *ct_irc_info,
+static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
 			  struct ip_conntrack *ct,
-			  unsigned int datalen,
 			  struct sk_buff **pskb,
-			  enum ip_conntrack_info ctinfo)
+			  enum ip_conntrack_info ctinfo,
+			  struct ip_conntrack_expect *expect)
 {
 	u_int32_t newip;
 	struct ip_conntrack_tuple t;
@@ -121,9 +106,9 @@
 
 	MUST_BE_LOCKED(&ip_irc_lock);
 
-	DEBUGP("IRC_NAT: info (seq %u + %u) packet(seq %u + %u)\n",
-	       ct_irc_info->seq, ct_irc_info->len,
-	       ntohl(tcph->seq), datalen);
+	DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
+	       expect->seq, ct_irc_info->len,
+	       ntohl(tcph->seq));
 
 	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
 
@@ -133,13 +118,11 @@
 	   only set in ip_conntrack_irc, with ip_irc_lock held
 	   writable */
 
-	t = ct->expected.tuple;
+	t = expect->tuple;
 	t.dst.ip = newip;
 	for (port = ct_irc_info->port; port != 0; port++) {
 		t.dst.u.tcp.port = htons(port);
-		if (ip_conntrack_expect_related(ct, &t,
-						&ct->expected.mask,
-						NULL) == 0) {
+		if (ip_conntrack_change_expect(expect, &t) == 0) {
 			DEBUGP("using port %d", port);
 			break;
 		}
@@ -166,26 +149,28 @@
 	       buffer, NIPQUAD(newip), port);
 
 	return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
-					ct_irc_info->seq - ntohl(tcph->seq),
+					expect->seq - ntohl(tcph->seq),
 					ct_irc_info->len, buffer, 
 					strlen(buffer));
 }
 
 static unsigned int help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
 			 struct ip_nat_info *info,
 			 enum ip_conntrack_info ctinfo,
-			 unsigned int hooknum, struct sk_buff **pskb)
+			 unsigned int hooknum, 
+			 struct sk_buff **pskb)
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
 	unsigned int datalen;
 	int dir;
-	int score;
-	struct ip_ct_irc *ct_irc_info = &ct->help.ct_irc_info;
+	struct ip_ct_irc_expect *ct_irc_info;
 
-	/* Delete SACK_OK on initial TCP SYNs. */
-	if (tcph->syn && !tcph->ack)
-		ip_nat_delete_sack(*pskb, tcph);
+	if (!exp)
+		DEBUGP("ip_nat_irc: no exp!!");
+		
+	ct_irc_info = &exp->help.exp_irc_info;
 
 	/* Only mangle things once: original direction in POST_ROUTING
 	   and reply direction on PRE_ROUTING. */
@@ -202,55 +187,35 @@
 	DEBUGP("got beyond not touching\n");
 
 	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
-	score = 0;
 	LOCK_BH(&ip_irc_lock);
-	if (ct_irc_info->len) {
-		DEBUGP("got beyond ct_irc_info->len\n");
-
-		/* If it's in the right range... */
-		score += between(ct_irc_info->seq, ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		score += between(ct_irc_info->seq + ct_irc_info->len,
-				 ntohl(tcph->seq),
-				 ntohl(tcph->seq) + datalen);
-		if (score == 1) {
-			/* Half a match?  This means a partial retransmisison.
-			   It's a cracker being funky. */
-			if (net_ratelimit()) {
-				printk
-				    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
-				     ct_irc_info->seq, ct_irc_info->len,
-				     ntohl(tcph->seq),
-				     ntohl(tcph->seq) + datalen);
-			}
+	/* Check wether the whole IP/address pattern is carried in the payload */
+	if (between(exp->seq + ct_irc_info->len,
+		    ntohl(tcph->seq),
+		    ntohl(tcph->seq) + datalen)) {
+		if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
 			UNLOCK_BH(&ip_irc_lock);
 			return NF_DROP;
-		} else if (score == 2) {
-			DEBUGP("IRC_NAT: score=2, calling fixup\n");
-			if (!irc_data_fixup(ct_irc_info, ct, datalen,
-					    pskb, ctinfo)) {
-				UNLOCK_BH(&ip_irc_lock);
-				return NF_DROP;
-			}
-			/* skb may have been reallocated */
-			iph = (*pskb)->nh.iph;
-			tcph = (void *) iph + iph->ihl * 4;
 		}
+	} else { 
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk
+			    ("IRC_NAT: partial packet %u/%u in %u/%u\n",
+			     exp->seq, ct_irc_info->len,
+			     ntohl(tcph->seq),
+			     ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_irc_lock);
+		return NF_DROP;
 	}
-
 	UNLOCK_BH(&ip_irc_lock);
 
-	ip_nat_seq_adjust(*pskb, ct, ctinfo);
-
 	return NF_ACCEPT;
 }
 
 static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
-static char ip_nih_names[MAX_PORTS][6];
-
-static struct ip_nat_expect irc_expect
-    = { {NULL, NULL}, irc_nat_expected };
-
+static char irc_names[MAX_PORTS][10];
 
 /* This function is intentionally _NOT_ defined as  __exit, because
  * it is needed by init() */
@@ -262,52 +227,54 @@
 		DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
 		       ports[i]);
 		ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
-	}
-	ip_nat_expect_unregister(&irc_expect);
+	} 
 }
+
 static int __init init(void)
 {
-	int ret;
+	int ret = 0;
 	int i;
 	struct ip_nat_helper *hlpr;
 	char *tmpname;
 
-	ret = ip_nat_expect_register(&irc_expect);
-	if (ret == 0) {
-
-		if (ports[0] == 0) {
-			ports[0] = 6667;
-		}
+	if (ports[0] == 0) {
+		ports[0] = IRC_PORT;
+	}
 
-		for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
-			hlpr = &ip_nat_irc_helpers[i];
-			memset(hlpr, 0,
-			       sizeof(struct ip_nat_helper));
-
-			hlpr->tuple.dst.protonum = IPPROTO_TCP;
-			hlpr->tuple.src.u.tcp.port = htons(ports[i]);
-			hlpr->mask.src.u.tcp.port = 0xFFFF;
-			hlpr->mask.dst.protonum = 0xFFFF;
-			hlpr->help = help;
-
-			tmpname = &ip_nih_names[i][0];
-			sprintf(tmpname, "irc%2.2d", i);
-
-			hlpr->name = tmpname;
-			DEBUGP
-			    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
-			     ports[i], hlpr->name);
-			ret = ip_nat_helper_register(hlpr);
-
-			if (ret) {
-				printk
-				    ("ip_nat_irc: error registering helper for port %d\n",
-				     ports[i]);
-				fini();
-				return 1;
-			}
-			ports_c++;
+	for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
+		hlpr = &ip_nat_irc_helpers[i];
+		memset(hlpr, 0,
+		       sizeof(struct ip_nat_helper));
+
+		hlpr->tuple.dst.protonum = IPPROTO_TCP;
+		hlpr->tuple.src.u.tcp.port = htons(ports[i]);
+		hlpr->mask.src.u.tcp.port = 0xFFFF;
+		hlpr->mask.dst.protonum = 0xFFFF;
+		hlpr->help = help;
+		hlpr->flags = 0;
+		hlpr->me = THIS_MODULE;
+		hlpr->expect = irc_nat_expected;
+
+		tmpname = &irc_names[i][0];
+		if (ports[i] == IRC_PORT)
+			sprintf(tmpname, "irc");
+		else
+			sprintf(tmpname, "irc-%d", i);
+		hlpr->name = tmpname;
+
+		DEBUGP
+		    ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
+		     ports[i], hlpr->name);
+		ret = ip_nat_helper_register(hlpr);
+
+		if (ret) {
+			printk
+			    ("ip_nat_irc: error registering helper for port %d\n",
+			     ports[i]);
+			fini();
+			return 1;
 		}
+		ports_c++;
 	}
 	return ret;
 }
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c	Wed Apr  3 17:11:13 2002
@@ -4,7 +4,6 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/if.h>
-
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c
--- a/net/ipv4/netfilter/ip_nat_proto_unknown.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c	Wed Apr  3 17:11:13 2002
@@ -1,5 +1,5 @@
 /* The "unknown" protocol.  This is what is used for protocols we
- * don't understand.  It's returned by find_proto().
+ * don't understand.  It's returned by ip_ct_find_proto().
  */
 
 #include <linux/types.h>
diff -Nru a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
--- a/net/ipv4/netfilter/ip_nat_rule.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_nat_rule.c	Wed Apr  3 17:11:15 2002
@@ -106,8 +106,6 @@
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
     NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
-LIST_HEAD(nat_expect_list);
-
 /* Source NAT */
 static unsigned int ipt_snat_target(struct sk_buff **pskb,
 				    unsigned int hooknum,
@@ -254,19 +252,6 @@
 	return ip_nat_setup_info(conntrack, &mr, hooknum);
 }
 
-static inline int call_expect(const struct ip_nat_expect *i,
-			      struct sk_buff **pskb,
-			      unsigned int hooknum,
-			      struct ip_conntrack *ct,
-			      struct ip_nat_info *info,
-			      struct ip_conntrack *master,
-			      struct ip_nat_info *masterinfo,
-			      unsigned int *verdict)
-{
-	return i->expect(pskb, hooknum, ct, info, master, masterinfo,
-			 verdict);
-}
-
 int ip_nat_rule_find(struct sk_buff **pskb,
 		     unsigned int hooknum,
 		     const struct net_device *in,
@@ -276,41 +261,14 @@
 {
 	int ret;
 
-	/* Master won't vanish while this ctrack still alive */
-	if (ct->master.master) {
-		struct ip_conntrack *master;
-
-		master = (struct ip_conntrack *)ct->master.master;
-		if (LIST_FIND(&nat_expect_list,
-			      call_expect,
-			      struct ip_nat_expect *,
-			      pskb, hooknum, ct, info,
-			      master, &master->nat.info, &ret))
-			return ret;
-	}
 	ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
+
 	if (ret == NF_ACCEPT) {
 		if (!(info->initialized & (1 << HOOK2MANIP(hooknum))))
 			/* NUL mapping */
 			ret = alloc_null_binding(ct, info, hooknum);
 	}
 	return ret;
-}
-
-int ip_nat_expect_register(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	list_prepend(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
-
-	return 0;
-}
-
-void ip_nat_expect_unregister(struct ip_nat_expect *expect)
-{
-	WRITE_LOCK(&ip_nat_lock);
-	LIST_DELETE(&nat_expect_list, expect);
-	WRITE_UNLOCK(&ip_nat_lock);
 }
 
 static struct ipt_target ipt_snat_reg
diff -Nru a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c	Wed Apr  3 17:11:14 2002
@@ -1244,6 +1244,7 @@
  * NAT helper function, packets arrive here from NAT code.
  */
 static unsigned int nat_help(struct ip_conntrack *ct,
+			     struct ip_conntrack_expect *exp,
                              struct ip_nat_info *info,
                              enum ip_conntrack_info ctinfo,
                              unsigned int hooknum,
@@ -1304,19 +1305,27 @@
 	return NF_DROP;
 }
 
-static struct ip_nat_helper snmp = { { NULL, NULL },
+static struct ip_nat_helper snmp = { 
+	{ NULL, NULL },
+	"snmp",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	  nat_help, "snmp" };
+	nat_help, NULL };
  
-static struct ip_nat_helper snmp_trap = { { NULL, NULL },
+static struct ip_nat_helper snmp_trap = { 
+	{ NULL, NULL },
+	"snmp_trap",
+	IP_NAT_HELPER_F_STANDALONE,
+	THIS_MODULE,
 	{ { 0, { __constant_htons(SNMP_TRAP_PORT) } },
 	  { 0, { 0 }, IPPROTO_UDP } },
 	{ { 0, { 0xFFFF } },
 	  { 0, { 0 }, 0xFFFF } },
-	nat_help, "snmp_trap" };
+	nat_help, NULL };
 
 /*****************************************************************************
  *
diff -Nru a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
--- a/net/ipv4/netfilter/ip_nat_standalone.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/netfilter/ip_nat_standalone.c	Wed Apr  3 17:11:14 2002
@@ -5,7 +5,12 @@
 */
 
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
-   Public Licence. */
+ * Public Licence.
+ *
+ * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
+ * 	- new API and handling of conntrack/nat helpers
+ * 	- now capable of multiple expectations for one master
+ * */
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -45,6 +50,15 @@
 			         : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
 				    : "*ERROR*")))
 
+static inline int call_expect(struct ip_conntrack *master,
+			      struct sk_buff **pskb,
+			      unsigned int hooknum,
+			      struct ip_conntrack *ct,
+			      struct ip_nat_info *info)
+{
+	return master->nat.info.helper->expect(pskb, hooknum, ct, info);
+}
+
 static unsigned int
 ip_nat_fn(unsigned int hooknum,
 	  struct sk_buff **pskb,
@@ -111,8 +125,16 @@
 			int in_hashes = info->initialized;
 			unsigned int ret;
 
-			ret = ip_nat_rule_find(pskb, hooknum, in, out,
-					       ct, info);
+			if (ct->master
+			    && master_ct(ct)->nat.info.helper
+			    && master_ct(ct)->nat.info.helper->expect) {
+				ret = call_expect(master_ct(ct), pskb, 
+						  hooknum, ct, info);
+			} else {
+				ret = ip_nat_rule_find(pskb, hooknum, in, out,
+						       ct, info);
+			}
+
 			if (ret != NF_ACCEPT) {
 				WRITE_UNLOCK(&ip_nat_lock);
 				return ret;
@@ -335,11 +357,7 @@
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
 EXPORT_SYMBOL(ip_nat_helper_register);
 EXPORT_SYMBOL(ip_nat_helper_unregister);
-EXPORT_SYMBOL(ip_nat_expect_register);
-EXPORT_SYMBOL(ip_nat_expect_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
-EXPORT_SYMBOL(ip_nat_seq_adjust);
-EXPORT_SYMBOL(ip_nat_delete_sack);
 EXPORT_SYMBOL(ip_nat_used_tuple);
 MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
--- a/net/ipv4/netfilter/ip_queue.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ip_queue.c	Wed Apr  3 17:11:15 2002
@@ -464,7 +464,7 @@
 	return netlink_unicast(nfnl, skb, nlq->peer.pid, MSG_DONTWAIT);
 }
 
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
 static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
 {
diff -Nru a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
--- a/net/ipv4/netfilter/ipt_ULOG.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/netfilter/ipt_ULOG.c	Wed Apr  3 17:11:15 2002
@@ -61,7 +61,7 @@
 #define DEBUGP(format, args...)
 #endif
 
-#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0)
 
 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
 MODULE_DESCRIPTION("IP tables userspace logging module");
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/route.c	Wed Apr  3 17:11:16 2002
@@ -583,7 +583,7 @@
 	if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
 		goto out;
 	if (net_ratelimit())
-		printk("dst cache overflow\n");
+		printk(KERN_WARNING "dst cache overflow\n");
 	return 1;
 
 work_done:
@@ -657,7 +657,7 @@
 			}
 
 			if (net_ratelimit())
-				printk("Neighbour table overflow.\n");
+				printk(KERN_WARNING "Neighbour table overflow.\n");
 			rt_drop(rt);
 			return -ENOBUFS;
 		}
@@ -667,8 +667,8 @@
 #if RT_CACHE_DEBUG >= 2
 	if (rt->u.rt_next) {
 		struct rtable *trt;
-		printk("rt_cache @%02x: %u.%u.%u.%u", hash,
-				NIPQUAD(rt->rt_dst));
+		printk(KERN_DEBUG "rt_cache @%02x: %u.%u.%u.%u", hash,
+		       NIPQUAD(rt->rt_dst));
 		for (trt = rt->u.rt_next; trt; trt = trt->u.rt_next)
 			printk(" . %u.%u.%u.%u", NIPQUAD(trt->rt_dst));
 		printk("\n");
@@ -2454,7 +2454,7 @@
 
 #ifdef CONFIG_NET_CLS_ROUTE
 	for (order = 0;
-	     (PAGE_SIZE << order) < 256 * sizeof(ip_rt_acct) * NR_CPUS; order++)
+	     (PAGE_SIZE << order) < 256 * sizeof(struct ip_rt_acct) * NR_CPUS; order++)
 		/* NOTHING */;
 	ip_rt_acct = (struct ip_rt_acct *)__get_free_pages(GFP_KERNEL, order);
 	if (!ip_rt_acct)
@@ -2487,7 +2487,7 @@
 	if (!rt_hash_table)
 		panic("Failed to allocate IP route cache hash table\n");
 
-	printk("IP: routing cache hash table of %u buckets, %ldKbytes\n",
+	printk(KERN_INFO "IP: routing cache hash table of %u buckets, %ldKbytes\n",
 	       rt_hash_mask,
 	       (long) (rt_hash_mask * sizeof(struct rt_hash_bucket)) / 1024);
 
diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
--- a/net/ipv4/sysctl_net_ipv4.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv4/sysctl_net_ipv4.c	Wed Apr  3 17:11:16 2002
@@ -219,6 +219,8 @@
 	 &sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_ICMP_RATEMASK, "icmp_ratemask",
 	 &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_TW_REUSE, "tcp_tw_reuse",
+	 &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/tcp.c	Wed Apr  3 17:11:14 2002
@@ -1792,7 +1792,7 @@
 
 #ifdef TCP_DEBUG
 	if (sk->zapped) {
-		printk("TCP: double destroy sk=%p\n", sk);
+		printk(KERN_DEBUG "TCP: double destroy sk=%p\n", sk);
 		sock_hold(sk);
 	}
 	sk->zapped = 1;
@@ -2558,7 +2558,7 @@
 		sysctl_tcp_rmem[2] = 2*43689;
 	}
 
-	printk("TCP: Hash tables configured (established %d bind %d)\n",
+	printk(KERN_INFO "TCP: Hash tables configured (established %d bind %d)\n",
 	       tcp_ehash_size<<1, tcp_bhash_size);
 
 	tcpdiag_init();
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/tcp_input.c	Wed Apr  3 17:11:14 2002
@@ -124,9 +124,6 @@
 	len = skb->len;
 	if (len >= tp->ack.rcv_mss) {
 		tp->ack.rcv_mss = len;
-		/* Dubious? Rather, it is final cut. 8) */
-		if (tcp_flag_word(skb->h.th)&TCP_REMNANT)
-			tp->ack.pending |= TCP_ACK_PUSHED;
 	} else {
 		/* Otherwise, we make more careful check taking into account,
 		 * that SACKs block is variable.
@@ -463,7 +460,7 @@
 		if (after(tp->snd_una, tp->rtt_seq)) {
 			if (tp->mdev_max < tp->rttvar)
 				tp->rttvar -= (tp->rttvar-tp->mdev_max)>>2;
-			tp->rtt_seq = tp->snd_una;
+			tp->rtt_seq = tp->snd_nxt;
 			tp->mdev_max = TCP_RTO_MIN;
 		}
 	} else {
@@ -1769,6 +1766,7 @@
 			acked |= FLAG_DATA_ACKED;
 		} else {
 			acked |= FLAG_SYN_ACKED;
+			tp->retrans_stamp = 0;
 		}
 
 		if (sacked) {
@@ -3873,6 +3871,7 @@
 	switch (sk->state) {
 	case TCP_CLOSE_WAIT:
 	case TCP_CLOSING:
+	case TCP_LAST_ACK:
 		if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt))
 			break;
 	case TCP_FIN_WAIT1:
@@ -3890,7 +3889,6 @@
 			}
 		}
 		/* Fall through */
-	case TCP_LAST_ACK:
 	case TCP_ESTABLISHED: 
 		tcp_data_queue(sk, skb);
 		queued = 1;
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/tcp_ipv4.c	Wed Apr  3 17:11:14 2002
@@ -64,6 +64,8 @@
 #include <linux/ipsec.h>
 
 extern int sysctl_ip_dynaddr;
+extern int sysctl_ip_default_ttl;
+int sysctl_tcp_tw_reuse = 0;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_MIN_LENGTH 8
@@ -163,18 +165,18 @@
 	local_bh_enable();
 }
 
-static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum) 
-{ 
-	inet_sk(sk)->num = snum; 
+static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum)
+{
+	inet_sk(sk)->num = snum;
 	if ((sk->bind_next = tb->owners) != NULL)
 		tb->owners->bind_pprev = &sk->bind_next;
 	tb->owners = sk;
 	sk->bind_pprev = &tb->owners;
 	sk->prev = (struct sock *) tb;
-} 
+}
 
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
-{ 
+{
 	struct inet_opt *inet = inet_sk(sk);
 	struct sock *sk2 = tb->owners;
 	int sk_reuse = sk->reuse;
@@ -193,8 +195,8 @@
 			}
 		}
 	}
-	return sk2 != NULL; 
-} 
+	return sk2 != NULL;
+}
 
 /* Obtain a reference to a local port for the given sock,
  * if snum is zero it means select any available local port.
@@ -247,12 +249,14 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
-		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+		if (sk->reuse > 1)
+			goto success;
+		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
-			ret = 1; 
+			ret = 1;
 			if (tcp_bind_conflict(sk, tb))
-				goto fail_unlock; 
+				goto fail_unlock;
 		}
 	}
 	ret = 1;
@@ -269,7 +273,7 @@
 		tb->fastreuse = 0;
 success:
 	if (sk->prev == NULL)
-		tcp_bind_hash(sk, tb, snum); 
+		tcp_bind_hash(sk, tb, snum);
 	BUG_TRAP(sk->prev == (struct sock *) tb);
  	ret = 0;
 
@@ -341,13 +345,13 @@
 	}
 }
 
-static __inline__ void __tcp_v4_hash(struct sock *sk)
+static __inline__ void __tcp_v4_hash(struct sock *sk, const int listen_possible)
 {
 	struct sock **skp;
 	rwlock_t *lock;
 
 	BUG_TRAP(sk->pprev==NULL);
-	if(sk->state == TCP_LISTEN) {
+	if(listen_possible && sk->state == TCP_LISTEN) {
 		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 		lock = &tcp_lhash_lock;
 		tcp_listen_wlock();
@@ -362,7 +366,7 @@
 	sk->pprev = skp;
 	sock_prot_inc_use(sk->prot);
 	write_unlock(lock);
-	if (sk->state == TCP_LISTEN)
+	if (listen_possible && sk->state == TCP_LISTEN)
 		wake_up(&tcp_lhash_wait);
 }
 
@@ -370,7 +374,7 @@
 {
 	if (sk->state != TCP_CLOSE) {
 		local_bh_disable();
-		__tcp_v4_hash(sk);
+		__tcp_v4_hash(sk, 1);
 		local_bh_enable();
 	}
 }
@@ -379,6 +383,9 @@
 {
 	rwlock_t *lock;
 
+	if (!sk->pprev)
+		goto ende;
+
 	if (sk->state == TCP_LISTEN) {
 		local_bh_disable();
 		tcp_listen_wlock();
@@ -397,6 +404,8 @@
 		sock_prot_dec_use(sk->prot);
 	}
 	write_unlock_bh(lock);
+
+ ende:
 	if (sk->state == TCP_LISTEN)
 		wake_up(&tcp_lhash_wait);
 }
@@ -538,20 +547,22 @@
 					  skb->h.th->source);
 }
 
-static int tcp_v4_check_established(struct sock *sk)
+/* called with local bh disabled */
+static int __tcp_v4_check_established(struct sock *sk, __u16 lport,
+				      struct tcp_tw_bucket **twp)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	u32 daddr = inet->rcv_saddr;
 	u32 saddr = inet->daddr;
 	int dif = sk->bound_dev_if;
 	TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
-	__u32 ports = TCP_COMBINED_PORTS(inet->dport, inet->num);
-	int hash = tcp_hashfn(daddr, inet->num, saddr, inet->dport);
+	__u32 ports = TCP_COMBINED_PORTS(inet->dport, lport);
+	int hash = tcp_hashfn(daddr, lport, saddr, inet->dport);
 	struct tcp_ehash_bucket *head = &tcp_ehash[hash];
 	struct sock *sk2, **skp;
 	struct tcp_tw_bucket *tw;
 
-	write_lock_bh(&head->lock);
+	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
 	for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp) != NULL;
@@ -575,7 +586,9 @@
 			   fall back to VJ's scheme and use initial
 			   timestamp retrieved from peer table.
 			 */
-			if (tw->ts_recent_stamp) {
+			if (tw->ts_recent_stamp &&
+			    (!twp || (sysctl_tcp_tw_reuse &&
+				      xtime.tv_sec - tw->ts_recent_stamp > 1))) {
 				if ((tp->write_seq =
 						tw->snd_nxt + 65535 + 2) == 0)
 					tp->write_seq = 1;
@@ -597,6 +610,10 @@
 	}
 
 unique:
+	/* Must record num and sport now. Otherwise we will see
+	 * in hash table socket with a funny identity. */
+	inet->num = lport;
+	inet->sport = htons(lport);
 	BUG_TRAP(sk->pprev==NULL);
 	if ((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
@@ -605,15 +622,16 @@
 	sk->pprev = skp;
 	sk->hashent = hash;
 	sock_prot_inc_use(sk->prot);
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 
-	if (tw) {
+	if (twp) {
+		*twp = tw;
+		NET_INC_STATS_BH(TimeWaitRecycled);
+	} else if (tw) {
 		/* Silly. Should hash-dance instead... */
-		local_bh_disable();
 		tcp_tw_deschedule(tw);
 		tcp_timewait_kill(tw);
 		NET_INC_STATS_BH(TimeWaitRecycled);
-		local_bh_enable();
 
 		tcp_tw_put(tw);
 	}
@@ -621,34 +639,120 @@
 	return 0;
 
 not_unique:
-	write_unlock_bh(&head->lock);
+	write_unlock(&head->lock);
 	return -EADDRNOTAVAIL;
 }
 
-/* Hash SYN-SENT socket to established hash table after
- * checking that it is unique. Note, that without kernel lock
- * we MUST make these two operations atomically.
- *
- * Optimization: if it is bound and tcp_bind_bucket has the only
- * owner (us), we need not to scan established bucket.
+/*
+ * Bind a port for a connect operation and hash it.
  */
-
-int tcp_v4_hash_connecting(struct sock *sk)
+static int tcp_v4_hash_connect(struct sock *sk)
 {
 	unsigned short snum = inet_sk(sk)->num;
-	struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
-	struct tcp_bind_bucket *tb = (struct tcp_bind_bucket *)sk->prev;
-
+ 	struct tcp_bind_hashbucket *head;
+ 	struct tcp_bind_bucket *tb;
+ 
+ 	if (snum == 0) {
+ 		int rover;
+ 		int low = sysctl_local_port_range[0];
+ 		int high = sysctl_local_port_range[1];
+ 		int remaining = (high - low) + 1;
+ 		struct tcp_tw_bucket *tw = NULL;
+ 
+ 		local_bh_disable();
+ 
+ 		/* TODO. Actually it is not so bad idea to remove
+ 		 * tcp_portalloc_lock before next submission to Linus.
+ 		 * As soon as we touch this place at all it is time to think.
+ 		 *
+ 		 * Now it protects single _advisory_ variable tcp_port_rover,
+ 		 * hence it is mostly useless.
+ 		 * Code will work nicely if we just delete it, but
+ 		 * I am afraid in contented case it will work not better or
+ 		 * even worse: another cpu just will hit the same bucket
+ 		 * and spin there.
+ 		 * So some cpu salt could remove both contention and
+ 		 * memory pingpong. Any ideas how to do this in a nice way?
+ 		 */
+ 		spin_lock(&tcp_portalloc_lock);
+ 		rover = tcp_port_rover;
+ 
+ 		do {
+ 			rover++;
+ 			if ((rover < low) || (rover > high))
+ 				rover = low;
+ 			head = &tcp_bhash[tcp_bhashfn(rover)];
+ 			spin_lock(&head->lock);		
+ 
+ 			/* Does not bother with rcv_saddr checks,
+ 			 * because the established check is already
+ 			 * unique enough.
+ 			 */
+ 			for (tb = head->chain; tb; tb = tb->next) {
+ 				if (tb->port == rover) {
+ 					BUG_TRAP(tb->owners != NULL);
+ 					if (tb->fastreuse >= 0)
+ 						goto next_port;
+ 					if (!__tcp_v4_check_established(sk, rover, &tw))
+ 						goto ok;
+ 					goto next_port;
+ 				}
+ 			}
+ 
+ 			tb = tcp_bucket_create(head, rover);
+ 			if (!tb) {
+ 				spin_unlock(&head->lock);
+ 				break;
+ 			}
+ 			tb->fastreuse = -1;
+ 			goto ok;
+ 
+ 		next_port:
+ 			spin_unlock(&head->lock);
+ 		} while (--remaining > 0);
+ 		tcp_port_rover = rover;
+ 		spin_unlock(&tcp_portalloc_lock);
+ 
+ 		local_bh_enable();
+ 
+ 		return -EADDRNOTAVAIL;
+ 
+ 	ok:
+ 		/* All locks still held and bhs disabled */
+ 		tcp_port_rover = rover;
+ 		spin_unlock(&tcp_portalloc_lock);
+ 
+ 		tcp_bind_hash(sk, tb, rover);
+ 		if (!sk->pprev) {
+ 			inet_sk(sk)->sport = htons(rover);
+ 			__tcp_v4_hash(sk, 0);
+ 		}
+ 		spin_unlock(&head->lock);
+
+ 		if (tw) {
+ 			tcp_tw_deschedule(tw);
+ 			tcp_timewait_kill(tw);
+ 			tcp_tw_put(tw);
+ 		}
+ 
+ 		local_bh_enable();
+ 		return 0;
+ 	}
+ 
+ 	head  = &tcp_bhash[tcp_bhashfn(snum)];
+ 	tb  = (struct tcp_bind_bucket *)sk->prev;
 	spin_lock_bh(&head->lock);
 	if (tb->owners == sk && sk->bind_next == NULL) {
-		__tcp_v4_hash(sk);
+		__tcp_v4_hash(sk, 0);
 		spin_unlock_bh(&head->lock);
 		return 0;
 	} else {
-		spin_unlock_bh(&head->lock);
-
+		int ret;
+		spin_unlock(&head->lock);
 		/* No definite answer... Walk to established hash table */
-		return tcp_v4_check_established(sk);
+		ret = __tcp_v4_check_established(sk, snum, NULL);
+		local_bh_enable();
+		return ret;
 	}
 }
 
@@ -658,7 +762,6 @@
 	struct inet_opt *inet = inet_sk(sk);
 	struct tcp_opt *tp = tcp_sk(sk);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
-	struct sk_buff *buff;
 	struct rtable *rt;
 	u32 daddr, nexthop;
 	int tmp;
@@ -693,12 +796,6 @@
 	if (!inet->opt || !inet->opt->srr)
 		daddr = rt->rt_dst;
 
-	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
-	if (buff == NULL)
-		goto failure;
-
 	if (!inet->saddr)
 		inet->saddr = rt->rt_src;
 	inet->rcv_saddr = inet->saddr;
@@ -729,24 +826,38 @@
 	inet->dport = usin->sin_port;
 	inet->daddr = daddr;
 
+	tp->ext_header_len = 0;
+	if (inet->opt)
+		tp->ext_header_len = inet->opt->optlen;
+
+	tp->mss_clamp = 536;
+
+	/* Socket identity is still unknown (sport may be zero).
+	 * However we set state to SYN-SENT and not releasing socket
+	 * lock select source port, enter ourselves into the hash tables and
+	 * complete initalization after this.
+	 */
+	tcp_set_state(sk, TCP_SYN_SENT);
+	err = tcp_v4_hash_connect(sk);
+	if (err)
+		goto failure;
+
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcp_sequence_number(inet->saddr,
 							   inet->daddr,
 							   inet->sport,
 							   usin->sin_port);
 
-	tp->ext_header_len = 0;
-	if (inet->opt)
-		tp->ext_header_len = inet->opt->optlen;
 	inet->id = tp->write_seq ^ jiffies;
 
-	tp->mss_clamp = 536;
+	err = tcp_connect(sk);
+	if (err)
+		goto failure;
 
-	err = tcp_connect(sk, buff);
-	if (err == 0)
-		return 0;
+	return 0;
 
 failure:
+	tcp_set_state(sk, TCP_CLOSE);
 	__sk_dst_reset(sk);
 	sk->route_caps = 0;
 	inet->dport = 0;
@@ -799,7 +910,6 @@
 	req->expires = jiffies + TCP_TIMEOUT_INIT;
 	req->retrans = 0;
 	req->sk = NULL;
-	req->index = h;
 	req->dl_next = lopt->syn_table[h];
 
 	write_lock(&tp->syn_wait_lock);
@@ -1092,6 +1202,7 @@
 	arg.n_iov = 1;
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2; 
 
+	inet_sk(tcp_socket->sk)->ttl = sysctl_ip_default_ttl;
 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
 
 	TCP_INC_STATS_BH(TcpOutSegs);
@@ -1478,7 +1589,7 @@
 	newtp->advmss = dst->advmss;
 	tcp_initialize_rcv_mss(newsk);
 
-	__tcp_v4_hash(newsk);
+	__tcp_v4_hash(newsk, 0);
 	__tcp_inherit_port(sk, newsk);
 
 	return newsk;
@@ -1902,7 +2013,6 @@
 	tcp_v4_rebuild_header,
 	tcp_v4_conn_request,
 	tcp_v4_syn_recv_sock,
-	tcp_v4_hash_connecting,
 	tcp_v4_remember_stamp,
 	sizeof(struct iphdr),
 
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/tcp_minisocks.c	Wed Apr  3 17:11:14 2002
@@ -786,6 +786,8 @@
 			newtp->ack.last_seg_size = skb->len-newtp->tcp_header_len;
 		newtp->mss_clamp = req->mss;
 		TCP_ECN_openreq_child(newtp, req);
+
+		TCP_INC_STATS_BH(TcpPassiveOpens);
 	}
 	return newsk;
 }
@@ -849,8 +851,38 @@
 	/* Further reproduces section "SEGMENT ARRIVES"
 	   for state SYN-RECEIVED of RFC793.
 	   It is broken, however, it does not work only
-	   when SYNs are crossed, which is impossible in our
-	   case.
+	   when SYNs are crossed.
+
+	   You would think that SYN crossing is impossible here, since
+	   we should have a SYN_SENT socket (from connect()) on our end,
+	   but this is not true if the crossed SYNs were sent to both
+	   ends by a malicious third party.  We must defend against this,
+	   and to do that we first verify the ACK (as per RFC793, page
+	   36) and reset if it is invalid.  Is this a true full defense?
+	   To convince ourselves, let us consider a way in which the ACK
+	   test can still pass in this 'malicious crossed SYNs' case.
+	   Malicious sender sends identical SYNs (and thus identical sequence
+	   numbers) to both A and B:
+
+		A: gets SYN, seq=7
+		B: gets SYN, seq=7
+
+	   By our good fortune, both A and B select the same initial
+	   send sequence number of seven :-)
+
+		A: sends SYN|ACK, seq=7, ack_seq=8
+		B: sends SYN|ACK, seq=7, ack_seq=8
+
+	   So we are now A eating this SYN|ACK, ACK test passes.  So
+	   does sequence test, SYN is truncated, and thus we consider
+	   it a bare ACK.
+
+	   If tp->defer_accept, we silently drop this bare ACK.  Otherwise,
+	   we create an established connection.  Both ends (listening sockets)
+	   accept the new incoming connection and try to talk to each other. 8-)
+
+	   Note: This case is both harmless, and rare.  Possibility is about the
+	   same as us discovering intelligent life on another plant tomorrow.
 
 	   But generally, we should (RFC lies!) to accept ACK
 	   from SYNACK both here and in tcp_rcv_state_process().
@@ -862,6 +894,22 @@
 	   before attempt to create socket.
 	 */
 
+	/* RFC793 page 36: "If the connection is in any non-synchronized state ...
+	 *                  and the incoming segment acknowledges something not yet
+	 *                  sent (the segment carries an unaccaptable ACK) ...
+	 *                  a reset is sent."
+	 */
+	if (!(flg & TCP_FLAG_ACK))
+		return NULL;
+
+	/* Invalid ACK: reset will be sent by listening socket */
+	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
+		return sk;
+	/* Also, it would be not so bad idea to check rcv_tsecr, which
+	 * is essentially ACK extension and too early or too late values
+	 * should cause reset in unsynchronized states.
+	 */
+
 	/* RFC793: "first check sequence number". */
 
 	if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
@@ -890,19 +938,6 @@
 	 */
 	if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN))
 		goto embryonic_reset;
-
-	/* RFC793: "fifth check the ACK field" */
-
-	if (!(flg & TCP_FLAG_ACK))
-		return NULL;
-
-	/* Invalid ACK: reset will be sent by listening socket */
-	if (TCP_SKB_CB(skb)->ack_seq != req->snt_isn+1)
-		return sk;
-	/* Also, it would be not so bad idea to check rcv_tsecr, which
-	 * is essentially ACK extension and too early or too late values
-	 * should cause reset in unsynchronized states.
-	 */
 
 	/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
 	if (tp->defer_accept && TCP_SKB_CB(skb)->end_seq == req->rcv_isn+1) {
diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
--- a/net/ipv4/tcp_output.c	Wed Apr  3 17:11:15 2002
+++ b/net/ipv4/tcp_output.c	Wed Apr  3 17:11:15 2002
@@ -38,6 +38,7 @@
 
 #include <net/tcp.h>
 
+#include <linux/compiler.h>
 #include <linux/smp_lock.h>
 
 /* People can turn this off for buggy TCP's found in printers etc. */
@@ -1156,14 +1157,14 @@
 	return skb;
 }
 
-int tcp_connect(struct sock *sk, struct sk_buff *buff)
+/* 
+ * Do all connect socket setups that can be done AF independent.
+ */ 
+static inline void tcp_connect_init(struct sock *sk)
 {
 	struct dst_entry *dst = __sk_dst_get(sk);
 	struct tcp_opt *tp = tcp_sk(sk);
 
-	/* Reserve space for headers. */
-	skb_reserve(buff, MAX_TCP_HEADER);
-
 	/* We'll fix this up when we get a response from the other end.
 	 * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
 	 */
@@ -1190,14 +1191,6 @@
 
 	tp->rcv_ssthresh = tp->rcv_wnd;
 
-	/* Socket identity change complete, no longer
-	 * in TCP_CLOSE, so enter ourselves into the
-	 * hash tables.
-	 */
-	tcp_set_state(sk,TCP_SYN_SENT);
-	if (tp->af_specific->hash_connecting(sk))
-		goto err_out;
-
 	sk->err = 0;
 	sk->done = 0;
 	tp->snd_wnd = 0;
@@ -1211,6 +1204,24 @@
 	tp->rto = TCP_TIMEOUT_INIT;
 	tp->retransmits = 0;
 	tcp_clear_retrans(tp);
+}
+
+/*
+ * Build a SYN and send it off.
+ */ 
+int tcp_connect(struct sock *sk)
+{
+	struct tcp_opt *tp = tcp_sk(sk);
+	struct sk_buff *buff;
+
+	tcp_connect_init(sk);
+
+	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
+	if (unlikely(buff == NULL))
+		return -ENOBUFS;
+
+	/* Reserve space for headers. */
+	skb_reserve(buff, MAX_TCP_HEADER);
 
 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
 	TCP_ECN_send_syn(tp, buff);
@@ -1233,11 +1244,6 @@
 	/* Timer for repeating the SYN until an answer. */
 	tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto);
 	return 0;
-
-err_out:
-	tcp_set_state(sk,TCP_CLOSE);
-	kfree_skb(buff);
-	return -EADDRNOTAVAIL;
 }
 
 /* Send out a delayed ack, the caller does the policy checking
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv4/udp.c	Wed Apr  3 17:11:14 2002
@@ -725,6 +725,8 @@
 	struct inet_opt *inet = inet_sk(sk);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
 	struct rtable *rt;
+	u32 saddr;
+	int oif;
 	int err;
 
 	
@@ -736,8 +738,16 @@
 
 	sk_dst_reset(sk);
 
-	err = ip_route_connect(&rt, usin->sin_addr.s_addr, inet->saddr,
-			       RT_CONN_FLAGS(sk), sk->bound_dev_if);
+	oif = sk->bound_dev_if;
+	saddr = inet->saddr;
+	if (MULTICAST(usin->sin_addr.s_addr)) {
+		if (!oif)
+			oif = inet->mc_index;
+		if (!saddr)
+			saddr = inet->mc_addr;
+	}
+	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
+			       RT_CONN_FLAGS(sk), oif);
 	if (err)
 		return err;
 	if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) {
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv6/addrconf.c	Wed Apr  3 17:11:16 2002
@@ -62,6 +62,8 @@
 
 #include <asm/uaccess.h>
 
+#define IPV6_MAX_ADDRESSES 16
+
 /* Set to 3 to get tracing... */
 #define ACONF_DEBUG 2
 
@@ -586,6 +588,18 @@
 	return err;
 }
 
+int ipv6_count_addresses(struct inet6_dev *idev)
+{
+	int cnt = 0;
+	struct inet6_ifaddr *ifp;
+
+	read_lock_bh(&idev->lock);
+	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+		cnt++;
+	read_unlock_bh(&idev->lock);
+	return cnt;
+}
+
 int ipv6_chk_addr(struct in6_addr *addr, struct net_device *dev)
 {
 	struct inet6_ifaddr * ifp;
@@ -895,8 +909,12 @@
 		ifp = ipv6_get_ifaddr(&addr, dev);
 
 		if (ifp == NULL && valid_lft) {
-			ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
-					    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
+			/* Do not allow to create too much of autoconfigured
+			 * addresses; this would be too easy way to crash kernel.
+			 */
+			if (ipv6_count_addresses(in6_dev) < IPV6_MAX_ADDRESSES)
+				ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+						    addr_type&IPV6_ADDR_SCOPE_MASK, 0);
 
 			if (ifp == NULL) {
 				in6_dev_put(in6_dev);
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv6/ndisc.c	Wed Apr  3 17:11:14 2002
@@ -361,7 +361,7 @@
 	ipv6_addr_copy(&msg->target, solicited_addr);
 
 	if (inc_opt)
-		ndisc_fill_option((void*)&msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
+		ndisc_fill_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(solicited_addr, daddr, len, 
@@ -422,7 +422,7 @@
 	ipv6_addr_copy(&msg->target, solicit);
 
 	if (send_llinfo)
-		ndisc_fill_option((void*)&msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
+		ndisc_fill_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, dev->addr_len);
 
 	/* checksum */
 	msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr,
@@ -572,6 +572,11 @@
 			printk(KERN_WARNING "ICMP RA: source address is not linklocal\n");
 		return;
 	}
+	if (optlen < 0) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "ICMP RA: packet too short\n");
+		return;
+	}
 
 	/*
 	 *	set the RA_RECV flag in the interface
@@ -928,7 +933,7 @@
 	u8 *opt;
 
 	opt = skb->h.raw;
-	opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+	opt += sizeof(struct nd_msg);
 	opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_SOURCE_LL_ADDR);
 
 	return neigh_event_ns(&nd_tbl, opt, saddr, skb->dev);
@@ -936,12 +941,11 @@
 
 static __inline__ int ndisc_recv_na(struct neighbour *neigh, struct sk_buff *skb)
 {
-	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	u8 *opt;
+	struct nd_msg *msg = (struct nd_msg*) skb->h.raw;
 
-	opt = skb->h.raw;
-	opt += sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-	opt = ndisc_find_option(opt, skb->dev->addr_len+2, skb->tail - opt, ND_OPT_TARGET_LL_ADDR);
+	opt = ndisc_find_option(msg->opt, skb->dev->addr_len+2,
+				skb->tail - msg->opt, ND_OPT_TARGET_LL_ADDR);
 
 	return neigh_update(neigh, opt,
 			    msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
@@ -962,7 +966,6 @@
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
-	unsigned int payload_len;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -985,11 +988,9 @@
 	 *	(Some checking in ndisc_find_option)
 	 */
 
-	payload_len = ntohs(skb->nh.ipv6h->payload_len);
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
-		/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-		if (payload_len < 8+16) {
+		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
 			return 0;
@@ -1069,12 +1070,13 @@
 
 				neigh = ndisc_recv_ns(saddr, skb);
 
-				if (neigh) {
+				if (neigh || !dev->hard_header) {
 					ndisc_send_na(dev, neigh, saddr, &ifp->addr, 
 						      ifp->idev->cnf.forwarding, 1, 
 						      ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1, 
 						      1);
-					neigh_release(neigh);
+					if (neigh)
+						neigh_release(neigh);
 				}
 			}
 			in6_ifa_put(ifp);
@@ -1118,8 +1120,7 @@
 		return 0;
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
-		/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-		if (payload_len < 16+8 ) {
+		if (skb->len < sizeof(struct nd_msg)) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
 			return 0;
@@ -1180,34 +1181,11 @@
 		break;
 
 	case NDISC_ROUTER_ADVERTISEMENT:
-		/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-		if (payload_len < 8+4+4) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP RA: packet too short\n");
-			return 0;
-		}
 		ndisc_router_discovery(skb);
 		break;
 
 	case NDISC_REDIRECT:
-		/* XXX: import nd_redirect from glibc netinet/icmp6.h */
-		if (payload_len < 8+16+16) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP redirect: packet too short\n");
-			return 0;
-		}
 		ndisc_redirect_rcv(skb);
-		break;
-
-	case NDISC_ROUTER_SOLICITATION:
-		/* No RS support in the kernel, but we do some required checks */
-
-		/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-		if (payload_len < 8) {
-			if (net_ratelimit())
-				printk(KERN_WARNING "ICMP RS: packet too short\n");
-			return 0;
-		}
 		break;
 	};
 
diff -Nru a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
--- a/net/ipv6/netfilter/ip6_queue.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv6/netfilter/ip6_queue.c	Wed Apr  3 17:11:14 2002
@@ -518,7 +518,7 @@
 	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
 }
 
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 
 static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
 {
diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c	Wed Apr  3 17:11:16 2002
+++ b/net/ipv6/sit.c	Wed Apr  3 17:11:16 2002
@@ -517,7 +517,11 @@
 		goto tx_error;
 	}
 
-	mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	if (tiph->frag_off)
+		mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
+	else
+		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;
+
 	if (mtu < 68) {
 		tunnel->stat.collisions++;
 		ip_rt_put(rt);
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Wed Apr  3 17:11:13 2002
+++ b/net/ipv6/tcp_ipv6.c	Wed Apr  3 17:11:13 2002
@@ -136,7 +136,7 @@
 				break;
 	}
 	if (tb != NULL && tb->owners != NULL) {
-		if (tb->fastreuse != 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
 			struct ipv6_pinfo *np = inet6_sk(sk);
@@ -377,22 +377,22 @@
 }
 
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
-					      struct ipv6hdr *ip6h,
-					      struct tcphdr *th,
-					      int iif,
-					      struct open_request ***prevp)
+					      struct open_request ***prevp,
+					      __u16 rport,
+					      struct in6_addr *raddr,
+					      struct in6_addr *laddr,
+					      int iif)
 {
 	struct tcp_listen_opt *lopt = tp->listen_opt;
 	struct open_request *req, **prev;  
-	__u16 rport = th->source;
 
-	for (prev = &lopt->syn_table[tcp_v6_synq_hash(&ip6h->saddr, rport)];
+	for (prev = &lopt->syn_table[tcp_v6_synq_hash(raddr, rport)];
 	     (req = *prev) != NULL;
 	     prev = &req->dl_next) {
 		if (req->rmt_port == rport &&
 		    req->class->family == AF_INET6 &&
-		    !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
-		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
+		    !ipv6_addr_cmp(&req->af.v6_req.rmt_addr, raddr) &&
+		    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, laddr) &&
 		    (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
 			BUG_TRAP(req->sk == NULL);
 			*prevp = prev;
@@ -499,11 +499,21 @@
 	return -EADDRNOTAVAIL;
 }
 
-static int tcp_v6_hash_connecting(struct sock *sk)
+static int tcp_v6_hash_connect(struct sock *sk)
 {
-	unsigned short snum = inet_sk(sk)->num;
-	struct tcp_bind_hashbucket *head = &tcp_bhash[tcp_bhashfn(snum)];
-	struct tcp_bind_bucket *tb = head->chain;
+	struct tcp_bind_hashbucket *head;
+	struct tcp_bind_bucket *tb;
+
+	/* XXX */
+	if (inet_sk(sk)->num == 0) { 
+		int err = tcp_v6_get_port(sk, inet_sk(sk)->num);
+		if (err)
+			return err;
+		inet_sk(sk)->sport = htons(inet_sk(sk)->num);
+	}
+
+	head = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)];
+	tb = head->chain;
 
 	spin_lock_bh(&head->lock);
 
@@ -534,7 +544,6 @@
 	struct in6_addr saddr_buf;
 	struct flowi fl;
 	struct dst_entry *dst;
-	struct sk_buff *buff;
 	int addr_type;
 	int err;
 
@@ -675,17 +684,12 @@
 		tp->ext_header_len = np->opt->opt_flen + np->opt->opt_nflen;
 	tp->mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
 
-	err = -ENOBUFS;
-	buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation);
-
-	if (buff == NULL)
-		goto failure;
-
 	inet->dport = usin->sin6_port;
 
-	/*
-	 *	Init variables
-	 */
+	tcp_set_state(sk, TCP_SYN_SENT);
+	err = tcp_v6_hash_connect(sk);
+	if (err)
+		goto late_failure;
 
 	if (!tp->write_seq)
 		tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32,
@@ -693,10 +697,14 @@
 							     inet->sport,
 							     inet->dport);
 
-	err = tcp_connect(sk, buff);
-	if (err == 0)
-		return 0;
+	err = tcp_connect(sk);
+	if (err)
+		goto late_failure;
+
+	return 0;
 
+late_failure:
+	tcp_set_state(sk, TCP_CLOSE);
 failure:
 	__sk_dst_reset(sk);
 	inet->dport = 0;
@@ -708,8 +716,6 @@
 		int type, int code, int offset, __u32 info)
 {
 	struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data;
-	struct in6_addr *saddr = &hdr->saddr;
-	struct in6_addr *daddr = &hdr->daddr;
 	struct tcphdr *th = (struct tcphdr *)(skb->data+offset);
 	struct ipv6_pinfo *np;
 	struct sock *sk;
@@ -717,7 +723,7 @@
 	struct tcp_opt *tp; 
 	__u32 seq;
 
-	sk = tcp_v6_lookup(daddr, th->dest, saddr, th->source, skb->dev->ifindex);
+	sk = tcp_v6_lookup(&hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
 		ICMP6_INC_STATS_BH(Icmp6InErrors);
@@ -790,15 +796,12 @@
 	/* Might be for an open_request */
 	switch (sk->state) {
 		struct open_request *req, **prev;
-		struct ipv6hdr hd;
 	case TCP_LISTEN:
 		if (sk->lock.users)
 			goto out;
 
-		/* Grrrr - fix this later. */
-		ipv6_addr_copy(&hd.saddr, saddr);
-		ipv6_addr_copy(&hd.daddr, daddr); 
-		req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
+		req = tcp_v6_search_req(tp, &prev, th->dest, &hdr->daddr,
+					&hdr->saddr, tcp_v6_iif(skb));
 		if (!req)
 			goto out;
 
@@ -1107,7 +1110,8 @@
 	struct sock *nsk;
 
 	/* Find possible connection requests. */
-	req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &prev);
+	req = tcp_v6_search_req(tp, &prev, th->source, &skb->nh.ipv6h->saddr,
+				&skb->nh.ipv6h->daddr, tcp_v6_iif(skb));
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
@@ -1142,7 +1146,6 @@
 	req->sk = NULL;
 	req->expires = jiffies + TCP_TIMEOUT_INIT;
 	req->retrans = 0;
-	req->index = h;
 	req->dl_next = lopt->syn_table[h];
 
 	write_lock(&tp->syn_wait_lock);
@@ -1790,7 +1793,6 @@
 	tcp_v6_rebuild_header,
 	tcp_v6_conn_request,
 	tcp_v6_syn_recv_sock,
-	tcp_v6_hash_connecting,
 	tcp_v6_remember_stamp,
 	sizeof(struct ipv6hdr),
 
@@ -1810,7 +1812,6 @@
 	tcp_v4_rebuild_header,
 	tcp_v6_conn_request,
 	tcp_v6_syn_recv_sock,
-	tcp_v4_hash_connecting,
 	tcp_v4_remember_stamp,
 	sizeof(struct iphdr),
 
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c	Wed Apr  3 17:11:14 2002
+++ b/net/ipv6/udp.c	Wed Apr  3 17:11:14 2002
@@ -293,6 +293,8 @@
 				return -EINVAL;
 			}
 			sk->bound_dev_if = usin->sin6_scope_id;
+			if (!sk->bound_dev_if && (addr_type&IPV6_ADDR_MULTICAST))
+				fl.oif = np->mcast_oif;
 		}
 
 		/* Connect to link-local address requires an interface */
@@ -316,6 +318,9 @@
 	fl.oif = sk->bound_dev_if;
 	fl.uli_u.ports.dport = inet->dport;
 	fl.uli_u.ports.sport = inet->sport;
+
+	if (!fl.oif && (addr_type&IPV6_ADDR_MULTICAST))
+		fl.oif = np->mcast_oif;
 
 	if (flowlabel) {
 		if (flowlabel->opt && flowlabel->opt->srcrt) {
diff -Nru a/net/khttpd/sockets.c b/net/khttpd/sockets.c
--- a/net/khttpd/sockets.c	Wed Apr  3 17:11:14 2002
+++ b/net/khttpd/sockets.c	Wed Apr  3 17:11:14 2002
@@ -82,7 +82,7 @@
 	
 	MainSocket = sock;
 	
-	EnterFunction("StartListening");
+	LeaveFunction("StartListening");
 	return 1; 
 }	
 
diff -Nru a/net/lapb/lapb_iface.c b/net/lapb/lapb_iface.c
--- a/net/lapb/lapb_iface.c	Wed Apr  3 17:11:15 2002
+++ b/net/lapb/lapb_iface.c	Wed Apr  3 17:11:15 2002
@@ -407,5 +407,6 @@
 
 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol");
+MODULE_LICENSE("GPL");
 
 module_init(lapb_init);
diff -Nru a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
--- a/net/netlink/netlink_dev.c	Wed Apr  3 17:11:15 2002
+++ b/net/netlink/netlink_dev.c	Wed Apr  3 17:11:15 2002
@@ -206,6 +206,8 @@
 
 #ifdef MODULE
 
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	printk(KERN_INFO "Network Kernel/User communications module 0.04\n");
diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c	Wed Apr  3 17:11:15 2002
+++ b/net/netrom/af_netrom.c	Wed Apr  3 17:11:15 2002
@@ -29,7 +29,7 @@
  *	NET/ROM 006	Alan(GW4PTS)	Brought in line with the ANK changes
  *			Jonathan(G4KLX)	Removed hdrincl.
  *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
- *					Impmented Idle timer.
+ *					Implemented Idle timer.
  *			Arnaldo C. Melo s/suser/capable/, micro cleanups
  */
 
@@ -1338,6 +1338,7 @@
 
 MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");
+MODULE_LICENSE("GPL");
 
 static void __exit nr_exit(void)
 {
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Wed Apr  3 17:11:15 2002
+++ b/net/netsyms.c	Wed Apr  3 17:11:15 2002
@@ -364,7 +364,6 @@
 EXPORT_SYMBOL(tcp_v4_syn_recv_sock);
 EXPORT_SYMBOL(tcp_v4_do_rcv);
 EXPORT_SYMBOL(tcp_v4_connect);
-EXPORT_SYMBOL(tcp_v4_hash_connecting);
 EXPORT_SYMBOL(tcp_unhash);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(tcp_prot);
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Wed Apr  3 17:11:14 2002
+++ b/net/packet/af_packet.c	Wed Apr  3 17:11:14 2002
@@ -358,6 +358,8 @@
 	if (dev->hard_header) {
 		skb->data -= dev->hard_header_len;
 		skb->tail -= dev->hard_header_len;
+		if (len < dev->hard_header_len)
+			skb->nh.raw = skb->data;
 	}
 
 	/* Returns -EFAULT on error */
diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c	Wed Apr  3 17:11:15 2002
+++ b/net/rose/af_rose.c	Wed Apr  3 17:11:15 2002
@@ -1519,6 +1519,7 @@
 
 MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol");
+MODULE_LICENSE("GPL");
 
 static void __exit rose_exit(void)
 {
diff -Nru a/net/sched/sch_prio.c b/net/sched/sch_prio.c
--- a/net/sched/sch_prio.c	Wed Apr  3 17:11:15 2002
+++ b/net/sched/sch_prio.c	Wed Apr  3 17:11:15 2002
@@ -327,6 +327,7 @@
 
 	if (cl - 1 > q->bands)
 		return -ENOENT;
+	tcm->tcm_handle |= TC_H_MIN(cl);
 	if (q->queues[cl-1])
 		tcm->tcm_info = q->queues[cl-1]->handle;
 	return 0;
diff -Nru a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
--- a/net/sched/sch_sfq.c	Wed Apr  3 17:11:15 2002
+++ b/net/sched/sch_sfq.c	Wed Apr  3 17:11:15 2002
@@ -105,6 +105,7 @@
 /* Parameters */
 	int		perturb_period;
 	unsigned	quantum;	/* Allotment per round: MUST BE >= MTU */
+	int		limit;
 
 /* Variables */
 	struct timer_list perturb_timer;
@@ -275,7 +276,7 @@
 			q->tail = x;
 		}
 	}
-	if (++sch->q.qlen < SFQ_DEPTH-1) {
+	if (++sch->q.qlen < q->limit-1) {
 		sch->stats.bytes += skb->len;
 		sch->stats.packets++;
 		return 0;
@@ -310,7 +311,7 @@
 			q->tail = x;
 		}
 	}
-	if (++sch->q.qlen < SFQ_DEPTH-1)
+	if (++sch->q.qlen < q->limit - 1)
 		return 0;
 
 	sch->stats.drops++;
@@ -390,6 +391,11 @@
 	sch_tree_lock(sch);
 	q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
 	q->perturb_period = ctl->perturb_period*HZ;
+	if (ctl->limit)
+		q->limit = min_t(u32, ctl->limit, SFQ_DEPTH);
+
+	while (sch->q.qlen >= q->limit-1)
+		sfq_drop(sch);
 
 	del_timer(&q->perturb_timer);
 	if (q->perturb_period) {
@@ -416,6 +422,7 @@
 		q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH;
 		q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH;
 	}
+	q->limit = SFQ_DEPTH;
 	q->max_depth = 0;
 	q->tail = SFQ_DEPTH;
 	if (opt == NULL) {
@@ -448,9 +455,9 @@
 	opt.quantum = q->quantum;
 	opt.perturb_period = q->perturb_period/HZ;
 
-	opt.limit = SFQ_DEPTH;
+	opt.limit = q->limit;
 	opt.divisor = SFQ_HASH_DIVISOR;
-	opt.flows = SFQ_DEPTH;
+	opt.flows = q->limit;
 
 	RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
 
diff -Nru a/net/sunrpc/stats.c b/net/sunrpc/stats.c
--- a/net/sunrpc/stats.c	Wed Apr  3 17:11:15 2002
+++ b/net/sunrpc/stats.c	Wed Apr  3 17:11:15 2002
@@ -21,6 +21,7 @@
 #include <linux/proc_fs.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svcsock.h>
+#include <linux/init.h>
 
 #define RPCDBG_FACILITY	RPCDBG_MISC
 
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Wed Apr  3 17:11:14 2002
+++ b/net/sunrpc/xprt.c	Wed Apr  3 17:11:14 2002
@@ -1097,7 +1097,7 @@
 		return;
 
 	/* Wait until we have enough socket memory. */
-	if (sock_writeable(sk))
+	if (!sock_writeable(sk))
 		return;
 
 	if (!xprt_test_and_set_wspace(xprt)) {
diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c	Wed Apr  3 17:11:15 2002
+++ b/net/x25/af_x25.c	Wed Apr  3 17:11:15 2002
@@ -1371,6 +1371,7 @@
 
 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The X.25 Packet Layer network layer protocol");
+MODULE_LICENSE("GPL");
 
 static void __exit x25_exit(void)
 {
diff -Nru a/scripts/mkspec b/scripts/mkspec
--- a/scripts/mkspec	Wed Apr  3 17:11:13 2002
+++ b/scripts/mkspec	Wed Apr  3 17:11:13 2002
@@ -6,9 +6,15 @@
 #	The only gothic bit here is redefining install_post to avoid 
 #	stripping the symbols from files in the kernel which we want
 #
+if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
+	PROVIDES=kernel-drm
+fi
+
+PROVIDES="$PROVIDES kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+
 echo "Name: kernel"
 echo "Summary: The Linux Kernel"
-echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//"
+echo "Version: "$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION | sed -e "s/-//g"
 # we need to determine the NEXT version number so that uname and
 # rpm -q will agree
 echo "Release: `. scripts/mkversion`"
@@ -17,8 +23,9 @@
 echo "Vendor: The Linux Community"
 echo "URL: http://www.kernel.org"
 echo -n "Source: kernel-$VERSION.$PATCHLEVEL.$SUBLEVEL"
-echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//"
+echo "$EXTRAVERSION.tar.gz" | sed -e "s/-//g"
 echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "Provides: $PROVIDES"
 echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
 echo ""
 echo "%description"
@@ -35,6 +42,7 @@
 echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make modules_install'
 echo 'cp arch/i386/boot/bzImage $RPM_BUILD_ROOT'"/boot/vmlinuz-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
+echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION"
 echo ""
 echo "%clean"
 echo '#echo -rf $RPM_BUILD_ROOT'
diff -Nru a/sound/core/rtctimer.c b/sound/core/rtctimer.c
--- a/sound/core/rtctimer.c	Wed Apr  3 17:11:14 2002
+++ b/sound/core/rtctimer.c	Wed Apr  3 17:11:14 2002
@@ -52,7 +52,7 @@
 
 
 /*
- * The hardware dependent description for this timer.
+ * The hardware dependant description for this timer.
  */
 static struct _snd_timer_hardware rtc_hw = {
 	flags:		SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
diff -Nru a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
--- a/sound/oss/ac97_codec.c	Wed Apr  3 17:11:14 2002
+++ b/sound/oss/ac97_codec.c	Wed Apr  3 17:11:14 2002
@@ -105,7 +105,9 @@
 	{0x41445340, "Analog Devices AD1881",	&null_ops},
 	{0x41445348, "Analog Devices AD1881A",	&null_ops},
 	{0x41445360, "Analog Devices AD1885",	&default_ops},
+	{0x41445361, "Analog Devices AD1886",	&default_ops},
 	{0x41445460, "Analog Devices AD1885",	&default_ops},
+	{0x41445461, "Analog Devices AD1886",	&default_ops},
 	{0x414B4D00, "Asahi Kasei AK4540",	&null_ops},
 	{0x414B4D01, "Asahi Kasei AK4542",	&null_ops},
 	{0x414B4D02, "Asahi Kasei AK4543",	&null_ops},
diff -Nru a/sound/oss/ad1848.h b/sound/oss/ad1848.h
--- a/sound/oss/ad1848.h	Wed Apr  3 17:11:13 2002
+++ b/sound/oss/ad1848.h	Wed Apr  3 17:11:13 2002
@@ -1,8 +1,3 @@
-/*
- * ad1848.c
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- */
 
 #define AD_F_CS4231     0x0001  /* Returned if a CS4232 (or compatible) detected */
 #define AD_F_CS4248     0x0001  /* Returned if a CS4248 (or compatible) detected */
diff -Nru a/sound/oss/cs4232.h b/sound/oss/cs4232.h
--- a/sound/oss/cs4232.h	Wed Apr  3 17:11:14 2002
+++ b/sound/oss/cs4232.h	Wed Apr  3 17:11:14 2002
@@ -1,9 +1,3 @@
-/*
- *	cs4232.h
- *
- * Copyright: Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 int probe_cs4232 (struct address_info *hw_config,int useisapnp);
 void attach_cs4232 (struct address_info *hw_config);
diff -Nru a/sound/oss/gus.h b/sound/oss/gus.h
--- a/sound/oss/gus.h	Wed Apr  3 17:11:14 2002
+++ b/sound/oss/gus.h	Wed Apr  3 17:11:14 2002
@@ -1,9 +1,3 @@
-/*
- * gus.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 #include "ad1848.h"
 
diff -Nru a/sound/oss/mad16.c b/sound/oss/mad16.c
--- a/sound/oss/mad16.c	Wed Apr  3 17:11:14 2002
+++ b/sound/oss/mad16.c	Wed Apr  3 17:11:14 2002
@@ -42,6 +42,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/module.h>
+#include <linux/gameport.h>
 
 #include "sound_config.h"
 
@@ -51,6 +52,7 @@
 
 static int      mad16_conf;
 static int      mad16_cdsel;
+static struct gameport gameport;
 
 static int      already_initialized = 0;
 
@@ -664,13 +666,13 @@
 
 	outb((bits | dma_bits[dma] | dma2_bit), config_port);	/* Write IRQ+DMA setup */
 
-	hw_config->slots[0] = ad1848_init("MAD16 WSS", hw_config->io_base + 4,
+	hw_config->slots[0] = ad1848_init("mad16 WSS", hw_config->io_base + 4,
 					  hw_config->irq,
 					  dma,
 					  dma2, 0,
 					  hw_config->osp,
 					  THIS_MODULE);
-	request_region(hw_config->io_base, 4, "MAD16 WSS config");
+	request_region(hw_config->io_base, 4, "mad16 WSS config");
 }
 
 static int __init probe_mad16_mpu(struct address_info *hw_config)
@@ -1010,14 +1012,6 @@
 	}
 
 	printk(".\n");
-        printk(KERN_INFO "Joystick port ");
-        if (joystick == 1)
-                printk("enabled.\n");
-        else
-        {
-                joystick = 0;
-                printk("disabled.\n");
-        }
 
 	cfg.io_base = io;
 	cfg.irq = irq;
@@ -1038,6 +1032,18 @@
 	attach_mad16(&cfg);
 
 	found_mpu = probe_mad16_mpu(&cfg_mpu);
+
+	if (joystick == 1) {
+	        /* register gameport */
+                if (!request_region(0x201, 1, "mad16 gameport"))
+                        printk(KERN_ERR "mad16: gameport address 0x201 already in use\n");
+                else {
+			printk(KERN_ERR "mad16: gameport enabled at 0x201\n");
+                        gameport.io = 0x201;
+		        gameport_register_port(&gameport);
+                }
+	}
+	else printk(KERN_ERR "mad16: gameport disabled.\n");
 	return 0;
 }
 
@@ -1055,16 +1061,17 @@
 static int __init setup_mad16(char *str)
 {
         /* io, irq */
-	int ints[7];
+	int ints[8];
 	
 	str = get_options(str, ARRAY_SIZE(ints), ints);
 
-	io	= ints[1];
-	irq	= ints[2];
-	dma	= ints[3];
-	dma16	= ints[4];
-	mpu_io	= ints[5];
-	mpu_irq = ints[6];
+	io	 = ints[1];
+	irq	 = ints[2];
+	dma	 = ints[3];
+	dma16	 = ints[4];
+	mpu_io	 = ints[5];
+	mpu_irq  = ints[6];
+	joystick = ints[7];
 
 	return 1;
 }
diff -Nru a/sound/oss/mpu401.h b/sound/oss/mpu401.h
--- a/sound/oss/mpu401.h	Wed Apr  3 17:11:15 2002
+++ b/sound/oss/mpu401.h	Wed Apr  3 17:11:15 2002
@@ -1,9 +1,3 @@
-/*
- *	uart401.h 
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 /*	From uart401.c */
 int probe_uart401 (struct address_info *hw_config, struct module *owner);
diff -Nru a/sound/oss/opl3.h b/sound/oss/opl3.h
--- a/sound/oss/opl3.h	Wed Apr  3 17:11:13 2002
+++ b/sound/oss/opl3.h	Wed Apr  3 17:11:13 2002
@@ -1,9 +1,3 @@
-/*
- *	opl3.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 int opl3_detect (int ioaddr, int *osp);
 int opl3_init(int ioaddr, int *osp, struct module *owner);
diff -Nru a/sound/oss/pas2.h b/sound/oss/pas2.h
--- a/sound/oss/pas2.h	Wed Apr  3 17:11:14 2002
+++ b/sound/oss/pas2.h	Wed Apr  3 17:11:14 2002
@@ -1,9 +1,3 @@
-/*
- * pas2.h
- *
- * Copyright:	Christoph Hellwig <chhellwig@gmx.net>
- *
- */
 
 /*	From pas_card.c	*/
 int pas_set_intr(int mask);
diff -Nru a/sound/oss/pss.c b/sound/oss/pss.c
--- a/sound/oss/pss.c	Wed Apr  3 17:11:15 2002
+++ b/sound/oss/pss.c	Wed Apr  3 17:11:15 2002
@@ -48,7 +48,7 @@
  *          Added module parameter pss_firmware to allow the user to tell 
  *          the driver where the fireware file is located.  The default 
  *          setting is the previous hardcoded setting "/etc/sound/pss_synth".
- * 00-03-03: Christoph Hellwig <chhellwig@gmx.net>
+ * 00-03-03: Christoph Hellwig <chhellwig@infradead.org>
  *	    Adapted to module_init/module_exit
  * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
  *	    Added __init to probe_pss(), attach_pss() and probe_pss_mpu()
