diff -u --recursive --new-file v2.4.11/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog
--- v2.4.11/linux/Documentation/filesystems/devfs/ChangeLog	Tue Oct  9 17:06:51 2001
+++ linux/Documentation/filesystems/devfs/ChangeLog	Wed Oct 10 23:23:24 2001
@@ -1759,3 +1759,15 @@
 Changes for patch v193
 
 - Went back to global rwsem for symlinks (refcount scheme no good)
+===============================================================================
+Changes for patch v194
+
+- Fixed overrun in <devfs_link> by removing function (not needed)
+
+- Updated README from master HTML file
+===============================================================================
+Changes for patch v195
+
+- Fixed buffer underrun in <try_modload>
+
+- Moved down_read() from <search_for_entry_in_dir> to <find_entry>
diff -u --recursive --new-file v2.4.11/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README
--- v2.4.11/linux/Documentation/filesystems/devfs/README	Sun Sep 23 11:40:54 2001
+++ linux/Documentation/filesystems/devfs/README	Wed Oct 10 23:23:24 2001
@@ -3,7 +3,7 @@
 
 Linux Devfs (Device File System) FAQ
 Richard Gooch
-23-AUG-2001
+29-SEP-2001
 
 -----------------------------------------------------------------------------
 
@@ -1753,7 +1753,7 @@
 
 Douglas Gilbert has written yet another useful document at
 
-http://www.torque.net/scsi/linux_scsi_24/ which
+http://www.torque.net/scsi/SCSI-2.4-HOWTO/ which
 discusses the Linux SCSI subsystem in 2.4.
 
 
diff -u --recursive --new-file v2.4.11/linux/Makefile linux/Makefile
--- v2.4.11/linux/Makefile	Tue Oct  9 17:06:51 2001
+++ linux/Makefile	Wed Oct 10 23:42:46 2001
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 11
+SUBLEVEL = 12
 EXTRAVERSION =
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
@@ -300,7 +300,8 @@
 $(TOPDIR)/include/linux/compile.h: include/linux/compile.h
 
 newversion:
-	. scripts/mkversion > .version
+	. scripts/mkversion > .tmpversion
+	@mv -f .tmpversion .version
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
 	@echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
diff -u --recursive --new-file v2.4.11/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.4.11/linux/arch/sparc/kernel/process.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc/kernel/process.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.155 2001/02/13 01:16:43 davem Exp $
+/*  $Id: process.c,v 1.156 2001/10/02 02:22:26 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.11/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.4.11/linux/arch/sparc/kernel/systbls.S	Sun Aug 13 12:01:54 2000
+++ linux/arch/sparc/kernel/systbls.S	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.99 2000/08/12 20:49:49 jj Exp $
+/* $Id: systbls.S,v 1.100 2001/10/09 10:54:38 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -46,7 +46,7 @@
 /*125*/	.long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
 /*130*/	.long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 /*135*/	.long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
-/*140*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+/*140*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_gettid, sys_getrlimit
 /*145*/	.long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 /*155*/	.long sys_fcntl64, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.11/linux/arch/sparc64/defconfig	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/defconfig	Wed Oct 10 23:42:46 2001
@@ -567,6 +567,7 @@
 CONFIG_VFAT_FS=m
 CONFIG_EFS_FS=m
 # CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
 CONFIG_CRAMFS=m
 # CONFIG_TMPFS is not set
 CONFIG_RAMFS=m
@@ -737,6 +738,7 @@
 CONFIG_USB_MDC800=m
 CONFIG_USB_SCANNER=m
 CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
 
 #
 # USB Multimedia devices
@@ -773,11 +775,14 @@
 CONFIG_USB_SERIAL_EMPEG=m
 CONFIG_USB_SERIAL_FTDI_SIO=m
 CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IR is not set
 CONFIG_USB_SERIAL_EDGEPORT=m
 CONFIG_USB_SERIAL_KEYSPAN_PDA=m
 CONFIG_USB_SERIAL_KEYSPAN=m
 # CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
 # CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/kernel/dtlb_backend.S linux/arch/sparc64/kernel/dtlb_backend.S
--- v2.4.11/linux/arch/sparc64/kernel/dtlb_backend.S	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/kernel/dtlb_backend.S	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.15 2001/09/24 21:54:09 davem Exp $
+/* $Id: dtlb_backend.S,v 1.16 2001/10/09 04:02:11 davem Exp $
  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
  *                 This is included directly into the trap table.
  *
@@ -41,23 +41,25 @@
 	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
 	add		%g3, %g3, %g5			! Compute VPTE base
 	cmp		%g4, %g5			! VPTE miss?
-	blu,pn		%xcc, from_tl1_trap		! Fall to tl0 miss
+	bgeu,pt		%xcc, 1f			! Continue here
 	 andcc		%g4, TAG_CONTEXT_BITS, %g5	! From Nucleus? (for tl0 miss)
-	sllx		%g6, VPTE_SHIFT, %g4		! Position TAG_ACCESS
-	or		%g4, %g5, %g4			! Prepare TAG_ACCESS
-	mov		TSB_REG, %g1			! Grab TSB reg
+	ba,pt		%xcc, from_tl1_trap		! Fall to tl0 miss
+	 rdpr		%tl, %g5			! For tl0 miss TL==3 test
+1:	sllx		%g6, VPTE_SHIFT, %g4		! Position TAG_ACCESS
 
 /* TLB1 ** ICACHE line 2: Quick VPTE miss	  	*/
+	or		%g4, %g5, %g4			! Prepare TAG_ACCESS
+	mov		TSB_REG, %g1			! Grab TSB reg
 	ldxa		[%g1] ASI_DMMU, %g5		! Doing PGD caching?
 	srlx		%g6, (TLB_PMD_SHIFT - 1), %g1	! Position PMD offset
 	be,pn		%xcc, sparc64_vpte_nucleus	! Is it from Nucleus?
 	 and		%g1, TLB_PMD_MASK, %g1		! Mask PMD offset bits
 	brnz,pt		%g5, sparc64_vpte_continue	! Yep, go like smoke
 	 add		%g1, %g1, %g1			! Position PMD offset some more
-	srlx		%g6, (TLB_PGD_SHIFT - 2), %g5	! Position PGD offset
-	and		%g5, TLB_PGD_MASK, %g5		! Mask PGD offset
 
 /* TLB1 ** ICACHE line 3: Quick VPTE miss	  	*/
+	srlx		%g6, (TLB_PGD_SHIFT - 2), %g5	! Position PGD offset
+	and		%g5, TLB_PGD_MASK, %g5		! Mask PGD offset
 	lduwa		[%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
 	brz,pn		%g5, vpte_noent			! Valid?
 sparc64_kpte_continue:
@@ -66,18 +68,16 @@
 	lduwa		[%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
 	sllx		%g5, 11, %g5			! Shift into place
 	brz,pn		%g5, vpte_noent			! Valid?
+
+/* TLB1 ** ICACHE line 4: Quick VPTE miss	  	*/
 	 FILL_VALID_SZ_BITS1(%g1)			! Put _PAGE_VALID into %g1
 	FILL_VALID_SZ_BITS2(%g1)			! Put _PAGE_VALID into %g1
 	or		%g5, VPTE_BITS, %g5		! Prepare VPTE data
-
-/* TLB1 ** ICACHE line 4: Quick VPTE miss	  	*/
 	or		%g5, %g1, %g5			! ...
 	mov		TLB_SFSR, %g1			! Restore %g1 value
 	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Load VPTE into TLB
 	stxa		%g4, [%g1 + %g1] ASI_DMMU	! Restore previous TAG_ACCESS
 	retry						! Load PTE once again
-	nop
-	nop
 	FILL_VALID_SZ_BITS_NOP
 
 #undef VPTE_SHIFT
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S
--- v2.4.11/linux/arch/sparc64/kernel/dtlb_base.S	Sun Sep 23 11:40:56 2001
+++ linux/arch/sparc64/kernel/dtlb_base.S	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.14 2001/09/11 02:20:23 kanoj Exp $
+/* $Id: dtlb_base.S,v 1.16 2001/10/09 04:02:11 davem Exp $
  * dtlb_base.S:	Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -65,27 +65,28 @@
 /* DTLB ** ICACHE line 1: Quick user TLB misses		*/
 	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
 	andcc		%g4, TAG_CONTEXT_BITS, %g0	! From Nucleus?
+	mov		1, %g5				! For TL==3 test
 from_tl1_trap:
 	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
 	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
+	cmp		%g5, 3				! Last trap level?
+	be,a,pn		%xcc, 1f			! Yep, use non-faulting load
+	 ldxa		[%g3 + %g6] ASI_SNF, %g5	! Load VPTE (no-VPTE-fault)
+
+/* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses	*/
 	ldxa		[%g3 + %g6] ASI_S, %g5		! Load VPTE
-1:	brlz,pt		%g5, 9f				! Valid, load into TLB
+1:	brgez,pn	%g5, longpath			! Invalid, branch out
 	 nop						! Delay-slot
-	ba,a,pt		%xcc, longpath			! Invalid, branch out
-
-/* DTLB ** ICACHE line 2: Quick kernel TLB misses	*/
-3:	brlz,pt		%g4, 9f				! Kernel virtual map?
-	 xor		%g2, %g4, %g5			! Finish bit twiddles
-	ba,pt		%xcc, kvmap			! Yep, go check for obp/vmalloc
-	 nop
-	nop
 9:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
 	retry						! Trap return
-longpath:
-	rdpr		%pstate, %g5			! Move into alternate globals
+3:	brlz,pt		%g4, 9b				! Kernel virtual map?
+	 xor		%g2, %g4, %g5			! Finish bit twiddles
+	ba,a,pt		%xcc, kvmap			! Yep, go check for obp/vmalloc
 
 /* DTLB ** ICACHE line 3: winfixups+real_faults		*/
+longpath:
+	rdpr		%pstate, %g5			! Move into alternate globals
 	wrpr		%g5, PSTATE_AG|PSTATE_MG, %pstate
 	rdpr		%tl, %g4			! See where we came from.
 	cmp		%g4, 1				! Is etrap/rtrap window fault?
@@ -93,10 +94,9 @@
 	ldxa		[%g4] ASI_DMMU, %g5		! Load faulting VA page
 	be,pt		%xcc, sparc64_realfault_common	! Jump to normal fault handling
 	 mov		FAULT_CODE_DTLB, %g4		! It was read from DTLB
-	ba,a,pt		%xcc, winfix_trampoline		! Call window fixup code
 
 /* DTLB ** ICACHE line 4: Unused...	*/
-	nop
+	ba,a,pt		%xcc, winfix_trampoline		! Call window fixup code
 	nop
 	nop
 	nop
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.4.11/linux/arch/sparc64/kernel/pci.c	Tue Jul  3 17:08:19 2001
+++ linux/arch/sparc64/kernel/pci.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.35 2001/06/13 06:34:30 davem Exp $
+/* $Id: pci.c,v 1.36 2001/10/06 00:38:25 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -317,6 +317,7 @@
 {
 	struct pcidev_cookie *pcp = pdev->sysdata;
 	struct pci_pbm_info *pbm;
+	struct pci_controller_info *p;
 	unsigned long space_size, user_offset, user_size;
 
 	if (!pcp)
@@ -325,12 +326,44 @@
 	if (!pbm)
 		return -ENXIO;
 
-	if (mmap_state == pci_mmap_io) {
-		space_size = (pbm->io_space.end -
-			      pbm->io_space.start) + 1;
+	p = pbm->parent;
+	if (p->pbms_same_domain) {
+		unsigned long lowest, highest;
+
+		lowest = ~0UL; highest = 0UL;
+		if (mmap_state == pci_mmap_io) {
+			if (p->pbm_A.io_space.flags) {
+				lowest = p->pbm_A.io_space.start;
+				highest = p->pbm_A.io_space.end + 1;
+			}
+			if (p->pbm_B.io_space.flags) {
+				if (lowest > p->pbm_B.io_space.start)
+					lowest = p->pbm_B.io_space.start;
+				if (highest < p->pbm_B.io_space.end + 1)
+					highest = p->pbm_B.io_space.end + 1;
+			}
+			space_size = highest - lowest;
+		} else {
+			if (p->pbm_A.mem_space.flags) {
+				lowest = p->pbm_A.mem_space.start;
+				highest = p->pbm_A.mem_space.end + 1;
+			}
+			if (p->pbm_B.mem_space.flags) {
+				if (lowest > p->pbm_B.mem_space.start)
+					lowest = p->pbm_B.mem_space.start;
+				if (highest < p->pbm_B.mem_space.end + 1)
+					highest = p->pbm_B.mem_space.end + 1;
+			}
+			space_size = highest - lowest;
+		}
 	} else {
-		space_size = (pbm->mem_space.end -
-			      pbm->mem_space.start) + 1;
+		if (mmap_state == pci_mmap_io) {
+			space_size = (pbm->io_space.end -
+				      pbm->io_space.start) + 1;
+		} else {
+			space_size = (pbm->mem_space.end -
+				      pbm->mem_space.start) + 1;
+		}
 	}
 
 	/* Make sure the request is in range. */
@@ -341,12 +374,31 @@
 	    (user_offset + user_size) > space_size)
 		return -EINVAL;
 
-	if (mmap_state == pci_mmap_io) {
-		vma->vm_pgoff = (pbm->io_space.start +
-				 user_offset) >> PAGE_SHIFT;
+	if (p->pbms_same_domain) {
+		unsigned long lowest = ~0UL;
+
+		if (mmap_state == pci_mmap_io) {
+			if (p->pbm_A.io_space.flags)
+				lowest = p->pbm_A.io_space.start;
+			if (p->pbm_B.io_space.flags &&
+			    lowest > p->pbm_B.io_space.start)
+				lowest = p->pbm_B.io_space.start;
+		} else {
+			if (p->pbm_A.mem_space.flags)
+				lowest = p->pbm_A.mem_space.start;
+			if (p->pbm_B.mem_space.flags &&
+			    lowest > p->pbm_B.mem_space.start)
+				lowest = p->pbm_B.mem_space.start;
+		}
+		vma->vm_pgoff = (lowest + user_offset) >> PAGE_SHIFT;
 	} else {
-		vma->vm_pgoff = (pbm->mem_space.start +
-				 user_offset) >> PAGE_SHIFT;
+		if (mmap_state == pci_mmap_io) {
+			vma->vm_pgoff = (pbm->io_space.start +
+					 user_offset) >> PAGE_SHIFT;
+		} else {
+			vma->vm_pgoff = (pbm->mem_space.start +
+					 user_offset) >> PAGE_SHIFT;
+		}
 	}
 
 	return 0;
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.4.11/linux/arch/sparc64/kernel/process.c	Tue Oct  9 17:06:51 2001
+++ linux/arch/sparc64/kernel/process.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.119 2001/09/07 21:04:40 kanoj Exp $
+/*  $Id: process.c,v 1.120 2001/10/02 02:22:26 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.11/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.4.11/linux/arch/sparc64/kernel/systbls.S	Wed Aug 23 09:30:13 2000
+++ linux/arch/sparc64/kernel/systbls.S	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.77 2000/08/22 10:09:10 jj Exp $
+/* $Id: systbls.S,v 1.78 2001/10/09 10:54:38 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -47,7 +47,7 @@
 	.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
-/*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+/*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_gettid, sys32_getrlimit
 	.word sys32_setrlimit, sys_pivot_root, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys32_fcntl64, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
@@ -106,7 +106,7 @@
 	.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
 	.word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
-/*140*/	.word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+/*140*/	.word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_gettid, sys_getrlimit
 	.word sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
diff -u --recursive --new-file v2.4.11/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.4.11/linux/drivers/net/acenic.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/net/acenic.c	Wed Oct 10 23:23:24 2001
@@ -2,7 +2,7 @@
  * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card
  *           and other Tigon based cards.
  *
- * Copyright 1998-2001 by Jes Sorensen, <jes@linuxcare.com>.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
  *
  * Thanks to Alteon and 3Com for providing hardware and documentation
  * enabling me to write this driver.
@@ -145,6 +145,10 @@
 #endif
 
 
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(a)
+#endif
+
 #ifndef wmb
 #define wmb()	mb()
 #endif
@@ -161,7 +165,7 @@
 #define SMP_CACHE_BYTES	L1_CACHE_BYTES
 #endif
 
-#if (BITS_PER_LONG == 64)
+#if (BITS_PER_LONG == 64) || defined(CONFIG_HIGHMEM)
 #define ACE_64BIT_PTR	1
 #endif
 
@@ -263,7 +267,6 @@
 #define pci_set_dma_mask(dev, mask)		dev->dma_mask = mask;
 #endif
 
-
 #if (LINUX_VERSION_CODE >= 0x02031b)
 #define NEW_NETINIT
 #define ACE_PROBE_ARG				void
@@ -271,6 +274,16 @@
 #define ACE_PROBE_ARG				struct net_device *dev
 #endif
 
+#ifndef min_t
+#define min_t(type,a,b)	(((a)<(b))?(a):(b))
+#endif
+
+#ifndef ARCH_HAS_PREFETCHW
+#ifndef prefetchw
+#define prefetchw(x)				{do{} while(0);}
+#endif
+#endif
+
 #define ACE_MAX_MOD_PARMS	8
 #define BOARD_IDX_STATIC	0
 #define BOARD_IDX_OVERFLOW	-1
@@ -514,7 +527,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.81 04/20/2001  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.83 09/30/2001  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -746,15 +759,20 @@
 
 #ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
-MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_LICENSE("GPL");
-
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM_DESC(link, "Acenic/3C985/NetGear link state");
+MODULE_PARM_DESC(trace, "Acenic/3C985/NetGear firmware trace level");
+MODULE_PARM_DESC(tx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first tx descriptor arrives");
+MODULE_PARM_DESC(max_tx_desc, "AceNIC/3C985/GA620 max number of transmit descriptors to wait");
+MODULE_PARM_DESC(rx_coal_tick, "AceNIC/3C985/GA620 max clock ticks to wait from first rx descriptor arrives");
+MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descriptors to wait");
 #endif
 
 
@@ -795,14 +813,12 @@
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
 
 			if (skb) {
-#ifndef DUMMY_PCI_UNMAP
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_std_skbuff[i].mapping;
 				pci_unmap_single(ap->pdev, mapping,
 						 ACE_STD_BUFSIZE - (2 + 16),
 						 PCI_DMA_FROMDEVICE);
-#endif
 
 				ap->rx_std_ring[i].size = 0;
 				ap->skb->rx_std_skbuff[i].skb = NULL;
@@ -814,14 +830,13 @@
 				struct sk_buff *skb = ap->skb->rx_mini_skbuff[i].skb;
 
 				if (skb) {
-#ifndef DUMMY_PCI_UNMAP
 					dma_addr_t mapping;
 
 					mapping = ap->skb->rx_mini_skbuff[i].mapping;
 					pci_unmap_single(ap->pdev, mapping,
 							 ACE_MINI_BUFSIZE - (2 + 16),
 							 PCI_DMA_FROMDEVICE);
-#endif
+
 					ap->rx_mini_ring[i].size = 0;
 					ap->skb->rx_mini_skbuff[i].skb = NULL;
 					dev_kfree_skb(skb);
@@ -831,14 +846,12 @@
 		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_jumbo_skbuff[i].skb;
 			if (skb) {
-#ifndef DUMMY_PCI_UNMAP
 				dma_addr_t mapping;
 
 				mapping = ap->skb->rx_jumbo_skbuff[i].mapping;
 				pci_unmap_single(ap->pdev, mapping,
 						 ACE_JUMBO_BUFSIZE - (2 + 16),
 						 PCI_DMA_FROMDEVICE);
-#endif
 
 				ap->rx_jumbo_ring[i].size = 0;
 				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
@@ -1766,6 +1779,8 @@
 
 	regs = ap->regs;
 
+	prefetchw(&ap->cur_rx_bufs);
+
 	idx = ap->rx_std_skbprd;
 
 	for (i = 0; i < nr_bufs; i++) {
@@ -1785,9 +1800,7 @@
 					 ACE_STD_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
-#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_std_skbuff[idx].mapping = mapping;
-#endif
 
 		rd = &ap->rx_std_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1831,6 +1844,8 @@
 
 	regs = ap->regs;
 
+	prefetchw(&ap->cur_mini_bufs);
+
 	idx = ap->rx_mini_skbprd;
 	for (i = 0; i < nr_bufs; i++) {
 		struct sk_buff *skb;
@@ -1849,9 +1864,7 @@
 					 ACE_MINI_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
-#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
-#endif
 
 		rd = &ap->rx_mini_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -1910,9 +1923,7 @@
 					 ACE_JUMBO_BUFSIZE - (2 + 16),
 					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
-#ifndef DUMMY_PCI_UNMAP
 		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
-#endif
 
 		rd = &ap->rx_jumbo_ring[idx];
 		set_aceaddr(&rd->addr, mapping);
@@ -2067,6 +2078,9 @@
 
 	idx = rxretcsm;
 
+	prefetchw(&ap->cur_rx_bufs);
+	prefetchw(&ap->cur_mini_bufs);
+	
 	while (idx != rxretprd) {
 		struct ring_info *rip;
 		struct sk_buff *skb;
@@ -2115,15 +2129,9 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-#ifndef DUMMY_PCI_UNMAP
 		pci_unmap_single(ap->pdev, rip->mapping, mapsize,
 				 PCI_DMA_FROMDEVICE);
-#endif
 		skb_put(skb, retdesc->size);
-#if 0
-		/* unncessary */
-		rxdesc->size = 0;
-#endif
 
 		/*
 		 * Fly baby, fly!
@@ -2182,14 +2190,11 @@
 
 	do {
 		struct sk_buff *skb;
-#ifndef DUMMY_PCI_UNMAP
 		dma_addr_t mapping;
-#endif
 		struct tx_ring_info *info;
 
 		info = ap->skb->tx_skbuff + idx;
 		skb = info->skb;
-#ifndef DUMMY_PCI_UNMAP
 		mapping = info->mapping;
 
 		if (mapping) {
@@ -2197,7 +2202,7 @@
 					 PCI_DMA_TODEVICE);
 			info->mapping = 0;
 		}
-#endif
+
 		if (skb) {
 			ap->stats.tx_packets++;
 			ap->stats.tx_bytes += skb->len;
@@ -2474,14 +2479,11 @@
 
 	for (i = 0; i < TX_RING_ENTRIES; i++) {
 		struct sk_buff *skb;
-#ifndef DUMMY_PCI_UNMAP
 		dma_addr_t mapping;
-#endif
 		struct tx_ring_info *info;
 
 		info = ap->skb->tx_skbuff + i;
 		skb = info->skb;
-#ifndef DUMMY_PCI_UNMAP
 		mapping = info->mapping;
 
 		if (mapping) {
@@ -2490,7 +2492,7 @@
 					 PCI_DMA_TODEVICE);
 			info->mapping = 0;
 		}
-#endif
+
 		if (skb) {
 			dev_kfree_skb(skb);
 			info->skb = NULL;
@@ -2516,9 +2518,6 @@
  * For now, let it stay here.
  */
 #if defined(CONFIG_HIGHMEM) && MAX_SKB_FRAGS
-#ifndef DUMMY_PCI_UNMAP
-#error Sorry, cannot DMA from high memory on this architecture.
-#endif
 
 #if defined(CONFIG_X86)
 #define DMAADDR_OFFSET	0
@@ -2565,10 +2564,9 @@
 
 	info = ap->skb->tx_skbuff + idx;
 	info->skb = tail;
-#ifndef DUMMY_PCI_UNMAP
 	info->mapping = addr;
 	info->maplen = skb->len;
-#endif
+
 	return addr;
 }
 
@@ -2673,10 +2671,9 @@
 			} else {
 				info->skb = NULL;
 			}
-#ifndef DUMMY_PCI_UNMAP
 			info->mapping = phys;
 			info->maplen = frag->size;
-#endif
+
 			ace_load_tx_bd(desc, phys, flagsize);
 		}
 	}
@@ -2998,7 +2995,7 @@
 
 	while (size > 0) {
 		tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
-			    min_t(u32, size, ACE_WINDOW_SIZE));
+				min_t(u32, size, ACE_WINDOW_SIZE));
 		tdest = (unsigned long)&regs->Window +
 			(dest & (ACE_WINDOW_SIZE - 1));
 		writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
diff -u --recursive --new-file v2.4.11/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.4.11/linux/drivers/net/acenic.h	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/acenic.h	Wed Oct 10 23:23:24 2001
@@ -582,28 +582,21 @@
 	aceaddr	stats2_ptr;
 };
 
-#if defined(CONFIG_X86) || defined(CONFIG_PPC)
-/* Intel has null pci_unmap_single, no reasons to remember mapping. */
-#define DUMMY_PCI_UNMAP
-#endif
 
 struct ring_info {
 	struct sk_buff		*skb;
-#ifndef DUMMY_PCI_UNMAP
 	dma_addr_t		mapping;
-#endif
 };
 
-/* Funny... As soon as we add maplen on alpha, it starts to work
+/*
+ * Funny... As soon as we add maplen on alpha, it starts to work
  * much slower. Hmm... is it because struct does not fit to one cacheline?
  * So, split tx_ring_info.
  */
 struct tx_ring_info {
 	struct sk_buff		*skb;
-#ifndef DUMMY_PCI_UNMAP
 	dma_addr_t		mapping;
 	int			maplen;
-#endif
 };
 
 /*
diff -u --recursive --new-file v2.4.11/linux/drivers/net/aironet4500.h linux/drivers/net/aironet4500.h
--- v2.4.11/linux/drivers/net/aironet4500.h	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/aironet4500.h	Wed Oct 10 23:23:24 2001
@@ -1531,7 +1531,6 @@
 extern int 		awc_start_xmit(struct sk_buff *, struct net_device *);
 extern void 		awc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 extern struct net_device_stats *	awc_get_stats(struct net_device *dev);
-extern int 		awc_rx(struct net_device *dev, struct awc_fid * rx_fid);
 extern void		awc_set_multicast_list(struct net_device *dev);
 extern int awc_change_mtu(struct net_device *dev, int new_mtu);  
 extern int 		awc_close(struct net_device *dev);
diff -u --recursive --new-file v2.4.11/linux/drivers/net/at1700.c linux/drivers/net/at1700.c
--- v2.4.11/linux/drivers/net/at1700.c	Tue Oct  9 17:06:51 2001
+++ linux/drivers/net/at1700.c	Wed Oct 10 23:24:09 2001
@@ -158,7 +158,7 @@
 extern int at1700_probe(struct net_device *dev);
 
 static int at1700_probe1(struct net_device *dev, int ioaddr);
-static int read_eeprom(int ioaddr, int location);
+static int read_eeprom(long ioaddr, int location);
 static int net_open(struct net_device *dev);
 static int	net_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
diff -u --recursive --new-file v2.4.11/linux/drivers/net/macsonic.c linux/drivers/net/macsonic.c
--- v2.4.11/linux/drivers/net/macsonic.c	Sun Sep 23 11:40:58 2001
+++ linux/drivers/net/macsonic.c	Wed Oct 10 23:23:24 2001
@@ -168,6 +168,8 @@
 	if ((lp->rba = (char *)
 	     kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) {
 		printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name);
+		kfree(lp->sonic_desc);
+		lp->sonic_desc = NULL;
 		return -ENOMEM;
 	}
 
@@ -322,7 +324,7 @@
 		/* methinks this will always be true but better safe than sorry */
 		if (dev->priv == NULL) {
 			dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
-			if (!dev->priv) /* FIXME: kfree dev if necessary */
+			if (!dev->priv)
 				return -ENOMEM;
 		}
 	} else {
@@ -518,9 +520,14 @@
 
 	if (dev) {
 		dev = init_etherdev(dev, sizeof(struct sonic_local));
+		if (!dev)
+			return -ENOMEM;
 		/* methinks this will always be true but better safe than sorry */
-		if (dev->priv == NULL)
+		if (dev->priv == NULL) {
 			dev->priv = kmalloc(sizeof(struct sonic_local), GFP_KERNEL);
+			if (!dev->priv) /* FIXME: kfree dev if necessary */
+				return -ENOMEM;
+		}
 	} else {
 		dev = init_etherdev(NULL, sizeof(struct sonic_local));
 	}
diff -u --recursive --new-file v2.4.11/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.11/linux/drivers/net/sk98lin/skge.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/net/sk98lin/skge.c	Wed Oct 10 23:23:24 2001
@@ -228,7 +228,7 @@
  *		<linux/string.h>
  *		<linux/errno.h>
  *		<linux/ioport.h>
- *		<linux/malloc.h>
+ *		<linux/slab.h>
  *		<linux/interrupt.h>
  *		<linux/pci.h>
  *		<asm/byteorder.h>
diff -u --recursive --new-file v2.4.11/linux/drivers/net/sonic.c linux/drivers/net/sonic.c
--- v2.4.11/linux/drivers/net/sonic.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/sonic.c	Wed Oct 10 23:23:24 2001
@@ -28,13 +28,13 @@
  */
 static int sonic_open(struct net_device *dev)
 {
-    if (sonic_debug > 2)
-      printk("sonic_open: initializing sonic driver.\n");
-    
-    /*
-     * We don't need to deal with auto-irq stuff since we
-     * hardwire the sonic interrupt.
-     */
+	if (sonic_debug > 2)
+		printk("sonic_open: initializing sonic driver.\n");
+
+	/*
+	 * We don't need to deal with auto-irq stuff since we
+	 * hardwire the sonic interrupt.
+	 */
 /*
  * XXX Horrible work around:  We install sonic_interrupt as fast interrupt.
  * This means that during execution of the handler interrupt are disabled
@@ -42,335 +42,339 @@
  * this glue works ok under all situations.
  */
 //    if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
-    if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {
-	printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
-	return -EAGAIN;
-    }
-
-    /*
-     * Initialize the SONIC
-     */
-    sonic_init(dev);
-
-    dev->tbusy = 0;
-    dev->interrupt = 0;
-    dev->start = 1;
-
-    if (sonic_debug > 2)
-      printk("sonic_open: Initialization done.\n");
-	
-    return 0;
+	if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT,
+	                      "sonic", dev)) {
+		printk("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+
+	/*
+	 * Initialize the SONIC
+	 */
+	sonic_init(dev);
+
+	netif_start_queue(dev);
+
+	if (sonic_debug > 2)
+		printk("sonic_open: Initialization done.\n");
+
+	return 0;
 }
 
 
 /*
  * Close the SONIC device
  */
-static int
-sonic_close(struct net_device *dev)
+static int sonic_close(struct net_device *dev)
 {
-    unsigned int base_addr = dev->base_addr;
-    
-    if (sonic_debug > 2)
-      printk ("sonic_close\n");
-
-    dev->tbusy = 1;
-    dev->start = 0;
-    
-    /*
-     * stop the SONIC, disable interrupts
-     */
-    SONIC_WRITE(SONIC_ISR,0x7fff);
-    SONIC_WRITE(SONIC_IMR,0);
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+	unsigned int base_addr = dev->base_addr;
+
+	if (sonic_debug > 2)
+		printk("sonic_close\n");
+
+	netif_stop_queue(dev);
+
+	/*
+	 * stop the SONIC, disable interrupts
+	 */
+	SONIC_WRITE(SONIC_ISR, 0x7fff);
+	SONIC_WRITE(SONIC_IMR, 0);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
 
-    sonic_free_irq(dev->irq, dev);		/* release the IRQ */
+	sonic_free_irq(dev->irq, dev);	/* release the IRQ */
 
-    return 0;
+	return 0;
 }
 
+static void sonic_tx_timeout(struct net_device *dev)
+{
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	printk("%s: transmit timed out.\n", dev->name);
+
+	/* Try to restart the adaptor. */
+	sonic_init(dev);
+	lp->stats.tx_errors++;
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
 
 /*
  * transmit packet
  */
 static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-    struct sonic_local *lp = (struct sonic_local *)dev->priv;
-    unsigned int base_addr = dev->base_addr;
-    unsigned int laddr;
-    int entry,length;
-    
-    if (sonic_debug > 2)
-      printk("sonic_send_packet: skb=%p, dev=%p\n",skb,dev);
-  
-    if (dev->tbusy) {
-	int tickssofar = jiffies - dev->trans_start;
-
-	/* If we get here, some higher level has decided we are broken.
-	 There should really be a "kick me" function call instead. */
-      
-	if (sonic_debug > 1)
-	  printk("sonic_send_packet: called with dev->tbusy = 1 !\n");
-	
-	if (tickssofar < 5)
-	  return 1;
-	
-	printk("%s: transmit timed out.\n", dev->name);
-	
-	/* Try to restart the adaptor. */
-	sonic_init(dev);
-	dev->tbusy=0;
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	unsigned int base_addr = dev->base_addr;
+	unsigned int laddr;
+	int entry, length;
+
+	netif_stop_queue(dev);
+
+	if (sonic_debug > 2)
+		printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev);
+
+	/* 
+	 * Block a timer-based transmit from overlapping.  This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	/*
+	 * Map the packet data into the logical DMA address space
+	 */
+	if ((laddr = vdma_alloc(PHYSADDR(skb->data), skb->len)) == ~0UL) {
+		printk("%s: no VDMA entry for transmit available.\n",
+		       dev->name);
+		dev_kfree_skb(skb);
+		netif_start_queue(dev);
+		return 1;
+	}
+	entry = lp->cur_tx & SONIC_TDS_MASK;
+	lp->tx_laddr[entry] = laddr;
+	lp->tx_skb[entry] = skb;
+
+	length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+	flush_cache_all();
+
+	/*
+	 * Setup the transmit descriptor and issue the transmit command.
+	 */
+	lp->tda[entry].tx_status = 0;	/* clear status */
+	lp->tda[entry].tx_frag_count = 1;	/* single fragment */
+	lp->tda[entry].tx_pktsize = length;	/* length of packet */
+	lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;
+	lp->tda[entry].tx_frag_ptr_h = laddr >> 16;
+	lp->tda[entry].tx_frag_size = length;
+	lp->cur_tx++;
+	lp->stats.tx_bytes += length;
+
+	if (sonic_debug > 2)
+		printk("sonic_send_packet: issueing Tx command\n");
+
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
+
 	dev->trans_start = jiffies;
-    }
 
-    /* 
-     * Block a timer-based transmit from overlapping.  This could better be
-     * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
-     */
-    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-	printk("%s: Transmitter access conflict.\n", dev->name);
-	return 1;
-    }
-    
-    /*
-     * Map the packet data into the logical DMA address space
-     */
-    if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) {
-	printk("%s: no VDMA entry for transmit available.\n",dev->name);
-	dev_kfree_skb(skb);
-	dev->tbusy = 0;
-	return 1;
-    }
-    entry = lp->cur_tx & SONIC_TDS_MASK;    
-    lp->tx_laddr[entry] = laddr;
-    lp->tx_skb[entry] = skb;
-    
-    length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
-    flush_cache_all();
-    
-    /*
-     * Setup the transmit descriptor and issue the transmit command.
-     */
-    lp->tda[entry].tx_status = 0;		/* clear status */
-    lp->tda[entry].tx_frag_count = 1;		/* single fragment */
-    lp->tda[entry].tx_pktsize = length;		/* length of packet */    
-    lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;
-    lp->tda[entry].tx_frag_ptr_h = laddr >> 16;
-    lp->tda[entry].tx_frag_size  = length;
-    lp->cur_tx++;
-    lp->stats.tx_bytes += length;
-    
-    if (sonic_debug > 2)
-      printk("sonic_send_packet: issueing Tx command\n");
-
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);
-
-    dev->trans_start = jiffies;
-
-    if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS)
-      dev->tbusy = 0;
-    else
-      lp->tx_full = 1;
-    
-    return 0;
+	if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS)
+		netif_start_queue(dev);
+	else
+		lp->tx_full = 1;
+
+	return 0;
 }
 
