## Automatically generated incremental diff
## From:   linux-2.5.3-pre3
## To:     linux-2.5.3-pre4
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.5.3-pre3/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.5.3-pre3/Documentation/Configure.help	Wed Jan 23 17:30:57 2002
+++ linux/Documentation/Configure.help	Wed Jan 23 17:31:03 2002
@@ -2433,6 +2433,14 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+AH/ESP match support
+CONFIG_IP_NF_MATCH_AH_ESP
+  These two match extensions (`ah' and `esp') allow you to match a
+  range of SPIs inside AH or ESP headers of IPSec packets.
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 TOS match support
 CONFIG_IP_NF_MATCH_TOS
   TOS matching allows you to match packets based on the Type Of
@@ -2600,6 +2608,19 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+ULOG target support
+CONFIG_IP_NF_TARGET_ULOG
+  This option adds a `ULOG' target, which allows you to create rules in
+  any iptables table. The packet is passed to a userspace logging
+  daemon using netlink multicast sockets; unlike the LOG target
+  which can only be viewed through syslog.
+
+  The apropriate userspace logging daemon (ulogd) may be obtained from
+  http://www.gnumonks.org/projects/ulogd
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
 LOG target support
 CONFIG_IP_NF_TARGET_LOG
   This option adds a `LOG' target, which allows you to create rules in
@@ -2656,6 +2677,23 @@
   If you want to compile it as a module, say M here and read
   <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+IPV6 queue handler (EXPERIMENTAL)
+CONFIG_IP6_NF_QUEUE
+
+  This option adds a queue handler to the kernel for IPv6
+  packets which lets us to receive the filtered packets
+  with QUEUE target using libiptc as we can do with
+  the IPv4 now.
+
+  (C) Fernando Anton 2001
+  IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+  Universidad Carlos III de Madrid
+  Universidad Politecnica de Alcala de Henares
+  email: fanton@it.uc3m.es
+
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. If unsure, say `N'.
+
 Owner match support
 CONFIG_IP6_NF_MATCH_OWNER
   Packet owner matching allows you to match locally-generated packets
@@ -4127,6 +4165,16 @@
 CONFIG_FB_L7200
   This driver supports the L7200 Color LCD.
   Say Y if you want graphics support.
+
+NeoMagic display support (EXPERIMENTAL)
+CONFIG_FB_NEOMAGIC
+  This driver supports notebooks with NeoMagic PCI chips.
+  Say Y if you have such a graphics card. 
+
+  The driver is also available as a module ( = code which can be
+  inserted and removed from the running kernel whenever you want). The
+  module will be called neofb.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
 
 PowerMac "control" frame buffer device support
 CONFIG_FB_CONTROL
diff -urN linux-2.5.3-pre3/Makefile linux/Makefile
--- linux-2.5.3-pre3/Makefile	Wed Jan 23 17:30:57 2002
+++ linux/Makefile	Wed Jan 23 17:31:03 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 3
-EXTRAVERSION =-pre3
+EXTRAVERSION =-pre4
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.3-pre3/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- linux-2.5.3-pre3/arch/alpha/kernel/time.c	Sat Nov 17 11:47:44 2001
+++ linux/arch/alpha/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -379,8 +379,6 @@
 	/* Startup the timer source. */
 	alpha_mv.init_rtc();
 
-	do_get_fast_time = do_gettimeofday;
-
 	/*
 	 * If we had wanted SRM console printk echoing early, undo it now.
 	 *
diff -urN linux-2.5.3-pre3/arch/alpha/vmlinux.lds.in linux/arch/alpha/vmlinux.lds.in
--- linux-2.5.3-pre3/arch/alpha/vmlinux.lds.in	Thu Nov 22 10:54:10 2001
+++ linux/arch/alpha/vmlinux.lds.in	Wed Jan 23 17:31:03 2002
@@ -41,7 +41,15 @@
 
   . = ALIGN(8);
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
 
   . = ALIGN(2*8192);	/* Align double page for init_task_union */
diff -urN linux-2.5.3-pre3/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- linux-2.5.3-pre3/arch/arm/kernel/ecard.c	Wed Jan 23 17:30:57 2002
+++ linux/arch/arm/kernel/ecard.c	Wed Jan 23 17:31:03 2002
@@ -1097,6 +1097,8 @@
 	ecard_proc_init();
 }
 
+subsys_initcall(ecard_init);
+
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
 EXPORT_SYMBOL(ecard_readchunk);
diff -urN linux-2.5.3-pre3/arch/arm/vmlinux-armo.lds.in linux/arch/arm/vmlinux-armo.lds.in
--- linux-2.5.3-pre3/arch/arm/vmlinux-armo.lds.in	Sat Jan  5 13:04:30 2002
+++ linux/arch/arm/vmlinux-armo.lds.in	Wed Jan 23 17:31:03 2002
@@ -27,7 +27,13 @@
 			*(.setup.init)
 		__setup_end = .;
 		__initcall_start = .;
-			*(.initcall.init)
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
 		__initcall_end = .;
 		. = ALIGN(32768);
 		__init_end = .;
diff -urN linux-2.5.3-pre3/arch/arm/vmlinux-armv.lds.in linux/arch/arm/vmlinux-armv.lds.in
--- linux-2.5.3-pre3/arch/arm/vmlinux-armv.lds.in	Sat Jan  5 13:04:30 2002
+++ linux/arch/arm/vmlinux-armv.lds.in	Wed Jan 23 17:31:03 2002
@@ -26,7 +26,13 @@
 			*(.setup.init)
 		__setup_end = .;
 		__initcall_start = .;
-			*(.initcall.init)
+			*(.initcall1.init)
+			*(.initcall2.init)
+			*(.initcall3.init)
+			*(.initcall4.init)
+			*(.initcall5.init)
+			*(.initcall6.init)
+			*(.initcall7.init)
 		__initcall_end = .;
 		. = ALIGN(4096);
 		__init_end = .;
diff -urN linux-2.5.3-pre3/arch/cris/cris.ld linux/arch/cris/cris.ld
--- linux-2.5.3-pre3/arch/cris/cris.ld	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/cris.ld	Wed Jan 23 17:31:03 2002
@@ -63,7 +63,13 @@
   	__setup_end = .;
   	.initcall.init : {
 		__initcall_start = .;
-		*(.initcall.init);
+		*(.initcall1.init);
+		*(.initcall2.init);
+		*(.initcall3.init);
+		*(.initcall4.init);
+		*(.initcall5.init);
+		*(.initcall6.init);
+		*(.initcall7.init);
 		__initcall_end = .;
 
 		/* We fill to the next page, so we can discard all init
diff -urN linux-2.5.3-pre3/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- linux-2.5.3-pre3/arch/i386/kernel/mca.c	Thu Aug 24 12:52:32 2000
+++ linux/arch/i386/kernel/mca.c	Wed Jan 23 17:31:03 2002
@@ -311,6 +311,8 @@
 #endif
 }
 
+subsys_initcall(mca_init);
+
 /*--------------------------------------------------------------------*/
 
 static void mca_handle_nmi_slot(int slot, int check_flag)
diff -urN linux-2.5.3-pre3/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- linux-2.5.3-pre3/arch/i386/kernel/time.c	Sun Nov 11 10:20:21 2001
+++ linux/arch/i386/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -681,7 +681,6 @@
 #ifndef do_gettimeoffset
 			do_gettimeoffset = do_fast_gettimeoffset;
 #endif
-			do_get_fast_time = do_gettimeofday;
 
 			/* report CPU clock rate in Hz.
 			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
diff -urN linux-2.5.3-pre3/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- linux-2.5.3-pre3/arch/i386/vmlinux.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/i386/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -48,7 +48,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- linux-2.5.3-pre3/arch/ia64/kernel/time.c	Fri Nov  9 14:26:17 2001
+++ linux/arch/ia64/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -145,9 +145,6 @@
 	tv->tv_usec = usec;
 }
 
-/* XXX there should be a cleaner way for declaring an alias... */
-asm (".global get_fast_time; get_fast_time = do_gettimeofday");
-
 static void
 timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
diff -urN linux-2.5.3-pre3/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S
--- linux-2.5.3-pre3/arch/ia64/vmlinux.lds.S	Tue Jul 31 10:30:09 2001
+++ linux/arch/ia64/vmlinux.lds.S	Wed Jan 23 17:31:03 2002
@@ -104,8 +104,16 @@
         { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : AT(ADDR(.initcall.init) - PAGE_OFFSET)
-        { *(.initcall.init) }
+  .initcall.init : AT(ADDR(.initcall1.init) - PAGE_OFFSET)
+	{
+		 *(.initcall1.init) 
+		 *(.initcall2.init) 
+		 *(.initcall3.init) 
+		 *(.initcall4.init) 
+		 *(.initcall5.init) 
+		 *(.initcall6.init) 
+		 *(.initcall7.init) 
+	}
   __initcall_end = .;
   . = ALIGN(PAGE_SIZE);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/m68k/vmlinux-sun3.lds linux/arch/m68k/vmlinux-sun3.lds
--- linux-2.5.3-pre3/arch/m68k/vmlinux-sun3.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/m68k/vmlinux-sun3.lds	Wed Jan 23 17:31:03 2002
@@ -43,7 +43,15 @@
 	.setup.init : { *(.setup.init) }
 	__setup_end = .;
 	__initcall_start = .;
-	.initcall.init : { *(.initcall.init) }
+	.initcall.init : {
+		*(.initcall1.init) 
+		*(.initcall2.init) 
+		*(.initcall3.init) 
+		*(.initcall4.init) 
+		*(.initcall5.init) 
+		*(.initcall6.init) 
+		*(.initcall7.init)
+	}
 	__initcall_end = .;
 	. = ALIGN(8192);
 	__init_end = .;
diff -urN linux-2.5.3-pre3/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- linux-2.5.3-pre3/arch/m68k/vmlinux.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/m68k/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -47,7 +47,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/mips/ld.script.in linux/arch/mips/ld.script.in
--- linux-2.5.3-pre3/arch/mips/ld.script.in	Mon Jul  2 13:56:40 2001
+++ linux/arch/mips/ld.script.in	Wed Jan 23 17:31:03 2002
@@ -44,7 +44,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/mips64/ld.script.elf32.S linux/arch/mips64/ld.script.elf32.S
--- linux-2.5.3-pre3/arch/mips64/ld.script.elf32.S	Mon Jul  2 14:40:58 2001
+++ linux/arch/mips64/ld.script.elf32.S	Wed Jan 23 17:31:03 2002
@@ -40,7 +40,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/mips64/ld.script.elf64 linux/arch/mips64/ld.script.elf64
--- linux-2.5.3-pre3/arch/mips64/ld.script.elf64	Mon Jul  2 14:40:58 2001
+++ linux/arch/mips64/ld.script.elf64	Wed Jan 23 17:31:03 2002
@@ -49,7 +49,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);	/* Align double page for init_task_union */
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/parisc/vmlinux.lds linux/arch/parisc/vmlinux.lds
--- linux-2.5.3-pre3/arch/parisc/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/parisc/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -51,7 +51,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) } 
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   __init_end = .;
 
diff -urN linux-2.5.3-pre3/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- linux-2.5.3-pre3/arch/ppc/kernel/setup.c	Wed Jan 23 17:30:57 2002
+++ linux/arch/ppc/kernel/setup.c	Wed Jan 23 17:31:03 2002
@@ -535,6 +535,8 @@
 	}
 }
 
+subsys_initcall(ppc_init);
+
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
diff -urN linux-2.5.3-pre3/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- linux-2.5.3-pre3/arch/ppc/kernel/time.c	Mon Oct  8 11:43:01 2001
+++ linux/arch/ppc/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -352,8 +352,6 @@
         	tz.tz_dsttime = 0;
         	do_sys_settimeofday(NULL, &tz);
         }
-
-       do_get_fast_time = do_gettimeofday;
 }
 
 #define TICK_SIZE tick
diff -urN linux-2.5.3-pre3/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds
--- linux-2.5.3-pre3/arch/ppc/vmlinux.lds	Tue Aug 28 06:58:33 2001
+++ linux/arch/ppc/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -94,7 +94,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- linux-2.5.3-pre3/arch/s390/kernel/time.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -249,7 +249,4 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -urN linux-2.5.3-pre3/arch/s390/vmlinux-shared.lds linux/arch/s390/vmlinux-shared.lds
--- linux-2.5.3-pre3/arch/s390/vmlinux-shared.lds	Sun Aug 12 10:38:48 2001
+++ linux/arch/s390/vmlinux-shared.lds	Wed Jan 23 17:31:03 2002
@@ -55,7 +55,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/s390/vmlinux.lds linux/arch/s390/vmlinux.lds
--- linux-2.5.3-pre3/arch/s390/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/s390/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -53,7 +53,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
--- linux-2.5.3-pre3/arch/s390x/kernel/time.c	Thu Oct 11 09:04:57 2001
+++ linux/arch/s390x/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -255,7 +255,4 @@
         init_timer_cc -= 0x8126d60e46000000LL -
                          (0x3c26700LL*1000000*4096);
         tod_to_timeval(init_timer_cc, &xtime);
-
-	/* Set do_get_fast_time function pointer.  */
-	do_get_fast_time = do_gettimeofday;
 }
diff -urN linux-2.5.3-pre3/arch/s390x/vmlinux-shared.lds linux/arch/s390x/vmlinux-shared.lds
--- linux-2.5.3-pre3/arch/s390x/vmlinux-shared.lds	Sun Aug 12 10:38:48 2001
+++ linux/arch/s390x/vmlinux-shared.lds	Wed Jan 23 17:31:03 2002
@@ -55,7 +55,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/s390x/vmlinux.lds linux/arch/s390x/vmlinux.lds
--- linux-2.5.3-pre3/arch/s390x/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/s390x/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -53,7 +53,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S
--- linux-2.5.3-pre3/arch/sh/vmlinux.lds.S	Sat Sep  8 12:29:09 2001
+++ linux/arch/sh/vmlinux.lds.S	Wed Jan 23 17:31:03 2002
@@ -63,7 +63,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   __machvec_start = .;
   .machvec.init : { *(.machvec.init) }
diff -urN linux-2.5.3-pre3/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c
--- linux-2.5.3-pre3/arch/sparc/kernel/pcic.c	Sun Feb 18 19:49:44 2001
+++ linux/arch/sparc/kernel/pcic.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: pcic.c,v 1.22 2001/02/13 01:16:43 davem Exp $
+/* $Id: pcic.c,v 1.23 2002/01/23 14:33:55 davem Exp $
  * pcic.c: Sparc/PCI controller support
  *
  * Copyright (C) 1998 V. Roganov and G. Raiko
@@ -759,7 +759,6 @@
 	unsigned long v;
 	int timer_irq, irq;
 
-	do_get_fast_time = pci_do_gettimeofday;
 	/* A hack until do_gettimeofday prototype is moved to arch specific headers
 	   and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
 	((unsigned int *)do_gettimeofday)[0] = 
diff -urN linux-2.5.3-pre3/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- linux-2.5.3-pre3/arch/sparc/kernel/process.c	Wed Jan 23 17:30:57 2002
+++ linux/arch/sparc/kernel/process.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.160 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.161 2002/01/23 11:27:32 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.5.3-pre3/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- linux-2.5.3-pre3/arch/sparc/kernel/time.c	Tue Oct 30 15:08:11 2001
+++ linux/arch/sparc/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.59 2001/10/30 04:54:21 davem Exp $
+/* $Id: time.c,v 1.60 2002/01/23 14:33:55 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -371,7 +371,6 @@
 	struct intersil *iregs;
 #endif
 
-	do_get_fast_time = do_gettimeofday;
 	BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
 	btfixup();
 
diff -urN linux-2.5.3-pre3/arch/sparc/vmlinux.lds linux/arch/sparc/vmlinux.lds
--- linux-2.5.3-pre3/arch/sparc/vmlinux.lds	Mon Jul  2 14:40:58 2001
+++ linux/arch/sparc/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -45,7 +45,15 @@
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -urN linux-2.5.3-pre3/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.5.3-pre3/arch/sparc64/defconfig	Wed Jan 23 17:30:57 2002
+++ linux/arch/sparc64/defconfig	Wed Jan 23 17:31:03 2002
@@ -253,6 +253,7 @@
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
 # CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
 # CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
 # CONFIG_BLK_DEV_IDEDISK_IBM is not set
@@ -267,6 +268,7 @@
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
 
 #
 # IDE chipset support/bugfixes
@@ -278,12 +280,15 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
+CONFIG_IDEDMA_ONLYDISK=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_IDEDMA_TIMEOUT is not set
 # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
@@ -298,6 +303,7 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC_ADMA is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
 # CONFIG_PDC202XX_FORCE is not set
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/pci_psycho.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/pci_psycho.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.31 2002/01/05 07:33:16 davem Exp $
+/* $Id: pci_psycho.c,v 1.32 2002/01/23 11:27:32 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -345,7 +345,7 @@
 /*0x2f*/15,		/* Correctable ECC		*/
 /*0x30*/15,		/* PCI Bus A Error		*/
 /*0x31*/15,		/* PCI Bus B Error		*/
-/*0x32*/1,		/* Power Management		*/
+/*0x32*/15,		/* Power Management		*/
 };
 
 static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -354,7 +354,7 @@
 
 	ret = psycho_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -377,7 +377,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -410,6 +410,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = psycho_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + imap_off;
 	imap += 4;
 
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/pci_sabre.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/pci_sabre.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.41 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_sabre.c,v 1.42 2002/01/23 11:27:32 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -582,7 +582,7 @@
 /*0x2f*/15,		/* Correctable ECC		*/
 /*0x30*/15,		/* PCI Bus A Error		*/
 /*0x31*/15,		/* PCI Bus B Error		*/
-/*0x32*/1,		/* Power Management		*/
+/*0x32*/15,		/* Power Management		*/
 };
 
 static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
@@ -596,7 +596,7 @@
 
 	ret = sabre_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -619,7 +619,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -651,6 +651,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = sabre_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + imap_off;
 	imap += 4;
 
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/pci_schizo.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/pci_schizo.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.23 2001/11/14 13:17:56 davem Exp $
+/* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -344,7 +344,7 @@
 
 	ret = schizo_pil_table[ino];
 	if (ret == 0 && pdev == NULL) {
-		ret = 1;
+		ret = 2;
 	} else if (ret == 0) {
 		switch ((pdev->class >> 16) & 0xff) {
 		case PCI_BASE_CLASS_STORAGE:
@@ -367,7 +367,7 @@
 			break;
 
 		default:
-			ret = 1;
+			ret = 2;
 			break;
 		};
 	}
@@ -395,6 +395,10 @@
 
 	/* Now build the IRQ bucket. */
 	pil = schizo_ino_to_pil(pdev, ino);
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = p->controller_regs + pbm_off + imap_off;
 	imap += 4;
 
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/process.c	Wed Jan 23 17:31:00 2002
+++ linux/arch/sparc64/kernel/process.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.128 2002/01/11 08:45:38 davem Exp $
+/*  $Id: process.c,v 1.129 2002/01/23 11:27:32 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/sbus.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/sbus.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.18 2001/12/17 07:05:09 davem Exp $
+/* $Id: sbus.c,v 1.19 2002/01/23 11:27:32 davem Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -628,10 +628,10 @@
 
 /* SBUS SYSIO INO number to Sparc PIL level. */
 static unsigned char sysio_ino_to_pil[] = {
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 0 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 1 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 2 */
-	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 3 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 0 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 1 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 2 */
+	0, 2, 2, 7, 5, 7, 8, 9,		/* SBUS slot 3 */
 	3, /* Onboard SCSI */
 	5, /* Onboard Ethernet */
 /*XXX*/	8, /* Onboard BPP */
@@ -754,6 +754,10 @@
 		printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino);
 		panic("Bad SYSIO IRQ translations...");
 	}
+
+	if (PIL_RESERVED(pil))
+		BUG();
+
 	imap = sysio_irq_offsets[ino];
 	if (imap == ((unsigned long)-1)) {
 		prom_printf("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/smp.c	Wed Jan 23 17:31:00 2002
+++ linux/arch/sparc64/kernel/smp.c	Wed Jan 23 17:31:03 2002
@@ -218,10 +218,12 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
+	init_idle();
+
 	while (!smp_threads_ready)
 		membar("#LoadLoad");
 
-	init_idle();
+	idle_startup_done();
 }
 
 void cpu_panic(void)
@@ -873,6 +875,48 @@
 	local_flush_and_out:
 		__flush_tlb_page(ctx, page, SECONDARY_CONTEXT);
 	}
+}
+
+/* Process migration IPIs. */
+
+extern unsigned long xcall_migrate_task;
+
+static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
+static task_t *new_task;
+
+void smp_migrate_task(int cpu, task_t *p)
+{
+	unsigned long mask = 1UL << cpu;
+
+	if (cpu == smp_processor_id())
+		return;
+
+	if (smp_processors_ready && (cpu_present_map & mask) != 0) {
+		u64 data0 = (((u64)&xcall_migrate_task) & 0xffffffff);
+
+		spin_lock(&migration_lock);
+		new_task = p;
+
+		if (tlb_type == spitfire)
+			spitfire_xcall_deliver(data0, 0, 0, mask);
+		else
+			cheetah_xcall_deliver(data0, 0, 0, mask);
+	}
+}
+
+/* Called at PIL level 1. */
+asmlinkage void smp_task_migration_interrupt(int irq, struct pt_regs *regs)
+{
+	task_t *p;
+
+	if (irq != PIL_MIGRATE)
+		BUG();
+
+	clear_softint(1 << irq);
+
+	p = new_task;
+	spin_unlock(&migration_lock);
+	sched_task_migrated(p);
 }
 
 /* CPU capture. */
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- linux-2.5.3-pre3/arch/sparc64/kernel/time.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/time.c	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.41 2001/11/20 18:24:55 kanoj Exp $
+/* $Id: time.c,v 1.42 2002/01/23 14:33:55 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -329,8 +329,6 @@
 	unsigned long dregs = 0UL;
 #endif
 	u8 tmp;
-
-	do_get_fast_time = do_gettimeofday;
 
 	if (!mregs && !dregs) {
 		prom_printf("Something wrong, clock regs not mapped yet.\n");
diff -urN linux-2.5.3-pre3/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- linux-2.5.3-pre3/arch/sparc64/kernel/ttable.S	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/ttable.S	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.36 2001/11/28 23:32:16 davem Exp $
+/* $Id: ttable.S,v 1.37 2002/01/23 11:27:32 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah extensions.
  *
  * Copyright (C) 1996, 2001 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,12 @@
 tl0_privact:	TRAP_NOSAVE(__do_privact)
 tl0_resv038:	BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
 tl0_resv03e:	BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
-tl0_irq1:	TRAP_IRQ(handler_irq, 1)  TRAP_IRQ(handler_irq, 2)
+#ifdef CONFIG_SMP
+tl0_irq1:	TRAP_IRQ(smp_task_migration_interrupt, 1)
+#else
+tl0_irq1:	BTRAP(0x41)
+#endif
+tl0_irq2:	TRAP_IRQ(handler_irq, 2)
 tl0_irq3:	TRAP_IRQ(handler_irq, 3)  TRAP_IRQ(handler_irq, 4)
 tl0_irq5:	TRAP_IRQ(handler_irq, 5)  TRAP_IRQ(handler_irq, 6)
 tl0_irq7:	TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
diff -urN linux-2.5.3-pre3/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- linux-2.5.3-pre3/arch/sparc64/mm/ultra.S	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/mm/ultra.S	Wed Jan 23 17:31:03 2002
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.70 2001/11/29 16:42:10 kanoj Exp $
+/* $Id: ultra.S,v 1.71 2002/01/23 11:27:36 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/spitfire.h>
 #include <asm/mmu_context.h>
+#include <asm/pil.h>
 
 	/* Basically, all this madness has to do with the
 	 * fact that Cheetah does not support IMMU flushes
@@ -690,5 +691,12 @@
 	 nop
 	b,pt		%xcc, rtrap
 	 clr		%l6
+
+	.globl		xcall_migrate_task
+xcall_migrate_task:
+	mov		1, %g2
+	sllx		%g2, (PIL_MIGRATE), %g2
+	wr		%g2, 0x0, %set_softint
+	retry
 
 #endif /* CONFIG_SMP */
diff -urN linux-2.5.3-pre3/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- linux-2.5.3-pre3/arch/sparc64/vmlinux.lds	Fri Sep  7 11:01:20 2001
+++ linux/arch/sparc64/vmlinux.lds	Wed Jan 23 17:31:03 2002
@@ -46,7 +46,15 @@
   .setup_init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(8192);
   __init_end = .;
diff -urN linux-2.5.3-pre3/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c
--- linux-2.5.3-pre3/drivers/char/joystick/iforce.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/char/joystick/iforce.c	Wed Jan 23 17:31:04 2002
@@ -133,7 +133,7 @@
 #endif
 #ifdef IFORCE_USB
 	struct usb_device *usbdev;	/* USB transfer */
-	struct urb irq, out, ctrl;
+	struct urb *irq, *out, *ctrl;
 	struct usb_ctrlrequest dr;
 #endif
 					/* Force Feedback */
@@ -196,28 +196,28 @@
 			DECLARE_WAITQUEUE(wait, current);
 			int timeout = HZ; /* 1 second */
 
-			memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));
-			((char*)iforce->out.transfer_buffer)[0] = HI(cmd);
-			iforce->out.transfer_buffer_length = LO(cmd) + 2;
-			iforce->out.dev = iforce->usbdev;
+			memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+			((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+			iforce->out->transfer_buffer_length = LO(cmd) + 2;
+			iforce->out->dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&iforce->wait, &wait);
 
-			if (usb_submit_urb(&iforce->out)) {
+			if (usb_submit_urb(iforce->out)) {
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&iforce->wait, &wait);
 				return;
 			}
 
-			while (timeout && iforce->out.status == -EINPROGRESS)
+			while (timeout && iforce->out->status == -EINPROGRESS)
 				timeout = schedule_timeout(timeout);
 
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&iforce->wait, &wait);
 
 			if (!timeout)
-				usb_unlink_urb(&iforce->out);
+				usb_unlink_urb(iforce->out);
 
 			return;
 		}
@@ -284,25 +284,25 @@
 		case IFORCE_USB:
 
 			iforce->dr.bRequest = packet[0];
-			iforce->ctrl.dev = iforce->usbdev;
+			iforce->ctrl->dev = iforce->usbdev;
 
 			set_current_state(TASK_INTERRUPTIBLE);
 			add_wait_queue(&iforce->wait, &wait);
 
-			if (usb_submit_urb(&iforce->ctrl)) {
+			if (usb_submit_urb(iforce->ctrl)) {
 				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&iforce->wait, &wait);
 				return -1;
 			}
 
-			while (timeout && iforce->ctrl.status == -EINPROGRESS)
+			while (timeout && iforce->ctrl->status == -EINPROGRESS)
 				timeout = schedule_timeout(timeout);
 
 			set_current_state(TASK_RUNNING);
 			remove_wait_queue(&iforce->wait, &wait);
 
 			if (!timeout) {
-				usb_unlink_urb(&iforce->ctrl);
+				usb_unlink_urb(iforce->ctrl);
 				return -1;
 			}
 
@@ -344,8 +344,8 @@
 		case IFORCE_USB:
 			if (iforce->open++)
 				break;
-			iforce->irq.dev = iforce->usbdev;
-			if (usb_submit_urb(&iforce->irq))
+			iforce->irq->dev = iforce->usbdev;
+			if (usb_submit_urb(iforce->irq))
 					return -EIO;
 			break;
 #endif
@@ -361,7 +361,7 @@
 #ifdef IFORCE_USB
 		case IFORCE_USB:
 			if (!--iforce->open)
-				usb_unlink_urb(&iforce->irq);
+				usb_unlink_urb(iforce->irq);
 			break;
 #endif
 	}
@@ -1024,6 +1024,25 @@
 	if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
 	memset(iforce, 0, sizeof(struct iforce));
 
+	iforce->irq = usb_alloc_urb(0);
+	if (!iforce->irq) {
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->out = usb_alloc_urb(0);
+	if (!iforce->out) {
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+	iforce->ctrl = usb_alloc_urb(0);
+	if (!iforce->ctrl) {
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
+		kfree(iforce);
+		return NULL;
+	}
+
 	iforce->bus = IFORCE_USB;
 	iforce->usbdev = dev;
 
@@ -1031,16 +1050,19 @@
 	iforce->dr.wIndex = 0;
 	iforce->dr.wLength = 16;
 
-	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+	FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
 			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
 
-	FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+	FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
 			iforce + 1, 32, iforce_usb_out, iforce);
 
-	FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+	FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
 			(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
 
 	if (iforce_init_device(iforce)) {
+		usb_free_urb(iforce->ctrl);
+		usb_free_urb(iforce->out);
+		usb_free_urb(iforce->irq);
 		kfree(iforce);
 		return NULL;
 	}
@@ -1055,8 +1077,11 @@
 static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct iforce *iforce = ptr;
-	usb_unlink_urb(&iforce->irq);
+	usb_unlink_urb(iforce->irq);
 	input_unregister_device(&iforce->dev);
+	usb_free_urb(iforce->ctrl);
+	usb_free_urb(iforce->out);
+	usb_free_urb(iforce->irq);
 	kfree(iforce);
 }
 
diff -urN linux-2.5.3-pre3/drivers/dio/dio.c linux/drivers/dio/dio.c
--- linux-2.5.3-pre3/drivers/dio/dio.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/dio/dio.c	Wed Jan 23 17:31:04 2002
@@ -208,6 +208,8 @@
         }
 }
 
+subsys_initcall(dio_init);
+
 /* Bear in mind that this is called in the very early stages of initialisation
  * in order to get the virtual address of the serial port for the console...
  */
diff -urN linux-2.5.3-pre3/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.5.3-pre3/drivers/ieee1394/video1394.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/ieee1394/video1394.c	Wed Jan 23 17:31:04 2002
@@ -639,7 +639,7 @@
 		if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) {
 			reset_ir_status(d, i);
 			d->buffer_status[i] = VIDEO1394_BUFFER_READY;
-			get_fast_time(&d->buffer_time[i]);
+			do_gettimeofday(&d->buffer_time[i]);
 		}
 	}
 	spin_unlock(&d->lock);
diff -urN linux-2.5.3-pre3/drivers/input/evdev.c linux/drivers/input/evdev.c
--- linux-2.5.3-pre3/drivers/input/evdev.c	Thu Jan  3 12:20:10 2002
+++ linux/drivers/input/evdev.c	Wed Jan 23 17:31:04 2002
@@ -67,7 +67,7 @@
 
 	while (list) {
 
-		get_fast_time(&list->buffer[list->head].time);
+		do_gettimeofday(&list->buffer[list->head].time);
 		list->buffer[list->head].type = type;
 		list->buffer[list->head].code = code;
 		list->buffer[list->head].value = value;
diff -urN linux-2.5.3-pre3/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- linux-2.5.3-pre3/drivers/media/video/zr36067.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/media/video/zr36067.c	Wed Jan 23 17:31:04 2002
@@ -2608,7 +2608,7 @@
 		}
 		frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
 		gbuf = &zr->jpg_gbuf[frame];
-		get_fast_time(&gbuf->bs.timestamp);
+		do_gettimeofday(&gbuf->bs.timestamp);
 
 		if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
 			gbuf->bs.length = (stat_com & 0x7fffff) >> 1;
diff -urN linux-2.5.3-pre3/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- linux-2.5.3-pre3/drivers/net/irda/ali-ircc.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/net/irda/ali-ircc.c	Wed Jan 23 17:31:04 2002
@@ -1496,7 +1496,7 @@
 		if (mtt) 
 		{
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			/* self->stamp is set from ali_ircc_dma_receive_complete() */
@@ -1913,7 +1913,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
diff -urN linux-2.5.3-pre3/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux-2.5.3-pre3/drivers/net/irda/irda-usb.c	Tue Jan  1 13:52:10 2002
+++ linux/drivers/net/irda/irda-usb.c	Wed Jan 23 17:31:04 2002
@@ -427,7 +427,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			int diff;
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 #ifdef IU_USB_MIN_RTT
 			/* Factor in USB delays -> Get rid of udelay() that
@@ -798,7 +798,7 @@
 	 * reduce the min turn time a bit since we will know
 	 * how much time we have used for protocol processing
 	 */
-        get_fast_time(&self->stamp);
+        do_gettimeofday(&self->stamp);
 
 	/* Fix skb, and remove USB-IrDA header */
 	skb_put(skb, urb->actual_length);
diff -urN linux-2.5.3-pre3/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.5.3-pre3/drivers/net/irda/nsc-ircc.c	Wed Jan  9 14:56:33 2002
+++ linux/drivers/net/irda/nsc-ircc.c	Wed Jan 23 17:31:04 2002
@@ -1163,7 +1163,7 @@
 		mtt = irda_get_mtt(skb);
 		if (mtt) {
 			/* Check how much time we have used already */
-			get_fast_time(&self->now);
+			do_gettimeofday(&self->now);
 			diff = self->now.tv_usec - self->stamp.tv_usec;
 			if (diff < 0) 
 				diff += 1000000;
@@ -1535,7 +1535,7 @@
 			 * reduce the min turn time a bit since we will know
 			 * how much time we have used for protocol processing
 			 */
-			get_fast_time(&self->stamp);
+			do_gettimeofday(&self->stamp);
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
diff -urN linux-2.5.3-pre3/drivers/net/sungem.c linux/drivers/net/sungem.c
--- linux-2.5.3-pre3/drivers/net/sungem.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/net/sungem.c	Wed Jan 23 17:31:04 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.48 2002/01/15 06:26:37 davem Exp $
+/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -10,6 +10,10 @@
  *  - Get rid of all those nasty mdelay's and replace them
  * with schedule_timeout.
  *  - Implement WOL
+ *  - Currently, forced Gb mode is only supported on bcm54xx
+ *    PHY for which I use the SPD2 bit of the control register.
+ *    On m1011 PHY, I can't force as I don't have the specs, but
+ *    I can at least detect gigabit with autoneg.
  */
 
 #include <linux/module.h>
@@ -86,7 +90,7 @@
 	BMCR_ANENABLE,			/* 0 : autoneg */
 	0,				/* 1 : 10bt half duplex */
 	BMCR_SPEED100,			/* 2 : 100bt half duplex */
-	BMCR_SPD2, /* verify this */	/* 3 : 1000bt half duplex */
+	BMCR_SPD2, /* bcm54xx only */   /* 3 : 1000bt half duplex */
 	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */
 	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */
 	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */
@@ -1004,6 +1008,14 @@
 			*fd = 1;
 		if (val & (LPA_100FULL | LPA_100HALF))
 			*spd = 100;
+
+		if (gp->phy_mod == phymod_m1011) {
+			val = phy_read(gp, 0x0a);
+			if (val & 0xc00)
+				*spd = 1000;
+			if (val & 0x800)
+				*fd = 1;
+		}
 	}
 }
 
@@ -1579,6 +1591,11 @@
 			gem_init_bcm5411_phy(gp);
 			gp->gigabit_capable = 1;
 			break;
+		case 0x1410c60:
+			printk("M1011 (Marvel ?)\n");
+			gp->phy_mod = phymod_m1011;
+			gp->gigabit_capable = 1;
+			break;
 
 		case 0x18074c0:
 			printk("Lucent\n");
@@ -1591,7 +1608,7 @@
 			break;
 
 		default:
-			printk("Unknown\n");
+			printk("Unknown (Using generic mode)\n");
 			gp->phy_mod = phymod_generic;
 			break;
 		};
@@ -1662,6 +1679,12 @@
 		writel(val, gp->regs + PCS_SCTRL);
 		gp->gigabit_capable = 1;
 	}
+
+	/* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
+	if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
+	    gp->phy_mod != phymod_bcm5411)
+	    	gp->link_cntl &= ~BMCR_SPD2;
+	    
 }
 
 static void gem_init_dma(struct gem *gp)
@@ -1851,9 +1874,8 @@
 	u32 mif_cfg;
 
 	/* On Apple's sungem, we can't rely on registers as the chip
-	 * was been powered down by the firmware. We do the PHY lookup
-	 * when the interface is opened and we configure the driver
-	 * with known values.
+	 * was been powered down by the firmware. The PHY is looked
+	 * up later on.
 	 */
 	if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
 		gp->phy_type = phy_mii_mdio0;
@@ -1978,7 +2000,8 @@
 
 	pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
 
-	udelay(100);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout((21 * HZ) / 1000);
 
 	pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
 	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
@@ -2048,7 +2071,8 @@
 				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
 #endif				
 			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-		}
+		} else if (gp->phy_mod == phymod_m1011)
+			phy_write(gp, MII_BMCR, BMCR_PDOWN);
 
 		/* According to Apple, we must set the MDIO pins to this begnign
 		 * state or we may 1) eat more current, 2) damage some PHYs
diff -urN linux-2.5.3-pre3/drivers/net/sungem.h linux/drivers/net/sungem.h
--- linux-2.5.3-pre3/drivers/net/sungem.h	Wed Jan 23 17:31:01 2002
+++ linux/drivers/net/sungem.h	Wed Jan 23 17:31:04 2002
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.11 2002/01/12 07:19:55 davem Exp $
+/* $Id: sungem.h,v 1.12 2002/01/23 15:40:45 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -941,6 +941,7 @@
 	phymod_bcm5400,
 	phymod_bcm5401,
 	phymod_bcm5411,
+	phymod_m1011,
 };
 
 enum link_state {
diff -urN linux-2.5.3-pre3/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- linux-2.5.3-pre3/drivers/nubus/nubus.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/nubus/nubus.c	Wed Jan 23 17:31:04 2002
@@ -1039,3 +1039,5 @@
 	nubus_proc_init();
 #endif
 }
+
+subsys_initcall(nubus_init);
diff -urN linux-2.5.3-pre3/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux-2.5.3-pre3/drivers/pci/pci.c	Tue Nov 20 21:53:29 2001
+++ linux/drivers/pci/pci.c	Wed Jan 23 17:31:04 2002
@@ -1064,6 +1064,7 @@
 		memset(b, 0, sizeof(*b));
 		INIT_LIST_HEAD(&b->children);
 		INIT_LIST_HEAD(&b->devices);
+		iobus_init(&b->iobus);
 	}
 	return b;
 }
@@ -1085,6 +1086,13 @@
 	child->ops = parent->ops;
 	child->sysdata = parent->sysdata;
 
+	/* init generic fields */
+	child->iobus.self = &dev->dev;
+	child->iobus.parent = &parent->iobus;
+	dev->dev.subordinate = &child->iobus;
+
+	strcpy(child->iobus.name,dev->dev.name);
+
 	/*
 	 * Set up the primary, secondary and subordinate
 	 * bus numbers.
@@ -1180,6 +1188,7 @@
 		pci_write_config_word(dev, PCI_COMMAND, cr);
 	}
 	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+
 	return max;
 }
 
@@ -1288,13 +1297,22 @@
 	dev->vendor = l & 0xffff;
 	dev->device = (l >> 16) & 0xffff;
 
+	/* make sure generic fields are setup properly */
+	device_init_dev(&dev->dev);
+
 	/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
 	   set this higher, assuming the system even supports it.  */
 	dev->dma_mask = 0xffffffff;
 	if (pci_setup_device(dev) < 0) {
 		kfree(dev);
-		dev = NULL;
+		return NULL;
 	}
+
+	/* now put in global tree */
+	strcpy(dev->dev.name,dev->name);
+	strcpy(dev->dev.bus_id,dev->slot_name);
+
+	device_register(&dev->dev);
 	return dev;
 }
 
@@ -1345,10 +1363,17 @@
 	DBG("Scanning bus %02x\n", bus->number);
 	max = bus->secondary;
 
+	/* we should know for sure what the bus number is, so set the bus ID
+	 * for the bus and make sure it's registered in the device tree */
+	sprintf(bus->iobus.bus_id,"pci%d",bus->number);
+	iobus_register(&bus->iobus);
+
 	/* Create a device template */
 	memset(&dev0, 0, sizeof(dev0));
+	device_init_dev(&dev0.dev);
 	dev0.bus = bus;
 	dev0.sysdata = bus->sysdata;
+	dev0.dev.parent = &bus->iobus;
 
 	/* Go find them, Rover! */
 	for (devfn = 0; devfn < 0x100; devfn += 8) {
@@ -1403,8 +1428,14 @@
 	}
 
 	b = pci_alloc_bus();
+	if (!b)
+		return NULL;
 	list_add_tail(&b->node, &pci_root_buses);
 
+	sprintf(b->iobus.bus_id,"pci%d",bus);
+	strcpy(b->iobus.name,"Host/PCI Bridge");
+	iobus_register(&b->iobus);
+
 	b->number = b->secondary = bus;
 	b->resource[0] = &ioport_resource;
 	b->resource[1] = &iomem_resource;
@@ -1929,7 +1960,7 @@
 }
 
 
-void __devinit  pci_init(void)
+static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
 
@@ -1942,6 +1973,7 @@
 #ifdef CONFIG_PM
 	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
 #endif
+	return 0;
 }
 
 static int __devinit  pci_setup(char *str)
@@ -1958,6 +1990,8 @@
 	}
 	return 1;
 }
+
+subsys_initcall(pci_init);
 
 __setup("pci=", pci_setup);
 
diff -urN linux-2.5.3-pre3/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-2.5.3-pre3/drivers/pcmcia/ds.c	Tue Jan  1 11:51:31 2002
+++ linux/drivers/pcmcia/ds.c	Wed Jan 23 17:31:04 2002
@@ -966,12 +966,9 @@
     return 0;
 }
 
-#ifdef MODULE
+late_initcall(init_pcmcia_ds);
 
-int __init init_module(void)
-{
-    return init_pcmcia_ds();
-}
+#ifdef MODULE
 
 void __exit cleanup_module(void)
 {
diff -urN linux-2.5.3-pre3/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- linux-2.5.3-pre3/drivers/pnp/isapnp.c	Mon Nov 12 10:02:54 2001
+++ linux/drivers/pnp/isapnp.c	Wed Jan 23 17:31:04 2002
@@ -2356,12 +2356,9 @@
 	return 0;
 }
 
-#ifdef MODULE
+subsys_initcall(isapnp_init);
 
-int init_module(void)
-{
-	return isapnp_init();
-}
+#ifdef MODULE
 
 void cleanup_module(void)
 {
diff -urN linux-2.5.3-pre3/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- linux-2.5.3-pre3/drivers/sbus/sbus.c	Mon Jan 14 10:10:44 2002
+++ linux/drivers/sbus/sbus.c	Wed Jan 23 17:31:04 2002
@@ -509,3 +509,5 @@
 	}
 #endif
 }
+
+subsys_initcall(sbus_init);
diff -urN linux-2.5.3-pre3/drivers/scsi/README.st linux/drivers/scsi/README.st
--- linux-2.5.3-pre3/drivers/scsi/README.st	Fri Nov  9 13:52:21 2001
+++ linux/drivers/scsi/README.st	Wed Jan 23 17:31:04 2002
@@ -2,7 +2,7 @@
 The driver is currently maintained by Kai M{kisara (email
 Kai.Makisara@metla.fi)
 
-Last modified: Thu Nov  1 22:41:59 2001 by makisara@kai.makisara.local
+Last modified: Tue Jan 22 21:08:57 2002 by makisara
 
 
 BASICS
@@ -86,6 +86,11 @@
 
 The compile options are defined in the file linux/drivers/scsi/st_options.h.
 
+4. If the open option O_NONBLOCK is used, open succeeds even if the
+drive is not ready. If O_NONBLOCK is not used, the driver waits for
+the drive to become ready. If this does not happen in ST_BLOCK_SECONDS
+seconds, open fails with the errno value EIO.
+
 
 BSD AND SYS V SEMANTICS
 
@@ -327,12 +332,19 @@
 	   0xffffff means that the default is not used any more.
 	MT_ST_DEF_DENSITY
 	MT_ST_DEF_DRVBUFFER
+	   Used to set or clear the density (8 bits), and drive buffer
+	   state (3 bits). If the value is MT_ST_CLEAR_DEFAULT
+	   (0xfffff) the default will not be used any more. Otherwise
+	   the lowermost bits of the value contain the new value of
+	   the parameter.
 	MT_ST_DEF_COMPRESSION
-	   Used to set or clear the density (8 bits), drive buffer
-	   state (3 bits), and compression (single bit). If the value is
-	   MT_ST_CLEAR_DEFAULT (0xfffff), the default will not be used
-	   any more. Otherwise the lower-most bits of the value contain
-	   the new value of the parameter.
+	   The compression default will not be used if the value of
+	   the lowermost byte is 0xff. Otherwise the lowermost bit
+	   contains the new default. If the bits 8-15 are set to a
+	   non-zero number, and this number is not 0xff, the number is
+	   used as the compression algorithm. The value
+	   MT_ST_CLEAR_DEFAULT can be used to clear the compression
+	   default.
 	MT_ST_SET_TIMEOUT
 	   Set the normal timeout in seconds for this device. The
 	   default is 900 seconds (15 minutes). The timeout should be
diff -urN linux-2.5.3-pre3/drivers/scsi/st.c linux/drivers/scsi/st.c
--- linux-2.5.3-pre3/drivers/scsi/st.c	Fri Jan  4 12:07:27 2002
+++ linux/drivers/scsi/st.c	Wed Jan 23 17:31:04 2002
@@ -9,19 +9,16 @@
    Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
    Michael Schaefer, J"org Weule, and Eric Youngdale.
 
-   Copyright 1992 - 2001 Kai Makisara
+   Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sat Nov  3 19:30:55 2001 by makisara@kai.makisara.local
+   Last modified: Wed Jan 23 20:22:42 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
-
-   Reminder: write_lock_irqsave() can be replaced by write_lock() when the old SCSI
-   error handling will be discarded.
  */
 
-static char *verstr = "20011103";
+static char *verstr = "20020123";
 
 #include <linux/module.h>
 
@@ -160,21 +157,19 @@
 static int append_to_buffer(const char *, ST_buffer *, int);
 static int from_buffer(ST_buffer *, char *, int);
 
-static int st_init(void);
 static int st_attach(Scsi_Device *);
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-static struct Scsi_Device_Template st_template =
-{
-	name:"tape", 
-	tag:"st", 
-	scsi_type:TYPE_TAPE,
-	major:SCSI_TAPE_MAJOR, 
-	detect:st_detect, 
-	init:st_init,
-	attach:st_attach, 
-	detach:st_detach
+static struct Scsi_Device_Template st_template = {
+	module:		THIS_MODULE,
+	name:		"tape", 
+	tag:		"st", 
+	scsi_type:	TYPE_TAPE,
+	major:		SCSI_TAPE_MAJOR, 
+	detect:		st_detect, 
+	attach:		st_attach, 
+	detach:		st_detach
 };
 
 static int st_compression(Scsi_Tape *, int);
@@ -239,7 +234,7 @@
 		return 0;
 	}
 
-	if (driver_byte(result) & DRIVER_SENSE)
+	if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
 		scode = sense[2] & 0x0f;
 	else {
 		sense[0] = 0;
@@ -638,20 +633,96 @@
 	return 0;
 }
 
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+   error code. */
+#define CHKRES_READY       0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY   2
+#define CHKRES_NO_TAPE     3
+
+#define MAX_ATTENTIONS    10
+
+static int test_ready(Scsi_Tape *STp, int do_wait)
+{
+	int attentions, waits, max_wait, scode;
+	int retval = CHKRES_READY, new_session = FALSE;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	Scsi_Request *SRpnt = NULL;
+
+	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+	for (attentions=waits=0; ; ) {
+		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+		cmd[0] = TEST_UNIT_READY;
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
+				   STp->long_timeout, MAX_READY_RETRIES, TRUE);
+
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			break;
+		}
+
+		if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) {
+
+			scode = (SRpnt->sr_sense_buffer[2] & 0x0f);
+
+			if (scode == UNIT_ATTENTION) { /* New media? */
+				new_session = TRUE;
+				if (attentions < MAX_ATTENTIONS) {
+					attentions++;
+					continue;
+				}
+				else {
+					retval = (-EIO);
+					break;
+				}
+			}
+
+			if (scode == NOT_READY) {
+				if (waits < max_wait) {
+					set_current_state(TASK_INTERRUPTIBLE);
+					schedule_timeout(HZ);
+					if (signal_pending(current)) {
+						retval = (-EINTR);
+						break;
+					}
+					waits++;
+					continue;
+				}
+				else {
+					if ((STp->device)->scsi_level >= SCSI_2 &&
+					    SRpnt->sr_sense_buffer[12] == 0x3a)	/* Check ASC */
+						retval = CHKRES_NO_TAPE;
+					else
+						retval = CHKRES_NOT_READY;
+					break;
+				}
+			}
+		}
+
+		retval = (STp->buffer)->syscall_result;
+		if (!retval)
+			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+		break;
+	}
+
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	return retval;
+}
+
+
 /* See if the drive is ready and gather information about the tape. Return values:
    < 0   negative error code from errno.h
    0     drive ready
    1     drive not ready (possibly no tape)
 */
-#define CHKRES_READY      0
-#define CHKRES_NOT_READY  1
-
 static int check_tape(Scsi_Tape *STp, struct file *filp)
 {
-	int i, retval, new_session = FALSE;
+	int i, retval, new_session = FALSE, do_wait;
 	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
 	unsigned short st_flags = filp->f_flags;
-	Scsi_Request *SRpnt;
+	Scsi_Request *SRpnt = NULL;
 	ST_mode *STm;
 	ST_partstat *STps;
 	int dev = TAPE_NR(STp->devt);
@@ -668,32 +739,16 @@
 	}
 	STm = &(STp->modes[STp->current_mode]);
 
-	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-	cmd[0] = TEST_UNIT_READY;
-
 	saved_cleaning = STp->cleaning_req;
 	STp->cleaning_req = 0;
-	SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout,
-			   MAX_READY_RETRIES, TRUE);
-	if (!SRpnt) {
-		retval = (STp->buffer)->syscall_result;
-		goto err_out;
-	}
 
-	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+	do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
+	retval = test_ready(STp, do_wait);
 
-		/* Flush the queued UNIT ATTENTION sense data */
-		for (i=0; i < 10; i++) {
-                        memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
-                        cmd[0] = TEST_UNIT_READY;
-                        SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
-					   STp->long_timeout, MAX_READY_RETRIES, TRUE);
-                        if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
-                            (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
-                                break;
-		}
+	if (retval < 0)
+	    goto err_out;
 
+	if (retval == CHKRES_NEW_SESSION) {
 		(STp->device)->was_reset = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
@@ -710,26 +765,23 @@
 		}
 		new_session = TRUE;
 	}
-	else
+	else {
 		STp->cleaning_req |= saved_cleaning;
 
-	if ((STp->buffer)->syscall_result != 0) {
-		if ((STp->device)->scsi_level >= SCSI_2 &&
-		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
-		    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
-		    SRpnt->sr_sense_buffer[12] == 0x3a) {	/* Check ASC */
-			STp->ready = ST_NO_TAPE;
-		} else
-			STp->ready = ST_NOT_READY;
-		scsi_release_request(SRpnt);
-		SRpnt = NULL;
-		STp->density = 0;	/* Clear the erroneous "residue" */
-		STp->write_prot = 0;
-		STp->block_size = 0;
-		STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-		STp->partition = STp->new_partition = 0;
-		STp->door_locked = ST_UNLOCKED;
-		return CHKRES_NOT_READY;
+		if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+			if (retval == CHKRES_NO_TAPE)
+				STp->ready = ST_NO_TAPE;
+			else
+				STp->ready = ST_NOT_READY;
+
+			STp->density = 0;	/* Clear the erroneous "residue" */
+			STp->write_prot = 0;
+			STp->block_size = 0;
+			STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+			STp->partition = STp->new_partition = 0;
+			STp->door_locked = ST_UNLOCKED;
+			return CHKRES_NOT_READY;
+		}
 	}
 
 	if (STp->omit_blklims)
@@ -740,6 +792,10 @@
 
 		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout,
 				   MAX_READY_RETRIES, TRUE);
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			goto err_out;
+		}
 
 		if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) {
 			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
@@ -763,6 +819,10 @@
 
 	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout,
 			   MAX_READY_RETRIES, TRUE);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;
+		goto err_out;
+	}
 
 	if ((STp->buffer)->syscall_result != 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev));
@@ -862,22 +922,21 @@
 	Scsi_Tape *STp;
 	ST_partstat *STps;
 	int dev = TAPE_NR(inode->i_rdev);
-	unsigned long flags;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	STp = scsi_tapes[dev];
 	if (dev >= st_template.dev_max || STp == NULL) {
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		return (-ENXIO);
 	}
 
 	if (STp->in_use) {
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		DEB( printk(ST_DEB_MSG "st%d: Device already in use.\n", dev); )
 		return (-EBUSY);
 	}
 	STp->in_use = 1;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	STp->rew_at_close = STp->autorew_dev = (minor(inode->i_rdev) & 0x80) == 0;
 
 	if (STp->device->host->hostt->module)
@@ -891,7 +950,7 @@
 
 	/* Allocate a buffer for this user */
 	need_dma_buffer = STp->restr_dma;
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	for (i = 0; i < st_nbr_buffers; i++)
 		if (!st_buffers[i]->in_use &&
 		    (!need_dma_buffer || st_buffers[i]->dma)) {
@@ -899,7 +958,7 @@
 			(STp->buffer)->in_use = 1;
 			break;
 		}
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	if (i >= st_nbr_buffers) {
 		STp->buffer = new_tape_buffer(FALSE, need_dma_buffer, TRUE);
 		if (STp->buffer == NULL) {
@@ -935,6 +994,11 @@
 	retval = check_tape(STp, filp);
 	if (retval < 0)
 		goto err_out;
+	if ((filp->f_flags & O_NONBLOCK) == 0 &&
+	    retval != CHKRES_READY) {
+		retval = (-EIO);
+		goto err_out;
+	}
 	return 0;
 
  err_out:
@@ -1076,7 +1140,6 @@
 {
 	int result = 0;
 	Scsi_Tape *STp;
-	unsigned long flags;
 
 	kdev_t devt = inode->i_rdev;
 	int dev;
@@ -1091,16 +1154,16 @@
 
 	if (STp->buffer != NULL) {
 		normalize_buffer(STp->buffer);
-		write_lock_irqsave(&st_dev_arr_lock, flags);
+		write_lock(&st_dev_arr_lock);
 		(STp->buffer)->in_use = 0;
 		STp->buffer = NULL;
 	}
 	else {
-		write_lock_irqsave(&st_dev_arr_lock, flags);
+		write_lock(&st_dev_arr_lock);
 	}
 
 	STp->in_use = 0;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	STp->device->access_count--;
 	if (STp->device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
@@ -1944,6 +2007,10 @@
 			STm->default_blksize = value;
 			printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
 			       dev, STm->default_blksize);
+			if (STp->ready == ST_READY) {
+				STp->blksize_changed = FALSE;
+				set_mode_densblk(STp, STm);
+			}
 		}
 	} else if (code == MT_ST_TIMEOUTS) {
 		value = (options & ~MT_ST_OPTIONS);
@@ -1979,6 +2046,10 @@
 				STm->default_density = value & 0xff;
 				printk(KERN_INFO "st%d: Density default set to %x\n",
 				       dev, STm->default_density);
+				if (STp->ready == ST_READY) {
+					STp->density_changed = FALSE;
+					set_mode_densblk(STp, STm);
+				}
 			}
 		} else if (code == MT_ST_DEF_DRVBUFFER) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1990,6 +2061,8 @@
 				printk(KERN_INFO
                                        "st%d: Drive buffer default set to %x\n",
 				       dev, STp->default_drvbuffer);
+				if (STp->ready == ST_READY)
+					st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
 			}
 		} else if (code == MT_ST_DEF_COMPRESSION) {
 			if (value == MT_ST_CLEAR_DEFAULT) {
@@ -1997,9 +2070,20 @@
 				printk(KERN_INFO
                                        "st%d: Compression default disabled.\n", dev);
 			} else {
-				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-				printk(KERN_INFO "st%d: Compression default set to %x\n",
-				       dev, (value & 1));
+				if ((value & 0xff00) != 0) {
+					STp->c_algo = (value & 0xff00) >> 8;
+					printk(KERN_INFO "st%d: Compression algorithm set to 0x%x.\n",
+					       dev, STp->c_algo);
+				}
+				if ((value & 0xff) != 0xff) {
+					STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+					printk(KERN_INFO "st%d: Compression default set to %x\n",
+					       dev, (value & 1));
+					if (STp->ready == ST_READY) {
+						STp->compression_changed = FALSE;
+						st_compression(STp, (STm->default_compression == ST_YES));
+					}
+				}
 			}
 		}
 	} else
@@ -2087,6 +2171,7 @@
 #define COMPRESSION_PAGE_LENGTH 16
 
 #define CP_OFF_DCE_DCC          2
+#define CP_OFF_C_ALGO           7
 
 #define DCE_MASK  0x80
 #define DCC_MASK  0x40
@@ -2122,16 +2207,22 @@
                     (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
 
 	/* Check if compression can be changed */
-	if ((b_data[mpoffs + 2] & DCC_MASK) == 0) {
+	if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
                 DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev));
 		return (-EIO);
 	}
 
 	/* Do the change */
-	if (state)
+	if (state) {
 		b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
-	else
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
+	}
+	else {
 		b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
+	}
 
 	retval = write_mode_page(STp, COMPRESSION_PAGE);
 	if (retval) {
@@ -2171,7 +2262,7 @@
 	 */
 	if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
 	    && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
-		DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+		DEBC(printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2d.\n",
 			    dev, (cmd[4]) ? "" : "un",
 			    load_code - MT_ST_HPLOADER_OFFSET));
 		cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
@@ -2202,12 +2293,12 @@
 
 		if (!load_code)
 			STp->rew_at_close = 0;
-		else
+		else {
 			STp->rew_at_close = STp->autorew_dev;
-
-		retval = check_tape(STp, filp);
-		if (retval > 0)
-			retval = 0;
+			retval = check_tape(STp, filp);
+			if (retval > 0)
+				retval = 0;
+		}
 	}
 	else {
 		STps = &(STp->ps[STp->partition]);
@@ -3286,7 +3377,6 @@
  new_tape_buffer(int from_initialization, int need_dma, int in_use)
 {
 	int i, priority, b_size, order, got = 0, segs = 0;
-	unsigned long flags;
 	ST_buffer *tb;
 
 	read_lock(&st_dev_arr_lock);
@@ -3381,9 +3471,9 @@
 	tb->buffer_size = got;
 	tb->writing = 0;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	st_buffers[st_nbr_buffers++] = tb;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 
 	return tb;
 }
@@ -3611,7 +3701,6 @@
 	ST_mode *STm;
 	ST_partstat *STps;
 	int i, mode, target_nbr, dev_num;
-	unsigned long flags = 0;
 	char *stp;
 
 	if (SDp->type != TYPE_TAPE)
@@ -3624,7 +3713,7 @@
 		return 1;
 	}
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	if (st_template.nr_dev >= st_template.dev_max) {
 		Scsi_Tape **tmp_da;
 		ST_buffer **tmp_ba;
@@ -3635,7 +3724,7 @@
 			tmp_dev_max = ST_MAX_TAPES;
 		if (tmp_dev_max <= st_template.nr_dev) {
 			SDp->attached--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
 			       ST_MAX_TAPES);
 			return 1;
@@ -3649,7 +3738,7 @@
 			if (tmp_ba != NULL)
 				kfree(tmp_ba);
 			SDp->attached--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Can't extend device array.\n");
 			return 1;
 		}
@@ -3682,7 +3771,7 @@
 	tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
 		SDp->attached--;
-		write_unlock_irqrestore(&st_dev_arr_lock, flags);
+		write_unlock(&st_dev_arr_lock);
 		printk(KERN_ERR "st: Can't allocate device descriptor.\n");
 		return 1;
 	}
@@ -3770,7 +3859,7 @@
 	init_MUTEX(&tpnt->lock);
 
 	st_template.nr_dev++;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	printk(KERN_WARNING
 	"Attached scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
 	       dev_num, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
@@ -3798,45 +3887,12 @@
 	return 1;
 }
 
-static int st_registered = 0;
-
-/* Driver initialization (not __init because may be called later) */
-static int st_init()
-{
-	unsigned long flags;
-
-	if (st_template.dev_noticed == 0 || st_registered)
-		return 0;
-
-	printk(KERN_INFO
-	       "st: Version %s, bufsize %d, wrt %d, max init. bufs %d, s/g segs %d\n",
-	       verstr, st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
-
-	write_lock_irqsave(&st_dev_arr_lock, flags);
-	if (!st_registered) {
-		if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
-			printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
-                               MAJOR_NR);
-			return 1;
-		}
-		st_registered++;
-	}
-
-	st_template.dev_max = 0;
-	st_nbr_buffers = 0;
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
-
-	return 0;
-}
-
 static void st_detach(Scsi_Device * SDp)
 {
 	Scsi_Tape *tpnt;
 	int i, mode;
-	unsigned long flags;
 
-	write_lock_irqsave(&st_dev_arr_lock, flags);
+	write_lock(&st_dev_arr_lock);
 	for (i = 0; i < st_template.dev_max; i++) {
 		tpnt = scsi_tapes[i];
 		if (tpnt != NULL && tpnt->device == SDp) {
@@ -3852,22 +3908,30 @@
 			SDp->attached--;
 			st_template.nr_dev--;
 			st_template.dev_noticed--;
-			write_unlock_irqrestore(&st_dev_arr_lock, flags);
+			write_unlock(&st_dev_arr_lock);
 			return;
 		}
 	}
 
-	write_unlock_irqrestore(&st_dev_arr_lock, flags);
+	write_unlock(&st_dev_arr_lock);
 	return;
 }
 
-
 static int __init init_st(void)
 {
 	validate_options();
 
-	st_template.module = THIS_MODULE;
-        return scsi_register_device(&st_template);
+	printk(KERN_INFO
+		"st: Version %s, bufsize %d, wrt %d, "
+		"max init. bufs %d, s/g segs %d\n",
+		verstr, st_buffer_size, st_write_threshold,
+		st_max_buffers, st_max_sg_segs);
+
+	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
+		return scsi_register_device(&st_template);
+
+	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+	return 1;
 }
 
 static void __exit exit_st(void)
@@ -3876,7 +3940,6 @@
 
 	scsi_unregister_device(&st_template);
 	devfs_unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-	st_registered--;
 	if (scsi_tapes != NULL) {
 		for (i=0; i < st_template.dev_max; ++i)
 			if (scsi_tapes[i])
diff -urN linux-2.5.3-pre3/drivers/scsi/st.h linux/drivers/scsi/st.h
--- linux-2.5.3-pre3/drivers/scsi/st.h	Fri Nov  9 13:52:21 2001
+++ linux/drivers/scsi/st.h	Wed Jan 23 17:31:04 2002
@@ -83,6 +83,7 @@
 	unsigned char cln_sense_value;
 	unsigned char cln_sense_mask;
 	unsigned char use_pf;			/* Set Page Format bit in all mode selects? */
+	unsigned char c_algo;			/* compression algorithm */
 	int tape_type;
 	int write_threshold;
 	int timeout;		/* timeout for normal commands */
diff -urN linux-2.5.3-pre3/drivers/scsi/st_options.h linux/drivers/scsi/st_options.h
--- linux-2.5.3-pre3/drivers/scsi/st_options.h	Mon Apr 24 13:54:22 2000
+++ linux/drivers/scsi/st_options.h	Wed Jan 23 17:31:04 2002
@@ -3,7 +3,7 @@
 
    Copyright 1995-2000 Kai Makisara.
 
-   Last modified: Sat Apr 22 14:47:02 2000 by makisara@kai.makisara.local
+   Last modified: Tue Jan 22 21:52:34 2002 by makisara
 */
 
 #ifndef _ST_OPTIONS_H
@@ -99,5 +99,7 @@
    The default is BSD semantics. */
 #define ST_SYSV 0
 
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS     120
 
 #endif
diff -urN linux-2.5.3-pre3/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- linux-2.5.3-pre3/drivers/sound/cmpci.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/sound/cmpci.c	Wed Jan 23 17:31:04 2002
@@ -1440,7 +1440,7 @@
 
 static int cm_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 
 	while (s && s->dev_mixer != minor)
@@ -2190,7 +2190,7 @@
 
 static int cm_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 	unsigned char fmtm = ~0, fmts = 0;
 
@@ -2445,7 +2445,7 @@
 
 static int cm_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 	unsigned long flags;
 
@@ -2662,7 +2662,7 @@
 
 static int cm_dmfm_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct cm_state *s = devs;
 
 	while (s && s->dev_dmfm != minor)
@@ -2861,7 +2861,9 @@
 	struct cm_state *s;
 	mm_segment_t fs;
 	int i, val;
+#if defined(CONFIG_SOUND_CMPCI_MIDI) || defined(CONFIG_SOUND_CMPCI_FM)
 	unsigned char reg_mask = 0;
+#endif
 	struct {
 		unsigned short	deviceid;
 		char		*devicename;
diff -urN linux-2.5.3-pre3/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.5.3-pre3/drivers/sound/ymfpci.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/sound/ymfpci.c	Wed Jan 23 17:31:04 2002
@@ -832,7 +832,14 @@
 	u32 lpfK = ymfpci_calc_lpfK(rate);
 	ymfpci_playback_bank_t *bank;
 	int nbank;
-	unsigned le_0x40000000 = cpu_to_le32(0x40000000);
+
+	/*
+	 * The gain is a floating point number. According to the manual,
+	 * bit 31 indicates a sign bit, bit 30 indicates an integer part,
+	 * and bits [29:15] indicate a decimal fraction part. Thus,
+	 * for a gain of 1.0 the constant of 0x40000000 is loaded.
+	 */
+	unsigned default_gain = cpu_to_le32(0x40000000);
 
 	format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
 	if (stereo)
@@ -847,7 +854,7 @@
 		bank->loop_start = 0;
 		bank->loop_end = cpu_to_le32(end);
 		bank->loop_frac = 0;
-		bank->eg_gain_end = le_0x40000000;
+		bank->eg_gain_end = default_gain;
 		bank->lpfQ = cpu_to_le32(lpfQ);
 		bank->status = 0;
 		bank->num_of_frames = 0;
@@ -858,7 +865,7 @@
 		bank->delta_end = cpu_to_le32(delta);
 		bank->lpfK =
 		bank->lpfK_end = cpu_to_le32(lpfK);
-		bank->eg_gain = le_0x40000000;
+		bank->eg_gain = default_gain;
 		bank->lpfD1 =
 		bank->lpfD2 = 0;
 
@@ -878,31 +885,31 @@
 				bank->left_gain = 
 				bank->right_gain =
 				bank->left_gain_end =
-				bank->right_gain_end = le_0x40000000;
+				bank->right_gain_end = default_gain;
 			} else {
 				bank->eff2_gain =
 				bank->eff2_gain_end =
 				bank->eff3_gain =
-				bank->eff3_gain_end = le_0x40000000;
+				bank->eff3_gain_end = default_gain;
 			}
 		} else {
 			if (!spdif) {
 				if ((voice->number & 1) == 0) {
 					bank->left_gain =
-					bank->left_gain_end = le_0x40000000;
+					bank->left_gain_end = default_gain;
 				} else {
 					bank->format |= cpu_to_le32(1);
 					bank->right_gain =
-					bank->right_gain_end = le_0x40000000;
+					bank->right_gain_end = default_gain;
 				}
 			} else {
 				if ((voice->number & 1) == 0) {
 					bank->eff2_gain =
-					bank->eff2_gain_end = le_0x40000000;
+					bank->eff2_gain_end = default_gain;
 				} else {
 					bank->format |= cpu_to_le32(1);
 					bank->eff3_gain =
-					bank->eff3_gain_end = le_0x40000000;
+					bank->eff3_gain_end = default_gain;
 				}
 			}
 		}
diff -urN linux-2.5.3-pre3/drivers/tc/tc.c linux/drivers/tc/tc.c
--- linux-2.5.3-pre3/drivers/tc/tc.c	Thu Oct 11 09:43:30 2001
+++ linux/drivers/tc/tc.c	Wed Jan 23 17:31:04 2002
@@ -236,6 +236,8 @@
 	}
 }
 
+subsys_initcall(tc_init);
+
 EXPORT_SYMBOL(search_tc_card);
 EXPORT_SYMBOL(claim_tc_card);
 EXPORT_SYMBOL(release_tc_card);
diff -urN linux-2.5.3-pre3/drivers/usb/CDCEther.c linux/drivers/usb/CDCEther.c
--- linux-2.5.3-pre3/drivers/usb/CDCEther.c	Sat Dec  8 20:28:44 2001
+++ linux/drivers/usb/CDCEther.c	Wed Jan 23 17:31:04 2002
@@ -125,14 +125,14 @@
 
 goon:
 	// Prep the USB to wait for another frame
-	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
 			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
 			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
 			read_bulk_callback, ether_dev );
 			
 	// Give this to the USB subsystem so it can tell us 
 	// when more data arrives.
-	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) ) {
+	if ( (res = usb_submit_urb(ether_dev->rx_urb)) ) {
 		warn( __FUNCTION__ " failed submint rx_urb %d", res);
 	}
 	
@@ -259,8 +259,8 @@
 	warn("%s: Tx timed out.", net->name);
 	
 	// Tear the waiting frame off the list
-	ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( &ether_dev->tx_urb );
+	ether_dev->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( ether_dev->tx_urb );
 	
 	// Update statistics
 	ether_dev->stats.tx_errors++;
@@ -293,16 +293,16 @@
 	memcpy(ether_dev->tx_buff, skb->data, skb->len);
 
 	// Fill in the URB for shipping it out.
-	FILL_BULK_URB( &ether_dev->tx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->tx_urb, ether_dev->usb,
 			usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
 			ether_dev->tx_buff, ether_dev->wMaxSegmentSize, 
 			write_bulk_callback, ether_dev );
 
 	// Tell the URB how much it will be transporting today
-	ether_dev->tx_urb.transfer_buffer_length = count;
+	ether_dev->tx_urb->transfer_buffer_length = count;
 	
 	// Send the URB on its merry way.
-	if ((res = usb_submit_urb(&ether_dev->tx_urb)))  {
+	if ((res = usb_submit_urb(ether_dev->tx_urb)))  {
 		// Hmm...  It didn't go. Tell someone...
 		warn("failed tx_urb %d", res);
 		// update some stats...
@@ -344,13 +344,13 @@
 	}
 
 	// Prep a receive URB
-	FILL_BULK_URB( &ether_dev->rx_urb, ether_dev->usb,
+	FILL_BULK_URB( ether_dev->rx_urb, ether_dev->usb,
 			usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
 			ether_dev->rx_buff, ether_dev->wMaxSegmentSize, 
 			read_bulk_callback, ether_dev );
 
 	// Put it out there so the device can send us stuff
-	if ( (res = usb_submit_urb(&ether_dev->rx_urb)) )
+	if ( (res = usb_submit_urb(ether_dev->rx_urb)) )
 	{
 		// Hmm...  Okay...
 		warn( __FUNCTION__ " failed rx_urb %d", res );
@@ -383,9 +383,9 @@
 	}
 
 	// We don't need the URBs anymore.
-	usb_unlink_urb( &ether_dev->rx_urb );
-	usb_unlink_urb( &ether_dev->tx_urb );
-	usb_unlink_urb( &ether_dev->intr_urb );
+	usb_unlink_urb( ether_dev->rx_urb );
+	usb_unlink_urb( ether_dev->tx_urb );
+	usb_unlink_urb( ether_dev->intr_urb );
 	
 	// That's it.  I'm done.
 	return 0;
@@ -1144,6 +1144,25 @@
 	// Zero everything out.
 	memset(ether_dev, 0, sizeof(ether_dev_t));
 
+	ether_dev->rx_urb = usb_alloc_urb(0);
+	if (!ether_dev->rx_urb) {
+		kfree(ether_dev);
+		return NULL;
+	}
+	ether_dev->tx_urb = usb_alloc_urb(0);
+	if (!ether_dev->tx_urb) {
+		usb_free_urb(ether_dev->rx_urb);
+		kfree(ether_dev);
+		return NULL;
+	}
+	ether_dev->intr_urb = usb_alloc_urb(0);
+	if (!ether_dev->intr_urb) {
+		usb_free_urb(ether_dev->tx_urb);
+		usb_free_urb(ether_dev->rx_urb);
+		kfree(ether_dev);
+		return NULL;
+	}
+
 	// Let's see if we can find a configuration we can use.
 	rc = find_valid_configuration( usb, ether_dev );
 	if (rc)	{
@@ -1290,6 +1309,9 @@
 	                              &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
 
 	// No more tied up kernel memory
+	usb_free_urb(ether_dev->intr_urb);
+	usb_free_urb(ether_dev->rx_urb);
+	usb_free_urb(ether_dev->rx_urb);
 	kfree( ether_dev );
 	
 	// This does no good, but it looks nice!
diff -urN linux-2.5.3-pre3/drivers/usb/CDCEther.h linux/drivers/usb/CDCEther.h
--- linux-2.5.3-pre3/drivers/usb/CDCEther.h	Sun Sep 23 09:49:00 2001
+++ linux/drivers/usb/CDCEther.h	Wed Jan 23 17:31:04 2002
@@ -83,7 +83,7 @@
 	__u16			wNumberMCFilters;
 	__u8			bNumberPowerFilters;
 	int			intr_interval;
-	struct urb		rx_urb, tx_urb, intr_urb;
+	struct urb		*rx_urb, *tx_urb, *intr_urb;
 	unsigned char		ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
 	unsigned char		ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
 	unsigned char		ALIGN(intr_buff[8]);
diff -urN linux-2.5.3-pre3/drivers/usb/audio.c linux/drivers/usb/audio.c
--- linux-2.5.3-pre3/drivers/usb/audio.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/audio.c	Wed Jan 23 17:31:04 2002
@@ -297,12 +297,12 @@
 #define FLG_CONNECTED    32
 
 struct my_data_urb {
-	struct urb urb;
+	struct urb *urb;
 	struct usb_iso_packet_descriptor isoframe[DESCFRAMES];
 };
 
 struct my_sync_urb {
-	struct urb urb;
+	struct urb *urb;
 	struct usb_iso_packet_descriptor isoframe[SYNCFRAMES];
 };
 
@@ -648,27 +648,27 @@
 		spin_unlock_irqrestore(&as->lock, flags);
 		if (notkilled && signal_pending(current)) {
 			if (i & FLG_URB0RUNNING)
-				usb_unlink_urb(&u->durb[0].urb);
+				usb_unlink_urb(u->durb[0].urb);
 			if (i & FLG_URB1RUNNING)
-				usb_unlink_urb(&u->durb[1].urb);
+				usb_unlink_urb(u->durb[1].urb);
 			if (i & FLG_SYNC0RUNNING)
-				usb_unlink_urb(&u->surb[0].urb);
+				usb_unlink_urb(u->surb[0].urb);
 			if (i & FLG_SYNC1RUNNING)
-				usb_unlink_urb(&u->surb[1].urb);
+				usb_unlink_urb(u->surb[1].urb);
 			notkilled = 0;
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb.transfer_buffer)
-		kfree(u->durb[0].urb.transfer_buffer);
-	if (u->durb[1].urb.transfer_buffer)
-		kfree(u->durb[1].urb.transfer_buffer);
-	if (u->surb[0].urb.transfer_buffer)
-		kfree(u->surb[0].urb.transfer_buffer);
-	if (u->surb[1].urb.transfer_buffer)
-		kfree(u->surb[1].urb.transfer_buffer);
-	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+	if (u->durb[0].urb->transfer_buffer)
+		kfree(u->durb[0].urb->transfer_buffer);
+	if (u->durb[1].urb->transfer_buffer)
+		kfree(u->durb[1].urb->transfer_buffer);
+	if (u->surb[0].urb->transfer_buffer)
+		kfree(u->surb[0].urb->transfer_buffer);
+	if (u->surb[1].urb->transfer_buffer)
+		kfree(u->surb[1].urb->transfer_buffer);
+	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbin_release(struct usb_audiodev *as)
@@ -904,9 +904,9 @@
 #if 0
 	printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->durb[0].urb)
+	if (urb == u->durb[0].urb)
 		mask = FLG_URB0RUNNING;
-	else if (urb == &u->durb[1].urb)
+	else if (urb == u->durb[1].urb)
 		mask = FLG_URB1RUNNING;
 	else {
 		mask = 0;
@@ -969,9 +969,9 @@
 #if 0
 	printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->surb[0].urb)
+	if (urb == u->surb[0].urb)
 		mask = FLG_SYNC0RUNNING;
-	else if (urb == &u->surb[1].urb)
+	else if (urb == u->surb[1].urb)
 		mask = FLG_SYNC1RUNNING;
 	else {
 		mask = 0;
@@ -1017,26 +1017,26 @@
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb.transfer_buffer)
-			kfree(u->durb[0].urb.transfer_buffer);
-		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb.transfer_buffer_length = bufsz;
-		if (u->durb[1].urb.transfer_buffer)
-			kfree(u->durb[1].urb.transfer_buffer);
-		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->durb[0].urb->transfer_buffer)
+			kfree(u->durb[0].urb->transfer_buffer);
+		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb->transfer_buffer_length = bufsz;
+		if (u->durb[1].urb->transfer_buffer)
+			kfree(u->durb[1].urb->transfer_buffer);
+		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb.transfer_buffer)
-				kfree(u->surb[0].urb.transfer_buffer);
-			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb.transfer_buffer)
-				kfree(u->surb[1].urb.transfer_buffer);
-			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[0].urb->transfer_buffer)
+				kfree(u->surb[0].urb->transfer_buffer);
+			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb->transfer_buffer)
+				kfree(u->surb[1].urb->transfer_buffer);
+			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
-		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
 			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
 			return 0;
 		}
@@ -1048,7 +1048,7 @@
 	}
 	u->flags |= FLG_RUNNING;
 	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = &u->durb[0].urb;
+		urb = u->durb[0].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1061,7 +1061,7 @@
 			u->flags &= ~FLG_RUNNING;
 	}
 	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = &u->durb[1].urb;
+		urb = u->durb[1].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1075,7 +1075,7 @@
 	}
 	if (u->syncpipe) {
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = &u->surb[0].urb;
+			urb = u->surb[0].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1089,7 +1089,7 @@
 				u->flags &= ~FLG_RUNNING;
 		}
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = &u->surb[1].urb;
+			urb = u->surb[1].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1125,27 +1125,27 @@
 		spin_unlock_irqrestore(&as->lock, flags);
 		if (notkilled && signal_pending(current)) {
 			if (i & FLG_URB0RUNNING)
-				usb_unlink_urb(&u->durb[0].urb);
+				usb_unlink_urb(u->durb[0].urb);
 			if (i & FLG_URB1RUNNING)
-				usb_unlink_urb(&u->durb[1].urb);
+				usb_unlink_urb(u->durb[1].urb);
 			if (i & FLG_SYNC0RUNNING)
-				usb_unlink_urb(&u->surb[0].urb);
+				usb_unlink_urb(u->surb[0].urb);
 			if (i & FLG_SYNC1RUNNING)
-				usb_unlink_urb(&u->surb[1].urb);
+				usb_unlink_urb(u->surb[1].urb);
 			notkilled = 0;
 		}
 	}
 	set_current_state(TASK_RUNNING);
-	if (u->durb[0].urb.transfer_buffer)
-		kfree(u->durb[0].urb.transfer_buffer);
-	if (u->durb[1].urb.transfer_buffer)
-		kfree(u->durb[1].urb.transfer_buffer);
-	if (u->surb[0].urb.transfer_buffer)
-		kfree(u->surb[0].urb.transfer_buffer);
-	if (u->surb[1].urb.transfer_buffer)
-		kfree(u->surb[1].urb.transfer_buffer);
-	u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = 
-		u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;
+	if (u->durb[0].urb->transfer_buffer)
+		kfree(u->durb[0].urb->transfer_buffer);
+	if (u->durb[1].urb->transfer_buffer)
+		kfree(u->durb[1].urb->transfer_buffer);
+	if (u->surb[0].urb->transfer_buffer)
+		kfree(u->surb[0].urb->transfer_buffer);
+	if (u->surb[1].urb->transfer_buffer)
+		kfree(u->surb[1].urb->transfer_buffer);
+	u->durb[0].urb->transfer_buffer = u->durb[1].urb->transfer_buffer = 
+		u->surb[0].urb->transfer_buffer = u->surb[1].urb->transfer_buffer = NULL;
 }
 
 static inline void usbout_release(struct usb_audiodev *as)
@@ -1262,9 +1262,9 @@
 #if 0
 	printk(KERN_DEBUG "usbout_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->durb[0].urb)
+	if (urb == u->durb[0].urb)
 		mask = FLG_URB0RUNNING;
-	else if (urb == &u->durb[1].urb)
+	else if (urb == u->durb[1].urb)
 		mask = FLG_URB1RUNNING;
 	else {
 		mask = 0;
@@ -1334,9 +1334,9 @@
 #if 0
 	printk(KERN_DEBUG "usbout_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);
 #endif
-	if (urb == &u->surb[0].urb)
+	if (urb == u->surb[0].urb)
 		mask = FLG_SYNC0RUNNING;
-	else if (urb == &u->surb[1].urb)
+	else if (urb == u->surb[1].urb)
 		mask = FLG_SYNC1RUNNING;
 	else {
 		mask = 0;
@@ -1382,26 +1382,26 @@
 		u->phase = 0;
 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
 		bufsz = DESCFRAMES * maxsze;
-		if (u->durb[0].urb.transfer_buffer)
-			kfree(u->durb[0].urb.transfer_buffer);
-		u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[0].urb.transfer_buffer_length = bufsz;
-		if (u->durb[1].urb.transfer_buffer)
-			kfree(u->durb[1].urb.transfer_buffer);
-		u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
-		u->durb[1].urb.transfer_buffer_length = bufsz;
+		if (u->durb[0].urb->transfer_buffer)
+			kfree(u->durb[0].urb->transfer_buffer);
+		u->durb[0].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[0].urb->transfer_buffer_length = bufsz;
+		if (u->durb[1].urb->transfer_buffer)
+			kfree(u->durb[1].urb->transfer_buffer);
+		u->durb[1].urb->transfer_buffer = kmalloc(bufsz, GFP_KERNEL);
+		u->durb[1].urb->transfer_buffer_length = bufsz;
 		if (u->syncpipe) {
-			if (u->surb[0].urb.transfer_buffer)
-				kfree(u->surb[0].urb.transfer_buffer);
-			u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES;
-			if (u->surb[1].urb.transfer_buffer)
-				kfree(u->surb[1].urb.transfer_buffer);
-			u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
-			u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[0].urb->transfer_buffer)
+				kfree(u->surb[0].urb->transfer_buffer);
+			u->surb[0].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[0].urb->transfer_buffer_length = 3*SYNCFRAMES;
+			if (u->surb[1].urb->transfer_buffer)
+				kfree(u->surb[1].urb->transfer_buffer);
+			u->surb[1].urb->transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL);
+			u->surb[1].urb->transfer_buffer_length = 3*SYNCFRAMES;
 		}
-		if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || 
-		    (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) {
+		if (!u->durb[0].urb->transfer_buffer || !u->durb[1].urb->transfer_buffer || 
+		    (u->syncpipe && (!u->surb[0].urb->transfer_buffer || !u->surb[1].urb->transfer_buffer))) {
 			printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum);
 			return 0;
 		}
@@ -1413,7 +1413,7 @@
 	}
        	u->flags |= FLG_RUNNING;
 	if (!(u->flags & FLG_URB0RUNNING)) {
-		urb = &u->durb[0].urb;
+		urb = u->durb[0].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1426,7 +1426,7 @@
 			u->flags &= ~FLG_RUNNING;
 	}
 	if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) {
-		urb = &u->durb[1].urb;
+		urb = u->durb[1].urb;
 		urb->dev = dev;
 		urb->pipe = u->datapipe;
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -1440,7 +1440,7 @@
 	}
 	if (u->syncpipe) {
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) {
-			urb = &u->surb[0].urb;
+			urb = u->surb[0].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1454,7 +1454,7 @@
 				u->flags &= ~FLG_RUNNING;
 		}
 		if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) {
-			urb = &u->surb[1].urb;
+			urb = u->surb[1].urb;
 			urb->dev = dev;
 			urb->pipe = u->syncpipe;
 			urb->transfer_flags = USB_ISO_ASAP;
@@ -1921,6 +1921,14 @@
 		usbout_release(as);
 		dmabuf_release(&as->usbin.dma);
 		dmabuf_release(&as->usbout.dma);
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 	}
 	while (!list_empty(&s->mixerlist)) {
@@ -2821,14 +2829,33 @@
 	init_waitqueue_head(&as->usbin.dma.wait);
 	init_waitqueue_head(&as->usbout.dma.wait);
 	spin_lock_init(&as->lock);
-	spin_lock_init(&as->usbin.durb[0].urb.lock);
-	spin_lock_init(&as->usbin.durb[1].urb.lock);
-	spin_lock_init(&as->usbin.surb[0].urb.lock);
-	spin_lock_init(&as->usbin.surb[1].urb.lock);
-	spin_lock_init(&as->usbout.durb[0].urb.lock);
-	spin_lock_init(&as->usbout.durb[1].urb.lock);
-	spin_lock_init(&as->usbout.surb[0].urb.lock);
-	spin_lock_init(&as->usbout.surb[1].urb.lock);
+	as->usbin.durb[0].urb = usb_alloc_urb(0);
+	as->usbin.durb[1].urb = usb_alloc_urb(0);
+	as->usbin.surb[0].urb = usb_alloc_urb(0);
+	as->usbin.surb[1].urb = usb_alloc_urb(0);
+	as->usbout.durb[0].urb = usb_alloc_urb(0);
+	as->usbout.durb[1].urb = usb_alloc_urb(0);
+	as->usbout.surb[0].urb = usb_alloc_urb(0);
+	as->usbout.surb[1].urb = usb_alloc_urb(0);
+	if ((!as->usbin.durb[0].urb) ||
+	    (!as->usbin.durb[1].urb) ||
+	    (!as->usbin.surb[0].urb) ||
+	    (!as->usbin.surb[1].urb) ||
+	    (!as->usbout.durb[0].urb) ||
+	    (!as->usbout.durb[1].urb) ||
+	    (!as->usbout.surb[0].urb) ||
+	    (!as->usbout.surb[1].urb)) {
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
+		kfree(as);
+		return;
+	}
 	as->state = s;
 	as->usbin.interface = asifin;
 	as->usbout.interface = asifout;
@@ -2997,11 +3024,27 @@
 		}
 	}
 	if (as->numfmtin == 0 && as->numfmtout == 0) {
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 		return;
 	}
 	if ((as->dev_audio = register_sound_dsp(&usb_audio_fops, -1)) < 0) {
 		printk(KERN_ERR "usbaudio: cannot register dsp\n");
+		usb_free_urb(as->usbin.durb[0].urb);
+		usb_free_urb(as->usbin.durb[1].urb);
+		usb_free_urb(as->usbin.surb[0].urb);
+		usb_free_urb(as->usbin.surb[1].urb);
+		usb_free_urb(as->usbout.durb[0].urb);
+		usb_free_urb(as->usbout.durb[1].urb);
+		usb_free_urb(as->usbout.surb[0].urb);
+		usb_free_urb(as->usbout.surb[1].urb);
 		kfree(as);
 		return;
 	}
diff -urN linux-2.5.3-pre3/drivers/usb/catc.c linux/drivers/usb/catc.c
--- linux-2.5.3-pre3/drivers/usb/catc.c	Thu Jan 10 16:23:46 2002
+++ linux/drivers/usb/catc.c	Wed Jan 23 17:31:04 2002
@@ -179,7 +179,7 @@
 		void (*callback)(struct catc *catc, struct ctrl_queue *q);
 	} ctrl_queue[CTRL_QUEUE];
 
-	struct urb tx_urb, rx_urb, irq_urb, ctrl_urb;
+	struct urb *tx_urb, *rx_urb, *irq_urb, *ctrl_urb;
 };
 
 /*
@@ -256,8 +256,8 @@
 	}
 
 	if ((data[1] & 0x80) && !test_and_set_bit(RX_RUNNING, &catc->flags)) {
-		catc->rx_urb.dev = catc->usbdev;
-		if ((status = usb_submit_urb(&catc->rx_urb)) < 0) {
+		catc->rx_urb->dev = catc->usbdev;
+		if ((status = usb_submit_urb(catc->rx_urb)) < 0) {
 			err("submit(rx_urb) status %d", status);
 			return;
 		} 
@@ -282,11 +282,11 @@
 {
 	int status;
 
-	catc->tx_urb.transfer_buffer_length = catc->tx_ptr;
-	catc->tx_urb.transfer_buffer = catc->tx_buf[catc->tx_idx];
-	catc->tx_urb.dev = catc->usbdev;
+	catc->tx_urb->transfer_buffer_length = catc->tx_ptr;
+	catc->tx_urb->transfer_buffer = catc->tx_buf[catc->tx_idx];
+	catc->tx_urb->dev = catc->usbdev;
 
-	if ((status = usb_submit_urb(&catc->tx_urb)) < 0)
+	if ((status = usb_submit_urb(catc->tx_urb)) < 0)
 		err("submit(tx_urb), status %d", status);
 
 	catc->tx_idx = !catc->tx_idx;
@@ -363,8 +363,8 @@
 	struct catc *catc = netdev->priv;
 
 	warn("Transmit timed out.");
-	catc->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb(&catc->tx_urb);
+	catc->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb(catc->tx_urb);
 }
 
 /*
@@ -383,7 +383,7 @@
 {
 	struct ctrl_queue *q = catc->ctrl_queue + catc->ctrl_tail;
 	struct usb_device *usbdev = catc->usbdev;
-	struct urb *urb = &catc->ctrl_urb;
+	struct urb *urb = catc->ctrl_urb;
 	struct usb_ctrlrequest *dr = &catc->ctrl_dr;
 	int status;
 
@@ -402,7 +402,7 @@
 	if (!q->dir && q->buf && q->len)
 		memcpy(catc->ctrl_buf, q->buf, q->len);
 
-	if ((status = usb_submit_urb(&catc->ctrl_urb)))
+	if ((status = usb_submit_urb(catc->ctrl_urb)))
 		err("submit(ctrl_urb) status %d", status);
 }
 
@@ -624,8 +624,8 @@
 	struct catc *catc = netdev->priv;
 	int status;
 
-	catc->irq_urb.dev = catc->usbdev;
-	if ((status = usb_submit_urb(&catc->irq_urb)) < 0) {
+	catc->irq_urb->dev = catc->usbdev;
+	if ((status = usb_submit_urb(catc->irq_urb)) < 0) {
 		err("submit(irq_urb) status %d", status);
 		return -1;
 	}
@@ -645,10 +645,10 @@
 
 	del_timer_sync(&catc->timer);
 
-	usb_unlink_urb(&catc->rx_urb);
-	usb_unlink_urb(&catc->tx_urb);
-	usb_unlink_urb(&catc->irq_urb);
-	usb_unlink_urb(&catc->ctrl_urb);
+	usb_unlink_urb(catc->rx_urb);
+	usb_unlink_urb(catc->tx_urb);
+	usb_unlink_urb(catc->irq_urb);
+	usb_unlink_urb(catc->ctrl_urb);
 
 	return 0;
 }
@@ -694,16 +694,26 @@
 	catc->timer.data = (long) catc;
 	catc->timer.function = catc_stats_timer;
 
-	FILL_CONTROL_URB(&catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
+	catc->ctrl_urb = usb_alloc_urb(0);
+	catc->tx_urb = usb_alloc_urb(0);
+	catc->rx_urb = usb_alloc_urb(0);
+	catc->irq_urb = usb_alloc_urb(0);
+	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
+	    (!catc->rx_urb) || (!catc->irq_urb)) {
+		err("No free urbs available.");
+		return NULL;
+	}
+
+	FILL_CONTROL_URB(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
 		NULL, NULL, 0, catc_ctrl_done, catc);
 
-	FILL_BULK_URB(&catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
+	FILL_BULK_URB(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
 		NULL, 0, catc_tx_done, catc);
 
-	FILL_BULK_URB(&catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
+	FILL_BULK_URB(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
 		catc->rx_buf, RX_MAX_BURST * (PKT_SZ + 2), catc_rx_done, catc);
 
-	FILL_INT_URB(&catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
+	FILL_INT_URB(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
                 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
 	dbg("Checking memory size\n");
@@ -772,6 +782,10 @@
 {
 	struct catc *catc = dev_ptr;
 	unregister_netdev(catc->netdev);
+	usb_free_urb(catc->ctrl_urb);
+	usb_free_urb(catc->tx_urb);
+	usb_free_urb(catc->rx_urb);
+	usb_free_urb(catc->irq_urb);
 	kfree(catc->netdev);
 	kfree(catc);
 }
diff -urN linux-2.5.3-pre3/drivers/usb/devio.c linux/drivers/usb/devio.c
--- linux-2.5.3-pre3/drivers/usb/devio.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/devio.c	Wed Jan 23 17:31:04 2002
@@ -53,7 +53,7 @@
 	unsigned int signr;
 	void *userbuffer;
         void *userurb;
-        struct urb urb;
+        struct urb *urb;
 };
 
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -175,17 +175,21 @@
         if (!as)
                 return NULL;
         memset(as, 0, assize);
-        as->urb.number_of_packets = numisoframes;
-        spin_lock_init(&as->urb.lock);
+	as->urb = usb_alloc_urb(numisoframes);
+	if (!as->urb) {
+		kfree(as);
+		return NULL;
+	}
         return as;
 }
 
 static void free_async(struct async *as)
 {
-        if (as->urb.transfer_buffer)
-                kfree(as->urb.transfer_buffer);
-        if (as->urb.setup_packet)
-                kfree(as->urb.setup_packet);
+        if (as->urb->transfer_buffer)
+                kfree(as->urb->transfer_buffer);
+        if (as->urb->setup_packet)
+                kfree(as->urb->setup_packet);
+	usb_free_urb(as->urb);
         kfree(as);
 }
 
@@ -259,7 +263,7 @@
         wake_up(&ps->wait);
 	if (as->signr) {
 		sinfo.si_signo = as->signr;
-		sinfo.si_errno = as->urb.status;
+		sinfo.si_errno = as->urb->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		send_sig_info(as->signr, &sinfo, as->task);
@@ -278,7 +282,7 @@
                 INIT_LIST_HEAD(&as->asynclist);
                 spin_unlock_irqrestore(&ps->lock, flags);
                 /* usb_unlink_urb calls the completion handler with status == -ENOENT */
-                usb_unlink_urb(&as->urb);
+                usb_unlink_urb(as->urb);
                 spin_lock_irqsave(&ps->lock, flags);
         }
         spin_unlock_irqrestore(&ps->lock, flags);
@@ -862,7 +866,7 @@
 			kfree(dr);
 		return -ENOMEM;
 	}
-	if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
+	if (!(as->urb->transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
 		if (isopkt)
 			kfree(isopkt);
 		if (dr)
@@ -870,19 +874,19 @@
 		free_async(as);
 		return -ENOMEM;
 	}
-        as->urb.next = NULL;
-        as->urb.dev = ps->dev;
-        as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
-        as->urb.transfer_flags = uurb.flags;
-	as->urb.transfer_buffer_length = uurb.buffer_length;
-	as->urb.setup_packet = (unsigned char*)dr;
-	as->urb.start_frame = uurb.start_frame;
-	as->urb.number_of_packets = uurb.number_of_packets;
-        as->urb.context = as;
-        as->urb.complete = async_completed;
+        as->urb->next = NULL;
+        as->urb->dev = ps->dev;
+        as->urb->pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb.flags;
+	as->urb->transfer_buffer_length = uurb.buffer_length;
+	as->urb->setup_packet = (unsigned char*)dr;
+	as->urb->start_frame = uurb.start_frame;
+	as->urb->number_of_packets = uurb.number_of_packets;
+        as->urb->context = as;
+        as->urb->complete = async_completed;
 	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
-		as->urb.iso_frame_desc[u].offset = totlen;
-		as->urb.iso_frame_desc[u].length = isopkt[u].length;
+		as->urb->iso_frame_desc[u].offset = totlen;
+		as->urb->iso_frame_desc[u].length = isopkt[u].length;
 		totlen += isopkt[u].length;
 	}
 	if (isopkt)
@@ -896,13 +900,13 @@
 	as->signr = uurb.signr;
 	as->task = current;
 	if (!(uurb.endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb.transfer_buffer, uurb.buffer, as->urb.transfer_buffer_length)) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
 	}
         async_newpending(as);
-        if ((ret = usb_submit_urb(&as->urb))) {
+        if ((ret = usb_submit_urb(as->urb))) {
 		printk(KERN_DEBUG "usbdevfs: usb_submit_urb returned %d\n", ret);
                 async_removepending(as);
                 free_async(as);
@@ -918,34 +922,35 @@
 	as = async_getpending(ps, arg);
 	if (!as)
 		return -EINVAL;
-	usb_unlink_urb(&as->urb);
+	usb_unlink_urb(as->urb);
 	return 0;
 }
 
 static int processcompl(struct async *as)
 {
+	struct urb *urb = as->urb;
 	unsigned int i;
 
 	if (as->userbuffer)
-		if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
+		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(as->urb.status,
+	if (put_user(urb->status,
 		     &((struct usbdevfs_urb *)as->userurb)->status))
 		return -EFAULT;
-	if (put_user(as->urb.actual_length,
+	if (put_user(urb->actual_length,
 		     &((struct usbdevfs_urb *)as->userurb)->actual_length))
 		return -EFAULT;
-	if (put_user(as->urb.error_count,
+	if (put_user(urb->error_count,
 		     &((struct usbdevfs_urb *)as->userurb)->error_count))
 		return -EFAULT;
 
-	if (!(usb_pipeisoc(as->urb.pipe)))
+	if (!(usb_pipeisoc(urb->pipe)))
 		return 0;
-	for (i = 0; i < as->urb.number_of_packets; i++) {
-		if (put_user(as->urb.iso_frame_desc[i].actual_length, 
+	for (i = 0; i < urb->number_of_packets; i++) {
+		if (put_user(urb->iso_frame_desc[i].actual_length, 
 			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length))
 			return -EFAULT;
-		if (put_user(as->urb.iso_frame_desc[i].status, 
+		if (put_user(urb->iso_frame_desc[i].status, 
 			     &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
 			return -EFAULT;
 	}
diff -urN linux-2.5.3-pre3/drivers/usb/dsbr100.c linux/drivers/usb/dsbr100.c
--- linux-2.5.3-pre3/drivers/usb/dsbr100.c	Tue Oct  9 15:15:02 2001
+++ linux/drivers/usb/dsbr100.c	Wed Jan 23 17:31:04 2002
@@ -90,7 +90,7 @@
 MODULE_PARM(radio_nr, "i");
 
 typedef struct
-{	struct urb readurb,writeurb;
+{
 	struct usb_device *dev;
 	unsigned char transfer_buffer[TB_LEN];
 	int curfreq;
diff -urN linux-2.5.3-pre3/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c
--- linux-2.5.3-pre3/drivers/usb/hpusbscsi.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/hpusbscsi.c	Wed Jan 23 17:31:04 2002
@@ -56,8 +56,17 @@
 		return NULL;
 	DEBUG ("Allocated memory\n");
 	memset (new, 0, sizeof (struct hpusbscsi));
-	spin_lock_init (&new->dataurb.lock);
-	spin_lock_init (&new->controlurb.lock);
+	new->dataurb = usb_alloc_urb(0);
+	if (!new->dataurb) {
+		kfree (new);
+		return NULL;
+	}
+	new->controlurb = usb_alloc_urb(0);
+	if (!new->controlurb) {
+		usb_free_urb (new->dataurb);
+		kfree (new);
+		return NULL;
+	}
 	new->dev = dev;
 	init_waitqueue_head (&new->pending);
 	init_waitqueue_head (&new->deathrow);
@@ -126,6 +135,8 @@
 	return new;
 
       err_out:
+	usb_free_urb (new->controlurb);
+	usb_free_urb (new->dataurb);
 	kfree (new);
 	return NULL;
 }
@@ -133,7 +144,7 @@
 static void
 hpusbscsi_usb_disconnect (struct usb_device *dev, void *ptr)
 {
-                 usb_unlink_urb(&(((struct hpusbscsi *) ptr)->controlurb));
+                 usb_unlink_urb((((struct hpusbscsi *) ptr)->controlurb));
 	((struct hpusbscsi *) ptr)->dev = NULL;
 }
 
@@ -184,8 +195,10 @@
 		old = tmp;
 		tmp = tmp->next;
 		o = (struct hpusbscsi *)old;
-		usb_unlink_urb(&o->controlurb);
+		usb_unlink_urb(o->controlurb);
 		scsi_unregister_host(&o->ctempl);
+		usb_free_urb(o->controlurb);
+		usb_free_urb(o->dataurb);
 		kfree(old);
 	}
 
@@ -222,7 +235,7 @@
 	sht->proc_dir = NULL;
 
 	/* build and submit an interrupt URB for status byte handling */
- 	FILL_INT_URB(&desc->controlurb,
+ 	FILL_INT_URB(desc->controlurb,
 			desc->dev,
 			usb_rcvintpipe(desc->dev,desc->ep_int),
 			&desc->scsi_state_byte,
@@ -232,7 +245,7 @@
 			desc->interrupt_interval
 	);
 
-	if ( 0  >  usb_submit_urb(&desc->controlurb)) {
+	if ( 0  >  usb_submit_urb(desc->controlurb)) {
 		kfree(sht->proc_name);
 		return 0;
 	}
@@ -241,7 +254,7 @@
 	desc->host = scsi_register (sht, sizeof (desc));
 	if (desc->host == NULL) {
 		kfree (sht->proc_name);
-		usb_unlink_urb(&desc->controlurb);
+		usb_unlink_urb(desc->controlurb);
 		return 0;
 	}
 	desc->host->hostdata[0] = (unsigned long) desc;
@@ -297,7 +310,7 @@
 
 	/* We prepare the urb for writing out the scsi command */
 	FILL_BULK_URB(
-		&hpusbscsi->dataurb,
+		hpusbscsi->dataurb,
 		hpusbscsi->dev,
 		usb_sndbulkpipe(hpusbscsi->dev,hpusbscsi->ep_out),
 		srb->cmnd,
@@ -308,7 +321,7 @@
 	hpusbscsi->scallback = callback;
 	hpusbscsi->srb = srb;
 
-	res = usb_submit_urb(&hpusbscsi->dataurb);
+	res = usb_submit_urb(hpusbscsi->dataurb);
 	if (unlikely(res)) {
 		hpusbscsi->state = HP_STATE_FREE;
 		TRACE_STATE;
@@ -340,8 +353,8 @@
 	struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->host->hostdata[0]);
 	printk(KERN_DEBUG"Requested is canceled.\n");
 
-	usb_unlink_urb(&hpusbscsi->dataurb);
-	usb_unlink_urb(&hpusbscsi->controlurb);
+	usb_unlink_urb(hpusbscsi->dataurb);
+	usb_unlink_urb(hpusbscsi->controlurb);
 	hpusbscsi->state = HP_STATE_FREE;
 
 	return SCSI_ABORT_PENDING;
diff -urN linux-2.5.3-pre3/drivers/usb/hpusbscsi.h linux/drivers/usb/hpusbscsi.h
--- linux-2.5.3-pre3/drivers/usb/hpusbscsi.h	Wed Nov 28 10:22:27 2001
+++ linux/drivers/usb/hpusbscsi.h	Wed Jan 23 17:31:04 2002
@@ -26,8 +26,8 @@
         wait_queue_head_t pending;
         wait_queue_head_t deathrow;
 
-        struct urb dataurb;
-        struct urb controlurb;
+        struct urb *dataurb;
+        struct urb *controlurb;
         int fragment;
 
         int state;
diff -urN linux-2.5.3-pre3/drivers/usb/inode.c linux/drivers/usb/inode.c
--- linux-2.5.3-pre3/drivers/usb/inode.c	Tue Jan  1 13:52:10 2002
+++ linux/drivers/usb/inode.c	Wed Jan 23 17:31:04 2002
@@ -678,6 +678,8 @@
 void usbfs_add_device(struct usb_device *dev)
 {
 	char name[8];
+	int i;
+	int i_size;
 
 	sprintf (name, "%03d", dev->devnum);
 	dev->dentry = fs_create_file (name,
@@ -687,6 +689,17 @@
 				      devuid, devgid);
 	if (dev->dentry == NULL)
 		return;
+
+	/* Set the size of the device's file to be
+	 * equal to the size of the device descriptors. */
+	i_size = sizeof (struct usb_device_descriptor);
+	for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
+		struct usb_config_descriptor *config =
+			(struct usb_config_descriptor *)dev->rawdescriptors[i];
+		i_size += le16_to_cpu (config->wTotalLength);
+	}
+	if (dev->dentry->d_inode)
+		dev->dentry->d_inode->i_size = i_size;
 
 	usbfs_update_special();
 	usbdevfs_conn_disc_event();
diff -urN linux-2.5.3-pre3/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- linux-2.5.3-pre3/drivers/usb/microtek.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/microtek.c	Wed Jan 23 17:31:04 2002
@@ -324,7 +324,7 @@
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
 
-	usb_unlink_urb( &desc->urb );
+	usb_unlink_urb( desc->urb );
 }
 
 static struct mts_desc * mts_list; /* list of active scanners */
@@ -365,6 +365,7 @@
 	scsi_unregister_host(&to_remove->ctempl);
 	unlock_kernel();
 
+	usb_free_urb(to_remove->urb);
 	kfree( to_remove );
 }
 
@@ -705,7 +706,7 @@
 	}
 
 	
-	FILL_BULK_URB(&desc->urb,
+	FILL_BULK_URB(desc->urb,
 		      desc->usb_dev,
 		      usb_sndbulkpipe(desc->usb_dev,desc->ep_out),
 		      srb->cmnd,
@@ -718,7 +719,7 @@
 	mts_build_transfer_context( srb, desc );
 	desc->context.final_callback = callback;
 	
-	res=usb_submit_urb(&desc->urb);
+	res=usb_submit_urb(desc->urb);
 
 	if(unlikely(res)){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
@@ -932,10 +933,12 @@
 		return NULL;
 	}
 
-	/* As done by usb_alloc_urb */
 	memset( new_desc, 0, sizeof(*new_desc) );
-	spin_lock_init(&new_desc->urb.lock);
-	
+	new_desc->urb = usb_alloc_urb(0);
+	if (!new_desc->urb) {
+		kfree(new_desc);
+		return NULL;
+	}
 		
 	/* initialising that descriptor */
 	new_desc->usb_dev = dev;
diff -urN linux-2.5.3-pre3/drivers/usb/microtek.h linux/drivers/usb/microtek.h
--- linux-2.5.3-pre3/drivers/usb/microtek.h	Fri Mar 23 11:50:01 2001
+++ linux/drivers/usb/microtek.h	Wed Jan 23 17:31:04 2002
@@ -46,7 +46,7 @@
 
 	struct semaphore lock;
 
-	struct urb urb;
+	struct urb *urb;
 	struct mts_transfer_context context;
 };
 
diff -urN linux-2.5.3-pre3/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- linux-2.5.3-pre3/drivers/usb/pegasus.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/pegasus.c	Wed Jan 23 17:31:04 2002
@@ -147,9 +147,9 @@
 	pegasus->dr.wValue = cpu_to_le16 (0);
 	pegasus->dr.wIndex = cpu_to_le16p(&indx);
 	pegasus->dr.wLength = cpu_to_le16p(&size);
-	pegasus->ctrl_urb.transfer_buffer_length = size;
+	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_rcvctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, size, ctrl_callback, pegasus );
@@ -157,7 +157,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRLs %d", ret);
 		goto out;
 	}
@@ -197,9 +197,9 @@
 	pegasus->dr.wValue = cpu_to_le16 (0);
 	pegasus->dr.wIndex = cpu_to_le16p( &indx );
 	pegasus->dr.wLength = cpu_to_le16p( &size );
-	pegasus->ctrl_urb.transfer_buffer_length = size;
+	pegasus->ctrl_urb->transfer_buffer_length = size;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, size, ctrl_callback, pegasus );
@@ -207,7 +207,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		goto out;
 	}
@@ -247,9 +247,9 @@
 	pegasus->dr.wValue = cpu_to_le16p( &dat);
 	pegasus->dr.wIndex = cpu_to_le16p( &indx );
 	pegasus->dr.wLength = cpu_to_le16( 1 );
-	pegasus->ctrl_urb.transfer_buffer_length = 1;
+	pegasus->ctrl_urb->transfer_buffer_length = 1;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  buffer, 1, ctrl_callback, pegasus );
@@ -257,7 +257,7 @@
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
 	set_current_state( TASK_UNINTERRUPTIBLE );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
 		goto out;
 	}
@@ -280,14 +280,14 @@
 	pegasus->dr.wValue = 0;
 	pegasus->dr.wIndex =  cpu_to_le16(EthCtrl0);
 	pegasus->dr.wLength = cpu_to_le16(3);
-	pegasus->ctrl_urb.transfer_buffer_length = 3;
+	pegasus->ctrl_urb->transfer_buffer_length = 3;
 
-	FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb,
+	FILL_CONTROL_URB( pegasus->ctrl_urb, pegasus->usb,
 			  usb_sndctrlpipe(pegasus->usb,0),
 			  (char *)&pegasus->dr,
 			  pegasus->eth_regs, 3, ctrl_callback, pegasus );
 
-	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) )
+	if ( (ret = usb_submit_urb( pegasus->ctrl_urb )) )
 		err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags );
 
 	return	ret;
@@ -569,11 +569,11 @@
 	pegasus->stats.rx_bytes += pkt_len;
 
 goon:
-	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
 		warn( __FUNCTION__ " failed submint rx_urb %d", res);
 	pegasus->flags &= ~PEGASUS_RX_BUSY;
 }
@@ -639,8 +639,8 @@
 		return;
 		
 	warn("%s: Tx timed out.", net->name);
-	pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
-	usb_unlink_urb( &pegasus->tx_urb );
+	pegasus->tx_urb->transfer_flags |= USB_ASYNC_UNLINK;
+	usb_unlink_urb( pegasus->tx_urb );
 	pegasus->stats.tx_errors++;
 }
 
@@ -656,12 +656,12 @@
 		
 	((__u16 *)pegasus->tx_buff)[0] = cpu_to_le16( l16 );
 	memcpy(pegasus->tx_buff+2, skb->data, skb->len);
-	FILL_BULK_URB( &pegasus->tx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->tx_urb, pegasus->usb,
 			usb_sndbulkpipe(pegasus->usb, 2),
 			pegasus->tx_buff, PEGASUS_MAX_MTU, 
 			write_bulk_callback, pegasus );
-	pegasus->tx_urb.transfer_buffer_length = count;
-	if ((res = usb_submit_urb(&pegasus->tx_urb))) {
+	pegasus->tx_urb->transfer_buffer_length = count;
+	if ((res = usb_submit_urb(pegasus->tx_urb))) {
 		warn("failed tx_urb %d", res);
 		pegasus->stats.tx_errors++;
 		netif_start_queue( net );
@@ -717,18 +717,18 @@
 		err("can't enable_net_traffic() - %d", res);
 		return -EIO;
 	}
-	FILL_BULK_URB( &pegasus->rx_urb, pegasus->usb,
+	FILL_BULK_URB( pegasus->rx_urb, pegasus->usb,
 			usb_rcvbulkpipe(pegasus->usb, 1),
 			pegasus->rx_buff, PEGASUS_MAX_MTU, 
 			read_bulk_callback, pegasus );
-	if ( (res = usb_submit_urb(&pegasus->rx_urb)) )
+	if ( (res = usb_submit_urb(pegasus->rx_urb)) )
 		warn( __FUNCTION__ " failed rx_urb %d", res );
 #ifdef	PEGASUS_USE_INTR
-	FILL_INT_URB( &pegasus->intr_urb, pegasus->usb,
+	FILL_INT_URB( pegasus->intr_urb, pegasus->usb,
 			usb_rcvintpipe(pegasus->usb, 3),
 			pegasus->intr_buff, sizeof(pegasus->intr_buff),
 			intr_callback, pegasus, pegasus->intr_interval );
-	if ( (res = usb_submit_urb(&pegasus->intr_urb)) )
+	if ( (res = usb_submit_urb(pegasus->intr_urb)) )
 		warn( __FUNCTION__ " failed intr_urb %d", res);
 #endif
 	netif_start_queue( net );
@@ -747,11 +747,11 @@
 	if ( !(pegasus->flags & PEGASUS_UNPLUG) )
 		disable_net_traffic( pegasus );
 
-	usb_unlink_urb( &pegasus->rx_urb );
-	usb_unlink_urb( &pegasus->tx_urb );
-	usb_unlink_urb( &pegasus->ctrl_urb );
+	usb_unlink_urb( pegasus->rx_urb );
+	usb_unlink_urb( pegasus->tx_urb );
+	usb_unlink_urb( pegasus->ctrl_urb );
 #ifdef	PEGASUS_USE_INTR
-	usb_unlink_urb( &pegasus->intr_urb );
+	usb_unlink_urb( pegasus->intr_urb );
 #endif
 
 	return 0;
@@ -800,7 +800,7 @@
 	}
 
 	pegasus->flags |= ETH_REGS_CHANGE;
-	ctrl_callback( &pegasus->ctrl_urb );
+	ctrl_callback( pegasus->ctrl_urb );
 
 	netif_wake_queue(net);
 }
@@ -856,6 +856,33 @@
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head( &pegasus->ctrl_wait );
 
+	pegasus->ctrl_urb = usb_alloc_urb(0);
+	if (!pegasus->ctrl_urb) {
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->rx_urb = usb_alloc_urb(0);
+	if (!pegasus->rx_urb) {
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->tx_urb = usb_alloc_urb(0);
+	if (!pegasus->tx_urb) {
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+	pegasus->intr_urb = usb_alloc_urb(0);
+	if (!pegasus->intr_urb) {
+		usb_free_urb (pegasus->tx_urb);
+		usb_free_urb (pegasus->rx_urb);
+		usb_free_urb (pegasus->ctrl_urb);
+		kfree (pegasus);
+		return NULL;
+	}
+
 	net = init_etherdev( NULL, 0 );
 	if ( !net ) {
 		kfree( pegasus );
@@ -883,6 +910,7 @@
 	if ( reset_mac(pegasus) ) {
 		err("can't reset MAC");
 		unregister_netdev( pegasus->net );
+		kfree(pegasus->net);
 		kfree(pegasus);
 		pegasus = NULL;
 		return NULL;
@@ -919,6 +947,11 @@
 	pegasus->flags |= PEGASUS_UNPLUG;
 	unregister_netdev( pegasus->net );
 	usb_dec_dev_use( dev );
+	usb_free_urb (pegasus->intr_urb);
+	usb_free_urb (pegasus->tx_urb);
+	usb_free_urb (pegasus->rx_urb);
+	usb_free_urb (pegasus->ctrl_urb);
+	kfree( pegasus->net );
 	kfree( pegasus );
 	pegasus = NULL;
 }
diff -urN linux-2.5.3-pre3/drivers/usb/pegasus.h linux/drivers/usb/pegasus.h
--- linux-2.5.3-pre3/drivers/usb/pegasus.h	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/pegasus.h	Wed Jan 23 17:31:04 2002
@@ -107,7 +107,7 @@
 	unsigned		features;
 	int			dev_index;
 	int			intr_interval;
-	struct urb		ctrl_urb, rx_urb, tx_urb, intr_urb;
+	struct urb		*ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
 	struct usb_ctrlrequest	dr;
 	wait_queue_head_t	ctrl_wait;
 	struct semaphore	ctrl_sem;
@@ -145,6 +145,7 @@
 #define	VENDOR_SMARTBRIDGES	0x08d1
 #define	VENDOR_SMC		0x0707
 #define	VENDOR_SOHOWARE		0x15e8
+#define	VENDOR_SIEMENS		0x067c
 
 
 #else	/* PEGASUS_DEV */
@@ -173,6 +174,8 @@
 		DEFAULT_GPIO_RESET | PEGASUS_II ) 	
 PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
+		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
@@ -244,6 +247,8 @@
 PEGASUS_DEV( "SMC 202 USB Ethernet", VENDOR_SMC, 0x0200,
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SOHOware NUB100 Ethernet", VENDOR_SOHOWARE, 0x9100,
+		DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_SIEMENS, 0x1001,
 		DEFAULT_GPIO_RESET )
 
 
diff -urN linux-2.5.3-pre3/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- linux-2.5.3-pre3/drivers/usb/scanner.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/scanner.c	Wed Jan 23 17:31:04 2002
@@ -972,6 +972,13 @@
 	}
 	memset (scn, 0, sizeof(struct scn_usb_data));
 
+	scn->scn_irq = usb_alloc_urb(0);
+	if (!scn->scn_irq) {
+		kfree(scn);
+		up(&scn_mutex);
+		return NULL;
+	}
+
 	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
 
 	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
@@ -979,13 +986,13 @@
 /* Ok, if we detected an interrupt EP, setup a handler for it */
 	if (have_intr) {
 		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
-		FILL_INT_URB(&scn->scn_irq, dev,
+		FILL_INT_URB(scn->scn_irq, dev,
 			     usb_rcvintpipe(dev, have_intr),
 			     &scn->button, 1, irq_scanner, scn,
 			     // endpoint[(int)have_intr].bInterval);
 			     250);
 
-	        if (usb_submit_urb(&scn->scn_irq)) {
+	        if (usb_submit_urb(scn->scn_irq)) {
 			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
                 	kfree(scn);
 			up(&scn_mutex);
@@ -1067,7 +1074,7 @@
 
 	if(scn->intr_ep) {
 		dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
-		usb_unlink_urb(&scn->scn_irq);
+		usb_unlink_urb(scn->scn_irq);
 	}
         usb_driver_release_interface(&scanner_driver,
                 &scn->scn_dev->actconfig->interface[scn->ifnum]);
@@ -1078,6 +1085,7 @@
 	dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 	devfs_unregister(scn->devfs);
 	p_scn_table[scn->scn_minor] = NULL;
+	usb_free_urb(scn->scn_irq);
 	up (&(scn->sem));
 	kfree (scn);
 	up (&scn_mutex);
diff -urN linux-2.5.3-pre3/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- linux-2.5.3-pre3/drivers/usb/scanner.h	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/scanner.h	Wed Jan 23 17:31:04 2002
@@ -241,7 +241,7 @@
 struct scn_usb_data {
 	struct usb_device *scn_dev;
 	devfs_handle_t devfs;	/* devfs device */
-	struct urb scn_irq;
+	struct urb *scn_irq;
 	unsigned int ifnum;	/* Interface number of the USB device */
 	int scn_minor;		/* Scanner minor - used in disconnect() */
 	unsigned char button;	/* Front panel buffer */
diff -urN linux-2.5.3-pre3/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- linux-2.5.3-pre3/drivers/usb/usb-uhci.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/usb-uhci.c	Wed Jan 23 17:31:04 2002
@@ -16,7 +16,7 @@
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: usb-uhci.c,v 1.268 2001/08/29 14:08:43 acher Exp $
+ * $Id: usb-uhci.c,v 1.275 2002/01/19 20:57:33 acher Exp $
  */
 
 #include <linux/config.h>
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/pm.h>
+#include <linux/timer.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -52,7 +53,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.268 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.275 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -61,7 +62,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.268"
+#define DRIVER_VERSION "v1.275"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -71,6 +72,9 @@
 #define DEBUG_SYMBOLS
 #ifdef DEBUG_SYMBOLS
 	#define _static
+	#ifndef EXPORT_SYMTAB
+		#define EXPORT_SYMTAB
+	#endif
 #else
 	#define _static static
 #endif
@@ -1182,6 +1186,7 @@
 		// cleanup the rest
 		switch (usb_pipetype (urb->pipe)) {
 
+		case PIPE_INTERRUPT:
 		case PIPE_ISOCHRONOUS:
 			uhci_wait_ms(1);
 			uhci_clean_iso_step2(s, urb_priv);
@@ -1779,17 +1784,15 @@
 		type = usb_pipetype (urb->pipe);
 
 		hcpriv = (urb_priv_t*)urb->hcpriv;
-				
-		if ( urb->timeout && 
-			((hcpriv->started + urb->timeout) < jiffies)) {
+		
+		if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
 			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
 			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
 		}
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
-		     (hcpriv->use_loop) &&
-		     ((hcpriv->started + IDLE_TIMEOUT) < jiffies))
+			 (hcpriv->use_loop) && time_after(jiffies, hcpriv->started + IDLE_TIMEOUT))
 			disable_desc_loop(s, urb);
 #endif
 
@@ -2445,7 +2448,7 @@
 			break;
 		}
 
-		if (!desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC)) {
+		if (!(desc->hw.td.status & cpu_to_le32(TD_CTRL_IOC))) {
 			// do not process one-shot TDs, no recycling
 			break;
 		}
@@ -2509,6 +2512,8 @@
 			}
 			else {
 				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				// correct toggle after unlink
+				usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
 				clr_td_ioc(desc); // inactivate TD
 			}
 		}
@@ -2738,7 +2743,7 @@
 
 	if (status != 1) {
 		// Avoid too much error messages at a time
-		if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+		if (time_after(jiffies, s->last_error_time + ERROR_SUPPRESSION_TIME)) {
 			warn("interrupt, status %x, frame# %i", status, 
 			     UHCI_GET_CURRENT_FRAME(s));
 			s->last_error_time = jiffies;
@@ -2786,7 +2791,7 @@
 				break;
 		}
 	}
-	if ((jiffies - s->timeout_check) > (HZ/30)) 
+	if (time_after(jiffies, s->timeout_check + (HZ/30)))
 		uhci_check_timeouts(s);
 
 	clean_descs(s, CLEAN_NOT_FORCED);
@@ -2815,7 +2820,7 @@
 _static void start_hc (uhci_t *s)
 {
 	unsigned int io_addr = s->io_addr;
-	int timeout = 1000;
+	int timeout = 10;
 
 	/*
 	 * Reset the HC - this will force us to get a
@@ -2830,6 +2835,7 @@
 			err("USBCMD_HCRESET timed out!");
 			break;
 		}
+		udelay(1);
 	}
 
 	/* Turn on all interrupts */
@@ -2845,7 +2851,8 @@
 	s->running = 1;
 }
 
-_static void __devexit
+/* No  __devexit, since it maybe called from alloc_uhci() */
+_static void
 uhci_pci_remove (struct pci_dev *dev)
 {
 	uhci_t *s = pci_get_drvdata(dev);
@@ -3130,4 +3137,3 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
-
diff -urN linux-2.5.3-pre3/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- linux-2.5.3-pre3/drivers/usb/usbkbd.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/usbkbd.c	Wed Jan 23 17:31:04 2002
@@ -73,7 +73,7 @@
 	struct usb_device *usbdev;
 	unsigned char new[8];
 	unsigned char old[8];
-	struct urb irq, led;
+	struct urb *irq, *led;
 	struct usb_ctrlrequest dr;
 	unsigned char leds, newleds;
 	char name[128];
@@ -121,15 +121,15 @@
 		       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
 		       (!!test_bit(LED_NUML,    dev->led));
 
-	if (kbd->led.status == -EINPROGRESS)
+	if (kbd->led->status == -EINPROGRESS)
 		return 0;
 
 	if (kbd->leds == kbd->newleds)
 		return 0;
 
 	kbd->leds = kbd->newleds;
-	kbd->led.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->led))
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led))
 		err("usb_submit_urb(leds) failed");
 
 	return 0;
@@ -146,8 +146,8 @@
 		return;
 
 	kbd->leds = kbd->newleds;
-	kbd->led.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->led))
+	kbd->led->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->led))
 		err("usb_submit_urb(leds) failed");
 }
 
@@ -158,8 +158,8 @@
 	if (kbd->open++)
 		return 0;
 
-	kbd->irq.dev = kbd->usbdev;
-	if (usb_submit_urb(&kbd->irq))
+	kbd->irq->dev = kbd->usbdev;
+	if (usb_submit_urb(kbd->irq))
 		return -EIO;
 
 	return 0;
@@ -170,7 +170,7 @@
 	struct usb_kbd *kbd = dev->private;
 
 	if (!--kbd->open)
-		usb_unlink_urb(&kbd->irq);
+		usb_unlink_urb(kbd->irq);
 }
 
 static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
@@ -201,6 +201,18 @@
 	if (!(kbd = kmalloc(sizeof(struct usb_kbd), GFP_KERNEL))) return NULL;
 	memset(kbd, 0, sizeof(struct usb_kbd));
 
+	kbd->irq = usb_alloc_urb(0);
+	if (!kbd->irq) {
+		kfree(kbd);
+		return NULL;
+	}
+	kbd->led = usb_alloc_urb(0);
+	if (!kbd->led) {
+		usb_free_urb(kbd->irq);
+		kfree(kbd);
+		return NULL;
+	}
+
 	kbd->usbdev = dev;
 
 	kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
@@ -215,7 +227,7 @@
 	kbd->dev.open = usb_kbd_open;
 	kbd->dev.close = usb_kbd_close;
 
-	FILL_INT_URB(&kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
+	FILL_INT_URB(kbd->irq, dev, pipe, kbd->new, maxp > 8 ? 8 : maxp,
 		usb_kbd_irq, kbd, endpoint->bInterval);
 
 	kbd->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
@@ -248,7 +260,7 @@
 
 	kfree(buf);
 
-	FILL_CONTROL_URB(&kbd->led, dev, usb_sndctrlpipe(dev, 0),
+	FILL_CONTROL_URB(kbd->led, dev, usb_sndctrlpipe(dev, 0),
 		(void*) &kbd->dr, &kbd->leds, 1, usb_kbd_led, kbd);
 			
 	input_register_device(&kbd->dev);
@@ -262,8 +274,10 @@
 static void usb_kbd_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_kbd *kbd = ptr;
-	usb_unlink_urb(&kbd->irq);
+	usb_unlink_urb(kbd->irq);
 	input_unregister_device(&kbd->dev);
+	usb_free_urb(kbd->irq);
+	usb_free_urb(kbd->led);
 	kfree(kbd);
 }
 
diff -urN linux-2.5.3-pre3/drivers/usb/usbmouse.c linux/drivers/usb/usbmouse.c
--- linux-2.5.3-pre3/drivers/usb/usbmouse.c	Sat Dec  8 20:28:45 2001
+++ linux/drivers/usb/usbmouse.c	Wed Jan 23 17:31:04 2002
@@ -54,7 +54,7 @@
 	char name[128];
 	struct usb_device *usbdev;
 	struct input_dev dev;
-	struct urb irq;
+	struct urb *irq;
 	int open;
 };
 
@@ -84,8 +84,8 @@
 	if (mouse->open++)
 		return 0;
 
-	mouse->irq.dev = mouse->usbdev;
-	if (usb_submit_urb(&mouse->irq))
+	mouse->irq->dev = mouse->usbdev;
+	if (usb_submit_urb(mouse->irq))
 		return -EIO;
 
 	return 0;
@@ -96,7 +96,7 @@
 	struct usb_mouse *mouse = dev->private;
 
 	if (!--mouse->open)
-		usb_unlink_urb(&mouse->irq);
+		usb_unlink_urb(mouse->irq);
 }
 
 static void *usb_mouse_probe(struct usb_device *dev, unsigned int ifnum,
@@ -126,6 +126,12 @@
 	if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL))) return NULL;
 	memset(mouse, 0, sizeof(struct usb_mouse));
 
+	mouse->irq = usb_alloc_urb(0);
+	if (!mouse->irq) {
+		kfree(mouse);
+		return NULL;
+	}
+
 	mouse->usbdev = dev;
 
 	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
@@ -162,7 +168,7 @@
 
 	kfree(buf);
 
-	FILL_INT_URB(&mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
+	FILL_INT_URB(mouse->irq, dev, pipe, mouse->data, maxp > 8 ? 8 : maxp,
 		usb_mouse_irq, mouse, endpoint->bInterval);
 
 	input_register_device(&mouse->dev);
@@ -176,8 +182,9 @@
 static void usb_mouse_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct usb_mouse *mouse = ptr;
-	usb_unlink_urb(&mouse->irq);
+	usb_unlink_urb(mouse->irq);
 	input_unregister_device(&mouse->dev);
+	usb_free_urb(mouse->irq);
 	kfree(mouse);
 }
 
diff -urN linux-2.5.3-pre3/drivers/usb/vicam.c linux/drivers/usb/vicam.c
--- linux-2.5.3-pre3/drivers/usb/vicam.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/vicam.c	Wed Jan 23 17:31:04 2002
@@ -344,7 +344,7 @@
 	synchronize(vicam);
 	mdelay(10);
 	vicam_parameters(vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 #endif
 }
 
@@ -841,9 +841,9 @@
 
 	vicam_parameters(vicam);
 
-	FILL_BULK_URB(&vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
+	FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
 		      buf, 0x1e480, vicam_bulk, vicam);
-	printk("Submiting urb: %d\n", usb_submit_urb(&vicam->readurb));
+	printk("Submiting urb: %d\n", usb_submit_urb(vicam->readurb));
 
 	return 0;
 error:
@@ -877,7 +877,13 @@
 		return NULL;
 	}
 	memset(vicam, 0, sizeof(*vicam));
-	
+
+	vicam->readurb = usb_alloc_urb(0);
+	if (!vicam->readurb) {
+		kfree(vicam);
+		return NULL;
+	}
+
 	vicam->udev = udev;
 	vicam->camera_name = camera_name;
 	vicam->win.brightness = 128;
@@ -925,6 +931,7 @@
 
 	if (!vicam->open_count) {
 		/* Other random junk */
+		usb_free_urb(vicam->readurb);
 		kfree(vicam);
 		vicam = NULL;
 	}
diff -urN linux-2.5.3-pre3/drivers/usb/vicam.h linux/drivers/usb/vicam.h
--- linux-2.5.3-pre3/drivers/usb/vicam.h	Wed Jan 23 17:31:01 2002
+++ linux/drivers/usb/vicam.h	Wed Jan 23 17:31:04 2002
@@ -75,7 +75,7 @@
 	int maxframesize;
 	struct picture_parm win;
 	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-	struct urb readurb;
+	struct urb *readurb;
 };
 
 #endif
diff -urN linux-2.5.3-pre3/drivers/usb/wacom.c linux/drivers/usb/wacom.c
--- linux-2.5.3-pre3/drivers/usb/wacom.c	Mon Sep 17 22:52:35 2001
+++ linux/drivers/usb/wacom.c	Wed Jan 23 17:31:04 2002
@@ -100,7 +100,7 @@
 	signed char data[10];
 	struct input_dev dev;
 	struct usb_device *usbdev;
-	struct urb irq;
+	struct urb *irq;
 	struct wacom_features *features;
 	int tool[2];
 	int open;
@@ -335,8 +335,8 @@
 	if (wacom->open++)
 		return 0;
 
-	wacom->irq.dev = wacom->usbdev;
-	if (usb_submit_urb(&wacom->irq))
+	wacom->irq->dev = wacom->usbdev;
+	if (usb_submit_urb(wacom->irq))
 		return -EIO;
 
 	return 0;
@@ -347,7 +347,7 @@
 	struct wacom *wacom = dev->private;
 
 	if (!--wacom->open)
-		usb_unlink_urb(&wacom->irq);
+		usb_unlink_urb(wacom->irq);
 }
 
 static void *wacom_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
@@ -358,6 +358,12 @@
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) return NULL;
 	memset(wacom, 0, sizeof(struct wacom));
 
+	wacom->irq = usb_alloc_urb(0);
+	if (!wacom->irq) {
+		kfree(wacom);
+		return NULL;
+	}
+
 	wacom->features = wacom_features + id->driver_info;
 
 	wacom->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC) | wacom->features->evbit;
@@ -397,7 +403,7 @@
 
 	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
 
-	FILL_INT_URB(&wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+	FILL_INT_URB(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
 		     wacom->data, wacom->features->pktlen, wacom->features->irq, wacom, endpoint->bInterval);
 
 	input_register_device(&wacom->dev);
@@ -411,8 +417,9 @@
 static void wacom_disconnect(struct usb_device *dev, void *ptr)
 {
 	struct wacom *wacom = ptr;
-	usb_unlink_urb(&wacom->irq);
+	usb_unlink_urb(wacom->irq);
 	input_unregister_device(&wacom->dev);
+	usb_free_urb(wacom->irq);
 	kfree(wacom);
 }
 
diff -urN linux-2.5.3-pre3/drivers/video/Config.in linux/drivers/video/Config.in
--- linux-2.5.3-pre3/drivers/video/Config.in	Wed Nov 14 15:16:31 2001
+++ linux/drivers/video/Config.in	Wed Jan 23 17:31:04 2002
@@ -143,6 +143,7 @@
 	    bool '    SIS 630/540/730 support' CONFIG_FB_SIS_300
 	    bool '    SIS 315H/315 support' CONFIG_FB_SIS_315
 	 fi
+	 tristate '  NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
       fi
@@ -268,7 +269,7 @@
 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
 	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
 	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_SIS" = "y" ]; then
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -288,7 +289,7 @@
 	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
 	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_TX3912" = "m" ]; then
+	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
@@ -304,7 +305,8 @@
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+	   "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -319,7 +321,8 @@
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
+	      "$CONFIG_FB_NEOMAGIC" = "m" ]; then
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -328,7 +331,7 @@
 	   "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
            "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
-	   "$CONFIG_FB_VOODOO1" = "y" ]; then
+	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	 define_tristate CONFIG_FBCON_CFB24 y
       else
 	 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
@@ -336,7 +339,7 @@
 	      "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
-	      "$CONFIG_FB_VOODOO1" = "m" ]; then
+	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
 	    define_tristate CONFIG_FBCON_CFB24 m
 	 fi
       fi
diff -urN linux-2.5.3-pre3/drivers/video/Makefile linux/drivers/video/Makefile
--- linux-2.5.3-pre3/drivers/video/Makefile	Thu Oct 25 13:53:52 2001
+++ linux/drivers/video/Makefile	Wed Jan 23 17:31:04 2002
@@ -49,6 +49,7 @@
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
diff -urN linux-2.5.3-pre3/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c
--- linux-2.5.3-pre3/drivers/video/S3triofb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/S3triofb.c	Wed Jan 23 17:31:04 2002
@@ -554,7 +554,7 @@
 
     strcpy(fb_info.modename, "Trio64 ");
     strncat(fb_info.modename, dp->full_name, sizeof(fb_info.modename));
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &s3trio_ops;
 #if 0
     fb_info.fbvar_num = 1;
diff -urN linux-2.5.3-pre3/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- linux-2.5.3-pre3/drivers/video/acornfb.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/video/acornfb.c	Wed Jan 23 17:31:04 2002
@@ -1318,7 +1318,7 @@
 	strcpy(fb_info.modename, "Acorn");
 	strcpy(fb_info.fontname, "Acorn8x8");
 
-	fb_info.node		   = -1;
+	fb_info.node		   = NODEV;
 	fb_info.fbops		   = &acornfb_ops;
 	fb_info.disp		   = &global_disp;
 	fb_info.changevar	   = NULL;
diff -urN linux-2.5.3-pre3/drivers/video/amifb.c linux/drivers/video/amifb.c
--- linux-2.5.3-pre3/drivers/video/amifb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/amifb.c	Wed Jan 23 17:31:04 2002
@@ -1730,7 +1730,7 @@
 
 	strcpy(fb_info.modename, amifb_name);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &amifb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &amifbcon_switch;
diff -urN linux-2.5.3-pre3/drivers/video/atafb.c linux/drivers/video/atafb.c
--- linux-2.5.3-pre3/drivers/video/atafb.c	Thu Oct 25 00:02:26 2001
+++ linux/drivers/video/atafb.c	Wed Jan 23 17:31:04 2002
@@ -2828,7 +2828,7 @@
 
 	strcpy(fb_info.modename, "Atari Builtin ");
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &atafb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &atafb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c
--- linux-2.5.3-pre3/drivers/video/aty128fb.c	Sun Nov 11 10:09:37 2001
+++ linux/drivers/video/aty128fb.c	Wed Jan 23 17:31:04 2002
@@ -1704,7 +1704,7 @@
 
     /* fill in info */
     strcpy(info->fb_info.modename, aty128fb_name);
-    info->fb_info.node  = -1;
+    info->fb_info.node  = NODEV;
     info->fb_info.fbops = &aty128fb_ops;
     info->fb_info.disp  = &info->disp;
     strcpy(info->fb_info.fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- linux-2.5.3-pre3/drivers/video/chipsfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/chipsfb.c	Wed Jan 23 17:31:04 2002
@@ -578,7 +578,7 @@
 	p->disp.scrollmode = SCROLL_YREDRAW;
 
 	strcpy(p->info.modename, p->fix.id);
-	p->info.node = -1;
+	p->info.node = NODEV;
 	p->info.fbops = &chipsfb_ops;
 	p->info.disp = &p->disp;
 	p->info.fontname[0] = 0;
diff -urN linux-2.5.3-pre3/drivers/video/clgenfb.c linux/drivers/video/clgenfb.c
--- linux-2.5.3-pre3/drivers/video/clgenfb.c	Mon Nov 19 15:19:42 2001
+++ linux/drivers/video/clgenfb.c	Wed Jan 23 17:31:04 2002
@@ -2758,7 +2758,7 @@
 		 sizeof (fb_info->gen.info.modename));
 	fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
 
-	fb_info->gen.info.node = -1;
+	fb_info->gen.info.node = NODEV;
 	fb_info->gen.info.fbops = &clgenfb_ops;
 	fb_info->gen.info.disp = &disp;
 	fb_info->gen.info.changevar = NULL;
diff -urN linux-2.5.3-pre3/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- linux-2.5.3-pre3/drivers/video/controlfb.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/video/controlfb.c	Wed Jan 23 17:31:04 2002
@@ -1376,7 +1376,7 @@
 static void __init control_init_info(struct fb_info *info, struct fb_info_control *p)
 {
 	strcpy(info->modename, "control");
-	info->node = -1;	/* ??? danj */
+	info->node = NODEV;
 	info->fbops = &controlfb_ops;
 	info->disp = &p->display;
 	strcpy(info->fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- linux-2.5.3-pre3/drivers/video/cyberfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/cyberfb.c	Wed Jan 23 17:31:04 2002
@@ -1085,7 +1085,7 @@
 
 	    strcpy(fb_info.modename, cyberfb_name);
 	    fb_info.changevar = NULL;
-	    fb_info.node = -1;
+	    fb_info.node = NODEV;
 	    fb_info.fbops = &cyberfb_ops;
 	    fb_info.disp = &disp;
 	    fb_info.switch_con = &Cyberfb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c
--- linux-2.5.3-pre3/drivers/video/dn_cfb4.c	Sun Dec 30 10:31:51 2001
+++ linux/drivers/video/dn_cfb4.c	Wed Jan 23 17:31:04 2002
@@ -305,7 +305,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;	
 
diff -urN linux-2.5.3-pre3/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- linux-2.5.3-pre3/drivers/video/dn_cfb8.c	Sun Dec 30 10:31:51 2001
+++ linux/drivers/video/dn_cfb8.c	Wed Jan 23 17:31:04 2002
@@ -292,7 +292,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	
 printk("dn_fb_init: register\n");
diff -urN linux-2.5.3-pre3/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- linux-2.5.3-pre3/drivers/video/dnfb.c	Sun Dec 30 10:31:51 2001
+++ linux/drivers/video/dnfb.c	Wed Jan 23 17:31:04 2002
@@ -307,7 +307,7 @@
 	fb_info.switch_con=&dnfbcon_switch;
 	fb_info.updatevar=&dnfbcon_updatevar;
 	fb_info.blank=&dnfbcon_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &dn_fb_ops;
 	
         dn_fb_get_var(&disp[0].var,0, &fb_info);
diff -urN linux-2.5.3-pre3/drivers/video/epson1355fb.c linux/drivers/video/epson1355fb.c
--- linux-2.5.3-pre3/drivers/video/epson1355fb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/epson1355fb.c	Wed Jan 23 17:31:04 2002
@@ -500,7 +500,7 @@
 	fb_info.gen.fbhw->detect();
 	strcpy(fb_info.gen.info.modename, "SED1355");
 	fb_info.gen.info.changevar = NULL;
-	fb_info.gen.info.node = -1;
+	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.fbops = &e1355fb_ops;
 	fb_info.gen.info.disp = &disp;
 	fb_info.gen.parsize = sizeof(struct e1355_par);
diff -urN linux-2.5.3-pre3/drivers/video/fbmem.c linux/drivers/video/fbmem.c
--- linux-2.5.3-pre3/drivers/video/fbmem.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/video/fbmem.c	Wed Jan 23 17:31:04 2002
@@ -73,6 +73,8 @@
 extern int atyfb_setup(char*);
 extern int aty128fb_init(void);
 extern int aty128fb_setup(char*);
+extern int neofb_init(void);
+extern int neofb_setup(char*);
 extern int igafb_init(void);
 extern int igafb_setup(char*);
 extern int imsttfb_init(void);
@@ -172,6 +174,9 @@
 #endif
 #ifdef CONFIG_FB_ATY128
 	{ "aty128fb", aty128fb_init, aty128fb_setup },
+#endif
+#ifdef CONFIG_FB_NEOMAGIC
+	{ "neo", neofb_init, neofb_setup },
 #endif
 #ifdef CONFIG_FB_VIRGE
 	{ "virge", virgefb_init, virgefb_setup },
diff -urN linux-2.5.3-pre3/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c
--- linux-2.5.3-pre3/drivers/video/fm2fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/fm2fb.c	Wed Jan 23 17:31:04 2002
@@ -401,7 +401,7 @@
 	disp.scrollmode = SCROLL_YREDRAW;
 
 	strcpy(fb_info.modename, fb_fix.id);
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &fm2fb_ops;
 	fb_info.disp = &disp;
 	fb_info.fontname[0] = '\0';
diff -urN linux-2.5.3-pre3/drivers/video/g364fb.c linux/drivers/video/g364fb.c
--- linux-2.5.3-pre3/drivers/video/g364fb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/g364fb.c	Wed Jan 23 17:31:04 2002
@@ -378,7 +378,7 @@
     disp.dispsw = &fbcon_g364cfb8;
 
     strcpy(fb_info.modename, fb_fix.id);
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &g364fb_ops;
     fb_info.disp = &disp;
     fb_info.fontname[0] = '\0';
diff -urN linux-2.5.3-pre3/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- linux-2.5.3-pre3/drivers/video/hgafb.c	Mon Nov 12 09:46:25 2001
+++ linux/drivers/video/hgafb.c	Wed Jan 23 17:31:04 2002
@@ -742,7 +742,7 @@
 	disp.scrollmode = SCROLL_YREDRAW;
 	
 	strcpy (fb_info.modename, hga_fix.id);
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 /*	fb_info.open = ??? */
 	fb_info.var = hga_default_var;
diff -urN linux-2.5.3-pre3/drivers/video/hitfb.c linux/drivers/video/hitfb.c
--- linux-2.5.3-pre3/drivers/video/hitfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/hitfb.c	Wed Jan 23 17:31:04 2002
@@ -344,7 +344,7 @@
 int __init hitfb_init(void)
 {
     strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &hitfb_ops;
     fb_info.gen.info.disp = &fb_info.disp;
diff -urN linux-2.5.3-pre3/drivers/video/hpfb.c linux/drivers/video/hpfb.c
--- linux-2.5.3-pre3/drivers/video/hpfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/hpfb.c	Wed Jan 23 17:31:04 2002
@@ -328,7 +328,7 @@
 	 */
 	strcpy(fb_info.modename, "Topcat");
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &hpfb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &hpfb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/igafb.c linux/drivers/video/igafb.c
--- linux-2.5.3-pre3/drivers/video/igafb.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/video/igafb.c	Wed Jan 23 17:31:04 2002
@@ -568,7 +568,7 @@
 	}
 
 	strcpy(info->fb_info.modename, igafb_name);
-	info->fb_info.node = -1;
+	info->fb_info.node = NODEV;
 	info->fb_info.fbops = &igafb_ops;
 	info->fb_info.disp = &info->disp;
 	strcpy(info->fb_info.fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- linux-2.5.3-pre3/drivers/video/imsttfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/imsttfb.c	Wed Jan 23 17:31:04 2002
@@ -1866,7 +1866,7 @@
 
 	strcpy(p->info.modename, p->fix.id);
 	strcpy(p->info.fontname, fontname);
-	p->info.node = -1;
+	p->info.node = NODEV;
 	p->info.fbops = &imsttfb_ops;
 	p->info.disp = &p->disp;
 	p->info.changevar = 0;
diff -urN linux-2.5.3-pre3/drivers/video/macfb.c linux/drivers/video/macfb.c
--- linux-2.5.3-pre3/drivers/video/macfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/macfb.c	Wed Jan 23 17:31:04 2002
@@ -1221,7 +1221,7 @@
 		}
 	
 	fb_info.changevar  = NULL;
-	fb_info.node       = -1;
+	fb_info.node       = NODEV;
 	fb_info.fbops      = &macfb_ops;
 	fb_info.disp       = &disp;
 	fb_info.switch_con = &macfb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c
--- linux-2.5.3-pre3/drivers/video/maxinefb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/maxinefb.c	Wed Jan 23 17:31:04 2002
@@ -358,7 +358,7 @@
 	strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
 	/* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &maxinefb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &maxinefb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/neofb.c linux/drivers/video/neofb.c
--- linux-2.5.3-pre3/drivers/video/neofb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/neofb.c	Wed Jan 23 17:31:04 2002
@@ -0,0 +1,2421 @@
+/*
+ * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ *
+ * Card specific code is based on XFree86's neomagic driver.
+ * Framebuffer framework code is based on code of cyber2000fb.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ *
+ * 0.3.1
+ *  - added module license (dok)
+ *
+ * 0.3
+ *  - hardware accelerated clear and move for 2200 and above (dok)
+ *  - maximum allowed dotclock is handled now (dok)
+ *
+ * 0.2.1
+ *  - correct panning after X usage (dok)
+ *  - added module and kernel parameters (dok)
+ *  - no stretching if external display is enabled (dok)
+ *
+ * 0.2
+ *  - initial version (dok)
+ *
+ *
+ * TODO
+ * - ioctl for internal/external switching
+ * - blanking
+ * - 32bit depth support, maybe impossible
+ * - disable pan-on-sync, need specs
+ *
+ * BUGS
+ * - white margin on bootup like with tdfxfb (colormap problem?)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "neofb.h"
+
+
+#define NEOFB_VERSION "0.3.1"
+
+/* --------------------------------------------------------------------- */
+
+static int disabled   = 0;
+static int internal   = 0;
+static int external   = 0;
+static int nostretch  = 0;
+static int nopciburst = 0;
+
+
+#ifdef MODULE
+
+MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
+MODULE_PARM(disabled, "i");
+MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
+MODULE_PARM(internal, "i");
+MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
+MODULE_PARM(external, "i");
+MODULE_PARM_DESC(external, "Enable output on external CRT.");
+MODULE_PARM(nostretch, "i");
+MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM(nopciburst, "i");
+MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+
+static biosMode bios8[] = {	
+    { 320, 240, 0x40 },
+    { 300, 400, 0x42 },    
+    { 640, 400, 0x20 },
+    { 640, 480, 0x21 },
+    { 800, 600, 0x23 },
+    { 1024, 768, 0x25 },
+};
+
+static biosMode bios16[] = {
+    { 320, 200, 0x2e },
+    { 320, 240, 0x41 },
+    { 300, 400, 0x43 },
+    { 640, 480, 0x31 },
+    { 800, 600, 0x34 },
+    { 1024, 768, 0x37 },
+};
+
+static biosMode bios24[] = {
+    { 640, 480, 0x32 },
+    { 800, 600, 0x35 },
+    { 1024, 768, 0x38 }
+};
+
+#ifdef NO_32BIT_SUPPORT_YET
+/* FIXME: guessed values, wrong */
+static biosMode bios32[] = {
+    { 640, 480, 0x33 },
+    { 800, 600, 0x36 },
+    { 1024, 768, 0x39 }
+    };
+#endif
+
+static int neoFindMode (int xres, int yres, int depth)
+{
+  int xres_s;
+  int i, size;
+  biosMode *mode;
+
+  switch (depth)
+    {
+    case 8:
+      size = sizeof(bios8) / sizeof(biosMode);
+      mode = bios8;
+      break;
+    case 16:
+      size = sizeof(bios16) / sizeof(biosMode);
+      mode = bios16;
+      break;
+    case 24:
+      size = sizeof(bios24) / sizeof(biosMode);
+      mode = bios24;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+      size = sizeof(bios32) / sizeof(biosMode);
+      mode = bios32;
+      break;
+#endif
+    default:
+      return 0;
+    }
+
+  for (i = 0; i < size; i++)
+    {
+      if (xres <= mode[i].x_res)
+	{
+	  xres_s = mode[i].x_res;
+	  for (; i < size; i++)
+	    {
+	      if (mode[i].x_res != xres_s)
+		return mode[i-1].mode;
+	      if (yres <= mode[i].y_res)
+		return mode[i].mode;
+	    }
+	}
+    }
+  return mode[size - 1].mode;
+}
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle (struct neofb_info *fb)
+{
+  int waitcycles;
+
+  while (fb->neo2200->bltStat & 1)
+    waitcycles++;
+}
+
+static inline void neo2200_wait_fifo (struct neofb_info *fb,
+                                      int requested_fifo_space)
+{
+  //  ndev->neo.waitfifo_calls++;
+  //  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+  /* FIXME: does not work
+  if (neo_fifo_space < requested_fifo_space)
+    {
+      neo_fifo_waitcycles++;
+
+      while (1)
+        {
+          neo_fifo_space = (neo2200->bltStat >> 8);
+          if (neo_fifo_space >= requested_fifo_space)
+            break;
+        }
+    }
+  else
+    {
+      neo_fifo_cache_hits++;
+    }
+
+  neo_fifo_space -= requested_fifo_space;
+  */
+
+  neo2200_wait_idle (fb);
+}
+
+static inline void neo2200_accel_init (struct neofb_info        *fb,
+				       struct fb_var_screeninfo *var)
+{
+  Neo2200 *neo2200 = fb->neo2200;
+  u32 bltMod, pitch;
+
+  neo2200_wait_idle (fb);
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      bltMod = NEO_MODE1_DEPTH8;
+      pitch  = var->xres_virtual;
+      break;
+    case 15:
+    case 16:
+      bltMod = NEO_MODE1_DEPTH16;
+      pitch  = var->xres_virtual * 2;
+      break;
+    default:
+      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
+      return;
+    }
+
+  neo2200->bltStat = bltMod << 16;
+  neo2200->pitch   = (pitch << 16) | pitch;
+}
+
+static void neo2200_accel_setup (struct display *p)
+{
+  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+
+  fb->dispsw->setup(p);
+
+  neo2200_accel_init (fb, var);
+}
+
+static void
+neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long src, dst;
+  int bpp, pitch, inc_y;
+  u_int fh, fw;
+
+  /* setting blitting direction does not work, so this case is unaccelerated */
+  if (sx != dx)
+    {
+      neo2200_wait_idle (fb);
+      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
+      return;
+    }
+
+  bpp    = (var->bits_per_pixel+7) / 8;
+  pitch  = var->xres_virtual * bpp;
+
+  fw     = fontwidth(p);
+  sx    *= fw * bpp;
+  dx    *= fw * bpp;
+  width *= fw;
+
+  fh     = fontheight(p);
+  sy    *= fh;
+  dy    *= fh;
+
+  if (sy > dy)
+    inc_y = fh;
+  else
+    {
+      inc_y  = -fh;
+      sy    += (height - 1) * fh;
+      dy    += (height - 1) * fh;
+    }
+
+  neo2200_wait_fifo (fb, 1);
+
+  /* set blt control */
+  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
+                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  /* looks silly, but setting the blitting direction did not work */
+  while (height--)
+    {
+      src = sx + sy * pitch;
+      dst = dx + dy * pitch;
+
+      neo2200_wait_fifo (fb, 3);
+
+      neo2200->srcStart = src;
+      neo2200->dstStart = dst;
+      neo2200->xyExt = (fh << 16) | (width & 0xffff);
+
+      sy += inc_y;
+      dy += inc_y;
+    }
+}
+
+static void
+neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
+		     int height, int width)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+  struct fb_var_screeninfo *var = &p->fb_info->var;
+  Neo2200 *neo2200 = fb->neo2200;
+  u_long dst;
+  u_int fw, fh;
+  u32 bgx = attr_bgcol_ec(p, conp);
+
+  fw = fontwidth(p);
+  fh = fontheight(p);
+
+  dst    = sx * fw + sy * var->xres_virtual * fh;
+  width  = width * fw;
+  height = height * fh;
+
+  neo2200_wait_fifo (fb, 4);
+
+  /* set blt control */
+  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
+                      NEO_BC0_SRC_IS_FG    |
+                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
+
+  switch (var->bits_per_pixel)
+    {
+    case 8:
+      neo2200->fgColor = bgx;
+      break;
+    case 16:
+      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
+      break;
+    }
+
+  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+
+  neo2200->xyExt    = (height << 16) | (width & 0xffff);
+}
+
+static void
+neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
+		    int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putc(conp, p, c, yy, xx);
+}
+
+static void
+neo2200_accel_putcs (struct vc_data *conp, struct display *p,
+		     const unsigned short *s, int count, int yy, int xx)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  neo2200_wait_idle (fb);
+  fb->dispsw->putcs(conp, p, s, count, yy, xx);
+}
+
+static void neo2200_accel_revc (struct display *p, int xx, int yy)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	
+  neo2200_wait_idle (fb);
+  fb->dispsw->revc (p, xx, yy);
+}
+
+static void
+neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
+			     int bottom_only)
+{
+  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+
+  fb->dispsw->clear_margins (conp, p, bottom_only);
+}
+
+static struct display_switch fbcon_neo2200_accel = {
+  setup:		neo2200_accel_setup,
+  bmove:		neo2200_accel_bmove,
+  clear:		neo2200_accel_clear,
+  putc:			neo2200_accel_putc,
+  putcs:		neo2200_accel_putcs,
+  revc:			neo2200_accel_revc,
+  clear_margins:	neo2200_accel_clear_margins,
+  fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
+};
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ *    Set a single color register. Return != 0 for invalid regno.
+ */
+static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  if (regno >= NR_PALETTE)
+    return -EINVAL;
+
+  info->palette[regno].red    = red;
+  info->palette[regno].green  = green;
+  info->palette[regno].blue   = blue;
+  info->palette[regno].transp = transp;
+
+  switch (fb->var.bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      outb(regno, 0x3c8);
+
+      outb(red   >> 10, 0x3c9);
+      outb(green >> 10, 0x3c9);
+      outb(blue  >> 10, 0x3c9);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      if (regno < 16)
+	((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
+	                                     ((green & 0xfc00) >>  5) |
+                                             ((blue  & 0xf800) >> 11);
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
+                                             ((green & 0xff00)     ) |
+	                                     ((blue  & 0xff00) >> 8);
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+#ifdef FBCON_HAS_CFB32
+    case 32:
+      if (regno < 16)
+	((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
+	                                     ((red    & 0xff00) <<  8) |
+                                             ((green  & 0xff00)      ) |
+	                                     ((blue   & 0xff00) >>  8);
+      break;
+#endif
+#endif
+
+    default:
+      return 1;
+    }
+
+  return 0;
+}
+
+static void vgaHWLock (void)
+{
+  /* Protect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) | 0x80);
+}
+
+static void vgaHWUnlock (void)
+{
+  /* Unprotect CRTC[0-7] */
+  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
+}
+
+static void neoLock (void)
+{
+  VGAwGR (0x09, 0x00);
+  vgaHWLock();
+}
+
+static void neoUnlock (void)
+{
+  vgaHWUnlock();
+  VGAwGR (0x09, 0x26);
+}
+
+/*
+ * vgaHWSeqReset
+ *      perform a sequencer reset.
+ */
+void
+vgaHWSeqReset(int start)
+{
+  if (start)
+    VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
+  else
+    VGAwSEQ (0x00, 0x03);		/* End Reset */
+}
+
+void
+vgaHWProtect(int on)
+{
+  unsigned char tmp;
+  
+  if (on)
+    {
+      /*
+       * Turn off screen and disable sequencer.
+       */
+      tmp = VGArSEQ (0x01);
+
+      vgaHWSeqReset (1);			/* start synchronous reset */
+      VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+
+      VGAenablePalette();
+    }
+  else
+    {
+      /*
+       * Reenable sequencer, then turn on screen.
+       */
+  
+      tmp = VGArSEQ (0x01);
+
+      VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
+      vgaHWSeqReset (0);		/* clear synchronousreset */
+
+      VGAdisablePalette();
+    }
+}
+
+static void vgaHWRestore (const struct neofb_info *info,
+			  const struct neofb_par  *par)
+{
+  int i;
+
+  VGAwMISC (par->MiscOutReg);
+
+  for (i = 1; i < 5; i++)
+    VGAwSEQ (i, par->Sequencer[i]);
+  
+  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+  VGAwCR (17, par->CRTC[17] & ~0x80);
+
+  for (i = 0; i < 25; i++)
+    VGAwCR (i, par->CRTC[i]);
+
+  for (i = 0; i < 9; i++)
+    VGAwGR (i, par->Graphics[i]);
+
+  VGAenablePalette();
+
+  for (i = 0; i < 21; i++)
+    VGAwATTR (i, par->Attribute[i]);
+
+  VGAdisablePalette();
+}
+
+static void neofb_set_par (struct neofb_info       *info,
+			   const struct neofb_par  *par)
+{
+  unsigned char temp;
+  int i;
+  int clock_hi = 0;
+    
+  DBG("neofb_set_par");
+
+  neoUnlock();
+
+  vgaHWProtect (1);		/* Blank the screen */
+
+  /* linear colormap for non palettized modes */
+  switch (par->depth)
+    {
+    case 8:
+      break;
+    case 16:
+      for (i=0; i<64; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i << 1, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i << 1, 0x3c9);
+	}
+      break;
+    case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32:
+#endif
+      for (i=0; i<256; i++)
+	{
+	  outb(i, 0x3c8);
+	  
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	  outb(i, 0x3c9);
+	}
+      break;
+    }
+    
+  /* alread unlocked above */
+  /* BOGUS  VGAwGR (0x09, 0x26);*/
+    
+  /* don't know what this is, but it's 0 from bootup anyway */
+  VGAwGR (0x15, 0x00);
+
+  /* was set to 0x01 by my bios in text and vesa modes */
+  VGAwGR (0x0A, par->GeneralLockReg);
+
+  /*
+   * The color mode needs to be set before calling vgaHWRestore
+   * to ensure the DAC is initialized properly.
+   *
+   * NOTE: Make sure we don't change bits make sure we don't change
+   * any reserved bits.
+   */
+  temp = VGArGR(0x90);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xF0; /* Save bits 7:4 */
+      temp |= (par->ExtColorModeSelect & ~0xF0);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x70; /* Save bits 6:4 */
+      temp |= (par->ExtColorModeSelect & ~0x70);
+      break;
+    }
+
+  VGAwGR(0x90,temp);
+
+  /*
+   * In some rare cases a lockup might occur if we don't delay
+   * here. (Reported by Miles Lane)
+   */
+  //mdelay(200);
+
+  /*
+   * Disable horizontal and vertical graphics and text expansions so
+   * that vgaHWRestore works properly.
+   */
+  temp = VGArGR(0x25);
+  temp &= 0x39;
+  VGAwGR (0x25, temp);
+
+  /*
+   * Sleep for 200ms to make sure that the two operations above have
+   * had time to take effect.
+   */
+  mdelay(200);
+
+  /*
+   * This function handles restoring the generic VGA registers.  */
+  vgaHWRestore (info, par);
+
+
+  VGAwGR(0x0E, par->ExtCRTDispAddr);
+  VGAwGR(0x0F, par->ExtCRTOffset);
+  temp = VGArGR(0x10);
+  temp &= 0x0F; /* Save bits 3:0 */
+  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
+  VGAwGR(0x10, temp);
+
+  VGAwGR(0x11, par->SysIfaceCntl2);
+  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
+  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
+
+  temp = VGArGR(0x20);
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      temp &= 0xFC; /* Save bits 7:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xFC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+    case FB_ACCEL_NEOMAGIC_NM2097:
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      temp &= 0xDC; /* Save bits 7:6,4:2 */
+      temp |= (par->PanelDispCntlReg1 & ~0xDC);
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+    case FB_ACCEL_NEOMAGIC_NM2230:
+    case FB_ACCEL_NEOMAGIC_NM2360:
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      temp &= 0x98; /* Save bits 7,4:3 */
+      temp |= (par->PanelDispCntlReg1 & ~0x98);
+      break;
+    }
+  VGAwGR(0x20, temp);
+
+  temp = VGArGR(0x25);
+  temp &= 0x38; /* Save bits 5:3 */
+  temp |= (par->PanelDispCntlReg2 & ~0x38);
+  VGAwGR(0x25, temp);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      temp = VGArGR(0x30);
+      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
+      temp |= (par->PanelDispCntlReg3 & ~0xEF);
+      VGAwGR(0x30, temp);
+    }
+
+  VGAwGR(0x28, par->PanelVertCenterReg1);
+  VGAwGR(0x29, par->PanelVertCenterReg2);
+  VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
+    {
+      VGAwGR(0x32, par->PanelVertCenterReg4);
+      VGAwGR(0x33, par->PanelHorizCenterReg1);
+      VGAwGR(0x34, par->PanelHorizCenterReg2);
+      VGAwGR(0x35, par->PanelHorizCenterReg3);
+    }
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
+    VGAwGR(0x36, par->PanelHorizCenterReg4);
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwGR(0x36, par->PanelHorizCenterReg4);
+      VGAwGR(0x37, par->PanelVertCenterReg5);
+      VGAwGR(0x38, par->PanelHorizCenterReg5);
+
+      clock_hi = 1;
+    }
+
+  /* Program VCLK3 if needed. */
+  if (par->ProgramVCLK
+      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+	  || (VGArGR(0x9F) !=  par->VCLK3Denominator)
+	  || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+			   != (par->VCLK3NumeratorHigh & ~0x0F)))))
+    {
+      VGAwGR(0x9B, par->VCLK3NumeratorLow);
+      if (clock_hi)
+	{
+	  temp = VGArGR(0x8F);
+	  temp &= 0x0F; /* Save bits 3:0 */
+	  temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+	  VGAwGR(0x8F, temp);
+	}
+      VGAwGR(0x9F, par->VCLK3Denominator);
+    }
+
+  if (par->biosMode)
+    VGAwCR(0x23, par->biosMode);
+    
+  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
+
+  /* Program vertical extension register */
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      VGAwCR(0x70, par->VerticalExt);
+    }
+
+
+  vgaHWProtect (0);		/* Turn on screen */
+
+  /* Calling this also locks offset registers required in update_start */
+  neoLock();
+}
+
+static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
+{
+  int oldExtCRTDispAddr;
+  int Base; 
+
+  DBG("neofb_update_start");
+
+  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+  Base *= (var->bits_per_pixel + 7) / 8;
+
+  neoUnlock();
+
+  /*
+   * These are the generic starting address registers.
+   */
+  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+  VGAwCR(0x0D, (Base & 0x00FF));
+
+  /*
+   * Make sure we don't clobber some other bits that might already
+   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+   * be needed.
+   */
+  oldExtCRTDispAddr = VGArGR(0x0E);
+  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
+
+  neoLock();
+}
+
+/*
+ * Set the Colormap
+ */
+static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
+  struct fb_cmap *dcmap = &disp->cmap;
+  int err = 0;
+
+  /* no colormap allocated? */
+  if (!dcmap->len)
+    {
+      int size;
+
+      if (fb->var.bits_per_pixel == 8)
+	size = NR_PALETTE;
+      else
+	size = 32;
+
+      err = fb_alloc_cmap (dcmap, size, 0);
+    }
+
+  /*
+   * we should be able to remove this test once fbcon has been
+   * "improved" --rmk
+   */
+  if (!err && con == info->currcon)
+    {
+      err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
+      dcmap = &fb->cmap;
+    }
+
+  if (!err)
+    fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
+
+  return err;
+}
+
+/*
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
+ */
+#define REF_FREQ 14.31818
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
+{
+  int n, d, f;
+  double f_out;
+  double f_diff;
+  int n_best = 0, d_best = 0, f_best = 0;
+  double f_best_diff = 999999.0;
+  double f_target = freq/1000.0;
+
+  for (f = 0; f <= MAX_F; f++)
+    for (n = 0; n <= MAX_N; n++)
+      for (d = 0; d <= MAX_D; d++)
+	{
+	  f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
+	  f_diff = abs(f_out-f_target);
+	  if (f_diff < f_best_diff)
+	    {
+	      f_best_diff = f_diff;
+	      n_best = n;
+	      d_best = d;
+	      f_best = f;
+	    }
+	}
+
+  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
+    {
+      /* NOT_DONE:  We are trying the full range of the 2200 clock.
+	 We should be able to try n up to 2047 */
+      par->VCLK3NumeratorLow  = n_best;
+      par->VCLK3NumeratorHigh = (f_best << 7);
+    }
+  else
+    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
+
+  par->VCLK3Denominator = d_best;
+
+#ifdef NEOFB_DEBUG
+  printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
+	  f_target,
+	  par->VCLK3NumeratorLow,
+	  par->VCLK3NumeratorHigh,
+	  par->VCLK3Denominator,
+	  f_best_diff);
+#endif
+}
+
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
+
+static int vgaHWInit (const struct fb_var_screeninfo *var,
+		      const struct neofb_info        *info,
+		      struct neofb_par               *par,
+		      struct xtimings                *timings)
+{
+  par->MiscOutReg = 0x23;
+
+  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+    par->MiscOutReg |= 0x40;
+
+  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+    par->MiscOutReg |= 0x80;
+    
+  /*
+   * Time Sequencer
+   */
+  par->Sequencer[0] = 0x00;
+  par->Sequencer[1] = 0x01;
+  par->Sequencer[2] = 0x0F;
+  par->Sequencer[3] = 0x00;                             /* Font select */
+  par->Sequencer[4] = 0x0E;                             /* Misc */
+
+  /*
+   * CRTC Controller
+   */
+  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
+  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
+  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+  par->CRTC[4]  = (timings->HSyncStart >> 3);
+  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+    | (((timings->HSyncEnd >> 3)) & 0x1F);
+  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
+  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
+    | (((timings->VDisplay - 1) & 0x100) >> 7)
+    | ((timings->VSyncStart & 0x100) >> 6)
+    | (((timings->VDisplay - 1) & 0x100) >> 5)
+    | 0x10
+    | (((timings->VTotal - 2) & 0x200)   >> 4)
+    | (((timings->VDisplay - 1) & 0x200) >> 3)
+    | ((timings->VSyncStart & 0x200) >> 2);
+  par->CRTC[8]  = 0x00;
+  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+  if (timings->dblscan)
+    par->CRTC[9] |= 0x80;
+
+  par->CRTC[10] = 0x00;
+  par->CRTC[11] = 0x00;
+  par->CRTC[12] = 0x00;
+  par->CRTC[13] = 0x00;
+  par->CRTC[14] = 0x00;
+  par->CRTC[15] = 0x00;
+  par->CRTC[16] = timings->VSyncStart & 0xFF;
+  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+  par->CRTC[19] = var->xres_virtual >> 4;
+  par->CRTC[20] = 0x00;
+  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
+  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+  par->CRTC[23] = 0xC3;
+  par->CRTC[24] = 0xFF;
+
+  /*
+   * are these unnecessary?
+   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+   */
+
+  /*
+   * Graphics Display Controller
+   */
+  par->Graphics[0] = 0x00;
+  par->Graphics[1] = 0x00;
+  par->Graphics[2] = 0x00;
+  par->Graphics[3] = 0x00;
+  par->Graphics[4] = 0x00;
+  par->Graphics[5] = 0x40;
+  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
+  par->Graphics[7] = 0x0F;
+  par->Graphics[8] = 0xFF;
+  
+
+  par->Attribute[0]  = 0x00; /* standard colormap translation */
+  par->Attribute[1]  = 0x01;
+  par->Attribute[2]  = 0x02;
+  par->Attribute[3]  = 0x03;
+  par->Attribute[4]  = 0x04;
+  par->Attribute[5]  = 0x05;
+  par->Attribute[6]  = 0x06;
+  par->Attribute[7]  = 0x07;
+  par->Attribute[8]  = 0x08;
+  par->Attribute[9]  = 0x09;
+  par->Attribute[10] = 0x0A;
+  par->Attribute[11] = 0x0B;
+  par->Attribute[12] = 0x0C;
+  par->Attribute[13] = 0x0D;
+  par->Attribute[14] = 0x0E;
+  par->Attribute[15] = 0x0F;
+  par->Attribute[16] = 0x41;
+  par->Attribute[17] = 0xFF;
+  par->Attribute[18] = 0x0F;
+  par->Attribute[19] = 0x00;
+  par->Attribute[20] = 0x00;
+
+  return 0;
+}
+
+static int neofb_decode_var (struct fb_var_screeninfo        *var,
+                             const struct neofb_info         *info,
+                             struct neofb_par                *par)
+{
+  struct xtimings timings;
+  int lcd_stretch;
+  int hoffset, voffset;
+  int memlen, vramlen;
+  int mode_ok = 0;
+  unsigned int pixclock = var->pixclock;
+
+  DBG("neofb_decode_var");
+
+  if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
+  timings.pixclock = 1000000000 / pixclock;
+  if (timings.pixclock < 1) timings.pixclock = 1;
+  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+  timings.HDisplay = var->xres;
+  timings.HSyncStart = timings.HDisplay + var->right_margin;
+  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+  timings.HTotal = timings.HSyncEnd + var->left_margin;
+  timings.VDisplay = var->yres;
+  timings.VSyncStart = timings.VDisplay + var->lower_margin;
+  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+  timings.VTotal = timings.VSyncEnd + var->upper_margin;
+  timings.sync = var->sync;
+
+  if (timings.pixclock > info->maxClock)
+    return -EINVAL;
+
+  /* Is the mode larger than the LCD panel? */
+  if ((var->xres > info->NeoPanelWidth) ||
+      (var->yres > info->NeoPanelHeight))
+    {
+      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+	      var->xres,
+	      var->yres,
+	      info->NeoPanelWidth,
+	      info->NeoPanelHeight);
+      return -EINVAL;
+    }
+
+  /* Is the mode one of the acceptable sizes? */
+  switch (var->xres)
+    {
+    case 1280:
+      if (var->yres == 1024)
+	mode_ok = 1;
+      break;
+    case 1024:
+      if (var->yres == 768)
+	mode_ok = 1;
+      break;
+    case  800:
+      if (var->yres == 600)
+	mode_ok = 1;
+      break;
+    case  640:
+      if (var->yres == 480)
+	mode_ok = 1;
+      break;
+    }
+
+  if (!mode_ok)
+    {
+      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
+	      var->xres, var->yres);
+      return -EINVAL;
+    }
+
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16:
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24:
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32:
+      break;
+# endif
+#endif
+
+    default:
+      return -EINVAL;
+    }
+
+  par->depth = var->bits_per_pixel;
+
+  vramlen = info->video.len;
+  if (vramlen > 4*1024*1024)
+    vramlen = 4*1024*1024;
+
+  if (var->yres_virtual < var->yres)
+    var->yres_virtual = var->yres;
+  if (var->xres_virtual < var->xres)
+    var->xres_virtual = var->xres;
+
+  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+  if (memlen > vramlen)
+    {
+      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
+      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+    }
+
+  /* we must round yres/xres down, we already rounded y/xres_virtual up
+     if it was possible. We should return -EINVAL, but I disagree */
+  if (var->yres_virtual < var->yres)
+    var->yres = var->yres_virtual;
+  if (var->xres_virtual < var->xres)
+    var->xres = var->xres_virtual;
+  if (var->xoffset + var->xres > var->xres_virtual)
+    var->xoffset = var->xres_virtual - var->xres;
+  if (var->yoffset + var->yres > var->yres_virtual)
+    var->yoffset = var->yres_virtual - var->yres;
+
+
+  /*
+   * This will allocate the datastructure and initialize all of the
+   * generic VGA registers.
+   */
+
+  if (vgaHWInit (var, info, par, &timings))
+    return -EINVAL;
+
+  /*
+   * The default value assigned by vgaHW.c is 0x41, but this does
+   * not work for NeoMagic.
+   */
+  par->Attribute[16] = 0x01;
+
+  switch (var->bits_per_pixel)
+    {
+    case  8:
+      par->CRTC[0x13]   = var->xres_virtual >> 3;
+      par->ExtCRTOffset = var->xres_virtual >> 11;
+      par->ExtColorModeSelect = 0x11;
+      break;
+    case 16:
+      par->CRTC[0x13]   = var->xres_virtual >> 2;
+      par->ExtCRTOffset = var->xres_virtual >> 10;
+      par->ExtColorModeSelect = 0x13;
+      break;
+    case 24:
+      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
+      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
+      par->ExtColorModeSelect = 0x14;
+      break;
+#ifdef NO_32BIT_SUPPORT_YET
+    case 32: /* FIXME: guessed values */
+      par->CRTC[0x13]   = var->xres_virtual >> 1;
+      par->ExtCRTOffset = var->xres_virtual >> 9;
+      par->ExtColorModeSelect = 0x15;
+      break;
+#endif
+    default:
+      break;
+    }
+	
+  par->ExtCRTDispAddr = 0x10;
+
+  /* Vertical Extension */
+  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
+    | (((timings.VDisplay -1) & 0x400) >> 9 )
+    | (((timings.VSyncStart) & 0x400) >> 8 )
+    | (((timings.VSyncStart) & 0x400) >> 7 );
+
+  /* Fast write bursts on unless disabled. */
+  if (info->pci_burst)
+    par->SysIfaceCntl1 = 0x30; 
+  else
+    par->SysIfaceCntl1 = 0x00; 
+
+  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
+
+  /* Enable any user specified display devices. */
+  par->PanelDispCntlReg1 = 0x00;
+  if (info->internal_display)
+    par->PanelDispCntlReg1 |= 0x02;
+  if (info->external_display)
+    par->PanelDispCntlReg1 |= 0x01;
+
+  /* If the user did not specify any display devices, then... */
+  if (par->PanelDispCntlReg1 == 0x00) {
+    /* Default to internal (i.e., LCD) only. */
+    par->PanelDispCntlReg1 |= 0x02;
+  }
+
+  /* If we are using a fixed mode, then tell the chip we are. */
+  switch (var->xres)
+    {
+    case 1280:
+      par->PanelDispCntlReg1 |= 0x60;
+      break;
+    case 1024:
+      par->PanelDispCntlReg1 |= 0x40;
+      break;
+    case 800:
+      par->PanelDispCntlReg1 |= 0x20;
+      break;
+    case 640:
+    default:
+      break;
+    }
+  
+  /* Setup shadow register locking. */
+  switch (par->PanelDispCntlReg1 & 0x03)
+    {
+    case 0x01: /* External CRT only mode: */
+      par->GeneralLockReg = 0x00;
+      /* We need to program the VCLK for external display only mode. */
+      par->ProgramVCLK = 1;
+      break;
+    case 0x02: /* Internal LCD only mode: */
+    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
+      par->GeneralLockReg = 0x01;
+      /* Don't program the VCLK when using the LCD. */
+      par->ProgramVCLK = 0;
+      break;
+    }
+
+  /*
+   * If the screen is to be stretched, turn on stretching for the
+   * various modes.
+   *
+   * OPTION_LCD_STRETCH means stretching should be turned off!
+   */
+  par->PanelDispCntlReg2 = 0x00;
+  par->PanelDispCntlReg3 = 0x00;
+
+  if (info->lcd_stretch &&
+      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
+      (var->xres != info->NeoPanelWidth))
+    {
+      switch (var->xres)
+	{
+	case  320: /* Needs testing.  KEM -- 24 May 98 */
+	case  400: /* Needs testing.  KEM -- 24 May 98 */
+	case  640:
+	case  800:
+	case 1024:
+	  lcd_stretch = 1;
+	  par->PanelDispCntlReg2 |= 0xC6;
+	  break;
+	default:
+	  lcd_stretch = 0;
+	  /* No stretching in these modes. */
+	}
+    }
+  else
+    lcd_stretch = 0;
+
+  /*
+   * If the screen is to be centerd, turn on the centering for the
+   * various modes.
+   */
+  par->PanelVertCenterReg1  = 0x00;
+  par->PanelVertCenterReg2  = 0x00;
+  par->PanelVertCenterReg3  = 0x00;
+  par->PanelVertCenterReg4  = 0x00;
+  par->PanelVertCenterReg5  = 0x00;
+  par->PanelHorizCenterReg1 = 0x00;
+  par->PanelHorizCenterReg2 = 0x00;
+  par->PanelHorizCenterReg3 = 0x00;
+  par->PanelHorizCenterReg4 = 0x00;
+  par->PanelHorizCenterReg5 = 0x00;
+
+
+  if (par->PanelDispCntlReg1 & 0x02)
+    {
+      if (var->xres == info->NeoPanelWidth)
+	{
+	  /*
+	   * No centering required when the requested display width
+	   * equals the panel width.
+	   */
+	}
+      else
+	{
+	  par->PanelDispCntlReg2 |= 0x01;
+	  par->PanelDispCntlReg3 |= 0x10;
+
+	  /* Calculate the horizontal and vertical offsets. */
+	  if (!lcd_stretch)
+	    {
+	      hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
+	      voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
+	    }
+	  else
+	    {
+	      /* Stretched modes cannot be centered. */
+	      hoffset = 0;
+	      voffset = 0;
+	    }
+
+	  switch (var->xres)
+	    {
+	    case  320: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg3 = hoffset;
+	      par->PanelVertCenterReg2  = voffset;
+	      break;
+	    case  400: /* Needs testing.  KEM -- 24 May 98 */
+	      par->PanelHorizCenterReg4 = hoffset;
+	      par->PanelVertCenterReg1  = voffset;
+	      break;
+	    case  640:
+	      par->PanelHorizCenterReg1 = hoffset;
+	      par->PanelVertCenterReg3  = voffset;
+	      break;
+	    case  800:
+	      par->PanelHorizCenterReg2 = hoffset;
+	      par->PanelVertCenterReg4  = voffset;
+	      break;
+	    case 1024:
+	      par->PanelHorizCenterReg5 = hoffset;
+	      par->PanelVertCenterReg5  = voffset;
+	      break;
+	    case 1280:
+	    default:
+	      /* No centering in these modes. */
+	      break;
+	    }
+	}
+    }
+
+  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
+    
+  /*
+   * Calculate the VCLK that most closely matches the requested dot
+   * clock.
+   */
+  neoCalcVCLK (info, par, timings.pixclock);
+
+  /* Since we program the clocks ourselves, always use VCLK3. */
+  par->MiscOutReg |= 0x0C;
+
+  return 0;
+}
+
+static int neofb_set_var (struct fb_var_screeninfo *var, int con,
+                          struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *display;
+  struct neofb_par par;
+  int err, chgvar = 0;
+
+  DBG("neofb_set_var");
+
+  err = neofb_decode_var (var, info, &par);
+  if (err)
+    return err;
+
+  if (var->activate & FB_ACTIVATE_TEST)
+    return 0;
+
+  if (con < 0)
+    {
+      display = fb->disp;
+      chgvar = 0;
+    }
+  else
+    {
+      display = fb_display + con;
+
+      if (fb->var.xres != var->xres)
+	chgvar = 1;
+      if (fb->var.yres != var->yres)
+	chgvar = 1;
+      if (fb->var.xres_virtual != var->xres_virtual)
+	chgvar = 1;
+      if (fb->var.yres_virtual != var->yres_virtual)
+	chgvar = 1;
+      if (fb->var.bits_per_pixel != var->bits_per_pixel)
+	chgvar = 1;
+    }
+
+  if (!info->neo2200)
+    var->accel_flags &= ~FB_ACCELF_TEXT;
+
+  var->red.msb_right	= 0;
+  var->green.msb_right	= 0;
+  var->blue.msb_right	= 0;
+
+  switch (var->bits_per_pixel)
+    {
+#ifdef FBCON_HAS_CFB8
+    case 8:	/* PSEUDOCOLOUR, 256 */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 0;
+      var->red.length      = 8;
+      var->green.offset	   = 0;
+      var->green.length	   = 8;
+      var->blue.offset	   = 0;
+      var->blue.length	   = 8;
+      
+      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
+      info->dispsw         = &fbcon_cfb8;
+      display->dispsw_data = NULL;
+      display->next_line   = var->xres_virtual;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB16
+    case 16: /* DIRECTCOLOUR, 64k */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 11;
+      var->red.length      = 5;
+      var->green.offset    = 5;
+      var->green.length    = 6;
+      var->blue.offset     = 0;
+      var->blue.length     = 5;
+
+      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
+      info->dispsw         = &fbcon_cfb16;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 2;
+      break;
+#endif
+
+#ifdef FBCON_HAS_CFB24
+    case 24: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 0;
+      var->transp.length   = 0;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb24;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 3;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+#endif
+
+#ifdef NO_32BIT_SUPPORT_YET
+# ifdef FBCON_HAS_CFB32
+    case 32: /* TRUECOLOUR, 16m */
+      var->transp.offset   = 24;
+      var->transp.length   = 8;
+      var->red.offset      = 16;
+      var->red.length      = 8;
+      var->green.offset    = 8;
+      var->green.length    = 8;
+      var->blue.offset     = 0;
+      var->blue.length     = 8;
+
+      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
+      info->dispsw         = &fbcon_cfb32;
+      display->dispsw_data = fb->pseudo_palette;
+      display->next_line   = var->xres_virtual * 4;
+
+      var->accel_flags    &= ~FB_ACCELF_TEXT;
+      break;
+# endif
+#endif
+
+    default:
+      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
+      info->dispsw      = &fbcon_dummy;
+      var->accel_flags &= ~FB_ACCELF_TEXT;
+      break;
+    }
+
+  if (var->accel_flags & FB_ACCELF_TEXT)
+    display->dispsw = &fbcon_neo2200_accel;
+  else
+    display->dispsw = info->dispsw;
+
+  fb->fix.line_length = display->next_line;
+
+  display->screen_base    = fb->screen_base;
+  display->line_length    = fb->fix.line_length;
+  display->visual         = fb->fix.visual;
+  display->type	          = fb->fix.type;
+  display->type_aux       = fb->fix.type_aux;
+  display->ypanstep       = fb->fix.ypanstep;
+  display->ywrapstep      = fb->fix.ywrapstep;
+  display->can_soft_blank = 1;
+  display->inverse        = 0;
+
+  fb->var = *var;
+  fb->var.activate &= ~FB_ACTIVATE_ALL;
+
+  /*
+   * Update the old var.  The fbcon drivers still use this.
+   * Once they are using cfb->fb.var, this can be dropped.
+   *					--rmk
+   */
+  display->var = fb->var;
+
+  /*
+   * If we are setting all the virtual consoles, also set the
+   * defaults used to create new consoles.
+   */
+  if (var->activate & FB_ACTIVATE_ALL)
+    fb->disp->var = fb->var;
+
+  if (chgvar && fb && fb->changevar)
+    fb->changevar (con);
+
+  if (con == info->currcon)
+    {
+      if (chgvar || con < 0)
+        neofb_set_par (info, &par);
+
+      neofb_update_start (info, var);
+      fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
+
+      if (var->accel_flags & FB_ACCELF_TEXT)
+	neo2200_accel_init (info, var);
+    }
+
+  return 0;
+}
+
+/*
+ *    Pan or Wrap the Display
+ */
+static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
+			      struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  u_int y_bottom;
+
+  y_bottom = var->yoffset;
+
+  if (!(var->vmode & FB_VMODE_YWRAP))
+    y_bottom += var->yres;
+
+  if (var->xoffset > (var->xres_virtual - var->xres))
+    return -EINVAL;
+  if (y_bottom > fb->var.yres_virtual)
+    return -EINVAL;
+
+  neofb_update_start (info, var);
+
+  fb->var.xoffset = var->xoffset;
+  fb->var.yoffset = var->yoffset;
+
+  if (var->vmode & FB_VMODE_YWRAP)
+    fb->var.vmode |= FB_VMODE_YWRAP;
+  else
+    fb->var.vmode &= ~FB_VMODE_YWRAP;
+
+  return 0;
+}
+
+
+/*
+ *    Update the `var' structure (called by fbcon.c)
+ *
+ *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
+ *    Since it's called by a kernel driver, no range checking is done.
+ */
+static int neofb_updatevar (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+
+  neofb_update_start (info, &fb_display[con].var);
+
+  return 0;
+}
+
+static int neofb_switch (int con, struct fb_info *fb)
+{
+  struct neofb_info *info = (struct neofb_info *)fb;
+  struct display *disp;
+  struct fb_cmap *cmap;
+
+  if (info->currcon >= 0)
+    {
+      disp = fb_display + info->currcon;
+
+      /*
+       * Save the old colormap and video mode.
+       */
+      disp->var = fb->var;
+      if (disp->cmap.len)
+	fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
+    }
+
+  info->currcon = con;
+  disp = fb_display + con;
+
+  /*
+   * Install the new colormap and change the video mode.  By default,
+   * fbcon sets all the colormaps and video modes to the default
+   * values at bootup.
+   *
+   * Really, we want to set the colourmap size depending on the
+   * depth of the new video mode.  For now, we leave it at its
+   * default 256 entry.
+   */
+  if (disp->cmap.len)
+    cmap = &disp->cmap;
+  else
+    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+  fb_copy_cmap(cmap, &fb->cmap, 0);
+
+  disp->var.activate = FB_ACTIVATE_NOW;
+  neofb_set_var(&disp->var, con, fb);
+
+  return 0;
+}
+
+/*
+ *    (Un)Blank the display.
+ */
+static void neofb_blank (int blank, struct fb_info *fb)
+{
+  //  struct neofb_info *info = (struct neofb_info *)fb;
+
+  /*
+   *  Blank the screen if blank_mode != 0, else unblank. If
+   *  blank == NULL then the caller blanks by setting the CLUT
+   *  (Color Look Up Table) to all black. Return 0 if blanking
+   *  succeeded, != 0 if un-/blanking failed due to e.g. a
+   *  video mode which doesn't support it. Implements VESA
+   *  suspend and powerdown modes on hardware that supports
+   *  disabling hsync/vsync:
+   *    blank_mode == 2: suspend vsync
+   *    blank_mode == 3: suspend hsync
+   *    blank_mode == 4: powerdown
+   *
+   *  wms...Enable VESA DMPS compatible powerdown mode
+   *  run "setterm -powersave powerdown" to take advantage
+   */
+     
+  switch (blank)
+    {
+    case 4:	/* powerdown - both sync lines down */
+      break;	
+    case 3:	/* hsync off */
+      break;	
+    case 2:	/* vsync off */
+      break;	
+    case 1:	/* just software blanking of screen */
+      break;
+    default: /* case 0, or anything else: unblank */
+      break;
+    }
+}
+
+/*
+ * Get the currently displayed virtual consoles colormap.
+ */
+static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
+{
+  fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
+  return 0;
+}
+
+/*
+ * Get the currently displayed virtual consoles fixed part of the display.
+ */
+static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
+{
+  *fix = fb->fix;
+  return 0;
+}
+
+/*
+ * Get the current user defined part of the display.
+ */
+static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
+{
+  *var = fb->var;
+  return 0;
+}
+
+static struct fb_ops neofb_ops = {
+  owner:          THIS_MODULE,
+  fb_set_var:     neofb_set_var,
+  fb_set_cmap:    neofb_set_cmap,
+  fb_pan_display: neofb_pan_display,
+  fb_get_fix:     gen_get_fix,
+  fb_get_var:     gen_get_var,
+  fb_get_cmap:    gen_get_cmap,
+};
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		640,
+	yres:		480,
+	xres_virtual:   640,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	39722,
+	left_margin:	48,
+	right_margin:	16,
+	upper_margin:	33,
+	lower_margin:	10,
+	hsync_len:	96,
+	vsync_len:	2,
+	sync:		0,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		800,
+	yres:		600,
+	xres_virtual:   800,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	25000,
+	left_margin:	88,
+	right_margin:	40,
+	upper_margin:	23,
+	lower_margin:	1,
+	hsync_len:	128,
+	vsync_len:	4,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1024,
+	yres:		768,
+	xres_virtual:   1024,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	15385,
+	left_margin:	160,
+	right_margin:	24,
+	upper_margin:	29,
+	lower_margin:	3,
+	hsync_len:	136,
+	vsync_len:	6,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+
+#ifdef NOT_DONE
+static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
+	accel_flags:	FB_ACCELF_TEXT,
+	xres:		1280,
+	yres:		1024,
+	xres_virtual:   1280,
+	yres_virtual:   30000,
+	bits_per_pixel: 8,
+	pixclock:	9260,
+	left_margin:	248,
+	right_margin:	48,
+	upper_margin:	38,
+	lower_margin:	1,
+	hsync_len:	112,
+	vsync_len:	3,
+	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	vmode:		FB_VMODE_NONINTERLACED
+};
+#endif
+
+static struct fb_var_screeninfo *neofb_var = NULL;
+
+
+static int __devinit neo_map_mmio (struct neofb_info *info)
+{
+  DBG("neo_map_mmio");
+
+  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
+  info->mmio.len   = MMIO_SIZE;
+
+  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
+    {
+      printk ("neofb: memory mapped IO in use\n");
+      return -EBUSY;
+    }
+
+  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
+  if (!info->mmio.vbase)
+    {
+      printk ("neofb: unable to map memory mapped IO\n");
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+
+  info->fb.fix.mmio_start = info->mmio.pbase;
+  info->fb.fix.mmio_len   = info->mmio.len;
+
+  return 0;
+}
+
+static void __devinit neo_unmap_mmio (struct neofb_info *info)
+{
+  DBG("neo_unmap_mmio");
+
+  if (info->mmio.vbase)
+    {
+      iounmap (info->mmio.vbase);
+      info->mmio.vbase = NULL;
+
+      release_mem_region (info->mmio.pbase, info->mmio.len);
+    }
+}
+
+static int __devinit neo_map_video (struct neofb_info *info, int video_len)
+{
+  DBG("neo_map_video");
+
+  info->video.pbase = pci_resource_start (info->pcidev, 0);
+  info->video.len   = video_len;
+
+  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
+    {
+      printk ("neofb: frame buffer in use\n");
+      return -EBUSY;
+    }
+
+  info->video.vbase = ioremap (info->video.pbase, info->video.len);
+  if (!info->video.vbase)
+    {
+      printk ("neofb: unable to map screen memory\n");
+      release_mem_region (info->video.pbase, info->video.len);
+      return -ENOMEM;
+    }
+  else
+    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+
+  info->fb.fix.smem_start = info->video.pbase;
+  info->fb.fix.smem_len   = info->video.len;
+  info->fb.screen_base    = info->video.vbase;
+
+#ifdef CONFIG_MTRR
+  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+#endif
+
+  /* Clear framebuffer, it's all white in memory after boot */
+  memset (info->video.vbase, 0, info->video.len);
+
+  return 0;
+}
+
+static void __devinit neo_unmap_video (struct neofb_info *info)
+{
+  DBG("neo_unmap_video");
+
+  if (info->video.vbase)
+    {
+#ifdef CONFIG_MTRR
+      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
+#endif
+
+      iounmap (info->video.vbase);
+      info->video.vbase = NULL;
+      info->fb.screen_base = NULL;
+
+      release_mem_region (info->video.pbase, info->video.len);
+    }
+}
+
+static int __devinit neo_init_hw (struct neofb_info *info)
+{
+  int videoRam = 896;
+  int maxClock = 65000;
+  int CursorMem = 1024;
+  int CursorOff = 0x100;
+  int linearSize = 1024;
+  int maxWidth = 1024;
+  int maxHeight = 1024;
+  unsigned char type, display;
+  int w;
+    
+  DBG("neo_init_hw");
+
+  neoUnlock();
+
+#if 0
+  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
+  for (w=0; w<0x85; w++)
+    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
+  for (w=0; w<0xC7; w++)
+    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
+#endif
+
+  /* Determine the panel type */
+  VGAwGR(0x09,0x26);
+  type = VGArGR(0x21);
+  display = VGArGR(0x20);
+    
+  /* Determine panel width -- used in NeoValidMode. */
+  w = VGArGR(0x20);
+  VGAwGR(0x09,0x00);
+  switch ((w & 0x18) >> 3)
+    {
+    case 0x00:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    case 0x01:
+      info->NeoPanelWidth  = 800;
+      info->NeoPanelHeight = 600;
+      neofb_var = &neofb_var800x600x8;
+      break;
+    case 0x02:
+      info->NeoPanelWidth  = 1024;
+      info->NeoPanelHeight = 768;
+      neofb_var = &neofb_var1024x768x8;
+      break;
+    case 0x03:
+      /* 1280x1024 panel support needs to be added */
+#ifdef NOT_DONE
+      info->NeoPanelWidth  = 1280;
+      info->NeoPanelHeight = 1024;
+      neofb_var = &neofb_var1280x1024x8;
+      break;
+#else
+      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+      return -1;
+#endif
+    default:
+      info->NeoPanelWidth  = 640;
+      info->NeoPanelHeight = 480;
+      neofb_var = &neofb_var640x480x8;
+      break;
+    }
+
+  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
+	  info->NeoPanelWidth,
+	  info->NeoPanelHeight,
+	  (type & 0x02) ? "color" : "monochrome",
+	  (type & 0x10) ? "TFT" : "dual scan");
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      videoRam   = 896;
+      maxClock   = 65000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 1024;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 2048;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      videoRam   = 1152;
+      maxClock   = 80000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      videoRam   = 2048;
+      maxClock   = 90000;
+      CursorMem  = 1024;
+      CursorOff  = 0x100;
+      linearSize = 2048;
+      maxWidth   = 1024;
+      maxHeight  = 1024;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      videoRam   = 2560;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      videoRam   = 3008;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      videoRam   = 4096;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 4096;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      videoRam   = 6144;
+      maxClock   = 110000;
+      CursorMem  = 1024;
+      CursorOff  = 0x1000;
+      linearSize = 8192;
+      maxWidth   = 1280;
+      maxHeight  = 1024;  /* ???? */
+
+      info->neo2200 = (Neo2200*) info->mmio.vbase;
+      break;
+    }
+
+  info->maxClock = maxClock;
+
+  return videoRam * 1024;
+}
+
+
+static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
+							const struct pci_device_id *id)
+{
+  struct neofb_info *info;
+
+  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
+		  sizeof(u32) * 16, GFP_KERNEL);
+
+  if (!info)
+    return NULL;
+
+  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
+
+  info->currcon = -1;
+  info->pcidev  = dev;
+  info->accel   = id->driver_data;
+
+  info->pci_burst   = !nopciburst;
+  info->lcd_stretch = !nostretch;
+
+  if (!internal && !external)
+    {
+      info->internal_display = 1;
+      info->external_display = 0;
+    }
+  else
+    {
+      info->internal_display = internal;
+      info->external_display = external;
+    }
+
+  switch (info->accel)
+    {
+    case FB_ACCEL_NEOMAGIC_NM2070:
+      sprintf (info->fb.fix.id, "MagicGraph 128");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2090:
+      sprintf (info->fb.fix.id, "MagicGraph 128V");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2093:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2097:
+      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2160:
+      sprintf (info->fb.fix.id, "MagicGraph 128XD");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2200:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2230:
+      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2360:
+      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
+      break;
+    case FB_ACCEL_NEOMAGIC_NM2380:
+      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
+      break;
+    }
+
+  info->fb.fix.type	   = FB_TYPE_PACKED_PIXELS;
+  info->fb.fix.type_aux	   = 0;
+  info->fb.fix.xpanstep	   = 0;
+  info->fb.fix.ypanstep	   = 4;
+  info->fb.fix.ywrapstep   = 0;
+  info->fb.fix.accel       = id->driver_data;
+
+  info->fb.var.nonstd      = 0;
+  info->fb.var.activate    = FB_ACTIVATE_NOW;
+  info->fb.var.height      = -1;
+  info->fb.var.width       = -1;
+  info->fb.var.accel_flags = 0;
+
+  strcpy (info->fb.modename, info->fb.fix.id);
+
+  info->fb.fbops          = &neofb_ops;
+  info->fb.changevar      = NULL;
+  info->fb.switch_con     = neofb_switch;
+  info->fb.updatevar      = neofb_updatevar;
+  info->fb.blank          = neofb_blank;
+  info->fb.flags          = FBINFO_FLAG_DEFAULT;
+  info->fb.disp           = (struct display *)(info + 1);
+  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
+
+  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
+
+  return info;
+}
+
+static void __devinit neo_free_fb_info (struct neofb_info *info)
+{
+  if (info)
+    {
+      /*
+       * Free the colourmap
+       */
+      fb_alloc_cmap (&info->fb.cmap, 0, 0);
+
+      kfree (info);
+    }
+}
+
+/* --------------------------------------------------------------------- */
+
+static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+{
+  struct neofb_info *info;
+  u_int h_sync, v_sync;
+  int err;
+  int video_len;
+
+  DBG("neofb_probe");
+
+  err = pci_enable_device (dev);
+  if (err)
+    return err;
+
+  err = -ENOMEM;
+  info = neo_alloc_fb_info (dev, id);
+  if (!info)
+    goto failed;
+
+  err = neo_map_mmio (info);
+  if (err)
+    goto failed;
+
+  video_len = neo_init_hw (info);
+  if (video_len < 0)
+    {
+      err = video_len;
+      goto failed;
+    }
+
+  err = neo_map_video (info, video_len);
+  if (err)
+    goto failed;
+
+  neofb_set_var (neofb_var, -1, &info->fb);
+
+  /*
+   * Calculate the hsync and vsync frequencies.  Note that
+   * we split the 1e12 constant up so that we can preserve
+   * the precision and fit the results into 32-bit registers.
+   *  (1953125000 * 512 = 1e12)
+   */
+  h_sync = 1953125000 / info->fb.var.pixclock;
+  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
+			   info->fb.var.right_margin + info->fb.var.hsync_len);
+  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
+		     info->fb.var.lower_margin + info->fb.var.vsync_len);
+
+  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	 info->fb.fix.smem_len >> 10,
+	 info->fb.var.xres, info->fb.var.yres,
+	 h_sync / 1000, h_sync % 1000, v_sync);
+
+
+  err = register_framebuffer (&info->fb);
+  if (err < 0)
+    goto failed;
+
+  printk (KERN_INFO "fb%d: %s frame buffer device\n",
+	  GET_FB_IDX(info->fb.node), info->fb.modename);
+
+  /*
+   * Our driver data
+   */
+  dev->driver_data = info;
+
+  return 0;
+
+failed:
+  neo_unmap_video (info);
+  neo_unmap_mmio (info);
+  neo_free_fb_info (info);
+
+  return err;
+}
+
+static void __devexit neofb_remove (struct pci_dev *dev)
+{
+  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
+
+  DBG("neofb_remove");
+
+  if (info)
+    {
+      /*
+       * If unregister_framebuffer fails, then
+       * we will be leaving hooks that could cause
+       * oopsen laying around.
+       */
+      if (unregister_framebuffer (&info->fb))
+	printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
+
+      neo_unmap_video (info);
+      neo_unmap_mmio (info);
+      neo_free_fb_info (info);
+
+      /*
+       * Ensure that the driver data is no longer
+       * valid.
+       */
+      dev->driver_data = NULL;
+    }
+}
+
+static struct pci_device_id neofb_devices[] __devinitdata = {
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+
+  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+
+  {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, neofb_devices);
+
+static struct pci_driver neofb_driver = {
+  name:      "neofb",
+  id_table:  neofb_devices,
+  probe:     neofb_probe,
+  remove:    neofb_remove
+};
+
+/* **************************** init-time only **************************** */
+
+static void __init neo_init (void)
+{
+  DBG("neo_init");
+  pci_register_driver (&neofb_driver);
+}
+
+/* **************************** exit-time only **************************** */
+
+static void __exit neo_done (void)
+{
+  DBG("neo_done");
+  pci_unregister_driver (&neofb_driver);
+}
+
+
+#ifndef MODULE
+
+/* ************************* init in-kernel code ************************** */
+
+int __init neofb_setup (char *options)
+{
+  char *this_opt;
+
+  DBG("neofb_setup");
+
+  if (!options || !*options)
+    return 0;
+
+  for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
+    {
+      if (!*this_opt) continue;
+
+      if (!strncmp(this_opt, "disabled", 8))
+	disabled = 1;
+      if (!strncmp(this_opt, "internal", 8))
+	internal = 1;
+      if (!strncmp(this_opt, "external", 8))
+	external = 1;
+      if (!strncmp(this_opt, "nostretch", 9))
+	nostretch = 1;
+      if (!strncmp(this_opt, "nopciburst", 10))
+	nopciburst = 1;
+    }
+
+  return 0;
+}
+
+static int __init initialized = 0;
+
+int __init neofb_init(void)
+{
+  DBG("neofb_init");
+
+  if (disabled)
+    return -ENXIO;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      neo_init();
+    }
+
+  /* never return failure, user can hotplug card later... */
+  return 0;
+}
+
+#else
+
+/* *************************** init module code **************************** */
+
+int __init init_module(void)
+{
+  DBG("init_module");
+
+  if (disabled)
+    return -ENXIO;
+
+  neo_init();
+
+  /* never return failure; user can hotplug card later... */
+  return 0;
+}
+
+#endif	/* MODULE */
+
+module_exit(neo_done);
diff -urN linux-2.5.3-pre3/drivers/video/neofb.h linux/drivers/video/neofb.h
--- linux-2.5.3-pre3/drivers/video/neofb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/neofb.h	Wed Jan 23 17:31:04 2002
@@ -0,0 +1,294 @@
+/*
+ * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+
+#ifdef NEOFB_DEBUG
+# define DBG(x)		printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+  unsigned int pixclock;
+  unsigned int HDisplay;
+  unsigned int HSyncStart;
+  unsigned int HSyncEnd;
+  unsigned int HTotal;
+  unsigned int VDisplay;
+  unsigned int VSyncStart;
+  unsigned int VSyncEnd;
+  unsigned int VTotal;
+  unsigned int sync;
+  int	       dblscan;
+  int	       interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+  __u32 bltStat;
+  __u32 bltCntl;
+  __u32 xpColor;
+  __u32 fgColor;
+  __u32 bgColor;
+  __u32 pitch;
+  __u32 clipLT;
+  __u32 clipRB;
+  __u32 srcBitOffset;
+  __u32 srcStart;
+  __u32 reserved0;
+  __u32 dstStart;
+  __u32 xyExt;
+
+  __u32 reserved1[19];
+
+  __u32 pageCntl;
+  __u32 pageBase;
+  __u32 postBase;
+  __u32 postPtr;
+  __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE	256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+
+  int depth;
+
+  unsigned char MiscOutReg;     /* Misc */
+  unsigned char CRTC[25];       /* Crtc Controller */
+  unsigned char Sequencer[5];   /* Video Sequencer */
+  unsigned char Graphics[9];    /* Video Graphics */
+  unsigned char Attribute[21];  /* Video Atribute */
+
+  unsigned char GeneralLockReg;
+  unsigned char ExtCRTDispAddr;
+  unsigned char ExtCRTOffset;
+  unsigned char SysIfaceCntl1;
+  unsigned char SysIfaceCntl2;
+  unsigned char ExtColorModeSelect;
+  unsigned char biosMode;
+
+  unsigned char PanelDispCntlReg1;
+  unsigned char PanelDispCntlReg2;
+  unsigned char PanelDispCntlReg3;
+  unsigned char PanelVertCenterReg1;
+  unsigned char PanelVertCenterReg2;
+  unsigned char PanelVertCenterReg3;
+  unsigned char PanelVertCenterReg4;
+  unsigned char PanelVertCenterReg5;
+  unsigned char PanelHorizCenterReg1;
+  unsigned char PanelHorizCenterReg2;
+  unsigned char PanelHorizCenterReg3;
+  unsigned char PanelHorizCenterReg4;
+  unsigned char PanelHorizCenterReg5;
+
+  int           ProgramVCLK;
+  unsigned char VCLK3NumeratorLow;
+  unsigned char VCLK3NumeratorHigh;
+  unsigned char VCLK3Denominator;
+  unsigned char VerticalExt;
+};
+
+struct neofb_info {
+
+  struct fb_info  fb;
+  struct display_switch	*dispsw;
+
+  struct pci_dev *pcidev;
+
+  int   currcon;
+
+  int   accel;
+  char *name;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+#ifdef CONFIG_MTRR
+    int    mtrr;
+#endif
+  } video;
+
+  struct {
+    u8    *vbase;
+    u32    pbase;
+    u32    len;
+  } mmio;
+
+  Neo2200 *neo2200;
+
+  /* Panels size */
+  int NeoPanelWidth;
+  int NeoPanelHeight;
+
+  int maxClock;
+
+  int pci_burst;
+  int lcd_stretch;
+  int internal_display;
+  int external_display;
+
+  struct {
+    u16 red, green, blue, transp;
+  } palette[NR_PALETTE];
+};
+
+
+typedef struct {
+    int x_res;
+    int y_res;
+    int mode;
+} biosMode;
+
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+  outb (index, 0x3d4);
+  outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+  outb (index, 0x3ce);
+  outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+  outb (index, 0x3c4);
+  outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x00, 0x3c0);
+  paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x20, 0x3c0);
+  paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+  u8 tmp;
+
+  if (paletteEnabled)
+    index &= ~0x20;
+  else
+    index |= 0x20;
+
+  tmp = inb (0x3da);
+  outb (index, 0x3c0);
+  outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+  outb (value, 0x3c2);
+}
+
+
+#define NEO_BS0_BLT_BUSY        0x00000001
+#define NEO_BS0_FIFO_AVAIL      0x00000002
+#define NEO_BS0_FIFO_PEND       0x00000004
+
+#define NEO_BC0_DST_Y_DEC       0x00000001
+#define NEO_BC0_X_DEC           0x00000002
+#define NEO_BC0_SRC_TRANS       0x00000004
+#define NEO_BC0_SRC_IS_FG       0x00000008
+#define NEO_BC0_SRC_Y_DEC       0x00000010
+#define NEO_BC0_FILL_PAT        0x00000020
+#define NEO_BC0_SRC_MONO        0x00000040
+#define NEO_BC0_SYS_TO_VID      0x00000080
+
+#define NEO_BC1_DEPTH8          0x00000100
+#define NEO_BC1_DEPTH16         0x00000200
+#define NEO_BC1_X_320           0x00000400
+#define NEO_BC1_X_640           0x00000800
+#define NEO_BC1_X_800           0x00000c00
+#define NEO_BC1_X_1024          0x00001000
+#define NEO_BC1_X_1152          0x00001400
+#define NEO_BC1_X_1280          0x00001800
+#define NEO_BC1_X_1600          0x00001c00
+#define NEO_BC1_DST_TRANS       0x00002000
+#define NEO_BC1_MSTR_BLT        0x00004000
+#define NEO_BC1_FILTER_Z        0x00008000
+
+#define NEO_BC2_WR_TR_DST       0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR     0x01000000
+#define NEO_BC3_DST_XY_ADDR     0x02000000
+#define NEO_BC3_CLIP_ON         0x04000000
+#define NEO_BC3_FIFO_EN         0x08000000
+#define NEO_BC3_BLT_ON_ADDR     0x10000000
+#define NEO_BC3_SKIP_MAPPING    0x80000000
+
+#define NEO_MODE1_DEPTH8        0x0100
+#define NEO_MODE1_DEPTH16       0x0200
+#define NEO_MODE1_DEPTH24       0x0300
+#define NEO_MODE1_X_320         0x0400
+#define NEO_MODE1_X_640         0x0800
+#define NEO_MODE1_X_800         0x0c00
+#define NEO_MODE1_X_1024        0x1000
+#define NEO_MODE1_X_1152        0x1400
+#define NEO_MODE1_X_1280        0x1800
+#define NEO_MODE1_X_1600        0x1c00
+#define NEO_MODE1_BLT_ON_ADDR   0x2000
diff -urN linux-2.5.3-pre3/drivers/video/offb.c linux/drivers/video/offb.c
--- linux-2.5.3-pre3/drivers/video/offb.c	Tue Oct  2 09:10:31 2001
+++ linux/drivers/video/offb.c	Wed Jan 23 17:31:04 2002
@@ -566,7 +566,7 @@
 
     strcpy(info->info.modename, "OFfb ");
     strncat(info->info.modename, full_name, sizeof(info->info.modename));
-    info->info.node = -1;
+    info->info.node = NODEV;
     info->info.fbops = &offb_ops;
     info->info.disp = disp;
     info->info.fontname[0] = '\0';
diff -urN linux-2.5.3-pre3/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- linux-2.5.3-pre3/drivers/video/platinumfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/platinumfb.c	Wed Jan 23 17:31:04 2002
@@ -591,7 +591,7 @@
 	disp = &info->disp;
 
 	strcpy(info->fb_info.modename, "platinum");
-	info->fb_info.node = -1;
+	info->fb_info.node = NODEV;
 	info->fb_info.fbops = &platinumfb_ops;
 	info->fb_info.disp = disp;
 	strcpy(info->fb_info.fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/pmag-ba-fb.c linux/drivers/video/pmag-ba-fb.c
--- linux-2.5.3-pre3/drivers/video/pmag-ba-fb.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/video/pmag-ba-fb.c	Wed Jan 23 17:31:04 2002
@@ -386,7 +386,7 @@
 	 */
 	strcpy(ip->info.modename, "PMAG-BA");
 	ip->info.changevar = NULL;
-	ip->info.node = -1;
+	ip->info.node = NODEV;
 	ip->info.fbops = &pmagbafb_ops;
 	ip->info.disp = &disp;
 	ip->info.switch_con = &pmagbafb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/pmagb-b-fb.c linux/drivers/video/pmagb-b-fb.c
--- linux-2.5.3-pre3/drivers/video/pmagb-b-fb.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/video/pmagb-b-fb.c	Wed Jan 23 17:31:04 2002
@@ -389,7 +389,7 @@
 	 */
 	strcpy(ip->info.modename, "PMAGB-BA");
 	ip->info.changevar = NULL;
-	ip->info.node = -1;
+	ip->info.node = NODEV;
 	ip->info.fbops = &pmagbbfb_ops;
 	ip->info.disp = &disp;
 	ip->info.switch_con = &pmagbbfb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/pvr2fb.c linux/drivers/video/pvr2fb.c
--- linux-2.5.3-pre3/drivers/video/pvr2fb.c	Mon Oct 15 13:36:48 2001
+++ linux/drivers/video/pvr2fb.c	Wed Jan 23 17:31:04 2002
@@ -1034,7 +1034,7 @@
 	
 	strcpy(fb_info.modename, pvr2fb_name);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &pvr2fb_ops;
 	fb_info.disp = &disp;
 	fb_info.switch_con = &pvr2fbcon_switch;
diff -urN linux-2.5.3-pre3/drivers/video/q40fb.c linux/drivers/video/q40fb.c
--- linux-2.5.3-pre3/drivers/video/q40fb.c	Sun Dec 30 10:31:51 2001
+++ linux/drivers/video/q40fb.c	Wed Jan 23 17:31:04 2002
@@ -331,7 +331,7 @@
 	fb_info.switch_con=&q40con_switch;
 	fb_info.updatevar=&q40con_updatevar;
 	fb_info.blank=&q40con_blank;	
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &q40fb_ops;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;  /* not as module for now */
 	
diff -urN linux-2.5.3-pre3/drivers/video/radeonfb.c linux/drivers/video/radeonfb.c
--- linux-2.5.3-pre3/drivers/video/radeonfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/radeonfb.c	Wed Jan 23 17:31:04 2002
@@ -1305,7 +1305,7 @@
 	info = &rinfo->info;
 
 	strcpy (info->modename, rinfo->name);
-        info->node = -1;
+        info->node = NODEV;
         info->flags = FBINFO_FLAG_DEFAULT;
         info->fbops = &radeon_fb_ops;
         info->display_fg = NULL;
diff -urN linux-2.5.3-pre3/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- linux-2.5.3-pre3/drivers/video/retz3fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/retz3fb.c	Wed Jan 23 17:31:04 2002
@@ -1422,7 +1422,7 @@
 
 		strcpy(fb_info->modename, retz3fb_name);
 		fb_info->changevar = NULL;
-		fb_info->node = -1;
+		fb_info->node = NODEV;
 		fb_info->fbops = &retz3fb_ops;
 		fb_info->disp = &zinfo->disp;
 		fb_info->switch_con = &z3fb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/sgivwfb.c linux/drivers/video/sgivwfb.c
--- linux-2.5.3-pre3/drivers/video/sgivwfb.c	Wed Jan 23 17:31:01 2002
+++ linux/drivers/video/sgivwfb.c	Wed Jan 23 17:31:04 2002
@@ -890,7 +890,7 @@
 
   strcpy(fb_info.modename, sgivwfb_name);
   fb_info.changevar = NULL;
-  fb_info.node = -1;
+  fb_info.node = NODEV;
   fb_info.fbops = &sgivwfb_ops;
   fb_info.disp = &disp;
   fb_info.switch_con = &sgivwfbcon_switch;
diff -urN linux-2.5.3-pre3/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- linux-2.5.3-pre3/drivers/video/skeletonfb.c	Thu Sep 13 16:04:43 2001
+++ linux/drivers/video/skeletonfb.c	Wed Jan 23 17:31:04 2002
@@ -306,7 +306,7 @@
     fb_info.gen.fbhw->detect();
     strcpy(fb_info.gen.info.modename, "XXX");
     fb_info.gen.info.changevar = NULL;
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.fbops = &xxxfb_ops;
     fb_info.gen.info.disp = &disp;
     fb_info.gen.info.switch_con = &xxxfb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/sstfb.c linux/drivers/video/sstfb.c
--- linux-2.5.3-pre3/drivers/video/sstfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/sstfb.c	Wed Jan 23 17:31:04 2002
@@ -1797,7 +1797,7 @@
 		f_ddprintk("membase_phys: %#lx\n", fb_info.video.base);
 		f_ddprintk("fbbase_virt: %#lx\n", fb_info.video.vbase);
 
-		fb_info.info.node       = -1 ;
+		fb_info.info.node       = NODEV;
 		fb_info.info.flags      = FBINFO_FLAG_DEFAULT;
 		fb_info.info.fbops      = &sstfb_ops;
 		fb_info.info.disp       = &disp;
diff -urN linux-2.5.3-pre3/drivers/video/stifb.c linux/drivers/video/stifb.c
--- linux-2.5.3-pre3/drivers/video/stifb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/stifb.c	Wed Jan 23 17:31:04 2002
@@ -166,7 +166,7 @@
 	if ((fb_info.sti = sti_init_roms()) == NULL)
 		return -ENXIO;
 
-	fb_info.gen.info.node = -1;
+	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
 	fb_info.gen.info.fbops = &stifb_ops;
 	fb_info.gen.info.disp = &disp;
diff -urN linux-2.5.3-pre3/drivers/video/sun3fb.c linux/drivers/video/sun3fb.c
--- linux-2.5.3-pre3/drivers/video/sun3fb.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/video/sun3fb.c	Wed Jan 23 17:31:04 2002
@@ -573,7 +573,7 @@
 	fix->type = FB_TYPE_PACKED_PIXELS;
 	fix->visual = FB_VISUAL_PSEUDOCOLOR;
 	
-	fb->info.node = -1;
+	fb->info.node = NODEV;
 	fb->info.fbops = &sun3fb_ops;
 	fb->info.disp = disp;
 	strcpy(fb->info.fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/tdfxfb.c linux/drivers/video/tdfxfb.c
--- linux-2.5.3-pre3/drivers/video/tdfxfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/tdfxfb.c	Wed Jan 23 17:31:04 2002
@@ -1975,7 +1975,7 @@
 	strcpy(fb_info.fb_info.modename, "3Dfx "); 
 	strcat(fb_info.fb_info.modename, name);
 	fb_info.fb_info.changevar  = NULL;
-	fb_info.fb_info.node       = -1;
+	fb_info.fb_info.node       = NODEV;
 	fb_info.fb_info.fbops      = &tdfxfb_ops;
 	fb_info.fb_info.disp       = &fb_info.disp;
 	strcpy(fb_info.fb_info.fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- linux-2.5.3-pre3/drivers/video/tgafb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/tgafb.c	Wed Jan 23 17:31:04 2002
@@ -937,7 +937,7 @@
 
     /* setup framebuffer */
 
-    fb_info.gen.info.node = -1;
+    fb_info.gen.info.node = NODEV;
     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     fb_info.gen.info.fbops = &tgafb_ops;
     fb_info.gen.info.disp = &disp;
diff -urN linux-2.5.3-pre3/drivers/video/tx3912fb.c linux/drivers/video/tx3912fb.c
--- linux-2.5.3-pre3/drivers/video/tx3912fb.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/video/tx3912fb.c	Wed Jan 23 17:31:04 2002
@@ -397,7 +397,7 @@
 
 	strcpy(fb_info.modename, TX3912FB_NAME);
 	fb_info.changevar = NULL;
-	fb_info.node = -1;
+	fb_info.node = NODEV;
 	fb_info.fbops = &tx3912fb_ops;
 	fb_info.disp = &global_disp;
 	fb_info.switch_con = &tx3912fbcon_switch;
diff -urN linux-2.5.3-pre3/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- linux-2.5.3-pre3/drivers/video/valkyriefb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/valkyriefb.c	Wed Jan 23 17:31:04 2002
@@ -779,7 +779,7 @@
 static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
 {
 	strcpy(info->modename, p->fix.id);
-	info->node = -1;	/* ??? danj */
+	info->node = NODEV;
 	info->fbops = &valkyriefb_ops;
 	info->disp = &p->disp;
 	strcpy(info->fontname, fontname);
diff -urN linux-2.5.3-pre3/drivers/video/vfb.c linux/drivers/video/vfb.c
--- linux-2.5.3-pre3/drivers/video/vfb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/vfb.c	Wed Jan 23 17:31:04 2002
@@ -404,7 +404,7 @@
 
     strcpy(fb_info.modename, vfb_name);
     fb_info.changevar = NULL;
-    fb_info.node = -1;
+    fb_info.node = NODEV;
     fb_info.fbops = &vfb_ops;
     fb_info.disp = &disp;
     fb_info.switch_con = &vfbcon_switch;
diff -urN linux-2.5.3-pre3/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- linux-2.5.3-pre3/drivers/video/vga16fb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/vga16fb.c	Wed Jan 23 17:31:04 2002
@@ -926,7 +926,7 @@
 	/* name should not depend on EGA/VGA */
 	strcpy(vga16fb.fb_info.modename, "VGA16 VGA");
 	vga16fb.fb_info.changevar = NULL;
-	vga16fb.fb_info.node = -1;
+	vga16fb.fb_info.node = NODEV;
 	vga16fb.fb_info.fbops = &vga16fb_ops;
 	vga16fb.fb_info.disp=&disp;
 	vga16fb.fb_info.switch_con=&vga16fb_switch;
diff -urN linux-2.5.3-pre3/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- linux-2.5.3-pre3/drivers/video/virgefb.c	Wed Nov 14 14:52:20 2001
+++ linux/drivers/video/virgefb.c	Wed Jan 23 17:31:04 2002
@@ -1168,7 +1168,7 @@
 
 	    strcpy(fb_info.modename, virgefb_name);
 	    fb_info.changevar = NULL;
-	    fb_info.node = -1;
+	    fb_info.node = NODEV;
 	    fb_info.fbops = &virgefb_ops;
 	    fb_info.disp = &disp;
 	    fb_info.switch_con = &Cyberfb_switch;
diff -urN linux-2.5.3-pre3/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- linux-2.5.3-pre3/drivers/zorro/zorro.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/zorro/zorro.c	Wed Jan 23 17:31:04 2002
@@ -170,6 +170,7 @@
 			m68k_memory[i].addr+m68k_memory[i].size, 0);
 }
 
+subsys_initcall(zorro_init);
 
 EXPORT_SYMBOL(zorro_find_device);
 EXPORT_SYMBOL(zorro_unused_z2ram);
diff -urN linux-2.5.3-pre3/fs/Config.in linux/fs/Config.in
--- linux-2.5.3-pre3/fs/Config.in	Tue Dec 25 15:39:20 2001
+++ linux/fs/Config.in	Wed Jan 23 17:31:04 2002
@@ -31,7 +31,10 @@
 # msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
 dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+#dep_tristate '    UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+# UMSDOS is temprory broken
+define_bool CONFIG_UMSDOS_FS n
+
 dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL
 dep_tristate 'Journalling Flash File System (JFFS) support' CONFIG_JFFS_FS $CONFIG_MTD
diff -urN linux-2.5.3-pre3/fs/coda/inode.c linux/fs/coda/inode.c
--- linux-2.5.3-pre3/fs/coda/inode.c	Wed Jan 23 17:31:01 2002
+++ linux/fs/coda/inode.c	Wed Jan 23 17:31:04 2002
@@ -45,6 +45,8 @@
 {
 	struct coda_inode_info *ei;
 	ei = (struct coda_inode_info *)kmem_cache_alloc(coda_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
 	memset(&ei->c_fid, 0, sizeof(struct ViceFid));
 	ei->c_flags = 0;
 	INIT_LIST_HEAD(&ei->c_cilist);
@@ -52,8 +54,6 @@
 	ei->c_contcount = 0;
 	memset(&ei->c_cached_cred, 0, sizeof(struct coda_cred));
 	ei->c_cached_perm = 0;
-	if (!ei)
-		return NULL;
 	return &ei->vfs_inode;
 }
 
diff -urN linux-2.5.3-pre3/fs/driverfs/inode.c linux/fs/driverfs/inode.c
--- linux-2.5.3-pre3/fs/driverfs/inode.c	Mon Jan 14 11:08:35 2002
+++ linux/fs/driverfs/inode.c	Wed Jan 23 17:31:04 2002
@@ -31,7 +31,7 @@
 #include <linux/dcache.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/driverfs_fs.h>
+#include <linux/device.h>
 
 #include <asm/uaccess.h>
 
@@ -232,6 +232,7 @@
 	struct driver_file_entry * entry;
 	unsigned char *page;
 	ssize_t retval = 0;
+	struct device * dev;
 
 	entry = (struct driver_file_entry *)file->private_data;
 	if (!entry) {
@@ -239,10 +240,13 @@
 		return -ENOENT;
 	}
 
-	if (!entry->ops || !entry->ops->read) {
-		DBG("%s: no read callback\n",__FUNCTION__);
-		return -ENOENT;
-	}
+	dev = list_entry(entry->parent,struct device, dir);
+
+	if (!valid_device(dev))
+		return -EFAULT;
+
+	if (!entry->show)
+		goto done;
 
 	page = (unsigned char*)__get_free_page(GFP_KERNEL);
 	if (!page) {
@@ -253,7 +257,7 @@
 	while (count > 0) {
 		ssize_t len;
 
-		len = entry->ops->read(page,count,*ppos,entry->data);
+		len = entry->show(dev,page,count,*ppos);
 
 		if (len <= 0) {
 			if (len < 0)
@@ -274,6 +278,7 @@
 	free_page((unsigned long)page);
 
  done:
+	put_device(dev);
 	return retval;
 }
 
@@ -294,6 +299,7 @@
 driverfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
 	struct driver_file_entry * entry;
+	struct device * dev;
 	ssize_t retval = 0;
 
 	entry = (struct driver_file_entry *)file->private_data;
@@ -302,16 +308,18 @@
 		return -ENOENT;
 	}
 
-	if (!entry->ops || !entry->ops->write) {
-		DBG("%s: no write callback\n",__FUNCTION__);
-		retval = -ENOENT;
+	dev = list_entry(entry->parent,struct device, dir);
+
+	if (!valid_device(dev))
+		return -EFAULT;
+
+	if (!entry->store)
 		goto done;
-	}
 
 	while (count > 0) {
 		ssize_t len;
 
-		len = entry->ops->write(buf,count,*ppos,entry->data);
+		len = entry->store(dev,buf,count,*ppos);
 
 		if (len <= 0) {
 			if (len < 0)
@@ -323,8 +331,8 @@
 		*ppos += len;
 		buf += len;
 	}
-
  done:
+	put_device(dev);
 	return retval;
 }
 
@@ -378,18 +386,6 @@
 	return 0;
 }
 
-/* Similar to above - if this dentry goes away, free the
- * driver_dir_entry associated with it..
- */
-static int driverfs_d_delete_dir (struct dentry * dentry)
-{
-	struct driver_dir_entry * entry;
-	entry = (struct driver_dir_entry *)dentry->d_fsdata;
-	if (entry)
-		kfree(entry);
-	return 0;
-}
-
 static struct address_space_operations driverfs_aops = {
 
 };
@@ -425,10 +421,6 @@
 	d_delete:	driverfs_d_delete_file,
 };
 
-static struct dentry_operations driverfs_dentry_dir_ops = {
-	d_delete:	driverfs_d_delete_dir,
-};
-
 static struct super_operations driverfs_ops = {
 	statfs:		driverfs_statfs,
 	put_inode:	force_delete,
@@ -546,33 +538,6 @@
 MODULE_LICENSE("GPL");
 
 /**
- * driverfs_create_dir_entry - allocate and initialise directory entry
- * @name:	name of the directory
- * @mode:	permissions of the dir
- */
-struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode)
-{
-	struct driver_dir_entry * entry;
-	int size = sizeof(struct driver_dir_entry) + strlen(name) + 1;
-
-
-	entry = kmalloc(size, GFP_KERNEL);
-	if (!entry)
-		return NULL;
-
-	memset(entry, 0, size);
-	strcpy((char *)entry + sizeof(struct driver_dir_entry), name);
-
-	entry->name = (char *)entry + sizeof(struct driver_dir_entry);
-
-	INIT_LIST_HEAD(&entry->files);
-	entry->mode = mode;
-
-	return entry;
-}
-
-/**
  * driverfs_create_dir - create a directory in the filesystem
  * @entry:	directory entry
  * @parent:	parent directory entry
@@ -672,6 +637,7 @@
 		dentry->d_inode->u.generic_ip = (void *)entry;
 
 		entry->dentry = dentry;
+		entry->parent = parent;
 
 		list_add_tail(&entry->node,&parent->files);
 	}
@@ -784,39 +750,3 @@
  done:
 	put_mount();
 }
-
-/**
- * driverfs_create_entry - allocate and initialise a struct driver_file_entry
- * @name:	name of the file
- * @mode:	permissions of the file
- * @ops:	Operations for the file
- * @data:	data that will be passed back to the callback
- *
- */
-struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data)
-{
-	struct driver_file_entry * entry;
-	int size;
-
-	size = sizeof(struct driver_file_entry) + strlen(name) + 1;
-
-	entry = kmalloc(size,GFP_KERNEL);
-	if (!entry)
-		return NULL;
-
-	memset(entry, 0, size);
-	strcpy((char *)entry + sizeof(struct driver_file_entry), name);
-
-	entry->name = (char *)entry + sizeof(struct driver_file_entry);
-
-	INIT_LIST_HEAD(&entry->node);
-
-	entry->mode = mode;
-	entry->ops = ops;
-	entry->data = data;
-
-	return entry;
-}
-
diff -urN linux-2.5.3-pre3/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- linux-2.5.3-pre3/fs/minix/bitmap.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/minix/bitmap.c	Wed Jan 23 17:31:04 2002
@@ -261,6 +261,7 @@
 	inode->i_ino = j;
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = inode->i_blksize = 0;
+	memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
diff -urN linux-2.5.3-pre3/fs/minix/inode.c linux/fs/minix/inode.c
--- linux-2.5.3-pre3/fs/minix/inode.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/minix/inode.c	Wed Jan 23 17:31:04 2002
@@ -75,7 +75,51 @@
 	return;
 }
 
+static kmem_cache_t * minix_inode_cachep;
+
+static struct inode *minix_alloc_inode(struct super_block *sb)
+{
+	struct minix_inode_info *ei;
+	ei = (struct minix_inode_info *)kmem_cache_alloc(minix_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void minix_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(minix_inode_cachep, minix_i(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct minix_inode_info *ei = (struct minix_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	minix_inode_cachep = kmem_cache_create("minix_inode_cache",
+					     sizeof(struct minix_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (minix_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(minix_inode_cachep))
+		printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations minix_sops = {
+	alloc_inode:	minix_alloc_inode,
+	destroy_inode:	minix_destroy_inode,
 	read_inode:	minix_read_inode,
 	write_inode:	minix_write_inode,
 	delete_inode:	minix_delete_inode,
@@ -344,6 +388,7 @@
 {
 	struct buffer_head * bh;
 	struct minix_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -359,7 +404,7 @@
 	inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
 	inode->i_blocks = inode->i_blksize = 0;
 	for (i = 0; i < 9; i++)
-		inode->u.minix_i.u.i1_data[i] = raw_inode->i_zone[i];
+		minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
 	minix_set_inode(inode, raw_inode->i_zone[0]);
 	brelse(bh);
 }
@@ -371,6 +416,7 @@
 {
 	struct buffer_head * bh;
 	struct minix2_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -388,7 +434,7 @@
 	inode->i_ctime = raw_inode->i_ctime;
 	inode->i_blocks = inode->i_blksize = 0;
 	for (i = 0; i < 10; i++)
-		inode->u.minix_i.u.i2_data[i] = raw_inode->i_zone[i];
+		minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
 	minix_set_inode(inode, raw_inode->i_zone[0]);
 	brelse(bh);
 }
@@ -411,6 +457,7 @@
 {
 	struct buffer_head * bh;
 	struct minix_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -425,7 +472,7 @@
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (i = 0; i < 9; i++)
-		raw_inode->i_zone[i] = inode->u.minix_i.u.i1_data[i];
+		raw_inode->i_zone[i] = minix_inode->u.i1_data[i];
 	mark_buffer_dirty(bh);
 	return bh;
 }
@@ -437,6 +484,7 @@
 {
 	struct buffer_head * bh;
 	struct minix2_inode * raw_inode;
+	struct minix_inode_info *minix_inode = minix_i(inode);
 	int i;
 
 	raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
@@ -453,7 +501,7 @@
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
 	else for (i = 0; i < 10; i++)
-		raw_inode->i_zone[i] = inode->u.minix_i.u.i2_data[i];
+		raw_inode->i_zone[i] = minix_inode->u.i2_data[i];
 	mark_buffer_dirty(bh);
 	return bh;
 }
@@ -514,12 +562,23 @@
 
 static int __init init_minix_fs(void)
 {
-        return register_filesystem(&minix_fs_type);
+	int err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&minix_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_minix_fs(void)
 {
         unregister_filesystem(&minix_fs_type);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.5.3-pre3/fs/minix/itree_v1.c linux/fs/minix/itree_v1.c
--- linux-2.5.3-pre3/fs/minix/itree_v1.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/itree_v1.c	Wed Jan 23 17:31:04 2002
@@ -19,7 +19,7 @@
 
 static inline block_t *i_data(struct inode *inode)
 {
-	return (block_t *)inode->u.minix_i.u.i1_data;
+	return (block_t *)minix_i(inode)->u.i1_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
diff -urN linux-2.5.3-pre3/fs/minix/itree_v2.c linux/fs/minix/itree_v2.c
--- linux-2.5.3-pre3/fs/minix/itree_v2.c	Fri Sep  7 09:45:51 2001
+++ linux/fs/minix/itree_v2.c	Wed Jan 23 17:31:04 2002
@@ -19,7 +19,7 @@
 
 static inline block_t *i_data(struct inode *inode)
 {
-	return (block_t *)inode->u.minix_i.u.i2_data;
+	return (block_t *)minix_i(inode)->u.i2_data;
 }
 
 static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
diff -urN linux-2.5.3-pre3/fs/namespace.c linux/fs/namespace.c
--- linux-2.5.3-pre3/fs/namespace.c	Sun Dec 30 16:59:04 2001
+++ linux/fs/namespace.c	Wed Jan 23 17:31:04 2002
@@ -38,7 +38,7 @@
 	return tmp & hash_mask;
 }
 
-struct vfsmount *alloc_vfsmnt(void)
+struct vfsmount *alloc_vfsmnt(char *name)
 {
 	struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); 
 	if (mnt) {
@@ -48,6 +48,14 @@
 		INIT_LIST_HEAD(&mnt->mnt_child);
 		INIT_LIST_HEAD(&mnt->mnt_mounts);
 		INIT_LIST_HEAD(&mnt->mnt_list);
+		if (name) {
+			int size = strlen(name)+1;
+			char * newname = kmalloc(size, GFP_KERNEL);
+			if (newname) {
+				memcpy(newname, name, size);
+				mnt->mnt_devname = newname;
+			}
+		}
 	}
 	return mnt;
 }
@@ -59,18 +67,6 @@
 	kmem_cache_free(mnt_cache, mnt);
 }
 
-void set_devname(struct vfsmount *mnt, const char *name)
-{
-	if (name) {
-		int size = strlen(name)+1;
-		char * newname = kmalloc(size, GFP_KERNEL);
-		if (newname) {
-			memcpy(newname, name, size);
-			mnt->mnt_devname = newname;
-		}
-	}
-}
-
 struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
 {
 	struct list_head * head = mount_hashtable + hash(mnt, dentry);
@@ -138,11 +134,10 @@
 clone_mnt(struct vfsmount *old, struct dentry *root)
 {
 	struct super_block *sb = old->mnt_sb;
-	struct vfsmount *mnt = alloc_vfsmnt();
+	struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
 
 	if (mnt) {
 		mnt->mnt_flags = old->mnt_flags;
-		set_devname(mnt, old->mnt_devname);
 		atomic_inc(&sb->s_active);
 		mnt->mnt_sb = sb;
 		mnt->mnt_root = dget(root);
diff -urN linux-2.5.3-pre3/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- linux-2.5.3-pre3/fs/ncpfs/inode.c	Thu Jan  3 12:20:18 2002
+++ linux/fs/ncpfs/inode.c	Wed Jan 23 17:31:04 2002
@@ -36,8 +36,54 @@
 static void ncp_put_super(struct super_block *);
 static int  ncp_statfs(struct super_block *, struct statfs *);
 
+static kmem_cache_t * ncp_inode_cachep;
+
+static struct inode *ncp_alloc_inode(struct super_block *sb)
+{
+	struct ncp_inode_info *ei;
+	ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void ncp_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		init_MUTEX(&ei->open_sem);
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
+					     sizeof(struct ncp_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (ncp_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(ncp_inode_cachep))
+		printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
+}
+
 static struct super_operations ncp_sops =
 {
+	alloc_inode:	ncp_alloc_inode,
+	destroy_inode:	ncp_destroy_inode,
 	put_inode:	force_delete,
 	delete_inode:	ncp_delete_inode,
 	put_super:	ncp_put_super,
@@ -61,6 +107,8 @@
 
 #ifdef CONFIG_NCPFS_STRONG
 	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
+#else
+	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
 #endif
 	NCP_FINFO(inode)->access = nwinfo->access;
 	NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
@@ -216,7 +264,6 @@
 
 	inode = new_inode(sb);
 	if (inode) {
-		init_MUTEX(&NCP_FINFO(inode)->open_sem);
 		atomic_set(&NCP_FINFO(inode)->opened, info->opened);
 
 		inode->i_ino = info->ino;
@@ -707,19 +754,31 @@
 
 static int __init init_ncp_fs(void)
 {
+	int err;
 	DPRINTK("ncpfs: init_module called\n");
 
 #ifdef DEBUG_NCP_MALLOC
 	ncp_malloced = 0;
 	ncp_current_malloced = 0;
 #endif
-	return register_filesystem(&ncp_fs_type);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&ncp_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_ncp_fs(void)
 {
 	DPRINTK("ncpfs: cleanup_module called\n");
 	unregister_filesystem(&ncp_fs_type);
+	destroy_inodecache();
 #ifdef DEBUG_NCP_MALLOC
 	PRINTK("ncp_malloced: %d\n", ncp_malloced);
 	PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
diff -urN linux-2.5.3-pre3/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c
--- linux-2.5.3-pre3/fs/nfsd/nfssvc.c	Wed Oct 17 14:16:34 2001
+++ linux/fs/nfsd/nfssvc.c	Wed Jan 23 17:31:04 2002
@@ -99,7 +99,7 @@
 		if (error < 0)
 			goto failure;
 #endif
-		get_fast_time(&nfssvc_boot);		/* record boot time */
+		do_gettimeofday(&nfssvc_boot);		/* record boot time */
 	} else
 		nfsd_serv->sv_nrthreads++;
 	nrservs -= (nfsd_serv->sv_nrthreads-1);
diff -urN linux-2.5.3-pre3/fs/reiserfs/bitmap.c linux/fs/reiserfs/bitmap.c
--- linux-2.5.3-pre3/fs/reiserfs/bitmap.c	Mon Jan 14 09:38:36 2002
+++ linux/fs/reiserfs/bitmap.c	Wed Jan 23 17:31:04 2002
@@ -466,6 +466,7 @@
 				unsigned long      * free_blocknrs,
 				unsigned long        search_start)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(p_s_inode);
   int ret=0, blks_gotten=0;
   unsigned long border = 0;
   unsigned long bstart = 0;
@@ -550,13 +551,13 @@
     }
 
   /* take a block off the prealloc list and return it -Hans */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count > 0) {
-    p_s_inode->u.reiserfs_i.i_prealloc_count--;
-    *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  if (ei->i_prealloc_count > 0) {
+    ei->i_prealloc_count--;
+    *free_blocknrs = ei->i_prealloc_block++;
 
     /* if no more preallocated blocks, remove inode from list */
-    if (! p_s_inode->u.reiserfs_i.i_prealloc_count) {
-      list_del(&p_s_inode->u.reiserfs_i.i_prealloc_list);
+    if (! ei->i_prealloc_count) {
+      list_del_init(&ei->i_prealloc_list);
     }
     
     return ret;
@@ -567,8 +568,8 @@
   /* this uses the last preallocated block as the search_start.  discard
   ** prealloc does not zero out this number.
   */
-  if (search_start <= p_s_inode->u.reiserfs_i.i_prealloc_block) {
-    search_start = p_s_inode->u.reiserfs_i.i_prealloc_block;
+  if (search_start <= ei->i_prealloc_block) {
+    search_start = ei->i_prealloc_block;
   }
   
   /* doing the compare again forces search_start to be >= the border,
@@ -611,18 +612,18 @@
     }
 #endif
     if (blks_gotten==0) {
-      p_s_inode->u.reiserfs_i.i_prealloc_block = *free_blocknrs;
+      ei->i_prealloc_block = *free_blocknrs;
     }
     search_start = *free_blocknrs; 
     *free_blocknrs = 0;
   }
-  p_s_inode->u.reiserfs_i.i_prealloc_count = blks;
-  *free_blocknrs = p_s_inode->u.reiserfs_i.i_prealloc_block;
-  p_s_inode->u.reiserfs_i.i_prealloc_block++;
+  ei->i_prealloc_count = blks;
+  *free_blocknrs = ei->i_prealloc_block;
+  ei->i_prealloc_block++;
 
   /* if inode has preallocated blocks, link him to list */
-  if (p_s_inode->u.reiserfs_i.i_prealloc_count) {
-    list_add(&p_s_inode->u.reiserfs_i.i_prealloc_list,
+  if (ei->i_prealloc_count) {
+    list_add(&ei->i_prealloc_list,
 	     &SB_JOURNAL(th->t_super)->j_prealloc_list);
   } 
   /* we did actually manage to get 1 block */
@@ -657,42 +658,43 @@
 // analog. You should be able to tell which portion by looking at the
 // ext2 code and comparing. 
 static void __discard_prealloc (struct reiserfs_transaction_handle * th,
-				struct inode * inode)
+				struct reiserfs_inode_info *ei)
 {
-  while (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    reiserfs_free_block(th,inode->u.reiserfs_i.i_prealloc_block);
-    inode->u.reiserfs_i.i_prealloc_block++;
-    inode->u.reiserfs_i.i_prealloc_count --;
+  while (ei->i_prealloc_count > 0) {
+    reiserfs_free_block(th,ei->i_prealloc_block);
+    ei->i_prealloc_block++;
+    ei->i_prealloc_count --;
   }
-  list_del (&(inode->u.reiserfs_i.i_prealloc_list));
+  list_del_init(&(ei->i_prealloc_list));
 }
 
 
 void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th, 
 				struct inode * inode)
 {
+  struct reiserfs_inode_info *ei = REISERFS_I(inode);
 #ifdef CONFIG_REISERFS_CHECK
-  if (inode->u.reiserfs_i.i_prealloc_count < 0)
+  if (ei->i_prealloc_count < 0)
      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode has negative prealloc blocks count.\n");
 #endif  
-    if (inode->u.reiserfs_i.i_prealloc_count > 0) {
-    __discard_prealloc(th, inode);
+    if (ei->i_prealloc_count > 0) {
+    __discard_prealloc(th, ei);
   }
       }
 
 void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
 {
   struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
-  struct inode * inode;
   
   while (!list_empty(plist)) {
-    inode = list_entry(plist->next, struct inode, u.reiserfs_i.i_prealloc_list);
+	struct reiserfs_inode_info *ei;
+	ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
 #ifdef CONFIG_REISERFS_CHECK
-    if (!inode->u.reiserfs_i.i_prealloc_count) {
-      reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
-    }
-#endif    
-    __discard_prealloc(th, inode);
+	if (!ei->i_prealloc_count) {
+		reiserfs_warning("zam-4001:" __FUNCTION__ ": inode is in prealloc list but has no preallocated blocks.\n");
+	}
+#endif
+	__discard_prealloc(th, ei);
     }
 }
 #endif
diff -urN linux-2.5.3-pre3/fs/reiserfs/buffer2.c linux/fs/reiserfs/buffer2.c
--- linux-2.5.3-pre3/fs/reiserfs/buffer2.c	Mon Jan  7 12:56:48 2002
+++ linux/fs/reiserfs/buffer2.c	Wed Jan 23 17:31:04 2002
@@ -186,7 +186,7 @@
 
       copy_key(&unf_key_to_search,p_s_key_to_search);
       unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
-      unf_key_to_search.k_offset = p_s_inode->u.reiserfs_i.i_first_direct_byte - 1;
+      unf_key_to_search.k_offset = REISERFS_I(p_s_inode)->i_first_direct_byte - 1;
 
         /* p_s_key_to_search->k_offset -  MAX_ITEM_LEN(p_s_sb->s_blocksize); */
       if (search_for_position_by_key (p_s_sb, &unf_key_to_search, p_unf_search_path, &n_pos_in_item) == POSITION_FOUND)
@@ -218,16 +218,16 @@
   unf_key_to_search.k_uniqueness = TYPE_INDIRECT;
   
   if (
-      (p_s_inode->u.reiserfs_i.i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
+      (REISERFS_I(p_s_inode)->i_first_direct_byte > 4095) /* i_first_direct_byte gets used for all sorts of
                                                               crap other than what the name indicates, thus
                                                               testing to see if it is 0 is not enough */
-      && (p_s_inode->u.reiserfs_i.i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
+      && (REISERFS_I(p_s_inode)->i_first_direct_byte < MAX_KEY_OFFSET) /* if there is no direct item then
                                                                            i_first_direct_byte = MAX_KEY_OFFSET */
       )
     {
                                 /* actually, we don't want the last unformatted node, we want the last unformatted node
                                    which is before the current file offset */
-      unf_key_to_search.k_offset = ((p_s_inode->u.reiserfs_i.i_first_direct_byte -1) < unf_key_to_search.k_offset) ? p_s_inode->u.reiserfs_i.i_first_direct_byte -1 :  unf_key_to_search.k_offset;
+      unf_key_to_search.k_offset = ((REISERFS_I(p_s_inode)->i_first_direct_byte -1) < unf_key_to_search.k_offset) ? REISERFS_I(p_s_inode)->i_first_direct_byte -1 :  unf_key_to_search.k_offset;
 
       while (unf_key_to_search.k_offset > -1)
         {
diff -urN linux-2.5.3-pre3/fs/reiserfs/file.c linux/fs/reiserfs/file.c
--- linux-2.5.3-pre3/fs/reiserfs/file.c	Fri Oct 12 14:20:42 2001
+++ linux/fs/reiserfs/file.c	Wed Jan 23 17:31:04 2002
@@ -33,9 +33,9 @@
 
     /* fast out for when nothing needs to be done */
     if ((atomic_read(&inode->i_count) > 1 ||
-         !inode->u.reiserfs_i.i_pack_on_close || 
+         REISERFS_I(inode)->i_pack_on_close || 
          !tail_has_to_be_packed(inode))       && 
-	inode->u.reiserfs_i.i_prealloc_count <= 0) {
+	REISERFS_I(inode)->i_prealloc_count <= 0) {
 	return 0;
     }    
     
@@ -50,7 +50,7 @@
     journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3) ;
 
     if (atomic_read(&inode->i_count) <= 1 &&
-	inode->u.reiserfs_i.i_pack_on_close &&
+	REISERFS_I(inode)->i_pack_on_close &&
         tail_has_to_be_packed (inode)) {
 	/* if regular file is released by last holder and it has been
 	   appended (we append by unformatted node only) or its direct
diff -urN linux-2.5.3-pre3/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- linux-2.5.3-pre3/fs/reiserfs/inode.c	Wed Jan 23 17:31:01 2002
+++ linux/fs/reiserfs/inode.c	Wed Jan 23 17:31:04 2002
@@ -69,7 +69,7 @@
 
 /* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
    offset and type of key */
-void make_cpu_key (struct cpu_key * key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * key, struct inode * inode, loff_t offset,
 	      int type, int length )
 {
   _make_cpu_key (key, inode_items_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
@@ -559,7 +559,7 @@
 	return ret;
     }
 
-    inode->u.reiserfs_i.i_pack_on_close = 1 ;
+    REISERFS_I(inode)->i_pack_on_close = 1 ;
 
     windex = push_journal_writer("reiserfs_get_block") ;
   
@@ -868,8 +868,6 @@
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
     inode->i_blksize = PAGE_SIZE;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
-
     if (stat_data_v1 (ih)) {
 	struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
 	unsigned long blocks;
@@ -898,7 +896,7 @@
 	}
 
         rdev = sd_v1_rdev(sd);
-	inode->u.reiserfs_i.i_first_direct_byte = sd_v1_first_direct_byte(sd);
+	REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
     } else {
 	// new stat data found, but object may have old items
 	// (directories and symlinks)
@@ -926,10 +924,15 @@
 	    inode_items_version (inode) = ITEM_VERSION_1;
 	else
 	    inode_items_version (inode) = ITEM_VERSION_2;
+	REISERFS_I(inode)->i_first_direct_byte = 0;
     }
-
+    REISERFS_I(inode)->i_pack_on_close = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
     /* nopack = 0, by default */
-    inode->u.reiserfs_i.nopack = 0;
+    REISERFS_I(inode)->nopack = 0;
 
     pathrelse (path);
     if (S_ISREG (inode->i_mode)) {
@@ -993,7 +996,7 @@
         set_sd_v1_blocks(sd_v1, inode->i_blocks );
 
     // Sigh. i_first_direct_byte is back
-    set_sd_v1_first_direct_byte(sd_v1, inode->u.reiserfs_i.i_first_direct_byte);
+    set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
 }
 
 
@@ -1331,7 +1334,7 @@
    containing "." and ".." entries */
 static int reiserfs_new_directory (struct reiserfs_transaction_handle *th, 
 				   struct item_head * ih, struct path * path,
-				   const struct inode * dir)
+				   struct inode * dir)
 {
     struct super_block * sb = th->t_super;
     char empty_dir [EMPTY_DIR_SIZE];
@@ -1419,7 +1422,7 @@
    directory) or reiserfs_new_symlink (to insert symlink body if new
    object is symlink) or nothing (if new object is regular file) */
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th,
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, 
 				   int i_size, /* 0 for regular, EMTRY_DIR_SIZE for dirs,
 						  strlen (symname) for symlinks)*/
@@ -1501,10 +1504,15 @@
     inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
     inode->i_size = i_size;
     inode->i_blocks = (inode->i_size + 511) >> 9;
-    inode->u.reiserfs_i.i_first_direct_byte = S_ISLNK(mode) ? 1 : 
+    REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 : 
       U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
 
-    INIT_LIST_HEAD(&inode->u.reiserfs_i.i_prealloc_list) ;
+    REISERFS_I(inode)->i_pack_on_close = 0;
+    REISERFS_I(inode)->i_prealloc_block = 0;
+    REISERFS_I(inode)->i_prealloc_count = 0;
+    REISERFS_I(inode)->nopack = 0;
+    REISERFS_I(inode)->i_trans_id = 0;
+    REISERFS_I(inode)->i_trans_index = 0;
 
     if (old_format_only (sb))
 	inode2sd_v1 (&sd, inode);
diff -urN linux-2.5.3-pre3/fs/reiserfs/ioctl.c linux/fs/reiserfs/ioctl.c
--- linux-2.5.3-pre3/fs/reiserfs/ioctl.c	Sat Sep  8 12:05:32 2001
+++ linux/fs/reiserfs/ioctl.c	Wed Jan 23 17:31:04 2002
@@ -46,7 +46,7 @@
         return -EINVAL ;
     }
     /* ioctl already done */
-    if (inode->u.reiserfs_i.nopack) {
+    if (REISERFS_I(inode)->nopack) {
         return 0 ;
     }
     lock_kernel();
@@ -59,7 +59,7 @@
     write_from = inode->i_size & (blocksize - 1) ;
     /* if we are on a block boundary, we are already unpacked.  */
     if ( write_from == 0) {
-	inode->u.reiserfs_i.nopack = 1;
+	REISERFS_I(inode)->nopack = 1;
 	goto out ;
     }
 
@@ -79,7 +79,7 @@
 
     /* conversion can change page contents, must flush */
     flush_dcache_page(page) ;
-    inode->u.reiserfs_i.nopack = 1;
+    REISERFS_I(inode)->nopack = 1;
     kunmap(page) ; /* mapped by prepare_write */
 
 out_unlock:
diff -urN linux-2.5.3-pre3/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- linux-2.5.3-pre3/fs/reiserfs/journal.c	Wed Jan 23 17:31:01 2002
+++ linux/fs/reiserfs/journal.c	Wed Jan 23 17:31:04 2002
@@ -2613,14 +2613,14 @@
 
 void reiserfs_update_inode_transaction(struct inode *inode) {
   
-  inode->u.reiserfs_i.i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+  REISERFS_I(inode)->i_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
 
-  inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+  REISERFS_I(inode)->i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }
 
 static int reiserfs_inode_in_this_transaction(struct inode *inode) {
-  if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
-      inode->u.reiserfs_i.i_trans_id == 0) {
+  if (REISERFS_I(inode)->i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id || 
+      REISERFS_I(inode)->i_trans_id == 0) {
     return 1; 
   } 
   return 0 ;
@@ -2631,14 +2631,14 @@
   struct reiserfs_transaction_handle th ;
   struct super_block *sb = inode->i_sb ;
 
-  jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
+  jl = SB_JOURNAL_LIST(sb) + REISERFS_I(inode)->i_trans_index ;
 
   /* is it from the current transaction, or from an unknown transaction? */
   if (reiserfs_inode_in_this_transaction(inode)) {
     journal_join(&th, sb, 1) ;
     reiserfs_update_inode_transaction(inode) ;
     journal_end_sync(&th, sb, 1) ;
-  } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
+  } else if (jl->j_trans_id == REISERFS_I(inode)->i_trans_id) {
     flush_commit_list(sb, jl, 1) ;
   }
   /* if the transaction id does not match, this list is long since flushed
diff -urN linux-2.5.3-pre3/fs/reiserfs/stree.c linux/fs/reiserfs/stree.c
--- linux-2.5.3-pre3/fs/reiserfs/stree.c	Mon Jan  7 12:55:16 2002
+++ linux/fs/reiserfs/stree.c	Wed Jan 23 17:31:04 2002
@@ -1489,7 +1489,7 @@
     */
     if (atomic_read(&p_s_inode->i_count) > 1 || 
         !tail_has_to_be_packed (p_s_inode) || 
-	!page || p_s_inode->u.reiserfs_i.nopack) {
+	!page || REISERFS_I(p_s_inode)->nopack) {
 	// leave tail in an unformatted node	
 	*p_c_mode = M_SKIP_BALANCING;
 	cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
@@ -1654,7 +1654,7 @@
 	    /* we delete first part of tail which was stored in direct
                item(s) */
 	    // FIXME: this is to keep 3.5 happy
-	    p_s_inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+	    REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
 	    p_s_inode->i_blocks -= p_s_sb->s_blocksize / 512;
 	}
     }
@@ -1691,7 +1691,7 @@
 	** be flushed before the transaction commits, so we don't need to 
 	** deal with it here.
 	*/
-	p_s_inode->u.reiserfs_i.i_pack_on_close = 0 ;
+	REISERFS_I(p_s_inode)->i_pack_on_close = 0 ;
     }
     return n_ret_value;
 }
diff -urN linux-2.5.3-pre3/fs/reiserfs/super.c linux/fs/reiserfs/super.c
--- linux-2.5.3-pre3/fs/reiserfs/super.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/reiserfs/super.c	Wed Jan 23 17:31:04 2002
@@ -124,8 +124,54 @@
   return;
 }
 
+static kmem_cache_t * reiserfs_inode_cachep;
+
+static struct inode *reiserfs_alloc_inode(struct super_block *sb)
+{
+	struct reiserfs_inode_info *ei;
+	ei = (struct reiserfs_inode_info *)kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void reiserfs_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_LIST_HEAD(&ei->i_prealloc_list) ;
+		inode_init_once(&ei->vfs_inode);
+	}
+}
+ 
+static int init_inodecache(void)
+{
+	reiserfs_inode_cachep = kmem_cache_create("reiserfs_inode_cache",
+					     sizeof(struct reiserfs_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (reiserfs_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(reiserfs_inode_cachep))
+		printk(KERN_INFO "reiserfs_inode_cache: not all structures were freed\n");
+}
+
 struct super_operations reiserfs_sops = 
 {
+  alloc_inode: reiserfs_alloc_inode,
+  destroy_inode: reiserfs_destroy_inode,
   read_inode: reiserfs_read_inode,
   read_inode2: reiserfs_read_inode2,
   write_inode: reiserfs_write_inode,
@@ -365,7 +411,7 @@
     bh = sb_bread (s, offset / s->s_blocksize);
     if (!bh) {
       printk ("read_super_block: "
-              "bread failed (dev %s, block %d, size %d)\n",
+              "bread failed (dev %s, block %ld, size %ld)\n",
               s->s_id, offset / s->s_blocksize, s->s_blocksize);
       return 1;
     }
@@ -373,7 +419,7 @@
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs)) {
       printk ("read_super_block: "
-              "can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+              "can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
               s->s_id, bh->b_blocknr, s->s_blocksize);
       brelse (bh);
       return 1;
@@ -389,7 +435,7 @@
     bh = reiserfs_bread (s, offset / s->s_blocksize);
     if (!bh) {
 	printk("read_super_block: "
-                "bread failed (dev %s, block %d, size %d)\n",
+                "bread failed (dev %s, block %ld, size %ld)\n",
                 s->s_id, offset / s->s_blocksize, s->s_blocksize);
 	return 1;
     }
@@ -397,7 +443,7 @@
     rs = (struct reiserfs_super_block *)bh->b_data;
     if (!is_reiserfs_magic_string (rs) || sb_blocksize(rs) != s->s_blocksize) {
 	printk ("read_super_block: "
-		"can't find a reiserfs filesystem on (dev %s, block %lu, size %d)\n",
+		"can't find a reiserfs filesystem on (dev %s, block %lu, size %ld)\n",
 		s->s_id, bh->b_blocknr, s->s_blocksize);
 	brelse (bh);
 	printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", s->s_id);
@@ -803,10 +849,22 @@
 //
 static int __init init_reiserfs_fs (void)
 {
+	int err = init_inodecache();
+	if (err)
+		goto out1;
 	reiserfs_proc_info_global_init();
 	reiserfs_proc_register_global( "version", 
 				       reiserfs_global_version_in_proc );
-        return register_filesystem(&reiserfs_fs_type);
+        err = register_filesystem(&reiserfs_fs_type);
+	if (err)
+		goto out;
+	return 0;
+out:
+	reiserfs_proc_unregister_global( "version" );
+	reiserfs_proc_info_global_done();
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 MODULE_DESCRIPTION("ReiserFS journaled filesystem");
@@ -822,6 +880,7 @@
 	reiserfs_proc_unregister_global( "version" );
 	reiserfs_proc_info_global_done();
         unregister_filesystem(&reiserfs_fs_type);
+	destroy_inodecache();
 }
 
 module_init(init_reiserfs_fs) ;
diff -urN linux-2.5.3-pre3/fs/reiserfs/tail_conversion.c linux/fs/reiserfs/tail_conversion.c
--- linux-2.5.3-pre3/fs/reiserfs/tail_conversion.c	Mon Jan 14 09:38:37 2002
+++ linux/fs/reiserfs/tail_conversion.c	Wed Jan 23 17:31:04 2002
@@ -125,7 +125,7 @@
 	memset(page_address(unbh->b_page) + pgoff, 0, n_blk_size - total_tail) ;
     }
 
-    inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+    REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
 
     return 0;
 }
@@ -285,7 +285,7 @@
 
     /* we store position of first direct item in the in-core inode */
     //mark_file_with_tail (p_s_inode, pos1 + 1);
-    p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;
+    REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
 
     return n_block_size - round_tail_len;
 }
diff -urN linux-2.5.3-pre3/fs/super.c linux/fs/super.c
--- linux-2.5.3-pre3/fs/super.c	Fri Jan  4 11:51:23 2002
+++ linux/fs/super.c	Wed Jan 23 17:31:04 2002
@@ -408,9 +408,8 @@
 		put_anon_dev(dev);
 }
 
-struct vfsmount *alloc_vfsmnt(void);
+struct vfsmount *alloc_vfsmnt(char *name);
 void free_vfsmnt(struct vfsmount *mnt);
-void set_devname(struct vfsmount *mnt, const char *name);
 
 static inline struct super_block * find_super(kdev_t dev)
 {
@@ -790,10 +789,9 @@
 	if (!type)
 		return ERR_PTR(-ENODEV);
 
-	mnt = alloc_vfsmnt();
+	mnt = alloc_vfsmnt(name);
 	if (!mnt)
 		goto out;
-	set_devname(mnt, name);
 	if (type->fs_flags & FS_REQUIRES_DEV)
 		sb = get_sb_bdev(type, flags, name, data);
 	else if (type->fs_flags & FS_SINGLE)
diff -urN linux-2.5.3-pre3/fs/sysv/ChangeLog linux/fs/sysv/ChangeLog
--- linux-2.5.3-pre3/fs/sysv/ChangeLog	Sat Jan  5 12:51:00 2002
+++ linux/fs/sysv/ChangeLog	Wed Jan 23 17:31:04 2002
@@ -1,3 +1,33 @@
+Mon Jan 21 2001  Alexander Viro  <viro@math.psu.edu>
+	* ialloc.c (sysv_new_inode): zero SYSV_I(inode)->i_data out.
+	* i_vnode renamed to vfs_inode.  Sorry, but let's keep that
+	  consistent.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+	* include/linux/sysv_fs.h (SYSV_I): Get fs-private inode data using
+		list_entry() instead of inode->u.
+	* include/linux/sysv_fs_i.h: Add 'struct inode  i_vnode' field to
+		sysv_inode_info structure.
+	* inode.c: Include <linux/slab.h>, implement alloc_inode/destroy_inode
+		sop methods, add infrastructure for per-fs inode slab cache.
+	* super.c (init_sysv_fs): Initialize inode cache, recover properly
+		in the case of failed register_filesystem for V7.
+	(exit_sysv_fs): Destroy inode cache.
+
+Sat Jan 19 2001  Christoph Hellwig  <hch@infradead.org>
+
+	* include/linux/sysv_fs.h: Include <linux/sysv_fs_i.h>, declare SYSV_I().
+	* dir.c (sysv_find_entry): Use SYSV_I() instead of ->u.sysv_i to
+		access fs-private inode data.
+	* ialloc.c (sysv_new_inode): Likewise.
+	* inode.c (sysv_read_inode): Likewise.
+	(sysv_update_inode): Likewise.
+	* itree.c (get_branch): Likewise.
+	(sysv_truncate): Likewise.
+	* symlink.c (sysv_readlink): Likewise.
+	(sysv_follow_link): Likewise.
+
 Fri Jan  4 2001  Alexander Viro  <viro@math.psu.edu>
 
 	* ialloc.c (sysv_free_inode): Use sb->s_id instead of bdevname().
diff -urN linux-2.5.3-pre3/fs/sysv/dir.c linux/fs/sysv/dir.c
--- linux-2.5.3-pre3/fs/sysv/dir.c	Sun Dec 30 10:53:53 2001
+++ linux/fs/sysv/dir.c	Wed Jan 23 17:31:04 2002
@@ -145,7 +145,7 @@
 
 	*res_page = NULL;
 
-	start = dir->u.sysv_i.i_dir_start_lookup;
+	start = SYSV_I(dir)->i_dir_start_lookup;
 	if (start >= npages)
 		start = 0;
 	n = start;
@@ -174,7 +174,7 @@
 	return NULL;
 
 found:
-	dir->u.sysv_i.i_dir_start_lookup = n;
+	SYSV_I(dir)->i_dir_start_lookup = n;
 	*res_page = page;
 	return de;
 }
diff -urN linux-2.5.3-pre3/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- linux-2.5.3-pre3/fs/sysv/ialloc.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/sysv/ialloc.c	Wed Jan 23 17:31:04 2002
@@ -165,7 +165,8 @@
 	inode->i_ino = fs16_to_cpu(sb, ino);
 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	inode->i_blocks = inode->i_blksize = 0;
-	inode->u.sysv_i.i_dir_start_lookup = 0;
+	memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
+	SYSV_I(inode)->i_dir_start_lookup = 0;
 	insert_inode_hash(inode);
 	mark_inode_dirty(inode);
 
diff -urN linux-2.5.3-pre3/fs/sysv/inode.c linux/fs/sysv/inode.c
--- linux-2.5.3-pre3/fs/sysv/inode.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/sysv/inode.c	Wed Jan 23 17:31:04 2002
@@ -26,6 +26,7 @@
 #include <linux/locks.h>
 #include <linux/smp_lock.h>
 #include <linux/highuid.h>
+#include <linux/slab.h>
 #include <asm/byteorder.h>
 
 /* This is only called on sync() and umount(), when s_dirt=1. */
@@ -144,6 +145,7 @@
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
+	struct sysv_inode_info * si;
 	unsigned int block, ino;
 	dev_t rdev = 0;
 
@@ -169,13 +171,15 @@
 	inode->i_mtime = fs32_to_cpu(sb, raw_inode->i_mtime);
 	inode->i_ctime = fs32_to_cpu(sb, raw_inode->i_ctime);
 	inode->i_blocks = inode->i_blksize = 0;
+
+	si = SYSV_I(inode);
 	for (block = 0; block < 10+1+1+1; block++)
 		read3byte(sb, &raw_inode->i_a.i_addb[3*block],
-			(unsigned char*)&inode->u.sysv_i.i_data[block]);
+			(unsigned char*)&si->i_data[block]);
 	brelse(bh);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		rdev = (u16)fs32_to_cpu(sb, inode->u.sysv_i.i_data[0]);
-	inode->u.sysv_i.i_dir_start_lookup = 0;
+		rdev = (u16)fs32_to_cpu(sb, si->i_data[0]);
+	si->i_dir_start_lookup = 0;
 	sysv_set_inode(inode, rdev);
 	return;
 
@@ -189,6 +193,7 @@
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
 	struct sysv_inode * raw_inode;
+	struct sysv_inode_info * si;
 	unsigned int ino, block;
 
 	ino = inode->i_ino;
@@ -211,11 +216,12 @@
 	raw_inode->i_atime = cpu_to_fs32(sb, inode->i_atime);
 	raw_inode->i_mtime = cpu_to_fs32(sb, inode->i_mtime);
 	raw_inode->i_ctime = cpu_to_fs32(sb, inode->i_ctime);
+
+	si = SYSV_I(inode);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		inode->u.sysv_i.i_data[0] = 
-			cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
+		si->i_data[0] = cpu_to_fs32(sb, kdev_t_to_nr(inode->i_rdev));
 	for (block = 0; block < 10+1+1+1; block++)
-		write3byte(sb, (unsigned char*)&inode->u.sysv_i.i_data[block],
+		write3byte(sb, (unsigned char*)&si->i_data[block],
 			&raw_inode->i_a.i_addb[3*block]);
 	mark_buffer_dirty(bh);
 	return bh;
@@ -260,7 +266,35 @@
 	unlock_kernel();
 }
 
+static kmem_cache_t *sysv_inode_cachep;
+
+static struct inode *sysv_alloc_inode(struct super_block *sb)
+{
+	struct sysv_inode_info *si;
+
+	si = kmem_cache_alloc(sysv_inode_cachep, SLAB_KERNEL);
+	if (!si)
+		return NULL;
+	return &si->vfs_inode;
+}
+
+static void sysv_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(sysv_inode_cachep, SYSV_I(inode));
+}
+
+static void init_once(void *p, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct sysv_inode_info *si = (struct sysv_inode_info *)p;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+			SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&si->vfs_inode);
+}
+
 struct super_operations sysv_sops = {
+	alloc_inode:	sysv_alloc_inode,
+	destroy_inode:	sysv_destroy_inode,
 	read_inode:	sysv_read_inode,
 	write_inode:	sysv_write_inode,
 	delete_inode:	sysv_delete_inode,
@@ -268,3 +302,18 @@
 	write_super:	sysv_write_super,
 	statfs:		sysv_statfs,
 };
+
+int __init sysv_init_icache(void)
+{
+	sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
+			sizeof(struct sysv_inode_info), 0,
+			SLAB_HWCACHE_ALIGN, init_once, NULL);
+	if (!sysv_inode_cachep)
+		return -ENOMEM;
+	return 0;
+}
+
+void sysv_destroy_icache(void)
+{
+	kmem_cache_destroy(sysv_inode_cachep);
+}
diff -urN linux-2.5.3-pre3/fs/sysv/itree.c linux/fs/sysv/itree.c
--- linux-2.5.3-pre3/fs/sysv/itree.c	Thu Dec 27 08:17:43 2001
+++ linux/fs/sysv/itree.c	Wed Jan 23 17:31:04 2002
@@ -91,7 +91,7 @@
 	struct buffer_head *bh;
 
 	*err = 0;
-	add_chain (chain, NULL, inode->u.sysv_i.i_data + *offsets);
+	add_chain (chain, NULL, SYSV_I(inode)->i_data + *offsets);
 	if (!p->key)
 		goto no_block;
 	while (--depth) {
@@ -348,7 +348,7 @@
 
 void sysv_truncate (struct inode * inode)
 {
-	u32 *i_data = inode->u.sysv_i.i_data;
+	u32 *i_data = SYSV_I(inode)->i_data;
 	int offsets[DEPTH];
 	Indirect chain[DEPTH];
 	Indirect *partial;
diff -urN linux-2.5.3-pre3/fs/sysv/super.c linux/fs/sysv/super.c
--- linux-2.5.3-pre3/fs/sysv/super.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/sysv/super.c	Wed Jan 23 17:31:04 2002
@@ -479,18 +479,37 @@
 static DECLARE_FSTYPE_DEV(sysv_fs_type, "sysv", sysv_read_super);
 static DECLARE_FSTYPE_DEV(v7_fs_type, "v7", v7_read_super);
 
+extern int sysv_init_icache(void) __init;
+extern void sysv_destroy_icache(void);
+
 static int __init init_sysv_fs(void)
 {
-	int err = register_filesystem(&sysv_fs_type);
-	if (!err)
-		err = register_filesystem(&v7_fs_type);
-	return err;
+	int error;
+
+	error = sysv_init_icache();
+	if (error)
+		goto out;
+	error = register_filesystem(&sysv_fs_type);
+	if (error)
+		goto destroy_icache;
+	error = register_filesystem(&v7_fs_type);
+	if (error)
+		goto unregister;
+	return 0;
+
+unregister:
+	unregister_filesystem(&sysv_fs_type);
+destroy_icache:
+	sysv_destroy_icache();
+out:
+	return error;
 }
 
 static void __exit exit_sysv_fs(void)
 {
 	unregister_filesystem(&sysv_fs_type);
 	unregister_filesystem(&v7_fs_type);
+	sysv_destroy_icache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.5.3-pre3/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- linux-2.5.3-pre3/fs/sysv/symlink.c	Sun Sep  2 10:34:36 2001
+++ linux/fs/sysv/symlink.c	Wed Jan 23 17:31:04 2002
@@ -6,16 +6,17 @@
  */
 
 #include <linux/fs.h>
+#include <linux/sysv_fs.h>
 
 static int sysv_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
 	return vfs_readlink(dentry, buffer, buflen, s);
 }
 
 static int sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-	char *s = (char *)dentry->d_inode->u.sysv_i.i_data;
+	char *s = (char *)SYSV_I(dentry->d_inode)->i_data;
 	return vfs_follow_link(nd, s);
 }
 
diff -urN linux-2.5.3-pre3/fs/udf/ialloc.c linux/fs/udf/ialloc.c
--- linux-2.5.3-pre3/fs/udf/ialloc.c	Thu Oct 11 08:59:24 2001
+++ linux/fs/udf/ialloc.c	Wed Jan 23 17:31:04 2002
@@ -95,6 +95,11 @@
 	}
 	lock_super(sb);
 
+	UDF_I_UNIQUE(inode) = 0;
+	UDF_I_LENEXTENTS(inode) = 0;
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+	UDF_I_STRAT4096(inode) = 0;
 	if (UDF_SB_LVIDBH(sb))
 	{
 		struct LogicalVolHeaderDesc *lvhd;
diff -urN linux-2.5.3-pre3/fs/udf/inode.c linux/fs/udf/inode.c
--- linux-2.5.3-pre3/fs/udf/inode.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/udf/inode.c	Wed Jan 23 17:31:04 2002
@@ -945,7 +945,6 @@
 	 *      i_nlink = 1
 	 *      i_op = NULL;
 	 */
-
 	inode->i_blksize = PAGE_SIZE;
 
 	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
@@ -1042,6 +1041,16 @@
 		UDF_I_STRAT4096(inode) = 1;
 
 	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+	UDF_I_UMTIME(inode) = 0;
+	UDF_I_UCTIME(inode) = 0;
+	UDF_I_CRTIME(inode) = 0;
+	UDF_I_UCRTIME(inode) = 0;
+	UDF_I_UNIQUE(inode) = 0;
+	UDF_I_LENEATTR(inode) = 0;
+	UDF_I_LENEXTENTS(inode) = 0;
+	UDF_I_LENALLOC(inode) = 0;
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 	if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
 		UDF_I_EXTENDED_FE(inode) = 1;
 	else if (fe->descTag.tagIdent == TID_FILE_ENTRY)
@@ -1069,9 +1078,6 @@
 
 	inode->i_mode = udf_convert_permissions(fe);
 	inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
-
-	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
-	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
 
 	if (UDF_I_EXTENDED_FE(inode) == 0)
 	{
diff -urN linux-2.5.3-pre3/fs/udf/super.c linux/fs/udf/super.c
--- linux-2.5.3-pre3/fs/udf/super.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/udf/super.c	Wed Jan 23 17:31:04 2002
@@ -98,8 +98,52 @@
 /* UDF filesystem type */
 static DECLARE_FSTYPE_DEV(udf_fstype, "udf", udf_read_super);
 
+static kmem_cache_t * udf_inode_cachep;
+
+static struct inode *udf_alloc_inode(struct super_block *sb)
+{
+	struct udf_inode_info *ei;
+	ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
+	if (!ei)
+		return NULL;
+	return &ei->vfs_inode;
+}
+
+static void udf_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(udf_inode_cachep, UDF_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+	struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+ 
+static int init_inodecache(void)
+{
+	udf_inode_cachep = kmem_cache_create("udf_inode_cache",
+					     sizeof(struct udf_inode_info),
+					     0, SLAB_HWCACHE_ALIGN,
+					     init_once, NULL);
+	if (udf_inode_cachep == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void destroy_inodecache(void)
+{
+	if (kmem_cache_destroy(udf_inode_cachep))
+		printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+}
+
 /* Superblock operations */
 static struct super_operations udf_sb_ops = {
+	alloc_inode:		udf_alloc_inode,
+	destroy_inode:		udf_destroy_inode,
 	read_inode:		udf_read_inode,
 	write_inode:		udf_write_inode,
 	put_inode:		udf_put_inode,
@@ -130,14 +174,26 @@
 
 static int __init init_udf_fs(void)
 {
+	int err;
 	printk(KERN_NOTICE "udf: registering filesystem\n");
-	return register_filesystem(&udf_fstype);
+	err = init_inodecache();
+	if (err)
+		goto out1;
+	err = register_filesystem(&udf_fstype);
+	if (err)
+		goto out;
+	return 0;
+out:
+	destroy_inodecache();
+out1:
+	return err;
 }
 
 static void __exit exit_udf_fs(void)
 {
 	printk(KERN_NOTICE "udf: unregistering filesystem\n");
 	unregister_filesystem(&udf_fstype);
+	destroy_inodecache();
 }
 
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.5.3-pre3/fs/udf/udf_i.h linux/fs/udf/udf_i.h
--- linux-2.5.3-pre3/fs/udf/udf_i.h	Mon Jul  2 14:10:02 2001
+++ linux/fs/udf/udf_i.h	Wed Jan 23 17:31:04 2002
@@ -1,7 +1,11 @@
 #ifndef __LINUX_UDF_I_H
 #define __LINUX_UDF_I_H
 
-#define UDF_I(X)			(&((X)->u.udf_i))
+#include <linux/udf_fs_i.h>
+static inline struct udf_inode_info *UDF_I(struct inode *inode)
+{
+	return list_entry(inode, struct udf_inode_info, vfs_inode);
+}
 
 #define UDF_I_LOCATION(X)	( UDF_I(X)->i_location )
 #define UDF_I_LENEATTR(X)	( UDF_I(X)->i_lenEAttr )
diff -urN linux-2.5.3-pre3/include/asm-sparc/ide.h linux/include/asm-sparc/ide.h
--- linux-2.5.3-pre3/include/asm-sparc/ide.h	Wed Jan 23 17:31:02 2002
+++ linux/include/asm-sparc/ide.h	Wed Jan 23 17:31:05 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.6 2000/05/27 00:49:37 davem Exp $
+/* $Id: ide.h,v 1.7 2002/01/16 20:58:40 davem Exp $
  * ide.h: SPARC PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -91,7 +91,7 @@
 		unsigned int reserved456: 3;
 		unsigned bit3		: 1;	/* ATA-2 thingy */
 		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int nIEN	: 1;	/* device INTRQ to host */
 		unsigned int bit0	: 1;
 	} b;
 } control_t;
diff -urN linux-2.5.3-pre3/include/asm-sparc64/ide.h linux/include/asm-sparc64/ide.h
--- linux-2.5.3-pre3/include/asm-sparc64/ide.h	Wed Jan 23 17:31:02 2002
+++ linux/include/asm-sparc64/ide.h	Wed Jan 23 17:31:05 2002
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.21 2001/09/25 20:21:48 kanoj Exp $
+/* $Id: ide.h,v 1.22 2002/01/16 20:58:40 davem Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -87,7 +87,7 @@
 		unsigned int reserved456: 3;
 		unsigned bit3		: 1;	/* ATA-2 thingy */
 		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host *
+		unsigned int nIEN	: 1;	/* device INTRQ to host */
 		unsigned int bit0	: 1;
 	} b;
 } control_t;
diff -urN linux-2.5.3-pre3/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- linux-2.5.3-pre3/include/asm-sparc64/irq.h	Sun Mar 25 18:14:21 2001
+++ linux/include/asm-sparc64/irq.h	Wed Jan 23 17:31:05 2002
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.20 2001/03/09 01:31:40 davem Exp $
+/* $Id: irq.h,v 1.21 2002/01/23 11:27:36 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,10 +11,7 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/kernel.h>
-
-struct devid_cookie {
-	int dummy;
-};
+#include <asm/pil.h>
 
 /* You should not mess with this directly. That's the job of irq.c.
  *
diff -urN linux-2.5.3-pre3/include/asm-sparc64/pil.h linux/include/asm-sparc64/pil.h
--- linux-2.5.3-pre3/include/asm-sparc64/pil.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/pil.h	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,21 @@
+/* $Id: pil.h,v 1.1 2002/01/23 11:27:36 davem Exp $ */
+#ifndef _SPARC64_PIL_H
+#define _SPARC64_PIL_H
+
+/* To avoid some locking problems, we hard allocate certain PILs
+ * for SMP cross call messages.  cli() does not block the cross
+ * call delivery, so when SMP locking is an issue we reschedule
+ * the event into a PIL interrupt which is blocked by cli().
+ *
+ * XXX In fact the whole set of PILs used for hardware interrupts
+ * XXX may be allocated in this manner.  All of the devices can
+ * XXX happily sit at the same PIL.  We would then need only two
+ * XXX PILs, one for devices and one for the CPU local timer tick.
+ */
+#define PIL_MIGRATE	1
+
+#ifndef __ASSEMBLY__
+#define PIL_RESERVED(PIL)	((PIL) == PIL_MIGRATE)
+#endif
+
+#endif /* !(_SPARC64_PIL_H) */
diff -urN linux-2.5.3-pre3/include/linux/device.h linux/include/linux/device.h
--- linux-2.5.3-pre3/include/linux/device.h	Mon Jan 14 13:27:14 2002
+++ linux/include/linux/device.h	Wed Jan 23 17:31:05 2002
@@ -80,7 +80,7 @@
 	atomic_t	refcount;	/* refcount to make sure the device
 					 * persists for the right amount of time */
 
-	struct driver_dir_entry	* dir;
+	struct driver_dir_entry	dir;
 
 	struct device_driver *driver;	/* which driver has allocated this
 					   device */
@@ -123,7 +123,7 @@
 	struct list_head devices;	/* children devices */
 
 	struct device *self;		/* pointer to controlling device */
-	struct driver_dir_entry	* dir;	/* driverfs directory */
+	struct driver_dir_entry	dir;	/* driverfs directory */
 
 	char	name[DEVICE_NAME_SIZE];
 	char	bus_id[BUS_ID_SIZE];
@@ -154,14 +154,8 @@
 extern struct iobus * iobus_alloc(void);
 extern void iobus_init(struct iobus * iobus);
 
-extern int device_create_file(struct device *device, const char * name, mode_t mode,
-			      struct driverfs_operations * ops, void * data);
+extern int device_create_file(struct device *device, struct driver_file_entry * entry);
 extern void device_remove_file(struct device * dev, const char * name);
-
-extern int iobus_create_file(struct iobus *bus, const char * name, mode_t mode,
-			     struct driverfs_operations * ops, void * data);
-extern void iobus_remove_file(struct iobus * iobus, const char * name);
-
 
 /*
  * Platform "fixup" functions - allow the platform to have their say
diff -urN linux-2.5.3-pre3/include/linux/driverfs_fs.h linux/include/linux/driverfs_fs.h
--- linux-2.5.3-pre3/include/linux/driverfs_fs.h	Mon Jan 14 13:25:16 2002
+++ linux/include/linux/driverfs_fs.h	Wed Jan 23 17:31:05 2002
@@ -26,11 +26,6 @@
 #ifndef _DRIVER_FS_H_
 #define _DRIVER_FS_H_
 
-struct driverfs_operations {
-	ssize_t	(*read) (char *, size_t, loff_t, void *);
-	ssize_t (*write)(const char *, size_t, loff_t, void*);
-};
-
 struct driver_dir_entry {
 	char			* name;
 	struct dentry		* dentry;
@@ -38,6 +33,8 @@
 	struct list_head	files;
 };
 
+struct device;
+
 struct driver_file_entry {
 	struct driver_dir_entry * parent;
 	struct list_head	node;
@@ -45,21 +42,16 @@
 	mode_t			mode;
 	struct dentry		* dentry;
 	void			* data;
-	struct driverfs_operations	* ops;
-};
 
-extern struct driver_dir_entry *
-driverfs_create_dir_entry(const char * name, mode_t mode);
+	ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
+	ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+};
 
 extern int
 driverfs_create_dir(struct driver_dir_entry *, struct driver_dir_entry *);
 
 extern void
 driverfs_remove_dir(struct driver_dir_entry * entry);
-
-extern struct driver_file_entry *
-driverfs_create_entry (const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data);
 
 extern int
 driverfs_create_file(struct driver_file_entry * entry,
diff -urN linux-2.5.3-pre3/include/linux/fb.h linux/include/linux/fb.h
--- linux-2.5.3-pre3/include/linux/fb.h	Mon Dec 11 13:16:53 2000
+++ linux/include/linux/fb.h	Wed Jan 23 17:31:05 2002
@@ -94,6 +94,18 @@
 #define FB_ACCEL_IGS_CYBER5000	35	/* CyberPro 5000		*/
 #define FB_ACCEL_SIS_GLAMOUR    36	/* SiS 300/630/540              */
 
+
+#define FB_ACCEL_NEOMAGIC_NM2070 90	/* NeoMagic NM2070              */
+#define FB_ACCEL_NEOMAGIC_NM2090 91	/* NeoMagic NM2090              */
+#define FB_ACCEL_NEOMAGIC_NM2093 92	/* NeoMagic NM2093              */
+#define FB_ACCEL_NEOMAGIC_NM2097 93	/* NeoMagic NM2097              */
+#define FB_ACCEL_NEOMAGIC_NM2160 94	/* NeoMagic NM2160              */
+#define FB_ACCEL_NEOMAGIC_NM2200 95	/* NeoMagic NM2200              */
+#define FB_ACCEL_NEOMAGIC_NM2230 96	/* NeoMagic NM2230              */
+#define FB_ACCEL_NEOMAGIC_NM2360 97	/* NeoMagic NM2360              */
+#define FB_ACCEL_NEOMAGIC_NM2380 98	/* NeoMagic NM2380              */
+
+
 struct fb_fix_screeninfo {
 	char id[16];			/* identification string eg "TT Builtin" */
 	unsigned long smem_start;	/* Start of frame buffer mem */
diff -urN linux-2.5.3-pre3/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.5.3-pre3/include/linux/fs.h	Wed Jan 23 17:31:02 2002
+++ linux/include/linux/fs.h	Wed Jan 23 17:31:05 2002
@@ -287,20 +287,15 @@
 
 
 #include <linux/pipe_fs_i.h>
-#include <linux/minix_fs_i.h>
 #include <linux/ntfs_fs_i.h>
 #include <linux/msdos_fs_i.h>
-#include <linux/umsdos_fs_i.h>
+/* #include <linux/umsdos_fs_i.h> */
 #include <linux/iso_fs_i.h>
-#include <linux/sysv_fs_i.h>
 #include <linux/romfs_fs_i.h>
 #include <linux/smb_fs_i.h>
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
-#include <linux/reiserfs_fs_i.h>
 #include <linux/bfs_fs_i.h>
-#include <linux/udf_fs_i.h>
-#include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
@@ -466,20 +461,15 @@
 	unsigned int		i_attr_flags;
 	__u32			i_generation;
 	union {
-		struct minix_inode_info		minix_i;
 		struct ntfs_inode_info		ntfs_i;
 		struct msdos_inode_info		msdos_i;
-		struct umsdos_inode_info	umsdos_i;
+		/* struct umsdos_inode_info	umsdos_i; */
 		struct iso_inode_info		isofs_i;
-		struct sysv_inode_info		sysv_i;
 		struct romfs_inode_info		romfs_i;
 		struct smb_inode_info		smbfs_i;
 		struct hfs_inode_info		hfs_i;
 		struct adfs_inode_info		adfs_i;
-		struct reiserfs_inode_info	reiserfs_i;
 		struct bfs_inode_info		bfs_i;
-		struct udf_inode_info		udf_i;
-		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
 		struct jffs2_inode_info		jffs2_i;
diff -urN linux-2.5.3-pre3/include/linux/init.h linux/include/linux/init.h
--- linux-2.5.3-pre3/include/linux/init.h	Mon Jan 14 13:27:05 2002
+++ linux/include/linux/init.h	Wed Jan 23 17:31:05 2002
@@ -50,8 +50,26 @@
 
 extern initcall_t __initcall_start, __initcall_end;
 
-#define __initcall(fn)								\
-	static initcall_t __initcall_##fn __init_call = fn
+/* initcalls are now grouped by functionality into separate 
+ * subsections. Ordering inside the subsections is determined
+ * by link order. 
+ * For backwards compatability, initcall() puts the call in 
+ * the device init subsection.
+ */
+
+#define __define_initcall(level,fn) \
+	static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
+
+#define early_arch_initcall(fn)		__define_initcall("1",fn)
+#define mem_initcall(fn)		__define_initcall("2",fn)
+#define subsys_initcall(fn)		__define_initcall("3",fn)
+#define arch_initcall(fn)		__define_initcall("4",fn)
+#define fs_initcall(fn)			__define_initcall("5",fn)
+#define device_initcall(fn)		__define_initcall("6",fn)
+#define late_initcall(fn)		__define_initcall("7",fn)
+
+#define __initcall(fn) device_initcall(fn)
+
 #define __exitcall(fn)								\
 	static exitcall_t __exitcall_##fn __exit_call = fn
 
@@ -80,7 +98,7 @@
 #define __initdata	__attribute__ ((__section__ (".data.init")))
 #define __exitdata	__attribute__ ((unused, __section__ (".data.exit")))
 #define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
-#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+#define __init_call(level)  __attribute__ ((unused,__section__ (".initcall" level ".init")))
 #define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
 
 /* For assembly routines */
@@ -140,6 +158,14 @@
 	{ return x; }
 
 #define __setup(str,func) /* nothing */
+
+#define early_arch_initcall(fn)		module_init(fn)
+#define mem_initcall(fn)		module_init(fn)
+#define subsys_initcall(fn)		module_init(fn)
+#define arch_initcall(fn)		module_init(fn)
+#define fs_initcall(fn)			module_init(fn)
+#define device_initcall(fn)		module_init(fn)
+#define late_initcall(fn)		module_init(fn)
 
 #endif
 
diff -urN linux-2.5.3-pre3/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- linux-2.5.3-pre3/include/linux/minix_fs.h	Fri Sep  7 09:45:51 2001
+++ linux/include/linux/minix_fs.h	Wed Jan 23 17:31:05 2002
@@ -89,6 +89,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/minix_fs_i.h>
+
 /*
  * change the define below to 0 if you want names > info->s_namelen chars to be
  * truncated. Else they will be disallowed (ENAMETOOLONG).
@@ -128,6 +130,11 @@
 extern struct file_operations minix_file_operations;
 extern struct file_operations minix_dir_operations;
 extern struct dentry_operations minix_dentry_operations;
+
+static inline struct minix_inode_info *minix_i(struct inode *inode)
+{
+	return list_entry(inode, struct minix_inode_info, vfs_inode);
+}
 
 #endif /* __KERNEL__ */
 
diff -urN linux-2.5.3-pre3/include/linux/minix_fs_i.h linux/include/linux/minix_fs_i.h
--- linux-2.5.3-pre3/include/linux/minix_fs_i.h	Thu Jan  4 04:07:58 1996
+++ linux/include/linux/minix_fs_i.h	Wed Jan 23 17:31:05 2002
@@ -9,6 +9,7 @@
 		__u16 i1_data[16];
 		__u32 i2_data[16];
 	} u;
+	struct inode vfs_inode;
 };
 
 #endif
diff -urN linux-2.5.3-pre3/include/linux/ncp_fs.h linux/include/linux/ncp_fs.h
--- linux-2.5.3-pre3/include/linux/ncp_fs.h	Fri Feb  9 11:29:44 2001
+++ linux/include/linux/ncp_fs.h	Wed Jan 23 17:31:05 2002
@@ -12,6 +12,7 @@
 #include <linux/in.h>
 #include <linux/types.h>
 
+#include <linux/ncp_fs_i.h>
 #include <linux/ipx.h>
 #include <linux/ncp_no.h>
 
@@ -192,7 +193,10 @@
 #define NCP_SBP(sb)		(&((sb)->u.ncpfs_sb))
 
 #define NCP_SERVER(inode)	NCP_SBP((inode)->i_sb)
-#define NCP_FINFO(inode)	(&((inode)->u.ncpfs_i))
+static inline struct ncp_inode_info *NCP_FINFO(struct inode *inode)
+{
+	return list_entry(inode, struct ncp_inode_info, vfs_inode);
+}
 
 #ifdef DEBUG_NCP_MALLOC
 
diff -urN linux-2.5.3-pre3/include/linux/ncp_fs_i.h linux/include/linux/ncp_fs_i.h
--- linux-2.5.3-pre3/include/linux/ncp_fs_i.h	Thu Jun 29 10:42:56 2000
+++ linux/include/linux/ncp_fs_i.h	Wed Jan 23 17:31:05 2002
@@ -15,16 +15,16 @@
  * all the information we need to work with an inode after creation.
  */
 struct ncp_inode_info {
-	__u32	dirEntNum __attribute__((packed));
-	__u32	DosDirNum __attribute__((packed));
-	__u32	volNumber __attribute__((packed));
+	__u32	dirEntNum;
+	__u32	DosDirNum;
+	__u32	volNumber;
 	__u32	nwattr;
 	struct semaphore open_sem;
 	atomic_t	opened;
 	int	access;
-	__u32	server_file_handle __attribute__((packed));
-	__u8	open_create_action __attribute__((packed));
-	__u8	file_handle[6] __attribute__((packed));
+	__u32	server_file_handle;
+	__u8	file_handle[6];
+	struct inode vfs_inode;
 };
 
 #endif	/* __KERNEL__ */
diff -urN linux-2.5.3-pre3/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- linux-2.5.3-pre3/include/linux/netfilter_ipv4/ip_tables.h	Thu Jul 26 13:58:46 2001
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Wed Jan 23 17:31:05 2002
@@ -428,6 +428,9 @@
 
 	/* Man behind the curtain... */
 	struct ipt_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ipt_register_table(struct ipt_table *table);
diff -urN linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_ULOG.h linux/include/linux/netfilter_ipv4/ipt_ULOG.h
--- linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_ULOG.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ULOG.h	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,46 @@
+/* Header file for IP tables userspace logging, Version 1.8
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ * 
+ * Distributed under the terms of GNU GPL */
+
+#ifndef _IPT_ULOG_H
+#define _IPT_ULOG_H
+
+#ifndef NETLINK_NFLOG
+#define NETLINK_NFLOG 	5
+#endif
+
+#define ULOG_MAC_LEN	80
+#define ULOG_PREFIX_LEN	32
+
+#define ULOG_MAX_QLEN	50
+/* Why 50? Well... there is a limit imposed by the slab cache 131000
+ * bytes. So the multipart netlink-message has to be < 131000 bytes.
+ * Assuming a standard ethernet-mtu of 1500, we could define this up
+ * to 80... but even 50 seems to be big enough. */
+
+/* private data structure for each rule with a ULOG target */
+struct ipt_ulog_info {
+	unsigned int nl_group;
+	size_t copy_range;
+	size_t qthreshold;
+	char prefix[ULOG_PREFIX_LEN];
+};
+
+/* Format of the ULOG packets passed through netlink */
+typedef struct ulog_packet_msg {
+	unsigned long mark;
+	long timestamp_sec;
+	long timestamp_usec;
+	unsigned int hook;
+	char indev_name[IFNAMSIZ];
+	char outdev_name[IFNAMSIZ];
+	size_t data_len;
+	char prefix[ULOG_PREFIX_LEN];
+	unsigned char mac_len;
+	unsigned char mac[ULOG_MAC_LEN];
+	unsigned char payload[0];
+} ulog_packet_msg_t;
+
+#endif /*_IPT_ULOG_H*/
diff -urN linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_ah.h linux/include/linux/netfilter_ipv4/ipt_ah.h
--- linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_ah.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_ah.h	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_AH_H
+#define _IPT_AH_H
+
+struct ipt_ah
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_ah. */
+#define IPT_AH_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_AH_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_AH_H*/
diff -urN linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_esp.h linux/include/linux/netfilter_ipv4/ipt_esp.h
--- linux-2.5.3-pre3/include/linux/netfilter_ipv4/ipt_esp.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/netfilter_ipv4/ipt_esp.h	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,16 @@
+#ifndef _IPT_ESP_H
+#define _IPT_ESP_H
+
+struct ipt_esp
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+
+
+/* Values for "invflags" field in struct ipt_esp. */
+#define IPT_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IPT_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IPT_ESP_H*/
diff -urN linux-2.5.3-pre3/include/linux/netfilter_ipv6/ip6_tables.h linux/include/linux/netfilter_ipv6/ip6_tables.h
--- linux-2.5.3-pre3/include/linux/netfilter_ipv6/ip6_tables.h	Thu Jul 26 13:59:06 2001
+++ linux/include/linux/netfilter_ipv6/ip6_tables.h	Wed Jan 23 17:31:05 2002
@@ -435,6 +435,9 @@
 
 	/* Man behind the curtain... */
 	struct ip6t_table_info *private;
+
+	/* Set this to THIS_MODULE if you are a module, otherwise NULL */
+	struct module *me;
 };
 
 extern int ip6t_register_table(struct ip6t_table *table);
diff -urN linux-2.5.3-pre3/include/linux/netlink.h linux/include/linux/netlink.h
--- linux-2.5.3-pre3/include/linux/netlink.h	Wed Jan 23 17:31:02 2002
+++ linux/include/linux/netlink.h	Wed Jan 23 17:31:05 2002
@@ -6,6 +6,7 @@
 #define NETLINK_USERSOCK	2	/* Reserved for user mode socket protocols 	*/
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
 #define NETLINK_TCPDIAG		4	/* TCP socket monitoring			*/
+#define NETLINK_NFLOG		5	/* netfilter/iptables ULOG */
 #define NETLINK_ARPD		8
 #define NETLINK_ROUTE6		11	/* af_inet6 route comm channel */
 #define NETLINK_IP6_FW		13
diff -urN linux-2.5.3-pre3/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.5.3-pre3/include/linux/pci.h	Mon Jan 14 13:28:08 2002
+++ linux/include/linux/pci.h	Wed Jan 23 17:31:05 2002
@@ -301,6 +301,7 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 
 /* File state for mmap()s on /proc/bus/pci/X/Y */
 enum pci_mmap_state {
@@ -363,6 +364,8 @@
 					   this is D0-D3, D0 being fully functional,
 					   and D3 being off. */
 
+	struct	device	dev;		/* Generic device interface */
+
 	/* device is compatible with these IDs */
 	unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];
 	unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];
@@ -429,6 +432,8 @@
 	unsigned char	productver;	/* product version */
 	unsigned char	checksum;	/* if zero - checksum passed */
 	unsigned char	pad1;
+
+	struct iobus	iobus;		/* Generic device interface */
 };
 
 #define pci_bus_b(n) list_entry(n, struct pci_bus, node)
@@ -525,7 +530,6 @@
 
 /* Generic PCI functions used internally */
 
-void pci_init(void);
 int pci_bus_exists(const struct list_head *list, int nr);
 struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_alloc_primary_bus(int bus);
diff -urN linux-2.5.3-pre3/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- linux-2.5.3-pre3/include/linux/reiserfs_fs.h	Mon Jan 14 09:38:36 2002
+++ linux/include/linux/reiserfs_fs.h	Wed Jan 23 17:31:05 2002
@@ -20,6 +20,7 @@
 #include <asm/unaligned.h>
 #include <linux/bitops.h>
 #include <linux/proc_fs.h>
+#include <linux/reiserfs_fs_i.h>
 #endif
 
 /*
@@ -204,9 +205,13 @@
 */
 #define MIN_PACK_ON_CLOSE		512
 
+static inline struct reiserfs_inode_info *REISERFS_I(struct inode *inode)
+{
+	return list_entry(inode, struct reiserfs_inode_info, vfs_inode);
+}
 // this says about version of all items (but stat data) the object
 // consists of
-#define inode_items_version(inode) ((inode)->u.reiserfs_i.i_version)
+#define inode_items_version(inode) (REISERFS_I(inode)->i_version)
 
 
   /* This is an aggressive tail suppression policy, I am hoping it
@@ -1257,10 +1262,10 @@
 #define UNFM_P_SIZE (sizeof(unp_t))
 
 // in in-core inode key is stored on le form
-#define INODE_PKEY(inode) ((struct key *)((inode)->u.reiserfs_i.i_key))
-//#define mark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted),1))
-//#define unmark_tail_converted(inode) (atomic_set(&((inode)->u.reiserfs_i.i_converted), 0))
-//#define is_tail_converted(inode) (atomic_read(&((inode)->u.reiserfs_i.i_converted)))
+#define INODE_PKEY(inode) ((struct key *)(REISERFS_I(inode)->i_key))
+//#define mark_tail_converted(inode) (atomic_set(&(REISERFS_I(inode)->i_converted),1))
+//#define unmark_tail_converted(inode) (REISERFS_I(inode)->i_converted), 0))
+//#define is_tail_converted(inode) (REISERFS_I(inode)->i_converted)))
 
 
 
@@ -1272,7 +1277,7 @@
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
-static inline loff_t max_reiserfs_offset (const struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
 {
     if (inode_items_version (inode) == ITEM_VERSION_1)
 	return (loff_t)U32_MAX;
@@ -1848,7 +1853,7 @@
 
 int reiserfs_prepare_write(struct file *, struct page *, unsigned, unsigned) ;
 void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
-void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset,
+void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
 		   int type, int key_length);
 void make_le_item_head (struct item_head * ih, const struct cpu_key * key, 
 			int version,
@@ -1873,7 +1878,7 @@
 void reiserfs_dirty_inode (struct inode * inode) ;
 
 struct inode * reiserfs_new_inode (struct reiserfs_transaction_handle *th, 
-				   const struct inode * dir, int mode, 
+				   struct inode * dir, int mode, 
 				   const char * symname, int item_len,
 				   struct dentry *dentry, struct inode *inode, int * err);
 int reiserfs_sync_inode (struct reiserfs_transaction_handle *th, struct inode * inode);
diff -urN linux-2.5.3-pre3/include/linux/reiserfs_fs_i.h linux/include/linux/reiserfs_fs_i.h
--- linux-2.5.3-pre3/include/linux/reiserfs_fs_i.h	Mon Jan 14 13:27:06 2002
+++ linux/include/linux/reiserfs_fs_i.h	Wed Jan 23 17:31:05 2002
@@ -46,6 +46,7 @@
   */
   unsigned long i_trans_id ;
   unsigned long i_trans_index ;
+  struct inode vfs_inode;
 };
 
 
diff -urN linux-2.5.3-pre3/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- linux-2.5.3-pre3/include/linux/rtnetlink.h	Wed Jan 23 17:31:02 2002
+++ linux/include/linux/rtnetlink.h	Wed Jan 23 17:31:05 2002
@@ -586,9 +586,9 @@
 extern void rtnetlink_init(void);
 
 #define ASSERT_RTNL() do { if (down_trylock(&rtnl_sem) == 0)  { up(&rtnl_sem); \
-printk("RTNL: assertion failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); } \
+printk("RTNL: assertion failed at " __FILE__ "(%d)\n", __LINE__); } \
 		   } while(0);
-#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
+#define BUG_TRAP(x) if (!(x)) { printk("KERNEL: assertion (" #x ") failed at " __FILE__ "(%d)\n", __LINE__); }
 
 
 #endif /* __KERNEL__ */
diff -urN linux-2.5.3-pre3/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- linux-2.5.3-pre3/include/linux/sysv_fs.h	Fri Nov  9 13:45:35 2001
+++ linux/include/linux/sysv_fs.h	Wed Jan 23 17:31:05 2002
@@ -21,6 +21,15 @@
 #include <linux/sched.h>	/* declares wake_up() */
 #include <linux/sysv_fs_sb.h>	/* defines the sv_... shortcuts */
 
+/* temporary hack. */
+#include <linux/sysv_fs_i.h>
+static inline struct sysv_inode_info *SYSV_I(struct inode *inode)
+{
+	/* I think list_entry should have a more descriptive name..  --hch */
+	return list_entry(inode, struct sysv_inode_info, vfs_inode);
+}
+/* end temporary hack. */
+
 
 /* Layout on disk */
 /* ============== */
diff -urN linux-2.5.3-pre3/include/linux/sysv_fs_i.h linux/include/linux/sysv_fs_i.h
--- linux-2.5.3-pre3/include/linux/sysv_fs_i.h	Fri Nov  9 13:45:35 2001
+++ linux/include/linux/sysv_fs_i.h	Wed Jan 23 17:31:05 2002
@@ -11,6 +11,7 @@
 				 * then 1 triple indirection block.
 				 */
 	u32 i_dir_start_lookup;
+	struct inode  vfs_inode;
 };
 
 #endif
diff -urN linux-2.5.3-pre3/include/linux/time.h linux/include/linux/time.h
--- linux-2.5.3-pre3/include/linux/time.h	Mon Jan 14 13:27:05 2002
+++ linux/include/linux/time.h	Wed Jan 23 17:31:05 2002
@@ -100,8 +100,6 @@
 #ifdef __KERNEL__
 extern void do_gettimeofday(struct timeval *tv);
 extern void do_settimeofday(struct timeval *tv);
-extern void get_fast_time(struct timeval *tv);
-extern void (*do_get_fast_time)(struct timeval *);
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
diff -urN linux-2.5.3-pre3/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h
--- linux-2.5.3-pre3/include/linux/udf_fs_i.h	Mon Jul  2 14:10:02 2001
+++ linux/include/linux/udf_fs_i.h	Wed Jan 23 17:31:05 2002
@@ -47,6 +47,7 @@
 	unsigned i_strat_4096 : 1;
 	unsigned i_new_inode : 1;
 	unsigned reserved : 26;
+	struct inode vfs_inode;
 };
 
 #endif
diff -urN linux-2.5.3-pre3/init/main.c linux/init/main.c
--- linux-2.5.3-pre3/init/main.c	Wed Jan 23 17:31:02 2002
+++ linux/init/main.c	Wed Jan 23 17:31:05 2002
@@ -38,35 +38,10 @@
 #include <asm/ccwcache.h>
 #endif
 
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#ifdef CONFIG_DIO
-#include <linux/dio.h>
-#endif
-
-#ifdef CONFIG_ZORRO
-#include <linux/zorro.h>
-#endif
-
 #ifdef CONFIG_MTRR
 #  include <asm/mtrr.h>
 #endif
 
-#ifdef CONFIG_NUBUS
-#include <linux/nubus.h>
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-#endif
-
-#ifdef CONFIG_IRDA
-extern int irda_proto_init(void);
-extern int irda_device_init(void);
-#endif
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
@@ -92,10 +67,8 @@
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern int init_pcmcia_ds(void);
 
 extern void free_initmem(void);
 
@@ -103,8 +76,6 @@
 extern void tc_init(void);
 #endif
 
-extern void ecard_init(void);
-
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -492,50 +463,11 @@
 	/* bring up the device tree */
 	device_driver_init();
 
-#ifdef CONFIG_PCI
-	pci_init();
-#endif
-#ifdef CONFIG_SBUS
-	sbus_init();
-#endif
-#if defined(CONFIG_PPC)
-	ppc_init();
-#endif
-#ifdef CONFIG_MCA
-	mca_init();
-#endif
-#ifdef CONFIG_ARCH_ACORN
-	ecard_init();
-#endif
-#ifdef CONFIG_ZORRO
-	zorro_init();
-#endif
-#ifdef CONFIG_DIO
-	dio_init();
-#endif
-#ifdef CONFIG_NUBUS
-	nubus_init();
-#endif
-#ifdef CONFIG_ISAPNP
-	isapnp_init();
-#endif
-#ifdef CONFIG_TC
-	tc_init();
-#endif
-
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
 	start_context_thread();
 	do_initcalls();
-
-#ifdef CONFIG_IRDA
-	irda_proto_init();
-	irda_device_init(); /* Must be done after protocol initialization */
-#endif
-#ifdef CONFIG_PCMCIA
-	init_pcmcia_ds();		/* Do this last */
-#endif
 }
 
 extern void prepare_namespace(void);
diff -urN linux-2.5.3-pre3/kernel/device.c linux/kernel/device.c
--- linux-2.5.3-pre3/kernel/device.c	Mon Jan 14 13:25:16 2002
+++ linux/kernel/device.c	Wed Jan 23 17:31:05 2002
@@ -51,46 +51,37 @@
 
 static spinlock_t device_lock;
 
-static ssize_t device_read_status(char *, size_t, loff_t, void *);
-static ssize_t device_write_status(const char *, size_t, loff_t, void *);
+static ssize_t device_read_status(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_status(struct device *,const char *, size_t, loff_t);
 
-static struct driverfs_operations device_status_ops = {
-	read:	device_read_status,
-	write:	device_write_status,
+static struct driver_file_entry device_status_entry = {
+	name:		"status",
+	mode:		S_IWUSR | S_IRUGO,
+	show:		device_read_status,
+	store:		device_write_status,
 };
 
-static ssize_t device_read_power(char *, size_t, loff_t, void *);
-static ssize_t device_write_power(const char *, size_t, loff_t, void *);
+static ssize_t device_read_power(struct device *, char *, size_t, loff_t);
+static ssize_t device_write_power(struct device *, const char *, size_t, loff_t);
 
-static struct driverfs_operations device_power_ops = {
-	read:	device_read_power,
-	write:	device_write_power,
+static struct driver_file_entry device_power_entry = {
+	name:		"power",
+	mode:		S_IWUSR | S_IRUGO,
+	show:		device_read_power,
+	store:		device_write_power,
 };
 
-static ssize_t iobus_read_status(char *, size_t, loff_t, void *);
-static ssize_t iobus_write_status(const char *, size_t, loff_t, void *);
-
-static struct driverfs_operations iobus_status_ops = {
-	read:	iobus_read_status,
-	write:	iobus_write_status,
-};
-
-
 /**
  * device_create_file - create a driverfs file for a device
  * @dev:	device requesting file
- * @name:	name of file
- * @mode:	permissions of file
- * @ops:	operations for the file
- * @data:	private data for the file
+ * @entry:	entry describing file
  *
- * Create a driverfs entry, then create the actual file the entry describes.
+ * Allocate space for file entry, copy descriptor, and create.
  */
-int device_create_file(struct device * dev, const char * name, mode_t mode,
-		       struct driverfs_operations * ops, void * data)
+int device_create_file(struct device * dev, struct driver_file_entry * entry)
 {
-	int error = -EFAULT;
-	struct driver_file_entry * entry;
+	struct driver_file_entry * new_entry;
+	int error = -ENOMEM;
 
 	if (!dev)
 		return -EINVAL;
@@ -98,10 +89,15 @@
 	if (!valid_device(dev))
 		return -EFAULT;
 
-	entry = driverfs_create_entry(name,mode,ops,data);
-	if (entry)
-		error = driverfs_create_file(entry,dev->dir);
+	new_entry = kmalloc(sizeof(*new_entry),GFP_KERNEL);
+	if (!new_entry)
+		goto done;
 
+	memcpy(new_entry,entry,sizeof(*entry));
+	error = driverfs_create_file(new_entry,&dev->dir);
+	if (error)
+		kfree(new_entry);
+ done:
 	put_device(dev);
 	return error;
 }
@@ -120,7 +116,7 @@
 	if (!valid_device(dev))
 		return;
 
-	driverfs_remove_file(dev->dir,name);
+	driverfs_remove_file(&dev->dir,name);
 
 	put_device(dev);
 }
@@ -131,18 +127,8 @@
  */
 void device_remove_dir(struct device * dev)
 {
-	struct driver_dir_entry * dir;
-
-	if (!dev)
-		return;
-
-	lock_device(dev);
-	dir = dev->dir;
-	dev->dir = NULL;
-	unlock_device(dev);
-
-	if (dir)
-		driverfs_remove_dir(dir);
+	if (dev)
+		driverfs_remove_dir(&dev->dir);
 }
 
 /**
@@ -159,128 +145,52 @@
  */
 static int device_make_dir(struct device * dev)
 {
-	struct driver_dir_entry * entry;
+	struct driver_dir_entry * parent = NULL;
 	int error;
 
-	entry = driverfs_create_dir_entry(dev->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-	if (!entry)
-		return -EFAULT;
+	INIT_LIST_HEAD(&dev->dir.files);
+	dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	dev->dir.name = dev->bus_id;
 
-	error = driverfs_create_dir(entry,dev->parent->dir);
+	if (dev->parent)
+		parent = &dev->parent->dir;
 
-	if (error) {
-		kfree(entry);
-		return error;
-	}
+	error = driverfs_create_dir(&dev->dir,parent);
 
-	lock_device(dev);
-	dev->dir = entry;
-	unlock_device(dev);
+	if (error)
+		return error;
 
-	/* first the status file */
-	error = device_create_file(dev, "status", S_IRUGO | S_IWUSR,
-				   &device_status_ops, (void *) dev);
+	error = device_create_file(dev,&device_status_entry);
 	if (error) {
 		device_remove_dir(dev);
 		goto done;
 	}
-
-	/* now the power file */
-	error = device_create_file(dev,"power",S_IRUGO | S_IWUSR,
-				   &device_power_ops, (void *) dev);
-	if (error)
+	error = device_create_file(dev,&device_power_entry);
+	if (error) 
 		device_remove_dir(dev);
-
  done:
 	return error;
 }
 
-/* iobus interface.
- * For practical purposes, it's exactly the same as the device interface above.
- * Even below, the two are almost identical, only taking different pointer
- * types.
- * I have fantasized about removing struct iobus completely. It would reduce
- * this file by about 30%, and make life much easier. However, it will take some
- * time to really work everything out..
- */
-
-int iobus_create_file(struct iobus * iobus, const char * name, mode_t mode,
-		      struct driverfs_operations * ops, void * data)
-{
-	int error = -EFAULT;
-	struct driver_file_entry * entry;
-
-	if (!iobus)
-		return -EINVAL;
-
-	if (!valid_iobus(iobus))
-		return -EFAULT;
-
-	entry = driverfs_create_entry(name,mode,ops,data);
-	if (entry)
-		error = driverfs_create_file(entry,iobus->dir);
-
-	put_iobus(iobus);
-	return error;
-}
-
-void iobus_remove_file(struct iobus * iobus, const char * name)
-{
-	if (!iobus)
-		return;
-
-	if (!valid_iobus(iobus))
-		return;
-
-	driverfs_remove_file(iobus->dir,name);
-
-	put_iobus(iobus);
-}
-
 void iobus_remove_dir(struct iobus * iobus)
 {
-	struct driver_dir_entry * dir;
-
-	if (!iobus)
-		return;
-
-	lock_iobus(iobus);
-	dir = iobus->dir;
-	iobus->dir = NULL;
-	unlock_iobus(iobus);
-
-	if (dir)
-		driverfs_remove_dir(dir);
+	if (iobus)
+		driverfs_remove_dir(&iobus->dir);
 }
 
 static int iobus_make_dir(struct iobus * iobus)
 {
-	struct driver_dir_entry * entry;
 	struct driver_dir_entry * parent = NULL;
 	int error;
 
-	entry = driverfs_create_dir_entry(iobus->bus_id,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-	if (!entry)
-		return -EFAULT;
+	INIT_LIST_HEAD(&iobus->dir.files);
+	iobus->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	iobus->dir.name = iobus->bus_id;
 
 	if (iobus->parent)
-		parent = iobus->parent->dir;
-
-	error = driverfs_create_dir(entry,parent);
-	if (error) {
-		kfree(entry);
-		return error;
-	}
-
-	lock_iobus(iobus);
-	iobus->dir = entry;
-	unlock_iobus(iobus);
-
-	error = iobus_create_file(iobus, "status", S_IRUGO | S_IWUSR,
-				  &iobus_status_ops, (void *)iobus);
-	if (error)
-		iobus_remove_dir(iobus);
+		parent = &iobus->parent->dir;
 
+	error = driverfs_create_dir(&iobus->dir,parent);
 	return error;
 }
 
@@ -304,6 +214,9 @@
 		dev->parent = &device_root;
 	parent = dev->parent;
 
+	DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
+	    dev->bus_id, dev->name, parent->bus_id);
+
 	if (valid_iobus(parent)) {
 		if (!valid_device(dev)) {
 			put_iobus(parent);
@@ -327,15 +240,10 @@
 	list_add_tail(&dev->node, &parent->devices);
 	unlock_iobus(parent);
 
-	DBG("DEV: registering device: ID = '%s', name = %s, parent = %s\n",
-	    dev->bus_id, dev->name, parent->bus_id);
-
 	/* notify platform of device entry */
 	if (platform_notify)
 		platform_notify(dev);
 
-	return 0;
-
  register_done:
 	put_device(dev);
 	put_iobus(parent);
@@ -430,8 +338,6 @@
 	list_add_tail(&bus->node,&parent->children);
 	unlock_iobus(parent);
 
-	return 0;
-
  register_done_put:
 	put_iobus(bus);
 	put_iobus(parent);
@@ -533,45 +439,6 @@
 	return bus;
 }
 
-static int do_device_suspend(struct device * dev, u32 state)
-{
-	int error = 0;
-
-	if (!dev->driver->suspend)
-		return error;
-
-	error = dev->driver->suspend(dev,state,SUSPEND_NOTIFY);
-
-	if (error)
-		return error;
-
-	error = dev->driver->suspend(dev,state,SUSPEND_SAVE_STATE);
-	if (error) {
-		if (dev->driver->resume)
-			dev->driver->resume(dev,RESUME_RESTORE_STATE);
-		return error;
-	}
-	error = dev->driver->suspend(dev,state,SUSPEND_POWER_DOWN);
-	if (error) {
-		if (dev->driver->resume)
-			dev->driver->resume(dev,RESUME_RESTORE_STATE);
-	}
-	return error;
-}
-
-static int do_device_resume(struct device * dev)
-{
-	int error = 0;
-
-	if (!dev->driver->resume)
-		return 0;
-	error = dev->driver->resume(dev,RESUME_POWER_ON);
-	if (error)
-		return error;
-	error = dev->driver->resume(dev,RESUME_RESTORE_STATE);
-	return error;
-}
-
 /**
  * device_read_status - report some device information
  * @page:	page-sized buffer to write into
@@ -582,37 +449,17 @@
  * Report some human-readable information about the device.
  * This includes the name, the bus id, and the current power state.
  */
-static ssize_t device_read_status(char * page, size_t count,
-				  loff_t off, void * data)
+static ssize_t device_read_status(struct device * dev, char * page, size_t count, loff_t off)
 {
 	char *str = page;
-	struct device *dev = (struct device*)data;
-	ssize_t len = 0;
-
-	if (!dev)
-		return -EINVAL;
-
-	if (!valid_device(dev))
-		return -EFAULT;
 
 	if (off)
-		goto done;
+		return 0;
 
 	str += sprintf(str,"Name:       %s\n",dev->name);
 	str += sprintf(str,"Bus ID:     %s\n",dev->bus_id);
 
-	len = str - page;
-
-	if (len > count)
-		len = count;
-
-	if (len < 0)
-		len = 0;
-
- done:
-	put_device(dev);
-
-	return len;
+	return (str - page);
 }
 
 /**
@@ -631,31 +478,24 @@
  * (See Documentation/driver-model.txt for the theory of an n-stage
  * suspend sequence).
  */
-static ssize_t device_write_status(const char* buf, size_t count, loff_t off, void *data)
+static ssize_t device_write_status(struct device * dev, const char* buf, size_t count, loff_t off)
 {
 	char command[20];
-	struct device *dev = (struct device *)data;
 	int num;
 	int arg = 0;
 	int error = 0;
 
-	if (!dev)
-		return 0;
-
-	if (!valid_device(dev))
-		return -EFAULT;
-
 	if (off)
-		goto done_put;
+		return 0;
 
 	/* everything involves dealing with the driver. */
 	if (!dev->driver)
-		goto done_put;
+		return 0;
 
 	num = sscanf(buf,"%10s %d",command,&arg);
 
 	if (!num)
-		goto done_put;
+		return 0;
 
 	if (!strcmp(command,"probe")) {
 		if (dev->driver->probe)
@@ -666,50 +506,25 @@
 			error = dev->driver->remove(dev,REMOVE_NOTIFY);
 	} else
 		error = -EFAULT;
-
- done_put:
-	put_device(dev);
 	return error < 0 ? error : count;
 }
 
 static ssize_t
-device_read_power(char * page, size_t count, loff_t off, void * data)
+device_read_power(struct device * dev, char * page, size_t count, loff_t off)
 {
 	char	* str = page;
-	struct	device * dev = (struct device *)data;
-	ssize_t len = 0;
 
-	if (!dev)
-		return 0;
-
-	if (!valid_device(dev))
+	if (off)
 		return 0;
 
 	str += sprintf(str,"State:      %d\n",dev->current_state);
 
-	len = str - page;
-
-	if (off) {
-		if (len < off) {
-			len = 0;
-			goto done;
-		}
-		str += off;
-		len -= off;
-	}
-
-	if (len > count)
-		len = count;
-
- done:
-	put_device(dev);
-	return len;
+	return (str - page);
 }
 
 static ssize_t
-device_write_power(const char * buf, size_t count, loff_t off, void * data)
+device_write_power(struct device * dev, const char * buf, size_t count, loff_t off)
 {
-	struct	device * dev = (struct device *)data;
 	char	str_command[20];
 	char	str_stage[20];
 	int	num_args;
@@ -717,14 +532,9 @@
 	u32	int_stage;
 	int	error = 0;
 
-	if (!dev)
+	if (off)
 		return 0;
 
-	if (!valid_device(dev))
-		return -EFAULT;
-
-	if (off)
-		goto done;
 	if (!dev->driver)
 		goto done;
 
@@ -772,107 +582,6 @@
 			error = 0;
 	}
  done:
-	put_device(dev);
-
-	DBG("%s: returning %d\n",__FUNCTION__,error);
-
-	return error < 0 ? error : count;
-}
-
-/**
- * bus_read_status - report human readable information
- * @page:	page-sized buffer to write into
- * @count:	number of bytes requested
- * @off:	offset into buffer to start at
- * @data:	bus-specific data
- */
-static ssize_t iobus_read_status(char *page, size_t count,
-				 loff_t off, void *data)
-{
-	char *str = page;
-	struct iobus *bus = (struct iobus*)data;
-	ssize_t len = 0;
-
-	if (!bus)
-		return -EINVAL;
-
-	if (!valid_iobus(bus))
-		return -EFAULT;
-
-	if (off)
-		goto done;
-
-	str += sprintf(str,"Name:       %s\n",bus->name);
-	str += sprintf(str,"Bus ID:     %s\n",bus->bus_id);
-
-	if (bus->driver)
-		str += sprintf(str,"Type:       %s\n",bus->driver->name);
-
-	len = str - page;
-	if (len < off)
-		len = 0;
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-
- done:
-	put_iobus(bus);
-	return len;
-}
-
-/**
- * bus_write_status - forward a command to a bus
- * @buf:	string encoded command
- * @count:	number of bytes requested
- * @off:	offset into buffer to start at
- * @data:	bus-specific data
- *
- * Like device_write_status, this sends a command to a bus driver.
- * Supported actions are:
- * scan - scan a bus for devices
- * add_device <id> - add a child device
- */
-static ssize_t iobus_write_status(const char *buf, size_t count, loff_t off, void *data)
-{
-	char command[10];
-	char which[15];
-	char id[10];
-	struct iobus *bus = (struct iobus*)data;
-	int num;
-	int error = -EINVAL;
-
-	if (!bus)
-		return -EINVAL;
-
-	if (!valid_iobus(bus))
-		return -EFAULT;
-
-	if (!bus->driver)
-		goto done;
-
-	num = sscanf(buf,"%10s %15s %10s",command,which,id);
-
-	if (!num)
-		goto done;
-
-	if (!strnicmp(command,"scan",4)) {
-		if (bus->driver->scan)
-			error = bus->driver->scan(bus);
-	} else if (!strnicmp(command,"add",3) && num == 2) {
-		error = bus->driver->add_device(bus,id);
-	} else if (!strnicmp(command, "suspend",7)) {
-		u32 state = simple_strtoul(which,NULL,0);
-		if (state > 0)
-			error = do_device_suspend(bus->self,state);
-
-	} else if (!strnicmp(command,"resume",6)) {
-		error = do_device_resume(bus->self);
-
-	}
-
- done:
-	put_iobus(bus);
 	return error < 0 ? error : count;
 }
 
@@ -885,9 +594,7 @@
 	 * needs to do is create the root directory. Easier
 	 * to just do it here than special case it elsewhere..
 	 */
-	iobus_make_dir(&device_root);
-
-	return (device_root.dir ? 0 : -EFAULT);
+	return iobus_make_dir(&device_root);
 }
 
 int __init device_driver_init(void)
@@ -937,8 +644,5 @@
 EXPORT_SYMBOL(iobus_register);
 EXPORT_SYMBOL(iobus_alloc);
 EXPORT_SYMBOL(iobus_init);
-
-EXPORT_SYMBOL(iobus_create_file);
-EXPORT_SYMBOL(iobus_remove_file);
 
 EXPORT_SYMBOL(device_driver_init);
diff -urN linux-2.5.3-pre3/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.5.3-pre3/kernel/ksyms.c	Wed Jan 23 17:31:02 2002
+++ linux/kernel/ksyms.c	Wed Jan 23 17:31:05 2002
@@ -271,6 +271,8 @@
 EXPORT_SYMBOL(lock_may_read);
 EXPORT_SYMBOL(lock_may_write);
 EXPORT_SYMBOL(dcache_readdir);
+EXPORT_SYMBOL(fd_install);
+EXPORT_SYMBOL(put_unused_fd);
 
 /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
 EXPORT_SYMBOL(default_llseek);
@@ -533,9 +535,6 @@
 
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
-
-/* time */
-EXPORT_SYMBOL(get_fast_time);
 
 /* library functions */
 EXPORT_SYMBOL(strnicmp);
diff -urN linux-2.5.3-pre3/kernel/time.c linux/kernel/time.c
--- linux-2.5.3-pre3/kernel/time.c	Mon Oct 16 12:58:51 2000
+++ linux/kernel/time.c	Wed Jan 23 17:31:05 2002
@@ -36,24 +36,6 @@
  */
 struct timezone sys_tz;
 
-static void do_normal_gettime(struct timeval * tm)
-{
-        *tm=xtime;
-}
-
-void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
-
-/*
- * Generic way to access 'xtime' (the current time of day).
- * This can be changed if the platform provides a more accurate (and fast!) 
- * version.
- */
-
-void get_fast_time(struct timeval * t)
-{
-	do_get_fast_time(t);
-}
-
 /* The xtime_lock is not only serializing the xtime read/writes but it's also
    serializing all accesses to the global NTP variables now. */
 extern rwlock_t xtime_lock;
diff -urN linux-2.5.3-pre3/net/bridge/br_fdb.c linux/net/bridge/br_fdb.c
--- linux-2.5.3-pre3/net/bridge/br_fdb.c	Thu Nov  9 15:57:53 2000
+++ linux/net/bridge/br_fdb.c	Wed Jan 23 17:31:05 2002
@@ -5,7 +5,7 @@
  *	Authors:
  *	Lennert Buytenhek		<buytenh@gnu.org>
  *
- *	$Id: br_fdb.c,v 1.5 2000/11/08 05:16:40 davem Exp $
+ *	$Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -292,7 +292,8 @@
 	write_lock_bh(&br->hash_lock);
 	fdb = br->hash[hash];
 	while (fdb != NULL) {
-		if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
+		if (!fdb->is_local &&
+		    !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
 			__fdb_possibly_replace(fdb, source, is_local);
 			write_unlock_bh(&br->hash_lock);
 			return;
diff -urN linux-2.5.3-pre3/net/core/dev.c linux/net/core/dev.c
--- linux-2.5.3-pre3/net/core/dev.c	Wed Jan 23 17:31:02 2002
+++ linux/net/core/dev.c	Wed Jan 23 17:31:05 2002
@@ -239,7 +239,7 @@
 
 #ifdef CONFIG_NET_FASTROUTE
 	/* Hack to detect packet socket */
-	if (pt->data) {
+	if ((pt->data) && ((int)(pt->data)!=1)) {
 		netdev_fastroute_obstacles++;
 		dev_clear_fastroute(pt->dev);
 	}
@@ -876,7 +876,7 @@
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct packet_type *ptype;
-	get_fast_time(&skb->stamp);
+	do_gettimeofday(&skb->stamp);
 
 	br_read_lock(BR_NETPROTO_LOCK);
 	for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 
@@ -1219,7 +1219,7 @@
 	unsigned long flags;
 
 	if (skb->stamp.tv_sec == 0)
-		get_fast_time(&skb->stamp);
+		do_gettimeofday(&skb->stamp);
 
 	/* The code is rearranged so that the path is the most
 	   short when CPU is congested, but is still operating.
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
--- linux-2.5.3-pre3/net/ipv4/netfilter/Config.in	Wed Jan 23 17:31:02 2002
+++ linux/net/ipv4/netfilter/Config.in	Wed Jan 23 17:31:05 2002
@@ -21,6 +21,7 @@
   dep_tristate '  netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
   dep_tristate '  Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+  dep_tristate '  AH/ESP match support' CONFIG_IP_NF_MATCH_AH_ESP $CONFIG_IP_NF_IPTABLES
   dep_tristate '  LENGTH match support' CONFIG_IP_NF_MATCH_LENGTH $CONFIG_IP_NF_IPTABLES
   dep_tristate '  TTL match support' CONFIG_IP_NF_MATCH_TTL $CONFIG_IP_NF_IPTABLES
   dep_tristate '  tcpmss match support' CONFIG_IP_NF_MATCH_TCPMSS $CONFIG_IP_NF_IPTABLES
@@ -74,6 +75,9 @@
     dep_tristate '    MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
   fi
   dep_tristate '  LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+  if [ "$CONFIG_NETLINK" != "n" ]; then
+     dep_tristate '  ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_NETLINK $CONFIG_IP_NF_IPTABLES
+  fi
   dep_tristate '  TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
 fi
 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
--- linux-2.5.3-pre3/net/ipv4/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/Makefile	Wed Jan 23 17:31:05 2002
@@ -56,6 +56,7 @@
 obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
 obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
 obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
 
@@ -73,6 +74,7 @@
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
 obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
 obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
 obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
 
 # backwards compatibility 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ip_fw_compat_masq.c	Fri Sep 14 14:04:08 2001
+++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c	Wed Jan 23 17:31:05 2002
@@ -157,7 +157,7 @@
 		/* Fall thru... */
 	case IPPROTO_TCP:
 	case IPPROTO_UDP:
-		IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
+		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
 		if (!get_tuple(iph, (*pskb)->len, &tuple, protocol)) {
 			if (net_ratelimit())
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ip_nat_rule.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_rule.c	Wed Jan 23 17:31:05 2002
@@ -104,7 +104,7 @@
 
 static struct ipt_table nat_table
 = { { NULL, NULL }, "nat", &nat_initial_table.repl,
-    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    NAT_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 LIST_HEAD(nat_expect_list);
 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ip_tables.c linux/net/ipv4/netfilter/ip_tables.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ip_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv4/netfilter/ip_tables.c	Wed Jan 23 17:31:05 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2009-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -84,6 +89,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP_NUMHOOKS];
@@ -902,6 +909,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1105,6 +1113,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1363,7 +1381,7 @@
 	int ret;
 	struct ipt_table_info *newinfo;
 	static struct ipt_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
@@ -1406,6 +1424,9 @@
 
 	duprintf("table->private->number = %u\n",
 		 table->private->number);
+	
+	/* save number of initial entries */
+	table->private->initial_entries = table->private->number;
 
 	table->lock = RW_LOCK_UNLOCKED;
 	list_prepend(&ipt_tables, table);
@@ -1746,7 +1767,7 @@
 	}
 #endif
 
-	printk("ip_tables: (c)2000 Netfilter core team\n");
+	printk("ip_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipchains_core.c linux/net/ipv4/netfilter/ipchains_core.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipchains_core.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipchains_core.c	Wed Jan 23 17:31:05 2002
@@ -838,6 +838,7 @@
 			i->branch->refcount--;
 		kfree(i);
 		i = tmp;
+		MOD_DEC_USE_COUNT;
 	}
 	return 0;
 }
@@ -875,13 +876,16 @@
 		 * interrupts is not necessary. */
 		chainptr->chain = rule;
 		if (rule->branch) rule->branch->refcount++;
-		return 0;
+		goto append_successful;
 	}
 
 	/* Find the rule before the end of the chain */
 	for (i = chainptr->chain; i->next; i = i->next);
 	i->next = rule;
 	if (rule->branch) rule->branch->refcount++;
+
+append_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -900,7 +904,7 @@
 		frwl->next = chainptr->chain;
 		if (frwl->branch) frwl->branch->refcount++;
 		chainptr->chain = frwl;
-		return 0;
+		goto insert_successful;
 	}
 	position--;
 	while (--position && f != NULL) f = f->next;
@@ -910,6 +914,9 @@
 	frwl->next = f->next;
 
 	f->next = frwl;
+
+insert_successful:
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -943,6 +950,8 @@
 		i->next = i->next->next;
 		kfree(tmp);
 	}
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1049,6 +1058,7 @@
 		else
 			chainptr->chain = ftmp->next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT;
 		break;
 	}
 
@@ -1089,6 +1099,8 @@
 
 	tmp->next = tmp2->next;
 	kfree(tmp2);
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1141,6 +1153,7 @@
 					      * user defined chain *
 					      * and therefore can be
 					      * deleted */
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipfwadm_core.c linux/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipfwadm_core.c	Thu Sep 20 14:12:56 2001
+++ linux/net/ipv4/netfilter/ipfwadm_core.c	Wed Jan 23 17:31:05 2002
@@ -20,7 +20,7 @@
  *	license in recognition of the original copyright.
  *				-- Alan Cox.
  *
- *	$Id: ipfwadm_core.c,v 1.9 2001/09/18 22:29:10 davem Exp $
+ *	$Id: ipfwadm_core.c,v 1.10 2002/01/23 13:20:54 davem Exp $
  *
  *	Ported from BSD to Linux,
  *		Alan Cox 22/Nov/1994.
@@ -104,6 +104,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -687,6 +688,7 @@
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
 		kfree(ftmp);
+		MOD_DEC_USE_COUNT();
 	}
 	restore_flags(flags);
 }
@@ -730,6 +732,7 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT();
 	return(0);
 }
 
@@ -780,6 +783,7 @@
 	else
         	*chainptr=ftmp;
 	restore_flags(flags);
+	MOD_INC_USE_COUNT();
 	return(0);
 }
 
@@ -853,9 +857,10 @@
 		 }
 	}
 	restore_flags(flags);
-	if (was_found)
+	if (was_found) {
+		MOD_DEC_USE_COUNT();
 		return 0;
-	else
+	} else
 		return(EINVAL);
 }
 
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipt_LOG.c linux/net/ipv4/netfilter/ipt_LOG.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipt_LOG.c	Mon Nov  5 09:53:07 2001
+++ linux/net/ipv4/netfilter/ipt_LOG.c	Wed Jan 23 17:31:05 2002
@@ -217,7 +217,7 @@
 				printk("[");
 				dump_packet(info,
 					    (struct iphdr *)(icmph + 1),
-					    datalen-sizeof(struct iphdr),
+					    datalen-sizeof(struct icmphdr),
 					    0);
 				printk("] ");
 			}
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipt_REDIRECT.c linux/net/ipv4/netfilter/ipt_REDIRECT.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipt_REDIRECT.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/ipt_REDIRECT.c	Wed Jan 23 17:31:05 2002
@@ -74,10 +74,17 @@
 	/* Local packets: make them go to loopback */
 	if (hooknum == NF_IP_LOCAL_OUT)
 		newdst = htonl(0x7F000001);
-	else
+	else {
+		struct in_device *indev;
+
+		/* Device might not have an associated in_device. */
+		indev = (struct in_device *)(*pskb)->dev->ip_ptr;
+		if (indev == NULL)
+			return NF_DROP;
+
 		/* Grab first address on interface. */
-		newdst = (((struct in_device *)(*pskb)->dev->ip_ptr)
-			  ->ifa_list->ifa_local);
+		newdst = indev->ifa_list->ifa_local;
+	}
 
 	/* Transfer from original range. */
 	newrange = ((struct ip_nat_multi_range)
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipt_ULOG.c linux/net/ipv4/netfilter/ipt_ULOG.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipt_ULOG.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ULOG.c	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,349 @@
+/*
+ * netfilter module for userspace packet logging daemons
+ *
+ * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
+ *
+ * 2000/09/22 ulog-cprange feature added
+ * 2001/01/04 in-kernel queue as proposed by Sebastian Zander 
+ * 						<zander@fokus.gmd.de>
+ * 2001/01/30 per-rule nlgroup conflicts with global queue. 
+ *            nlgroup now global (sysctl)
+ * 2001/04/19 ulog-queue reworked, now fixed buffer size specified at
+ * 	      module loadtime -HW
+ *
+ * Released under the terms of the GPL
+ *
+ * This module accepts two parameters: 
+ * 
+ * nlbufsiz:
+ *   The parameter specifies how big the buffer for each netlink multicast
+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
+ * get accumulated in the kernel until they are sent to userspace. It is
+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
+ * because atomically allocating 128kB inside the network rx softirq is not
+ * reliable. Please also keep in mind that this buffer size is allocated for
+ * each nlgroup you are using, so the total kernel memory usage increases
+ * by that factor.
+ *
+ * flushtimeout:
+ *   Specify, after how many clock ticks (intel: 100 per second) the queue
+ * should be flushed even if it is not full yet.
+ *
+ * ipt_ULOG.c,v 1.15 2002/01/18 21:33:19 laforge Exp
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/netlink.h>
+#include <linux/netdevice.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_ULOG.h>
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+
+#define ULOG_NL_EVENT		111		/* Harald's favorite number */
+#define ULOG_MAXNLGROUPS	32		/* numer of nlgroups */
+
+#if 0
+#define DEBUGP(format, args...)	printk(__FILE__ ":" __FUNCTION__ ":" \
+				       format, ## args)
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format, ## args); } while (0);
+
+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
+MODULE_DESCRIPTION("IP tables userspace logging module");
+
+
+static unsigned int nlbufsiz = 4096;
+MODULE_PARM(nlbufsiz, "i");
+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
+
+static unsigned int flushtimeout = 10 * HZ;
+MODULE_PARM(flushtimeout, "i");
+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout");
+
+/* global data structures */
+
+typedef struct {
+	unsigned int qlen;		/* number of nlmsgs' in the skb */
+	struct nlmsghdr *lastnlh;	/* netlink header of last msg in skb */
+	struct sk_buff *skb;		/* the pre-allocated skb */
+	struct timer_list timer;	/* the timer function */
+} ulog_buff_t;
+
+static ulog_buff_t ulog_buffers[ULOG_MAXNLGROUPS];	/* array of buffers */
+
+static struct sock *nflognl;	/* our socket */
+static size_t qlen;		/* current length of multipart-nlmsg */
+DECLARE_LOCK(ulog_lock);	/* spinlock */
+
+/* send one ulog_buff_t to userspace */
+static void ulog_send(unsigned int nlgroup)
+{
+	ulog_buff_t *ub = &ulog_buffers[nlgroup];
+
+	if (timer_pending(&ub->timer)) {
+		DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+		del_timer(&ub->timer);
+	}
+
+	/* last nlmsg needs NLMSG_DONE */
+	if (ub->qlen > 1)
+		ub->lastnlh->nlmsg_type = NLMSG_DONE;
+
+	NETLINK_CB(ub->skb).dst_groups = nlgroup;
+	DEBUGP("ipt_ULOG: throwing %d packets to netlink mask %u\n",
+		ub->qlen, nlgroup);
+	netlink_broadcast(nflognl, ub->skb, 0, nlgroup, GFP_ATOMIC);
+
+	ub->qlen = 0;
+	ub->skb = NULL;
+	ub->lastnlh = NULL;
+
+}
+
+
+/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */
+static void ulog_timer(unsigned long data)
+{
+	DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+
+	/* lock to protect against somebody modifying our structure
+	 * from ipt_ulog_target at the same time */
+	LOCK_BH(&ulog_lock);
+	ulog_send(data);
+	UNLOCK_BH(&ulog_lock);
+}
+
+static void nflog_rcv(struct sock *sk, int len)
+{
+	printk("ipt_ULOG:nflog_rcv() did receive netlink message ?!?\n");
+}
+
+struct sk_buff *ulog_alloc_skb(unsigned int size)
+{
+	struct sk_buff *skb;
+
+	/* alloc skb which should be big enough for a whole
+	 * multipart message. WARNING: has to be <= 131000
+	 * due to slab allocator restrictions */
+
+	skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+	if (!skb) {
+		PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
+			nlbufsiz);
+
+		/* try to allocate only as much as we need for 
+		 * current packet */
+
+		skb = alloc_skb(size, GFP_ATOMIC);
+		if (!skb)
+			PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+	}
+
+	return skb;
+}
+
+static unsigned int ipt_ulog_target(struct sk_buff **pskb,
+				    unsigned int hooknum,
+				    const struct net_device *in,
+				    const struct net_device *out,
+				    const void *targinfo, void *userinfo)
+{
+	ulog_buff_t *ub;
+	ulog_packet_msg_t *pm;
+	size_t size, copy_len;
+	struct nlmsghdr *nlh;
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	/* calculate the size of the skb needed */
+	if ((loginfo->copy_range == 0) ||
+	    (loginfo->copy_range > (*pskb)->len)) {
+		copy_len = (*pskb)->len;
+	} else {
+		copy_len = loginfo->copy_range;
+	}
+
+	size = NLMSG_SPACE(sizeof(*pm) + copy_len);
+
+	ub = &ulog_buffers[loginfo->nl_group];
+	
+	LOCK_BH(&ulog_lock);
+
+	if (!ub->skb) {
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	} else if (ub->qlen >= loginfo->qthreshold ||
+		   size > skb_tailroom(ub->skb)) {
+		/* either the queue len is too high or we don't have 
+		 * enough room in nlskb left. send it to userspace. */
+
+		ulog_send(loginfo->nl_group);
+
+		if (!(ub->skb = ulog_alloc_skb(size)))
+			goto alloc_failure;
+	}
+
+	DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, 
+		loginfo->qthreshold);
+
+	/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
+	nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, 
+			size - sizeof(*nlh));
+	ub->qlen++;
+
+	pm = NLMSG_DATA(nlh);
+
+	/* copy hook, prefix, timestamp, payload, etc. */
+	pm->data_len = copy_len;
+	pm->timestamp_sec = (*pskb)->stamp.tv_sec;
+	pm->timestamp_usec = (*pskb)->stamp.tv_usec;
+	pm->mark = (*pskb)->nfmark;
+	pm->hook = hooknum;
+	if (loginfo->prefix[0] != '\0')
+		strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
+	else
+		*(pm->prefix) = '\0';
+
+	if (in && in->hard_header_len > 0
+	    && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph
+	    && in->hard_header_len <= ULOG_MAC_LEN) {
+		memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len);
+		pm->mac_len = in->hard_header_len;
+	}
+
+	if (in)
+		strncpy(pm->indev_name, in->name, sizeof(pm->indev_name));
+	else
+		pm->indev_name[0] = '\0';
+
+	if (out)
+		strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name));
+	else
+		pm->outdev_name[0] = '\0';
+
+	if (copy_len)
+		memcpy(pm->payload, (*pskb)->data, copy_len);
+	
+	/* check if we are building multi-part messages */
+	if (ub->qlen > 1) {
+		ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
+	}
+
+	/* if threshold is reached, send message to userspace */
+	if (qlen >= loginfo->qthreshold) {
+		if (loginfo->qthreshold > 1)
+			nlh->nlmsg_type = NLMSG_DONE;
+	}
+
+	ub->lastnlh = nlh;
+
+	/* if timer isn't already running, start it */
+	if (!timer_pending(&ub->timer)) {
+		ub->timer.expires = jiffies + flushtimeout;
+		add_timer(&ub->timer);
+	}
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+
+
+nlmsg_failure:
+	PRINTR("ipt_ULOG: error during NLMSG_PUT\n");
+
+alloc_failure:
+	PRINTR("ipt_ULOG: Error building netlink message\n");
+
+	UNLOCK_BH(&ulog_lock);
+
+	return IPT_CONTINUE;
+}
+
+static int ipt_ulog_checkentry(const char *tablename,
+			       const struct ipt_entry *e,
+			       void *targinfo,
+			       unsigned int targinfosize,
+			       unsigned int hookmask)
+{
+	struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+
+	if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ulog_info))) {
+		DEBUGP("ipt_ULOG: targinfosize %u != 0\n", targinfosize);
+		return 0;
+	}
+
+	if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
+		DEBUGP("ipt_ULOG: prefix term %i\n",
+		       loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+		return 0;
+	}
+
+	if (loginfo->qthreshold > ULOG_MAX_QLEN) {
+		DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
+			loginfo->qthreshold);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_target ipt_ulog_reg =
+    { {NULL, NULL}, "ULOG", ipt_ulog_target, ipt_ulog_checkentry, NULL,
+THIS_MODULE
+};
+
+static int __init init(void)
+{
+	int i;
+
+	DEBUGP("ipt_ULOG: init module\n");
+
+	if (nlbufsiz >= 128*1024) {
+		printk("Netlink buffer has to be <= 128kB\n");
+		return -EINVAL;
+	}
+
+	/* initialize ulog_buffers */
+	for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
+		memset(&ulog_buffers[i], 0, sizeof(ulog_buff_t));
+		init_timer(&ulog_buffers[i].timer);
+		ulog_buffers[i].timer.function = ulog_timer;
+		ulog_buffers[i].timer.data = i;
+	}
+
+	nflognl = netlink_kernel_create(NETLINK_NFLOG, nflog_rcv);
+	if (!nflognl)
+		return -ENOMEM;
+
+	if (ipt_register_target(&ipt_ulog_reg) != 0) {
+		sock_release(nflognl->socket);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	DEBUGP("ipt_ULOG: cleanup_module\n");
+
+	ipt_unregister_target(&ipt_ulog_reg);
+	sock_release(nflognl->socket);
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipt_ah.c linux/net/ipv4/netfilter/ipt_ah.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipt_ah.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_ah.c	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_ah.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct ahhdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct ahhdr *ah = hdr;
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct ahhdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil AH tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(ahinfo->spis[0], ahinfo->spis[1],
+			      ntohl(ah->spi),
+			      !!(ahinfo->invflags & IPT_AH_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_ah *ahinfo = matchinfo;
+
+	/* Must specify proto == AH, and no unknown invflags */
+	if (ip->proto != IPPROTO_AH || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_ah: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_AH);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_ah))) {
+		duprintf("ipt_ah: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_ah)));
+		return 0;
+	}
+	if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
+		duprintf("ipt_ah: unknown flags %X\n",
+			 ahinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+int __init init(void)
+{
+	return ipt_register_match(&ah_match);
+}
+
+void __exit cleanup(void)
+{
+	ipt_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/ipt_esp.c linux/net/ipv4/netfilter/ipt_esp.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/ipt_esp.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv4/netfilter/ipt_esp.c	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,105 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv4/ipt_esp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
+#ifdef DEBUG_CONNTRACK
+#define duprintf(format, args...) printk(format , ## args)
+#else
+#define duprintf(format, args...)
+#endif
+
+struct esphdr {
+	__u32   spi;
+};
+
+/* Returns 1 if the spi is matched by the range, 0 otherwise */
+static inline int
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+{
+	int r=0;
+        duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	duprintf(" result %s\n",r? "PASS" : "FAILED");
+	return r;
+}
+
+static int
+match(const struct sk_buff *skb,
+      const struct net_device *in,
+      const struct net_device *out,
+      const void *matchinfo,
+      int offset,
+      const void *hdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	const struct esphdr *esp = hdr;
+	const struct ipt_esp *espinfo = matchinfo;
+
+	if (offset == 0 && datalen < sizeof(struct esphdr)) {
+		/* We've been asked to examine this packet, and we
+		   can't.  Hence, no choice but to drop. */
+		duprintf("Dropping evil ESP tinygram.\n");
+		*hotdrop = 1;
+		return 0;
+	}
+
+	/* Must not be a fragment. */
+	return !offset
+		&& spi_match(espinfo->spis[0], espinfo->spis[1],
+			      ntohl(esp->spi),
+			      !!(espinfo->invflags & IPT_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ipt_ip *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ipt_esp *espinfo = matchinfo;
+
+	/* Must specify proto == ESP, and no unknown invflags */
+	if (ip->proto != IPPROTO_ESP || (ip->invflags & IPT_INV_PROTO)) {
+		duprintf("ipt_esp: Protocol %u != %u\n", ip->proto,
+			 IPPROTO_ESP);
+		return 0;
+	}
+	if (matchinfosize != IPT_ALIGN(sizeof(struct ipt_esp))) {
+		duprintf("ipt_esp: matchsize %u != %u\n",
+			 matchinfosize, IPT_ALIGN(sizeof(struct ipt_esp)));
+		return 0;
+	}
+	if (espinfo->invflags & ~IPT_ESP_INV_MASK) {
+		duprintf("ipt_esp: unknown flags %X\n",
+			 espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ipt_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ipt_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+	ipt_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/iptable_filter.c linux/net/ipv4/netfilter/iptable_filter.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/iptable_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_filter.c	Wed Jan 23 17:31:05 2002
@@ -83,7 +83,7 @@
 
 static struct ipt_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -urN linux-2.5.3-pre3/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c
--- linux-2.5.3-pre3/net/ipv4/netfilter/iptable_mangle.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv4/netfilter/iptable_mangle.c	Wed Jan 23 17:31:05 2002
@@ -2,6 +2,8 @@
  * This is the 1999 rewrite of IP Firewalling, aiming for kernel 2.3.x.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ * Extended to all five netfilter hooks by Brad Chapman & Harald Welte
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -12,7 +14,11 @@
 #include <net/route.h>
 #include <linux/ip.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | \
+			    (1 << NF_IP_LOCAL_IN) | \
+			    (1 << NF_IP_FORWARD) | \
+			    (1 << NF_IP_LOCAL_OUT) | \
+			    (1 << NF_IP_POST_ROUTING))
 
 /* Standard entry. */
 struct ipt_standard
@@ -33,18 +39,25 @@
 	struct ipt_error_target target;
 };
 
+/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
 static struct
 {
 	struct ipt_replace repl;
-	struct ipt_standard entries[2];
+	struct ipt_standard entries[5];
 	struct ipt_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
-      { [NF_IP_PRE_ROUTING] 0,
-	[NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING] 	sizeof(struct ipt_standard) * 4 },
+      { [NF_IP_PRE_ROUTING] 	0,
+	[NF_IP_LOCAL_IN] 	sizeof(struct ipt_standard),
+	[NF_IP_FORWARD] 	sizeof(struct ipt_standard) * 2,
+	[NF_IP_LOCAL_OUT] 	sizeof(struct ipt_standard) * 3,
+	[NF_IP_POST_ROUTING]	sizeof(struct ipt_standard) * 4 },
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
@@ -55,6 +68,22 @@
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+ 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
 	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
@@ -62,7 +91,15 @@
 		sizeof(struct ipt_standard),
 		0, { 0, 0 }, { } },
 	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
-		-NF_ACCEPT - 1 } }
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
+	    { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ipt_entry),
+		sizeof(struct ipt_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
     },
     /* ERROR */
     { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
@@ -79,11 +116,11 @@
 
 static struct ipt_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ipt_hook(unsigned int hook,
+ipt_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -121,7 +158,7 @@
 }
 
 static unsigned int
-ipt_local_out_hook(unsigned int hook,
+ipt_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -159,9 +196,16 @@
 }
 
 static struct nf_hook_ops ipt_ops[]
-= { { { NULL, NULL }, ipt_hook, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_MANGLE },
-    { { NULL, NULL }, ipt_local_out_hook, PF_INET, NF_IP_LOCAL_OUT,
-		NF_IP_PRI_MANGLE }
+= { { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_PRE_ROUTING, 
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_IN,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_FORWARD,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_local_hook, PF_INET, NF_IP_LOCAL_OUT,
+	NF_IP_PRI_MANGLE },
+    { { NULL, NULL }, ipt_route_hook, PF_INET, NF_IP_POST_ROUTING,
+	NF_IP_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -182,8 +226,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ipt_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ipt_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ipt_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ipt_ops[3]);
+ cleanup_hook2:
+        nf_unregister_hook(&ipt_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ipt_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ipt_ops[0]);
  cleanup_table:
diff -urN linux-2.5.3-pre3/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c
--- linux-2.5.3-pre3/net/ipv6/ndisc.c	Wed Jan 23 17:31:02 2002
+++ linux/net/ipv6/ndisc.c	Wed Jan 23 17:31:05 2002
@@ -957,6 +957,7 @@
 	struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
 	struct neighbour *neigh;
 	struct inet6_ifaddr *ifp;
+	unsigned int payload_len;
 
 	__skb_push(skb, skb->data-skb->h.raw);
 
@@ -979,10 +980,11 @@
 	 *	(Some checking in ndisc_find_option)
 	 */
 
+	payload_len = ntohs(skb->nh.ipv6h->payload_len);
 	switch (msg->icmph.icmp6_type) {
 	case NDISC_NEIGHBOUR_SOLICITATION:
 		/* XXX: import nd_neighbor_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16) {
+		if (payload_len < 8+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NS: packet too short\n");
 			return 0;
@@ -1112,7 +1114,7 @@
 
 	case NDISC_NEIGHBOUR_ADVERTISEMENT:
 		/* XXX: import nd_neighbor_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 16+8 ) {
+		if (payload_len < 16+8 ) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP NA: packet too short\n");
 			return 0;
@@ -1174,7 +1176,7 @@
 
 	case NDISC_ROUTER_ADVERTISEMENT:
 		/* XXX: import nd_router_advert from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+4+4) {
+		if (payload_len < 8+4+4) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RA: packet too short\n");
 			return 0;
@@ -1184,7 +1186,7 @@
 
 	case NDISC_REDIRECT:
 		/* XXX: import nd_redirect from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8+16+16) {
+		if (payload_len < 8+16+16) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP redirect: packet too short\n");
 			return 0;
@@ -1196,7 +1198,7 @@
 		/* No RS support in the kernel, but we do some required checks */
 
 		/* XXX: import nd_router_solicit from glibc netinet/icmp6.h */
-		if (skb->nh.ipv6h->payload_len < 8) {
+		if (payload_len < 8) {
 			if (net_ratelimit())
 				printk(KERN_WARNING "ICMP RS: packet too short\n");
 			return 0;
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/Config.in linux/net/ipv6/netfilter/Config.in
--- linux-2.5.3-pre3/net/ipv6/netfilter/Config.in	Wed Jan 23 17:31:02 2002
+++ linux/net/ipv6/netfilter/Config.in	Wed Jan 23 17:31:05 2002
@@ -9,9 +9,10 @@
 #  dep_tristate '  FTP protocol support' CONFIG_IP6_NF_FTP $CONFIG_IP6_NF_CONNTRACK
 #fi
 
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-#  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
-#fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Userspace queueing via NETLINK (EXPERIMENTAL)' CONFIG_IP6_NF_QUEUE
+fi
+
 tristate 'IP6 tables support (required for filtering/masq/NAT)' CONFIG_IP6_NF_IPTABLES
 if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
 # The simple matches.
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile
--- linux-2.5.3-pre3/net/ipv6/netfilter/Makefile	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/Makefile	Wed Jan 23 17:31:05 2002
@@ -21,6 +21,7 @@
 obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
+obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
 obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/ip6_queue.c linux/net/ipv6/netfilter/ip6_queue.c
--- linux-2.5.3-pre3/net/ipv6/netfilter/ip6_queue.c	Wed Dec 31 16:00:00 1969
+++ linux/net/ipv6/netfilter/ip6_queue.c	Wed Jan 23 17:31:05 2002
@@ -0,0 +1,721 @@
+/*
+ * This is a module which is used for queueing IPv6 packets and
+ * communicating with userspace via netlink.
+ *
+ * (C) 2001 Fernando Anton, this code is GPL.
+ *     IPv64 Project - Work based in IPv64 draft by Arturo Azcorra.
+ *     Universidad Carlos III de Madrid - Leganes (Madrid) - Spain
+ *     Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain
+ *     email: fanton@it.uc3m.es
+ *
+ * 2001-11-06: First try. Working with ip_queue.c for IPv4 and trying
+ *             to adapt it to IPv6
+ *             HEAVILY based in ipqueue.c by James Morris. It's just
+ *             a little modified version of it, so he's nearly the
+ *             real coder of this.
+ *             Few changes needed, mainly the hard_routing code and
+ *             the netlink socket protocol (we're NETLINK_IP6_FW).
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ipv6.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+
+/* We're still usign the following structs. No need to change them: */
+/*   ipq_packet_msg                                                 */
+/*   ipq_mode_msg                                                   */
+/*   ipq_verdict_msg                                                */
+/*   ipq_peer_msg                                                   */
+#include <linux/netfilter_ipv4/ip_queue.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+#define IPQ_QMAX_DEFAULT 1024
+#define IPQ_PROC_FS_NAME "ip6_queue"
+#define NET_IPQ_QMAX 2088
+#define NET_IPQ_QMAX_NAME "ip6_queue_maxlen"
+
+typedef struct ip6q_rt_info {
+	struct in6_addr daddr;
+	struct in6_addr saddr;
+} ip6q_rt_info_t;
+
+typedef struct ip6q_queue_element {
+	struct list_head list;		/* Links element into queue */
+	int verdict;			/* Current verdict */
+	struct nf_info *info;		/* Extra info from netfilter */
+	struct sk_buff *skb;		/* Packet inside */
+	ip6q_rt_info_t rt_info;		/* May need post-mangle routing */
+} ip6q_queue_element_t;
+
+typedef int (*ip6q_send_cb_t)(ip6q_queue_element_t *e);
+
+typedef struct ip6q_peer {
+	pid_t pid;			/* PID of userland peer */
+	unsigned char died;		/* We think the peer died */
+	unsigned char copy_mode;	/* Copy packet as well as metadata? */
+	size_t copy_range;		/* Range past metadata to copy */
+	ip6q_send_cb_t send;		/* Callback for sending data to peer */
+} ip6q_peer_t;
+
+typedef struct ip6q_queue {
+ 	int len;			/* Current queue len */
+ 	int *maxlen;			/* Maximum queue len, via sysctl */
+ 	unsigned char flushing;		/* If queue is being flushed */
+ 	unsigned char terminate;	/* If the queue is being terminated */
+ 	struct list_head list;		/* Head of packet queue */
+ 	spinlock_t lock;		/* Queue spinlock */
+ 	ip6q_peer_t peer;		/* Userland peer */
+} ip6q_queue_t;
+
+/****************************************************************************
+ *
+ * Packet queue
+ *
+ ****************************************************************************/
+/* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
+static ip6q_queue_element_t *
+ip6q_dequeue(ip6q_queue_t *q,
+            int (*cmp)(ip6q_queue_element_t *, unsigned long),
+            unsigned long data)
+{
+	struct list_head *i;
+
+	spin_lock_bh(&q->lock);
+	for (i = q->list.prev; i != &q->list; i = i->prev) {
+		ip6q_queue_element_t *e = (ip6q_queue_element_t *)i;
+		
+		if (!cmp || cmp(e, data)) {
+			list_del(&e->list);
+			q->len--;
+			spin_unlock_bh(&q->lock);
+			return e;
+		}
+	}
+	spin_unlock_bh(&q->lock);
+	return NULL;
+}
+
+/* Flush all packets */
+static void ip6q_flush(ip6q_queue_t *q)
+{
+	ip6q_queue_element_t *e;
+	
+	spin_lock_bh(&q->lock);
+	q->flushing = 1;
+	spin_unlock_bh(&q->lock);
+	while ((e = ip6q_dequeue(q, NULL, 0))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+	spin_lock_bh(&q->lock);
+	q->flushing = 0;
+	spin_unlock_bh(&q->lock);
+}
+
+static ip6q_queue_t *ip6q_create_queue(nf_queue_outfn_t outfn,
+                                     ip6q_send_cb_t send_cb,
+                                     int *errp, int *sysctl_qmax)
+{
+	int status;
+	ip6q_queue_t *q;
+
+	*errp = 0;
+	q = kmalloc(sizeof(ip6q_queue_t), GFP_KERNEL);
+	if (q == NULL) {
+		*errp = -ENOMEM;
+		return NULL;
+	}
+	q->peer.pid = 0;
+	q->peer.died = 0;
+	q->peer.copy_mode = IPQ_COPY_NONE;
+	q->peer.copy_range = 0;
+	q->peer.send = send_cb;
+	q->len = 0;
+	q->maxlen = sysctl_qmax;
+	q->flushing = 0;
+	q->terminate = 0;
+	INIT_LIST_HEAD(&q->list);
+	spin_lock_init(&q->lock);
+	status = nf_register_queue_handler(PF_INET6, outfn, q);
+	if (status < 0) {
+		*errp = -EBUSY;
+		kfree(q);
+		return NULL;
+	}
+	return q;
+}
+
+static int ip6q_enqueue(ip6q_queue_t *q,
+                       struct sk_buff *skb, struct nf_info *info)
+{
+	ip6q_queue_element_t *e;
+	int status;
+	
+	e = kmalloc(sizeof(*e), GFP_ATOMIC);
+	if (e == NULL) {
+		printk(KERN_ERR "ip6_queue: OOM in enqueue\n");
+		return -ENOMEM;
+	}
+
+	e->verdict = NF_DROP;
+	e->info = info;
+	e->skb = skb;
+
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = skb->nh.ipv6h;
+
+		e->rt_info.daddr = iph->daddr;
+		e->rt_info.saddr = iph->saddr;
+	}
+
+	spin_lock_bh(&q->lock);
+	if (q->len >= *q->maxlen) {
+		spin_unlock_bh(&q->lock);
+		if (net_ratelimit()) 
+			printk(KERN_WARNING "ip6_queue: full at %d entries, "
+			       "dropping packet(s).\n", q->len);
+		goto free_drop;
+	}
+	if (q->flushing || q->peer.copy_mode == IPQ_COPY_NONE
+	    || q->peer.pid == 0 || q->peer.died || q->terminate) {
+		spin_unlock_bh(&q->lock);
+		goto free_drop;
+	}
+	status = q->peer.send(e);
+	if (status > 0) {
+		list_add(&e->list, &q->list);
+		q->len++;
+		spin_unlock_bh(&q->lock);
+		return status;
+	}
+	spin_unlock_bh(&q->lock);
+	if (status == -ECONNREFUSED) {
+		printk(KERN_INFO "ip6_queue: peer %d died, "
+		       "resetting state and flushing queue\n", q->peer.pid);
+			q->peer.died = 1;
+			q->peer.pid = 0;
+			q->peer.copy_mode = IPQ_COPY_NONE;
+			q->peer.copy_range = 0;
+			ip6q_flush(q);
+	}
+free_drop:
+	kfree(e);
+	return -EBUSY;
+}
+
+static void ip6q_destroy_queue(ip6q_queue_t *q)
+{
+	nf_unregister_queue_handler(PF_INET6);
+	spin_lock_bh(&q->lock);
+	q->terminate = 1;
+	spin_unlock_bh(&q->lock);
+	ip6q_flush(q);
+	kfree(q);
+}
+
+/*
+ * Taken from net/ipv6/ip6_output.c
+ *
+ * We should use the one there, but is defined static
+ * so we put this just here and let the things as
+ * they are now.
+ *
+ * If that one is modified, this one should be modified too.
+ */
+static int route6_me_harder(struct sk_buff *skb)
+{
+	struct ipv6hdr *iph = skb->nh.ipv6h;
+	struct dst_entry *dst;
+	struct flowi fl;
+
+	fl.proto = iph->nexthdr;
+	fl.fl6_dst = &iph->daddr;
+	fl.fl6_src = &iph->saddr;
+	fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
+	fl.fl6_flowlabel = 0;
+	fl.uli_u.ports.dport = 0;
+	fl.uli_u.ports.sport = 0;
+
+	dst = ip6_route_output(skb->sk, &fl);
+
+	if (dst->error) {
+		if (net_ratelimit())
+			printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+		return -EINVAL;
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+
+	skb->dst = dst;
+	return 0;
+}
+static int ip6q_mangle_ipv6(ipq_verdict_msg_t *v, ip6q_queue_element_t *e)
+{
+	int diff;
+	struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload;
+
+	if (v->data_len < sizeof(*user_iph))
+		return 0;
+	diff = v->data_len - e->skb->len;
+	if (diff < 0)
+		skb_trim(e->skb, v->data_len);
+	else if (diff > 0) {
+		if (v->data_len > 0xFFFF)
+			return -EINVAL;
+		if (diff > skb_tailroom(e->skb)) {
+			struct sk_buff *newskb;
+			
+			newskb = skb_copy_expand(e->skb,
+			                         skb_headroom(e->skb),
+			                         diff,
+			                         GFP_ATOMIC);
+			if (newskb == NULL) {
+				printk(KERN_WARNING "ip6_queue: OOM "
+				      "in mangle, dropping packet\n");
+				return -ENOMEM;
+			}
+			if (e->skb->sk)
+				skb_set_owner_w(newskb, e->skb->sk);
+			kfree_skb(e->skb);
+			e->skb = newskb;
+		}
+		skb_put(e->skb, diff);
+	}
+	memcpy(e->skb->data, v->payload, v->data_len);
+	e->skb->nfcache |= NFC_ALTERED;
+
+	/*
+	 * Extra routing may needed on local out, as the QUEUE target never
+	 * returns control to the table.
+         * Not a nice way to cmp, but works
+	 */
+	if (e->info->hook == NF_IP_LOCAL_OUT) {
+		struct ipv6hdr *iph = e->skb->nh.ipv6h;
+		if (!(   iph->daddr.in6_u.u6_addr32[0] == e->rt_info.daddr.in6_u.u6_addr32[0]
+                      && iph->daddr.in6_u.u6_addr32[1] == e->rt_info.daddr.in6_u.u6_addr32[1]
+                      && iph->daddr.in6_u.u6_addr32[2] == e->rt_info.daddr.in6_u.u6_addr32[2]
+                      && iph->daddr.in6_u.u6_addr32[3] == e->rt_info.daddr.in6_u.u6_addr32[3]
+		      && iph->saddr.in6_u.u6_addr32[0] == e->rt_info.saddr.in6_u.u6_addr32[0]
+		      && iph->saddr.in6_u.u6_addr32[1] == e->rt_info.saddr.in6_u.u6_addr32[1]
+		      && iph->saddr.in6_u.u6_addr32[2] == e->rt_info.saddr.in6_u.u6_addr32[2]
+		      && iph->saddr.in6_u.u6_addr32[3] == e->rt_info.saddr.in6_u.u6_addr32[3]))
+			return route6_me_harder(e->skb);
+	}
+	return 0;
+}
+
+static inline int id_cmp(ip6q_queue_element_t *e, unsigned long id)
+{
+	return (id == (unsigned long )e);
+}
+
+static int ip6q_set_verdict(ip6q_queue_t *q,
+                           ipq_verdict_msg_t *v, unsigned int len)
+{
+	ip6q_queue_element_t *e;
+
+	if (v->value > NF_MAX_VERDICT)
+		return -EINVAL;
+	e = ip6q_dequeue(q, id_cmp, v->id);
+	if (e == NULL)
+		return -ENOENT;
+	else {
+		e->verdict = v->value;
+		if (v->data_len && v->data_len == len)
+			if (ip6q_mangle_ipv6(v, e) < 0)
+				e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+		return 0;
+	}
+}
+
+static int ip6q_receive_peer(ip6q_queue_t* q, ipq_peer_msg_t *m,
+                            unsigned char type, unsigned int len)
+{
+
+	int status = 0;
+	int busy;
+		
+	spin_lock_bh(&q->lock);
+	busy = (q->terminate || q->flushing);
+	spin_unlock_bh(&q->lock);
+	if (busy)
+		return -EBUSY;
+	if (len < sizeof(ipq_peer_msg_t))
+		return -EINVAL;
+	switch (type) {
+		case IPQM_MODE:
+			switch (m->msg.mode.value) {
+				case IPQ_COPY_META:
+					q->peer.copy_mode = IPQ_COPY_META;
+					q->peer.copy_range = 0;
+					break;
+				case IPQ_COPY_PACKET:
+					q->peer.copy_mode = IPQ_COPY_PACKET;
+					q->peer.copy_range = m->msg.mode.range;
+					if (q->peer.copy_range > 0xFFFF)
+						q->peer.copy_range = 0xFFFF;
+					break;
+				default:
+					status = -EINVAL;
+			}
+			break;
+		case IPQM_VERDICT:
+			if (m->msg.verdict.value > NF_MAX_VERDICT)
+				status = -EINVAL;
+			else
+				status = ip6q_set_verdict(q,
+				                         &m->msg.verdict,
+				                         len - sizeof(*m));
+			break;
+		default:
+			 status = -EINVAL;
+	}
+	return status;
+}
+
+static inline int dev_cmp(ip6q_queue_element_t *e, unsigned long ifindex)
+{
+	if (e->info->indev)
+		if (e->info->indev->ifindex == ifindex)
+			return 1;
+	if (e->info->outdev)
+		if (e->info->outdev->ifindex == ifindex)
+			return 1;
+	return 0;
+}
+
+/* Drop any queued packets associated with device ifindex */
+static void ip6q_dev_drop(ip6q_queue_t *q, int ifindex)
+{
+	ip6q_queue_element_t *e;
+	
+	while ((e = ip6q_dequeue(q, dev_cmp, ifindex))) {
+		e->verdict = NF_DROP;
+		nf_reinject(e->skb, e->info, e->verdict);
+		kfree(e);
+	}
+}
+
+/****************************************************************************
+ *
+ * Netfilter interface
+ *
+ ****************************************************************************/
+
+/*
+ * Packets arrive here from netfilter for queuing to userspace.
+ * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
+ */
+static int netfilter6_receive(struct sk_buff *skb,
+                             struct nf_info *info, void *data)
+{
+	return ip6q_enqueue((ip6q_queue_t *)data, skb, info);
+}
+
+/****************************************************************************
+ *
+ * Netlink interface.
+ *
+ ****************************************************************************/
+
+static struct sock *nfnl = NULL;
+/* This is not a static one, so we should not repeat its name */
+ip6q_queue_t *nlq6 = NULL;
+
+static struct sk_buff *netlink_build_message(ip6q_queue_element_t *e, int *errp)
+{
+	unsigned char *old_tail;
+	size_t size = 0;
+	size_t data_len = 0;
+	struct sk_buff *skb;
+	ipq_packet_msg_t *pm;
+	struct nlmsghdr *nlh;
+
+	switch (nlq6->peer.copy_mode) {
+		size_t copy_range;
+
+		case IPQ_COPY_META:
+			size = NLMSG_SPACE(sizeof(*pm));
+			data_len = 0;
+			break;
+		case IPQ_COPY_PACKET:
+			copy_range = nlq6->peer.copy_range;
+			if (copy_range == 0 || copy_range > e->skb->len)
+				data_len = e->skb->len;
+			else
+				data_len = copy_range;
+			size = NLMSG_SPACE(sizeof(*pm) + data_len);
+			
+			break;
+		case IPQ_COPY_NONE:
+		default:
+			*errp = -EINVAL;
+			return NULL;
+	}
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
+	pm = NLMSG_DATA(nlh);
+	memset(pm, 0, sizeof(*pm));
+	pm->packet_id = (unsigned long )e;
+	pm->data_len = data_len;
+	pm->timestamp_sec = e->skb->stamp.tv_sec;
+	pm->timestamp_usec = e->skb->stamp.tv_usec;
+	pm->mark = e->skb->nfmark;
+	pm->hook = e->info->hook;
+	if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
+	else pm->indev_name[0] = '\0';
+	if (e->info->outdev) strcpy(pm->outdev_name, e->info->outdev->name);
+	else pm->outdev_name[0] = '\0';
+	pm->hw_protocol = e->skb->protocol;
+	if (e->info->indev && e->skb->dev) {
+		pm->hw_type = e->skb->dev->type;
+		if (e->skb->dev->hard_header_parse)
+			pm->hw_addrlen =
+				e->skb->dev->hard_header_parse(e->skb,
+				                               pm->hw_addr);
+	}
+	if (data_len)
+		memcpy(pm->payload, e->skb->data, data_len);
+	nlh->nlmsg_len = skb->tail - old_tail;
+	NETLINK_CB(skb).dst_groups = 0;
+	return skb;
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = 0;
+	printk(KERN_ERR "ip6_queue: error creating netlink message\n");
+	return NULL;
+}
+
+static int netlink_send_peer(ip6q_queue_element_t *e)
+{
+	int status = 0;
+	struct sk_buff *skb;
+
+	skb = netlink_build_message(e, &status);
+	if (skb == NULL)
+		return status;
+	return netlink_unicast(nfnl, skb, nlq6->peer.pid, MSG_DONTWAIT);
+}
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0);
+
+static __inline__ void netlink_receive_user_skb(struct sk_buff *skb)
+{
+	int status, type;
+	struct nlmsghdr *nlh;
+
+	if (skb->len < sizeof(struct nlmsghdr))
+		return;
+
+	nlh = (struct nlmsghdr *)skb->data;
+	if (nlh->nlmsg_len < sizeof(struct nlmsghdr)
+	    || skb->len < nlh->nlmsg_len)
+	    	return;
+
+	if(nlh->nlmsg_pid <= 0
+	    || !(nlh->nlmsg_flags & NLM_F_REQUEST)
+	    || nlh->nlmsg_flags & NLM_F_MULTI)
+		RCV_SKB_FAIL(-EINVAL);
+	if (nlh->nlmsg_flags & MSG_TRUNC)
+		RCV_SKB_FAIL(-ECOMM);
+	type = nlh->nlmsg_type;
+	if (type < NLMSG_NOOP || type >= IPQM_MAX)
+		RCV_SKB_FAIL(-EINVAL);
+	if (type <= IPQM_BASE)
+		return;
+	if(!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+		RCV_SKB_FAIL(-EPERM);
+	if (nlq6->peer.pid && !nlq6->peer.died
+	    && (nlq6->peer.pid != nlh->nlmsg_pid)) {
+	    	printk(KERN_WARNING "ip6_queue: peer pid changed from %d to "
+	    	      "%d, flushing queue\n", nlq6->peer.pid, nlh->nlmsg_pid);
+		ip6q_flush(nlq6);
+	}	
+	nlq6->peer.pid = nlh->nlmsg_pid;
+	nlq6->peer.died = 0;
+	status = ip6q_receive_peer(nlq6, NLMSG_DATA(nlh),
+	                          type, skb->len - NLMSG_LENGTH(0));
+	if (status < 0)
+		RCV_SKB_FAIL(status);
+	if (nlh->nlmsg_flags & NLM_F_ACK)
+		netlink_ack(skb, nlh, 0);
+        return;
+}
+
+/* Note: we are only dealing with single part messages at the moment. */
+static void netlink_receive_user_sk(struct sock *sk, int len)
+{
+	do {
+		struct sk_buff *skb;
+
+		if (rtnl_shlock_nowait())
+			return;
+		while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+			netlink_receive_user_skb(skb);
+			kfree_skb(skb);
+		}
+		up(&rtnl_sem);
+	} while (nfnl && nfnl->receive_queue.qlen);
+}
+
+/****************************************************************************
+ *
+ * System events
+ *
+ ****************************************************************************/
+
+static int receive_event(struct notifier_block *this,
+                         unsigned long event, void *ptr)
+{
+	struct net_device *dev = ptr;
+
+	/* Drop any packets associated with the downed device */
+	if (event == NETDEV_DOWN)
+		ip6q_dev_drop(nlq6, dev->ifindex);
+	return NOTIFY_DONE;
+}
+
+struct notifier_block ip6q_dev_notifier = {
+	receive_event,
+	NULL,
+	0
+};
+
+/****************************************************************************
+ *
+ * Sysctl - queue tuning.
+ *
+ ****************************************************************************/
+
+static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
+
+static struct ctl_table_header *ip6q_sysctl_header;
+
+static ctl_table ip6q_table[] = {
+	{ NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
+	  sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
+ 	{ 0 }
+};
+
+static ctl_table ip6q_dir_table[] = {
+	{NET_IPV6, "ipv6", NULL, 0, 0555, ip6q_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+static ctl_table ip6q_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ip6q_dir_table, 0, 0, 0, 0, 0},
+	{ 0 }
+};
+
+/****************************************************************************
+ *
+ * Procfs - debugging info.
+ *
+ ****************************************************************************/
+
+static int ip6q_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	int len;
+
+	spin_lock_bh(&nlq6->lock);
+	len = sprintf(buffer,
+	              "Peer pid            : %d\n"
+	              "Peer died           : %d\n"
+	              "Peer copy mode      : %d\n"
+	              "Peer copy range     : %Zu\n"
+	              "Queue length        : %d\n"
+	              "Queue max. length   : %d\n"
+	              "Queue flushing      : %d\n"
+	              "Queue terminate     : %d\n",
+	              nlq6->peer.pid,
+	              nlq6->peer.died,
+	              nlq6->peer.copy_mode,
+	              nlq6->peer.copy_range,
+	              nlq6->len,
+	              *nlq6->maxlen,
+	              nlq6->flushing,
+	              nlq6->terminate);
+	spin_unlock_bh(&nlq6->lock);
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	else if (len < 0)
+		len = 0;
+	return len;
+}
+
+/****************************************************************************
+ *
+ * Module stuff.
+ *
+ ****************************************************************************/
+
+static int __init init(void)
+{
+	int status = 0;
+	struct proc_dir_entry *proc;
+	
+        /* We must create the NETLINK_IP6_FW protocol service */
+	nfnl = netlink_kernel_create(NETLINK_IP6_FW, netlink_receive_user_sk);
+	if (nfnl == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create kernel netlink socket\n");
+		return -ENOMEM;
+	}
+	nlq6 = ip6q_create_queue(netfilter6_receive,
+	                       netlink_send_peer, &status, &sysctl_maxlen);
+	if (nlq6 == NULL) {
+		printk(KERN_ERR "ip6_queue: initialisation failed: unable to "
+		       "create queue\n");
+		sock_release(nfnl->socket);
+		return status;
+	}
+        /* The file will be /proc/net/ip6_queue */
+	proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ip6q_get_info);
+	if (proc) proc->owner = THIS_MODULE;
+	else {
+		ip6q_destroy_queue(nlq6);
+		sock_release(nfnl->socket);
+		return -ENOMEM;
+	}
+	register_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_sysctl_header = register_sysctl_table(ip6q_root_table, 0);
+	return status;
+}
+
+static void __exit fini(void)
+{
+	unregister_sysctl_table(ip6q_sysctl_header);
+	proc_net_remove(IPQ_PROC_FS_NAME);
+	unregister_netdevice_notifier(&ip6q_dev_notifier);
+	ip6q_destroy_queue(nlq6);
+	sock_release(nfnl->socket);
+}
+
+MODULE_DESCRIPTION("IPv6 packet queue handler");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/ip6_tables.c linux/net/ipv6/netfilter/ip6_tables.c
--- linux-2.5.3-pre3/net/ipv6/netfilter/ip6_tables.c	Tue Oct 30 15:08:12 2001
+++ linux/net/ipv6/netfilter/ip6_tables.c	Wed Jan 23 17:31:05 2002
@@ -2,6 +2,11 @@
  * Packet matching code.
  *
  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
+ *
+ * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
+ * 	- increase module usage count as soon as we have rules inside
+ * 	  a table
  */
 #include <linux/config.h>
 #include <linux/skbuff.h>
@@ -86,6 +91,8 @@
 	unsigned int size;
 	/* Number of entries: FIXME. --RR */
 	unsigned int number;
+	/* Initial number of entries. Needed for module usage count */
+	unsigned int initial_entries;
 
 	/* Entry points and underflows */
 	unsigned int hook_entry[NF_IP6_NUMHOOKS];
@@ -949,6 +956,7 @@
 	}
 	oldinfo = table->private;
 	table->private = newinfo;
+	newinfo->initial_entries = oldinfo->initial_entries;
 	write_unlock_bh(&table->lock);
 
 	return oldinfo;
@@ -1148,6 +1156,16 @@
 	if (!oldinfo)
 		goto free_newinfo_counters_untrans_unlock;
 
+	/* Update module usage count based on number of rules */
+	duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
+		oldinfo->number, oldinfo->initial_entries, newinfo->number);
+	if (t->me && (oldinfo->number <= oldinfo->initial_entries) &&
+ 	    (newinfo->number > oldinfo->initial_entries))
+		__MOD_INC_USE_COUNT(t->me);
+	else if (t->me && (oldinfo->number > oldinfo->initial_entries) &&
+	 	 (newinfo->number <= oldinfo->initial_entries))
+		__MOD_DEC_USE_COUNT(t->me);
+
 	/* Get the old counters. */
 	get_counters(oldinfo, counters);
 	/* Decrease module usage counts and free resource */
@@ -1406,7 +1424,7 @@
 	int ret;
 	struct ip6t_table_info *newinfo;
 	static struct ip6t_table_info bootstrap
-		= { 0, 0, { 0 }, { 0 }, { }, { } };
+		= { 0, 0, 0, { 0 }, { 0 }, { }, { } };
 
 	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
@@ -1783,7 +1801,7 @@
 	}
 #endif
 
-	printk("ip6_tables: (c)2000 Netfilter core team\n");
+	printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
 	return 0;
 }
 
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/ip6t_MARK.c linux/net/ipv6/netfilter/ip6t_MARK.c
--- linux-2.5.3-pre3/net/ipv6/netfilter/ip6t_MARK.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6t_MARK.c	Wed Jan 23 17:31:05 2002
@@ -51,7 +51,7 @@
 
 static int __init init(void)
 {
-	printk(KERN_DEBUG "registreing ipv6 mark target\n");
+	printk(KERN_DEBUG "registering ipv6 mark target\n");
 	if (ip6t_register_target(&ip6t_mark_reg))
 		return -EINVAL;
 
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/ip6table_filter.c linux/net/ipv6/netfilter/ip6table_filter.c
--- linux-2.5.3-pre3/net/ipv6/netfilter/ip6table_filter.c	Sun Sep 30 12:26:08 2001
+++ linux/net/ipv6/netfilter/ip6table_filter.c	Wed Jan 23 17:31:05 2002
@@ -83,7 +83,7 @@
 
 static struct ip6t_table packet_filter
 = { { NULL, NULL }, "filter", &initial_table.repl,
-    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    FILTER_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
diff -urN linux-2.5.3-pre3/net/ipv6/netfilter/ip6table_mangle.c linux/net/ipv6/netfilter/ip6table_mangle.c
--- linux-2.5.3-pre3/net/ipv6/netfilter/ip6table_mangle.c	Sun Sep 30 12:26:09 2001
+++ linux/net/ipv6/netfilter/ip6table_mangle.c	Wed Jan 23 17:31:05 2002
@@ -1,14 +1,18 @@
 /*
  * IPv6 packet mangling table, a port of the IPv4 mangle table to IPv6
  *
- * Copyright (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
  */
 #include <linux/module.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 
-#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
+#define MANGLE_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | \
+			    (1 << NF_IP6_LOCAL_IN) | \
+			    (1 << NF_IP6_FORWARD) | \
+			    (1 << NF_IP6_LOCAL_OUT) | \
+			    (1 << NF_IP6_POST_ROUTING))
 
-#if 1
+#if 0
 #define DEBUGP(x, args...)	printk(KERN_DEBUG x, ## args)
 #else
 #define DEBUGP(x, args...)
@@ -36,19 +40,41 @@
 static struct
 {
 	struct ip6t_replace repl;
-	struct ip6t_standard entries[2];
+	struct ip6t_standard entries[5];
 	struct ip6t_error term;
 } initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 3,
-      sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
-      { [NF_IP6_PRE_ROUTING] 0,
-	[NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) },
+= { { "mangle", MANGLE_VALID_HOOKS, 6,
+      sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
+      { [NF_IP6_PRE_ROUTING] 	0,
+	[NF_IP6_LOCAL_IN]	sizeof(struct ip6t_standard),
+	[NF_IP6_FORWARD]	sizeof(struct ip6t_standard) * 2,
+	[NF_IP6_LOCAL_OUT] 	sizeof(struct ip6t_standard) * 3,
+	[NF_IP6_POST_ROUTING]	sizeof(struct ip6t_standard) * 4},
       0, NULL, { } },
     {
 	    /* PRE_ROUTING */
-	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* LOCAL_IN */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* FORWARD */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
 		sizeof(struct ip6t_standard),
@@ -56,6 +82,14 @@
 	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
 		-NF_ACCEPT - 1 } },
 	    /* LOCAL_OUT */
+            { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+		0,
+		sizeof(struct ip6t_entry),
+		sizeof(struct ip6t_standard),
+		0, { 0, 0 }, { } },
+	      { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
+		-NF_ACCEPT - 1 } },
+	    /* POST_ROUTING */
 	    { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
 		0,
 		sizeof(struct ip6t_entry),
@@ -79,11 +113,11 @@
 
 static struct ip6t_table packet_mangler
 = { { NULL, NULL }, "mangle", &initial_table.repl,
-    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL };
+    MANGLE_VALID_HOOKS, RW_LOCK_UNLOCKED, NULL, THIS_MODULE };
 
 /* The work comes in here from netfilter.c. */
 static unsigned int
-ip6t_hook(unsigned int hook,
+ip6t_route_hook(unsigned int hook,
 	 struct sk_buff **pskb,
 	 const struct net_device *in,
 	 const struct net_device *out,
@@ -93,7 +127,7 @@
 }
 
 static unsigned int
-ip6t_local_out_hook(unsigned int hook,
+ip6t_local_hook(unsigned int hook,
 		   struct sk_buff **pskb,
 		   const struct net_device *in,
 		   const struct net_device *out,
@@ -142,9 +176,11 @@
 }
 
 static struct nf_hook_ops ip6t_ops[]
-= { { { NULL, NULL }, ip6t_hook, PF_INET6, NF_IP6_PRE_ROUTING, NF_IP6_PRI_MANGLE },
-    { { NULL, NULL }, ip6t_local_out_hook, PF_INET6, NF_IP6_LOCAL_OUT,
-		NF_IP6_PRI_MANGLE }
+= { { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_PRE_ROUTING,  NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_IN,     NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_FORWARD,      NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_local_hook, PF_INET6, NF_IP6_LOCAL_OUT,    NF_IP6_PRI_MANGLE },
+    { { NULL, NULL }, ip6t_route_hook, PF_INET6, NF_IP6_POST_ROUTING, NF_IP6_PRI_MANGLE }
 };
 
 static int __init init(void)
@@ -165,8 +201,26 @@
 	if (ret < 0)
 		goto cleanup_hook0;
 
+	ret = nf_register_hook(&ip6t_ops[2]);
+	if (ret < 0)
+		goto cleanup_hook1;
+
+	ret = nf_register_hook(&ip6t_ops[3]);
+	if (ret < 0)
+		goto cleanup_hook2;
+
+	ret = nf_register_hook(&ip6t_ops[4]);
+	if (ret < 0)
+		goto cleanup_hook3;
+
 	return ret;
 
+ cleanup_hook3:
+        nf_unregister_hook(&ip6t_ops[3]);
+ cleanup_hook2:
+	nf_unregister_hook(&ip6t_ops[2]);
+ cleanup_hook1:
+	nf_unregister_hook(&ip6t_ops[1]);
  cleanup_hook0:
 	nf_unregister_hook(&ip6t_ops[0]);
  cleanup_table:
diff -urN linux-2.5.3-pre3/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.5.3-pre3/net/irda/af_irda.c	Fri Nov 30 13:25:10 2001
+++ linux/net/irda/af_irda.c	Wed Jan 23 17:31:05 2002
@@ -2590,14 +2590,11 @@
 	register_netdevice_notifier(&irda_dev_notifier);
 
 	irda_init();
-#ifdef MODULE
- 	irda_device_init();  /* Called by init/main.c when non-modular */
-#endif
+ 	irda_device_init();
 	return 0;
 }
-#ifdef MODULE
-module_init(irda_proto_init);	/* If non-module, called from init/main.c */
-#endif
+
+late_initcall(irda_proto_init);
 
 /*
  * Function irda_proto_cleanup (void)
diff -urN linux-2.5.3-pre3/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c
--- linux-2.5.3-pre3/net/netlink/af_netlink.c	Wed Jan 23 17:31:02 2002
+++ linux/net/netlink/af_netlink.c	Wed Jan 23 17:31:05 2002
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
 #include <net/sock.h>
@@ -47,8 +47,6 @@
 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
 #define NL_EMULATE_DEV
 #endif
-
-#define BUG_TRAP(x) if (!(x)) { printk("Assertion (" #x ") failed at " __FILE__ "(%d):" __FUNCTION__ "\n", __LINE__); }
 
 struct netlink_opt
 {
diff -urN linux-2.5.3-pre3/net/netsyms.c linux/net/netsyms.c
--- linux-2.5.3-pre3/net/netsyms.c	Wed Jan 23 17:31:02 2002
+++ linux/net/netsyms.c	Wed Jan 23 17:31:05 2002
@@ -292,6 +292,8 @@
 EXPORT_SYMBOL(ndisc_mc_map);
 EXPORT_SYMBOL(register_inet6addr_notifier);
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
+#include <net/ip6_route.h>
+EXPORT_SYMBOL(ip6_route_output);
 #endif
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_KHTTPD) || defined (CONFIG_KHTTPD_MODULE)
 /* inet functions common to v4 and v6 */
@@ -517,6 +519,10 @@
 
 #ifdef CONFIG_HIPPI
 EXPORT_SYMBOL(hippi_type_trans);
+#endif
+
+#ifdef CONFIG_NET_FASTROUTE
+EXPORT_SYMBOL(netdev_fastroute);
 #endif
 
 #ifdef CONFIG_SYSCTL