-
 /*
  * The typical workload of the driver:
  * Handle the network interface interrupts.
  */
-static void
-sonic_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-    struct net_device *dev = (struct net_device *)dev_id;
-    unsigned int base_addr = dev->base_addr;
-    struct sonic_local *lp;
-    int status;
-
-    if (dev == NULL) {
-	printk ("sonic_interrupt: irq %d for unknown device.\n", irq);
-	return;
-    }
-    dev->interrupt = 1;
-    lp = (struct sonic_local *)dev->priv;
-
-    status = SONIC_READ(SONIC_ISR);
-    SONIC_WRITE(SONIC_ISR,0x7fff); /* clear all bits */
-  
-    if (sonic_debug > 2)
-      printk("sonic_interrupt: ISR=%x\n",status);
-
-    if (status & SONIC_INT_PKTRX) {
-	sonic_rx(dev);				/* got packet(s) */
-    }
-    
-    if (status & SONIC_INT_TXDN) {
-	int dirty_tx = lp->dirty_tx;
-
-	while (dirty_tx < lp->cur_tx) {
-	    int entry = dirty_tx & SONIC_TDS_MASK;
-	    int status = lp->tda[entry].tx_status;
-
-	    if (sonic_debug > 3)
-	      printk ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",
-		      status,lp->cur_tx,lp->dirty_tx);
-
-	    if (status == 0) {
-		/* It still hasn't been Txed, kick the sonic again */
-		SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);		
-		break;
-	    }
-
-	    /* put back EOL and free descriptor */
-	    lp->tda[entry].tx_frag_count = 0;
-	    lp->tda[entry].tx_status = 0;
-
-	    if (status & 0x0001)
-	      lp->stats.tx_packets++;
-	    else {
+	struct net_device *dev = (struct net_device *) dev_id;
+	unsigned int base_addr = dev->base_addr;
+	struct sonic_local *lp;
+	int status;
+
+	if (dev == NULL) {
+		printk("sonic_interrupt: irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	lp = (struct sonic_local *) dev->priv;
+
+	status = SONIC_READ(SONIC_ISR);
+	SONIC_WRITE(SONIC_ISR, 0x7fff);	/* clear all bits */
+
+	if (sonic_debug > 2)
+		printk("sonic_interrupt: ISR=%x\n", status);
+
+	if (status & SONIC_INT_PKTRX) {
+		sonic_rx(dev);	/* got packet(s) */
+	}
+
+	if (status & SONIC_INT_TXDN) {
+		int dirty_tx = lp->dirty_tx;
+
+		while (dirty_tx < lp->cur_tx) {
+			int entry = dirty_tx & SONIC_TDS_MASK;
+			int status = lp->tda[entry].tx_status;
+
+			if (sonic_debug > 3)
+				printk
+				    ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",
+				     status, lp->cur_tx, lp->dirty_tx);
+
+			if (status == 0) {
+				/* It still hasn't been Txed, kick the sonic again */
+				SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
+				break;
+			}
+
+			/* put back EOL and free descriptor */
+			lp->tda[entry].tx_frag_count = 0;
+			lp->tda[entry].tx_status = 0;
+
+			if (status & 0x0001)
+				lp->stats.tx_packets++;
+			else {
+				lp->stats.tx_errors++;
+				if (status & 0x0642)
+					lp->stats.tx_aborted_errors++;
+				if (status & 0x0180)
+					lp->stats.tx_carrier_errors++;
+				if (status & 0x0020)
+					lp->stats.tx_window_errors++;
+				if (status & 0x0004)
+					lp->stats.tx_fifo_errors++;
+			}
+
+			/* We must free the original skb */
+			if (lp->tx_skb[entry]) {
+				dev_kfree_skb(lp->tx_skb[entry]);
+				lp->tx_skb[entry] = 0;
+			}
+			/* and the VDMA address */
+			vdma_free(lp->tx_laddr[entry]);
+			dirty_tx++;
+		}
+
+		if (lp->tx_full
+		    && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {
+			/* The ring is no longer full, clear tbusy. */
+			lp->tx_full = 0;
+			netif_wake_queue(dev);
+		}
+
+		lp->dirty_tx = dirty_tx;
+	}
+
+	/*
+	 * check error conditions
+	 */
+	if (status & SONIC_INT_RFO) {
+		printk("%s: receive fifo underrun\n", dev->name);
+		lp->stats.rx_fifo_errors++;
+	}
+	if (status & SONIC_INT_RDE) {
+		printk("%s: receive descriptors exhausted\n", dev->name);
+		lp->stats.rx_dropped++;
+	}
+	if (status & SONIC_INT_RBE) {
+		printk("%s: receive buffer exhausted\n", dev->name);
+		lp->stats.rx_dropped++;
+	}
+	if (status & SONIC_INT_RBAE) {
+		printk("%s: receive buffer area exhausted\n", dev->name);
+		lp->stats.rx_dropped++;
+	}
+
+	/* counter overruns; all counters are 16bit wide */
+	if (status & SONIC_INT_FAE)
+		lp->stats.rx_frame_errors += 65536;
+	if (status & SONIC_INT_CRC)
+		lp->stats.rx_crc_errors += 65536;
+	if (status & SONIC_INT_MP)
+		lp->stats.rx_missed_errors += 65536;
+
+	/* transmit error */
+	if (status & SONIC_INT_TXER)
 		lp->stats.tx_errors++;
-		if (status & 0x0642) lp->stats.tx_aborted_errors++;
-		if (status & 0x0180) lp->stats.tx_carrier_errors++;
-		if (status & 0x0020) lp->stats.tx_window_errors++;
-		if (status & 0x0004) lp->stats.tx_fifo_errors++;
-	    }
-
-	    /* We must free the original skb */
-	    if (lp->tx_skb[entry]) {
-		dev_kfree_skb(lp->tx_skb[entry]);
-		lp->tx_skb[entry] = 0;
-	    }
-	    /* and the VDMA address */
-	    vdma_free(lp->tx_laddr[entry]);
-	    dirty_tx++;
-	}
-	
-	if (lp->tx_full && dev->tbusy
-	    && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) {
-	    /* The ring is no longer full, clear tbusy. */
-	    lp->tx_full = 0;
-	    dev->tbusy = 0;
-	    mark_bh(NET_BH);
-	}
-	
-	lp->dirty_tx = dirty_tx;
-    }
-    
-    /*
-     * check error conditions
-     */
-    if (status & SONIC_INT_RFO) {
-	printk ("%s: receive fifo underrun\n",dev->name);
-	lp->stats.rx_fifo_errors++;
-    }
-    if (status & SONIC_INT_RDE) {
-	printk ("%s: receive descriptors exhausted\n",dev->name);
-	lp->stats.rx_dropped++;
-    }
-    if (status & SONIC_INT_RBE) {
-	printk ("%s: receive buffer exhausted\n",dev->name);
-	lp->stats.rx_dropped++;	
-    }
-    if (status & SONIC_INT_RBAE) {
-	printk ("%s: receive buffer area exhausted\n",dev->name);
-	lp->stats.rx_dropped++;	
-    }
-
-    /* counter overruns; all counters are 16bit wide */
-    if (status & SONIC_INT_FAE)
-      lp->stats.rx_frame_errors += 65536;
-    if (status & SONIC_INT_CRC)
-      lp->stats.rx_crc_errors += 65536;
-    if (status & SONIC_INT_MP)
-      lp->stats.rx_missed_errors += 65536;
-
-    /* transmit error */
-    if (status & SONIC_INT_TXER)
-      lp->stats.tx_errors++;
-    
-    /*
-     * clear interrupt bits and return
-     */
-    SONIC_WRITE(SONIC_ISR,status);
-    dev->interrupt = 0;
-    return;
+
+	/*
+	 * clear interrupt bits and return
+	 */
+	SONIC_WRITE(SONIC_ISR, status);
 }
 
 /*
  * We have a good packet(s), get it/them out of the buffers.
  */
-static void
-sonic_rx(struct net_device *dev)
+static void sonic_rx(struct net_device *dev)
 {
-    unsigned int base_addr = dev->base_addr;
-    struct sonic_local *lp = (struct sonic_local *)dev->priv;
-    sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];
-    int status;
-
-    while (rd->in_use == 0) {
-	struct sk_buff *skb;
-	int pkt_len;
-	unsigned char *pkt_ptr;
-	
-	status = rd->rx_status;
-	if (sonic_debug > 3)
-	  printk ("status %x, cur_rx %d, cur_rra %x\n",status,lp->cur_rx,lp->cur_rra);
-	if (status & SONIC_RCR_PRX) {	    
-	    pkt_len = rd->rx_pktlen;
-	    pkt_ptr = (char *)sonic_chiptomem((rd->rx_pktptr_h << 16) +
-						      rd->rx_pktptr_l);
-	    
-	    if (sonic_debug > 3)
-	      printk ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", pkt_ptr,lp->rba,
-		      rd->rx_pktptr_h,rd->rx_pktptr_l,
-		      SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0));
-	
-	    /* Malloc up new buffer. */
-	    skb = dev_alloc_skb(pkt_len+2);
-	    if (skb == NULL) {
-		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
-		break;
-	    }
-	    skb->dev = dev;
-	    skb_reserve(skb,2);	/* 16 byte align */
-	    skb_put(skb,pkt_len);	/* Make room */
-	    eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0);
-	    skb->protocol=eth_type_trans(skb,dev);
-	    netif_rx(skb);			/* pass the packet to upper layers */
-	    dev->last_rx = jiffies;
-	    lp->stats.rx_packets++;
-	    lp->stats.rx_bytes += pkt_len;
-	    
-	} else {
-	    /* This should only happen, if we enable accepting broken packets. */
-	    lp->stats.rx_errors++;
-	    if (status & SONIC_RCR_FAER) lp->stats.rx_frame_errors++;
-	    if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++;
-	}
-	
-	rd->in_use = 1;
-	rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK];
-	/* now give back the buffer to the receive buffer area */
-	if (status & SONIC_RCR_LPKT) {
-	    /*
-	     * this was the last packet out of the current receice buffer
-	     * give the buffer back to the SONIC
-	     */
-	    lp->cur_rra += sizeof(sonic_rr_t);
-	    if (lp->cur_rra > (lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t)))
-		lp->cur_rra = lp->rra_laddr;
-	    SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff);
-	} else
-	    printk ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",dev->name);
-    }
-    /*
-     * If any worth-while packets have been received, dev_rint()
-     * has done a mark_bh(NET_BH) for us and will work on them
-     * when we get to the bottom-half routine.
-     */
-    return;
+	unsigned int base_addr = dev->base_addr;
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];
+	int status;
+
+	while (rd->in_use == 0) {
+		struct sk_buff *skb;
+		int pkt_len;
+		unsigned char *pkt_ptr;
+
+		status = rd->rx_status;
+		if (sonic_debug > 3)
+			printk("status %x, cur_rx %d, cur_rra %x\n",
+			       status, lp->cur_rx, lp->cur_rra);
+		if (status & SONIC_RCR_PRX) {
+			pkt_len = rd->rx_pktlen;
+			pkt_ptr =
+			    (char *)
+			    sonic_chiptomem((rd->rx_pktptr_h << 16) +
+					    rd->rx_pktptr_l);
+
+			if (sonic_debug > 3)
+				printk
+				    ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n",
+				     pkt_ptr, lp->rba, rd->rx_pktptr_h,
+				     rd->rx_pktptr_l,
+				     SONIC_READ(SONIC_RBWC1),
+				     SONIC_READ(SONIC_RBWC0));
+
+			/* Malloc up new buffer. */
+			skb = dev_alloc_skb(pkt_len + 2);
+			if (skb == NULL) {
+				printk
+				    ("%s: Memory squeeze, dropping packet.\n",
+				     dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align */
+			skb_put(skb, pkt_len);	/* Make room */
+			eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);	/* pass the packet to upper layers */
+			dev->last_rx = jiffies;
+			lp->stats.rx_packets++;
+			lp->stats.rx_bytes += pkt_len;
+
+		} else {
+			/* This should only happen, if we enable accepting broken packets. */
+			lp->stats.rx_errors++;
+			if (status & SONIC_RCR_FAER)
+				lp->stats.rx_frame_errors++;
+			if (status & SONIC_RCR_CRCR)
+				lp->stats.rx_crc_errors++;
+		}
+
+		rd->in_use = 1;
+		rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK];
+		/* now give back the buffer to the receive buffer area */
+		if (status & SONIC_RCR_LPKT) {
+			/*
+			 * this was the last packet out of the current receice buffer
+			 * give the buffer back to the SONIC
+			 */
+			lp->cur_rra += sizeof(sonic_rr_t);
+			if (lp->cur_rra >
+			    (lp->rra_laddr +
+			     (SONIC_NUM_RRS -
+			      1) * sizeof(sonic_rr_t))) lp->cur_rra =
+				    lp->rra_laddr;
+			SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff);
+		} else
+			printk
+			    ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
+			     dev->name);
+	}
+	/*
+	 * If any worth-while packets have been received, dev_rint()
+	 * has done a mark_bh(NET_BH) for us and will work on them
+	 * when we get to the bottom-half routine.
+	 */
 }
 
 
@@ -378,68 +382,71 @@
  * Get the current statistics.
  * This may be called with the device open or closed.
  */
-static struct net_device_stats *
-sonic_get_stats(struct net_device *dev)
+static struct net_device_stats *sonic_get_stats(struct net_device *dev)
 {
-    struct sonic_local *lp = (struct sonic_local *)dev->priv;
-    unsigned int base_addr = dev->base_addr;
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	unsigned int base_addr = dev->base_addr;
+
+	/* read the tally counter from the SONIC and reset them */
+	lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT);
+	SONIC_WRITE(SONIC_CRCT, 0xffff);
+	lp->stats.rx_frame_errors += SONIC_READ(SONIC_FAET);
+	SONIC_WRITE(SONIC_FAET, 0xffff);
+	lp->stats.rx_missed_errors += SONIC_READ(SONIC_MPT);
+	SONIC_WRITE(SONIC_MPT, 0xffff);
 
-    /* read the tally counter from the SONIC and reset them */
-    lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT);
-    SONIC_WRITE(SONIC_CRCT,0xffff);
-    lp->stats.rx_frame_errors += SONIC_READ(SONIC_FAET);
-    SONIC_WRITE(SONIC_FAET,0xffff);
-    lp->stats.rx_missed_errors += SONIC_READ(SONIC_MPT);
-    SONIC_WRITE(SONIC_MPT,0xffff);
-    
-    return &lp->stats;
+	return &lp->stats;
 }
 
 
 /*
  * Set or clear the multicast filter for this adaptor.
  */
-static void
-sonic_multicast_list(struct net_device *dev)
+static void sonic_multicast_list(struct net_device *dev)
 {
-    struct sonic_local *lp = (struct sonic_local *)dev->priv;    
-    unsigned int base_addr = dev->base_addr;    
-    unsigned int rcr;
-    struct dev_mc_list *dmi = dev->mc_list;
-    unsigned char *addr;
-    int i;
-
-    rcr = SONIC_READ(SONIC_RCR) & ~(SONIC_RCR_PRO | SONIC_RCR_AMC);
-    rcr |= SONIC_RCR_BRD; /* accept broadcast packets */
-    
-    if (dev->flags & IFF_PROMISC) {         /* set promiscuous mode */
-	rcr |= SONIC_RCR_PRO;
-    } else {
-	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) {
-	    rcr |= SONIC_RCR_AMC;
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	unsigned int base_addr = dev->base_addr;
+	unsigned int rcr;
+	struct dev_mc_list *dmi = dev->mc_list;
+	unsigned char *addr;
+	int i;
+
+	rcr = SONIC_READ(SONIC_RCR) & ~(SONIC_RCR_PRO | SONIC_RCR_AMC);
+	rcr |= SONIC_RCR_BRD;	/* accept broadcast packets */
+
+	if (dev->flags & IFF_PROMISC) {	/* set promiscuous mode */
+		rcr |= SONIC_RCR_PRO;
 	} else {
-	    if (sonic_debug > 2)
-	      printk ("sonic_multicast_list: mc_count %d\n",dev->mc_count);
-	    lp->cda.cam_enable = 1; /* always enable our own address */
-	    for (i = 1; i <= dev->mc_count; i++) {
-		addr = dmi->dmi_addr;
-		dmi = dmi->next;
-		lp->cda.cam_desc[i].cam_cap0 = addr[1] << 8 | addr[0];
-		lp->cda.cam_desc[i].cam_cap1 = addr[3] << 8 | addr[2];
-		lp->cda.cam_desc[i].cam_cap2 = addr[5] << 8 | addr[4];
-		lp->cda.cam_enable |= (1 << i);
-	    }
-	    SONIC_WRITE(SONIC_CDC,16);
-	    /* issue Load CAM command */
-	    SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);	    
-	    SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM);
-	}
-    }
-    
-    if (sonic_debug > 2)
-      printk("sonic_multicast_list: setting RCR=%x\n",rcr);
-    
-    SONIC_WRITE(SONIC_RCR,rcr);
+		if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) {
+			rcr |= SONIC_RCR_AMC;
+		} else {
+			if (sonic_debug > 2)
+				printk
+				    ("sonic_multicast_list: mc_count %d\n",
+				     dev->mc_count);
+			lp->cda.cam_enable = 1;	/* always enable our own address */
+			for (i = 1; i <= dev->mc_count; i++) {
+				addr = dmi->dmi_addr;
+				dmi = dmi->next;
+				lp->cda.cam_desc[i].cam_cap0 =
+				    addr[1] << 8 | addr[0];
+				lp->cda.cam_desc[i].cam_cap1 =
+				    addr[3] << 8 | addr[2];
+				lp->cda.cam_desc[i].cam_cap2 =
+				    addr[5] << 8 | addr[4];
+				lp->cda.cam_enable |= (1 << i);
+			}
+			SONIC_WRITE(SONIC_CDC, 16);
+			/* issue Load CAM command */
+			SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
+			SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
+		}
+	}
+
+	if (sonic_debug > 2)
+		printk("sonic_multicast_list: setting RCR=%x\n", rcr);
+
+	SONIC_WRITE(SONIC_RCR, rcr);
 }
 
 
@@ -448,168 +455,168 @@
  */
 static int sonic_init(struct net_device *dev)
 {
-    unsigned int base_addr = dev->base_addr;
-    unsigned int cmd;
-    struct sonic_local *lp = (struct sonic_local *)dev->priv;
-    unsigned int rra_start;
-    unsigned int rra_end;
-    int i;
-    
-    /*
-     * put the Sonic into software-reset mode and
-     * disable all interrupts
-     */
-    SONIC_WRITE(SONIC_ISR,0x7fff);
-    SONIC_WRITE(SONIC_IMR,0);
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
-  
-    /*
-     * clear software reset flag, disable receiver, clear and
-     * enable interrupts, then completely initialize the SONIC
-     */
-    SONIC_WRITE(SONIC_CMD,0);
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RXDIS);
-
-    /*
-     * initialize the receive resource area
-     */
-    if (sonic_debug > 2)
-      printk ("sonic_init: initialize receive resource area\n");
-    
-    rra_start = lp->rra_laddr & 0xffff;
-    rra_end   = (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff;
-  
-    for (i = 0; i < SONIC_NUM_RRS; i++) {
-	lp->rra[i].rx_bufadr_l = (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
-	lp->rra[i].rx_bufadr_h = (lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
-	lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
-	lp->rra[i].rx_bufsize_h = 0;
-    }
-
-    /* initialize all RRA registers */
-    SONIC_WRITE(SONIC_RSA,rra_start);
-    SONIC_WRITE(SONIC_REA,rra_end);
-    SONIC_WRITE(SONIC_RRP,rra_start);
-    SONIC_WRITE(SONIC_RWP,rra_end);
-    SONIC_WRITE(SONIC_URRA,lp->rra_laddr >> 16);
-    SONIC_WRITE(SONIC_EOBC,(SONIC_RBSIZE-2) >> 1);
-    
-    lp->cur_rra = lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t);
-
-    /* load the resource pointers */
-    if (sonic_debug > 3)
-      printk("sonic_init: issueing RRRA command\n");
-  
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RRRA);
-    i = 0;
-    while (i++ < 100) {
-	if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
-	  break;
-    }
-    
-    if (sonic_debug > 2)
-      printk("sonic_init: status=%x\n",SONIC_READ(SONIC_CMD));
-    
-    /*
-     * Initialize the receive descriptors so that they
-     * become a circular linked list, ie. let the last
-     * descriptor point to the first again.
-     */
-    if (sonic_debug > 2)
-      printk ("sonic_init: initialize receive descriptors\n");      
-    for (i=0; i<SONIC_NUM_RDS; i++) {
-	lp->rda[i].rx_status = 0;
-	lp->rda[i].rx_pktlen = 0;
-	lp->rda[i].rx_pktptr_l = 0;
-	lp->rda[i].rx_pktptr_h = 0;
-	lp->rda[i].rx_seqno = 0;
-	lp->rda[i].in_use = 1;		       	
-	lp->rda[i].link = lp->rda_laddr + (i+1) * sizeof (sonic_rd_t);
-    }
-    /* fix last descriptor */
-    lp->rda[SONIC_NUM_RDS-1].link = lp->rda_laddr;
-    lp->cur_rx = 0;
-    SONIC_WRITE(SONIC_URDA,lp->rda_laddr >> 16);
-    SONIC_WRITE(SONIC_CRDA,lp->rda_laddr & 0xffff);
-    
-    /* 
-     * initialize transmit descriptors
-     */
-    if (sonic_debug > 2)
-      printk ("sonic_init: initialize transmit descriptors\n");
-    for (i = 0; i < SONIC_NUM_TDS; i++) {
-	lp->tda[i].tx_status = 0;
-	lp->tda[i].tx_config = 0;
-	lp->tda[i].tx_pktsize = 0;
-	lp->tda[i].tx_frag_count = 0;
-	lp->tda[i].link = (lp->tda_laddr + (i+1) * sizeof (sonic_td_t)) | SONIC_END_OF_LINKS;
-    }
-    lp->tda[SONIC_NUM_TDS-1].link = (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS;    
-
-    SONIC_WRITE(SONIC_UTDA,lp->tda_laddr >> 16);
-    SONIC_WRITE(SONIC_CTDA,lp->tda_laddr & 0xffff);
-    lp->cur_tx = lp->dirty_tx = 0;
-    
-    /*
-     * put our own address to CAM desc[0]
-     */
-    lp->cda.cam_desc[0].cam_cap0 = dev->dev_addr[1] << 8 | dev->dev_addr[0];
-    lp->cda.cam_desc[0].cam_cap1 = dev->dev_addr[3] << 8 | dev->dev_addr[2];
-    lp->cda.cam_desc[0].cam_cap2 = dev->dev_addr[5] << 8 | dev->dev_addr[4];
-    lp->cda.cam_enable = 1;
-    
-    for (i=0; i < 16; i++)
-      lp->cda.cam_desc[i].cam_entry_pointer = i;
-
-    /*
-     * initialize CAM registers
-     */
-    SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
-    SONIC_WRITE(SONIC_CDC,16);
-    
-    /*
-     * load the CAM
-     */
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM);
-    
-    i = 0;
-    while (i++ < 100) {
-	if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
-	  break;
-    }
-    if (sonic_debug > 2) {
-	printk("sonic_init: CMD=%x, ISR=%x\n",
-	       SONIC_READ(SONIC_CMD),
-	       SONIC_READ(SONIC_ISR));
-    }
-
-    /*
-     * enable receiver, disable loopback
-     * and enable all interrupts
-     */
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RXEN | SONIC_CR_STP);
-    SONIC_WRITE(SONIC_RCR,SONIC_RCR_DEFAULT);
-    SONIC_WRITE(SONIC_TCR,SONIC_TCR_DEFAULT);
-    SONIC_WRITE(SONIC_ISR,0x7fff);
-    SONIC_WRITE(SONIC_IMR,SONIC_IMR_DEFAULT);
-
-    cmd = SONIC_READ(SONIC_CMD);
-    if ((cmd & SONIC_CR_RXEN) == 0 ||
-	(cmd & SONIC_CR_STP) == 0)
-      printk("sonic_init: failed, status=%x\n",cmd);
+	unsigned int base_addr = dev->base_addr;
+	unsigned int cmd;
+	struct sonic_local *lp = (struct sonic_local *) dev->priv;
+	unsigned int rra_start;
+	unsigned int rra_end;
+	int i;
+
+	/*
+	 * put the Sonic into software-reset mode and
+	 * disable all interrupts
+	 */
+	SONIC_WRITE(SONIC_ISR, 0x7fff);
+	SONIC_WRITE(SONIC_IMR, 0);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
+	/*
+	 * clear software reset flag, disable receiver, clear and
+	 * enable interrupts, then completely initialize the SONIC
+	 */
+	SONIC_WRITE(SONIC_CMD, 0);
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
+
+	/*
+	 * initialize the receive resource area
+	 */
+	if (sonic_debug > 2)
+		printk("sonic_init: initialize receive resource area\n");
+
+	rra_start = lp->rra_laddr & 0xffff;
+	rra_end =
+	    (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff;
+
+	for (i = 0; i < SONIC_NUM_RRS; i++) {
+		lp->rra[i].rx_bufadr_l =
+		    (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff;
+		lp->rra[i].rx_bufadr_h =
+		    (lp->rba_laddr + i * SONIC_RBSIZE) >> 16;
+		lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1;
+		lp->rra[i].rx_bufsize_h = 0;
+	}
 
-    if (sonic_debug > 2)
-      printk("sonic_init: new status=%x\n",SONIC_READ(SONIC_CMD));
+	/* initialize all RRA registers */
+	SONIC_WRITE(SONIC_RSA, rra_start);
+	SONIC_WRITE(SONIC_REA, rra_end);
+	SONIC_WRITE(SONIC_RRP, rra_start);
+	SONIC_WRITE(SONIC_RWP, rra_end);
+	SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
+	SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE - 2) >> 1);
 
-    return(0);
-}
+	lp->cur_rra =
+	    lp->rra_laddr + (SONIC_NUM_RRS - 1) * sizeof(sonic_rr_t);
 
-
-/*
- * Local variables:
- *  compile-command: "mipsel-linux-gcc -D__KERNEL__ -D__mips64 -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -mcpu=r4000 -c sonic.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
+	/* load the resource pointers */
+	if (sonic_debug > 3)
+		printk("sonic_init: issueing RRRA command\n");
+
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
+	i = 0;
+	while (i++ < 100) {
+		if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
+			break;
+	}
+
+	if (sonic_debug > 2)
+		printk("sonic_init: status=%x\n", SONIC_READ(SONIC_CMD));
+
+	/*
+	 * Initialize the receive descriptors so that they
+	 * become a circular linked list, ie. let the last
+	 * descriptor point to the first again.
+	 */
+	if (sonic_debug > 2)
+		printk("sonic_init: initialize receive descriptors\n");
+	for (i = 0; i < SONIC_NUM_RDS; i++) {
+		lp->rda[i].rx_status = 0;
+		lp->rda[i].rx_pktlen = 0;
+		lp->rda[i].rx_pktptr_l = 0;
+		lp->rda[i].rx_pktptr_h = 0;
+		lp->rda[i].rx_seqno = 0;
+		lp->rda[i].in_use = 1;
+		lp->rda[i].link =
+		    lp->rda_laddr + (i + 1) * sizeof(sonic_rd_t);
+	}
+	/* fix last descriptor */
+	lp->rda[SONIC_NUM_RDS - 1].link = lp->rda_laddr;
+	lp->cur_rx = 0;
+	SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
+	SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
+
+	/* 
+	 * initialize transmit descriptors
+	 */
+	if (sonic_debug > 2)
+		printk("sonic_init: initialize transmit descriptors\n");
+	for (i = 0; i < SONIC_NUM_TDS; i++) {
+		lp->tda[i].tx_status = 0;
+		lp->tda[i].tx_config = 0;
+		lp->tda[i].tx_pktsize = 0;
+		lp->tda[i].tx_frag_count = 0;
+		lp->tda[i].link =
+		    (lp->tda_laddr +
+		     (i + 1) * sizeof(sonic_td_t)) | SONIC_END_OF_LINKS;
+	}
+	lp->tda[SONIC_NUM_TDS - 1].link =
+	    (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS;
+
+	SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16);
+	SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
+	lp->cur_tx = lp->dirty_tx = 0;
+
+	/*
+	 * put our own address to CAM desc[0]
+	 */
+	lp->cda.cam_desc[0].cam_cap0 =
+	    dev->dev_addr[1] << 8 | dev->dev_addr[0];
+	lp->cda.cam_desc[0].cam_cap1 =
+	    dev->dev_addr[3] << 8 | dev->dev_addr[2];
+	lp->cda.cam_desc[0].cam_cap2 =
+	    dev->dev_addr[5] << 8 | dev->dev_addr[4];
+	lp->cda.cam_enable = 1;
+
+	for (i = 0; i < 16; i++)
+		lp->cda.cam_desc[i].cam_entry_pointer = i;
+
+	/*
+	 * initialize CAM registers
+	 */
+	SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
+	SONIC_WRITE(SONIC_CDC, 16);
+
+	/*
+	 * load the CAM
+	 */
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
+
+	i = 0;
+	while (i++ < 100) {
+		if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
+			break;
+	}
+	if (sonic_debug > 2) {
+		printk("sonic_init: CMD=%x, ISR=%x\n",
+		       SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR));
+	}
+
+	/*
+	 * enable receiver, disable loopback
+	 * and enable all interrupts
+	 */
+	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN | SONIC_CR_STP);
+	SONIC_WRITE(SONIC_RCR, SONIC_RCR_DEFAULT);
+	SONIC_WRITE(SONIC_TCR, SONIC_TCR_DEFAULT);
+	SONIC_WRITE(SONIC_ISR, 0x7fff);
+	SONIC_WRITE(SONIC_IMR, SONIC_IMR_DEFAULT);
+
+	cmd = SONIC_READ(SONIC_CMD);
+	if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
+		printk("sonic_init: failed, status=%x\n", cmd);
+
+	if (sonic_debug > 2)
+		printk("sonic_init: new status=%x\n",
+		       SONIC_READ(SONIC_CMD));
+
+	return 0;
+}
diff -u --recursive --new-file v2.4.11/linux/drivers/net/sonic.h linux/drivers/net/sonic.h
--- v2.4.11/linux/drivers/net/sonic.h	Sat Mar  3 10:55:47 2001
+++ linux/drivers/net/sonic.h	Wed Oct 10 23:23:24 2001
@@ -13,7 +13,6 @@
  *		see CONFIG_MACSONIC branch below.
  *
  */
-
 #ifndef SONIC_H
 #define SONIC_H
 
@@ -22,7 +21,7 @@
 /*
  * SONIC register offsets
  */
- 
+
 #define SONIC_CMD              0x00
 #define SONIC_DCR              0x01
 #define SONIC_RCR              0x02
@@ -219,16 +218,16 @@
 
 
 #ifdef CONFIG_MACSONIC
-/* Big endian like structures on Mac
- * (680x0)
+/*
+ * Big endian like structures on 680x0 Macs
  */
 
 typedef struct {
-  u32 rx_bufadr_l;	/* receive buffer ptr */
-  u32 rx_bufadr_h;
+	u32 rx_bufadr_l;	/* receive buffer ptr */
+	u32 rx_bufadr_h;
 
-  u32 rx_bufsize_l;	/* no. of words in the receive buffer */
-  u32 rx_bufsize_h;
+	u32 rx_bufsize_l;	/* no. of words in the receive buffer */
+	u32 rx_bufsize_h;
 } sonic_rr_t;
 
 /*
@@ -237,35 +236,35 @@
  */
 
 typedef struct {
-  SREGS_PAD(pad0);
-  u16 rx_status;	/* status after reception of a packet */
-  SREGS_PAD(pad1);
-  u16 rx_pktlen;	/* length of the packet incl. CRC */
-  
-  /*
-   * Pointers to the location in the receive buffer area (RBA)
-   * where the packet resides. A packet is always received into
-   * a contiguous piece of memory.
-   */
-  SREGS_PAD(pad2);
-  u16 rx_pktptr_l;
-  SREGS_PAD(pad3);
-  u16 rx_pktptr_h;
-
-  SREGS_PAD(pad4);
-  u16 rx_seqno;	/* sequence no. */
-
-  SREGS_PAD(pad5);
-  u16 link;		/* link to next RDD (end if EOL bit set) */
-
-  /*
-   * Owner of this descriptor, 0= driver, 1=sonic
-   */
-  
-  SREGS_PAD(pad6);
-  u16 in_use;	
+	SREGS_PAD(pad0);
+	u16 rx_status;		/* status after reception of a packet */
+	 SREGS_PAD(pad1);
+	u16 rx_pktlen;		/* length of the packet incl. CRC */
+
+	/*
+	 * Pointers to the location in the receive buffer area (RBA)
+	 * where the packet resides. A packet is always received into
+	 * a contiguous piece of memory.
+	 */
+	 SREGS_PAD(pad2);
+	u16 rx_pktptr_l;
+	 SREGS_PAD(pad3);
+	u16 rx_pktptr_h;
+
+	 SREGS_PAD(pad4);
+	u16 rx_seqno;		/* sequence no. */
+
+	 SREGS_PAD(pad5);
+	u16 link;		/* link to next RDD (end if EOL bit set) */
+
+	/*
+	 * Owner of this descriptor, 0= driver, 1=sonic
+	 */
+
+	 SREGS_PAD(pad6);
+	u16 in_use;
 
-  caddr_t rda_next;		/* pointer to next RD */
+	caddr_t rda_next;	/* pointer to next RD */
 } sonic_rd_t;
 
 
@@ -273,24 +272,24 @@
  * Describes a Transmit Descriptor
  */
 typedef struct {
-  SREGS_PAD(pad0);		
-  u16 tx_status;	/* status after transmission of a packet */
-  SREGS_PAD(pad1);		
-  u16 tx_config;	/* transmit configuration for this packet */
-  SREGS_PAD(pad2);		
-  u16 tx_pktsize;	/* size of the packet to be transmitted */
-  SREGS_PAD(pad3);		
-  u16 tx_frag_count;	/* no. of fragments */
-
-  SREGS_PAD(pad4);		
-  u16 tx_frag_ptr_l;
-  SREGS_PAD(pad5);		
-  u16 tx_frag_ptr_h;
-  SREGS_PAD(pad6);		
-  u16 tx_frag_size;
-  
-  SREGS_PAD(pad7);		
-  u16 link;		/* ptr to next descriptor */
+	SREGS_PAD(pad0);
+	u16 tx_status;		/* status after transmission of a packet */
+	 SREGS_PAD(pad1);
+	u16 tx_config;		/* transmit configuration for this packet */
+	 SREGS_PAD(pad2);
+	u16 tx_pktsize;		/* size of the packet to be transmitted */
+	 SREGS_PAD(pad3);
+	u16 tx_frag_count;	/* no. of fragments */
+
+	 SREGS_PAD(pad4);
+	u16 tx_frag_ptr_l;
+	 SREGS_PAD(pad5);
+	u16 tx_frag_ptr_h;
+	 SREGS_PAD(pad6);
+	u16 tx_frag_size;
+
+	 SREGS_PAD(pad7);
+	u16 link;		/* ptr to next descriptor */
 } sonic_td_t;
 
 
@@ -299,37 +298,37 @@
  */
 
 typedef struct {
-  SREGS_PAD(pad0);
-  u16 cam_entry_pointer;
-  SREGS_PAD(pad1);
-  u16 cam_cap0;
-  SREGS_PAD(pad2);
-  u16 cam_cap1;
-  SREGS_PAD(pad3);
-  u16 cam_cap2;
+	SREGS_PAD(pad0);
+	u16 cam_entry_pointer;
+	 SREGS_PAD(pad1);
+	u16 cam_cap0;
+	 SREGS_PAD(pad2);
+	u16 cam_cap1;
+	 SREGS_PAD(pad3);
+	u16 cam_cap2;
 } sonic_cd_t;
 
 #define CAM_DESCRIPTORS 16
 
 
 typedef struct {
-  sonic_cd_t cam_desc[CAM_DESCRIPTORS];
-  SREGS_PAD(pad);
-  u16 cam_enable;
+	sonic_cd_t cam_desc[CAM_DESCRIPTORS];
+	 SREGS_PAD(pad);
+	u16 cam_enable;
 } sonic_cda_t;
 
-#else /* original declarations, little endian 32 bit */
+#else				/* original declarations, little endian 32 bit */
 
 /*
  * structure definitions
  */
 
 typedef struct {
-  u32 rx_bufadr_l;	/* receive buffer ptr */
-  u32 rx_bufadr_h;
+	u32 rx_bufadr_l;	/* receive buffer ptr */
+	u32 rx_bufadr_h;
 
-  u32 rx_bufsize_l;	/* no. of words in the receive buffer */
-  u32 rx_bufsize_h;
+	u32 rx_bufsize_l;	/* no. of words in the receive buffer */
+	u32 rx_bufsize_h;
 } sonic_rr_t;
 
 /*
@@ -338,35 +337,35 @@
  */
 
 typedef struct {
-  u16 rx_status;	/* status after reception of a packet */
-  SREGS_PAD(pad0);
-  u16 rx_pktlen;	/* length of the packet incl. CRC */
-  SREGS_PAD(pad1);
-  
-  /*
-   * Pointers to the location in the receive buffer area (RBA)
-   * where the packet resides. A packet is always received into
-   * a contiguous piece of memory.
-   */
-  u16 rx_pktptr_l;
-  SREGS_PAD(pad2);
-  u16 rx_pktptr_h;
-  SREGS_PAD(pad3);
-
-  u16 rx_seqno;	/* sequence no. */
-  SREGS_PAD(pad4);
-
-  u16 link;		/* link to next RDD (end if EOL bit set) */
-  SREGS_PAD(pad5);
-
-  /*
-   * Owner of this descriptor, 0= driver, 1=sonic
-   */
-  
-  u16 in_use;	
-  SREGS_PAD(pad6);
+	u16 rx_status;		/* status after reception of a packet */
+	 SREGS_PAD(pad0);
+	u16 rx_pktlen;		/* length of the packet incl. CRC */
+	 SREGS_PAD(pad1);
+
+	/*
+	 * Pointers to the location in the receive buffer area (RBA)
+	 * where the packet resides. A packet is always received into
+	 * a contiguous piece of memory.
+	 */
+	u16 rx_pktptr_l;
+	 SREGS_PAD(pad2);
+	u16 rx_pktptr_h;
+	 SREGS_PAD(pad3);
+
+	u16 rx_seqno;		/* sequence no. */
+	 SREGS_PAD(pad4);
+
+	u16 link;		/* link to next RDD (end if EOL bit set) */
+	 SREGS_PAD(pad5);
+
+	/*
+	 * Owner of this descriptor, 0= driver, 1=sonic
+	 */
+
+	u16 in_use;
+	 SREGS_PAD(pad6);
 
-  caddr_t rda_next;		/* pointer to next RD */
+	caddr_t rda_next;	/* pointer to next RD */
 } sonic_rd_t;
 
 
@@ -374,24 +373,24 @@
  * Describes a Transmit Descriptor
  */
 typedef struct {
-  u16 tx_status;	/* status after transmission of a packet */
-  SREGS_PAD(pad0);
-  u16 tx_config;	/* transmit configuration for this packet */
-  SREGS_PAD(pad1);
-  u16 tx_pktsize;	/* size of the packet to be transmitted */
-  SREGS_PAD(pad2);
-  u16 tx_frag_count;	/* no. of fragments */
-  SREGS_PAD(pad3);
-
-  u16 tx_frag_ptr_l;
-  SREGS_PAD(pad4);
-  u16 tx_frag_ptr_h;
-  SREGS_PAD(pad5);
-  u16 tx_frag_size;
-  SREGS_PAD(pad6);
-  
-  u16 link;		/* ptr to next descriptor */
-  SREGS_PAD(pad7);
+	u16 tx_status;		/* status after transmission of a packet */
+	 SREGS_PAD(pad0);
+	u16 tx_config;		/* transmit configuration for this packet */
+	 SREGS_PAD(pad1);
+	u16 tx_pktsize;		/* size of the packet to be transmitted */
+	 SREGS_PAD(pad2);
+	u16 tx_frag_count;	/* no. of fragments */
+	 SREGS_PAD(pad3);
+
+	u16 tx_frag_ptr_l;
+	 SREGS_PAD(pad4);
+	u16 tx_frag_ptr_h;
+	 SREGS_PAD(pad5);
+	u16 tx_frag_size;
+	 SREGS_PAD(pad6);
+
+	u16 link;		/* ptr to next descriptor */
+	 SREGS_PAD(pad7);
 } sonic_td_t;
 
 
@@ -400,25 +399,25 @@
  */
 
 typedef struct {
-  u16 cam_entry_pointer;
-  SREGS_PAD(pad0);
-  u16 cam_cap0;
-  SREGS_PAD(pad1);
-  u16 cam_cap1;
-  SREGS_PAD(pad2);
-  u16 cam_cap2;
-  SREGS_PAD(pad3);
+	u16 cam_entry_pointer;
+	 SREGS_PAD(pad0);
+	u16 cam_cap0;
+	 SREGS_PAD(pad1);
+	u16 cam_cap1;
+	 SREGS_PAD(pad2);
+	u16 cam_cap2;
+	 SREGS_PAD(pad3);
 } sonic_cd_t;
 
 #define CAM_DESCRIPTORS 16
 
 
 typedef struct {
-  sonic_cd_t cam_desc[CAM_DESCRIPTORS];
-  u16 cam_enable;
-  SREGS_PAD(pad);
+	sonic_cd_t cam_desc[CAM_DESCRIPTORS];
+	u16 cam_enable;
+	 SREGS_PAD(pad);
 } sonic_cda_t;
-#endif	/* endianness */ 
+#endif				/* endianness */
 
 /*
  * Some tunables for the buffer areas. Power of 2 is required
@@ -427,15 +426,15 @@
  * MSch: use more buffer space for the slow m68k Macs!
  */
 #ifdef CONFIG_MACSONIC
-#define SONIC_NUM_RRS    32             /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
-#define SONIC_NUM_TDS    32      /* number of transmit descriptors */
+#define SONIC_NUM_RRS    32	/* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS	/* number of receive descriptors */
+#define SONIC_NUM_TDS    32	/* number of transmit descriptors */
 #else
-#define SONIC_NUM_RRS    16             /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
-#define SONIC_NUM_TDS    16      /* number of transmit descriptors */
+#define SONIC_NUM_RRS    16	/* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS	/* number of receive descriptors */
+#define SONIC_NUM_TDS    16	/* number of transmit descriptors */
 #endif
-#define SONIC_RBSIZE   1520      /* size of one resource buffer */
+#define SONIC_RBSIZE   1520	/* size of one resource buffer */
 
 #define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
 #define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
@@ -443,26 +442,28 @@
 
 /* Information that need to be kept for each board. */
 struct sonic_local {
-    sonic_cda_t   cda;                     /* virtual CPU address of CDA */
-    sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
-    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource area */
-    sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
-    struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
-    unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
-    unsigned char *rba;                    /* start of receive buffer areas */    
-    unsigned int  cda_laddr;               /* logical DMA address of CDA */    
-    unsigned int  tda_laddr;               /* logical DMA address of TDA */
-    unsigned int  rra_laddr;               /* logical DMA address of RRA */    
-    unsigned int  rda_laddr;               /* logical DMA address of RDA */
-    unsigned int  rba_laddr;               /* logical DMA address of RBA */
-    unsigned int  cur_rra;                 /* current indexes to resource areas */
-    unsigned int  cur_rx;
-    unsigned int  cur_tx;
-    unsigned int  dirty_tx;                /* last unacked transmit packet */
-    char tx_full;
-    struct net_device_stats stats;
+	sonic_cda_t cda;	/* virtual CPU address of CDA */
+	sonic_td_t tda[SONIC_NUM_TDS];	/* transmit descriptor area */
+	sonic_rr_t rra[SONIC_NUM_RRS];	/* receive resource area */
+	sonic_rd_t rda[SONIC_NUM_RDS];	/* receive descriptor area */
+	struct sk_buff *tx_skb[SONIC_NUM_TDS];	/* skbuffs for packets to transmit */
+	unsigned int tx_laddr[SONIC_NUM_TDS];	/* logical DMA address fro skbuffs */
+	unsigned char *rba;	/* start of receive buffer areas */
+	unsigned int cda_laddr;	/* logical DMA address of CDA */
+	unsigned int tda_laddr;	/* logical DMA address of TDA */
+	unsigned int rra_laddr;	/* logical DMA address of RRA */
+	unsigned int rda_laddr;	/* logical DMA address of RDA */
+	unsigned int rba_laddr;	/* logical DMA address of RBA */
+	unsigned int cur_rra;	/* current indexes to resource areas */
+	unsigned int cur_rx;
+	unsigned int cur_tx;
+	unsigned int dirty_tx;	/* last unacked transmit packet */
+	char tx_full;
+	struct net_device_stats stats;
 };
 
+#define TX_TIMEOUT 6
+
 /* Index to functions, as function prototypes. */
 
 static int sonic_open(struct net_device *dev);
@@ -473,8 +474,9 @@
 static struct net_device_stats *sonic_get_stats(struct net_device *dev);
 static void sonic_multicast_list(struct net_device *dev);
 static int sonic_init(struct net_device *dev);
+static void sonic_tx_timeout(struct net_device *dev);
 
 static const char *version =
-	"sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
+    "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
 
 #endif /* SONIC_H */
diff -u --recursive --new-file v2.4.11/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- v2.4.11/linux/drivers/parport/ChangeLog	Tue Oct  9 17:06:52 2001
+++ linux/drivers/parport/ChangeLog	Wed Oct 10 23:19:30 2001
@@ -1,3 +1,23 @@
+2001-10-10  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Support for OX16PCI954 PCI card.
+
+2001-10-10  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c: Support for OX12PCI840 PCI card (reported by
+	mk@daveg.com).  Lock-ups diagnosed by Ronnie Arosa (and now we
+	just don't trust its ECR).
+
+2001-10-10  Gunther Mayer  <gunther.mayer@braunschweig.okersurf.de>
+
+	* parport_pc.c: Support for AVLAB cards.
+
+2001-10-10  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (ecp_forward_to_reverse, ecp_reverse_to_forward):
+	Remember to retry direction switch if it fails.  Patch from David
+	Lambert.
+
 2001-10-08  David C. Hansen  <haveblue@us.ibm.com>
 
 	* share.c: Make driverlist_lock and parportlist_lock static.
diff -u --recursive --new-file v2.4.11/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- v2.4.11/linux/drivers/parport/ieee1284_ops.c	Sat May 19 18:07:04 2001
+++ linux/drivers/parport/ieee1284_ops.c	Wed Oct 10 23:19:30 2001
@@ -359,6 +359,10 @@
 		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
 			 port->name);
 		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+	} else {
+		DPRINTK (KERN_DEBUG "%s: ECP direction: failed to reverse\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_DIR_UNKNOWN;
 	}
 
 	return retval;
@@ -386,7 +390,13 @@
 		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
 			 port->name);
 		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+	} else {
+		DPRINTK (KERN_DEBUG
+			 "%s: ECP direction: failed to switch forward\n",
+			 port->name);
+		port->ieee1284.phase = IEEE1284_PH_DIR_UNKNOWN;
 	}
+
 
 	return retval;
 }
diff -u --recursive --new-file v2.4.11/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- v2.4.11/linux/drivers/parport/parport_pc.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/parport/parport_pc.c	Wed Oct 10 23:19:30 2001
@@ -2528,7 +2528,6 @@
 	lava_parallel_dual_b,
 	boca_ioppar,
 	plx_9050,
-	afavlab_tk9902,
 	timedia_4078a,
 	timedia_4079h,
 	timedia_4085h,
@@ -2556,6 +2555,10 @@
 	syba_1p_ecp,
 	titan_010l,
 	titan_1284p2,
+	avlab_1p,
+	avlab_2p,
+	oxsemi_954,
+	oxsemi_840,
 };
 
 
@@ -2594,7 +2597,6 @@
 	/* lava_parallel_dual_b */	{ 1, { { 0, -1 }, } },
 	/* boca_ioppar */		{ 1, { { 0, -1 }, } },
 	/* plx_9050 */			{ 2, { { 4, -1 }, { 5, -1 }, } },
-	/* afavlab_tk9902 */		{ 1, { { 0, 1 }, } },
 	/* timedia_4078a */		{ 1, { { 2, -1 }, } },
 	/* timedia_4079h */             { 1, { { 2, 3 }, } },
 	/* timedia_4085h */             { 2, { { 2, -1 }, { 4, -1 }, } },
@@ -2624,6 +2626,12 @@
 	/* syba_1p_ecp W83787 */	{ 1, { { 0, 0x078 }, } },
 	/* titan_010l */		{ 1, { { 3, -1 }, } },
 	/* titan_1284p2 */		{ 2, { { 0, 1 }, { 2, 3 }, } },
+	/* avlab_1p		*/	{ 1, { { 0, 1}, } },
+	/* avlab_2p		*/	{ 2, { { 0, 1}, { 2, 3 },} },
+	/* The Oxford Semi cards are unusual: 954 doesn't support ECP,
+	 * and 840 locks up if you write 1 to bit 2! */
+	/* oxsemi_954 */		{ 1, { { 0, -1 }, } },
+	/* oxsemi_840 */		{ 1, { { 0, -1 }, } },
 };
 
 static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
@@ -2679,8 +2687,6 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar },
 	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 	  PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
-	{ PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 },
 	/* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
 	{ 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
 	{ 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
@@ -2712,6 +2718,13 @@
 	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
 	{ 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
+	/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
+	{ 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
+	{ 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p},
+	{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 },
+	{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_840 },
 	{ 0, } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c
--- v2.4.11/linux/drivers/sbus/audio/audio.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/audio/audio.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: audio.c,v 1.61 2001/08/13 14:40:12 davem Exp $
+/* $Id: audio.c,v 1.62 2001/10/08 22:19:50 davem Exp $
  * drivers/sbus/audio/audio.c
  *
  * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu)
@@ -2138,8 +2138,9 @@
 	devfs_unregister (devfs_handle);
 }
 
-module_init(sparcaudio_init)
-module_exit(sparcaudio_exit)
+module_init(sparcaudio_init);
+module_exit(sparcaudio_exit);
+MODULE_LICENSE("GPL");
 
 /*
  * Code from Linux Streams, Copyright 1995 by
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c
--- v2.4.11/linux/drivers/sbus/audio/cs4231.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/audio/cs4231.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: cs4231.c,v 1.46 2001/05/21 01:25:22 davem Exp $
+/* $Id: cs4231.c,v 1.47 2001/10/08 22:19:50 davem Exp $
  * drivers/sbus/audio/cs4231.c
  *
  * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -2443,6 +2443,7 @@
 
 module_init(cs4231_init);
 module_exit(cs4231_exit);
+MODULE_LICENSE("GPL");
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c
--- v2.4.11/linux/drivers/sbus/audio/dbri.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/audio/dbri.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: dbri.c,v 1.26 2001/05/21 01:25:22 davem Exp $
+/* $Id: dbri.c,v 1.27 2001/10/08 22:19:50 davem Exp $
  * drivers/sbus/audio/dbri.c
  *
  * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de)
@@ -2377,6 +2377,8 @@
 
 module_init(dbri_init);
 module_exit(dbri_exit);
+MODULE_LICENSE("GPL");
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/audio/dmy.c linux/drivers/sbus/audio/dmy.c
--- v2.4.11/linux/drivers/sbus/audio/dmy.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/audio/dmy.c	Wed Oct 10 23:42:46 2001
@@ -1,4 +1,4 @@
-/* $Id: dmy.c,v 1.9 2001/05/22 23:16:10 davem Exp $
+/* $Id: dmy.c,v 1.10 2001/10/08 22:19:50 davem Exp $
  * drivers/sbus/audio/dummy.c
  *
  * Copyright 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -783,6 +783,8 @@
 
 module_init(dummy_init);
 module_exit(dummy_exit);
+MODULE_LICENSE("GPL");
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.4.11/linux/drivers/sbus/char/aurora.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/aurora.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/*	$Id: aurora.c,v 1.15 2001/08/13 14:40:08 davem Exp $
+/*	$Id: aurora.c,v 1.16 2001/10/08 22:19:51 davem Exp $
  *	linux/drivers/sbus/char/aurora.c -- Aurora multiport driver
  *
  *	Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro)
@@ -2482,3 +2482,4 @@
 
 module_init(aurora_init);
 module_exit(aurora_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.4.11/linux/drivers/sbus/char/bpp.c	Mon Jan 22 13:30:20 2001
+++ linux/drivers/sbus/char/bpp.c	Wed Oct 10 23:42:47 2001
@@ -1073,3 +1073,4 @@
 
 module_init(bpp_init);
 module_exit(bpp_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/cpwatchdog.c linux/drivers/sbus/char/cpwatchdog.c
--- v2.4.11/linux/drivers/sbus/char/cpwatchdog.c	Thu Apr 12 12:10:25 2001
+++ linux/drivers/sbus/char/cpwatchdog.c	Wed Oct 10 23:42:47 2001
@@ -193,6 +193,7 @@
 	("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION
 	("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE
 	("watchdog");
 #endif /* ifdef MODULE */
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/display7seg.c linux/drivers/sbus/char/display7seg.c
--- v2.4.11/linux/drivers/sbus/char/display7seg.c	Thu Nov  9 15:57:41 2000
+++ linux/drivers/sbus/char/display7seg.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: display7seg.c,v 1.4 2000/11/08 05:08:23 davem Exp $
+/* $Id: display7seg.c,v 1.5 2001/10/08 22:19:51 davem Exp $
  *
  * display7seg - Driver implementation for the 7-segment display
  * present on Sun Microsystems CP1400 and CP1500
@@ -55,6 +55,7 @@
 	("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION
 	("7-Segment Display driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE
 	("d7s");
 #endif /* ifdef MODULE */
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/envctrl.c linux/drivers/sbus/char/envctrl.c
--- v2.4.11/linux/drivers/sbus/char/envctrl.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/envctrl.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.23 2001/08/09 23:42:09 davem Exp $
+/* $Id: envctrl.c,v 1.24 2001/10/08 22:19:51 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
@@ -1175,3 +1175,4 @@
 
 module_init(envctrl_init);
 module_exit(envctrl_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/flash.c linux/drivers/sbus/char/flash.c
--- v2.4.11/linux/drivers/sbus/char/flash.c	Tue Mar  6 22:44:16 2001
+++ linux/drivers/sbus/char/flash.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.23 2001/03/02 06:32:40 davem Exp $
+/* $Id: flash.c,v 1.24 2001/10/08 22:19:51 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -247,3 +247,4 @@
 
 module_init(flash_init);
 module_exit(flash_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/jsflash.c linux/drivers/sbus/char/jsflash.c
--- v2.4.11/linux/drivers/sbus/char/jsflash.c	Sun Sep 23 11:40:59 2001
+++ linux/drivers/sbus/char/jsflash.c	Wed Oct 10 23:42:47 2001
@@ -682,6 +682,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 
 int init_module(void) {
 	int rc;
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c
--- v2.4.11/linux/drivers/sbus/char/openprom.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/openprom.c	Wed Oct 10 23:42:47 2001
@@ -653,3 +653,4 @@
 
 module_init(openprom_init);
 module_exit(openprom_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/riowatchdog.c linux/drivers/sbus/char/riowatchdog.c
--- v2.4.11/linux/drivers/sbus/char/riowatchdog.c	Thu Apr 12 12:10:25 2001
+++ linux/drivers/sbus/char/riowatchdog.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: riowatchdog.c,v 1.2 2001/03/26 23:47:18 davem Exp $
+/* $Id: riowatchdog.c,v 1.3 2001/10/08 22:19:51 davem Exp $
  * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -47,6 +47,7 @@
 MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
 MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
 MODULE_SUPPORTED_DEVICE("watchdog");
+MODULE_LICENSE("GPL");
 
 #define RIOWD_NAME	"pmc"
 #define RIOWD_MINOR	215
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.4.11/linux/drivers/sbus/char/rtc.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/rtc.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.27 2001/08/13 14:40:08 davem Exp $
+/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -174,3 +174,4 @@
 
 module_init(rtc_sun_init);
 module_exit(rtc_sun_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.4.11/linux/drivers/sbus/char/sab82532.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/sbus/char/sab82532.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.63 2001/06/29 21:23:44 davem Exp $
+/* $Id: sab82532.c,v 1.64 2001/10/08 22:19:51 davem Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2205,7 +2205,7 @@
 
 static inline void __init show_serial_version(void)
 {
-	char *revision = "$Revision: 1.63 $";
+	char *revision = "$Revision: 1.64 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
@@ -2427,6 +2427,8 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	if (get_sab82532(0))
diff -u --recursive --new-file v2.4.11/linux/drivers/sbus/char/uctrl.c linux/drivers/sbus/char/uctrl.c
--- v2.4.11/linux/drivers/sbus/char/uctrl.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/uctrl.c	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: uctrl.c,v 1.11 2001/08/13 14:40:08 davem Exp $
+/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
  * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
  *
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
@@ -424,3 +424,4 @@
 
 module_init(ts102_uctrl_init);
 module_exit(ts102_uctrl_cleanup);
+MODULE_LICENSE("GPL");
diff -u --recursive --new-file v2.4.11/linux/drivers/scsi/aic7xxx_old.c linux/drivers/scsi/aic7xxx_old.c
--- v2.4.11/linux/drivers/scsi/aic7xxx_old.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/scsi/aic7xxx_old.c	Wed Oct 10 09:31:46 2001
@@ -219,9 +219,7 @@
  * #define AIC7XXX_VERBOSE_DEBUGGING
  */
  
-#if defined(MODULE) || defined(PCMCIA)
 #include <linux/module.h>
-#endif
 
 #if defined(PCMCIA)
 #  undef MODULE
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- v2.4.11/linux/drivers/usb/serial/belkin_sa.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Wed Oct 10 23:42:47 2001
@@ -23,8 +23,8 @@
  *    framework in, but haven't analyzed the "tty_flip" interface yet.
  * -- Add support for flush commands
  * -- Add everything that is missing :)
- * 
- * (30-May-2001 gkh
+ *
+ * 30-May-2001 gkh
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
  * 08-Apr-2001 gb
@@ -350,6 +350,15 @@
 
 static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
 {
+	struct usb_serial *serial;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+
 	dbg(__FUNCTION__" port %d", port->number);
 
 	down (&port->sem);
@@ -357,10 +366,12 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* 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);	/* wgg - do I need this? I think so. */
+		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->active = 0;
 	}
 	
@@ -636,7 +647,7 @@
 	usb_serial_register (&belkin_old_device);
 	usb_serial_register (&peracom_device);
 	usb_serial_register (&gocom232_device);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/cyberjack.c linux/drivers/usb/serial/cyberjack.c
--- v2.4.11/linux/drivers/usb/serial/cyberjack.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/cyberjack.c	Wed Oct 10 23:42:47 2001
@@ -198,10 +198,12 @@
 	--port->open_count;
 
 	if (port->open_count <= 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);
+		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->active = 0;
 		port->open_count = 0;
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.4.11/linux/drivers/usb/serial/digi_acceleport.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Wed Oct 10 23:42:47 2001
@@ -1591,53 +1591,55 @@
 	if( tty->ldisc.flush_buffer )
 		tty->ldisc.flush_buffer( tty );
 
-	/* wait for transmit idle */
-	if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
-		digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );
-	}
-
-	/* drop DTR and RTS */
-	digi_set_modem_signals( port, 0, 0 );
+	if (port->serial->dev) {
+		/* wait for transmit idle */
+		if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
+			digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );
+		}
+
+		/* drop DTR and RTS */
+		digi_set_modem_signals( port, 0, 0 );
+
+		/* disable input flow control */
+		buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
+		buf[1] = priv->dp_port_num;
+		buf[2] = DIGI_DISABLE;
+		buf[3] = 0;
+
+		/* disable output flow control */
+		buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
+		buf[5] = priv->dp_port_num;
+		buf[6] = DIGI_DISABLE;
+		buf[7] = 0;
+
+		/* disable reading modem signals automatically */
+		buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
+		buf[9] = priv->dp_port_num;
+		buf[10] = DIGI_DISABLE;
+		buf[11] = 0;
+
+		/* disable receive */
+		buf[12] = DIGI_CMD_RECEIVE_ENABLE;
+		buf[13] = priv->dp_port_num;
+		buf[14] = DIGI_DISABLE;
+		buf[15] = 0;
+
+		/* flush fifos */
+		buf[16] = DIGI_CMD_IFLUSH_FIFO;
+		buf[17] = priv->dp_port_num;
+		buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
+		buf[19] = 0;
+
+		if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
+			dbg( "digi_close: write oob failed, ret=%d", ret );
+
+		/* wait for final commands on oob port to complete */
+		interruptible_sleep_on_timeout( &priv->dp_flush_wait,
+			DIGI_CLOSE_TIMEOUT );
 
-	/* disable input flow control */
-	buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
-	buf[1] = priv->dp_port_num;
-	buf[2] = DIGI_DISABLE;
-	buf[3] = 0;
-
-	/* disable output flow control */
-	buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
-	buf[5] = priv->dp_port_num;
-	buf[6] = DIGI_DISABLE;
-	buf[7] = 0;
-
-	/* disable reading modem signals automatically */
-	buf[8] = DIGI_CMD_READ_INPUT_SIGNALS;
-	buf[9] = priv->dp_port_num;
-	buf[10] = DIGI_DISABLE;
-	buf[11] = 0;
-
-	/* disable receive */
-	buf[12] = DIGI_CMD_RECEIVE_ENABLE;
-	buf[13] = priv->dp_port_num;
-	buf[14] = DIGI_DISABLE;
-	buf[15] = 0;
-
-	/* flush fifos */
-	buf[16] = DIGI_CMD_IFLUSH_FIFO;
-	buf[17] = priv->dp_port_num;
-	buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
-	buf[19] = 0;
-
-	if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
-		dbg( "digi_close: write oob failed, ret=%d", ret );
-
-	/* wait for final commands on oob port to complete */
-	interruptible_sleep_on_timeout( &priv->dp_flush_wait,
-		DIGI_CLOSE_TIMEOUT );
-
-	/* shutdown any outstanding bulk writes */
-	usb_unlink_urb (port->write_urb);
+		/* shutdown any outstanding bulk writes */
+		usb_unlink_urb (port->write_urb);
+	}
 
 	tty->closing = 0;
 
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.11/linux/drivers/usb/serial/empeg.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/empeg.c	Wed Oct 10 23:42:47 2001
@@ -217,8 +217,10 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* shutdown our bulk read */
-		usb_unlink_urb (port->read_urb);
+		if (serial->dev) {
+			/* shutdown our bulk read */
+			usb_unlink_urb (port->read_urb);
+		}
 		port->active = 0;
 		port->open_count = 0;
 	}
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.11/linux/drivers/usb/serial/ftdi_sio.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Wed Oct 10 23:42:47 2001
@@ -371,29 +371,31 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		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");
-			}	    
+		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 */
+				/* 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 */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
+			/* shutdown our bulk reads and writes */
+			usb_unlink_urb (port->write_urb);
+			usb_unlink_urb (port->read_urb);
+		}
 		port->active = 0;
 		port->open_count = 0;
 	} else {  
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.4.11/linux/drivers/usb/serial/io_edgeport.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Wed Oct 10 23:42:47 2001
@@ -1241,42 +1241,45 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		// 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 (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);
+
+			//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);
+			}
 		}
 	
-		/* 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;
-	
 		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_unlink_urb (edge_port->write_urb);
 			usb_free_urb   (edge_port->write_urb);
 		}
-	
 		if (edge_port->txfifo.fifo) {
 			kfree(edge_port->txfifo.fifo);
 		}
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c
--- v2.4.11/linux/drivers/usb/serial/ir-usb.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/ir-usb.c	Wed Oct 10 23:42:47 2001
@@ -14,6 +14,10 @@
  * please use the usb-irda driver, as it contains the proper error checking and
  * other goodness of a full IrDA stack.
  *
+ * Portions of this driver were taken from drivers/net/irda/irda-usb.c, which
+ * was written by Roman Weissgaerber <weissg@vienna.at>, Dag Brattli
+ * <dag@brattli.net>, and Jean Tourrilhes <jt@hpl.hp.com>
+
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
  * 2001_Oct_07	greg kh
@@ -112,7 +116,7 @@
  * offer to us, describing their IrDA characteristics. We will use that in
  * irda_usb_init_qos()
  */
-static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface_descriptor *interface;
 	struct irda_class_desc *desc;
@@ -229,8 +233,10 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* shutdown our bulk read */
-		usb_unlink_urb (port->read_urb);
+		if (serial->dev) {
+			/* shutdown our bulk read */
+			usb_unlink_urb (port->read_urb);
+		}
 		port->active = 0;
 		port->open_count = 0;
 
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.4.11/linux/drivers/usb/serial/keyspan.c	Tue Oct  9 17:06:52 2001
+++ linux/drivers/usb/serial/keyspan.c	Wed Oct 10 23:42:47 2001
@@ -920,10 +920,14 @@
 static void keyspan_close(struct usb_serial_port *port, struct file *filp)
 {
 	int			i;
-	struct usb_serial	*serial = port->serial; /* FIXME should so sanity check */
+	struct usb_serial	*serial;
 	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private 	*p_priv;
 
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+
 	dbg("keyspan_close called\n");
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
@@ -931,7 +935,8 @@
 	p_priv->rts_state = 0;
 	p_priv->dtr_state = 0;
 	
-	keyspan_send_setup(port, 1);
+	if (serial->dev)
+		keyspan_send_setup(port, 1);
 
 	/*while (p_priv->outcont_urb->status == -EINPROGRESS) {
 		dbg("close - urb in progress\n");
@@ -944,18 +949,15 @@
 
 	if (--port->open_count <= 0) {
 		if (port->active) {
-			/* 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]);
+				}
 			}
-			/* Now done in shutdown 
-			if (atomic_dec_return(&s_priv->active_count) <= 0) {
-				stop_urb(s_priv->instat_urb);
-				stop_urb(s_priv->glocont_urb);
-			} */
 		}
 		port->active = 0;
 		port->open_count = 0;
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/keyspan_pda.c linux/drivers/usb/serial/keyspan_pda.c
--- v2.4.11/linux/drivers/usb/serial/keyspan_pda.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/keyspan_pda.c	Wed Oct 10 23:42:47 2001
@@ -743,13 +743,15 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* 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 (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);
+			/* shutdown our bulk reads and writes */
+			usb_unlink_urb (port->write_urb);
+			usb_unlink_urb (port->interrupt_in_urb);
+		}
 		port->active = 0;
 		port->open_count = 0;
 	}
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- v2.4.11/linux/drivers/usb/serial/mct_u232.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/mct_u232.c	Wed Oct 10 23:42:47 2001
@@ -475,11 +475,12 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		/* wgg - do I need this? I think so. */
-		usb_unlink_urb (port->interrupt_in_urb);
+		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->active = 0;
 	}
 	
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/omninet.c linux/drivers/usb/serial/omninet.c
--- v2.4.11/linux/drivers/usb/serial/omninet.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/omninet.c	Wed Oct 10 23:42:47 2001
@@ -216,14 +216,15 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		od = (struct omninet_data *)port->private;
-		wport = &serial->port[1];
-
-		usb_unlink_urb (wport->write_urb);
-		usb_unlink_urb (port->read_urb);
+		if (serial->dev) {
+			wport = &serial->port[1];
+			usb_unlink_urb (wport->write_urb);
+			usb_unlink_urb (port->read_urb);
+		}
 
 		port->active = 0;
 		port->open_count = 0;
+		od = (struct omninet_data *)port->private;
 		if (od)
 			kfree(od);
 	}
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/pl2303.c linux/drivers/usb/serial/pl2303.c
--- v2.4.11/linux/drivers/usb/serial/pl2303.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/serial/pl2303.c	Wed Oct 10 23:42:47 2001
@@ -434,40 +434,53 @@
 
 static void pl2303_close (struct usb_serial_port *port, struct file *filp)
 {
+	struct usb_serial *serial;
 	struct pl2303_private *priv;
 	unsigned int c_cflag;
 	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
-
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+	
 	dbg (__FUNCTION__ " - port %d", port->number);
 
 	down (&port->sem);
 
 	--port->open_count;
 	if (port->open_count <= 0) {
-		c_cflag = port->tty->termios->c_cflag;
-		if (c_cflag & HUPCL) {
-			/* drop DTR and RTS */
-			priv = port->private;
-			priv->line_control = 0;
-			set_control_lines (port->serial->dev, priv->line_control);
+		if (serial->dev) {
+			c_cflag = port->tty->termios->c_cflag;
+			if (c_cflag & HUPCL) {
+				/* drop DTR and RTS */
+				priv = port->private;
+				priv->line_control = 0;
+				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);
 		}
-
-		/* 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->active = 0;
 		port->open_count = 0;
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h
--- v2.4.11/linux/drivers/usb/serial/usb-serial.h	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/usb-serial.h	Wed Oct 10 23:42:47 2001
@@ -11,6 +11,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (10/10/2001) gkh
+ *	added vendor and product to serial structure.  Needed to determine device
+ *	owner when the device is disconnected.
+ *
  * (05/30/2001) gkh
  *	added sem to port structure and removed port_lock
  *
@@ -96,6 +100,8 @@
 	char				num_interrupt_in;	/* number of interrupt in endpoints we have */
 	char				num_bulk_in;		/* number of bulk in endpoints we have */
 	char				num_bulk_out;		/* number of bulk out endpoints we have */
+	__u16				vendor;			/* vendor id of this device */
+	__u16				product;		/* product id of this device */
 	struct usb_serial_port		port[MAX_NUM_PORTS];
 
 	void *			private;		/* data private to the specific driver */
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.11/linux/drivers/usb/serial/usbserial.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/serial/usbserial.c	Wed Oct 10 23:42:47 2001
@@ -14,7 +14,12 @@
  * based on a driver by Brad Keryan)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
+ *
+ * (10/10/2001) gkh
+ *	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
+ *	help prevent child drivers from accessing the device since it is now
+ *	gone.
+ *
  * (09/13/2001) gkh
  *	Moved generic driver initialize after we have registered with the USB
  *	core.  Thanks to Randy Dunlap for pointing this problem out.
@@ -344,9 +349,9 @@
 	shutdown:		generic_shutdown,
 };
 
-#define if_generic_do(x)					\
-	if ((serial->dev->descriptor.idVendor == vendor) &&	\
-	    (serial->dev->descriptor.idProduct == product))	\
+#define if_generic_do(x)			\
+	if ((serial->vendor == vendor) &&	\
+	    (serial->product == product))	\
 	                x
 #else
 #define if_generic_do(x)
@@ -462,10 +467,15 @@
 int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest)
 {
 	int result;
-	unsigned char *transfer_buffer =  kmalloc (length, GFP_KERNEL);
+	unsigned char *transfer_buffer;
 
-//	dbg("ezusb_writememory %x, %d", address, length);
+	/* dbg("ezusb_writememory %x, %d", address, length); */
+	if (!serial->dev) {
+		dbg(__FUNCTION__ " - no physical device present, failing.");
+		return -ENODEV;
+	}
 
+	transfer_buffer =  kmalloc (length, GFP_KERNEL);
 	if (!transfer_buffer) {
 		err(__FUNCTION__ " - kmalloc(%d) failed.", length);
 		return -ENOMEM;
@@ -821,11 +831,13 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		/* 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);
+		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->active = 0;
 		port->open_count = 0;
@@ -1186,6 +1198,8 @@
 	serial->num_bulk_in = num_bulk_in;
 	serial->num_bulk_out = num_bulk_out;
 	serial->num_interrupt_in = num_interrupt_in;
+	serial->vendor = dev->descriptor.idVendor;
+	serial->product = dev->descriptor.idProduct;
 
 	/* if this device type has a startup function, call it */
 	if (type->startup) {
@@ -1338,6 +1352,7 @@
 				serial->port[i].tty->driver_data = NULL;
 		}
 
+		serial->dev = NULL;
 		serial_shutdown (serial);
 
 		for (i = 0; i < serial->num_ports; ++i)
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.4.11/linux/drivers/usb/serial/visor.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/usb/serial/visor.c	Wed Oct 10 23:42:47 2001
@@ -380,21 +380,26 @@
 	--port->open_count;
 
 	if (port->open_count <= 0) {
-		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);
+		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);
 		}
-
-		/* shutdown our bulk read */
-		usb_unlink_urb (port->read_urb);
 		port->active = 0;
 		port->open_count = 0;
-
 	}
 	up (&port->sem);
 
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.11/linux/drivers/usb/uhci.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/uhci.c	Wed Oct 10 01:23:09 2001
@@ -1594,9 +1594,7 @@
 	}
 
 	uhci_unlink_generic(uhci, urb);
-	uhci_destroy_urb_priv(urb);
-
-	usb_dec_dev_use(urb->dev);
+	uhci_call_completion(urb);
 
 	return ret;
 }
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/usbvideo.c linux/drivers/usb/usbvideo.c
--- v2.4.11/linux/drivers/usb/usbvideo.c	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/usbvideo.c	Wed Oct 10 23:42:46 2001
@@ -84,27 +84,6 @@
 	return ret;
 }
 
-unsigned long usbvideo_uvirt_to_bus(unsigned long adr)
-{
-	unsigned long kva, ret;
-
-	kva = usbvideo_uvirt_to_kva(pgd_offset(current->mm, adr), adr);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
-unsigned long usbvideo_kvirt_to_bus(unsigned long adr)
-{
-	unsigned long va, kva, ret;
-
-	va = VMALLOC_VMADDR(adr);
-	kva = usbvideo_uvirt_to_kva(pgd_offset_k(va), va);
-	ret = virt_to_bus((void *)kva);
-	MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));
-	return ret;
-}
-
 /*
  * Here we want the physical address of the memory.
  * This is used when initializing the contents of the
diff -u --recursive --new-file v2.4.11/linux/drivers/usb/usbvideo.h linux/drivers/usb/usbvideo.h
--- v2.4.11/linux/drivers/usb/usbvideo.h	Tue Oct  9 17:06:53 2001
+++ linux/drivers/usb/usbvideo.h	Wed Oct 10 23:42:46 2001
@@ -329,8 +329,6 @@
 
 /* Memory allocation routines */
 unsigned long usbvideo_uvirt_to_kva(pgd_t *pgd, unsigned long adr);
-unsigned long usbvideo_uvirt_to_bus(unsigned long adr);
-unsigned long usbvideo_kvirt_to_bus(unsigned long adr);
 unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
 void *usbvideo_rvmalloc(unsigned long size);
 void usbvideo_rvfree(void *mem, unsigned long size);
diff -u --recursive --new-file v2.4.11/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- v2.4.11/linux/drivers/video/fbmem.c	Sun Sep 23 11:41:00 2001
+++ linux/drivers/video/fbmem.c	Wed Oct 10 15:47:16 2001
@@ -124,6 +124,8 @@
 extern int e1355fb_setup(char*);
 extern int pvr2fb_init(void);
 extern int pvr2fb_setup(char*);
+extern int sstfb_init(void);
+extern int sstfb_setup(char*);
 
 static struct {
 	const char *name;
@@ -274,7 +276,9 @@
 #ifdef CONFIG_FB_PVR2
 	{ "pvr2", pvr2fb_init, pvr2fb_setup },
 #endif
-
+#ifdef CONFIG_FB_VOODOO1
+	{ "sst", sstfb_init, sstfb_setup },
+#endif
 	/*
 	 * Generic drivers that don't use resource management (yet)
 	 */
diff -u --recursive --new-file v2.4.11/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.4.11/linux/fs/devfs/base.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/devfs/base.c	Wed Oct 10 23:23:24 2001
@@ -548,6 +548,13 @@
     20010927   Richard Gooch <rgooch@atnf.csiro.au>
 	       Went back to global rwsem for symlinks (refcount scheme no good)
   v0.117
+    20011008   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed overrun in <devfs_link> by removing function (not needed).
+  v0.118
+    20011009   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed buffer underrun in <try_modload>.
+	       Moved down_read() from <search_for_entry_in_dir> to <find_entry>
+  v0.119
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -580,7 +587,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "0.117 (20010927)"
+#define DEVFS_VERSION            "0.119 (20011009)"
 
 #define DEVFS_NAME "devfs"
 
@@ -810,12 +817,10 @@
     if (curr == NULL) return NULL;
     if (!S_ISLNK (curr->mode) || !traverse_symlink) return curr;
     /*  Need to follow the link: this is a stack chomper  */
-    down_read (&symlink_rwsem);
     retval = curr->registered ?
 	search_for_entry (parent, curr->u.symlink.linkname,
 			  curr->u.symlink.length, FALSE, FALSE, NULL,
 			  TRUE) : NULL;
-    up_read (&symlink_rwsem);
     return retval;
 }   /*  End Function search_for_entry_in_dir  */
 
@@ -1085,8 +1090,10 @@
 	    ++name;
 	    --namelen;
 	}
+	if (traverse_symlink) down_read (&symlink_rwsem);
 	entry = search_for_entry (dir, name, namelen, FALSE, FALSE, NULL,
 				  traverse_symlink);
+	if (traverse_symlink) up_read (&symlink_rwsem);
 	if (entry != NULL) return entry;
     }
     /*  Have to search by major and minor: slow  */
@@ -1647,8 +1654,7 @@
     devfs_handle_t de;
 
     if ( (name != NULL) && (name[0] == '\0') ) name = NULL;
-    de = find_entry (dir, name, 0, major, minor, type,
-		     traverse_symlinks);
+    de = find_entry (dir, name, 0, major, minor, type, traverse_symlinks);
     if (de == NULL) return NULL;
     if (!de->registered) return NULL;
     return de;
@@ -2138,7 +2144,7 @@
     if ( !( fs_info->devfsd_event_mask & (1 << DEVFSD_NOTIFY_LOOKUP) ) )
 	return -ENOENT;
     if ( is_devfsd_or_child (fs_info) ) return -ENOENT;
-    if (namelen >= STRING_LENGTH) return -ENAMETOOLONG;
+    if (namelen >= STRING_LENGTH - 1) return -ENAMETOOLONG;
     memcpy (buf + pos, name, namelen);
     buf[STRING_LENGTH - 1] = '\0';
     if (parent->parent != NULL) pos = devfs_generate_path (parent, buf, pos);
@@ -2781,19 +2787,6 @@
     return NULL;
 }   /*  End Function devfs_lookup  */
 
-static int devfs_link (struct dentry *old_dentry, struct inode *dir,
-		       struct dentry *dentry)
-{
-    /*struct inode *inode = old_dentry->d_inode;*/
-    char txt[STRING_LENGTH];
-
-    memset (txt, 0, STRING_LENGTH);
-    memcpy (txt, old_dentry->d_name.name, old_dentry->d_name.len);
-    txt[STRING_LENGTH - 1] = '\0';
-    printk ("%s: link of \"%s\"\n", DEVFS_NAME, txt);
-    return -EPERM;
-}   /*  End Function devfs_link  */
-
 static int devfs_unlink (struct inode *dir, struct dentry *dentry)
 {
     struct devfs_entry *de;
@@ -3054,7 +3047,6 @@
 static struct inode_operations devfs_dir_iops =
 {
     lookup:         devfs_lookup,
-    link:           devfs_link,
     unlink:         devfs_unlink,
     symlink:        devfs_symlink,
     mkdir:          devfs_mkdir,
diff -u --recursive --new-file v2.4.11/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.4.11/linux/fs/ext2/inode.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/ext2/inode.c	Wed Oct 10 23:42:47 2001
@@ -1148,63 +1148,3 @@
 {
 	return ext2_update_inode (inode, 1);
 }
-
-int ext2_notify_change(struct dentry *dentry, struct iattr *iattr)
-{
-	struct inode *inode = dentry->d_inode;
-	int		retval;
-	unsigned int	flags;
-	
-	retval = -EPERM;
-	if (iattr->ia_valid & ATTR_ATTR_FLAG &&
-	    ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) !=
-	      !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) ||
-	     (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) !=
-	      !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) {
-		if (!capable(CAP_LINUX_IMMUTABLE))
-			goto out;
-	} else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
-		goto out;
-
-	retval = inode_change_ok(inode, iattr);
-	if (retval != 0 || (((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-	    (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) &&
-	    DQUOT_TRANSFER(inode, iattr)))
-		goto out;
-
-	inode_setattr(inode, iattr);
-	
-	flags = iattr->ia_attr_flags;
-	if (flags & ATTR_FLAG_SYNCRONOUS) {
-		inode->i_flags |= S_SYNC;
-		inode->u.ext2_i.i_flags |= EXT2_SYNC_FL;
-	} else {
-		inode->i_flags &= ~S_SYNC;
-		inode->u.ext2_i.i_flags &= ~EXT2_SYNC_FL;
-	}
-	if (flags & ATTR_FLAG_NOATIME) {
-		inode->i_flags |= S_NOATIME;
-		inode->u.ext2_i.i_flags |= EXT2_NOATIME_FL;
-	} else {
-		inode->i_flags &= ~S_NOATIME;
-		inode->u.ext2_i.i_flags &= ~EXT2_NOATIME_FL;
-	}
-	if (flags & ATTR_FLAG_APPEND) {
-		inode->i_flags |= S_APPEND;
-		inode->u.ext2_i.i_flags |= EXT2_APPEND_FL;
-	} else {
-		inode->i_flags &= ~S_APPEND;
-		inode->u.ext2_i.i_flags &= ~EXT2_APPEND_FL;
-	}
-	if (flags & ATTR_FLAG_IMMUTABLE) {
-		inode->i_flags |= S_IMMUTABLE;
-		inode->u.ext2_i.i_flags |= EXT2_IMMUTABLE_FL;
-	} else {
-		inode->i_flags &= ~S_IMMUTABLE;
-		inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL;
-	}
-	mark_inode_dirty(inode);
-out:
-	return retval;
-}
-
diff -u --recursive --new-file v2.4.11/linux/fs/namei.c linux/fs/namei.c
--- v2.4.11/linux/fs/namei.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/namei.c	Wed Oct 10 23:15:49 2001
@@ -325,9 +325,7 @@
 }
 
 /*
- * Yes, this really increments the link_count by 5, and
- * decrements it by 4. Together with checking against 40,
- * this limits recursive symlink follows to 8, while
+ * This limits recursive symlink follows to 8, while
  * limiting consecutive symlinks to 40.
  *
  * Without that kind of total limit, nasty chains of consecutive
@@ -336,16 +334,19 @@
 static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
 	int err;
-	if (current->link_count >= 40)
+	if (current->link_count >= 5)
+		goto loop;
+	if (current->total_link_count >= 40)
 		goto loop;
 	if (current->need_resched) {
 		current->state = TASK_RUNNING;
 		schedule();
 	}
-	current->link_count += 5;
+	current->link_count++;
+	current->total_link_count++;
 	UPDATE_ATIME(dentry->d_inode);
 	err = dentry->d_inode->i_op->follow_link(dentry, nd);
-	current->link_count -= 4;
+	current->link_count--;
 	return err;
 loop:
 	path_release(nd);
@@ -636,7 +637,7 @@
 
 int path_walk(const char * name, struct nameidata *nd)
 {
-	current->link_count = 0;
+	current->total_link_count = 0;
 	return link_path_walk(name, nd);
 }
 
diff -u --recursive --new-file v2.4.11/linux/fs/namespace.c linux/fs/namespace.c
--- v2.4.11/linux/fs/namespace.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/namespace.c	Wed Oct 10 15:39:04 2001
@@ -336,9 +336,6 @@
 	struct vfsmount *p;
 	LIST_HEAD(kill);
 
-	if (list_empty(&mnt->mnt_list))
-		return;
-
 	for (p = mnt; p; p = next_mnt(p, mnt)) {
 		list_del(&p->mnt_list);
 		list_add(&p->mnt_list, &kill);
@@ -418,7 +415,8 @@
 	}
 	retval = -EBUSY;
 	if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
-		umount_tree(mnt);
+		if (!list_empty(&mnt->mnt_list))
+			umount_tree(mnt);
 		retval = 0;
 	}
 	spin_unlock(&dcache_lock);
@@ -592,9 +590,10 @@
 
 	if (mnt) {
 		err = graft_tree(mnt, nd);
-		if (err && recurse)
+		if (err)
 			umount_tree(mnt);
-		mntput(mnt);
+		else
+			mntput(mnt);
 	}
 
 	up(&mount_sem);
diff -u --recursive --new-file v2.4.11/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.4.11/linux/fs/proc/base.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/proc/base.c	Wed Oct 10 23:42:47 2001
@@ -184,29 +184,6 @@
 
 /* permission checks */
 
-static int standard_permission(struct inode *inode, int mask)
-{
-	int mode = inode->i_mode;
-
-	if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
-	    (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
-		return -EROFS; /* Nobody gets write access to a read-only fs */
-	else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
-		return -EACCES; /* Nobody gets write access to an immutable file */
-	else if (current->fsuid == inode->i_uid)
-		mode >>= 6;
-	else if (in_group_p(inode->i_gid))
-		mode >>= 3;
-	if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
-		return 0;
-	/* read and search access */
-	if ((mask == S_IROTH) ||
-	    (S_ISDIR(mode)  && !(mask & ~(S_IROTH | S_IXOTH))))
-		if (capable(CAP_DAC_READ_SEARCH))
-			return 0;
-	return -EACCES;
-}
-
 static int proc_check_root(struct inode *inode)
 {
 	struct dentry *de, *base, *root;
@@ -249,7 +226,7 @@
 
 static int proc_permission(struct inode *inode, int mask)
 {
-	if (standard_permission(inode, mask) != 0)
+	if (vfs_permission(inode, mask) != 0)
 		return -EACCES;
 	return proc_check_root(inode);
 }
diff -u --recursive --new-file v2.4.11/linux/fs/super.c linux/fs/super.c
--- v2.4.11/linux/fs/super.c	Tue Oct  9 17:06:53 2001
+++ linux/fs/super.c	Wed Oct 10 15:39:04 2001
@@ -443,7 +443,7 @@
 
 static struct super_block * read_super(kdev_t dev, struct block_device *bdev,
 				       struct file_system_type *type, int flags,
-				       void *data, int silent)
+				       void *data)
 {
 	struct super_block * s;
 	s = alloc_super();
@@ -460,7 +460,7 @@
 	spin_unlock(&sb_lock);
 	down_write(&s->s_umount);
 	lock_super(s);
-	if (!type->read_super(s, data, silent))
+	if (!type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
 		goto out_fail;
 	unlock_super(s);
 	/* tell bdcache that we are going to keep this one */
@@ -612,7 +612,7 @@
 
 	error = -EINVAL;
 	lock_super(s);
-	if (!fs_type->read_super(s, data, 0))
+	if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
 		goto out_fail;
 	unlock_super(s);
 	get_filesystem(fs_type);
@@ -646,7 +646,7 @@
 	if (dev) {
 		struct super_block * sb;
 		error = -EINVAL;
-		sb = read_super(dev, NULL, fs_type, flags, data, 0);
+		sb = read_super(dev, NULL, fs_type, flags, data);
 		if (sb) {
 			get_filesystem(fs_type);
 			return sb;
@@ -692,7 +692,7 @@
 		s->s_count += S_BIAS;
 		spin_unlock(&sb_lock);
 		lock_super(s);
-		if (!fs_type->read_super(s, data, 0))
+		if (!fs_type->read_super(s, data, flags & MS_VERBOSE ? 1 : 0))
 			goto out_fail;
 		unlock_super(s);
 		get_filesystem(fs_type);
@@ -865,10 +865,45 @@
 	return do_kern_mount((char *)type->name, 0, (char *)type->name, NULL);
 }
 
+static char * __initdata root_fs_names;
+static int __init fs_names_setup(char *str)
+{
+	root_fs_names = str;
+	return 0;
+}
+
+__setup("rootfstype=", fs_names_setup);
+
+static void __init get_fs_names(char *page)
+{
+	char *s = page;
+
+	if (root_fs_names) {
+		strcpy(page, root_fs_names);
+		while (*s++) {
+			if (s[-1] == ',')
+				s[-1] = '\0';
+		}
+	} else {
+		int len = get_filesystem_list(page);
+		char *p, *next;
+
+		page[len] = '\0';
+		for (p = page-1; p; p = next) {
+			next = strchr(++p, '\n');
+			if (*p++ != '\t')
+				continue;
+			while ((*s++ = *p++) != '\n')
+				;
+			s[-1] = '\0';
+		}
+	}
+	*s = '\0';
+}
+
 void __init mount_root(void)
 {
 	struct nameidata root_nd;
-	struct file_system_type * fs_type;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
 	struct block_device *bdev = NULL;
@@ -878,36 +913,24 @@
 	char path[64];
 	int path_start = -1;
 	char *name = "/dev/root";
-
+	char *fs_names, *p;
 #ifdef CONFIG_ROOT_NFS
 	void *data;
+#endif
+	root_mountflags |= MS_VERBOSE;
+
+#ifdef CONFIG_ROOT_NFS
 	if (MAJOR(ROOT_DEV) != UNNAMED_MAJOR)
 		goto skip_nfs;
-	fs_type = get_fs_type("nfs");
-	if (!fs_type)
-		goto no_nfs;
-	ROOT_DEV = get_unnamed_dev();
-	if (!ROOT_DEV)
-		/*
-		 * Your /linuxrc sucks worse than MSExchange - that's the
-		 * only way you could run out of anon devices at that point.
-		 */
-		goto no_anon;
 	data = nfs_root_data();
 	if (!data)
-		goto no_server;
-	sb = read_super(ROOT_DEV, NULL, fs_type, root_mountflags, data, 1);
-	if (sb)
-		/*
-		 * We _can_ fail there, but if that will happen we have no
-		 * chance anyway (no memory for vfsmnt and we _will_ need it,
-		 * no matter which fs we try to mount).
-		 */
-		goto mount_it;
-no_server:
-	put_unnamed_dev(ROOT_DEV);
-no_anon:
-	put_filesystem(fs_type);
+		goto no_nfs;
+	vfsmnt = do_kern_mount("nfs", root_mountflags, "/dev/root", data);
+	if (!IS_ERR(vfsmnt)) {
+		printk ("VFS: Mounted root (%s filesystem).\n", "nfs");
+		ROOT_DEV = vfsmnt->mnt_sb->s_dev;
+		goto attach_it;
+	}
 no_nfs:
 	printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
 	ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
@@ -936,6 +959,9 @@
 	}
 #endif
 
+	fs_names = __getname();
+	get_fs_names(fs_names);
+
 	devfs_make_root (root_device_name);
 	handle = devfs_find_handle (NULL, ROOT_DEVICE_NAME,
 	                            MAJOR (ROOT_DEV), MINOR (ROOT_DEV),
@@ -985,35 +1011,30 @@
 	sb = get_super(ROOT_DEV);
 	if (sb) {
 		/* FIXME */
-		fs_type = sb->s_type;
+		p = (char *)sb->s_type->name;
 		atomic_inc(&sb->s_active);
 		up_read(&sb->s_umount);
 		down_write(&sb->s_umount);
 		goto mount_it;
 	}
 
-	read_lock(&file_systems_lock);
-	for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
-  		if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
+	for (p = fs_names; *p; p += strlen(p)+1) {
+		struct file_system_type * fs_type = get_fs_type(p);
+		if (!fs_type)
   			continue;
-		if (!try_inc_mod_count(fs_type->owner))
-			continue;
-		read_unlock(&file_systems_lock);
-  		sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL,1);
+  		sb = read_super(ROOT_DEV,bdev,fs_type,root_mountflags,NULL);
 		if (sb) 
 			goto mount_it;
-		read_lock(&file_systems_lock);
 		put_filesystem(fs_type);
 	}
-	read_unlock(&file_systems_lock);
 	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
 
 mount_it:
 	/* FIXME */
 	up_write(&sb->s_umount);
-	printk ("VFS: Mounted root (%s filesystem)%s.\n",
-		fs_type->name,
+	printk ("VFS: Mounted root (%s filesystem)%s.\n", p,
 		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
+	putname(fs_names);
 	if (path_start >= 0) {
 		name = path + path_start;
 		devfs_mk_symlink (NULL, "root", DEVFS_FL_DEFAULT,
@@ -1027,18 +1048,15 @@
 	set_devname(vfsmnt, name);
 	vfsmnt->mnt_sb = sb;
 	vfsmnt->mnt_root = dget(sb->s_root);
+	bdput(bdev); /* sb holds a reference */
 
+attach_it:
 	root_nd.mnt = root_vfsmnt;
 	root_nd.dentry = root_vfsmnt->mnt_sb->s_root;
 	graft_tree(vfsmnt, &root_nd);
-	mntput(vfsmnt);
 
-	/* FIXME: if something will try to umount us right now... */
-	if (vfsmnt) {
-		set_fs_root(current->fs, vfsmnt, sb->s_root);
-		set_fs_pwd(current->fs, vfsmnt, sb->s_root);
-		if (bdev)
-			bdput(bdev); /* sb holds a reference */
-		return;
-	}
+	set_fs_root(current->fs, vfsmnt, vfsmnt->mnt_root);
+	set_fs_pwd(current->fs, vfsmnt, vfsmnt->mnt_root);
+
+	mntput(vfsmnt);
 }
diff -u --recursive --new-file v2.4.11/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.4.11/linux/include/asm-i386/smp.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-i386/smp.h	Thu Oct 11 00:50:24 2001
@@ -31,7 +31,7 @@
 #  define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
 # endif
 #else
-# define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
+# define INT_DELIVERY_MODE 1     /* logical delivery */
 # define TARGET_CPUS 0x01
 #endif
 
diff -u --recursive --new-file v2.4.11/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v2.4.11/linux/include/asm-sparc/processor.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-sparc/processor.h	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.82 2001/09/20 00:35:34 davem Exp $
+/* $Id: processor.h,v 1.83 2001/10/08 09:32:13 davem Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.11/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h
--- v2.4.11/linux/include/asm-sparc/unistd.h	Mon Aug 14 13:09:07 2000
+++ linux/include/asm-sparc/unistd.h	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.70 2000/08/14 05:39:07 jj Exp $ */
+/* $Id: unistd.h,v 1.71 2001/10/09 10:54:39 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -158,7 +158,7 @@
 /* #define __NR_adjtime         140    SunOS Specific                              */
 #define __NR_getpeername        141 /* Common                                      */
 /* #define __NR_gethostid       142    SunOS Specific                              */
-/* #define __NR_ni_syscall      143    ENOSYS under SunOS                          */
+#define __NR_gettid             143 /* ENOSYS under SunOS                          */
 #define __NR_getrlimit          144 /* Common                                      */
 #define __NR_setrlimit          145 /* Common                                      */
 #define __NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
diff -u --recursive --new-file v2.4.11/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h
--- v2.4.11/linux/include/asm-sparc64/processor.h	Tue Oct  9 17:06:53 2001
+++ linux/include/asm-sparc64/processor.h	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.75 2001/09/20 00:35:34 davem Exp $
+/* $Id: processor.h,v 1.76 2001/10/08 09:32:13 davem Exp $
  * include/asm-sparc64/processor.h
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.4.11/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h
--- v2.4.11/linux/include/asm-sparc64/unistd.h	Mon Aug 14 13:09:08 2000
+++ linux/include/asm-sparc64/unistd.h	Wed Oct 10 23:42:47 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.47 2000/08/14 05:39:07 jj Exp $ */
+/* $Id: unistd.h,v 1.48 2001/10/09 10:54:39 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -158,7 +158,7 @@
 /* #define __NR_adjtime         140    SunOS Specific                              */
 #define __NR_getpeername        141 /* Common                                      */
 /* #define __NR_gethostid       142    SunOS Specific                              */
-/* #define __NR_ni_syscall      143    ENOSYS under SunOS                          */
+#define __NR_gettid             143 /* ENOSYS under SunOS                          */
 #define __NR_getrlimit		144 /* Common                                      */
 #define __NR_setrlimit          145 /* Common                                      */
 #define __NR_pivot_root		146 /* Linux Specific, killpg under SunOS          */
diff -u --recursive --new-file v2.4.11/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.4.11/linux/include/linux/ext2_fs.h	Tue Oct  9 17:06:53 2001
+++ linux/include/linux/ext2_fs.h	Wed Oct 10 23:45:08 2001
@@ -545,9 +545,6 @@
 # define ATTRIB_NORET  __attribute__((noreturn))
 # define NORET_AND     noreturn,
 
-/* acl.c */
-extern int ext2_permission (struct inode *, int);
-
 /* balloc.c */
 extern int ext2_bg_has_super(struct super_block *sb, int group);
 extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
diff -u --recursive --new-file v2.4.11/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.11/linux/include/linux/fs.h	Tue Oct  9 17:06:53 2001
+++ linux/include/linux/fs.h	Wed Oct 10 23:44:34 2001
@@ -109,6 +109,7 @@
 #define MS_NODIRATIME	2048	/* Do not update directory access times */
 #define MS_BIND		4096
 #define MS_REC		16384
+#define MS_VERBOSE	32768
 #define MS_NOUSER	(1<<31)
 
 /*
diff -u --recursive --new-file v2.4.11/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.4.11/linux/include/linux/netdevice.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/netdevice.h	Wed Oct 10 23:44:52 2001
@@ -636,6 +636,41 @@
 	}
 }
 
+/*
+ * Network interface message level settings
+ */
+#define HAVE_NETIF_MSG 1
+
+enum {
+	NETIF_MSG_DRV		= 0x0001,
+	NETIF_MSG_PROBE		= 0x0002,
+	NETIF_MSG_LINK		= 0x0004,
+	NETIF_MSG_TIMER		= 0x0008,
+	NETIF_MSG_IFDOWN	= 0x0010,
+	NETIF_MSG_IFUP		= 0x0020,
+	NETIF_MSG_RX_ERR	= 0x0040,
+	NETIF_MSG_TX_ERR	= 0x0080,
+	NETIF_MSG_TX_QUEUED	= 0x0100,
+	NETIF_MSG_INTR		= 0x0200,
+	NETIF_MSG_TX_DONE	= 0x0400,
+	NETIF_MSG_RX_STATUS	= 0x0800,
+	NETIF_MSG_PKTDATA	= 0x1000,
+};
+
+#define netif_msg_drv(p)	((p)->msg_enable & NETIF_MSG_DRV)
+#define netif_msg_probe(p)	((p)->msg_enable & NETIF_MSG_PROBE)
+#define netif_msg_link(p)	((p)->msg_enable & NETIF_MSG_LINK)
+#define netif_msg_timer(p)	((p)->msg_enable & NETIF_MSG_TIMER)
+#define netif_msg_ifdown(p)	((p)->msg_enable & NETIF_MSG_IFDOWN)
+#define netif_msg_ifup(p)	((p)->msg_enable & NETIF_MSG_IFUP)
+#define netif_msg_rx_err(p)	((p)->msg_enable & NETIF_MSG_RX_ERR)
+#define netif_msg_tx_err(p)	((p)->msg_enable & NETIF_MSG_TX_ERR)
+#define netif_msg_tx_queued(p)	((p)->msg_enable & NETIF_MSG_TX_QUEUED)
+#define netif_msg_intr(p)	((p)->msg_enable & NETIF_MSG_INTR)
+#define netif_msg_tx_done(p)	((p)->msg_enable & NETIF_MSG_TX_DONE)
+#define netif_msg_rx_status(p)	((p)->msg_enable & NETIF_MSG_RX_STATUS)
+#define netif_msg_pktdata(p)	((p)->msg_enable & NETIF_MSG_PKTDATA)
+
 /* These functions live elsewhere (drivers/net/net_init.c, but related) */
 
 extern void		ether_setup(struct net_device *dev);
diff -u --recursive --new-file v2.4.11/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.4.11/linux/include/linux/parport.h	Sun Aug 12 13:28:01 2001
+++ linux/include/linux/parport.h	Wed Oct 10 23:19:30 2001
@@ -251,7 +251,8 @@
 	IEEE1284_PH_REV_DATA,
 	IEEE1284_PH_ECP_SETUP,
 	IEEE1284_PH_ECP_FWD_TO_REV,
-	IEEE1284_PH_ECP_REV_TO_FWD
+	IEEE1284_PH_ECP_REV_TO_FWD,
+	IEEE1284_PH_ECP_DIR_UNKNOWN,
 };
 struct ieee1284_info {
 	int mode;
diff -u --recursive --new-file v2.4.11/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.11/linux/include/linux/pci_ids.h	Tue Oct  9 17:06:53 2001
+++ linux/include/linux/pci_ids.h	Wed Oct 10 23:19:30 2001
@@ -1437,9 +1437,11 @@
 #define PCI_DEVICE_ID_TIMEDIA_1889	0x7168
 
 #define PCI_VENDOR_ID_OXSEMI		0x1415
+#define PCI_DEVICE_ID_OXSEMI_12PCI840	0x8403
 #define PCI_DEVICE_ID_OXSEMI_16PCI954	0x9501
 #define PCI_DEVICE_ID_OXSEMI_16PCI952	0x950A
 #define PCI_DEVICE_ID_OXSEMI_16PCI95N	0x9511
+#define PCI_DEVICE_ID_OXSEMI_16PCI954PP	0x9513
 
 #define PCI_VENDOR_ID_AIRONET		0x14b9
 #define PCI_DEVICE_ID_AIRONET_4800_1	0x0001
@@ -1462,9 +1464,6 @@
 #define PCI_VENDOR_ID_PANACOM		0x14d4
 #define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
 #define PCI_DEVICE_ID_PANACOM_DUALMODEM	0x0402
-
-#define PCI_VENDOR_ID_AFAVLAB		0x14db
-#define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
 
 #define PCI_VENDOR_ID_BROADCOM		0x14e4
 #define PCI_DEVICE_ID_TIGON3		0x1644
diff -u --recursive --new-file v2.4.11/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.4.11/linux/include/linux/sched.h	Sun Sep 23 11:41:01 2001
+++ linux/include/linux/sched.h	Wed Oct 10 23:44:34 2001
@@ -369,7 +369,7 @@
 	unsigned short used_math;
 	char comm[16];
 /* file system info */
-	int link_count;
+	int link_count, total_link_count;
 	struct tty_struct *tty; /* NULL if no tty */
 	unsigned int locks; /* How many file locks are being held */
 /* ipc stuff */
diff -u --recursive --new-file v2.4.11/linux/include/linux/shmem_fs.h linux/include/linux/shmem_fs.h
--- v2.4.11/linux/include/linux/shmem_fs.h	Thu Apr 12 12:25:53 2001
+++ linux/include/linux/shmem_fs.h	Wed Oct 10 07:53:57 2001
@@ -17,14 +17,18 @@
 	unsigned long val;
 } swp_entry_t;
 
+extern atomic_t shmem_nrpages;
+
 struct shmem_inode_info {
-	spinlock_t	lock;
-	unsigned long	max_index;
-	swp_entry_t	i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
-	swp_entry_t   **i_indirect; /* doubly indirect blocks */
-	unsigned long	swapped;
-	int		locked;     /* into memory */
+	spinlock_t		lock;
+	struct semaphore 	sem;
+	unsigned long		next_index;
+	swp_entry_t		i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */
+	void		      **i_indirect; /* indirect blocks */
+	unsigned long		swapped;
+	int			locked;     /* into memory */
 	struct list_head	list;
+	struct inode	       *inode;
 };
 
 struct shmem_sb_info {
@@ -34,5 +38,7 @@
 	unsigned long free_inodes;  /* How many are left for allocation */
 	spinlock_t    stat_lock;
 };
+
+#define SHMEM_I(inode)  (&inode->u.shmem_i)
 
 #endif
diff -u --recursive --new-file v2.4.11/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.11/linux/mm/shmem.c	Tue Oct  9 17:06:53 2001
+++ linux/mm/shmem.c	Wed Oct 10 07:53:57 2001
@@ -26,15 +26,16 @@
 #include <linux/pagemap.h>
 #include <linux/string.h>
 #include <linux/locks.h>
-#include <asm/smplock.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
 /* This magic number is used in glibc for posix shared memory */
 #define TMPFS_MAGIC	0x01021994
 
-#define ENTRIES_PER_PAGE (PAGE_SIZE/sizeof(unsigned long))
-#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE*ENTRIES_PER_PAGE)
+#define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long))
+
+#define SHMEM_SB(sb) (&sb->u.shmem_sb)
 
 static struct super_operations shmem_ops;
 static struct address_space_operations shmem_aops;
@@ -42,18 +43,19 @@
 static struct inode_operations shmem_inode_operations;
 static struct file_operations shmem_dir_operations;
 static struct inode_operations shmem_dir_inode_operations;
-static struct inode_operations shmem_symlink_inode_operations;
 static struct vm_operations_struct shmem_vm_ops;
 
 LIST_HEAD (shmem_inodes);
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
+atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */
 
-#define BLOCKS_PER_PAGE (PAGE_SIZE/512)
+#define BLOCKS_PER_PAGE (PAGE_CACHE_SIZE/512)
 
 /*
  * shmem_recalc_inode - recalculate the size of an inode
  *
  * @inode: inode to recalc
+ * @swap:  additional swap pages freed externally
  *
  * We have to calculate the free blocks since the mm can drop pages
  * behind our back
@@ -64,7 +66,7 @@
  *
  * So the mm freed 
  * inodes->i_blocks/BLOCKS_PER_PAGE - 
- *			(inode->i_mapping->nrpages + info->swapped)
+ * 			(inode->i_mapping->nrpages + info->swapped)
  *
  * It has to be called with the spinlock held.
  */
@@ -74,19 +76,63 @@
 	unsigned long freed;
 
 	freed = (inode->i_blocks/BLOCKS_PER_PAGE) -
-		(inode->i_mapping->nrpages + inode->u.shmem_i.swapped);
+		(inode->i_mapping->nrpages + SHMEM_I(inode)->swapped);
 	if (freed){
-		struct shmem_sb_info * info = &inode->i_sb->u.shmem_sb;
+		struct shmem_sb_info * sbinfo = SHMEM_SB(inode->i_sb);
 		inode->i_blocks -= freed*BLOCKS_PER_PAGE;
-		spin_lock (&info->stat_lock);
-		info->free_blocks += freed;
-		spin_unlock (&info->stat_lock);
+		spin_lock (&sbinfo->stat_lock);
+		sbinfo->free_blocks += freed;
+		spin_unlock (&sbinfo->stat_lock);
 	}
 }
 
-static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index) 
+/*
+ * shmem_swp_entry - find the swap vector position in the info structure
+ *
+ * @info:  info structure for the inode
+ * @index: index of the page to find
+ * @page:  optional page to add to the structure. Has to be preset to
+ *         all zeros
+ *
+ * If there is no space allocated yet it will return -ENOMEM when
+ * page == 0 else it will use the page for the needed block.
+ *
+ * returns -EFBIG if the index is too big.
+ *
+ *
+ * The swap vector is organized the following way:
+ *
+ * There are SHMEM_NR_DIRECT entries directly stored in the
+ * shmem_inode_info structure. So small files do not need an addional
+ * allocation.
+ *
+ * For pages with index > SHMEM_NR_DIRECT there is the pointer
+ * i_indirect which points to a page which holds in the first half
+ * doubly indirect blocks, in the second half triple indirect blocks:
+ *
+ * For an artificial ENTRIES_PER_PAGE = 4 this would lead to the
+ * following layout (for SHMEM_NR_DIRECT == 16):
+ *
+ * i_indirect -> dir --> 16-19
+ * 	      |	     +-> 20-23
+ * 	      |
+ * 	      +-->dir2 --> 24-27
+ * 	      |	       +-> 28-31
+ * 	      |	       +-> 32-35
+ * 	      |	       +-> 36-39
+ * 	      |
+ * 	      +-->dir3 --> 40-43
+ * 	       	       +-> 44-47
+ * 	      	       +-> 48-51
+ * 	      	       +-> 52-55
+ */
+
+#define SHMEM_MAX_BLOCKS (SHMEM_NR_DIRECT + ENTRIES_PER_PAGE * ENTRIES_PER_PAGE/2*(ENTRIES_PER_PAGE+1))
+
+static swp_entry_t * shmem_swp_entry (struct shmem_inode_info *info, unsigned long index, unsigned long page) 
 {
 	unsigned long offset;
+	void **dir;
 
 	if (index < SHMEM_NR_DIRECT)
 		return info->i_direct+index;
@@ -95,23 +141,66 @@
 	offset = index % ENTRIES_PER_PAGE;
 	index /= ENTRIES_PER_PAGE;
 
-	if (index >= ENTRIES_PER_PAGE)
-		return ERR_PTR(-EFBIG);
-
 	if (!info->i_indirect) {
-		info->i_indirect = (swp_entry_t **) get_zeroed_page(GFP_USER);
-		if (!info->i_indirect)
+		info->i_indirect = (void *) page;
+		return ERR_PTR(-ENOMEM);
+	}
+
+	dir = info->i_indirect + index;
+	if (index >= ENTRIES_PER_PAGE/2) {
+		index -= ENTRIES_PER_PAGE/2;
+		dir = info->i_indirect + ENTRIES_PER_PAGE/2 
+			+ index/ENTRIES_PER_PAGE;
+		index %= ENTRIES_PER_PAGE;
+
+		if(!*dir) {
+			*dir = (void *) page;
+			/* We return since we will need another page
+                           in the next step */
 			return ERR_PTR(-ENOMEM);
+		}
+		dir = ((void **)*dir) + index;
 	}
-	if(!(info->i_indirect[index])) {
-		info->i_indirect[index] = (swp_entry_t *) get_zeroed_page(GFP_USER);
-		if (!info->i_indirect[index])
+	if (!*dir) {
+		if (!page)
 			return ERR_PTR(-ENOMEM);
+		*dir = (void *)page;
 	}
-	
-	return info->i_indirect[index]+offset;
+	return ((swp_entry_t *)*dir) + offset;
 }
 
+/*
+ * shmem_alloc_entry - get the position of the swap entry for the
+ *                     page. If it does not exist allocate the entry
+ *
+ * @info:	info structure for the inode
+ * @index:	index of the page to find
+ */
+static inline swp_entry_t * shmem_alloc_entry (struct shmem_inode_info *info, unsigned long index)
+{
+	unsigned long page = 0;
+	swp_entry_t * res;
+
+	if (index >= SHMEM_MAX_BLOCKS)
+		return ERR_PTR(-EFBIG);
+
+	if (info->next_index <= index)
+		info->next_index = index + 1;
+
+	while ((res = shmem_swp_entry(info,index,page)) == ERR_PTR(-ENOMEM)) {
+		page = get_zeroed_page(GFP_USER);
+		if (!page)
+			break;
+	}
+	return res;
+}
+
+/*
+ * shmem_free_swp - free some swap entries in a directory
+ *
+ * @dir:   pointer to the directory
+ * @count: number of entries to scan
+ */
 static int shmem_free_swp(swp_entry_t *dir, unsigned int count)
 {
 	swp_entry_t *ptr, entry;
@@ -131,95 +220,197 @@
 }
 
 /*
- * shmem_truncate_part - free a bunch of swap entries
+ * shmem_truncate_direct - free the swap entries of a whole doubly
+ *                         indirect block
  *
- * @dir:	pointer to swp_entries 
- * @size:	number of entries in dir
- * @start:	offset to start from
- * @freed:	counter for freed pages
+ * @dir:	pointer to the pointer to the block
+ * @start:	offset to start from (in pages)
+ * @len:	how many pages are stored in this block
  *
- * It frees the swap entries from dir+start til dir+size
- *
- * returns 0 if it truncated something, else (offset-size)
+ * Returns the number of freed swap entries.
  */
 
-static unsigned long 
-shmem_truncate_part (swp_entry_t * dir, unsigned long size, 
-		     unsigned long start, unsigned long *freed) {
-	if (start > size)
-		return start - size;
-	if (dir)
-		*freed += shmem_free_swp (dir+start, size-start);
+static inline unsigned long 
+shmem_truncate_direct(swp_entry_t *** dir, unsigned long start, unsigned long len) {
+	swp_entry_t **last, **ptr;
+	unsigned long off, freed = 0;
+ 
+	if (!*dir)
+		return 0;
+
+	last = *dir + (len + ENTRIES_PER_PAGE-1) / ENTRIES_PER_PAGE;
+	off = start % ENTRIES_PER_PAGE;
+
+	for (ptr = *dir + start/ENTRIES_PER_PAGE; ptr < last; ptr++) {
+		if (!*ptr) {
+			off = 0;
+			continue;
+		}
+
+		if (!off) {
+			freed += shmem_free_swp(*ptr, ENTRIES_PER_PAGE);
+			free_page ((unsigned long) *ptr);
+			*ptr = 0;
+		} else {
+			freed += shmem_free_swp(*ptr+off,ENTRIES_PER_PAGE-off);
+			off = 0;
+		}
+	}
 	
-	return 0;
+	if (!start) {
+		free_page((unsigned long) *dir);
+		*dir = 0;
+	}
+	return freed;
+}
+
+/*
+ * shmem_truncate_indirect - truncate an inode
+ *
+ * @info:  the info structure of the inode
+ * @index: the index to truncate
+ *
+ * This function locates the last doubly indirect block and calls
+ * then shmem_truncate_direct to do the real work
+ */
+static inline unsigned long
+shmem_truncate_indirect(struct shmem_inode_info *info, unsigned long index)
+{
+	swp_entry_t ***base;
+	unsigned long baseidx, len, start;
+	unsigned long max = info->next_index-1;
+
+	if (max < SHMEM_NR_DIRECT) {
+		info->next_index = index;
+		return shmem_free_swp(info->i_direct + index,
+				      SHMEM_NR_DIRECT - index);
+	}
+
+	if (max < ENTRIES_PER_PAGE * ENTRIES_PER_PAGE/2 + SHMEM_NR_DIRECT) {
+		max -= SHMEM_NR_DIRECT;
+		base = (swp_entry_t ***) &info->i_indirect;
+		baseidx = SHMEM_NR_DIRECT;
+		len = max+1;
+	} else {
+		max -= ENTRIES_PER_PAGE*ENTRIES_PER_PAGE/2+SHMEM_NR_DIRECT;
+		if (max >= ENTRIES_PER_PAGE*ENTRIES_PER_PAGE*ENTRIES_PER_PAGE/2)
+			BUG();
+
+		baseidx = max & ~(ENTRIES_PER_PAGE*ENTRIES_PER_PAGE-1);
+		base = (swp_entry_t ***) info->i_indirect + ENTRIES_PER_PAGE/2 + baseidx/ENTRIES_PER_PAGE/ENTRIES_PER_PAGE ;
+		len = max - baseidx + 1;
+		baseidx += ENTRIES_PER_PAGE*ENTRIES_PER_PAGE/2+SHMEM_NR_DIRECT;
+	}
+
+	if (index > baseidx) {
+		info->next_index = index;
+		start = index - baseidx;
+	} else {
+		info->next_index = baseidx;
+		start = 0;
+	}
+	return shmem_truncate_direct(base, start, len);
 }
 
 static void shmem_truncate (struct inode * inode)
 {
-	int clear_base;
-	unsigned long index, start;
+	unsigned long index;
 	unsigned long freed = 0;
-	swp_entry_t **base, **ptr, **last;
-	struct shmem_inode_info * info = &inode->u.shmem_i;
+	struct shmem_inode_info * info = SHMEM_I(inode);
 
+	down(&info->sem);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 	spin_lock (&info->lock);
 	index = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (index > info->max_index)
-		goto out;
 
-	start = shmem_truncate_part (info->i_direct, SHMEM_NR_DIRECT, index, &freed);
+	while (index < info->next_index) 
+		freed += shmem_truncate_indirect(info, index);
 
-	if (!(base = info->i_indirect))
-		goto out;
+	info->swapped -= freed;
+	shmem_recalc_inode(inode);
+	spin_unlock (&info->lock);
+	up(&info->sem);
+}
 
-	clear_base = 1;
-	last = base + ((info->max_index - SHMEM_NR_DIRECT + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE);
-	for (ptr = base; ptr < last; ptr++) {
-		if (!start) {
-			if (!*ptr)
-				continue;
-			freed += shmem_free_swp (*ptr, ENTRIES_PER_PAGE);
-			free_page ((unsigned long) *ptr);
-			*ptr = 0;
-			continue;
-		}
-		clear_base = 0;
-		start = shmem_truncate_part (*ptr, ENTRIES_PER_PAGE, start, &freed);
+static void shmem_delete_inode(struct inode * inode)
+{
+	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
+
+	inode->i_size = 0;
+	if (inode->i_op->truncate == shmem_truncate){ 
+		spin_lock (&shmem_ilock);
+		list_del (&SHMEM_I(inode)->list);
+		spin_unlock (&shmem_ilock);
+		shmem_truncate (inode);
 	}
+	spin_lock (&sbinfo->stat_lock);
+	sbinfo->free_inodes++;
+	spin_unlock (&sbinfo->stat_lock);
+	clear_inode(inode);
+}
+
+static int shmem_clear_swp (swp_entry_t entry, swp_entry_t *ptr, int size) {
+	swp_entry_t *test;
 
-	if (clear_base) {
-		free_page ((unsigned long)base);
-		info->i_indirect = 0;
+	for (test = ptr; test < ptr + size; test++) {
+		if (test->val == entry.val) {
+			swap_free (entry);
+			*test = (swp_entry_t) {0};
+			return test - ptr;
+		}
 	}
+	return -1;
+}
 
-out:
-	/*
-	 * We have no chance to give an error, so we limit it to max
-	 * size here and the application will fail later
-	 */
-	if (index > SHMEM_MAX_BLOCKS) 
-		info->max_index = SHMEM_MAX_BLOCKS;
-	else
-		info->max_index = index;
-	info->swapped -= freed;
-	shmem_recalc_inode(inode);
+static int shmem_unuse_inode (struct shmem_inode_info *info, swp_entry_t entry, struct page *page)
+{
+	swp_entry_t *ptr;
+	unsigned long idx;
+	int offset;
+	
+	idx = 0;
+	spin_lock (&info->lock);
+	offset = shmem_clear_swp (entry, info->i_direct, SHMEM_NR_DIRECT);
+	if (offset >= 0)
+		goto found;
+
+	for (idx = SHMEM_NR_DIRECT; idx < info->next_index; 
+	     idx += ENTRIES_PER_PAGE) {
+		ptr = shmem_swp_entry(info, idx, 0);
+		if (IS_ERR(ptr))
+			continue;
+		offset = shmem_clear_swp (entry, ptr, ENTRIES_PER_PAGE);
+		if (offset >= 0)
+			goto found;
+	}
 	spin_unlock (&info->lock);
+	return 0;
+found:
+	add_to_page_cache(page, info->inode->i_mapping, offset + idx);
+	SetPageDirty(page);
+	SetPageUptodate(page);
+	UnlockPage(page);
+	info->swapped--;
+	spin_unlock(&info->lock);
+	return 1;
 }
 
-static void shmem_delete_inode(struct inode * inode)
+/*
+ * unuse_shmem() search for an eventually swapped out shmem page.
+ */
+void shmem_unuse(swp_entry_t entry, struct page *page)
 {
-	struct shmem_sb_info *info = &inode->i_sb->u.shmem_sb;
+	struct list_head *p;
+	struct shmem_inode_info * info;
 
 	spin_lock (&shmem_ilock);
-	list_del (&inode->u.shmem_i.list);
+	list_for_each(p, &shmem_inodes) {
+		info = list_entry(p, struct shmem_inode_info, list);
+
+		if (shmem_unuse_inode(info, entry, page))
+			break;
+	}
 	spin_unlock (&shmem_ilock);
-	inode->i_size = 0;
-	shmem_truncate (inode);
-	spin_lock (&info->stat_lock);
-	info->free_inodes++;
-	spin_unlock (&info->stat_lock);
-	clear_inode(inode);
 }
 
 /*
@@ -244,7 +435,7 @@
 	mapping = page->mapping;
 	index = page->index;
 	inode = mapping->host;
-	info = &inode->u.shmem_i;
+	info = SHMEM_I(inode);
 getswap:
 	swap = get_swap_page();
 	if (!swap.val) {
@@ -255,7 +446,7 @@
 	}
 
 	spin_lock(&info->lock);
-	entry = shmem_swp_entry(info, index);
+	entry = shmem_swp_entry(info, index, 0);
 	if (IS_ERR(entry))	/* this had been allocated on page allocation */
 		BUG();
 	shmem_recalc_inode(inode);
@@ -300,27 +491,25 @@
  * still need to guard against racing with shm_writepage(), which might
  * be trying to move the page to the swap cache as we run.
  */
-static struct page * shmem_getpage_locked(struct inode * inode, unsigned long idx)
+static struct page * shmem_getpage_locked(struct shmem_inode_info *info, struct inode * inode, unsigned long idx)
 {
 	struct address_space * mapping = inode->i_mapping;
-	struct shmem_inode_info *info;
+	struct shmem_sb_info *sbinfo;
 	struct page * page;
 	swp_entry_t *entry;
 
-	info = &inode->u.shmem_i;
-
 repeat:
 	page = find_lock_page(mapping, idx);
 	if (page)
 		return page;
 
-	entry = shmem_swp_entry (info, idx);
+	entry = shmem_alloc_entry (info, idx);
 	if (IS_ERR(entry))
 		return (void *)entry;
 
 	spin_lock (&info->lock);
 	
-	/* The shmem_swp_entry() call may have blocked, and
+	/* The shmem_alloc_entry() call may have blocked, and
 	 * shmem_writepage may have been moving a page between the page
 	 * cache and swap cache.  We need to recheck the page cache
 	 * under the protection of the info->lock spinlock. */
@@ -370,18 +559,19 @@
 		swap_free(*entry);
 		*entry = (swp_entry_t) {0};
 		delete_from_swap_cache(page);
-		flags = page->flags & ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_referenced | 1 << PG_arch_1);
+		flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1));
 		page->flags = flags | (1 << PG_dirty);
 		add_to_page_cache_locked(page, mapping, idx);
 		info->swapped--;
 		spin_unlock (&info->lock);
 	} else {
+		sbinfo = SHMEM_SB(inode->i_sb);
 		spin_unlock (&info->lock);
-		spin_lock (&inode->i_sb->u.shmem_sb.stat_lock);
-		if (inode->i_sb->u.shmem_sb.free_blocks == 0)
+		spin_lock (&sbinfo->stat_lock);
+		if (sbinfo->free_blocks == 0)
 			goto no_space;
-		inode->i_sb->u.shmem_sb.free_blocks--;
-		spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
+		sbinfo->free_blocks--;
+		spin_unlock (&sbinfo->stat_lock);
 
 		/* Ok, get a new page.  We don't have to worry about the
 		 * info->lock spinlock here: we cannot race against
@@ -404,7 +594,7 @@
 		page_cache_get(page);
 	return page;
 no_space:
-	spin_unlock (&inode->i_sb->u.shmem_sb.stat_lock);
+	spin_unlock (&sbinfo->stat_lock);
 	return ERR_PTR(-ENOSPC);
 
 wait_retry:
@@ -416,28 +606,28 @@
 
 static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr)
 {
+	struct shmem_inode_info *info = SHMEM_I(inode);
 	int error;
 
-	down (&inode->i_sem);
+	down (&info->sem);
+	*ptr = ERR_PTR(-EFAULT);
 	if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE)
-		goto sigbus;
-	*ptr = shmem_getpage_locked(inode, idx);
+		goto failed;
+
+	*ptr = shmem_getpage_locked(info, inode, idx);
 	if (IS_ERR (*ptr))
 		goto failed;
+
 	UnlockPage(*ptr);
-	up (&inode->i_sem);
+	up (&info->sem);
 	return 0;
 failed:
-	up (&inode->i_sem);
+	up (&info->sem);
 	error = PTR_ERR(*ptr);
-	*ptr = NOPAGE_OOM;
-	if (error != -EFBIG)
-		*ptr = NOPAGE_SIGBUS;
-	return error;
-sigbus:
-	up (&inode->i_sem);
 	*ptr = NOPAGE_SIGBUS;
-	return -EFAULT;
+	if (error == -ENOMEM)
+		*ptr = NOPAGE_OOM;
+	return error;
 }
 
 struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int no_share)
@@ -446,7 +636,7 @@
 	unsigned int idx;
 	struct inode * inode = vma->vm_file->f_dentry->d_inode;
 
-	idx = (address - vma->vm_start) >> PAGE_SHIFT;
+	idx = (address - vma->vm_start) >> PAGE_CACHE_SHIFT;
 	idx += vma->vm_pgoff;
 
 	if (shmem_getpage(inode, idx, &page))
@@ -471,13 +661,13 @@
 void shmem_lock(struct file * file, int lock)
 {
 	struct inode * inode = file->f_dentry->d_inode;
-	struct shmem_inode_info * info = &inode->u.shmem_i;
+	struct shmem_inode_info * info = SHMEM_I(inode);
 	struct page * page;
 	unsigned long idx, size;
 
-	if (info->locked == lock)
-		return;
-	down(&inode->i_sem);
+	down(&info->sem);
+	if (info->locked == lock) 
+		goto out;
 	info->locked = lock;
 	size = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	for (idx = 0; idx < size; idx++) {
@@ -491,7 +681,8 @@
 		}
 		UnlockPage(page);
 	}
-	up(&inode->i_sem);
+out:
+	up(&info->sem);
 }
 
 static int shmem_mmap(struct file * file, struct vm_area_struct * vma)
@@ -510,14 +701,16 @@
 struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
 {
 	struct inode * inode;
+	struct shmem_inode_info *info;
+	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 
-	spin_lock (&sb->u.shmem_sb.stat_lock);
-	if (!sb->u.shmem_sb.free_inodes) {
-		spin_unlock (&sb->u.shmem_sb.stat_lock);
+	spin_lock (&sbinfo->stat_lock);
+	if (!sbinfo->free_inodes) {
+		spin_unlock (&sbinfo->stat_lock);
 		return NULL;
 	}
-	sb->u.shmem_sb.free_inodes--;
-	spin_unlock (&sb->u.shmem_sb.stat_lock);
+	sbinfo->free_inodes--;
+	spin_unlock (&sbinfo->stat_lock);
 
 	inode = new_inode(sb);
 	if (inode) {
@@ -529,7 +722,10 @@
 		inode->i_rdev = NODEV;
 		inode->i_mapping->a_ops = &shmem_aops;
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-		spin_lock_init (&inode->u.shmem_i.lock);
+		info = SHMEM_I(inode);
+		info->inode = inode;
+		spin_lock_init (&info->lock);
+		sema_init (&info->sem, 1);
 		switch (mode & S_IFMT) {
 		default:
 			init_special_inode(inode, mode, dev);
@@ -537,6 +733,9 @@
 		case S_IFREG:
 			inode->i_op = &shmem_inode_operations;
 			inode->i_fop = &shmem_file_operations;
+			spin_lock (&shmem_ilock);
+			list_add (&SHMEM_I(inode)->list, &shmem_inodes);
+			spin_unlock (&shmem_ilock);
 			break;
 		case S_IFDIR:
 			inode->i_nlink++;
@@ -544,12 +743,8 @@
 			inode->i_fop = &shmem_dir_operations;
 			break;
 		case S_IFLNK:
-			inode->i_op = &shmem_symlink_inode_operations;
 			break;
 		}
-		spin_lock (&shmem_ilock);
-		list_add (&inode->u.shmem_i.list, &shmem_inodes);
-		spin_unlock (&shmem_ilock);
 	}
 	return inode;
 }
@@ -579,10 +774,15 @@
 }
 
 #ifdef CONFIG_TMPFS
+
+static struct inode_operations shmem_symlink_inode_operations;
+static struct inode_operations shmem_symlink_inline_operations;
+
 static ssize_t
 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
 	struct inode	*inode = file->f_dentry->d_inode; 
+	struct shmem_inode_info *info;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	loff_t		pos;
 	struct page	*page;
@@ -658,7 +858,11 @@
 			__get_user(dummy, buf+bytes-1);
 		}
 
-		page = shmem_getpage_locked(inode, index);
+		info = SHMEM_I(inode);
+		down (&info->sem);
+		page = shmem_getpage_locked(info, inode, index);
+		up (&info->sem);
+
 		status = PTR_ERR(page);
 		if (IS_ERR(page))
 			break;
@@ -669,7 +873,6 @@
 		}
 
 		kaddr = kmap(page);
-// can this do a truncated write? cr
 		status = copy_from_user(kaddr+offset, buf, bytes);
 		kunmap(page);
 		if (status)
@@ -684,9 +887,6 @@
 			buf += bytes;
 			if (pos > inode->i_size) 
 				inode->i_size = pos;
-			if (inode->u.shmem_i.max_index <= index)
-				inode->u.shmem_i.max_index = index+1;
-
 		}
 unlock:
 		/* Mark it unlocked again and drop the page.. */
@@ -792,14 +992,16 @@
 
 static int shmem_statfs(struct super_block *sb, struct statfs *buf)
 {
+	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
+
 	buf->f_type = TMPFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
-	spin_lock (&sb->u.shmem_sb.stat_lock);
-	buf->f_blocks = sb->u.shmem_sb.max_blocks;
-	buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
-	buf->f_files = sb->u.shmem_sb.max_inodes;
-	buf->f_ffree = sb->u.shmem_sb.free_inodes;
-	spin_unlock (&sb->u.shmem_sb.stat_lock);
+	spin_lock (&sbinfo->stat_lock);
+	buf->f_blocks = sbinfo->max_blocks;
+	buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
+	buf->f_files = sbinfo->max_inodes;
+	buf->f_ffree = sbinfo->free_inodes;
+	spin_unlock (&sbinfo->stat_lock);
 	buf->f_namelen = 255;
 	return 0;
 }
@@ -945,33 +1147,54 @@
 	struct inode *inode;
 	struct page *page;
 	char *kaddr;
+	struct shmem_inode_info * info;
 
 	error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
 	if (error)
 		return error;
 
-	len = strlen(symname);
-	if (len > PAGE_SIZE)
+	len = strlen(symname) + 1;
+	if (len > PAGE_CACHE_SIZE)
 		return -ENAMETOOLONG;
 		
 	inode = dentry->d_inode;
-	down(&inode->i_sem);
-	page = shmem_getpage_locked(inode, 0);
-	if (IS_ERR(page))
-		goto fail;
-	kaddr = kmap(page);
-	memcpy(kaddr, symname, len);
-	kunmap(page);
+	info = SHMEM_I(inode);
 	inode->i_size = len;
-	SetPageDirty(page);
-	UnlockPage(page);
-	page_cache_release(page);
-	up(&inode->i_sem);
+	if (len <= sizeof(struct shmem_inode_info)) {
+		/* do it inline */
+		memcpy(info, symname, len);
+		inode->i_op = &shmem_symlink_inline_operations;
+	} else {
+		spin_lock (&shmem_ilock);
+		list_add (&info->list, &shmem_inodes);
+		spin_unlock (&shmem_ilock);
+		down(&info->sem);
+		page = shmem_getpage_locked(info, inode, 0);
+		if (IS_ERR(page)) {
+			up(&info->sem);
+			return PTR_ERR(page);
+		}
+		kaddr = kmap(page);
+		memcpy(kaddr, symname, len);
+		kunmap(page);
+		SetPageDirty(page);
+		UnlockPage(page);
+		page_cache_release(page);
+		up(&info->sem);
+		inode->i_op = &shmem_symlink_inode_operations;
+	}
 	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	return 0;
-fail:
-	up(&inode->i_sem);
-	return PTR_ERR(page);
+}
+
+static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen)
+{
+	return vfs_readlink(dentry,buffer,buflen, (const char *)SHMEM_I(dentry->d_inode));
+}
+
+static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd)
+{
+	return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));
 }
 
 static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen)
@@ -1001,6 +1224,17 @@
 	return res;
 }
 
+static struct inode_operations shmem_symlink_inline_operations = {
+	readlink:	shmem_readlink_inline,
+	follow_link:	shmem_follow_link_inline,
+};
+
+static struct inode_operations shmem_symlink_inode_operations = {
+	truncate:	shmem_truncate,
+	readlink:	shmem_readlink,
+	follow_link:	shmem_follow_link,
+};
+
 static int shmem_parse_options(char *options, int *mode, unsigned long * blocks, unsigned long *inodes)
 {
 	char *this_char, *value;
@@ -1046,13 +1280,13 @@
 
 static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
 {
-	struct shmem_sb_info *info = &sb->u.shmem_sb;
-	unsigned long max_blocks = info->max_blocks;
-	unsigned long max_inodes = info->max_inodes;
+	struct shmem_sb_info *sbinfo = &sb->u.shmem_sb;
+	unsigned long max_blocks = sbinfo->max_blocks;
+	unsigned long max_inodes = sbinfo->max_inodes;
 
 	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
 		return -EINVAL;
-	return shmem_set_size(info, max_blocks, max_inodes);
+	return shmem_set_size(sbinfo, max_blocks, max_inodes);
 }
 
 int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync)
@@ -1067,6 +1301,7 @@
 	struct dentry * root;
 	unsigned long blocks, inodes;
 	int mode   = S_IRWXUGO | S_ISVTX;
+	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
 	struct sysinfo si;
 
 	/*
@@ -1083,12 +1318,12 @@
 	}
 #endif
 
-	spin_lock_init (&sb->u.shmem_sb.stat_lock);
-	sb->u.shmem_sb.max_blocks = blocks;
-	sb->u.shmem_sb.free_blocks = blocks;
-	sb->u.shmem_sb.max_inodes = inodes;
-	sb->u.shmem_sb.free_inodes = inodes;
-	sb->s_maxbytes = (unsigned long long)SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;
+	spin_lock_init (&sbinfo->stat_lock);
+	sbinfo->max_blocks = blocks;
+	sbinfo->free_blocks = blocks;
+	sbinfo->max_inodes = inodes;
+	sbinfo->free_inodes = inodes;
+	sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = TMPFS_MAGIC;
@@ -1109,7 +1344,7 @@
 
 
 static struct address_space_operations shmem_aops = {
-	writepage: shmem_writepage
+	writepage:	shmem_writepage,
 };
 
 static struct file_operations shmem_file_operations = {
@@ -1125,14 +1360,6 @@
 	truncate:	shmem_truncate,
 };
 
-static struct inode_operations shmem_symlink_inode_operations = {
-	truncate:	shmem_truncate,
-#ifdef CONFIG_TMPFS
-	readlink:	shmem_readlink,
-	follow_link:	shmem_follow_link,
-#endif
-};
-
 static struct file_operations shmem_dir_operations = {
 	read:		generic_read_dir,
 	readdir:	dcache_readdir,
@@ -1202,7 +1429,7 @@
 	shm_mnt = res;
 
 	/* The internal instance should not do size checking */
-	if ((error = shmem_set_size(&res->mnt_sb->u.shmem_sb, ULONG_MAX, ULONG_MAX)))
+	if ((error = shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX)))
 		printk (KERN_ERR "could not set limits on internal tmpfs\n");
 
 	return 0;
@@ -1220,73 +1447,6 @@
 module_init(init_shmem_fs)
 module_exit(exit_shmem_fs)
 
-static int shmem_clear_swp (swp_entry_t entry, swp_entry_t *ptr, int size) {
-	swp_entry_t *test;
-
-	for (test = ptr; test < ptr + size; test++) {
-		if (test->val == entry.val) {
-			swap_free (entry);
-			*test = (swp_entry_t) {0};
-			return test - ptr;
-		}
-	}
-	return -1;
-}
-
-static int shmem_unuse_inode (struct inode *inode, swp_entry_t entry, struct page *page)
-{
-	swp_entry_t **base, **ptr;
-	unsigned long idx;
-	int offset;
-	struct shmem_inode_info *info = &inode->u.shmem_i;
-	
-	idx = 0;
-	spin_lock (&info->lock);
-	if ((offset = shmem_clear_swp (entry,info->i_direct, SHMEM_NR_DIRECT)) >= 0)
-		goto found;
-
-	idx = SHMEM_NR_DIRECT;
-	if (!(base = info->i_indirect))
-		goto out;
-
-	for (ptr = base; ptr < base + ENTRIES_PER_PAGE; ptr++) {
-		if (*ptr &&
-		    (offset = shmem_clear_swp (entry, *ptr, ENTRIES_PER_PAGE)) >= 0)
-			goto found;
-		idx += ENTRIES_PER_PAGE;
-	}
-out:
-	spin_unlock (&info->lock);
-	return 0;
-found:
-	add_to_page_cache(page, inode->i_mapping, offset + idx);
-	SetPageDirty(page);
-	SetPageUptodate(page);
-	UnlockPage(page);
-	info->swapped--;
-	spin_unlock(&info->lock);
-	return 1;
-}
-
-/*
- * unuse_shmem() search for an eventually swapped out shmem page.
- */
-void shmem_unuse(swp_entry_t entry, struct page *page)
-{
-	struct list_head *p;
-	struct inode * inode;
-
-	spin_lock (&shmem_ilock);
-	list_for_each(p, &shmem_inodes) {
-		inode = list_entry(p, struct inode, u.shmem_i.list);
-
-		if (shmem_unuse_inode(inode, entry, page))
-			break;
-	}
-	spin_unlock (&shmem_ilock);
-}
-
-
 /*
  * shmem_file_setup - get an unlinked file living in shmem fs
  *
@@ -1306,7 +1466,7 @@
 	if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT)
 		return ERR_PTR(-EINVAL);
 
-	if (!vm_enough_memory((size) >> PAGE_SHIFT))
+	if (!vm_enough_memory((size) >> PAGE_CACHE_SHIFT))
 		return ERR_PTR(-ENOMEM);
 
 	this.name = name;
diff -u --recursive --new-file v2.4.11/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.4.11/linux/net/ipv4/tcp.c	Tue Oct  9 17:06:53 2001
+++ linux/net/ipv4/tcp.c	Wed Oct 10 23:42:47 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.212 2001/09/21 21:27:34 davem Exp $
+ * Version:	$Id: tcp.c,v 1.213 2001/10/10 23:54:50 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -852,7 +852,7 @@
 
 		page = pages[poffset/PAGE_SIZE];
 		offset = poffset % PAGE_SIZE;
-		size = min(psize, PAGE_SIZE-offset);
+		size = min_t(size_t, psize, PAGE_SIZE-offset);
 
 		if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) {
 new_segment:
