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

diff -urN linux-2.5.63-bk6/Makefile linux-2.5.63-bk7/Makefile
--- linux-2.5.63-bk6/Makefile	Mon Mar 31 12:20:04 2003
+++ linux-2.5.63-bk7/Makefile	Mon Mar 31 12:20:09 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 63
-EXTRAVERSION = bk6
+EXTRAVERSION = bk7
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
diff -urN linux-2.5.63-bk6/arch/arm/mach-pxa/irq.c linux-2.5.63-bk7/arch/arm/mach-pxa/irq.c
--- linux-2.5.63-bk6/arch/arm/mach-pxa/irq.c	Mon Mar 31 12:20:04 2003
+++ linux-2.5.63-bk7/arch/arm/mach-pxa/irq.c	Mon Mar 31 12:20:09 2003
@@ -86,7 +86,7 @@
 }
 
 /*
- * GPIO IRQs must be acknoledged.  This is for GPIO 0 and 1.
+ * GPIO IRQs must be acknowledged.  This is for GPIO 0 and 1.
  */
 
 static void pxa_ack_low_gpio(unsigned int irq)
diff -urN linux-2.5.63-bk6/arch/arm/mach-sa1100/irq.c linux-2.5.63-bk7/arch/arm/mach-sa1100/irq.c
--- linux-2.5.63-bk6/arch/arm/mach-sa1100/irq.c	Mon Feb 24 11:05:47 2003
+++ linux-2.5.63-bk7/arch/arm/mach-sa1100/irq.c	Mon Mar 31 12:20:09 2003
@@ -68,7 +68,7 @@
 }
 
 /*
- * GPIO IRQs must be acknoledged.  This is for IRQs from 0 to 10.
+ * GPIO IRQs must be acknowledged.  This is for IRQs from 0 to 10.
  */
 static void sa1100_low_gpio_ack(unsigned int irq)
 {
diff -urN linux-2.5.63-bk6/arch/cris/kernel/kgdb.c linux-2.5.63-bk7/arch/cris/kernel/kgdb.c
--- linux-2.5.63-bk6/arch/cris/kernel/kgdb.c	Mon Mar 31 12:20:04 2003
+++ linux-2.5.63-bk7/arch/cris/kernel/kgdb.c	Mon Mar 31 12:20:09 2003
@@ -152,7 +152,7 @@
  *    (IPL too high, disabled, ...)
  *
  *  - The gdb stub is currently not reentrant, i.e. errors that happen therein
- *    (e.g. accesing invalid memory) may not be caught correctly. This could
+ *    (e.g. accessing invalid memory) may not be caught correctly. This could
  *    be removed in future by introducing a stack of struct registers.
  *
  */
diff -urN linux-2.5.63-bk6/arch/i386/mach-voyager/voyager_smp.c linux-2.5.63-bk7/arch/i386/mach-voyager/voyager_smp.c
--- linux-2.5.63-bk6/arch/i386/mach-voyager/voyager_smp.c	Mon Mar 31 12:20:05 2003
+++ linux-2.5.63-bk7/arch/i386/mach-voyager/voyager_smp.c	Mon Mar 31 12:20:09 2003
@@ -1473,7 +1473,7 @@
 		outb((__u8)cpuset, VIC_CPI_Registers[VIC_CPI_LEVEL0]);
 }
 
-/* Acknowlege receipt of CPI in the QIC, clear in QIC hardware and
+/* Acknowledge receipt of CPI in the QIC, clear in QIC hardware and
  * set the cache line to shared by reading it.
  *
  * DON'T make this inline otherwise the cache line read will be
diff -urN linux-2.5.63-bk6/arch/ia64/sn/io/l1.c linux-2.5.63-bk7/arch/ia64/sn/io/l1.c
--- linux-2.5.63-bk6/arch/ia64/sn/io/l1.c	Mon Feb 24 11:05:44 2003
+++ linux-2.5.63-bk7/arch/ia64/sn/io/l1.c	Mon Mar 31 12:20:09 2003
@@ -2602,7 +2602,7 @@
 {
     sc_cq_t *q;         /* receive queue */
     int before_wrap,    /* packet may be split into two different       */
-        after_wrap;     /*   pieces to acommodate queue wraparound      */
+        after_wrap;     /*   pieces to accommodate queue wraparound      */
 
     /* pull message off the receive queue */
     q = subch->iqp;
diff -urN linux-2.5.63-bk6/arch/sparc/Kconfig linux-2.5.63-bk7/arch/sparc/Kconfig
--- linux-2.5.63-bk6/arch/sparc/Kconfig	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/arch/sparc/Kconfig	Mon Mar 31 12:20:09 2003
@@ -148,7 +148,7 @@
 config MCA
 	bool
 	help
-	  EISA is not supported.
+	  MCA is not supported.
 	  Say N
 
 config PCMCIA
diff -urN linux-2.5.63-bk6/arch/sparc/mm/iommu.c linux-2.5.63-bk7/arch/sparc/mm/iommu.c
--- linux-2.5.63-bk6/arch/sparc/mm/iommu.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/arch/sparc/mm/iommu.c	Mon Mar 31 12:20:09 2003
@@ -112,7 +112,7 @@
 	for (i = 6; i < 9; i++)
 		if ((1 << (i + PAGE_SHIFT)) == ptsize)
 			break;
-        tmp = __get_free_pages(GFP_DMA, i);
+        tmp = __get_free_pages(GFP_KERNEL, i);
 	if (!tmp) {
 		prom_printf("Could not allocate iopte of size 0x%08x\n", ptsize);
 		prom_halt();
diff -urN linux-2.5.63-bk6/arch/sparc64/Kconfig linux-2.5.63-bk7/arch/sparc64/Kconfig
--- linux-2.5.63-bk6/arch/sparc64/Kconfig	Mon Feb 24 11:05:42 2003
+++ linux-2.5.63-bk7/arch/sparc64/Kconfig	Mon Mar 31 12:20:09 2003
@@ -150,18 +150,6 @@
 
 	  If in doubt, say N.
 
-config CPU_FREQ_PROC_INTF
-	tristate "/proc/cpufreq interface (DEPRECATED)"
-	depends on CPU_FREQ && PROC_FS
-	help
-	  This enables the /proc/cpufreq interface for controlling
-	  CPUFreq. Please note that it is recommended to use the sysfs
-	  interface instead (which is built automatically). 
-	  
-	  For details, take a look at linux/Documentation/cpufreq. 
-	  
-	  If in doubt, say N.
-
 config CPU_FREQ_TABLE
        tristate
        default y
@@ -177,6 +165,8 @@
 
 	  If in doubt, say N.
 
+source "drivers/cpufreq/Kconfig"
+
 # Identify this as a Sparc64 build
 config SPARC64
 	bool
diff -urN linux-2.5.63-bk6/arch/sparc64/defconfig linux-2.5.63-bk7/arch/sparc64/defconfig
--- linux-2.5.63-bk6/arch/sparc64/defconfig	Mon Feb 24 11:05:15 2003
+++ linux-2.5.63-bk7/arch/sparc64/defconfig	Mon Mar 31 12:20:09 2003
@@ -15,12 +15,6 @@
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
-# CONFIG_LOG_BUF_SHIFT_17 is not set
-# CONFIG_LOG_BUF_SHIFT_16 is not set
-CONFIG_LOG_BUF_SHIFT_15=y
-# CONFIG_LOG_BUF_SHIFT_14 is not set
-# CONFIG_LOG_BUF_SHIFT_13 is not set
-# CONFIG_LOG_BUF_SHIFT_12 is not set
 CONFIG_LOG_BUF_SHIFT=15
 
 #
@@ -30,6 +24,7 @@
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 
 #
@@ -45,6 +40,7 @@
 CONFIG_NR_CPUS=4
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_PROC_INTF=y
+CONFIG_CPU_FREQ_TABLE=y
 CONFIG_US3_FREQ=m
 CONFIG_SPARC64=y
 CONFIG_HOTPLUG=y
@@ -89,15 +85,52 @@
 #
 # Graphics support
 #
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_BW2 is not set
+# CONFIG_FB_CG3 is not set
+CONFIG_FB_CG6=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_PM3 is not set
+CONFIG_FB_SBUS=y
+CONFIG_FB_FFB=y
+# CONFIG_FB_TCX is not set
+# CONFIG_FB_CG14 is not set
+# CONFIG_FB_P9100 is not set
+# CONFIG_FB_LEO is not set
+# CONFIG_FB_PCI is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
 # Console display driver support
 #
 # CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
-CONFIG_PROM_CONSOLE=y
+# CONFIG_PROM_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FONT_SUN8x16=y
+# CONFIG_FONT_SUN12x22 is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
 
 #
 # Serial drivers
@@ -110,7 +143,7 @@
 CONFIG_SERIAL_SUNCORE=y
 CONFIG_SERIAL_SUNZILOG=y
 CONFIG_SERIAL_SUNSU=y
-# CONFIG_SERIAL_SUNSAB is not set
+CONFIG_SERIAL_SUNSAB=m
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 
@@ -190,7 +223,7 @@
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
-CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5520 is not set
@@ -198,7 +231,7 @@
 # CONFIG_BLK_DEV_HPT366 is not set
 # CONFIG_BLK_DEV_SC1200 is not set
 # CONFIG_BLK_DEV_PIIX is not set
-CONFIG_BLK_DEV_NS87415=y
+# CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX_OLD is not set
 # CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -221,9 +254,9 @@
 #
 CONFIG_BLK_DEV_SD=y
 CONFIG_SD_EXTRA_DEVS=40
-CONFIG_CHR_DEV_ST=y
+CONFIG_CHR_DEV_ST=m
 CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR=m
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=m
@@ -320,11 +353,12 @@
 CONFIG_INET_ESP=y
 CONFIG_XFRM_USER=m
 CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
+CONFIG_IPV6_SCTP__=m
 CONFIG_IP_SCTP=m
 # CONFIG_SCTP_ADLER32 is not set
 # CONFIG_SCTP_DBG_MSG is not set
@@ -395,6 +429,7 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
 CONFIG_SUNLANCE=y
 CONFIG_HAPPYMEAL=y
 CONFIG_SUNBMAC=m
@@ -402,6 +437,7 @@
 CONFIG_SUNGEM=y
 CONFIG_NET_VENDOR_3COM=y
 CONFIG_VORTEX=m
+CONFIG_TYPHOON=m
 
 #
 # Tulip family network device support
@@ -419,9 +455,11 @@
 CONFIG_PCNET32=m
 # CONFIG_AMD8111_ETH is not set
 CONFIG_ADAPTEC_STARFIRE=m
+CONFIG_ADAPTEC_STARFIRE_NAPI=y
 CONFIG_B44=m
 CONFIG_DGRS=m
 CONFIG_EEPRO100=m
+# CONFIG_EEPRO100_PIO is not set
 CONFIG_E100=m
 CONFIG_FEALNX=m
 CONFIG_NATSEMI=m
@@ -940,6 +978,7 @@
 CONFIG_BT_HCIUART=m
 CONFIG_BT_HCIUART_H4=y
 CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
 CONFIG_BT_HCIVHCI=m
 
 #
diff -urN linux-2.5.63-bk6/arch/sparc64/kernel/Makefile linux-2.5.63-bk7/arch/sparc64/kernel/Makefile
--- linux-2.5.63-bk6/arch/sparc64/kernel/Makefile	Mon Feb 24 11:05:11 2003
+++ linux-2.5.63-bk7/arch/sparc64/kernel/Makefile	Mon Mar 31 12:20:09 2003
@@ -3,7 +3,7 @@
 #
 
 EXTRA_AFLAGS := -ansi
-CFLAGS += -Werror
+EXTRA_CFLAGS := -Werror
 
 EXTRA_TARGETS	:= head.o init_task.o
 
diff -urN linux-2.5.63-bk6/arch/sparc64/kernel/sparc64_ksyms.c linux-2.5.63-bk7/arch/sparc64/kernel/sparc64_ksyms.c
--- linux-2.5.63-bk6/arch/sparc64/kernel/sparc64_ksyms.c	Mon Feb 24 11:05:40 2003
+++ linux-2.5.63-bk7/arch/sparc64/kernel/sparc64_ksyms.c	Mon Mar 31 12:20:09 2003
@@ -114,6 +114,8 @@
 extern unsigned long phys_base;
 extern unsigned long pfn_base;
 
+extern unsigned int sys_call_table[];
+
 /* used by various drivers */
 #ifdef CONFIG_SMP
 #ifndef CONFIG_DEBUG_SPINLOCK
@@ -374,3 +376,6 @@
 
 /* for ns8703 */
 EXPORT_SYMBOL(ns87303_lock);
+
+/* for solaris compat module */
+EXPORT_SYMBOL_GPL(sys_call_table);
diff -urN linux-2.5.63-bk6/arch/sparc64/kernel/us3_cpufreq.c linux-2.5.63-bk7/arch/sparc64/kernel/us3_cpufreq.c
--- linux-2.5.63-bk6/arch/sparc64/kernel/us3_cpufreq.c	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/arch/sparc64/kernel/us3_cpufreq.c	Mon Mar 31 12:20:09 2003
@@ -186,12 +186,16 @@
 	set_cpus_allowed(current, cpus_allowed);
 }
 
-static int us3freq_setpolicy(struct cpufreq_policy *policy)
+static int us3freq_target(struct cpufreq_policy *policy,
+			  unsigned int target_freq,
+			  unsigned int relation)
 {
 	unsigned int new_index = 0;
 
-	if (cpufreq_frequency_table_setpolicy(policy,
+	if (cpufreq_frequency_table_target(policy,
 					      &us3_freq_table[policy->cpu].table[0],
+					      target_freq,
+					      relation,
 					      &new_index))
 		return -EINVAL;
 
@@ -224,6 +228,7 @@
 
 	policy->policy = CPUFREQ_POLICY_PERFORMANCE;
 	policy->cpuinfo.transition_latency = 0;
+	policy->cur = clock_tick;
 
 	return cpufreq_frequency_table_cpuinfo(policy, table);
 }
@@ -268,7 +273,7 @@
 		       (NR_CPUS * sizeof(struct us3_freq_percpu_info)));
 
 		driver->verify = us3freq_verify;
-		driver->setpolicy = us3freq_setpolicy;
+		driver->target = us3freq_target;
 		driver->init = us3freq_cpu_init;
 		driver->exit = us3freq_cpu_exit;
 		strcpy(driver->name, "UltraSPARC-III");
diff -urN linux-2.5.63-bk6/arch/sparc64/lib/Makefile linux-2.5.63-bk7/arch/sparc64/lib/Makefile
--- linux-2.5.63-bk6/arch/sparc64/lib/Makefile	Mon Feb 24 11:05:06 2003
+++ linux-2.5.63-bk7/arch/sparc64/lib/Makefile	Mon Mar 31 12:20:09 2003
@@ -3,7 +3,7 @@
 #
 
 EXTRA_AFLAGS := -ansi
-CFLAGS += -Werror
+EXTRA_CFLAGS := -Werror
 
 L_TARGET = lib.a
 obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \
diff -urN linux-2.5.63-bk6/arch/sparc64/mm/Makefile linux-2.5.63-bk7/arch/sparc64/mm/Makefile
--- linux-2.5.63-bk6/arch/sparc64/mm/Makefile	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/arch/sparc64/mm/Makefile	Mon Mar 31 12:20:09 2003
@@ -3,7 +3,7 @@
 #
 
 EXTRA_AFLAGS := -ansi
-CFLAGS += -Werror
+EXTRA_CFLAGS := -Werror
 
 obj-y    := ultra.o fault.o init.o generic.o extable.o
 
diff -urN linux-2.5.63-bk6/arch/sparc64/prom/Makefile linux-2.5.63-bk7/arch/sparc64/prom/Makefile
--- linux-2.5.63-bk6/arch/sparc64/prom/Makefile	Mon Feb 24 11:05:40 2003
+++ linux-2.5.63-bk7/arch/sparc64/prom/Makefile	Mon Mar 31 12:20:09 2003
@@ -4,7 +4,7 @@
 #
 
 EXTRA_AFLAGS := -ansi
-CFLAGS += -Werror
+EXTRA_CFLAGS := -Werror
 
 L_TARGET = lib.a
 obj-y   := bootstr.o devops.o init.o memory.o misc.o \
diff -urN linux-2.5.63-bk6/arch/sparc64/solaris/entry64.S linux-2.5.63-bk7/arch/sparc64/solaris/entry64.S
--- linux-2.5.63-bk6/arch/sparc64/solaris/entry64.S	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/arch/sparc64/solaris/entry64.S	Mon Mar 31 12:20:09 2003
@@ -16,6 +16,7 @@
 #include <asm/signal.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/thread_info.h>
 
 #include "conv.h"
 
diff -urN linux-2.5.63-bk6/drivers/atm/fore200e.c linux-2.5.63-bk7/drivers/atm/fore200e.c
--- linux-2.5.63-bk6/drivers/atm/fore200e.c	Mon Feb 24 11:06:02 2003
+++ linux-2.5.63-bk7/drivers/atm/fore200e.c	Mon Mar 31 12:20:09 2003
@@ -1132,8 +1132,7 @@
 	return;
     } 
 
-	do_gettimeofday(&vcc->timestamp);
-    skb->stamp = vcc->timestamp;
+    do_gettimeofday(&skb->stamp);
     
 #ifdef FORE200E_52BYTE_AAL0_SDU
     if (cell_header) {
diff -urN linux-2.5.63-bk6/drivers/atm/suni.c linux-2.5.63-bk7/drivers/atm/suni.c
--- linux-2.5.63-bk6/drivers/atm/suni.c	Mon Feb 24 11:05:40 2003
+++ linux-2.5.63-bk7/drivers/atm/suni.c	Mon Mar 31 12:20:09 2003
@@ -233,8 +233,6 @@
 	if (!(PRIV(dev) = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
 		return -ENOMEM;
 
-	MOD_INC_USE_COUNT;
-
 	PRIV(dev)->dev = dev;
 	spin_lock_irqsave(&sunis_lock,flags);
 	first = !sunis;
@@ -280,7 +278,6 @@
 	spin_unlock_irqrestore(&sunis_lock,flags);
 	kfree(PRIV(dev));
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -293,7 +290,7 @@
 };
 
 
-int __init suni_init(struct atm_dev *dev)
+int suni_init(struct atm_dev *dev)
 {
 	unsigned char mri;
 
diff -urN linux-2.5.63-bk6/drivers/base/base.h linux-2.5.63-bk7/drivers/base/base.h
--- linux-2.5.63-bk6/drivers/base/base.h	Mon Feb 24 11:05:16 2003
+++ linux-2.5.63-bk7/drivers/base/base.h	Mon Mar 31 12:20:09 2003
@@ -1,6 +1,7 @@
 #undef DEBUG
 
 extern struct semaphore device_sem;
+extern struct semaphore devclass_sem;
 
 extern int bus_add_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
diff -urN linux-2.5.63-bk6/drivers/base/class.c linux-2.5.63-bk7/drivers/base/class.c
--- linux-2.5.63-bk6/drivers/base/class.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/drivers/base/class.c	Mon Mar 31 12:20:09 2003
@@ -13,6 +13,8 @@
 #define to_class_attr(_attr) container_of(_attr,struct devclass_attribute,attr)
 #define to_class(obj) container_of(obj,struct device_class,subsys.kset.kobj)
 
+DECLARE_MUTEX(devclass_sem);
+
 static ssize_t
 devclass_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -163,29 +165,34 @@
 	struct device_class * cls;
 	int error = 0;
 
+	down(&devclass_sem);
 	if (dev->driver) {
 		cls = get_devclass(dev->driver->devclass);
-		if (cls) {
-			down_write(&cls->subsys.rwsem);
-			pr_debug("device class %s: adding device %s\n",
-				 cls->name,dev->name);
-			if (cls->add_device) 
-				error = cls->add_device(dev);
-			if (!error) {
-				enum_device(cls,dev);
-				interface_add_dev(dev);
-			}
-
-			list_add_tail(&dev->class_list,&cls->devices.list);
-
-			/* notify userspace (call /sbin/hotplug) */
-			class_hotplug (dev, "add");
-
-			up_write(&cls->subsys.rwsem);
-			if (error)
-				put_devclass(cls);
+
+		if (!cls)
+			goto Done;
+
+		pr_debug("device class %s: adding device %s\n",
+			 cls->name,dev->name);
+		if (cls->add_device) 
+			error = cls->add_device(dev);
+		if (error) {
+			put_devclass(cls);
+			goto Done;
 		}
+
+		down_write(&cls->subsys.rwsem);
+		enum_device(cls,dev);
+		list_add_tail(&dev->class_list,&cls->devices.list);
+		/* notify userspace (call /sbin/hotplug) */
+		class_hotplug (dev, "add");
+
+		up_write(&cls->subsys.rwsem);
+
+		interface_add_dev(dev);
 	}
+ Done:
+	up(&devclass_sem);
 	return error;
 }
 
@@ -193,26 +200,33 @@
 {
 	struct device_class * cls;
 
+	down(&devclass_sem);
 	if (dev->driver) {
 		cls = dev->driver->devclass;
-		if (cls) {
-			down_write(&cls->subsys.rwsem);
-			pr_debug("device class %s: removing device %s\n",
-				 cls->name,dev->name);
-			interface_remove_dev(dev);
-			unenum_device(cls,dev);
-
-			list_del(&dev->class_list);
-
-			/* notify userspace (call /sbin/hotplug) */
-			class_hotplug (dev, "remove");
-
-			if (cls->remove_device)
-				cls->remove_device(dev);
-			up_write(&cls->subsys.rwsem);
-			put_devclass(cls);
-		}
+		if (!cls) 
+			goto Done;
+
+		interface_remove_dev(dev);
+
+		down_write(&cls->subsys.rwsem);
+		pr_debug("device class %s: removing device %s\n",
+			 cls->name,dev->name);
+
+		unenum_device(cls,dev);
+
+		list_del(&dev->class_list);
+
+		/* notify userspace (call /sbin/hotplug) */
+		class_hotplug (dev, "remove");
+
+		up_write(&cls->subsys.rwsem);
+
+		if (cls->remove_device)
+			cls->remove_device(dev);
+		put_devclass(cls);
 	}
+ Done:
+	up(&devclass_sem);
 }
 
 struct device_class * get_devclass(struct device_class * cls)
diff -urN linux-2.5.63-bk6/drivers/base/core.c linux-2.5.63-bk7/drivers/base/core.c
--- linux-2.5.63-bk6/drivers/base/core.c	Mon Feb 24 11:05:06 2003
+++ linux-2.5.63-bk7/drivers/base/core.c	Mon Mar 31 12:20:09 2003
@@ -143,7 +143,6 @@
 	INIT_LIST_HEAD(&dev->driver_list);
 	INIT_LIST_HEAD(&dev->bus_list);
 	INIT_LIST_HEAD(&dev->class_list);
-	INIT_LIST_HEAD(&dev->intf_list);
 }
 
 /**
diff -urN linux-2.5.63-bk6/drivers/base/intf.c linux-2.5.63-bk7/drivers/base/intf.c
--- linux-2.5.63-bk6/drivers/base/intf.c	Mon Feb 24 11:05:41 2003
+++ linux-2.5.63-bk7/drivers/base/intf.c	Mon Mar 31 12:20:09 2003
@@ -12,80 +12,31 @@
 
 #define to_intf(node) container_of(node,struct device_interface,kset.kobj.entry)
 
-#define to_data(e) container_of(e,struct intf_data,kobj.entry)
+#define to_dev(d) container_of(d,struct device,class_list)
 
 /**
  *	intf_dev_link - create sysfs symlink for interface.
- *	@data:	interface data descriptor.
+ *	@intf:	interface.
+ *	@dev:	device.
  *
  *	Create a symlink 'phys' in the interface's directory to 
  */
 
-static int intf_dev_link(struct intf_data * data)
+static int intf_dev_link(struct device_interface * intf, struct device * dev)
 {
-	char	name[16];
-	snprintf(name,16,"%d",data->intf_num);
-	return sysfs_create_link(&data->intf->kset.kobj,&data->dev->kobj,name);
+	return sysfs_create_link(&intf->kset.kobj,&dev->kobj,dev->bus_id);
 }
 
 /**
  *	intf_dev_unlink - remove symlink for interface.
- *	@intf:	interface data descriptor.
- *
- */
-
-static void intf_dev_unlink(struct intf_data * data)
-{
-	char	name[16];
-	snprintf(name,16,"%d",data->intf_num);
-	sysfs_remove_link(&data->intf->kset.kobj,name);
-}
-
-
-/**
- *	interface_add_data - attach data descriptor
- *	@data:	interface data descriptor.
- *
- *	This attaches the per-instance interface object to the
- *	interface (by registering its kobject) and the device
- *	itself (by inserting it into the device's list).
- *
- *	Note that there is no explicit protection done in this
- *	function. This should be called from the interface's 
- *	add_device() method, which is called under the protection
- *	of the class's rwsem.
- */
-
-int interface_add_data(struct intf_data * data)
-{
-	struct device_interface * intf = data->intf;
-
-	if (intf) {
-		data->intf_num = intf->devnum++;
-		data->kobj.kset = &intf->kset;
-		kobject_register(&data->kobj);
-
-		list_add_tail(&data->dev_entry,&data->dev->intf_list);
-		return intf_dev_link(data);
-	}
-	return -EINVAL;
-}
-
-
-/**
- *	interface_remove_data - detach data descriptor.
- *	@data:	interface data descriptor.
+ *	@intf:	interface.
+ *	@dev:	device.
  *
- *	This detaches the per-instance data descriptor by removing 
- *	it from the device's list and unregistering the kobject from
- *	the subsystem.
  */
 
-void interface_remove_data(struct intf_data * data)
+static void intf_dev_unlink(struct device_interface * intf, struct device * dev)
 {
-	intf_dev_unlink(data);
-	list_del_init(&data->dev_entry);
-	kobject_unregister(&data->kobj);
+	sysfs_remove_link(&intf->kset.kobj,dev->bus_id);
 }
 
 
@@ -103,33 +54,28 @@
 {
 	int error = 0;
 
-	if (intf->add_device) 
-		error = intf->add_device(dev);
+	if (intf->add_device) {
+		if (!(error = intf->add_device(dev)))
+			intf_dev_link(intf,dev);
+	}
 	pr_debug(" -> %s (%d)\n",dev->bus_id,error);
 	return error;
 }
 
 /**
  *	del - detach device from interface.
- *	@data:	interface data descriptor.
- *
- *	Another simple helper. Remove the data descriptor from 
- *	the device and the interface, then call the interface's 
- *	remove_device() method.
+ *	@intf:	interface.
+ *	@dev:	device.
  */
 
-static void del(struct intf_data * data)
+static void del(struct device_interface * intf, struct device * dev)
 {
-	struct device_interface * intf = data->intf;
-
 	pr_debug(" -> %s ",intf->name);
-	interface_remove_data(data);
 	if (intf->remove_device)
-		intf->remove_device(data);
+		intf->remove_device(dev);
+	intf_dev_unlink(intf,dev);
 }
 
-#define to_dev(entry) container_of(entry,struct device,class_list)
-
 
 /**
  *	add_intf - add class's devices to interface.
@@ -145,10 +91,8 @@
 	struct device_class * cls = intf->devclass;
 	struct list_head * entry;
 
-	down_write(&cls->subsys.rwsem);
 	list_for_each(entry,&cls->devices.list)
 		add(intf,to_dev(entry));
-	up_write(&cls->subsys.rwsem);
 }
 
 /**
@@ -164,6 +108,7 @@
 {
 	struct device_class * cls = get_devclass(intf->devclass);
 
+	down(&devclass_sem);
 	if (cls) {
 		pr_debug("register interface '%s' with class '%s'\n",
 			 intf->name,cls->name);
@@ -173,6 +118,7 @@
 		kset_register(&intf->kset);
 		add_intf(intf);
 	}
+	up(&devclass_sem);
 	return 0;
 }
 
@@ -188,14 +134,13 @@
 
 static void del_intf(struct device_interface * intf)
 {
+	struct device_class * cls = intf->devclass;
 	struct list_head * entry;
 
-	down_write(&intf->devclass->subsys.rwsem);
-	list_for_each(entry,&intf->kset.list) {
-		struct intf_data * data = to_data(entry);
-		del(data);
+	list_for_each(entry,&cls->devices.list) {
+		struct device * dev = to_dev(entry);
+		del(intf,dev);
 	}
-	up_write(&intf->devclass->subsys.rwsem);
 }
 
 /**
@@ -210,6 +155,8 @@
 void interface_unregister(struct device_interface * intf)
 {
 	struct device_class * cls = intf->devclass;
+
+	down(&devclass_sem);
 	if (cls) {
 		pr_debug("unregistering interface '%s' from class '%s'\n",
 			 intf->name,cls->name);
@@ -217,6 +164,7 @@
 		kset_unregister(&intf->kset);
 		put_devclass(cls);
 	}
+	up(&devclass_sem);
 }
 
 
@@ -255,20 +203,21 @@
  *	This is another helper for the class driver core, and called
  *	when the device is being removed from the class. 
  *	
- *	We iterate over the list of interface data descriptors attached
- *	to the device, and call del() [above] for each. Again, the 
- *	class's rwsem is assumed to be held during this.
+ *	We iterate over the list of the class's devices and call del() 
+ *	[above] for each. Again, the class's rwsem is _not_ held, but
+ *	the devclass_sem is (see class.c).
  */
 
 void interface_remove_dev(struct device * dev)
 {
 	struct list_head * entry, * next;
+	struct device_class * cls = dev->driver->devclass;
 
 	pr_debug("interfaces: removing device %s\n",dev->name);
 
-	list_for_each_safe(entry,next,&dev->intf_list) {
-		struct intf_data * intf_data = to_data(entry);
-		del(intf_data);
+	list_for_each_safe(entry,next,&cls->subsys.kset.list) {
+		struct device_interface * intf = to_intf(entry);
+		del(intf,dev);
 	}
 }
 
diff -urN linux-2.5.63-bk6/drivers/cdrom/cdrom.c linux-2.5.63-bk7/drivers/cdrom/cdrom.c
--- linux-2.5.63-bk6/drivers/cdrom/cdrom.c	Mon Mar 31 12:20:05 2003
+++ linux-2.5.63-bk7/drivers/cdrom/cdrom.c	Mon Mar 31 12:20:09 2003
@@ -173,7 +173,7 @@
   -- Fixed the CDROMREADxxx ioctls.
   -- CDROMPLAYTRKIND uses the GPCMD_PLAY_AUDIO_MSF command - too few
   drives supported it. We lose the index part, however.
-  -- Small modifications to accomodate opens of /dev/hdc1, required
+  -- Small modifications to accommodate opens of /dev/hdc1, required
   for ide-cd to handle multisession discs.
   -- Export cdrom_mode_sense and cdrom_mode_select.
   -- init_cdrom_command() for setting up a cgc command.
diff -urN linux-2.5.63-bk6/drivers/char/cd1865.h linux-2.5.63-bk7/drivers/char/cd1865.h
--- linux-2.5.63-bk6/drivers/char/cd1865.h	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/drivers/char/cd1865.h	Mon Mar 31 12:20:09 2003
@@ -54,9 +54,9 @@
 #define CD186x_RCSR      0x7a    /* Receiver Character Status Register      */
 #define CD186x_TDR       0x7b    /* Transmit Data Register                  */
 #define CD186x_EOIR      0x7f    /* End of Interrupt Register               */
-#define CD186x_MRAR      0x75    /* Modem Request Acknowlege register       */
-#define CD186x_TRAR      0x76    /* Transmit Request Acknowlege register    */
-#define CD186x_RRAR      0x77    /* Receive Request Acknowlege register     */
+#define CD186x_MRAR      0x75    /* Modem Request Acknowledge register       */
+#define CD186x_TRAR      0x76    /* Transmit Request Acknowledge register    */
+#define CD186x_RRAR      0x77    /* Receive Request Acknowledge register     */
 #define CD186x_SRCR      0x66    /* Service Request Configuration register  */
 
 /* Channel Registers */
diff -urN linux-2.5.63-bk6/drivers/char/drm/i810_drm.h linux-2.5.63-bk7/drivers/char/drm/i810_drm.h
--- linux-2.5.63-bk6/drivers/char/drm/i810_drm.h	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/drivers/char/drm/i810_drm.h	Mon Mar 31 12:20:09 2003
@@ -38,7 +38,7 @@
  *    - zbuffer linear offset and pitch -- also invarient
  *    - drawing origin in back and depth buffers.
  *
- * Keep the depth/back buffer state here to acommodate private buffers
+ * Keep the depth/back buffer state here to accommodate private buffers
  * in the future.
  */
 #define I810_DESTREG_DI0  0	/* CMD_OP_DESTBUFFER_INFO (2 dwords) */
diff -urN linux-2.5.63-bk6/drivers/char/drm/i830_drm.h linux-2.5.63-bk7/drivers/char/drm/i830_drm.h
--- linux-2.5.63-bk6/drivers/char/drm/i830_drm.h	Mon Feb 24 11:05:16 2003
+++ linux-2.5.63-bk7/drivers/char/drm/i830_drm.h	Mon Mar 31 12:20:09 2003
@@ -68,7 +68,7 @@
  *    - zbuffer linear offset and pitch -- also invarient
  *    - drawing origin in back and depth buffers.
  *
- * Keep the depth/back buffer state here to acommodate private buffers
+ * Keep the depth/back buffer state here to accommodate private buffers
  * in the future.
  */
 
diff -urN linux-2.5.63-bk6/drivers/char/tty_io.c linux-2.5.63-bk7/drivers/char/tty_io.c
--- linux-2.5.63-bk6/drivers/char/tty_io.c	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/drivers/char/tty_io.c	Mon Mar 31 12:20:09 2003
@@ -1944,27 +1944,25 @@
 		schedule_delayed_work(&tty->flip.work, 1);
 		return;
 	}
+
+	spin_lock_irqsave(&tty->read_lock, flags);
 	if (tty->flip.buf_num) {
 		cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
 		fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
 		tty->flip.buf_num = 0;
-
-		local_irq_save(flags); // FIXME: is this safe?
 		tty->flip.char_buf_ptr = tty->flip.char_buf;
 		tty->flip.flag_buf_ptr = tty->flip.flag_buf;
 	} else {
 		cp = tty->flip.char_buf;
 		fp = tty->flip.flag_buf;
 		tty->flip.buf_num = 1;
-
-		local_irq_save(flags); // FIXME: is this safe?
 		tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
 		tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
 	}
 	count = tty->flip.count;
 	tty->flip.count = 0;
-	local_irq_restore(flags); // FIXME: is this safe?
-	
+	spin_unlock_irqrestore(&tty->read_lock, flags);
+
 	tty->ldisc.receive_buf(tty, cp, fp, count);
 }
 
diff -urN linux-2.5.63-bk6/drivers/net/fc/iph5526.c linux-2.5.63-bk7/drivers/net/fc/iph5526.c
--- linux-2.5.63-bk6/drivers/net/fc/iph5526.c	Mon Mar 31 12:20:05 2003
+++ linux-2.5.63-bk7/drivers/net/fc/iph5526.c	Mon Mar 31 12:20:11 2003
@@ -3175,38 +3175,6 @@
 	LEAVE("rx_net_mfs_packet");
 }
 
-unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev) 
-{
-struct fch_hdr *fch=(struct fch_hdr *)skb->data;
-struct fcllc *fcllc;
-	skb->mac.raw = skb->data;
-	fcllc = (struct fcllc *)(skb->data + sizeof(struct fch_hdr) + 2);
-	skb_pull(skb,sizeof(struct fch_hdr) + 2);
-
-	if(*fch->daddr & 1) {
-		if(!memcmp(fch->daddr,dev->broadcast,FC_ALEN)) 	
-			skb->pkt_type = PACKET_BROADCAST;
-		else
-			skb->pkt_type = PACKET_MULTICAST;
-	}
-	else if(dev->flags & IFF_PROMISC) {
-		if(memcmp(fch->daddr, dev->dev_addr, FC_ALEN))
-			skb->pkt_type=PACKET_OTHERHOST;
-	}
-	
-	/* Strip the SNAP header from ARP packets since we don't 
-	 * pass them through to the 802.2/SNAP layers.
-	 */
-
-	if (fcllc->dsap == EXTENDED_SAP &&
-		(fcllc->ethertype == ntohs(ETH_P_IP) ||
-		 fcllc->ethertype == ntohs(ETH_P_ARP))) {
-		skb_pull(skb, sizeof(struct fcllc));
-		return fcllc->ethertype;
-	}
-	return ntohs(ETH_P_802_2);
-}
-
 static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short tx_ox_id, u_int frame_class)
 {
 u_char df_ctl; 
diff -urN linux-2.5.63-bk6/drivers/net/sk98lin/skge.c linux-2.5.63-bk7/drivers/net/sk98lin/skge.c
--- linux-2.5.63-bk6/drivers/net/sk98lin/skge.c	Mon Feb 24 11:05:10 2003
+++ linux-2.5.63-bk7/drivers/net/sk98lin/skge.c	Mon Mar 31 12:20:12 2003
@@ -3627,7 +3627,7 @@
  * Description:
  *	This routine writes a 16 bit value to the pci configuration
  *	space. The flag PciConfigUp indicates whether the config space
- *	is accesible or must be set up first.
+ *	is accessible or must be set up first.
  *
  * Returns:
  *	0 - indicate everything worked ok.
@@ -3650,7 +3650,7 @@
  * Description:
  *	This routine writes a 8 bit value to the pci configuration
  *	space. The flag PciConfigUp indicates whether the config space
- *	is accesible or must be set up first.
+ *	is accessible or must be set up first.
  *
  * Returns:
  *	0 - indicate everything worked ok.
diff -urN linux-2.5.63-bk6/drivers/net/sk98lin/ski2c.c linux-2.5.63-bk7/drivers/net/sk98lin/ski2c.c
--- linux-2.5.63-bk6/drivers/net/sk98lin/ski2c.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/drivers/net/sk98lin/ski2c.c	Mon Mar 31 12:20:12 2003
@@ -444,7 +444,7 @@
 /*
  * Receive an ACK.
  *
- * returns	0 If acknoledged
+ * returns	0 If acknowledged
  *		1 in case of an error
  */
 int SkI2cRcvAck(
diff -urN linux-2.5.63-bk6/drivers/net/sunhme.c linux-2.5.63-bk7/drivers/net/sunhme.c
--- linux-2.5.63-bk6/drivers/net/sunhme.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/drivers/net/sunhme.c	Mon Mar 31 12:20:12 2003
@@ -520,7 +520,7 @@
 	ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
 
 	/* Welcome to Sun Microsystems, can I take your order please? */
-	if (!hp->happy_flags & HFLAG_FENABLE)
+	if (!(hp->happy_flags & HFLAG_FENABLE))
 		return happy_meal_bb_write(hp, tregs, reg, value);
 
 	/* Would you like fries with that? */
diff -urN linux-2.5.63-bk6/drivers/s390/block/dasd_eckd.c linux-2.5.63-bk7/drivers/s390/block/dasd_eckd.c
--- linux-2.5.63-bk6/drivers/s390/block/dasd_eckd.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/drivers/s390/block/dasd_eckd.c	Mon Mar 31 12:20:14 2003
@@ -19,7 +19,7 @@
  * 10/04/00 changed RW-CCWS to R/W Key and Data
  * 10/10/00 reverted last change according to ESS exploitation
  * 10/10/00 now dequeuing init_cqr before freeing *ouch*
- * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
+ * 26/10/00 fixed ITPM20144ASC (problems when accessing a device formatted by VIF)
  * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
  *	    fixed partition handling and HDIO_GETGEO
  * 2002/01/04 Created 2.4-2.5 compatibility mode
diff -urN linux-2.5.63-bk6/drivers/scsi/pcmcia/nsp_cs.h linux-2.5.63-bk7/drivers/scsi/pcmcia/nsp_cs.h
--- linux-2.5.63-bk6/drivers/scsi/pcmcia/nsp_cs.h	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/drivers/scsi/pcmcia/nsp_cs.h	Mon Mar 31 12:20:15 2003
@@ -183,7 +183,7 @@
 #define S_ATN		0x80	/**/
 #define S_SELECT	0x40	/**/
 #define S_REQUEST	0x20    /* Request line from SCSI bus*/
-#define S_ACK		0x10    /* Acknowlege line from SCSI bus*/
+#define S_ACK		0x10    /* Acknowledge line from SCSI bus*/
 #define S_BUSY		0x08    /* Busy line from SCSI bus*/
 #define S_CD		0x04    /* Command/Data line from SCSI bus*/
 #define S_IO		0x02    /* Input/Output line from SCSI bus*/
diff -urN linux-2.5.63-bk6/drivers/video/Kconfig linux-2.5.63-bk7/drivers/video/Kconfig
--- linux-2.5.63-bk6/drivers/video/Kconfig	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/drivers/video/Kconfig	Mon Mar 31 12:20:15 2003
@@ -376,19 +376,19 @@
 	bool "Sun3 framebuffer support"
 	depends on FB && (SUN3 || SUN3X)
 
-config FB_BWTWO
+config FB_BW2
 	bool "BWtwo support"
 	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
 	help
 	  This is the frame buffer device driver for the BWtwo frame buffer.
 
-config FB_CGTHREE
+config FB_CG3
 	bool "CGthree support"
 	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
 	help
 	  This is the frame buffer device driver for the CGthree frame buffer.
 
-config FB_CGSIX
+config FB_CG6
 	bool "CGsix (GX,TurboGX) support"
 	depends on FB && ((SPARC32 || SPARC64) && FB_SBUS || (SUN3 || SUN3X) && FB_SUN3)
 	help
@@ -809,30 +809,30 @@
 	help
 	  Say Y if you want support for SBUS or UPA based frame buffer device.
 
-config FB_CREATOR
-	bool "Creator/Creator3D support"
+config FB_FFB
+	bool "Creator/Creator3D/Elite3D support"
 	depends on FB_SBUS && SPARC64
 	help
-	  This is the frame buffer device driver for the Creator and Creator3D
-	  graphics boards.
+	  This is the frame buffer device driver for the Creator, Creator3D,
+	  and Elite3D graphics boards.
 
 config FB_TCX
 	bool "TCX (SS4/SS5 only) support"
-	depends on FB_SBUS && SPARC32
+	depends on FB_SBUS
 	help
 	  This is the frame buffer device driver for the TCX 24/8bit frame
 	  buffer.
 
-config FB_CGFOURTEEN
+config FB_CG14
 	bool "CGfourteen (SX) support"
-	depends on FB_SBUS && SPARC32
+	depends on FB_SBUS
 	help
 	  This is the frame buffer device driver for the CGfourteen frame
 	  buffer on Desktop SPARCsystems with the SX graphics option.
 
 config FB_P9100
 	bool "P9100 (Sparcbook 3 only) support"
-	depends on FB_SBUS && SPARC32
+	depends on FB_SBUS
 	help
 	  This is the frame buffer device driver for the P9100 card
 	  supported on Sparcbook 3 machines.
diff -urN linux-2.5.63-bk6/drivers/video/Makefile linux-2.5.63-bk7/drivers/video/Makefile
--- linux-2.5.63-bk6/drivers/video/Makefile	Mon Feb 24 11:05:08 2003
+++ linux-2.5.63-bk7/drivers/video/Makefile	Mon Mar 31 12:20:15 2003
@@ -48,14 +48,6 @@
 obj-$(CONFIG_FB_VIRGE)            += virgefb.o
 obj-$(CONFIG_FB_G364)             += g364fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_FM2)              += fm2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_CREATOR)          += creatorfb.o sbusfb.o
-obj-$(CONFIG_FB_CGSIX)            += cgsixfb.o sbusfb.o
-obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o sbusfb.o
-obj-$(CONFIG_FB_CGTHREE)          += cgthreefb.o sbusfb.o
-obj-$(CONFIG_FB_TCX)              += tcxfb.o sbusfb.o
-obj-$(CONFIG_FB_CGFOURTEEN)       += cgfourteenfb.o sbusfb.o
-obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
-obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
 obj-$(CONFIG_FB_STI)              += stifb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
@@ -78,6 +70,22 @@
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 
+# One by one these are being converted over to the new APIs
+#obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
+
+obj-$(CONFIG_FB_FFB)               += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
+obj-$(CONFIG_FB_CG6)               += cg6.o sbuslib.o cfbimgblt.o cfbcopyarea.o
+obj-$(CONFIG_FB_CG3)               += cg3.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+				      cfbfillrect.o
+obj-$(CONFIG_FB_BW2)               += bw2.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+				      cfbfillrect.o
+obj-$(CONFIG_FB_CG14)              += cg14.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+				      cfbfillrect.o
+obj-$(CONFIG_FB_P9100)             += p9100.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+				      cfbfillrect.o
+obj-$(CONFIG_FB_TCX)               += tcx.o sbuslib.o cfbimgblt.o cfbcopyarea.o \
+				      cfbfillrect.o
+
 # Files generated that shall be removed upon make clean
 clean-files := promcon_tbl.c
 
diff -urN linux-2.5.63-bk6/drivers/video/bw2.c linux-2.5.63-bk7/drivers/video/bw2.c
--- linux-2.5.63-bk6/drivers/video/bw2.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/bw2.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,448 @@
+/* bw2.c: BWTWO frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#ifdef CONFIG_SPARC32
+#include <asm/sun4paddr.h>
+#endif
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int bw2_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int bw2_set_par(struct fb_info *);
+static int bw2_blank(int, struct fb_info *);
+
+static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops bw2_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= bw2_check_var,
+	.fb_set_par		= bw2_set_par,
+	.fb_blank		= bw2_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= bw2_mmap,
+	.fb_cursor		= soft_cursor,
+};
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct bw2_regs {
+	struct bt_regs	cmap;
+	volatile u8	control;
+	volatile u8	status;
+	volatile u8	cursor_start;
+	volatile u8	cursor_end;
+	volatile u8	h_blank_start;
+	volatile u8	h_blank_end;
+	volatile u8	h_sync_start;
+	volatile u8	h_sync_end;
+	volatile u8	comp_sync_end;
+	volatile u8	v_blank_start_high;
+	volatile u8	v_blank_start_low;
+	volatile u8	v_blank_end;
+	volatile u8	v_sync_start;
+	volatile u8	v_sync_end;
+	volatile u8	xfer_holdoff_start;
+	volatile u8	xfer_holdoff_end;
+};
+
+/* Status Register Constants */
+#define BWTWO_SR_RES_MASK	0x70
+#define BWTWO_SR_1600_1280	0x50
+#define BWTWO_SR_1152_900_76_A	0x40
+#define BWTWO_SR_1152_900_76_B	0x60
+#define BWTWO_SR_ID_MASK	0x0f
+#define BWTWO_SR_ID_MONO	0x02
+#define BWTWO_SR_ID_MONO_ECL	0x03
+#define BWTWO_SR_ID_MSYNC	0x04
+#define BWTWO_SR_ID_NOCONN	0x0a
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS   0x80
+#define BWTWO_CTL_ENABLE_VIDEO  0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK     0x0C
+#define BWTWO_CTL_DIVISOR_MASK  0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT  0x80
+#define BWTWO_STAT_MSENSE_MASK  0x70
+#define BWTWO_STAT_ID_MASK      0x0f
+
+struct bw2_par {
+	spinlock_t		lock;
+	struct bw2_regs		*regs;
+
+	u32			flags;
+#define BW2_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      bw2_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int bw2_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      bw2_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+bw2_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      bw2_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+bw2_blank(int blank, struct fb_info *info)
+{
+	struct bw2_par *par = (struct bw2_par *) info->par;
+	struct bw2_regs *regs = par->regs;
+	unsigned long flags;
+	u8 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		val = sbus_readb(&regs->control);
+		val |= BWTWO_CTL_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags &= ~BW2_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+	case 2: /* VESA blank (vsync off) */
+	case 3: /* VESA blank (hsync off) */
+	case 4: /* Poweroff */
+		val = sbus_readb(&regs->control);
+		val &= ~BWTWO_CTL_ENABLE_VIDEO;
+		sbus_writeb(val, &regs->control);
+		par->flags |= BW2_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map bw2_mmap_map[] = {
+	{ 0,			0,			SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,			0		    }
+};
+
+static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct bw2_par *par = (struct bw2_par *)info->par;
+
+	return sbusfb_mmap_helper(bw2_mmap_map,
+				  par->physbase, par->fbsize,
+				  (par->sdev ?
+				   par->sdev->reg_addrs[0].which_io :
+				   0),
+				  vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+bw2_init_fix(struct fb_info *info, int linebytes)
+{
+	strncpy(info->fix.id, "bwtwo", sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_MONO01;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_BWTWO;
+}
+
+static u8 bw2regs_1600[] __initdata = {
+	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,
+	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x21,	0
+};
+
+static u8 bw2regs_ecl[] __initdata = {
+	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,
+	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,
+	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_analog[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,
+	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 bw2regs_76hz[] __initdata = {
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 bw2regs_66hz[] __initdata = {
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
+				int *linebytes)
+{
+	u8 status, mon;
+	u8 *p;
+
+	status = sbus_readb(&par->regs->status);
+	mon = status & BWTWO_SR_RES_MASK;
+	switch (status & BWTWO_SR_ID_MASK) {
+	case BWTWO_SR_ID_MONO_ECL:
+		if (mon == BWTWO_SR_1600_1280) {
+			p = bw2regs_1600;
+			info->var.xres = info->var.xres_virtual = 1600;
+			info->var.yres = info->var.yres_virtual = 1280;
+			*linebytes = 1600 / 8;
+		} else
+			p = bw2regs_ecl;
+		break;
+
+	case BWTWO_SR_ID_MONO:
+		p = bw2regs_analog;
+		break;
+
+	case BWTWO_SR_ID_MSYNC:
+		if (mon == BWTWO_SR_1152_900_76_A ||
+		    mon == BWTWO_SR_1152_900_76_B)
+			p = bw2regs_76hz;
+		else
+			p = bw2regs_66hz;
+		break;
+
+	case BWTWO_SR_ID_NOCONN:
+		return;
+
+	default:
+		prom_printf("bw2: can't handle SR %02x\n",
+			    status);
+		prom_halt();
+	}
+	for ( ; *p; p += 2) {
+		u8 *regp = &((u8 *)par->regs)[p[0]];
+		sbus_writeb(p[1], regp);
+	}
+}
+
+struct all_info {
+	struct fb_info info;
+	struct bw2_par par;
+	struct list_head list;
+};
+static LIST_HEAD(bw2_list);
+
+static void bw2_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	struct resource *resp;
+#ifdef CONFIG_SUN4
+	struct resource res;
+#endif
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "bw2: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+#ifdef CONFIG_SUN4
+	if (!sdev) {
+		all->par.physbase = sun4_bwtwo_physaddr;
+		res.start = sun4_bwtwo_physaddr;
+		res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1;
+		res.flags = IORESOURCE_IO;
+		resp = &res;
+		all->info.var.xres = all->info.var.xres_virtual = 1152;
+		all->info.var.yres = all->info.var.yres_virtual = 900;
+		all->info.bits_per_pixel = 1;
+		linebytes = 1152 / 8;
+	} else
+#else
+	{
+		if (!sdev)
+			BUG();
+		all->par.physbase = sdev->reg_addrs[0].phys_addr;
+		resp = &sdev->resource[0];
+		sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1);
+		linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+					       all->info.var.xres);
+	}
+#endif
+
+	all->par.regs = (struct bw2_regs *)
+		sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
+			     sizeof(struct bw2_regs), "bw2 regs");
+
+	if (sdev && !prom_getbool(sdev->prom_node, "width"))
+		bw2_do_default_mode(&all->par, &all->info, &linebytes);
+
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &bw2_ops;
+#if defined(CONFIG_SPARC32)
+	if (sdev)
+		all->info.screen_base = (char *)
+			prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = (char *)
+			sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram");
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	bw2_blank(0, &all->info);
+
+	bw2_set_par(&all->info);
+	bw2_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "bw2: Could not register framebuffer.\n");
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &bw2_list);
+
+	printk("bw2: bwtwo at %lx:%lx\n",
+	       (long) (sdev ? sdev->reg_addrs[0].which_io : 0),
+	       (long) all->par.physbase);
+}
+
+int __init bw2_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+#ifdef CONFIG_SUN4
+	bw2_init_one(NULL);
+#endif
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "bwtwo"))
+			bw2_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit bw2_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &bw2_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		kfree(all);
+	}
+}
+
+int __init
+bw2_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(bw2_init);
+module_exit(bw2_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/bwtwofb.c linux-2.5.63-bk7/drivers/video/bwtwofb.c
--- linux-2.5.63-bk6/drivers/video/bwtwofb.c	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/drivers/video/bwtwofb.c	Wed Dec 31 16:00:00 1969
@@ -1,269 +0,0 @@
-/* $Id: bwtwofb.c,v 1.15 2001/09/19 00:04:33 davem Exp $
- * bwtwofb.c: BWtwo frame buffer driver
- *
- * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1997 Eddie C. Dost   (ecd@skynet.be)
- * Copyright (C) 1998 Pavel Machek    (pavel@ucw.cz)
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-#if !defined(__sparc_v9__) && !defined(__mc68000__)
-#include <asm/sun4paddr.h>
-#endif
-
-#include <video/fbcon-mfb.h>
-
-/* OBio addresses for the bwtwo registers */
-#define BWTWO_REGISTER_OFFSET 0x400000
-
-struct bw2_regs {
-	struct bt_regs		bt;
-	volatile u8		control;
-	volatile u8		status;
-	volatile u8		cursor_start;
-	volatile u8		cursor_end;
-	volatile u8		h_blank_start;
-	volatile u8		h_blank_end;
-	volatile u8		h_sync_start;
-	volatile u8		h_sync_end;
-	volatile u8		comp_sync_end;
-	volatile u8		v_blank_start_high;
-	volatile u8		v_blank_start_low;
-	volatile u8		v_blank_end;
-	volatile u8		v_sync_start;
-	volatile u8		v_sync_end;
-	volatile u8		xfer_holdoff_start;
-	volatile u8		xfer_holdoff_end;
-};
-
-/* Status Register Constants */
-#define BWTWO_SR_RES_MASK	0x70
-#define BWTWO_SR_1600_1280	0x50
-#define BWTWO_SR_1152_900_76_A	0x40
-#define BWTWO_SR_1152_900_76_B	0x60
-#define BWTWO_SR_ID_MASK	0x0f
-#define BWTWO_SR_ID_MONO	0x02
-#define BWTWO_SR_ID_MONO_ECL	0x03
-#define BWTWO_SR_ID_MSYNC	0x04
-#define BWTWO_SR_ID_NOCONN	0x0a
-
-/* Control Register Constants */
-#define BWTWO_CTL_ENABLE_INTS   0x80
-#define BWTWO_CTL_ENABLE_VIDEO  0x40
-#define BWTWO_CTL_ENABLE_TIMING 0x20
-#define BWTWO_CTL_ENABLE_CURCMP 0x10
-#define BWTWO_CTL_XTAL_MASK     0x0C
-#define BWTWO_CTL_DIVISOR_MASK  0x03
-
-/* Status Register Constants */
-#define BWTWO_STAT_PENDING_INT  0x80
-#define BWTWO_STAT_MSENSE_MASK  0x70
-#define BWTWO_STAT_ID_MASK      0x0f
-
-static struct sbus_mmap_map bw2_mmap_map[] = {
-	{ 0,			0,			SBUS_MMAP_FBSIZE(1) },
-	{ 0,			0,			0		    }
-};
-
-static int bw2_blank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u8 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readb(&fb->s.bw2.regs->control);
-	tmp &= ~BWTWO_CTL_ENABLE_VIDEO;
-	sbus_writeb(tmp, &fb->s.bw2.regs->control);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static int bw2_unblank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u8 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readb(&fb->s.bw2.regs->control);
-	tmp |= BWTWO_CTL_ENABLE_VIDEO;
-	sbus_writeb(tmp, &fb->s.bw2.regs->control);
-	spin_unlock_irqrestore(&fb->lock, flags);
- 	return 0;
-}
-
-static void bw2_margins (struct fb_info_sbusfb *fb, struct display *p,
-			 int x_margin, int y_margin)
-{
-	fb->info.screen_base += (y_margin - fb->y_margin) *
-		p->fb_info->fix.line_length + ((x_margin - fb->x_margin) >> 3);
-}
-
-static u8 bw2regs_1600[] __initdata = {
-	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,
-	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,
-	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x21,	0
-};
-
-static u8 bw2regs_ecl[] __initdata = {
-	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,
-	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,
-	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x20,	0
-};
-
-static u8 bw2regs_analog[] __initdata = {
-	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,
-	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,
-	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x20,	0
-};
-
-static u8 bw2regs_76hz[] __initdata = {
-	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
-	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
-	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x24,	0
-};
-
-static u8 bw2regs_66hz[] __initdata = {
-	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
-	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
-	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x20,	0
-};
-
-static char idstring[60] __initdata = { 0 };
-
-char __init *bwtwofb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-#ifdef CONFIG_SUN4
-	unsigned long phys = sun4_bwtwo_physaddr;
-	struct resource res;
-#else
-	unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr;
-#endif
-	struct resource *resp;
-	unsigned int vaddr;
-
-#ifndef FBCON_HAS_MFB
-	return NULL;
-#endif
-
-#ifdef CONFIG_SUN4
-	res.start = phys;
-	res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1;
-	res.flags = IORESOURCE_IO | (fb->iospace & 0xff);
-	resp = &res;
-#else
-	resp = &fb->sbdp->resource[0];
-#endif
-	if (!fb->s.bw2.regs) {
-		fb->s.bw2.regs = (struct bw2_regs *)
-			sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
-				     sizeof(struct bw2_regs), "bw2 regs");
-		if ((!ARCH_SUN4) && (!prom_getbool(fb->prom_node, "width"))) {
-			/* Ugh, broken PROM didn't initialize us.
-			 * Let's deal with this ourselves.
-			 */
-			u8 status, mon;
-			u8 *p;
-			int sizechange = 0;
-
-			status = sbus_readb(&fb->s.bw2.regs->status);
-			mon = status & BWTWO_SR_RES_MASK;
-			switch (status & BWTWO_SR_ID_MASK) {
-				case BWTWO_SR_ID_MONO_ECL:
-					if (mon == BWTWO_SR_1600_1280) {
-						p = bw2regs_1600;
-						fb->type.fb_width = 1600;
-						fb->type.fb_height = 1280;
-						sizechange = 1;
-					} else
-						p = bw2regs_ecl;
-					break;
-				case BWTWO_SR_ID_MONO:
-					p = bw2regs_analog;
-					break;
-				case BWTWO_SR_ID_MSYNC:
-					if (mon == BWTWO_SR_1152_900_76_A ||
-					    mon == BWTWO_SR_1152_900_76_B)
-						p = bw2regs_76hz;
-					else
-						p = bw2regs_66hz;
-					break;
-				case BWTWO_SR_ID_NOCONN:
-					return NULL;
-				default:
-#ifndef CONFIG_FB_SUN3
-					prom_printf("bw2: can't handle SR %02x\n",
-						    status);
-					prom_halt();
-#endif					
-					return NULL; /* fool gcc. */
-			}
-			for ( ; *p; p += 2) {
-				u8 *regp = &((u8 *)fb->s.bw2.regs)[p[0]];
-				sbus_writeb(p[1], regp);
-			}
-		}
-	}
-
-	strcpy(fb->info.modename, "BWtwo");
-	strcpy(fix->id, "BWtwo");
-	fix->line_length = fb->info.var.xres_virtual >> 3;
-	fix->accel = FB_ACCEL_SUN_BWTWO;
-	
-	disp->scrollmode = SCROLL_YREDRAW;
-	disp->inverse = 1;
-	if (!fb->info.screen_base) {
-		fb->info.screen_base = (char *)
-			sbus_ioremap(resp, 0, type->fb_size, "bw2 ram");
-	}
-	fb->info.screen_base += fix->line_length * fb->y_margin + (fb->x_margin >> 3);
-	fb->dispsw = fbcon_mfb;
-	fix->visual = FB_VISUAL_MONO01;
-
-#ifndef CONFIG_SUN4
-	fb->blank = bw2_blank;
-	fb->unblank = bw2_unblank;
-
-	prom_getproperty(fb->sbdp->prom_node, "address",
-			 (char *)&vaddr, sizeof(vaddr));
-	fb->physbase = __get_phys((unsigned long)vaddr);
-
-#endif
-	fb->margins = bw2_margins;
-	fb->mmap_map = bw2_mmap_map;
-
-#ifdef __sparc_v9__
-	sprintf(idstring, "bwtwo at %016lx", phys);
-#else	
-	sprintf(idstring, "bwtwo at %x.%08lx", fb->iospace, phys);
-#endif
-	
-	return idstring;
-}
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/cfbcopyarea.c linux-2.5.63-bk7/drivers/video/cfbcopyarea.c
--- linux-2.5.63-bk6/drivers/video/cfbcopyarea.c	Mon Feb 24 11:05:43 2003
+++ linux-2.5.63-bk7/drivers/video/cfbcopyarea.c	Mon Mar 31 12:20:15 2003
@@ -65,14 +65,14 @@
 			// Single word
 			if (last)
 				first &= last;
-			FB_WRITEL((*src & first) | (FB_READL(dst) & ~first),
+			FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first),
 				  dst);
 		} else {
 			// Multiple destination words
 			// Leading bits
 			if (first) {
 				
-				FB_WRITEL((*src & first) | (FB_READL(dst) & 
+				FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & 
 							    ~first), dst);
 				dst++;
 				src++;
@@ -82,21 +82,21 @@
 			// Main chunk
 			n /= BITS_PER_LONG;
 			while (n >= 8) {
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
-				FB_WRITEL(*src++, dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
 				n -= 8;
 			}
 			while (n--)
-				FB_WRITEL(*src++, dst++);
+				FB_WRITEL(FB_READL(src++), dst++);
 			// Trailing bits
 			if (last)
-				FB_WRITEL((*src & last) | (FB_READL(dst) & 
+				FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & 
 							   ~last), dst);
 		}
 	} else {
@@ -111,22 +111,22 @@
 				first &= last;
 			if (shift > 0) {
 				// Single source word
-				FB_WRITEL(((*src >> right) & first) | 
+				FB_WRITEL(((FB_READL(src) >> right) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			} else if (src_idx+n <= BITS_PER_LONG) {
 				// Single source word
-				FB_WRITEL(((*src << left) & first) | 
+				FB_WRITEL(((FB_READL(src) << left) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			} else {
 				// 2 source words
-				d0 = *src++;
-				d1 = *src;
+				d0 = FB_READL(src++);
+				d1 = FB_READL(src);
 				FB_WRITEL(((d0<<left | d1>>right) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			}
 		} else {
 			// Multiple destination words
-			d0 = *src++;
+			d0 = FB_READL(src++);
 			// Leading bits
 			if (shift > 0) {
 				// Single source word
@@ -136,7 +136,7 @@
 				n -= BITS_PER_LONG-dst_idx;
 			} else {
 				// 2 source words
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(((d0<<left | d1>>right) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 				d0 = d1;
@@ -148,22 +148,22 @@
 			m = n % BITS_PER_LONG;
 			n /= BITS_PER_LONG;
 			while (n >= 4) {
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
 				n -= 4;
 			}
 			while (n--) {
-				d1 = *src++;
+				d1 = FB_READL(src++);
 				FB_WRITEL(d0 << left | d1 >> right, dst++);
 				d0 = d1;
 			}
@@ -177,7 +177,7 @@
 						  dst);
 				} else {
 					// 2 source words
-					d1 = *src;
+					d1 = FB_READL(src);
 					FB_WRITEL(((d0<<left | d1>>right) & 
 						   last) | (FB_READL(dst) & 
 							    ~last), dst);
@@ -220,13 +220,13 @@
 			// Single word
 			if (last)
 				first &= last;
-			FB_WRITEL((*src & first) | (FB_READL(dst) & ~first), 
+			FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & ~first), 
 				  dst);
 		} else {
 			// Multiple destination words
 			// Leading bits
 			if (first) {
-				FB_WRITEL((*src & first) | (FB_READL(dst) & 
+				FB_WRITEL((FB_READL(src) & first) | (FB_READL(dst) & 
 							    ~first), dst);
 				dst--;
 				src--;
@@ -236,22 +236,22 @@
 			// Main chunk
 			n /= BITS_PER_LONG;
 			while (n >= 8) {
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
-				FB_WRITEL(*src--, dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
 				n -= 8;
 			}
 			while (n--)
-				FB_WRITEL(*src--, dst--);
+				FB_WRITEL(FB_READL(src--), dst--);
 			
 			// Trailing bits
 			if (last)
-				FB_WRITEL((*src & last) | (FB_READL(dst) & 
+				FB_WRITEL((FB_READL(src) & last) | (FB_READL(dst) & 
 							   ~last), dst);
 		}
 	} else {
@@ -266,22 +266,22 @@
 				first &= last;
 			if (shift < 0) {
 				// Single source word
-				FB_WRITEL((*src << left & first) | 
+				FB_WRITEL((FB_READL(src) << left & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			} else if (1+(unsigned long)src_idx >= n) {
 				// Single source word
-				FB_WRITEL(((*src >> right) & first) | 
+				FB_WRITEL(((FB_READL(src) >> right) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			} else {
 				// 2 source words
-				d0 = *src--;
-				d1 = *src;
+				d0 = FB_READL(src--);
+				d1 = FB_READL(src);
 				FB_WRITEL(((d0>>right | d1<<left) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 			}
 		} else {
 			// Multiple destination words
-			d0 = *src--;
+			d0 = FB_READL(src--);
 			// Leading bits
 			if (shift < 0) {
 				// Single source word
@@ -291,7 +291,7 @@
 				n -= dst_idx+1;
 			} else {
 				// 2 source words
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(((d0>>right | d1<<left) & first) | 
 					  (FB_READL(dst) & ~first), dst);
 				d0 = d1;
@@ -303,22 +303,22 @@
 			m = n % BITS_PER_LONG;
 			n /= BITS_PER_LONG;
 			while (n >= 4) {
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
 				n -= 4;
 			}
 			while (n--) {
-				d1 = *src--;
+				d1 = FB_READL(src--);
 				FB_WRITEL(d0 >> right | d1 << left, dst--);
 				d0 = d1;
 			}
@@ -332,7 +332,7 @@
 						  dst);
 				} else {
 					// 2 source words
-					d1 = *src;
+					d1 = FB_READL(src);
 					FB_WRITEL(((d0>>right | d1<<left) & 
 						   last) | (FB_READL(dst) & 
 							    ~last), dst);
@@ -410,8 +410,8 @@
 			dst_idx &= (BYTES_PER_LONG-1);
 			src += src_idx >> SHIFT_PER_LONG;
 			src_idx &= (BYTES_PER_LONG-1);
-			bitcpy_rev((unsigned long*)dst, dst_idx, 
-				   (unsigned long *)src, src_idx, 
+			bitcpy_rev(dst, dst_idx,
+				   src, src_idx, 
 				   area->width*p->var.bits_per_pixel);
 		}	
 	} else {
@@ -420,8 +420,8 @@
 			dst_idx &= (BYTES_PER_LONG-1);
 			src += src_idx >> SHIFT_PER_LONG;
 			src_idx &= (BYTES_PER_LONG-1);
-			bitcpy((unsigned long*)dst, dst_idx, 
-			       (unsigned long *)src, src_idx, 
+			bitcpy(dst, dst_idx, 
+			       src, src_idx, 
 			       area->width*p->var.bits_per_pixel);
 			dst_idx += next_line*8;
 			src_idx += next_line*8;
diff -urN linux-2.5.63-bk6/drivers/video/cfbimgblt.c linux-2.5.63-bk7/drivers/video/cfbimgblt.c
--- linux-2.5.63-bk6/drivers/video/cfbimgblt.c	Mon Feb 24 11:05:33 2003
+++ linux-2.5.63-bk7/drivers/video/cfbimgblt.c	Mon Mar 31 12:20:15 2003
@@ -73,16 +73,11 @@
 	0x00000000, 0xffffffff
 };
 
-#if BITS_PER_LONG == 32
 #define FB_WRITEL fb_writel
 #define FB_READL  fb_readl
-#else
-#define FB_WRITEL fb_writeq
-#define FB_READL  fb_readq
-#endif 
 
 #if defined (__BIG_ENDIAN)
-#define LEFT_POS(bpp)          (BITS_PER_LONG - bpp)
+#define LEFT_POS(bpp)          (32 - bpp)
 #define NEXT_POS(pos, bpp)     ((pos) -= (bpp))
 #define SHIFT_HIGH(val, bits)  ((val) >> (bits))
 #define SHIFT_LOW(val, bits)   ((val) << (bits))
@@ -94,26 +89,25 @@
 #endif
 
 static inline void color_imageblit(struct fb_image *image, struct fb_info *p, 
-				   u8 *dst1, unsigned long start_index,
-				   unsigned long pitch_index)
+				   u8 *dst1, u32 start_index,
+				   u32 pitch_index)
 {
 	/* Draw the penguin */
-	unsigned long *dst, *dst2, color = 0, val, shift;
+	u32 *dst, *dst2, color = 0, val, shift;
 	int i, n, bpp = p->var.bits_per_pixel;
-	unsigned long null_bits = BITS_PER_LONG - bpp;
+	u32 null_bits = 32 - bpp;
 	u32 *palette = (u32 *) p->pseudo_palette;
 	u8 *src = image->data;
 
-	dst2 = (unsigned long *) dst1;
+	dst2 = (u32 *) dst1;
 	for (i = image->height; i--; ) {
 		n = image->width;
-		dst = (unsigned long *) dst1;
+		dst = (u32 *) dst1;
 		shift = 0;
 		val = 0;
 		
 		if (start_index) {
-			unsigned long start_mask = ~(SHIFT_HIGH(~0UL,
-								start_index));
+			u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
 			val = FB_READL(dst) & start_mask;
 			shift = start_index;
 		}
@@ -129,14 +123,14 @@
 				FB_WRITEL(val, dst++);
 	
 				val = (shift == null_bits) ? 0 : 
-					SHIFT_LOW(color,BITS_PER_LONG - shift);
+					SHIFT_LOW(color, 32 - shift);
 			}
 			shift += bpp;
-			shift &= (BITS_PER_LONG - 1);
+			shift &= (32 - 1);
 			src++;
 		}
 		if (shift) {
-			unsigned long  end_mask = SHIFT_HIGH(~0UL, shift);
+			u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
 
 			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
 		}
@@ -144,40 +138,39 @@
 		if (pitch_index) {
 			dst2 += p->fix.line_length;
 			dst1 = (char *) dst2;
-			(unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+			(unsigned long) dst1 &= ~(sizeof(u32) - 1);
 
 			start_index += pitch_index;
-			start_index &= BITS_PER_LONG - 1;
+			start_index &= 32 - 1;
 		}
 	}
 }
 
 static inline void slow_imageblit(struct fb_image *image, struct fb_info *p, 
-				  u8 *dst1, unsigned long fgcolor,
-				  unsigned long bgcolor, 
-				  unsigned long start_index,
-				  unsigned long pitch_index)
+				  u8 *dst1, u32 fgcolor,
+				  u32 bgcolor, 
+				  u32 start_index,
+				  u32 pitch_index)
 {
-	unsigned long shift, color = 0, bpp = p->var.bits_per_pixel;
-	unsigned long *dst, *dst2, val, pitch = p->fix.line_length;
-	unsigned long null_bits = BITS_PER_LONG - bpp;
-	unsigned long spitch = (image->width+7)/8;
+	u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+	u32 *dst, *dst2, val, pitch = p->fix.line_length;
+	u32 null_bits = 32 - bpp;
+	u32 spitch = (image->width+7)/8;
 	u8 *src = image->data, *s;
-	unsigned long i, j, l;
+	u32 i, j, l;
 	
-	dst2 = (unsigned long *) dst1;
+	dst2 = (u32 *) dst1;
 
 	for (i = image->height; i--; ) {
 		shift = val = 0;
 		l = 8;
 		j = image->width;
-		dst = (unsigned long *) dst1;
+		dst = (u32 *) dst1;
 		s = src;
 
 		/* write leading bits */
 		if (start_index) {
-			unsigned long start_mask = ~(SHIFT_HIGH(~0UL,
-								start_index));
+			u32 start_mask = ~(SHIFT_HIGH(~(u32)0, start_index));
 			val = FB_READL(dst) & start_mask;
 			shift = start_index;
 		}
@@ -192,16 +185,16 @@
 			if (shift >= null_bits) {
 				FB_WRITEL(val, dst++);
 				val = (shift == null_bits) ? 0 :
-					 SHIFT_LOW(color,BITS_PER_LONG - shift);
+					 SHIFT_LOW(color,32 - shift);
 			}
 			shift += bpp;
-			shift &= (BITS_PER_LONG - 1);
+			shift &= (32 - 1);
 			if (!l) { l = 8; s++; };
 		}
 
 		/* write trailing bits */
  		if (shift) {
-			unsigned long end_mask = SHIFT_HIGH(~0UL, shift);
+			u32 end_mask = SHIFT_HIGH(~(u32)0, shift);
 
 			FB_WRITEL((FB_READL(dst) & end_mask) | val, dst);
 		}
@@ -211,10 +204,10 @@
 		if (pitch_index) {
 			dst2 += pitch;
 			dst1 = (char *) dst2;
-			(unsigned long) dst1 &= ~(sizeof(unsigned long) - 1);
+			(unsigned long) dst1 &= ~(sizeof(u32) - 1);
 
 			start_index += pitch_index;
-			start_index &= BITS_PER_LONG - 1;
+			start_index &= 32 - 1;
 		}
 		
 	}
@@ -229,14 +222,14 @@
  *           beginning and end of a scanline is dword aligned
  */
 static inline void fast_imageblit(struct fb_image *image, struct fb_info *p, 
-				  u8 *dst1, unsigned long fgcolor, 
-				  unsigned long bgcolor) 
+				  u8 *dst1, u32 fgcolor, 
+				  u32 bgcolor) 
 {
-	unsigned long fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
-	unsigned long ppw = BITS_PER_LONG/bpp, spitch = (image->width + 7)/8;
-	unsigned long bit_mask, end_mask, eorx, shift;
+	u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+	u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+	u32 bit_mask, end_mask, eorx, shift;
 	char *s = image->data, *src;
-	unsigned long *dst;
+	u32 *dst;
 	u32 *tab = NULL;
 	int i, j, k;
 		
@@ -264,7 +257,7 @@
 	k = image->width/ppw;
 
 	for (i = image->height; i--; ) {
-		dst = (unsigned long *) dst1, shift = 8; src = s;
+		dst = (u32 *) dst1, shift = 8; src = s;
 		
 		for (j = k; j--; ) {
 			shift -= ppw;
@@ -279,8 +272,8 @@
 	
 void cfb_imageblit(struct fb_info *p, struct fb_image *image)
 {
-	unsigned long fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
-	unsigned long bpl = sizeof(unsigned long), bpp = p->var.bits_per_pixel;
+	u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+	u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
 	int x2, y2, vxres, vyres;
 	u8 *dst1;
 
@@ -304,7 +297,7 @@
 	image->height = y2 - image->dy;
 
 	bitstart = (image->dy * p->fix.line_length * 8) + (image->dx * bpp);
-	start_index = bitstart & (BITS_PER_LONG - 1);
+	start_index = bitstart & (32 - 1);
 	pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
 
 	bitstart /= 8;
@@ -324,8 +317,8 @@
 			bgcolor = image->bg_color;
 		}	
 		
-		if (BITS_PER_LONG % bpp == 0 && !start_index && !pitch_index && 
-		    ((image->width & (BITS_PER_LONG/bpp-1)) == 0) &&
+		if (32 % bpp == 0 && !start_index && !pitch_index && 
+		    ((image->width & (32/bpp-1)) == 0) &&
 		    bpp >= 8 && bpp <= 32) 			
 			fast_imageblit(image, p, dst1, fgcolor, bgcolor);
 		else 
diff -urN linux-2.5.63-bk6/drivers/video/cg14.c linux-2.5.63-bk7/drivers/video/cg14.c
--- linux-2.5.63-bk6/drivers/video/cg14.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/cg14.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,597 @@
+/* cg14.c: CGFOURTEEN frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg14_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int cg14_set_par(struct fb_info *);
+static int cg14_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+
+static int cg14_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+static int cg14_ioctl(struct inode *, struct file *, unsigned int,
+		      unsigned long, struct fb_info *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg14_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= cg14_check_var,
+	.fb_set_par		= cg14_set_par,
+	.fb_setcolreg		= cg14_setcolreg,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= cg14_mmap,
+	.fb_ioctl		= cg14_ioctl,
+	.fb_cursor		= soft_cursor,
+};
+
+#define CG14_MCR_INTENABLE_SHIFT	7
+#define CG14_MCR_INTENABLE_MASK		0x80
+#define CG14_MCR_VIDENABLE_SHIFT	6
+#define CG14_MCR_VIDENABLE_MASK		0x40
+#define CG14_MCR_PIXMODE_SHIFT		4
+#define CG14_MCR_PIXMODE_MASK		0x30
+#define CG14_MCR_TMR_SHIFT		2
+#define CG14_MCR_TMR_MASK		0x0c
+#define CG14_MCR_TMENABLE_SHIFT		1
+#define CG14_MCR_TMENABLE_MASK		0x02
+#define CG14_MCR_RESET_SHIFT		0
+#define CG14_MCR_RESET_MASK		0x01
+#define CG14_REV_REVISION_SHIFT		4
+#define CG14_REV_REVISION_MASK		0xf0
+#define CG14_REV_IMPL_SHIFT		0
+#define CG14_REV_IMPL_MASK		0x0f
+#define CG14_VBR_FRAMEBASE_SHIFT	12
+#define CG14_VBR_FRAMEBASE_MASK		0x00fff000
+#define CG14_VMCR1_SETUP_SHIFT		0
+#define CG14_VMCR1_SETUP_MASK		0x000001ff
+#define CG14_VMCR1_VCONFIG_SHIFT	9
+#define CG14_VMCR1_VCONFIG_MASK		0x00000e00
+#define CG14_VMCR2_REFRESH_SHIFT	0
+#define CG14_VMCR2_REFRESH_MASK		0x00000001
+#define CG14_VMCR2_TESTROWCNT_SHIFT	1
+#define CG14_VMCR2_TESTROWCNT_MASK	0x00000002
+#define CG14_VMCR2_FBCONFIG_SHIFT	2
+#define CG14_VMCR2_FBCONFIG_MASK	0x0000000c
+#define CG14_VCR_REFRESHREQ_SHIFT	0
+#define CG14_VCR_REFRESHREQ_MASK	0x000003ff
+#define CG14_VCR1_REFRESHENA_SHIFT	10
+#define CG14_VCR1_REFRESHENA_MASK	0x00000400
+#define CG14_VCA_CAD_SHIFT		0
+#define CG14_VCA_CAD_MASK		0x000003ff
+#define CG14_VCA_VERS_SHIFT		10
+#define CG14_VCA_VERS_MASK		0x00000c00
+#define CG14_VCA_RAMSPEED_SHIFT		12
+#define CG14_VCA_RAMSPEED_MASK		0x00001000
+#define CG14_VCA_8MB_SHIFT		13
+#define CG14_VCA_8MB_MASK		0x00002000
+
+#define CG14_MCR_PIXMODE_8		0
+#define CG14_MCR_PIXMODE_16		2
+#define CG14_MCR_PIXMODE_32		3
+
+struct cg14_regs{
+	volatile u8 mcr;	/* Master Control Reg */
+	volatile u8 ppr;	/* Packed Pixel Reg */
+	volatile u8 tms[2];	/* Test Mode Status Regs */
+	volatile u8 msr;	/* Master Status Reg */
+	volatile u8 fsr;	/* Fault Status Reg */
+	volatile u8 rev;	/* Revision & Impl */
+	volatile u8 ccr;	/* Clock Control Reg */
+	volatile u32 tmr;	/* Test Mode Read Back */
+	volatile u8 mod;	/* Monitor Operation Data Reg */
+	volatile u8 acr;	/* Aux Control */
+	u8 xxx0[6];
+	volatile u16 hct;	/* Hor Counter */
+	volatile u16 vct;	/* Vert Counter */
+	volatile u16 hbs;	/* Hor Blank Start */
+	volatile u16 hbc;	/* Hor Blank Clear */
+	volatile u16 hss;	/* Hor Sync Start */
+	volatile u16 hsc;	/* Hor Sync Clear */
+	volatile u16 csc;	/* Composite Sync Clear */
+	volatile u16 vbs;	/* Vert Blank Start */
+	volatile u16 vbc;	/* Vert Blank Clear */
+	volatile u16 vss;	/* Vert Sync Start */
+	volatile u16 vsc;	/* Vert Sync Clear */
+	volatile u16 xcs;
+	volatile u16 xcc;
+	volatile u16 fsa;	/* Fault Status Address */
+	volatile u16 adr;	/* Address Registers */
+	u8 xxx1[0xce];
+	volatile u8 pcg[0x100]; /* Pixel Clock Generator */
+	volatile u32 vbr;	/* Frame Base Row */
+	volatile u32 vmcr;	/* VBC Master Control */
+	volatile u32 vcr;	/* VBC refresh */
+	volatile u32 vca;	/* VBC Config */
+};
+
+#define CG14_CCR_ENABLE	0x04
+#define CG14_CCR_SELECT 0x02	/* HW/Full screen */
+
+struct cg14_cursor {
+	volatile u32 cpl0[32];	/* Enable plane 0 */
+	volatile u32 cpl1[32];  /* Color selection plane */
+	volatile u8 ccr;	/* Cursor Control Reg */
+	u8 xxx0[3];
+	volatile u16 cursx;	/* Cursor x,y position */
+	volatile u16 cursy;	/* Cursor x,y position */
+	volatile u32 color0;
+	volatile u32 color1;
+	u32 xxx1[0x1bc];
+	volatile u32 cpl0i[32];	/* Enable plane 0 autoinc */
+	volatile u32 cpl1i[32]; /* Color selection autoinc */
+};
+
+struct cg14_dac {
+	volatile u8 addr;	/* Address Register */
+	u8 xxx0[255];
+	volatile u8 glut;	/* Gamma table */
+	u8 xxx1[255];
+	volatile u8 select;	/* Register Select */
+	u8 xxx2[255];
+	volatile u8 mode;	/* Mode Register */
+};
+
+struct cg14_xlut{
+	volatile u8 x_xlut [256];
+	volatile u8 x_xlutd [256];
+	u8 xxx0[0x600];
+	volatile u8 x_xlut_inc [256];
+	volatile u8 x_xlutd_inc [256];
+};
+
+/* Color look up table (clut) */
+/* Each one of these arrays hold the color lookup table (for 256
+ * colors) for each MDI page (I assume then there should be 4 MDI
+ * pages, I still wonder what they are.  I have seen NeXTStep split
+ * the screen in four parts, while operating in 24 bits mode.  Each
+ * integer holds 4 values: alpha value (transparency channel, thanks
+ * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
+ *
+ * I currently use the clut instead of the Xlut
+ */
+struct cg14_clut {
+	u32 c_clut [256];
+	u32 c_clutd [256];    /* i wonder what the 'd' is for */
+	u32 c_clut_inc [256];
+	u32 c_clutd_inc [256];
+};
+
+#define CG14_MMAP_ENTRIES	16
+
+struct cg14_par {
+	spinlock_t		lock;
+	struct cg14_regs	*regs;
+	struct cg14_clut	*clut;
+	struct cg14_cursor	*cursor;
+
+	u32			flags;
+#define CG14_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		iospace;
+	unsigned long		fbsize;
+
+	struct sbus_mmap_map	mmap_map[CG14_MMAP_ENTRIES];
+
+	int			mode;
+	int			ramsize;
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+static void __cg14_reset(struct cg14_par *par)
+{
+	struct cg14_regs *regs = par->regs;
+	u8 val;
+
+	val = sbus_readb(&regs->mcr);
+	val &= ~(CG14_MCR_PIXMODE_MASK);
+	sbus_writeb(val, &regs->mcr);
+}
+
+/**
+ *      cg14_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int cg14_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      cg14_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg14_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      cg14_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int cg14_setcolreg(unsigned regno,
+			  unsigned red, unsigned green, unsigned blue,
+			  unsigned transp, struct fb_info *info)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+	struct cg14_clut *clut = par->clut;
+	unsigned long flags;
+	u32 val;
+
+	if (regno >= 256)
+		return 1;
+
+	val = (red | (green << 8) | (blue << 16));
+
+	spin_lock_irqsave(&par->lock, flags);
+	sbus_writel(val, &clut->c_clut[regno]);
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static int cg14_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+
+	return sbusfb_mmap_helper(par->mmap_map,
+				  par->physbase, par->fbsize,
+				  par->iospace, vma);
+}
+
+static int cg14_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		      unsigned long arg, struct fb_info *info)
+{
+	struct cg14_par *par = (struct cg14_par *) info->par;
+	struct cg14_regs *regs = par->regs;
+	struct mdi_cfginfo kmdi, *mdii;
+	unsigned long flags;
+	int cur_mode, mode, ret = 0;
+
+	switch (cmd) {
+	case MDI_RESET:
+		spin_lock_irqsave(&par->lock, flags);
+		__cg14_reset(par);
+		spin_unlock_irqrestore(&par->lock, flags);
+		break;
+
+	case MDI_GET_CFGINFO:
+		memset(&kmdi, 0, sizeof(kmdi));
+
+		spin_lock_irqsave(&par->lock, flags);
+		kmdi.mdi_type = FBTYPE_MDICOLOR;
+		kmdi.mdi_height = info->var.yres;
+		kmdi.mdi_width = info->var.xres;
+		kmdi.mdi_mode = par->mode;
+		kmdi.mdi_pixfreq = 72; /* FIXME */
+		kmdi.mdi_size = par->ramsize;
+		spin_unlock_irqrestore(&par->lock, flags);
+
+		mdii = (struct mdi_cfginfo *) arg;
+		if (copy_to_user(mdii, &kmdi, sizeof(kmdi)))
+			ret = -EFAULT;
+		break;
+
+	case MDI_SET_PIXELMODE:
+		if (get_user(mode, (int *) arg)) {
+			ret = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&par->lock, flags);
+		cur_mode = sbus_readb(&regs->mcr);
+		cur_mode &= ~CG14_MCR_PIXMODE_MASK;
+		switch(mode) {
+		case MDI_32_PIX:
+			cur_mode |= (CG14_MCR_PIXMODE_32 <<
+				     CG14_MCR_PIXMODE_SHIFT);
+			break;
+
+		case MDI_16_PIX:
+			cur_mode |= 0x20;
+			break;
+
+		case MDI_8_PIX:
+			break;
+
+		default:
+			ret = -ENOSYS;
+			break;
+		};
+		if (!ret) {
+			sbus_writeb(cur_mode, &regs->mcr);
+			par->mode = mode;
+		}
+		spin_unlock_irqrestore(&par->lock, flags);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	};
+
+	return ret;
+}
+
+/*
+ *  Initialisation
+ */
+
+static void cg14_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg14_par *par = (struct cg14_par *)info->par;
+
+	strncpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CG14;
+}
+
+static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = {
+	{ CG14_REGS,		0x80000000,		0x1000		    },
+	{ CG14_XLUT,		0x80003000,		0x1000		    },
+	{ CG14_CLUT1,		0x80004000,		0x1000		    },
+	{ CG14_CLUT2,		0x80005000,		0x1000		    },
+	{ CG14_CLUT3,		0x80006000,		0x1000		    },
+	{ CG3_MMAP_OFFSET - 
+	  0x7000,		0x80000000,		0x7000		    },
+	{ CG3_MMAP_OFFSET,	0x00000000,		SBUS_MMAP_FBSIZE(1) },
+	{ MDI_CURSOR_MAP,	0x80001000,		0x1000		    },
+	{ MDI_CHUNKY_BGR_MAP,	0x01000000,		0x400000	    },
+	{ MDI_PLANAR_X16_MAP,	0x02000000,		0x200000	    },
+	{ MDI_PLANAR_C16_MAP,	0x02800000,		0x200000	    },
+	{ MDI_PLANAR_X32_MAP,	0x03000000,		0x100000	    },
+	{ MDI_PLANAR_B32_MAP,	0x03400000,		0x100000	    },
+	{ MDI_PLANAR_G32_MAP,	0x03800000,		0x100000	    },
+	{ MDI_PLANAR_R32_MAP,	0x03c00000,		0x100000	    },
+	{ 0,			0,			0		    }
+};
+
+struct all_info {
+	struct fb_info info;
+	struct cg14_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg14_list);
+
+static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
+{
+	struct all_info *all;
+	unsigned long phys, rphys;
+	u32 bases[6];
+	int is_8mb, linebytes, i;
+
+	if (!sdev) {
+		prom_getproperty(node, "address",
+				 (char *) &bases[0], sizeof(bases));
+		if (!bases[0]) {
+			printk(KERN_ERR "cg14: Device is not mapped.\n");
+			return;
+		}
+		if (__get_iospace(bases[0]) != __get_iospace(bases[1])) {
+			printk(KERN_ERR "cg14: I/O spaces don't match.\n");
+			return;
+		}
+	}
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg14: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+
+	sbusfb_fill_var(&all->info.var, node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.sdev = sdev;
+	if (sdev) {
+		rphys = sdev->reg_addrs[0].phys_addr;
+		all->par.physbase = phys = sdev->reg_addrs[1].phys_addr;
+		all->par.iospace = sdev->reg_addrs[0].which_io;
+
+		all->par.regs = (struct cg14_regs *)
+			sbus_ioremap(&sdev->resource[0], 0,
+				     sizeof(struct cg14_regs),
+				     "cg14 regs");
+		all->par.clut = (struct cg14_clut *)
+			sbus_ioremap(&sdev->resource[0], CG14_CLUT1,
+				     sizeof(struct cg14_clut),
+				     "cg14 clut");
+		all->par.cursor = (struct cg14_cursor *)
+			sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS,
+				     sizeof(struct cg14_cursor),
+				     "cg14 cursor");
+		all->info.screen_base = (char *)
+			sbus_ioremap(&sdev->resource[1], 0,
+				     all->par.fbsize, "cg14 ram");
+	} else {
+		rphys = __get_phys(bases[0]);
+		all->par.physbase = phys = __get_phys(bases[1]);
+		all->par.iospace = __get_iospace(bases[0]);
+		all->par.regs = (struct cg14_regs *)(unsigned long)bases[0];
+		all->par.clut = (struct cg14_clut *)((unsigned long)bases[0] +
+						     CG14_CLUT1);
+		all->par.cursor =
+			(struct cg14_cursor *)((unsigned long)bases[0] +
+					       CG14_CURSORREGS);
+
+		all->info.screen_base = (char *)(unsigned long)bases[1];
+	}
+
+	prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases));
+	is_8mb = (bases[5] == 0x800000);
+
+	if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) {
+		extern void __cg14_mmap_sized_wrongly(void);
+
+		__cg14_mmap_sized_wrongly();
+	}
+		
+	memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map));
+	for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
+		struct sbus_mmap_map *map = &all->par.mmap_map[i];
+
+		if (!map->size)
+			break;
+		if (map->poff & 0x80000000)
+			map->poff = (map->poff & 0x7fffffff) + rphys - phys;
+		if (is_8mb &&
+		    map->size >= 0x100000 &&
+		    map->size <= 0x400000)
+			map->size *= 2;
+	}
+
+	all->par.mode = MDI_8_PIX;
+	all->par.ramsize = (is_8mb ? 0x800000 : 0x400000);
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &cg14_ops;
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	__cg14_reset(&all->par);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg14: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	cg14_set_par(&all->info);
+	cg14_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg14: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg14_list);
+
+	printk("cg14: cgfourteen at %lx:%lx\n",
+	       all->par.physbase, all->par.iospace);
+
+}
+
+int __init cg14_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+#ifdef CONFIG_SPARC32
+	{
+		int root, node;
+
+		root = prom_getchild(prom_root_node);
+		root = prom_searchsiblings(root, "obio");
+		if (root) {
+			node = prom_searchsiblings(prom_getchild(root),
+						   "cgfourteen");
+			if (node)
+				cg14_init_one(NULL, node, root);
+		}
+	}
+#endif
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgfourteen"))
+			cg14_init_one(sdev, sdev->prom_node, sbus->prom_node);
+	}
+
+	return 0;
+}
+
+void __exit cg14_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg14_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg14_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(cg14_init);
+module_exit(cg14_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/cg3.c linux-2.5.63-bk7/drivers/video/cg3.c
--- linux-2.5.63-bk6/drivers/video/cg3.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/cg3.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,507 @@
+/* cg3.c: CGTHREE frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg3_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int cg3_set_par(struct fb_info *);
+static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int cg3_blank(int, struct fb_info *);
+
+static int cg3_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg3_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= cg3_check_var,
+	.fb_set_par		= cg3_set_par,
+	.fb_setcolreg		= cg3_setcolreg,
+	.fb_blank		= cg3_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= cg3_mmap,
+	.fb_cursor		= soft_cursor,
+};
+
+
+/* Control Register Constants */
+#define CG3_CR_ENABLE_INTS      0x80
+#define CG3_CR_ENABLE_VIDEO     0x40
+#define CG3_CR_ENABLE_TIMING    0x20
+#define CG3_CR_ENABLE_CURCMP    0x10
+#define CG3_CR_XTAL_MASK        0x0c
+#define CG3_CR_DIVISOR_MASK     0x03
+
+/* Status Register Constants */
+#define CG3_SR_PENDING_INT      0x80
+#define CG3_SR_RES_MASK         0x70
+#define CG3_SR_1152_900_76_A    0x40
+#define CG3_SR_1152_900_76_B    0x60
+#define CG3_SR_ID_MASK          0x0f
+#define CG3_SR_ID_COLOR         0x01
+#define CG3_SR_ID_MONO          0x02
+#define CG3_SR_ID_MONO_ECL      0x03
+
+enum cg3_type {
+	CG3_AT_66HZ = 0,
+	CG3_AT_76HZ,
+	CG3_RDI
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct cg3_regs {
+	struct bt_regs	cmap;
+	volatile u8	control;
+	volatile u8	status;
+	volatile u8	cursor_start;
+	volatile u8	cursor_end;
+	volatile u8	h_blank_start;
+	volatile u8	h_blank_end;
+	volatile u8	h_sync_start;
+	volatile u8	h_sync_end;
+	volatile u8	comp_sync_end;
+	volatile u8	v_blank_start_high;
+	volatile u8	v_blank_start_low;
+	volatile u8	v_blank_end;
+	volatile u8	v_sync_start;
+	volatile u8	v_sync_end;
+	volatile u8	xfer_holdoff_start;
+	volatile u8	xfer_holdoff_end;
+};
+
+/* Offset of interesting structures in the OBIO space */
+#define CG3_REGS_OFFSET	     0x400000UL
+#define CG3_RAM_OFFSET	     0x800000UL
+
+struct cg3_par {
+	spinlock_t		lock;
+	struct cg3_regs		*regs;
+	u32			sw_cmap[((256 * 3) + 3) / 4];
+
+	u32			flags;
+#define CG3_FLAG_BLANKED	0x00000001
+#define CG3_FLAG_RDI		0x00000002
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      cg3_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int cg3_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      cg3_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg3_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      cg3_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ * The cg3 palette is loaded with 4 color values at each time
+ * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
+ * We keep a sw copy of the hw cmap to assist us in this esoteric
+ * loading procedure.
+ */
+static int cg3_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct cg3_par *par = (struct cg3_par *) info->par;
+	struct bt_regs *bt = &par->regs->cmap;
+	unsigned long flags;
+	u32 *p32;
+	u8 *p8;
+	int count;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	p8 = (u8 *)par->sw_cmap + (regno * 3);
+	p8[0] = red;
+	p8[1] = green;
+	p8[2] = blue;
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+	count = 3;
+	p32 = &par->sw_cmap[D4M3(regno)];
+	sbus_writel(D4M4(regno), &bt->addr);
+	while (count--)
+		sbus_writel(*p32++, &bt->color_map);
+
+#undef D4M3
+#undef D4M4
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      cg3_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg3_blank(int blank, struct fb_info *info)
+{
+	struct cg3_par *par = (struct cg3_par *) info->par;
+	struct cg3_regs *regs = par->regs;
+	unsigned long flags;
+	u8 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		val = sbus_readl(&regs->control);
+		val |= CG3_CR_ENABLE_VIDEO;
+		sbus_writel(val, &regs->control);
+		par->flags &= ~CG3_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+	case 2: /* VESA blank (vsync off) */
+	case 3: /* VESA blank (hsync off) */
+	case 4: /* Poweroff */
+		val = sbus_readl(&regs->control);
+		val |= CG3_CR_ENABLE_VIDEO;
+		sbus_writel(val, &regs->control);
+		par->flags |= CG3_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map cg3_mmap_map[] = {
+	{ CG3_MMAP_OFFSET,	CG3_RAM_OFFSET,		SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,			0		    }
+};
+
+static int cg3_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg3_par *par = (struct cg3_par *)info->par;
+
+	return sbusfb_mmap_helper(cg3_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+cg3_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg3_par *par = (struct cg3_par *)info->par;
+
+	strncpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
+}
+
+static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
+				    struct sbus_dev *sdev)
+{
+	char buffer[40];
+	char *p;
+	int ww, hh;
+
+	*buffer = 0;
+	prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer));
+	if (*buffer) {
+		ww = simple_strtoul(buffer, &p, 10);
+		if (ww && *p == 'x') {
+			hh = simple_strtoul(p + 1, &p, 10);
+			if (hh && *p == '-') {
+				if (var->xres != ww ||
+				    var->yres != hh) {
+					var->xres = var->xres_virtual = ww;
+					var->yres = var->yres_virtual = hh;
+				}
+			}
+		}
+	}
+}
+
+static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
+	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
+	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x20,	0
+};
+
+static u8 cg3regvals_76hz[] __initdata = {	/* 1152 x 900, 76 Hz */
+	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
+	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
+	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x24,	0
+};
+
+static u8 cg3regvals_rdi[] __initdata = {	/* 640 x 480, cgRDI */
+	0x14, 0x70,	0x15, 0x20,	0x16, 0x08,	0x17, 0x10,
+	0x18, 0x06,	0x19, 0x02,	0x1a, 0x31,	0x1b, 0x51,
+	0x1c, 0x06,	0x1d, 0x0c,	0x1e, 0xff,	0x1f, 0x01,
+	0x10, 0x22,	0
+};
+
+static u8 *cg3_regvals[] __initdata = {
+	cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
+};
+
+static u_char cg3_dacvals[] __initdata = {
+	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0
+};
+
+static void cg3_do_default_mode(struct cg3_par *par)
+{
+	enum cg3_type type;
+	u8 *p;
+
+	if (par->flags & CG3_FLAG_RDI)
+		type = CG3_RDI;
+	else {
+		u8 status = sbus_readb(&par->regs->status), mon;
+		if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
+			mon = status & CG3_SR_RES_MASK;
+			if (mon == CG3_SR_1152_900_76_A ||
+			    mon == CG3_SR_1152_900_76_B)
+				type = CG3_AT_76HZ;
+			else
+				type = CG3_AT_66HZ;
+		} else {
+			prom_printf("cgthree: can't handle SR %02x\n",
+				    status);
+			prom_halt();
+			return;
+		}
+	}
+
+	for (p = cg3_regvals[type]; *p; p += 2) {
+		u8 *regp = &((u8 *)par->regs)[p[0]];
+		sbus_writeb(p[1], regp);
+	}
+	for (p = cg3_dacvals; *p; p += 2) {
+		volatile u8 *regp;
+
+		regp = (volatile u8 *)&par->regs->cmap.addr;
+		sbus_writeb(p[0], regp);
+		regp = (volatile u8 *)&par->regs->cmap.control;
+		sbus_writeb(p[1], regp);
+	}
+}
+
+struct all_info {
+	struct fb_info info;
+	struct cg3_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg3_list);
+
+static void cg3_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg3: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.physbase = sdev->reg_addrs[0].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+	if (!strcmp(sdev->prom_name, "cgRDI"))
+		all->par.flags |= CG3_FLAG_RDI;
+	if (all->par.flags & CG3_FLAG_RDI)
+		cg3_rdi_maybe_fixup_var(&all->info.var, sdev);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.regs = (struct cg3_regs *)
+		sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
+			     sizeof(struct cg3_regs), "cg3 regs");
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &cg3_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = (char *)
+			sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
+				     all->par.fbsize, "cg3 ram");
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	cg3_blank(0, &all->info);
+
+	if (!prom_getbool(sdev->prom_node, "width"))
+		cg3_do_default_mode(&all->par);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg3: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	cg3_set_par(&all->info);
+	cg3_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg3: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg3_list);
+
+	printk("cg3: %s at %lx:%lx\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init cg3_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgthree") ||
+		    !strcmp(sdev->prom_name, "cgRDI"))
+			cg3_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit cg3_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg3_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg3_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(cg3_init);
+module_exit(cg3_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/cg6.c linux-2.5.63-bk7/drivers/video/cg6.c
--- linux-2.5.63-bk6/drivers/video/cg6.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/cg6.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,793 @@
+/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int cg6_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int cg6_set_par(struct fb_info *);
+static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int cg6_blank(int, struct fb_info *);
+
+static void cg6_imageblit(struct fb_info *, struct fb_image *);
+static void cg6_fillrect(struct fb_info *, struct fb_fillrect *);
+static int cg6_sync(struct fb_info *);
+static int cg6_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops cg6_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= cg6_check_var,
+	.fb_set_par		= cg6_set_par,
+	.fb_setcolreg		= cg6_setcolreg,
+	.fb_blank		= cg6_blank,
+	.fb_fillrect		= cg6_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cg6_imageblit,
+	.fb_sync		= cg6_sync,
+	.fb_mmap		= cg6_mmap,
+	.fb_cursor		= soft_cursor,
+};
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the frame buffer control
+ * The FHC could is the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0UL
+#define CG6_BROOKTREE_OFFSET 0x200000UL
+#define CG6_DHC_OFFSET       0x240000UL
+#define CG6_ALT_OFFSET       0x280000UL
+#define CG6_FHC_OFFSET       0x300000UL
+#define CG6_THC_OFFSET       0x301000UL
+#define CG6_FBC_OFFSET       0x700000UL
+#define CG6_TEC_OFFSET       0x701000UL
+#define CG6_RAM_OFFSET       0x800000UL
+
+/* FHC definitions */
+#define CG6_FHC_FBID_SHIFT           24
+#define CG6_FHC_FBID_MASK            255
+#define CG6_FHC_REV_SHIFT            20
+#define CG6_FHC_REV_MASK             15
+#define CG6_FHC_FROP_DISABLE         (1 << 19)
+#define CG6_FHC_ROW_DISABLE          (1 << 18)
+#define CG6_FHC_SRC_DISABLE          (1 << 17)
+#define CG6_FHC_DST_DISABLE          (1 << 16)
+#define CG6_FHC_RESET                (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
+#define CG6_FHC_RES_MASK             (3 << 11)
+#define CG6_FHC_1024                 (0 << 11)
+#define CG6_FHC_1152                 (1 << 11)
+#define CG6_FHC_1280                 (2 << 11)
+#define CG6_FHC_1600                 (3 << 11)
+#define CG6_FHC_CPU_MASK             (3 << 9)
+#define CG6_FHC_CPU_SPARC            (0 << 9)
+#define CG6_FHC_CPU_68020            (1 << 9)
+#define CG6_FHC_CPU_386              (2 << 9)
+#define CG6_FHC_TEST		     (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT	     4
+#define CG6_FHC_TEST_X_MASK	     15
+#define CG6_FHC_TEST_Y_SHIFT	     0
+#define CG6_FHC_TEST_Y_MASK	     15
+
+/* FBC mode definitions */
+#define CG6_FBC_BLIT_IGNORE		0x00000000
+#define CG6_FBC_BLIT_NOSRC		0x00100000
+#define CG6_FBC_BLIT_SRC		0x00200000
+#define CG6_FBC_BLIT_ILLEGAL		0x00300000
+#define CG6_FBC_BLIT_MASK		0x00300000
+
+#define CG6_FBC_VBLANK			0x00080000
+
+#define CG6_FBC_MODE_IGNORE		0x00000000
+#define CG6_FBC_MODE_COLOR8		0x00020000
+#define CG6_FBC_MODE_COLOR1		0x00040000
+#define CG6_FBC_MODE_HRMONO		0x00060000
+#define CG6_FBC_MODE_MASK		0x00060000
+
+#define CG6_FBC_DRAW_IGNORE		0x00000000
+#define CG6_FBC_DRAW_RENDER		0x00008000
+#define CG6_FBC_DRAW_PICK		0x00010000
+#define CG6_FBC_DRAW_ILLEGAL		0x00018000
+#define CG6_FBC_DRAW_MASK		0x00018000
+
+#define CG6_FBC_BWRITE0_IGNORE		0x00000000
+#define CG6_FBC_BWRITE0_ENABLE		0x00002000
+#define CG6_FBC_BWRITE0_DISABLE		0x00004000
+#define CG6_FBC_BWRITE0_ILLEGAL		0x00006000
+#define CG6_FBC_BWRITE0_MASK		0x00006000
+
+#define CG6_FBC_BWRITE1_IGNORE		0x00000000
+#define CG6_FBC_BWRITE1_ENABLE		0x00000800
+#define CG6_FBC_BWRITE1_DISABLE		0x00001000
+#define CG6_FBC_BWRITE1_ILLEGAL		0x00001800
+#define CG6_FBC_BWRITE1_MASK		0x00001800
+
+#define CG6_FBC_BREAD_IGNORE		0x00000000
+#define CG6_FBC_BREAD_0			0x00000200
+#define CG6_FBC_BREAD_1			0x00000400
+#define CG6_FBC_BREAD_ILLEGAL		0x00000600
+#define CG6_FBC_BREAD_MASK		0x00000600
+
+#define CG6_FBC_BDISP_IGNORE		0x00000000
+#define CG6_FBC_BDISP_0			0x00000080
+#define CG6_FBC_BDISP_1			0x00000100
+#define CG6_FBC_BDISP_ILLEGAL		0x00000180
+#define CG6_FBC_BDISP_MASK		0x00000180
+
+#define CG6_FBC_INDEX_MOD		0x00000040
+#define CG6_FBC_INDEX_MASK		0x00000030
+
+/* THC definitions */
+#define CG6_THC_MISC_REV_SHIFT       16
+#define CG6_THC_MISC_REV_MASK        15
+#define CG6_THC_MISC_RESET           (1 << 12)
+#define CG6_THC_MISC_VIDEO           (1 << 10)
+#define CG6_THC_MISC_SYNC            (1 << 9)
+#define CG6_THC_MISC_VSYNC           (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
+#define CG6_THC_MISC_CURS_RES        (1 << 6)
+#define CG6_THC_MISC_INT_ENAB        (1 << 5)
+#define CG6_THC_MISC_INT             (1 << 4)
+#define CG6_THC_MISC_INIT            0x9f
+
+/* The contents are unknown */
+struct cg6_tec {
+	volatile int tec_matrix;
+	volatile int tec_clip;
+	volatile int tec_vdc;
+};
+
+struct cg6_thc {
+        uint thc_pad0[512];
+	volatile uint thc_hs;		/* hsync timing */
+	volatile uint thc_hsdvs;
+	volatile uint thc_hd;
+	volatile uint thc_vs;		/* vsync timing */
+	volatile uint thc_vd;
+	volatile uint thc_refresh;
+	volatile uint thc_misc;
+	uint thc_pad1[56];
+	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile uint thc_cursmask[32];	/* cursor mask bits */
+	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct cg6_fbc {
+	u32		xxx0[1];
+	volatile u32	mode;
+	volatile u32	clip;
+	u32		xxx1[1];	    
+	volatile u32	s;
+	volatile u32	draw;
+	volatile u32	blit;
+	volatile u32	font;
+	u32		xxx2[24];
+	volatile u32	x0, y0, z0, color0;
+	volatile u32	x1, y1, z1, color1;
+	volatile u32	x2, y2, z2, color2;
+	volatile u32	x3, y3, z3, color3;
+	volatile u32	offx, offy;
+	u32		xxx3[2];
+	volatile u32	incx, incy;
+	u32		xxx4[2];
+	volatile u32	clipminx, clipminy;
+	u32		xxx5[2];
+	volatile u32	clipmaxx, clipmaxy;
+	u32		xxx6[2];
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	alu;
+	volatile u32	pm;
+	volatile u32	pixelm;
+	u32		xxx7[2];
+	volatile u32	patalign;
+	volatile u32	pattern[8];
+	u32		xxx8[432];
+	volatile u32	apointx, apointy, apointz;
+	u32		xxx9[1];
+	volatile u32	rpointx, rpointy, rpointz;
+	u32		xxx10[5];
+	volatile u32	pointr, pointg, pointb, pointa;
+	volatile u32	alinex, aliney, alinez;
+	u32		xxx11[1];
+	volatile u32	rlinex, rliney, rlinez;
+	u32		xxx12[5];
+	volatile u32	liner, lineg, lineb, linea;
+	volatile u32	atrix, atriy, atriz;
+	u32		xxx13[1];
+	volatile u32	rtrix, rtriy, rtriz;
+	u32		xxx14[5];
+	volatile u32	trir, trig, trib, tria;
+	volatile u32	aquadx, aquady, aquadz;
+	u32		xxx15[1];
+	volatile u32	rquadx, rquady, rquadz;
+	u32		xxx16[5];
+	volatile u32	quadr, quadg, quadb, quada;
+	volatile u32	arectx, arecty, arectz;
+	u32		xxx17[1];
+	volatile u32	rrectx, rrecty, rrectz;
+	u32		xxx18[5];
+	volatile u32	rectr, rectg, rectb, recta;
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+struct cg6_par {
+	spinlock_t		lock;
+	struct bt_regs		*bt;
+	struct cg6_fbc		*fbc;
+	struct cg6_thc		*thc;
+	struct cg6_tec		*tec;
+	volatile u32		*fhc;
+
+	u32			flags;
+#define CG6_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+static int cg6_sync(struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc *fbc = par->fbc;
+	int limit = 10000;
+
+	do {
+		if (!(sbus_readl(&fbc->s) & 0x10000000))
+			break;
+		udelay(10);
+	} while (--limit > 0);
+
+	return 0;
+}
+
+/**
+ *      cg6_fillrect - REQUIRED function. Can use generic routines if 
+ *                     non acclerated hardware and packed pixel based.
+ *                     Draws a rectangle on the screen.               
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @rect: structure defining the rectagle and operation.
+ */
+static void cg6_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc *fbc = par->fbc;
+	unsigned long flags;
+	s32 val;
+
+	/* XXX doesn't handle ROP_XOR */
+
+	spin_lock_irqsave(&par->lock, flags);
+	cg6_sync(info);
+	sbus_writel(rect->color, &fbc->fg);
+	sbus_writel(~(u32)0, &fbc->pixelm);
+	sbus_writel(0xea80ff00, &fbc->alu);
+	sbus_writel(0, &fbc->s);
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(~(u32)0, &fbc->pm);
+	sbus_writel(rect->dy, &fbc->arecty);
+	sbus_writel(rect->dx, &fbc->arectx);
+	sbus_writel(rect->dy + rect->height, &fbc->arecty);
+	sbus_writel(rect->dx + rect->width, &fbc->arectx);
+	do {
+		val = sbus_readl(&fbc->draw);
+	} while (val < 0 && (val & 0x20000000));
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      cg6_imageblit - REQUIRED function. Can use generic routines if
+ *                      non acclerated hardware and packed pixel based.
+ *                      Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void cg6_imageblit(struct fb_info *info, struct fb_image *image)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_fbc *fbc = par->fbc;
+	u8 *data = image->data;
+	unsigned long flags;
+	u32 x, y;
+	int i, width;
+
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	cg6_sync(info);
+
+	sbus_writel(image->fg_color, &fbc->fg);
+	sbus_writel(image->bg_color, &fbc->bg);
+	sbus_writel(0x140000, &fbc->mode);
+	sbus_writel(0xe880fc30, &fbc->alu);
+	sbus_writel(~(u32)0, &fbc->pixelm);
+	sbus_writel(0, &fbc->s);
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(0xff, &fbc->pm);
+	sbus_writel(32, &fbc->incx);
+	sbus_writel(0, &fbc->incy);
+
+	x = image->dx;
+	y = image->dy;
+	for (i = 0; i < image->height; i++) {
+		width = image->width;
+
+		while (width >= 32) {
+			u32 val;
+
+			sbus_writel(y, &fbc->y0);
+			sbus_writel(x, &fbc->x0);
+			sbus_writel(x + 32 - 1, &fbc->x1);
+			
+			val = ((u32)data[0] << 24) |
+			      ((u32)data[1] << 16) |
+			      ((u32)data[2] <<  8) |
+			      ((u32)data[3] <<  0);
+			sbus_writel(val, &fbc->font);
+
+			data += 4;
+			x += 32;
+			width -= 32;
+		}
+		if (width) {
+			u32 val;
+
+			sbus_writel(y, &fbc->y0);
+			sbus_writel(x, &fbc->x0);
+			sbus_writel(x + width - 1, &fbc->x1);
+			if (width <= 8) {
+				val = (u32) data[0] << 24;
+				data += 1;
+			} else if (width <= 16) {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16);
+				data += 2;
+			} else {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16) |
+				      ((u32) data[2] <<  8);
+				data += 3;
+			}
+			sbus_writel(val, &fbc->font);
+		}
+
+		y += 1;
+		x = image->dx;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      cg6_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int cg6_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      cg6_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg6_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      cg6_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int cg6_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct bt_regs *bt = par->bt;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel((u32)regno << 24, &bt->addr);
+	sbus_writel((u32)red << 24, &bt->color_map);
+	sbus_writel((u32)green << 24, &bt->color_map);
+	sbus_writel((u32)blue << 24, &bt->color_map);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      cg6_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+cg6_blank(int blank, struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_thc *thc = par->thc;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		val = sbus_readl(&thc->thc_misc);
+		val |= CG6_THC_MISC_VIDEO;
+		sbus_writel(val, &thc->thc_misc);
+		par->flags &= ~CG6_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+	case 2: /* VESA blank (vsync off) */
+	case 3: /* VESA blank (hsync off) */
+	case 4: /* Poweroff */
+		val = sbus_readl(&thc->thc_misc);
+		val &= ~CG6_THC_MISC_VIDEO;
+		sbus_writel(val, &thc->thc_misc);
+		par->flags |= CG6_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map cg6_mmap_map[] = {
+	{ CG6_FBC,		CG6_FBC_OFFSET,		PAGE_SIZE 		},
+	{ CG6_TEC,		CG6_TEC_OFFSET,		PAGE_SIZE 		},
+	{ CG6_BTREGS,		CG6_BROOKTREE_OFFSET,	PAGE_SIZE 		},
+	{ CG6_FHC,		CG6_FHC_OFFSET,		PAGE_SIZE 		},
+	{ CG6_THC,		CG6_THC_OFFSET,		PAGE_SIZE 		},
+	{ CG6_ROM,		CG6_ROM_OFFSET,		0x10000   		},
+	{ CG6_RAM,		CG6_RAM_OFFSET,		SBUS_MMAP_FBSIZE(1)  	},
+	{ CG6_DHC,		CG6_DHC_OFFSET,		0x40000   		},
+	{ 0,			0,			0	  		}
+};
+
+static int cg6_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct cg6_par *par = (struct cg6_par *)info->par;
+
+	return sbusfb_mmap_helper(cg6_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+cg6_init_fix(struct fb_info *info, int linebytes)
+{
+	struct cg6_par *par = (struct cg6_par *)info->par;
+	const char *cg6_cpu_name, *cg6_card_name;
+	u32 conf;
+
+	conf = sbus_readl(par->fhc);
+	switch(conf & CG6_FHC_CPU_MASK) {
+	case CG6_FHC_CPU_SPARC:
+		cg6_cpu_name = "sparc";
+		break;
+	case CG6_FHC_CPU_68020:
+		cg6_cpu_name = "68020";
+		break;
+	default:
+		cg6_cpu_name = "i386";
+		break;
+	};
+	if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
+		if (par->fbsize <= 0x100000) {
+			cg6_card_name = "TGX";
+		} else {
+			cg6_card_name = "TGX+";
+		}
+	} else {
+		if (par->fbsize <= 0x100000) {
+			cg6_card_name = "GX";
+		} else {
+			cg6_card_name = "GX+";
+		}
+	}
+
+	sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGSIX;
+}
+
+/* Initialize Brooktree DAC */
+static void cg6_bt_init(struct cg6_par *par)
+{
+	struct bt_regs *bt = par->bt;
+
+	sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
+	sbus_writel(0xff << 24, &bt->control);
+	sbus_writel(0x05 << 24, &bt->addr);
+	sbus_writel(0x00 << 24, &bt->control);
+	sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
+	sbus_writel(0x73 << 24, &bt->control);
+	sbus_writel(0x07 << 24, &bt->addr);
+	sbus_writel(0x00 << 24, &bt->control);
+}
+
+static void cg6_chip_init(struct fb_info *info)
+{
+	struct cg6_par *par = (struct cg6_par *) info->par;
+	struct cg6_tec *tec = par->tec;
+	struct cg6_fbc *fbc = par->fbc;
+	u32 rev, conf, mode, tmp;
+	int i;
+	
+	/* Turn off stuff in the Transform Engine. */
+	sbus_writel(0, &tec->tec_matrix);
+	sbus_writel(0, &tec->tec_clip);
+	sbus_writel(0, &tec->tec_vdc);
+
+	/* Take care of bugs in old revisions. */
+	rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
+	if (rev < 5) {
+		conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) |
+			CG6_FHC_CPU_68020 | CG6_FHC_TEST |
+			(11 << CG6_FHC_TEST_X_SHIFT) |
+			(11 << CG6_FHC_TEST_Y_SHIFT);
+		if (rev < 2)
+			conf |= CG6_FHC_DST_DISABLE;
+		sbus_writel(conf, par->fhc);
+	}
+
+	/* Set things in the FBC. Bad things appear to happen if we do
+	 * back to back store/loads on the mode register, so copy it
+	 * out instead. */
+	mode = sbus_readl(&fbc->mode);
+	do {
+		i = sbus_readl(&fbc->s);
+	} while (i & 0x10000000);
+	mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
+		       CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+		       CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+		       CG6_FBC_BDISP_MASK);
+	mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
+		      CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+		      CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+		      CG6_FBC_BDISP_0);
+	sbus_writel(mode, &fbc->mode);
+
+	sbus_writel(0, &fbc->clip);
+	sbus_writel(0, &fbc->offx);
+	sbus_writel(0, &fbc->offy);
+	sbus_writel(0, &fbc->clipminx);
+	sbus_writel(0, &fbc->clipminy);
+	sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
+	sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
+
+	/* Disable cursor in Brooktree DAC. */
+	sbus_writel(0x06 << 24, &par->bt->addr);
+	tmp = sbus_readl(&par->bt->control);
+	tmp &= ~(0x03 << 24);
+	sbus_writel(tmp, &par->bt->control);
+}
+
+struct all_info {
+	struct fb_info info;
+	struct cg6_par par;
+	struct list_head list;
+};
+static LIST_HEAD(cg6_list);
+
+static void cg6_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "cg6: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.physbase = sdev->reg_addrs[0].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+	if (prom_getbool(sdev->prom_node, "dblbuf"))
+		all->par.fbsize *= 4;
+
+	all->par.fbc = (struct cg6_fbc *)
+		sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
+			     4096, "cgsix fbc");
+	all->par.tec = (struct cg6_tec *)
+		sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
+			     sizeof(struct cg6_tec), "cgsix tec");
+	all->par.thc = (struct cg6_thc *)
+		sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
+			     sizeof(struct cg6_thc), "cgsix thc");
+	all->par.bt = (struct bt_regs *)
+		sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
+			     sizeof(struct bt_regs), "cgsix dac");
+	all->par.fhc = (u32 *)
+		sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
+			     sizeof(u32), "cgsix fhc");
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &cg6_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = (char *)
+			sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
+				     all->par.fbsize, "cgsix ram");
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	all->info.var.accel_flags = FB_ACCELF_TEXT;
+
+	cg6_bt_init(&all->par);
+	cg6_chip_init(&all->info);
+	cg6_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "cg6: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	cg6_set_par(&all->info);
+	cg6_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "cg6: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &cg6_list);
+
+	printk("cg6: CGsix [%s] at %lx:%lx\n",
+	       all->info.fix.id,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init cg6_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "cgsix") ||
+		    !strcmp(sdev->prom_name, "cgthree+"))
+			cg6_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit cg6_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &cg6_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+cg6_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(cg6_init);
+module_exit(cg6_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/cgfourteenfb.c linux-2.5.63-bk7/drivers/video/cgfourteenfb.c
--- linux-2.5.63-bk6/drivers/video/cgfourteenfb.c	Mon Feb 24 11:05:41 2003
+++ linux-2.5.63-bk7/drivers/video/cgfourteenfb.c	Wed Dec 31 16:00:00 1969
@@ -1,445 +0,0 @@
-/* $Id: cgfourteenfb.c,v 1.11 2001/09/19 00:04:33 davem Exp $
- * cgfourteenfb.c: CGfourteen frame buffer driver
- *
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#include <video/fbcon-cfb8.h>
-
-#define CG14_MCR_INTENABLE_SHIFT	7
-#define CG14_MCR_INTENABLE_MASK		0x80
-#define CG14_MCR_VIDENABLE_SHIFT	6
-#define CG14_MCR_VIDENABLE_MASK		0x40
-#define CG14_MCR_PIXMODE_SHIFT		4
-#define CG14_MCR_PIXMODE_MASK		0x30
-#define CG14_MCR_TMR_SHIFT		2
-#define CG14_MCR_TMR_MASK		0x0c
-#define CG14_MCR_TMENABLE_SHIFT		1
-#define CG14_MCR_TMENABLE_MASK		0x02
-#define CG14_MCR_RESET_SHIFT		0
-#define CG14_MCR_RESET_MASK		0x01
-#define CG14_REV_REVISION_SHIFT		4
-#define CG14_REV_REVISION_MASK		0xf0
-#define CG14_REV_IMPL_SHIFT		0
-#define CG14_REV_IMPL_MASK		0x0f
-#define CG14_VBR_FRAMEBASE_SHIFT	12
-#define CG14_VBR_FRAMEBASE_MASK		0x00fff000
-#define CG14_VMCR1_SETUP_SHIFT		0
-#define CG14_VMCR1_SETUP_MASK		0x000001ff
-#define CG14_VMCR1_VCONFIG_SHIFT	9
-#define CG14_VMCR1_VCONFIG_MASK		0x00000e00
-#define CG14_VMCR2_REFRESH_SHIFT	0
-#define CG14_VMCR2_REFRESH_MASK		0x00000001
-#define CG14_VMCR2_TESTROWCNT_SHIFT	1
-#define CG14_VMCR2_TESTROWCNT_MASK	0x00000002
-#define CG14_VMCR2_FBCONFIG_SHIFT	2
-#define CG14_VMCR2_FBCONFIG_MASK	0x0000000c
-#define CG14_VCR_REFRESHREQ_SHIFT	0
-#define CG14_VCR_REFRESHREQ_MASK	0x000003ff
-#define CG14_VCR1_REFRESHENA_SHIFT	10
-#define CG14_VCR1_REFRESHENA_MASK	0x00000400
-#define CG14_VCA_CAD_SHIFT		0
-#define CG14_VCA_CAD_MASK		0x000003ff
-#define CG14_VCA_VERS_SHIFT		10
-#define CG14_VCA_VERS_MASK		0x00000c00
-#define CG14_VCA_RAMSPEED_SHIFT		12
-#define CG14_VCA_RAMSPEED_MASK		0x00001000
-#define CG14_VCA_8MB_SHIFT		13
-#define CG14_VCA_8MB_MASK		0x00002000
-
-#define CG14_MCR_PIXMODE_8		0
-#define CG14_MCR_PIXMODE_16		2
-#define CG14_MCR_PIXMODE_32		3
-
-MODULE_LICENSE("GPL");
-
-struct cg14_regs{
-	volatile u8 mcr;	/* Master Control Reg */
-	volatile u8 ppr;	/* Packed Pixel Reg */
-	volatile u8 tms[2];	/* Test Mode Status Regs */
-	volatile u8 msr;	/* Master Status Reg */
-	volatile u8 fsr;	/* Fault Status Reg */
-	volatile u8 rev;	/* Revision & Impl */
-	volatile u8 ccr;	/* Clock Control Reg */
-	volatile u32 tmr;	/* Test Mode Read Back */
-	volatile u8 mod;	/* Monitor Operation Data Reg */
-	volatile u8 acr;	/* Aux Control */
-	u8 xxx0[6];
-	volatile u16 hct;	/* Hor Counter */
-	volatile u16 vct;	/* Vert Counter */
-	volatile u16 hbs;	/* Hor Blank Start */
-	volatile u16 hbc;	/* Hor Blank Clear */
-	volatile u16 hss;	/* Hor Sync Start */
-	volatile u16 hsc;	/* Hor Sync Clear */
-	volatile u16 csc;	/* Composite Sync Clear */
-	volatile u16 vbs;	/* Vert Blank Start */
-	volatile u16 vbc;	/* Vert Blank Clear */
-	volatile u16 vss;	/* Vert Sync Start */
-	volatile u16 vsc;	/* Vert Sync Clear */
-	volatile u16 xcs;
-	volatile u16 xcc;
-	volatile u16 fsa;	/* Fault Status Address */
-	volatile u16 adr;	/* Address Registers */
-	u8 xxx1[0xce];
-	volatile u8 pcg[0x100]; /* Pixel Clock Generator */
-	volatile u32 vbr;	/* Frame Base Row */
-	volatile u32 vmcr;	/* VBC Master Control */
-	volatile u32 vcr;	/* VBC refresh */
-	volatile u32 vca;	/* VBC Config */
-};
-
-#define CG14_CCR_ENABLE	0x04
-#define CG14_CCR_SELECT 0x02	/* HW/Full screen */
-
-struct cg14_cursor {
-	volatile u32 cpl0[32];	/* Enable plane 0 */
-	volatile u32 cpl1[32];  /* Color selection plane */
-	volatile u8 ccr;	/* Cursor Control Reg */
-	u8 xxx0[3];
-	volatile u16 cursx;	/* Cursor x,y position */
-	volatile u16 cursy;	/* Cursor x,y position */
-	volatile u32 color0;
-	volatile u32 color1;
-	u32 xxx1[0x1bc];
-	volatile u32 cpl0i[32];	/* Enable plane 0 autoinc */
-	volatile u32 cpl1i[32]; /* Color selection autoinc */
-};
-
-struct cg14_dac {
-	volatile u8 addr;	/* Address Register */
-	u8 xxx0[255];
-	volatile u8 glut;	/* Gamma table */
-	u8 xxx1[255];
-	volatile u8 select;	/* Register Select */
-	u8 xxx2[255];
-	volatile u8 mode;	/* Mode Register */
-};
-
-struct cg14_xlut{
-	volatile u8 x_xlut [256];
-	volatile u8 x_xlutd [256];
-	u8 xxx0[0x600];
-	volatile u8 x_xlut_inc [256];
-	volatile u8 x_xlutd_inc [256];
-};
-
-/* Color look up table (clut) */
-/* Each one of these arrays hold the color lookup table (for 256
- * colors) for each MDI page (I assume then there should be 4 MDI
- * pages, I still wonder what they are.  I have seen NeXTStep split
- * the screen in four parts, while operating in 24 bits mode.  Each
- * integer holds 4 values: alpha value (transparency channel, thanks
- * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
- *
- * I currently use the clut instead of the Xlut
- */
-struct cg14_clut {
-	u32 c_clut [256];
-	u32 c_clutd [256];    /* i wonder what the 'd' is for */
-	u32 c_clut_inc [256];
-	u32 c_clutd_inc [256];
-};
-
-static struct sbus_mmap_map cg14_mmap_map[] __initdata = {
-	{ CG14_REGS,		0x80000000,		0x1000		    },
-	{ CG14_XLUT,		0x80003000,		0x1000		    },
-	{ CG14_CLUT1,		0x80004000,		0x1000		    },
-	{ CG14_CLUT2,		0x80005000,		0x1000		    },
-	{ CG14_CLUT3,		0x80006000,		0x1000		    },
-	{ CG3_MMAP_OFFSET - 
-	  0x7000,		0x80000000,		0x7000		    },
-	{ CG3_MMAP_OFFSET,	0x00000000,		SBUS_MMAP_FBSIZE(1) },
-	{ MDI_CURSOR_MAP,	0x80001000,		0x1000		    },
-	{ MDI_CHUNKY_BGR_MAP,	0x01000000,		0x400000	    },
-	{ MDI_PLANAR_X16_MAP,	0x02000000,		0x200000	    },
-	{ MDI_PLANAR_C16_MAP,	0x02800000,		0x200000	    },
-	{ MDI_PLANAR_X32_MAP,	0x03000000,		0x100000	    },
-	{ MDI_PLANAR_B32_MAP,	0x03400000,		0x100000	    },
-	{ MDI_PLANAR_G32_MAP,	0x03800000,		0x100000	    },
-	{ MDI_PLANAR_R32_MAP,	0x03c00000,		0x100000	    },
-	{ 0,			0,			0		    }
-};
-
-static void cg14_loadcmap (struct fb_info_sbusfb *fb, struct display *p,
-			   int index, int count)
-{
-	struct cg14_clut *clut = fb->s.cg14.clut;
-	unsigned long flags;
-	        
-	spin_lock_irqsave(&fb->lock, flags);
-	for (; count--; index++) {
-		u32 val;
-
-		val = ((fb->color_map CM(index,2) << 16) |
-		       (fb->color_map CM(index,1) << 8) |
-		       (fb->color_map CM(index,0)));
-		sbus_writel(val, &clut->c_clut[index]);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg14_margins (struct fb_info_sbusfb *fb, struct display *p,
-			  int x_margin, int y_margin)
-{
-	fb->info.screen_base += (y_margin - fb->y_margin) *
-		fb->info.fix.line_length + (x_margin - fb->x_margin);
-}
-
-static void cg14_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
-	struct cg14_cursor *cur = fb->s.cg14.cursor;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(((red[0]) | (green[0] << 8) | (blue[0] << 16)), &cur->color0);
-	sbus_writel(((red[1]) | (green[1] << 8) | (blue[1] << 16)), &cur->color1);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void cg14_setcurshape (struct fb_info_sbusfb *fb)
-{
-	struct cg14_cursor *cur = fb->s.cg14.cursor;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	for (i = 0; i < 32; i++){
-		sbus_writel(fb->cursor.bits[0][i], &cur->cpl0[i]);
-		sbus_writel(fb->cursor.bits[1][i], &cur->cpl1[i]);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void cg14_setcursor (struct fb_info_sbusfb *fb)
-{
-	struct cg_cursor *c = &fb->cursor;
-	struct cg14_cursor *cur = fb->s.cg14.cursor;
-	unsigned long flags;
-                
-	spin_lock_irqsave(&fb->lock, flags);
-	if (c->enable) {
-		u8 tmp = sbus_readb(&cur->ccr);
-
-		tmp |= CG14_CCR_ENABLE;
-		sbus_writeb(tmp, &cur->ccr);
-	} else {
-		u8 tmp = sbus_readb(&cur->ccr);
-
-		tmp &= ~CG14_CCR_ENABLE;
-		sbus_writeb(tmp, &cur->ccr);
-	}
-	sbus_writew(((c->cpos.fbx - c->chot.fbx) & 0xfff), &cur->cursx);
-	sbus_writew(((c->cpos.fby - c->chot.fby) & 0xfff), &cur->cursy);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg14_switch_from_graph (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&fb->lock, flags);
-
-	/* Set the 8-bpp mode */
-	if (fb->open && fb->mmaped){
-		volatile char *mcr = &fb->s.cg14.regs->mcr;
-		char tmp;
-	                                
-		fb->s.cg14.mode = 8;
-		tmp = sbus_readb(mcr);
-		tmp &= ~(CG14_MCR_PIXMODE_MASK);
-		sbus_writeb(tmp, mcr);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg14_reset (struct fb_info_sbusfb *fb)
-{
-	volatile char *mcr = &fb->s.cg14.regs->mcr;
-	unsigned long flags;
-	char tmp;
-	        
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readb(mcr);
-	tmp &= ~(CG14_MCR_PIXMODE_MASK);
-	sbus_writeb(tmp, mcr);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int cg14_ioctl (struct fb_info_sbusfb *fb, unsigned int cmd, unsigned long arg)
-{
-	volatile char *mcr = &fb->s.cg14.regs->mcr;
-	struct mdi_cfginfo *mdii;
-	unsigned long flags;
-	int mode, ret = 0;
-	char tmp;
-	        
-	switch (cmd) {
-	case MDI_RESET:
-		spin_lock_irqsave(&fb->lock, flags);
-		tmp = sbus_readb(mcr);
-		tmp &= ~CG14_MCR_PIXMODE_MASK;
-		sbus_writeb(tmp, mcr);
-		spin_unlock_irqrestore(&fb->lock, flags);
-		break;
-	case MDI_GET_CFGINFO:
-		mdii = (struct mdi_cfginfo *)arg;
-		if (put_user(FBTYPE_MDICOLOR, &mdii->mdi_type) ||
-		    __put_user(fb->type.fb_height, &mdii->mdi_height) ||
-		    __put_user(fb->type.fb_width, &mdii->mdi_width) ||
-		    __put_user(fb->s.cg14.mode, &mdii->mdi_mode) ||
-		    __put_user(72, &mdii->mdi_pixfreq) || /* FIXME */
-		    __put_user(fb->s.cg14.ramsize, &mdii->mdi_size))
-			return -EFAULT;
-		break;
-	case MDI_SET_PIXELMODE:
-		if (get_user(mode, (int *)arg))
-			return -EFAULT;
-
-		spin_lock_irqsave(&fb->lock, flags);
-		tmp = sbus_readb(mcr);
-		switch (mode){
-		case MDI_32_PIX:
-			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK) |
-				(CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT);
-			break;
-		case MDI_16_PIX:
-			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK) | 0x20;
-			break;
-		case MDI_8_PIX:
-			tmp = (tmp & ~CG14_MCR_PIXMODE_MASK);
-			break;
-		default:
-			ret = -ENOSYS;
-			break;
-		};
-		if (ret == 0) {
-			sbus_writeb(tmp, mcr);
-			fb->s.cg14.mode = mode;
-		}
-		spin_unlock_irqrestore(&fb->lock, flags);
-		break;
-	default:
-		ret = -EINVAL;
-	};
-
-	return ret;
-}
-
-static unsigned long __init get_phys(unsigned long addr)
-{
-	return __get_phys(addr);
-}
-
-static int __init get_iospace(unsigned long addr)
-{
-	return __get_iospace(addr);
-}
-
-static char idstring[60] __initdata = { 0 };
-
-char __init *cgfourteenfb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	unsigned long rphys, phys;
-	u32 bases[6];
-	int is_8mb, i;
-
-#ifndef FBCON_HAS_CFB8
-	return NULL;
-#endif
-	prom_getproperty (fb->prom_node, "address", (char *) &bases[0], 8);
-	if (!bases[0]) {
-		printk("cg14 not mmaped\n");
-		return NULL;
-	}
-	if (get_iospace(bases[0]) != get_iospace(bases[1])) {
-		printk("Ugh. cg14 iospaces don't match\n");
-		return NULL;
-	}
-	fb->physbase = phys = get_phys(bases[1]);
-	rphys = get_phys(bases[0]);
-	fb->iospace = get_iospace(bases[0]);
-	fb->s.cg14.regs = (struct cg14_regs *)(unsigned long)bases[0];
-	fb->s.cg14.clut = (void *)((unsigned long)bases[0]+CG14_CLUT1);
-	fb->s.cg14.cursor = (void *)((unsigned long)bases[0]+CG14_CURSORREGS);
-	fb->info.screen_base = (char *)bases[1];
-	
-	/* CG14_VCA_8MB_MASK is not correctly set on the 501-2482
-	 * VSIMM, so we read the memory size from the PROM
-	 */
-	prom_getproperty(fb->prom_node, "reg", (char *) &bases[0], 24);
-	is_8mb = bases[5] == 0x800000;
-
-	fb->mmap_map = kmalloc(sizeof(cg14_mmap_map), GFP_KERNEL);
-	if (!fb->mmap_map)
-		return NULL;
-
-	for (i = 0; ; i++) {
-		fb->mmap_map[i].voff = cg14_mmap_map[i].voff;
-		fb->mmap_map[i].poff = (cg14_mmap_map[i].poff & 0x80000000) ?
-				       (cg14_mmap_map[i].poff & 0x7fffffff) + rphys - phys :
-				       cg14_mmap_map[i].poff;
-		fb->mmap_map[i].size = cg14_mmap_map[i].size;
-		if (is_8mb && fb->mmap_map[i].size >= 0x100000 &&
-		    fb->mmap_map[i].size <= 0x400000)
-			fb->mmap_map[i].size <<= 1;
-		if (!cg14_mmap_map[i].size)
-			break;
-	}
-
-	strcpy(fb->info.modename, "CGfourteen");
-	strcpy(fix->id, "CGfourteen");
-	fix->line_length = fb->info.var.xres_virtual;
-	fix->accel = FB_ACCEL_SUN_CG14;
-	
-	disp->scrollmode = SCROLL_YREDRAW;
-	fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
-	fb->dispsw = fbcon_cfb8;
-	
-	type->fb_depth = 24;
-	fb->emulations[1] = FBTYPE_SUN3COLOR;
-
-	fb->margins = cg14_margins;
-	fb->loadcmap = cg14_loadcmap;
-	fb->setcursor = cg14_setcursor;
-	fb->setcursormap = cg14_setcursormap;
-	fb->setcurshape = cg14_setcurshape;
-	fb->reset = cg14_reset;
-	fb->switch_from_graph = cg14_switch_from_graph;
-	fb->ioctl = cg14_ioctl;
-
-	fb->s.cg14.mode = 8;
-	fb->s.cg14.ramsize = (is_8mb) ? 0x800000 : 0x400000;
-	
-	cg14_reset(fb);
-	
-	sprintf(idstring, "cgfourteen at %x.%08lx, %dMB, rev=%d, impl=%d", fb->iospace, phys,
-		is_8mb ? 8 : 4, fb->s.cg14.regs->rev >> 4, fb->s.cg14.regs->rev & 0xf);
-	
-	return idstring;
-}
diff -urN linux-2.5.63-bk6/drivers/video/cgsixfb.c linux-2.5.63-bk7/drivers/video/cgsixfb.c
--- linux-2.5.63-bk6/drivers/video/cgsixfb.c	Mon Feb 24 11:05:29 2003
+++ linux-2.5.63-bk7/drivers/video/cgsixfb.c	Wed Dec 31 16:00:00 1969
@@ -1,824 +0,0 @@
-/* $Id: cgsixfb.c,v 1.26 2001/10/16 05:44:44 davem Exp $
- * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
- *
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-
-/* Offset of interesting structures in the OBIO space */
-/*
- * Brooktree is the video dac and is funny to program on the cg6.
- * (it's even funnier on the cg3)
- * The FBC could be the frame buffer control
- * The FHC could is the frame buffer hardware control.
- */
-#define CG6_ROM_OFFSET       0x0UL
-#define CG6_BROOKTREE_OFFSET 0x200000UL
-#define CG6_DHC_OFFSET       0x240000UL
-#define CG6_ALT_OFFSET       0x280000UL
-#define CG6_FHC_OFFSET       0x300000UL
-#define CG6_THC_OFFSET       0x301000UL
-#define CG6_FBC_OFFSET       0x700000UL
-#define CG6_TEC_OFFSET       0x701000UL
-#define CG6_RAM_OFFSET       0x800000UL
-
-/* FHC definitions */
-#define CG6_FHC_FBID_SHIFT           24
-#define CG6_FHC_FBID_MASK            255
-#define CG6_FHC_REV_SHIFT            20
-#define CG6_FHC_REV_MASK             15
-#define CG6_FHC_FROP_DISABLE         (1 << 19)
-#define CG6_FHC_ROW_DISABLE          (1 << 18)
-#define CG6_FHC_SRC_DISABLE          (1 << 17)
-#define CG6_FHC_DST_DISABLE          (1 << 16)
-#define CG6_FHC_RESET                (1 << 15)
-#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
-#define CG6_FHC_RES_MASK             (3 << 11)
-#define CG6_FHC_1024                 (0 << 11)
-#define CG6_FHC_1152                 (1 << 11)
-#define CG6_FHC_1280                 (2 << 11)
-#define CG6_FHC_1600                 (3 << 11)
-#define CG6_FHC_CPU_MASK             (3 << 9)
-#define CG6_FHC_CPU_SPARC            (0 << 9)
-#define CG6_FHC_CPU_68020            (1 << 9)
-#define CG6_FHC_CPU_386              (2 << 9)
-#define CG6_FHC_TEST		     (1 << 8)
-#define CG6_FHC_TEST_X_SHIFT	     4
-#define CG6_FHC_TEST_X_MASK	     15
-#define CG6_FHC_TEST_Y_SHIFT	     0
-#define CG6_FHC_TEST_Y_MASK	     15
-
-/* FBC mode definitions */
-#define CG6_FBC_BLIT_IGNORE		0x00000000
-#define CG6_FBC_BLIT_NOSRC		0x00100000
-#define CG6_FBC_BLIT_SRC		0x00200000
-#define CG6_FBC_BLIT_ILLEGAL		0x00300000
-#define CG6_FBC_BLIT_MASK		0x00300000
-
-#define CG6_FBC_VBLANK			0x00080000
-
-#define CG6_FBC_MODE_IGNORE		0x00000000
-#define CG6_FBC_MODE_COLOR8		0x00020000
-#define CG6_FBC_MODE_COLOR1		0x00040000
-#define CG6_FBC_MODE_HRMONO		0x00060000
-#define CG6_FBC_MODE_MASK		0x00060000
-
-#define CG6_FBC_DRAW_IGNORE		0x00000000
-#define CG6_FBC_DRAW_RENDER		0x00008000
-#define CG6_FBC_DRAW_PICK		0x00010000
-#define CG6_FBC_DRAW_ILLEGAL		0x00018000
-#define CG6_FBC_DRAW_MASK		0x00018000
-
-#define CG6_FBC_BWRITE0_IGNORE		0x00000000
-#define CG6_FBC_BWRITE0_ENABLE		0x00002000
-#define CG6_FBC_BWRITE0_DISABLE		0x00004000
-#define CG6_FBC_BWRITE0_ILLEGAL		0x00006000
-#define CG6_FBC_BWRITE0_MASK		0x00006000
-
-#define CG6_FBC_BWRITE1_IGNORE		0x00000000
-#define CG6_FBC_BWRITE1_ENABLE		0x00000800
-#define CG6_FBC_BWRITE1_DISABLE		0x00001000
-#define CG6_FBC_BWRITE1_ILLEGAL		0x00001800
-#define CG6_FBC_BWRITE1_MASK		0x00001800
-
-#define CG6_FBC_BREAD_IGNORE		0x00000000
-#define CG6_FBC_BREAD_0			0x00000200
-#define CG6_FBC_BREAD_1			0x00000400
-#define CG6_FBC_BREAD_ILLEGAL		0x00000600
-#define CG6_FBC_BREAD_MASK		0x00000600
-
-#define CG6_FBC_BDISP_IGNORE		0x00000000
-#define CG6_FBC_BDISP_0			0x00000080
-#define CG6_FBC_BDISP_1			0x00000100
-#define CG6_FBC_BDISP_ILLEGAL		0x00000180
-#define CG6_FBC_BDISP_MASK		0x00000180
-
-#define CG6_FBC_INDEX_MOD		0x00000040
-#define CG6_FBC_INDEX_MASK		0x00000030
-
-/* THC definitions */
-#define CG6_THC_MISC_REV_SHIFT       16
-#define CG6_THC_MISC_REV_MASK        15
-#define CG6_THC_MISC_RESET           (1 << 12)
-#define CG6_THC_MISC_VIDEO           (1 << 10)
-#define CG6_THC_MISC_SYNC            (1 << 9)
-#define CG6_THC_MISC_VSYNC           (1 << 8)
-#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
-#define CG6_THC_MISC_CURS_RES        (1 << 6)
-#define CG6_THC_MISC_INT_ENAB        (1 << 5)
-#define CG6_THC_MISC_INT             (1 << 4)
-#define CG6_THC_MISC_INIT            0x9f
-
-MODULE_LICENSE("GPL");
-
-/* The contents are unknown */
-struct cg6_tec {
-	volatile int tec_matrix;
-	volatile int tec_clip;
-	volatile int tec_vdc;
-};
-
-struct cg6_thc {
-        uint thc_pad0[512];
-	volatile uint thc_hs;		/* hsync timing */
-	volatile uint thc_hsdvs;
-	volatile uint thc_hd;
-	volatile uint thc_vs;		/* vsync timing */
-	volatile uint thc_vd;
-	volatile uint thc_refresh;
-	volatile uint thc_misc;
-	uint thc_pad1[56];
-	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
-	volatile uint thc_cursmask[32];	/* cursor mask bits */
-	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
-};
-
-struct cg6_fbc {
-	u32		xxx0[1];
-	volatile u32	mode;
-	volatile u32	clip;
-	u32		xxx1[1];	    
-	volatile u32	s;
-	volatile u32	draw;
-	volatile u32	blit;
-	volatile u32	font;
-	u32		xxx2[24];
-	volatile u32	x0, y0, z0, color0;
-	volatile u32	x1, y1, z1, color1;
-	volatile u32	x2, y2, z2, color2;
-	volatile u32	x3, y3, z3, color3;
-	volatile u32	offx, offy;
-	u32		xxx3[2];
-	volatile u32	incx, incy;
-	u32		xxx4[2];
-	volatile u32	clipminx, clipminy;
-	u32		xxx5[2];
-	volatile u32	clipmaxx, clipmaxy;
-	u32		xxx6[2];
-	volatile u32	fg;
-	volatile u32	bg;
-	volatile u32	alu;
-	volatile u32	pm;
-	volatile u32	pixelm;
-	u32		xxx7[2];
-	volatile u32	patalign;
-	volatile u32	pattern[8];
-	u32		xxx8[432];
-	volatile u32	apointx, apointy, apointz;
-	u32		xxx9[1];
-	volatile u32	rpointx, rpointy, rpointz;
-	u32		xxx10[5];
-	volatile u32	pointr, pointg, pointb, pointa;
-	volatile u32	alinex, aliney, alinez;
-	u32		xxx11[1];
-	volatile u32	rlinex, rliney, rlinez;
-	u32		xxx12[5];
-	volatile u32	liner, lineg, lineb, linea;
-	volatile u32	atrix, atriy, atriz;
-	u32		xxx13[1];
-	volatile u32	rtrix, rtriy, rtriz;
-	u32		xxx14[5];
-	volatile u32	trir, trig, trib, tria;
-	volatile u32	aquadx, aquady, aquadz;
-	u32		xxx15[1];
-	volatile u32	rquadx, rquady, rquadz;
-	u32		xxx16[5];
-	volatile u32	quadr, quadg, quadb, quada;
-	volatile u32	arectx, arecty, arectz;
-	u32		xxx17[1];
-	volatile u32	rrectx, rrecty, rrectz;
-	u32		xxx18[5];
-	volatile u32	rectr, rectg, rectb, recta;
-};
-
-static struct sbus_mmap_map cg6_mmap_map[] = {
-	{ CG6_FBC,		CG6_FBC_OFFSET,		PAGE_SIZE 		},
-	{ CG6_TEC,		CG6_TEC_OFFSET,		PAGE_SIZE 		},
-	{ CG6_BTREGS,		CG6_BROOKTREE_OFFSET,	PAGE_SIZE 		},
-	{ CG6_FHC,		CG6_FHC_OFFSET,		PAGE_SIZE 		},
-	{ CG6_THC,		CG6_THC_OFFSET,		PAGE_SIZE 		},
-	{ CG6_ROM,		CG6_ROM_OFFSET,		0x10000   		},
-	{ CG6_RAM,		CG6_RAM_OFFSET,		SBUS_MMAP_FBSIZE(1)  	},
-	{ CG6_DHC,		CG6_DHC_OFFSET,		0x40000   		},
-	{ 0,			0,			0	  		}
-};
-
-static void cg6_setup(struct display *p)
-{
-	p->next_line = p->fb_info->var.xres_virtual;
-	p->next_plane = 0;
-}
-
-static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx,
-		      int height, int width)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	unsigned long flags;
-	int x, y, w, h;
-	int i;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	sbus_writel(attr_bgcol_ec(p,conp), &fbc->fg);
-	sbus_writel(attr_bgcol_ec(p,conp), &fbc->bg);
-	sbus_writel(~0, &fbc->pixelm);
-	sbus_writel(0xea80ff00, &fbc->alu);
-	sbus_writel(0, &fbc->s);
-	sbus_writel(0, &fbc->clip);
-	sbus_writel(~0, &fbc->pm);
-
-        if (fontheightlog(p)) {
-		y = sy << fontheightlog(p); h = height << fontheightlog(p);
-	} else {
-		y = sy * fontheight(p); h = height * fontheight(p);
-	}
-	if (fontwidthlog(p)) {
-		x = sx << fontwidthlog(p); w = width << fontwidthlog(p);
-	} else {
-		x = sx * fontwidth(p); w = width * fontwidth(p);
-	}
-	sbus_writel(y + fb->y_margin, &fbc->arecty);
-	sbus_writel(x + fb->x_margin, &fbc->arectx);
-	sbus_writel(y + fb->y_margin + h, &fbc->arecty);
-	sbus_writel(x + fb->x_margin + w, &fbc->arectx);
-	do {
-		i = sbus_readl(&fbc->draw);
-	} while (i < 0 && (i & 0x20000000));
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
-		     int count, unsigned short *boxes)
-{
-	int i;
-	register struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	sbus_writel(attr_bgcol(p,s), &fbc->fg);
-	sbus_writel(attr_bgcol(p,s), &fbc->bg);
-	sbus_writel(~0, &fbc->pixelm);
-	sbus_writel(0xea80ff00, &fbc->alu);
-	sbus_writel(0, &fbc->s);
-	sbus_writel(0, &fbc->clip);
-	sbus_writel(~0, &fbc->pm);
-	while (count-- > 0) {
-		sbus_writel(boxes[1], &fbc->arecty);
-		sbus_writel(boxes[0], &fbc->arectx);
-		sbus_writel(boxes[3], &fbc->arecty);
-		sbus_writel(boxes[2], &fbc->arectx);
-		boxes += 4;
-		do {
-			i = sbus_readl(&fbc->draw);
-		} while (i < 0 && (i & 0x20000000));
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	unsigned long flags;
-	int i, x, y;
-	u8 *fd;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	if (fontheightlog(p)) {
-		y = fb->y_margin + (yy << fontheightlog(p));
-		i = ((c & p->charmask) << fontheightlog(p));
-	} else {
-		y = fb->y_margin + (yy * fontheight(p));
-		i = (c & p->charmask) * fontheight(p);
-	}
-	if (fontwidth(p) <= 8)
-		fd = p->fontdata + i;
-	else
-		fd = p->fontdata + (i << 1);
-	if (fontwidthlog(p))
-		x = fb->x_margin + (xx << fontwidthlog(p));
-	else
-		x = fb->x_margin + (xx * fontwidth(p));
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	sbus_writel(attr_fgcol(p,c), &fbc->fg);
-	sbus_writel(attr_bgcol(p,c), &fbc->bg);
-	sbus_writel(0x140000, &fbc->mode);
-	sbus_writel(0xe880fc30, &fbc->alu);
-	sbus_writel(~0, &fbc->pixelm);
-	sbus_writel(0, &fbc->s);
-	sbus_writel(0, &fbc->clip);
-	sbus_writel(0xff, &fbc->pm);
-	sbus_writel(0, &fbc->incx);
-	sbus_writel(1, &fbc->incy);
-	sbus_writel(x, &fbc->x0);
-	sbus_writel(x + fontwidth(p) - 1, &fbc->x1);
-	sbus_writel(y, &fbc->y0);
-	if (fontwidth(p) <= 8) {
-		for (i = 0; i < fontheight(p); i++) {
-			u32 val = *fd++ << 24;
-			sbus_writel(val, &fbc->font);
-		}
-	} else {
-		for (i = 0; i < fontheight(p); i++) {
-			u32 val = *(u16 *)fd << 16;
-
-			sbus_writel(val, &fbc->font);
-			fd += 2;
-		}
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
-		      int count, int yy, int xx)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	unsigned long flags;
-	int i, x, y;
-	u8 *fd1, *fd2, *fd3, *fd4;
-	u16 c;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	c = scr_readw(s);
-	sbus_writel(attr_fgcol(p, c), &fbc->fg);
-	sbus_writel(attr_bgcol(p, c), &fbc->bg);
-	sbus_writel(0x140000, &fbc->mode);
-	sbus_writel(0xe880fc30, &fbc->alu);
-	sbus_writel(~0, &fbc->pixelm);
-	sbus_writel(0, &fbc->s);
-	sbus_writel(0, &fbc->clip);
-	sbus_writel(0xff, &fbc->pm);
-	x = fb->x_margin;
-	y = fb->y_margin;
-	if (fontwidthlog(p))
-		x += (xx << fontwidthlog(p));
-	else
-		x += xx * fontwidth(p);
-	if (fontheightlog(p))
-		y += (yy << fontheightlog(p));
-	else
-		y += (yy * fontheight(p));
-	if (fontwidth(p) <= 8) {
-		while (count >= 4) {
-			count -= 4;
-			sbus_writel(0, &fbc->incx);
-			sbus_writel(1, &fbc->incy);
-			sbus_writel(x, &fbc->x0);
-			sbus_writel((x += 4 * fontwidth(p)) - 1, &fbc->x1);
-			sbus_writel(y, &fbc->y0);
-			if (fontheightlog(p)) {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-			} else {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-			}
-			if (fontwidth(p) == 8) {
-				for (i = 0; i < fontheight(p); i++) {
-					u32 val = ((u32)*fd4++) |
-						((((u32)*fd3++) |
-						  ((((u32)*fd2++) |
-						    (((u32)*fd1++)
-						     << 8)) << 8)) << 8);
-					sbus_writel(val, &fbc->font);
-				}
-			} else {
-				for (i = 0; i < fontheight(p); i++) {
-					u32 val = (((u32)*fd4++) |
-						   ((((u32)*fd3++) |
-						     ((((u32)*fd2++) |
-						       (((u32)*fd1++) 
-							<< fontwidth(p))) <<
-						      fontwidth(p))) <<
-						    fontwidth(p))) <<
-						(24 - 3 * fontwidth(p));
-					sbus_writel(val, &fbc->font);
-				}
-			}
-		}
-	} else {
-		while (count >= 2) {
-			count -= 2;
-			sbus_writel(0, &fbc->incx);
-			sbus_writel(1, &fbc->incy);
-			sbus_writel(x, &fbc->x0);
-			sbus_writel((x += 2 * fontwidth(p)) - 1, &fbc->x1);
-			sbus_writel(y, &fbc->y0);
-			if (fontheightlog(p)) {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
-			} else {
-				fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
-				fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
-			}
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) |
-					   ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
-				sbus_writel(val, &fbc->font);
-				fd1 += 2; fd2 += 2;
-			}
-		}
-	}
-	while (count) {
-		count--;
-		sbus_writel(0, &fbc->incx);
-		sbus_writel(1, &fbc->incy);
-		sbus_writel(x, &fbc->x0);
-		sbus_writel((x += fontwidth(p)) - 1, &fbc->x1);
-		sbus_writel(y, &fbc->y0);
-		if (fontheightlog(p))
-			i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-		else
-			i = ((scr_readw(s++) & p->charmask) * fontheight(p));
-		if (fontwidth(p) <= 8) {
-			fd1 = p->fontdata + i;
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = *fd1++ << 24;
-				sbus_writel(val, &fbc->font);
-			}
-		} else {
-			fd1 = p->fontdata + (i << 1);
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = *(u16 *)fd1 << 16;
-				sbus_writel(val, &fbc->font);
-				fd1 += 2;
-			}
-		}
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_revc(struct display *p, int xx, int yy)
-{
-	/* Not used if hw cursor */
-}
-
-static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
-	struct bt_regs *bt = fb->s.cg6.bt;
-	unsigned long flags;
-	int i;
-                
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(index << 24, &bt->addr);
-	for (i = index; count--; i++){
-		sbus_writel(fb->color_map CM(i,0) << 24,
-			    &bt->color_map);
-		sbus_writel(fb->color_map CM(i,1) << 24,
-			    &bt->color_map);
-		sbus_writel(fb->color_map CM(i,2) << 24,
-			    &bt->color_map);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_restore_palette (struct fb_info_sbusfb *fb)
-{
-	struct bt_regs *bt = fb->s.cg6.bt;
-	unsigned long flags;
-                
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(0, &bt->addr);
-	sbus_writel(0xffffffff, &bt->color_map);
-	sbus_writel(0xffffffff, &bt->color_map);
-	sbus_writel(0xffffffff, &bt->color_map);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static struct display_switch cg6_dispsw __initdata = {
-	.setup =	cg6_setup,
-	.bmove =	fbcon_redraw_bmove,
-	.clear =	cg6_clear,
-	.putc =		cg6_putc,
-	.putcs =	cg6_putcs,
-	.revc =		cg6_revc, 
-	.fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
-};
-
-static void cg6_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
-        struct bt_regs *bt = fb->s.cg6.bt;
-	unsigned long flags;
-        
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(1 << 24, &bt->addr);
-	sbus_writel(red[0] << 24, &bt->cursor);
-	sbus_writel(green[0] << 24, &bt->cursor);
-	sbus_writel(blue[0] << 24, &bt->cursor);
-	sbus_writel(3 << 24, &bt->addr);
-	sbus_writel(red[1] << 24, &bt->cursor);
-	sbus_writel(green[1] << 24, &bt->cursor);
-	sbus_writel(blue[1] << 24, &bt->cursor);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void cg6_setcurshape (struct fb_info_sbusfb *fb)
-{
-	struct cg6_thc *thc = fb->s.cg6.thc;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	for (i = 0; i < 32; i++) {
-		sbus_writel(fb->cursor.bits[0][i],
-			    &thc->thc_cursmask [i]);
-		sbus_writel(fb->cursor.bits[1][i],
-			    &thc->thc_cursbits [i]);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void cg6_setcursor (struct fb_info_sbusfb *fb)
-{
-	unsigned int v;
-	unsigned long flags;
-	struct cg_cursor *c = &fb->cursor;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	if (c->enable)
-		v = ((c->cpos.fbx - c->chot.fbx) << 16)
-		    |((c->cpos.fby - c->chot.fby) & 0xffff);
-	else
-		/* Magic constant to turn off the cursor */
-		v = ((65536-32) << 16) | (65536-32);
-	sbus_writel(v, &fb->s.cg6.thc->thc_cursxy);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int cg6_blank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
-	tmp &= ~CG6_THC_MISC_VIDEO;
-	sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static int cg6_unblank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
-	tmp |= CG6_THC_MISC_VIDEO;
-	sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static void cg6_reset (struct fb_info_sbusfb *fb)
-{
-	unsigned int rev, conf;
-	struct cg6_tec *tec = fb->s.cg6.tec;
-	struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	unsigned long flags;
-	u32 mode, tmp;
-	int i;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-
-	/* Turn off stuff in the Transform Engine. */
-	sbus_writel(0, &tec->tec_matrix);
-	sbus_writel(0, &tec->tec_clip);
-	sbus_writel(0, &tec->tec_vdc);
-
-	/* Take care of bugs in old revisions. */
-	rev = (sbus_readl(fb->s.cg6.fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
-	if (rev < 5) {
-		conf = (sbus_readl(fb->s.cg6.fhc) & CG6_FHC_RES_MASK) |
-			CG6_FHC_CPU_68020 | CG6_FHC_TEST |
-			(11 << CG6_FHC_TEST_X_SHIFT) |
-			(11 << CG6_FHC_TEST_Y_SHIFT);
-		if (rev < 2)
-			conf |= CG6_FHC_DST_DISABLE;
-		sbus_writel(conf, fb->s.cg6.fhc);
-	}
-
-	/* Set things in the FBC. Bad things appear to happen if we do
-	 * back to back store/loads on the mode register, so copy it
-	 * out instead. */
-	mode = sbus_readl(&fbc->mode);
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
-		       CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
-		       CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
-		       CG6_FBC_BDISP_MASK);
-	mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
-		      CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
-		      CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
-		      CG6_FBC_BDISP_0);
-	sbus_writel(mode, &fbc->mode);
-
-	sbus_writel(0, &fbc->clip);
-	sbus_writel(0, &fbc->offx);
-	sbus_writel(0, &fbc->offy);
-	sbus_writel(0, &fbc->clipminx);
-	sbus_writel(0, &fbc->clipminy);
-	sbus_writel(fb->type.fb_width - 1, &fbc->clipmaxx);
-	sbus_writel(fb->type.fb_height - 1, &fbc->clipmaxy);
-
-	/* Enable cursor in Brooktree DAC. */
-	sbus_writel(0x06 << 24, &fb->s.cg6.bt->addr);
-	tmp = sbus_readl(&fb->s.cg6.bt->control);
-	tmp |= 0x03 << 24;
-	sbus_writel(tmp, &fb->s.cg6.bt->control);
-
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void cg6_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
-	fb->info.screen_base += (y_margin - fb->y_margin) *
-		fb->info.fix.line_length + (x_margin - fb->x_margin);
-}
-
-static int __init cg6_rasterimg (struct fb_info *info, int start)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-	register struct cg6_fbc *fbc = fb->s.cg6.fbc;
-	int i;
-	
-	do {
-		i = sbus_readl(&fbc->s);
-	} while (i & 0x10000000);
-	return 0;
-}
-
-static char idstring[70] __initdata = { 0 };
-
-char __init *cgsixfb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct fb_var_screeninfo *var = &fb->info.var;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	struct sbus_dev *sdev = fb->sbdp;
-	unsigned long phys = sdev->reg_addrs[0].phys_addr;
-	u32 conf;
-	char *p;
-	char *cardtype;
-	struct bt_regs *bt;
-	struct fb_ops *fbops;
-
-	fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
-	if (fbops == NULL)
-		return NULL;
-	
-	*fbops = *fb->info.fbops;
-	fbops->fb_rasterimg = cg6_rasterimg;
-	fb->info.fbops = fbops;
-	
-	if (prom_getbool (fb->prom_node, "dblbuf")) {
-		type->fb_size *= 4;
-		fix->smem_len *= 4;
-	}
-
-	fix->line_length = fb->info.var.xres_virtual;
-	fix->accel = FB_ACCEL_SUN_CGSIX;
-	
-	var->accel_flags = FB_ACCELF_TEXT;
-	
-	disp->scrollmode = SCROLL_YREDRAW;
-	if (!fb->info.screen_base) {
-		fb->info.screen_base = (char *)
-			sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
-				     type->fb_size, "cgsix ram");
-	}
-	fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
-	fb->s.cg6.fbc = (struct cg6_fbc *)
-		sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
-			     4096, "cgsix fbc");
-	fb->s.cg6.tec = (struct cg6_tec *)
-		sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
-			     sizeof(struct cg6_tec), "cgsix tec");
-	fb->s.cg6.thc = (struct cg6_thc *)
-		sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
-			     sizeof(struct cg6_thc), "cgsix thc");
-	fb->s.cg6.bt = bt = (struct bt_regs *)
-		sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
-			     sizeof(struct bt_regs), "cgsix dac");
-	fb->s.cg6.fhc = (u32 *)
-		sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
-			     sizeof(u32), "cgsix fhc");
-#if 0
-	prom_printf("CG6: RES[%016lx:%016lx:%016lx]\n",
-		    sdev->resource[0].start,
-		    sdev->resource[0].end,
-		    sdev->resource[0].flags);
-	prom_printf("CG6: fbc(%p) tec(%p) thc(%p) bt(%p) fhc(%p)\n",
-		    fb->s.cg6.fbc,
-		    fb->s.cg6.tec,
-		    fb->s.cg6.thc,
-		    fb->s.cg6.bt,
-		    fb->s.cg6.fhc);
-	prom_halt();
-#endif
-	fb->dispsw = cg6_dispsw;
-
-	fb->margins = cg6_margins;
-	fb->loadcmap = cg6_loadcmap;
-	fb->setcursor = cg6_setcursor;
-	fb->setcursormap = cg6_setcursormap;
-	fb->setcurshape = cg6_setcurshape;
-	fb->restore_palette = cg6_restore_palette;
-	fb->fill = cg6_fill;
-	fb->blank = cg6_blank;
-	fb->unblank = cg6_unblank;
-	fb->reset = cg6_reset;
-	
-	fb->physbase = phys;
-	fb->mmap_map = cg6_mmap_map;
-	
-	/* Initialize Brooktree DAC */
-	sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
-	sbus_writel(0xff << 24, &bt->control);
-	sbus_writel(0x05 << 24, &bt->addr);
-	sbus_writel(0x00 << 24, &bt->control);
-	sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
-	sbus_writel(0x73 << 24, &bt->control);
-	sbus_writel(0x07 << 24, &bt->addr);
-	sbus_writel(0x00 << 24, &bt->control);
-	
-	conf = sbus_readl(fb->s.cg6.fhc);
-	switch(conf & CG6_FHC_CPU_MASK) {
-	case CG6_FHC_CPU_SPARC: p = "sparc"; break;
-	case CG6_FHC_CPU_68020: p = "68020"; break;
-	default: p = "i386"; break;
-	}
-
-	if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
-		if (fix->smem_len <= 0x100000) {
-			cardtype = "TGX";
-		} else {
-			cardtype = "TGX+";
-		}
-	} else {
-		if (fix->smem_len <= 0x100000) {
-			cardtype = "GX";
-		} else {
-			cardtype = "GX+";
-		}
-	}
-	                                                                        
-	sprintf(idstring, 
-#ifdef __sparc_v9__
-		    "cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]", phys,
-#else	
-		    "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]",
-		    fb->iospace, phys, 
-#endif
-		    ((sbus_readl(&fb->s.cg6.thc->thc_misc) >> CG6_THC_MISC_REV_SHIFT) &
-		     CG6_THC_MISC_REV_MASK),
-		    p, (conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK, cardtype);
-
-	sprintf(fb->info.modename, "CGsix [%s]", cardtype);
-	sprintf(fix->id, "CGsix [%s]", cardtype);
-		    
-	cg6_reset(fb);
-		    
-	return idstring;
-}
diff -urN linux-2.5.63-bk6/drivers/video/cgthreefb.c linux-2.5.63-bk7/drivers/video/cgthreefb.c
--- linux-2.5.63-bk6/drivers/video/cgthreefb.c	Mon Feb 24 11:05:42 2003
+++ linux-2.5.63-bk7/drivers/video/cgthreefb.c	Wed Dec 31 16:00:00 1969
@@ -1,286 +0,0 @@
-/* $Id: cgthreefb.c,v 1.11 2001/09/19 00:04:33 davem Exp $
- * cgthreefb.c: CGthree frame buffer driver
- *
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-
-#include <video/fbcon-cfb8.h>
-
-/* Control Register Constants */
-#define CG3_CR_ENABLE_INTS      0x80
-#define CG3_CR_ENABLE_VIDEO     0x40
-#define CG3_CR_ENABLE_TIMING    0x20
-#define CG3_CR_ENABLE_CURCMP    0x10
-#define CG3_CR_XTAL_MASK        0x0c
-#define CG3_CR_DIVISOR_MASK     0x03
-
-/* Status Register Constants */
-#define CG3_SR_PENDING_INT      0x80
-#define CG3_SR_RES_MASK         0x70
-#define CG3_SR_1152_900_76_A    0x40
-#define CG3_SR_1152_900_76_B    0x60
-#define CG3_SR_ID_MASK          0x0f
-#define CG3_SR_ID_COLOR         0x01
-#define CG3_SR_ID_MONO          0x02
-#define CG3_SR_ID_MONO_ECL      0x03
-
-MODULE_LICENSE("GPL");
-
-enum cg3_type {
-	CG3_AT_66HZ = 0,
-	CG3_AT_76HZ,
-	CG3_RDI
-};
-
-struct cg3_regs {
-	struct bt_regs	cmap;
-	volatile u8	control;
-	volatile u8	status;
-	volatile u8	cursor_start;
-	volatile u8	cursor_end;
-	volatile u8	h_blank_start;
-	volatile u8	h_blank_end;
-	volatile u8	h_sync_start;
-	volatile u8	h_sync_end;
-	volatile u8	comp_sync_end;
-	volatile u8	v_blank_start_high;
-	volatile u8	v_blank_start_low;
-	volatile u8	v_blank_end;
-	volatile u8	v_sync_start;
-	volatile u8	v_sync_end;
-	volatile u8	xfer_holdoff_start;
-	volatile u8	xfer_holdoff_end;
-};
-
-/* Offset of interesting structures in the OBIO space */
-#define CG3_REGS_OFFSET	     0x400000UL
-#define CG3_RAM_OFFSET	     0x800000UL
-
-static struct sbus_mmap_map cg3_mmap_map[] = {
-	{ CG3_MMAP_OFFSET,	CG3_RAM_OFFSET,		SBUS_MMAP_FBSIZE(1) },
-	{ 0,			0,			0		    }
-};
-
-/* The cg3 palette is loaded with 4 color values at each time  */
-/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
-
-#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
-#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
-
-static void cg3_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
-	struct bt_regs *bt = &fb->s.cg3.regs->cmap;
-	unsigned long flags;
-	u32 *i;
-	volatile u8 *regp;
-	int steps;
-	        
-	spin_lock_irqsave(&fb->lock, flags);
-
-	i = (((u32 *)fb->color_map) + D4M3(index));
-	steps = D4M3(index+count-1) - D4M3(index)+3;
-	                        
-	regp = (volatile u8 *)&bt->addr;
-	sbus_writeb(D4M4(index), regp);
-	while (steps--) {
-		u32 val = *i++;
-		sbus_writel(val, &bt->color_map);
-	}
-
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int cg3_blank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u8 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readb(&fb->s.cg3.regs->control);
-	tmp &= ~CG3_CR_ENABLE_VIDEO;
-	sbus_writeb(tmp, &fb->s.cg3.regs->control);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static int cg3_unblank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u8 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readb(&fb->s.cg3.regs->control);
-	tmp |= CG3_CR_ENABLE_VIDEO;
-	sbus_writeb(tmp, &fb->s.cg3.regs->control);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p,
-			 int x_margin, int y_margin)
-{
-	fb->info.screen_base += (y_margin - fb->y_margin) *
-		fb->info.fix.line_length + (x_margin - fb->x_margin);
-}
-
-static u8 cg3regvals_66hz[] __initdata = {	/* 1152 x 900, 66 Hz */
-	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
-	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
-	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x20,	0
-};
-
-static u8 cg3regvals_76hz[] __initdata = {	/* 1152 x 900, 76 Hz */
-	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
-	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
-	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x24,	0
-};
-
-static u8 cg3regvals_rdi[] __initdata = {	/* 640 x 480, cgRDI */
-	0x14, 0x70,	0x15, 0x20,	0x16, 0x08,	0x17, 0x10,
-	0x18, 0x06,	0x19, 0x02,	0x1a, 0x31,	0x1b, 0x51,
-	0x1c, 0x06,	0x1d, 0x0c,	0x1e, 0xff,	0x1f, 0x01,
-	0x10, 0x22,	0
-};
-
-static u8 *cg3_regvals[] __initdata = {
-	cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
-};
-
-static u_char cg3_dacvals[] __initdata = {
-	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0
-};
-
-static char idstring[60] __initdata = { 0 };
-
-char __init *cgthreefb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	struct sbus_dev *sdev = fb->sbdp;
-	unsigned long phys = sdev->reg_addrs[0].phys_addr;
-	int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
-
-#ifndef FBCON_HAS_CFB8
-	return NULL;
-#endif
-
-	if (!fb->s.cg3.regs) {
-		fb->s.cg3.regs = (struct cg3_regs *)
-			sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
-				     sizeof(struct cg3_regs), "cg3 regs");
-		if (cgRDI) {
-			char buffer[40];
-			char *p;
-			int ww, hh;
-		
-			*buffer = 0;
-			prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer));
-			if (*buffer) {
-				ww = simple_strtoul (buffer, &p, 10);
-				if (ww && *p == 'x') {
-					hh = simple_strtoul (p + 1, &p, 10);
-					if (hh && *p == '-') {
-						if (type->fb_width != ww || type->fb_height != hh) {
-							type->fb_width = ww;
-							type->fb_height = hh;
-							return SBUSFBINIT_SIZECHANGE;
-						}
-					}
-				}
-			}
-		}
-	}
-
-	strcpy(fb->info.modename, "CGthree");
-	strcpy(fix->id, "CGthree");
-	fix->line_length = fb->info.var.xres_virtual;
-	fix->accel = FB_ACCEL_SUN_CGTHREE;
-	
-	disp->scrollmode = SCROLL_YREDRAW;
-	if (!fb->info.screen_base) {
-		fb->info.screen_base = (char *)
-			sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
-				     type->fb_size, "cg3 ram");
-	}
-	fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
-	fb->dispsw = fbcon_cfb8;
-
-	fb->margins = cg3_margins;
-	fb->loadcmap = cg3_loadcmap;
-	fb->blank = cg3_blank;
-	fb->unblank = cg3_unblank;
-	
-	fb->physbase = phys;
-	fb->mmap_map = cg3_mmap_map;
-	
-#ifdef __sparc_v9__	
-	sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
-#else
-	sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys);
-#endif
-	
-	if (!prom_getbool(fb->prom_node, "width")) {
-		/* Ugh, broken PROM didn't initialize us.
-		 * Let's deal with this ourselves.
-		 */
-		enum cg3_type type;
-		u8 *p;
-
-		if (cgRDI)
-			type = CG3_RDI;
-		else {
-			u8 status = sbus_readb(&fb->s.cg3.regs->status), mon;
-			if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
-				mon = status & CG3_SR_RES_MASK;
-				if (mon == CG3_SR_1152_900_76_A ||
-				    mon == CG3_SR_1152_900_76_B)
-					type = CG3_AT_76HZ;
-				else
-					type = CG3_AT_66HZ;
-			} else {
-				prom_printf("cgthree: can't handle SR %02x\n",
-					    status);
-				prom_halt();
-				return NULL; /* fool gcc. */
-			}
-		}
-
-		for (p = cg3_regvals[type]; *p; p += 2) {
-			u8 *regp = &((u8 *)fb->s.cg3.regs)[p[0]];
-			sbus_writeb(p[1], regp);
-		}
-		for (p = cg3_dacvals; *p; p += 2) {
-			volatile u8 *regp;
-
-			regp = (volatile u8 *)&fb->s.cg3.regs->cmap.addr;
-			sbus_writeb(p[0], regp);
-			regp = (volatile u8 *)&fb->s.cg3.regs->cmap.control;
-			sbus_writeb(p[1], regp);
-		}
-	}
-
-	return idstring;
-}
diff -urN linux-2.5.63-bk6/drivers/video/creatorfb.c linux-2.5.63-bk7/drivers/video/creatorfb.c
--- linux-2.5.63-bk6/drivers/video/creatorfb.c	Mon Feb 24 11:05:06 2003
+++ linux-2.5.63-bk7/drivers/video/creatorfb.c	Wed Dec 31 16:00:00 1969
@@ -1,928 +0,0 @@
-/* $Id: creatorfb.c,v 1.37 2001/10/16 05:44:44 davem Exp $
- * creatorfb.c: Creator/Creator3D frame buffer driver
- *
- * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-
-#include <asm/upa.h>
-
-#define	FFB_SFB8R_VOFF		0x00000000
-#define	FFB_SFB8G_VOFF		0x00400000
-#define	FFB_SFB8B_VOFF		0x00800000
-#define	FFB_SFB8X_VOFF		0x00c00000
-#define	FFB_SFB32_VOFF		0x01000000
-#define	FFB_SFB64_VOFF		0x02000000
-#define	FFB_FBC_REGS_VOFF	0x04000000
-#define	FFB_BM_FBC_REGS_VOFF	0x04002000
-#define	FFB_DFB8R_VOFF		0x04004000
-#define	FFB_DFB8G_VOFF		0x04404000
-#define	FFB_DFB8B_VOFF		0x04804000
-#define	FFB_DFB8X_VOFF		0x04c04000
-#define	FFB_DFB24_VOFF		0x05004000
-#define	FFB_DFB32_VOFF		0x06004000
-#define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
-#define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
-#define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
-#define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
-#define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
-#define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
-#define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
-#define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
-#define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
-#define	FFB_FBC_KREGS_VOFF	0x0bc04000
-#define	FFB_DAC_VOFF		0x0bc06000
-#define	FFB_PROM_VOFF		0x0bc08000
-#define	FFB_EXP_VOFF		0x0bc18000
-
-#define	FFB_SFB8R_POFF		0x04000000UL
-#define	FFB_SFB8G_POFF		0x04400000UL
-#define	FFB_SFB8B_POFF		0x04800000UL
-#define	FFB_SFB8X_POFF		0x04c00000UL
-#define	FFB_SFB32_POFF		0x05000000UL
-#define	FFB_SFB64_POFF		0x06000000UL
-#define	FFB_FBC_REGS_POFF	0x00600000UL
-#define	FFB_BM_FBC_REGS_POFF	0x00600000UL
-#define	FFB_DFB8R_POFF		0x01000000UL
-#define	FFB_DFB8G_POFF		0x01400000UL
-#define	FFB_DFB8B_POFF		0x01800000UL
-#define	FFB_DFB8X_POFF		0x01c00000UL
-#define	FFB_DFB24_POFF		0x02000000UL
-#define	FFB_DFB32_POFF		0x03000000UL
-#define	FFB_FBC_KREGS_POFF	0x00610000UL
-#define	FFB_DAC_POFF		0x00400000UL
-#define	FFB_PROM_POFF		0x00000000UL
-#define	FFB_EXP_POFF		0x00200000UL
-#define FFB_DFB422A_POFF	0x09000000UL
-#define FFB_DFB422AD_POFF	0x09800000UL
-#define FFB_DFB24B_POFF		0x0a000000UL
-#define FFB_DFB422B_POFF	0x0b000000UL
-#define FFB_DFB422BD_POFF	0x0b800000UL
-#define FFB_SFB16Z_POFF		0x0c800000UL
-#define FFB_SFB8Z_POFF		0x0c000000UL
-#define FFB_SFB422_POFF		0x0d000000UL
-#define FFB_SFB422D_POFF	0x0d800000UL
-
-/* Draw operations */
-#define FFB_DRAWOP_DOT		0x00
-#define FFB_DRAWOP_AADOT	0x01
-#define FFB_DRAWOP_BRLINECAP	0x02
-#define FFB_DRAWOP_BRLINEOPEN	0x03
-#define FFB_DRAWOP_DDLINE	0x04
-#define FFB_DRAWOP_AALINE	0x05
-#define FFB_DRAWOP_TRIANGLE	0x06
-#define FFB_DRAWOP_POLYGON	0x07
-#define FFB_DRAWOP_RECTANGLE	0x08
-#define FFB_DRAWOP_FASTFILL	0x09
-#define FFB_DRAWOP_BCOPY	0x0a
-#define FFB_DRAWOP_VSCROLL	0x0b
-
-/* Pixel processor control */
-/* Force WID */
-#define FFB_PPC_FW_DISABLE	0x800000
-#define FFB_PPC_FW_ENABLE	0xc00000
-/* Auxiliary clip */
-#define FFB_PPC_ACE_DISABLE	0x040000
-#define FFB_PPC_ACE_AUX_SUB	0x080000
-#define FFB_PPC_ACE_AUX_ADD	0x0c0000
-/* Depth cue */
-#define FFB_PPC_DCE_DISABLE	0x020000
-#define FFB_PPC_DCE_ENABLE	0x030000
-/* Alpha blend */
-#define FFB_PPC_ABE_DISABLE	0x008000
-#define FFB_PPC_ABE_ENABLE	0x00c000
-/* View clip */
-#define FFB_PPC_VCE_DISABLE	0x001000
-#define FFB_PPC_VCE_2D		0x002000
-#define FFB_PPC_VCE_3D		0x003000
-/* Area pattern */
-#define FFB_PPC_APE_DISABLE	0x000800
-#define FFB_PPC_APE_ENABLE	0x000c00
-/* Transparent background */
-#define FFB_PPC_TBE_OPAQUE	0x000200
-#define FFB_PPC_TBE_TRANSPARENT	0x000300
-/* Z source */
-#define FFB_PPC_ZS_VAR		0x000080
-#define FFB_PPC_ZS_CONST	0x0000c0
-/* Y source */
-#define FFB_PPC_YS_VAR		0x000020
-#define FFB_PPC_YS_CONST	0x000030
-/* X source */
-#define FFB_PPC_XS_WID		0x000004
-#define FFB_PPC_XS_VAR		0x000008
-#define FFB_PPC_XS_CONST	0x00000c
-/* Color (BGR) source */
-#define FFB_PPC_CS_VAR		0x000002
-#define FFB_PPC_CS_CONST	0x000003
-
-#define FFB_ROP_NEW                  0x83
-
-#define FFB_UCSR_FIFO_MASK     0x00000fff
-#define FFB_UCSR_FB_BUSY       0x01000000
-#define FFB_UCSR_RP_BUSY       0x02000000
-#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
-#define FFB_UCSR_READ_ERR      0x40000000
-#define FFB_UCSR_FIFO_OVFL     0x80000000
-#define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
-
-struct ffb_fbc {
-	/* Next vertex registers */
-	u32		xxx1[3];
-	volatile u32	alpha;
-	volatile u32	red;
-	volatile u32	green;
-	volatile u32	blue;
-	volatile u32	depth;
-	volatile u32	y;
-	volatile u32	x;
-	u32		xxx2[2];
-	volatile u32	ryf;
-	volatile u32	rxf;
-	u32		xxx3[2];
-	
-	volatile u32	dmyf;
-	volatile u32	dmxf;
-	u32		xxx4[2];
-	volatile u32	ebyi;
-	volatile u32	ebxi;
-	u32		xxx5[2];
-	volatile u32	by;
-	volatile u32	bx;
-	u32		dy;
-	u32		dx;
-	volatile u32	bh;
-	volatile u32	bw;
-	u32		xxx6[2];
-	
-	u32		xxx7[32];
-	
-	/* Setup unit vertex state register */
-	volatile u32	suvtx;
-	u32		xxx8[63];
-	
-	/* Control registers */
-	volatile u32	ppc;
-	volatile u32	wid;
-	volatile u32	fg;
-	volatile u32	bg;
-	volatile u32	consty;
-	volatile u32	constz;
-	volatile u32	xclip;
-	volatile u32	dcss;
-	volatile u32	vclipmin;
-	volatile u32	vclipmax;
-	volatile u32	vclipzmin;
-	volatile u32	vclipzmax;
-	volatile u32	dcsf;
-	volatile u32	dcsb;
-	volatile u32	dczf;
-	volatile u32	dczb;
-	
-	u32		xxx9;
-	volatile u32	blendc;
-	volatile u32	blendc1;
-	volatile u32	blendc2;
-	volatile u32	fbramitc;
-	volatile u32	fbc;
-	volatile u32	rop;
-	volatile u32	cmp;
-	volatile u32	matchab;
-	volatile u32	matchc;
-	volatile u32	magnab;
-	volatile u32	magnc;
-	volatile u32	fbcfg0;
-	volatile u32	fbcfg1;
-	volatile u32	fbcfg2;
-	volatile u32	fbcfg3;
-	
-	u32		ppcfg;
-	volatile u32	pick;
-	volatile u32	fillmode;
-	volatile u32	fbramwac;
-	volatile u32	pmask;
-	volatile u32	xpmask;
-	volatile u32	ypmask;
-	volatile u32	zpmask;
-	volatile u32	clip0min;
-	volatile u32	clip0max;
-	volatile u32	clip1min;
-	volatile u32	clip1max;
-	volatile u32	clip2min;
-	volatile u32	clip2max;
-	volatile u32	clip3min;
-	volatile u32	clip3max;
-	
-	/* New 3dRAM III support regs */
-	volatile u32	rawblend2;
-	volatile u32	rawpreblend;
-	volatile u32	rawstencil;
-	volatile u32	rawstencilctl;
-	volatile u32	threedram1;
-	volatile u32	threedram2;
-	volatile u32	passin;
-	volatile u32	rawclrdepth;
-	volatile u32	rawpmask;
-	volatile u32	rawcsrc;
-	volatile u32	rawmatch;
-	volatile u32	rawmagn;
-	volatile u32	rawropblend;
-	volatile u32	rawcmp;
-	volatile u32	rawwac;
-	volatile u32	fbramid;
-	
-	volatile u32	drawop;
-	u32		xxx10[2];
-	volatile u32	fontlpat;
-	u32		xxx11;
-	volatile u32	fontxy;
-	volatile u32	fontw;
-	volatile u32	fontinc;
-	volatile u32	font;
-	u32		xxx12[3];
-	volatile u32	blend2;
-	volatile u32	preblend;
-	volatile u32	stencil;
-	volatile u32	stencilctl;
-
-	u32		xxx13[4];	
-	volatile u32	dcss1;
-	volatile u32	dcss2;
-	volatile u32	dcss3;
-	volatile u32	widpmask;
-	volatile u32	dcs2;
-	volatile u32	dcs3;
-	volatile u32	dcs4;
-	u32		xxx14;
-	volatile u32	dcd2;
-	volatile u32	dcd3;
-	volatile u32	dcd4;
-	u32		xxx15;
-	
-	volatile u32	pattern[32];
-	
-	u32		xxx16[256];
-	
-	volatile u32	devid;
-	u32		xxx17[63];
-	
-	volatile u32	ucsr;
-	u32		xxx18[31];
-	
-	volatile u32	mer;
-};
-
-static __inline__ void FFBFifo(struct fb_info_sbusfb *fb, int n)
-{
-	struct ffb_fbc *fbc;
-	int cache = fb->s.ffb.fifo_cache;
-
-	if (cache - n < 0) {
-		fbc = fb->s.ffb.fbc;
-		do {	cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
-		} while (cache - n < 0);
-	}
-	fb->s.ffb.fifo_cache = cache - n;
-}
-
-static __inline__ void FFBWait(struct ffb_fbc *ffb)
-{
-	int limit = 10000;
-
-	do {
-		if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
-			break;
-		if ((upa_readl(&ffb->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
-			upa_writel(FFB_UCSR_ALL_ERRORS, &ffb->ucsr);
-		}
-	} while(--limit > 0);
-}
-
-struct ffb_dac {
-	volatile u32	type;
-	volatile u32	value;
-	volatile u32	type2;
-	volatile u32	value2;
-};
-
-static struct sbus_mmap_map ffb_mmap_map[] = {
-	{ FFB_SFB8R_VOFF,	FFB_SFB8R_POFF,		0x0400000 },
-	{ FFB_SFB8G_VOFF,	FFB_SFB8G_POFF,		0x0400000 },
-	{ FFB_SFB8B_VOFF,	FFB_SFB8B_POFF,		0x0400000 },
-	{ FFB_SFB8X_VOFF,	FFB_SFB8X_POFF,		0x0400000 },
-	{ FFB_SFB32_VOFF,	FFB_SFB32_POFF,		0x1000000 },
-	{ FFB_SFB64_VOFF,	FFB_SFB64_POFF,		0x2000000 },
-	{ FFB_FBC_REGS_VOFF,	FFB_FBC_REGS_POFF,	0x0002000 },
-	{ FFB_BM_FBC_REGS_VOFF,	FFB_BM_FBC_REGS_POFF,	0x0002000 },
-	{ FFB_DFB8R_VOFF,	FFB_DFB8R_POFF,		0x0400000 },
-	{ FFB_DFB8G_VOFF,	FFB_DFB8G_POFF,		0x0400000 },
-	{ FFB_DFB8B_VOFF,	FFB_DFB8B_POFF,		0x0400000 },
-	{ FFB_DFB8X_VOFF,	FFB_DFB8X_POFF,		0x0400000 },
-	{ FFB_DFB24_VOFF,	FFB_DFB24_POFF,		0x1000000 },
-	{ FFB_DFB32_VOFF,	FFB_DFB32_POFF,		0x1000000 },
-	{ FFB_FBC_KREGS_VOFF,	FFB_FBC_KREGS_POFF,	0x0002000 },
-	{ FFB_DAC_VOFF,		FFB_DAC_POFF,		0x0002000 },
-	{ FFB_PROM_VOFF,	FFB_PROM_POFF,		0x0010000 },
-	{ FFB_EXP_VOFF,		FFB_EXP_POFF,		0x0002000 },
-	{ FFB_DFB422A_VOFF,	FFB_DFB422A_POFF,	0x0800000 },
-	{ FFB_DFB422AD_VOFF,	FFB_DFB422AD_POFF,	0x0800000 },
-	{ FFB_DFB24B_VOFF,	FFB_DFB24B_POFF,	0x1000000 },
-	{ FFB_DFB422B_VOFF,	FFB_DFB422B_POFF,	0x0800000 },
-	{ FFB_DFB422BD_VOFF,	FFB_DFB422BD_POFF,	0x0800000 },
-	{ FFB_SFB16Z_VOFF,	FFB_SFB16Z_POFF,	0x0800000 },
-	{ FFB_SFB8Z_VOFF,	FFB_SFB8Z_POFF,		0x0800000 },
-	{ FFB_SFB422_VOFF,	FFB_SFB422_POFF,	0x0800000 },
-	{ FFB_SFB422D_VOFF,	FFB_SFB422D_POFF,	0x0800000 },
-	{ 0,			0,			0	  }
-};
-
-static void ffb_setup(struct display *p)
-{
-	p->next_line = 8192;
-	p->next_plane = 0;
-}
-
-static void ffb_clear(struct vc_data *conp, struct display *p, int sy, int sx,
-		      int height, int width)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-	u64 yx, hw;
-	int fg;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	fg = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p,conp)];
-	if (fg != fb->s.ffb.fg_cache) {
-		FFBFifo(fb, 5);
-		upa_writel(fg, &fbc->fg);
-		fb->s.ffb.fg_cache = fg;
-	} else
-		FFBFifo(fb, 4);
-
-	if (fontheightlog(p)) {
-		yx = (u64)sy << (fontheightlog(p) + 32); hw = (u64)height << (fontheightlog(p) + 32);
-	} else {
-		yx = (u64)(sy * fontheight(p)) << 32; hw = (u64)(height * fontheight(p)) << 32;
-	}
-	if (fontwidthlog(p)) {
-		yx += sx << fontwidthlog(p); hw += width << fontwidthlog(p);
-	} else {
-		yx += sx * fontwidth(p); hw += width * fontwidth(p);
-	}
-	upa_writeq(yx + fb->s.ffb.yx_margin, &fbc->by);
-	upa_writeq(hw, &fbc->bh);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
-		     int count, unsigned short *boxes)
-{
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-	int fg;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	fg = ((u32 *)p->dispsw_data)[attr_bgcol(p,s)];
-	if (fg != fb->s.ffb.fg_cache) {
-		FFBFifo(fb, 1);
-		upa_writel(fg, &fbc->fg);
-		fb->s.ffb.fg_cache = fg;
-	}
-	while (count-- > 0) {
-		FFBFifo(fb, 4);
-		upa_writel(boxes[1], &fbc->by);
-		upa_writel(boxes[0], &fbc->bx);
-		upa_writel(boxes[3] - boxes[1], &fbc->bh);
-		upa_writel(boxes[2] - boxes[0], &fbc->bw);
-		boxes += 4;
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-	int i, xy;
-	u8 *fd;
-	u64 fgbg;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	if (fontheightlog(p)) {
-		xy = (yy << (16 + fontheightlog(p)));
-		i = ((c & p->charmask) << fontheightlog(p));
-	} else {
-		xy = ((yy * fontheight(p)) << 16);
-		i = (c & p->charmask) * fontheight(p);
-	}
-	if (fontwidth(p) <= 8)
-		fd = p->fontdata + i;
-	else
-		fd = p->fontdata + (i << 1);
-	if (fontwidthlog(p))
-		xy += (xx << fontwidthlog(p)) + fb->s.ffb.xy_margin;
-	else
-		xy += (xx * fontwidth(p)) + fb->s.ffb.xy_margin;
-	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p,c)])) << 32) |
-	       ((u32 *)p->dispsw_data)[attr_bgcol(p,c)];
-	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
-		FFBFifo(fb, 2);
-		upa_writeq(fgbg, &fbc->fg);
-		*(u64 *)&fb->s.ffb.fg_cache = fgbg;
-	}
-	FFBFifo(fb, 2 + fontheight(p));
-	upa_writel(xy, &fbc->fontxy);
-	upa_writel(fontwidth(p), &fbc->fontw);
-	if (fontwidth(p) <= 8) {
-		for (i = 0; i < fontheight(p); i++) {
-			u32 val = *fd++ << 24;
-
-			upa_writel(val, &fbc->font);
-		}
-	} else {
-		for (i = 0; i < fontheight(p); i++) {
-			u32 val = *(u16 *)fd << 16;
-
-			upa_writel(val, &fbc->font);
-			fd += 2;
-		}
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
-		      int count, int yy, int xx)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(p->fb_info);
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-	int i, xy;
-	u8 *fd1, *fd2, *fd3, *fd4;
-	u16 c;
-	u64 fgbg;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	c = scr_readw(s);
-	fgbg = (((u64)(((u32 *)p->dispsw_data)[attr_fgcol(p, c)])) << 32) |
-	       ((u32 *)p->dispsw_data)[attr_bgcol(p, c)];
-	if (fgbg != *(u64 *)&fb->s.ffb.fg_cache) {
-		FFBFifo(fb, 2);
-		upa_writeq(fgbg, &fbc->fg);
-		*(u64 *)&fb->s.ffb.fg_cache = fgbg;
-	}
-	xy = fb->s.ffb.xy_margin;
-	if (fontwidthlog(p))
-		xy += (xx << fontwidthlog(p));
-	else
-		xy += xx * fontwidth(p);
-	if (fontheightlog(p))
-		xy += (yy << (16 + fontheightlog(p)));
-	else
-		xy += ((yy * fontheight(p)) << 16);
-	if (fontwidth(p) <= 8) {
-		while (count >= 4) {
-			count -= 4;
-			FFBFifo(fb, 2 + fontheight(p));
-			upa_writel(4 * fontwidth(p), &fbc->fontw);
-			upa_writel(xy, &fbc->fontxy);
-			if (fontheightlog(p)) {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-			} else {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-				fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
-			}
-			if (fontwidth(p) == 8) {
-				for (i = 0; i < fontheight(p); i++) {
-					u32 val;
-
-					val = ((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
-						<< 8)) << 8)) << 8);
-					upa_writel(val, &fbc->font);
-				}
-				xy += 32;
-			} else {
-				for (i = 0; i < fontheight(p); i++) {
-					u32 val = (((u32)*fd4++) | ((((u32)*fd3++) | ((((u32)*fd2++) | (((u32)*fd1++) 
-						<< fontwidth(p))) << fontwidth(p))) << fontwidth(p))) << (24 - 3 * fontwidth(p));
-					upa_writel(val, &fbc->font);
-				}
-				xy += 4 * fontwidth(p);
-			}
-		}
-	} else {
-		while (count >= 2) {
-			count -= 2;
-			FFBFifo(fb, 2 + fontheight(p));
-			upa_writel(2 * fontwidth(p), &fbc->fontw);
-			upa_writel(xy, &fbc->fontxy);
-			if (fontheightlog(p)) {
-				fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
-				fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
-			} else {
-				fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
-				fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
-			}
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) | ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
-
-				upa_writel(val, &fbc->font);
-				fd1 += 2; fd2 += 2;
-			}
-			xy += 2 * fontwidth(p);
-		}
-	}
-	while (count) {
-		count--;
-		FFBFifo(fb, 2 + fontheight(p));
-		upa_writel(fontwidth(p), &fbc->fontw);
-		upa_writel(xy, &fbc->fontxy);
-		if (fontheightlog(p))
-			i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
-		else
-			i = ((scr_readw(s++) & p->charmask) * fontheight(p));
-		if (fontwidth(p) <= 8) {
-			fd1 = p->fontdata + i;
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = *fd1++ << 24;
-
-				upa_writel(val, &fbc->font);
-			}
-		} else {
-			fd1 = p->fontdata + (i << 1);
-			for (i = 0; i < fontheight(p); i++) {
-				u32 val = *(u16 *)fd1 << 16;
-
-				upa_writel(val, &fbc->font);
-				fd1 += 2;
-			}
-		}
-		xy += fontwidth(p);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_revc(struct display *p, int xx, int yy)
-{
-	/* Not used if hw cursor */
-}
-
-#if 0
-static int ffb_blank(struct fb_info_sbusfb *fb)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	upa_writel(0x6000, &dac->type);
-	tmp = (upa_readl(&dac->value) & ~0x1);
-	upa_writel(0x6000, &dac->type);
-	upa_writel(tmp, &dac->value);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-#endif
-
-static int ffb_unblank(struct fb_info_sbusfb *fb)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	upa_writel(0x6000, &dac->type);
-	tmp = (upa_readl(&dac->value) | 0x1);
-	upa_writel(0x6000, &dac->type);
-	upa_writel(tmp, &dac->value);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static void ffb_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	unsigned long flags;
-	int i, j = count;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	upa_writel(0x2000 | index, &dac->type);
-	for (i = index; j--; i++) {
-		u32 val;
-
-		/* Feed the colors in :)) */
-		val = ((fb->color_map CM(i,0))) |
-			((fb->color_map CM(i,1)) << 8) |
-			((fb->color_map CM(i,2)) << 16);
-		upa_writel(val, &dac->value);
-	}
-	if (!p)
-		goto out;
-	for (i = index, j = count; i < 16 && j--; i++)
-		((u32 *)p->dispsw_data)[i] = ((fb->color_map CM(i,0))) |
-			      		     ((fb->color_map CM(i,1)) << 8) |
-					     ((fb->color_map CM(i,2)) << 16);
-out:
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static struct display_switch ffb_dispsw __initdata = {
-	.setup =	ffb_setup,
-	.bmove =	fbcon_redraw_bmove,
-	.clear =	ffb_clear,
-	.putc =		ffb_putc,
-	.putcs =	ffb_putcs,
-	.revc =		ffb_revc, 
-	.fontwidthmask =FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
-};
-
-static void ffb_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	fb->s.ffb.xy_margin = (y_margin << 16) + x_margin;
-	fb->s.ffb.yx_margin = (((u64)y_margin) << 32) + x_margin;
-	fb->info.screen_base += 8192 * (y_margin - fb->y_margin) + 4 * (x_margin - fb->x_margin);
-	FFBWait(fbc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static __inline__ void __ffb_curs_enable (struct fb_info_sbusfb *fb, int enable)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	u32 val;
-
-	upa_writel(0x100, &dac->type2);
-	if (fb->s.ffb.dac_rev <= 2) {
-		val = enable ? 3 : 0;
-	} else {
-		val = enable ? 0 : 3;
-	}
-	upa_writel(val, &dac->value2);
-}
-
-static void ffb_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&fb->lock, flags);
-	__ffb_curs_enable (fb, 0);
-	upa_writel(0x102, &dac->type2);
-	upa_writel((red[0] | (green[0]<<8) | (blue[0]<<16)), &dac->value2);
-	upa_writel((red[1] | (green[1]<<8) | (blue[1]<<16)), &dac->value2);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void ffb_setcurshape (struct fb_info_sbusfb *fb)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	unsigned long flags;
-	int i, j;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	__ffb_curs_enable (fb, 0);
-	for (j = 0; j < 2; j++) {
-		u32 val = j ? 0 : 0x80;
-
-		upa_writel(val, &dac->type2);
-		for (i = 0; i < 0x40; i++) {
-			if (fb->cursor.size.fbx <= 32) {
-				upa_writel(fb->cursor.bits [j][i], &dac->value2);
-				upa_writel(0, &dac->value2);
-			} else {
-				upa_writel(fb->cursor.bits [j][2*i], &dac->value2);
-				upa_writel(fb->cursor.bits [j][2*i+1], &dac->value2);
-			}
-		}
-	}	
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void ffb_setcursor (struct fb_info_sbusfb *fb)
-{
-	struct ffb_dac *dac = fb->s.ffb.dac;
-	struct cg_cursor *c = &fb->cursor;
-	unsigned long flags;
-	u32 val;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	upa_writel(0x104, &dac->type2);
-	/* Should this be just 0x7ff?? 
-	   Should I do some margin handling and setcurshape in that case? */
-	val = (((c->cpos.fby - c->chot.fby) & 0xffff) << 16)
-		|((c->cpos.fbx - c->chot.fbx) & 0xffff);
-	upa_writel(val, &dac->value2);
-	__ffb_curs_enable (fb, fb->cursor.enable);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void ffb_switch_from_graph (struct fb_info_sbusfb *fb)
-{
-	register struct ffb_fbc *fbc = fb->s.ffb.fbc;
-	unsigned long flags;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	FFBWait(fbc);
-	fb->s.ffb.fifo_cache = 0;
-	FFBFifo(fb, 8);
-	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
-		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
-		   &fbc->ppc);
-	upa_writel(0x2000707f, &fbc->fbc);
-	upa_writel(FFB_ROP_NEW, &fbc->rop);
-	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
-	upa_writel(0xffffffff, &fbc->pmask);
-	upa_writel(0x10000, &fbc->fontinc);
-	upa_writel(fb->s.ffb.fg_cache, &fbc->fg);
-	upa_writel(fb->s.ffb.bg_cache, &fbc->bg);
-	FFBWait(fbc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int __init ffb_rasterimg (struct fb_info *info, int start)
-{
-	ffb_switch_from_graph (sbusfbinfo(info));
-	return 0;
-}
-
-static char idstring[60] __initdata = { 0 };
-
-static int __init creator_apply_upa_parent_ranges(int parent, struct linux_prom64_registers *regs)
-{
-	struct linux_prom64_ranges ranges[PROMREG_MAX];
-	char name[128];
-	int len, i;
-
-	prom_getproperty(parent, "name", name, sizeof(name));
-	if (strcmp(name, "upa") != 0)
-		return 0;
-
-	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
-	if (len <= 0)
-		return 1;
-
-	len /= sizeof(struct linux_prom64_ranges);
-	for (i = 0; i < len; i++) {
-		struct linux_prom64_ranges *rng = &ranges[i];
-		u64 phys_addr = regs->phys_addr;
-
-		if (phys_addr >= rng->ot_child_base &&
-		    phys_addr < (rng->ot_child_base + rng->or_size)) {
-			regs->phys_addr -= rng->ot_child_base;
-			regs->phys_addr += rng->ot_parent_base;
-			return 0;
-		}
-	}
-
-	return 1;
-}
-
-char __init *creatorfb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct fb_var_screeninfo *var = &fb->info.var;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	struct linux_prom64_registers regs[2*PROMREG_MAX];
-	int i, afb = 0;
-	unsigned int btype;
-	char name[64];
-	struct fb_ops *fbops;
-
-	if (prom_getproperty(fb->prom_node, "reg", (void *) regs, sizeof(regs)) <= 0)
-		return NULL;
-
-	if (creator_apply_upa_parent_ranges(fb->prom_parent, &regs[0]))
-		return NULL;
-		
-	disp->dispsw_data = (void *)kmalloc(16 * sizeof(u32), GFP_KERNEL);
-	if (disp->dispsw_data == NULL)
-		return NULL;
-	memset(disp->dispsw_data, 0, 16 * sizeof(u32));
-
-	fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
-	if (fbops == NULL) {
-		kfree(disp->dispsw_data);
-		return NULL;
-	}
-	
-	*fbops = *fb->info.fbops;
-	fbops->fb_rasterimg = ffb_rasterimg;
-	fb->info.fbops = fbops;
-
-	prom_getstring(fb->prom_node, "name", name, sizeof(name));
-	if (!strcmp(name, "SUNW,afb"))
-		afb = 1;
-		
-	btype = prom_getintdefault(fb->prom_node, "board_type", 0);
-		
-	strcpy(fb->info.modename, "Creator");
-	if (!afb) {
-		if ((btype & 7) == 3)
-		    strcpy(fix->id, "Creator 3D");
-		else
-		    strcpy(fix->id, "Creator");
-	} else
-		strcpy(fix->id, "Elite 3D");
-	
-	fix->visual = FB_VISUAL_TRUECOLOR;
-	fix->line_length = 8192;
-	fix->accel = FB_ACCEL_SUN_CREATOR;
-	
-	var->bits_per_pixel = 32;
-	var->green.offset = 8;
-	var->blue.offset = 16;
-	var->accel_flags = FB_ACCELF_TEXT;
-	
-	disp->scrollmode = SCROLL_YREDRAW;
-	fb->info.screen_base = (char *)(regs[0].phys_addr) + FFB_DFB24_POFF + 8192 * fb->y_margin + 4 * fb->x_margin;
-	fb->s.ffb.xy_margin = (fb->y_margin << 16) + fb->x_margin;
-	fb->s.ffb.yx_margin = (((u64)fb->y_margin) << 32) + fb->x_margin;
-	fb->s.ffb.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
-	fb->s.ffb.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
-	fb->dispsw = ffb_dispsw;
-
-	fb->margins = ffb_margins;
-	fb->loadcmap = ffb_loadcmap;
-	fb->setcursor = ffb_setcursor;
-	fb->setcursormap = ffb_setcursormap;
-	fb->setcurshape = ffb_setcurshape;
-	fb->switch_from_graph = ffb_switch_from_graph;
-	fb->fill = ffb_fill;
-#if 0
-	/* XXX Can't enable this for now, I've seen cases
-	 * XXX where the VC was blanked, and Xsun24 was started
-	 * XXX via a remote login, the sunfb code did not
-	 * XXX unblank creator when it was mmap'd for some
-	 * XXX reason, investigate later... -DaveM
-	 */
-	fb->blank = ffb_blank;
-	fb->unblank = ffb_unblank;
-#endif
-	
-	/* If there are any read errors or fifo overflow conditions,
-	 * clear them now.
-	 */
-	if((upa_readl(&fb->s.ffb.fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
-		upa_writel(FFB_UCSR_ALL_ERRORS, &fb->s.ffb.fbc->ucsr);
-
-	ffb_switch_from_graph(fb);
-	
-	fb->physbase = regs[0].phys_addr;
-	fb->mmap_map = ffb_mmap_map;
-	
-	fb->cursor.hwsize.fbx = 64;
-	fb->cursor.hwsize.fby = 64;
-	
-	type->fb_depth = 24;
-	
-	upa_writel(0x8000, &fb->s.ffb.dac->type);
-	fb->s.ffb.dac_rev = (upa_readl(&fb->s.ffb.dac->value) >> 0x1c);
-	                
-	i = prom_getintdefault (fb->prom_node, "board_type", 8);
-
-	sprintf(idstring, "%s at %016lx type %d DAC %d",
-		fix->id, regs[0].phys_addr, i, fb->s.ffb.dac_rev);
-	
-	/* Elite3D has different DAC revision numbering, and no DAC revisions
-	   have the reversed meaning of cursor enable */
-	if (afb)
-		fb->s.ffb.dac_rev = 10;
-	
-	/* Unblank it just to be sure.  When there are multiple
-	 * FFB/AFB cards in the system, or it is not the OBP
-	 * chosen console, it will have video outputs off in
-	 * the DAC.
-	 */
-	ffb_unblank(fb);
-
-	return idstring;
-}
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/fbmem.c linux-2.5.63-bk7/drivers/video/fbmem.c
--- linux-2.5.63-bk6/drivers/video/fbmem.c	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/drivers/video/fbmem.c	Mon Mar 31 12:20:15 2003
@@ -103,8 +103,6 @@
 extern int matroxfb_init(void);
 extern int matroxfb_setup(char*);
 extern int hpfb_init(void);
-extern int sbusfb_init(void);
-extern int sbusfb_setup(char*);
 extern int control_init(void);
 extern int control_setup(char*);
 extern int platinum_init(void);
@@ -146,6 +144,20 @@
 extern int sstfb_setup(char*);
 extern int i810fb_init(void);
 extern int i810fb_setup(char*);
+extern int ffb_init(void);
+extern int ffb_setup(char*);
+extern int cg6_init(void);
+extern int cg6_setup(char*);
+extern int cg3_init(void);
+extern int cg3_setup(char*);
+extern int bw2_init(void);
+extern int bw2_setup(char*);
+extern int cg14_init(void);
+extern int cg14_setup(char*);
+extern int p9100_init(void);
+extern int p9100_setup(char*);
+extern int tcx_init(void);
+extern int tcx_setup(char*);
 
 static struct {
 	const char *name;
@@ -153,13 +165,6 @@
 	int (*setup)(char*);
 } fb_drivers[] __initdata = {
 
-#ifdef CONFIG_FB_SBUS
-	/*
-	 * Sbusfb must be initialized _before_ other frame buffer devices that
-	 * use PCI probing
-	 */
-	{ "sbus", sbusfb_init, sbusfb_setup },
-#endif
 	/*
 	 * Chipset specific drivers that use resource management
 	 */
@@ -244,6 +249,27 @@
 #ifdef CONFIG_FB_STI
 	{ "stifb", stifb_init, stifb_setup },
 #endif
+#ifdef CONFIG_FB_FFB
+	{ "ffb", ffb_init, ffb_setup },
+#endif
+#ifdef CONFIG_FB_CG6
+	{ "cg6", cg6_init, cg6_setup },
+#endif
+#ifdef CONFIG_FB_CG3
+	{ "cg3", cg3_init, cg3_setup },
+#endif
+#ifdef CONFIG_FB_BW2
+	{ "bw2", bw2_init, bw2_setup },
+#endif
+#ifdef CONFIG_FB_CG14
+	{ "cg14", cg14_init, cg14_setup },
+#endif
+#ifdef CONFIG_FB_P9100
+	{ "p9100", p9100_init, p9100_setup },
+#endif
+#ifdef CONFIG_FB_TCX
+	{ "tcx", tcx_init, tcx_setup },
+#endif
 
 	/*
 	 * Generic drivers that are used as fallbacks
diff -urN linux-2.5.63-bk6/drivers/video/ffb.c linux-2.5.63-bk7/drivers/video/ffb.c
--- linux-2.5.63-bk6/drivers/video/ffb.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/ffb.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,1046 @@
+/* ffb.c: Creator/Elite3D frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+
+#include <asm/io.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int ffb_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int ffb_set_par(struct fb_info *);
+static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int ffb_blank(int, struct fb_info *);
+static void ffb_init_fix(struct fb_info *);
+
+static void ffb_imageblit(struct fb_info *, struct fb_image *);
+static void ffb_fillrect(struct fb_info *, struct fb_fillrect *);
+static void ffb_copyarea(struct fb_info *, struct fb_copyarea *);
+static int ffb_sync(struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops ffb_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= ffb_check_var,
+	.fb_set_par		= ffb_set_par,
+	.fb_setcolreg		= ffb_setcolreg,
+	.fb_blank		= ffb_blank,
+	.fb_fillrect		= ffb_fillrect,
+	.fb_copyarea		= ffb_copyarea,
+	.fb_imageblit		= ffb_imageblit,
+	.fb_sync		= ffb_sync,
+	.fb_mmap		= ffb_mmap,
+
+	/* XXX Use FFB hw cursor once fb cursor API is better understood... */
+	.fb_cursor		= soft_cursor,
+};
+
+/* Register layout and definitions */
+#define	FFB_SFB8R_VOFF		0x00000000
+#define	FFB_SFB8G_VOFF		0x00400000
+#define	FFB_SFB8B_VOFF		0x00800000
+#define	FFB_SFB8X_VOFF		0x00c00000
+#define	FFB_SFB32_VOFF		0x01000000
+#define	FFB_SFB64_VOFF		0x02000000
+#define	FFB_FBC_REGS_VOFF	0x04000000
+#define	FFB_BM_FBC_REGS_VOFF	0x04002000
+#define	FFB_DFB8R_VOFF		0x04004000
+#define	FFB_DFB8G_VOFF		0x04404000
+#define	FFB_DFB8B_VOFF		0x04804000
+#define	FFB_DFB8X_VOFF		0x04c04000
+#define	FFB_DFB24_VOFF		0x05004000
+#define	FFB_DFB32_VOFF		0x06004000
+#define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
+#define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
+#define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
+#define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
+#define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
+#define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
+#define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
+#define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
+#define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
+#define	FFB_FBC_KREGS_VOFF	0x0bc04000
+#define	FFB_DAC_VOFF		0x0bc06000
+#define	FFB_PROM_VOFF		0x0bc08000
+#define	FFB_EXP_VOFF		0x0bc18000
+
+#define	FFB_SFB8R_POFF		0x04000000UL
+#define	FFB_SFB8G_POFF		0x04400000UL
+#define	FFB_SFB8B_POFF		0x04800000UL
+#define	FFB_SFB8X_POFF		0x04c00000UL
+#define	FFB_SFB32_POFF		0x05000000UL
+#define	FFB_SFB64_POFF		0x06000000UL
+#define	FFB_FBC_REGS_POFF	0x00600000UL
+#define	FFB_BM_FBC_REGS_POFF	0x00600000UL
+#define	FFB_DFB8R_POFF		0x01000000UL
+#define	FFB_DFB8G_POFF		0x01400000UL
+#define	FFB_DFB8B_POFF		0x01800000UL
+#define	FFB_DFB8X_POFF		0x01c00000UL
+#define	FFB_DFB24_POFF		0x02000000UL
+#define	FFB_DFB32_POFF		0x03000000UL
+#define	FFB_FBC_KREGS_POFF	0x00610000UL
+#define	FFB_DAC_POFF		0x00400000UL
+#define	FFB_PROM_POFF		0x00000000UL
+#define	FFB_EXP_POFF		0x00200000UL
+#define FFB_DFB422A_POFF	0x09000000UL
+#define FFB_DFB422AD_POFF	0x09800000UL
+#define FFB_DFB24B_POFF		0x0a000000UL
+#define FFB_DFB422B_POFF	0x0b000000UL
+#define FFB_DFB422BD_POFF	0x0b800000UL
+#define FFB_SFB16Z_POFF		0x0c800000UL
+#define FFB_SFB8Z_POFF		0x0c000000UL
+#define FFB_SFB422_POFF		0x0d000000UL
+#define FFB_SFB422D_POFF	0x0d800000UL
+
+/* Draw operations */
+#define FFB_DRAWOP_DOT		0x00
+#define FFB_DRAWOP_AADOT	0x01
+#define FFB_DRAWOP_BRLINECAP	0x02
+#define FFB_DRAWOP_BRLINEOPEN	0x03
+#define FFB_DRAWOP_DDLINE	0x04
+#define FFB_DRAWOP_AALINE	0x05
+#define FFB_DRAWOP_TRIANGLE	0x06
+#define FFB_DRAWOP_POLYGON	0x07
+#define FFB_DRAWOP_RECTANGLE	0x08
+#define FFB_DRAWOP_FASTFILL	0x09
+#define FFB_DRAWOP_BCOPY	0x0a
+#define FFB_DRAWOP_VSCROLL	0x0b
+
+/* Pixel processor control */
+/* Force WID */
+#define FFB_PPC_FW_DISABLE	0x800000
+#define FFB_PPC_FW_ENABLE	0xc00000
+/* Auxiliary clip */
+#define FFB_PPC_ACE_DISABLE	0x040000
+#define FFB_PPC_ACE_AUX_SUB	0x080000
+#define FFB_PPC_ACE_AUX_ADD	0x0c0000
+/* Depth cue */
+#define FFB_PPC_DCE_DISABLE	0x020000
+#define FFB_PPC_DCE_ENABLE	0x030000
+/* Alpha blend */
+#define FFB_PPC_ABE_DISABLE	0x008000
+#define FFB_PPC_ABE_ENABLE	0x00c000
+/* View clip */
+#define FFB_PPC_VCE_DISABLE	0x001000
+#define FFB_PPC_VCE_2D		0x002000
+#define FFB_PPC_VCE_3D		0x003000
+/* Area pattern */
+#define FFB_PPC_APE_DISABLE	0x000800
+#define FFB_PPC_APE_ENABLE	0x000c00
+/* Transparent background */
+#define FFB_PPC_TBE_OPAQUE	0x000200
+#define FFB_PPC_TBE_TRANSPARENT	0x000300
+/* Z source */
+#define FFB_PPC_ZS_VAR		0x000080
+#define FFB_PPC_ZS_CONST	0x0000c0
+/* Y source */
+#define FFB_PPC_YS_VAR		0x000020
+#define FFB_PPC_YS_CONST	0x000030
+/* X source */
+#define FFB_PPC_XS_WID		0x000004
+#define FFB_PPC_XS_VAR		0x000008
+#define FFB_PPC_XS_CONST	0x00000c
+/* Color (BGR) source */
+#define FFB_PPC_CS_VAR		0x000002
+#define FFB_PPC_CS_CONST	0x000003
+
+#define FFB_ROP_NEW                  0x83
+#define FFB_ROP_OLD                  0x85
+#define FFB_ROP_NEW_XOR_OLD          0x86
+
+#define FFB_UCSR_FIFO_MASK     0x00000fff
+#define FFB_UCSR_FB_BUSY       0x01000000
+#define FFB_UCSR_RP_BUSY       0x02000000
+#define FFB_UCSR_ALL_BUSY      (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+#define FFB_UCSR_READ_ERR      0x40000000
+#define FFB_UCSR_FIFO_OVFL     0x80000000
+#define FFB_UCSR_ALL_ERRORS    (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
+
+struct ffb_fbc {
+	/* Next vertex registers */
+	u32		xxx1[3];
+	volatile u32	alpha;
+	volatile u32	red;
+	volatile u32	green;
+	volatile u32	blue;
+	volatile u32	depth;
+	volatile u32	y;
+	volatile u32	x;
+	u32		xxx2[2];
+	volatile u32	ryf;
+	volatile u32	rxf;
+	u32		xxx3[2];
+	
+	volatile u32	dmyf;
+	volatile u32	dmxf;
+	u32		xxx4[2];
+	volatile u32	ebyi;
+	volatile u32	ebxi;
+	u32		xxx5[2];
+	volatile u32	by;
+	volatile u32	bx;
+	u32		dy;
+	u32		dx;
+	volatile u32	bh;
+	volatile u32	bw;
+	u32		xxx6[2];
+	
+	u32		xxx7[32];
+	
+	/* Setup unit vertex state register */
+	volatile u32	suvtx;
+	u32		xxx8[63];
+	
+	/* Control registers */
+	volatile u32	ppc;
+	volatile u32	wid;
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	consty;
+	volatile u32	constz;
+	volatile u32	xclip;
+	volatile u32	dcss;
+	volatile u32	vclipmin;
+	volatile u32	vclipmax;
+	volatile u32	vclipzmin;
+	volatile u32	vclipzmax;
+	volatile u32	dcsf;
+	volatile u32	dcsb;
+	volatile u32	dczf;
+	volatile u32	dczb;
+	
+	u32		xxx9;
+	volatile u32	blendc;
+	volatile u32	blendc1;
+	volatile u32	blendc2;
+	volatile u32	fbramitc;
+	volatile u32	fbc;
+	volatile u32	rop;
+	volatile u32	cmp;
+	volatile u32	matchab;
+	volatile u32	matchc;
+	volatile u32	magnab;
+	volatile u32	magnc;
+	volatile u32	fbcfg0;
+	volatile u32	fbcfg1;
+	volatile u32	fbcfg2;
+	volatile u32	fbcfg3;
+	
+	u32		ppcfg;
+	volatile u32	pick;
+	volatile u32	fillmode;
+	volatile u32	fbramwac;
+	volatile u32	pmask;
+	volatile u32	xpmask;
+	volatile u32	ypmask;
+	volatile u32	zpmask;
+	volatile u32	clip0min;
+	volatile u32	clip0max;
+	volatile u32	clip1min;
+	volatile u32	clip1max;
+	volatile u32	clip2min;
+	volatile u32	clip2max;
+	volatile u32	clip3min;
+	volatile u32	clip3max;
+	
+	/* New 3dRAM III support regs */
+	volatile u32	rawblend2;
+	volatile u32	rawpreblend;
+	volatile u32	rawstencil;
+	volatile u32	rawstencilctl;
+	volatile u32	threedram1;
+	volatile u32	threedram2;
+	volatile u32	passin;
+	volatile u32	rawclrdepth;
+	volatile u32	rawpmask;
+	volatile u32	rawcsrc;
+	volatile u32	rawmatch;
+	volatile u32	rawmagn;
+	volatile u32	rawropblend;
+	volatile u32	rawcmp;
+	volatile u32	rawwac;
+	volatile u32	fbramid;
+	
+	volatile u32	drawop;
+	u32		xxx10[2];
+	volatile u32	fontlpat;
+	u32		xxx11;
+	volatile u32	fontxy;
+	volatile u32	fontw;
+	volatile u32	fontinc;
+	volatile u32	font;
+	u32		xxx12[3];
+	volatile u32	blend2;
+	volatile u32	preblend;
+	volatile u32	stencil;
+	volatile u32	stencilctl;
+
+	u32		xxx13[4];	
+	volatile u32	dcss1;
+	volatile u32	dcss2;
+	volatile u32	dcss3;
+	volatile u32	widpmask;
+	volatile u32	dcs2;
+	volatile u32	dcs3;
+	volatile u32	dcs4;
+	u32		xxx14;
+	volatile u32	dcd2;
+	volatile u32	dcd3;
+	volatile u32	dcd4;
+	u32		xxx15;
+	
+	volatile u32	pattern[32];
+	
+	u32		xxx16[256];
+	
+	volatile u32	devid;
+	u32		xxx17[63];
+	
+	volatile u32	ucsr;
+	u32		xxx18[31];
+	
+	volatile u32	mer;
+};
+
+struct ffb_dac {
+	volatile u32	type;
+	volatile u32	value;
+	volatile u32	type2;
+	volatile u32	value2;
+};
+
+struct ffb_par {
+	spinlock_t		lock;
+	struct ffb_fbc		*fbc;
+	struct ffb_dac		*dac;
+
+	u32			flags;
+#define FFB_FLAG_AFB		0x00000001
+#define FFB_FLAG_BLANKED	0x00000002
+
+	u32			fg_cache __attribute__((aligned (8)));
+	u32			bg_cache;
+	u32			rop_cache;
+
+	int			fifo_cache;
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	char			name[64];
+	int			prom_node;
+	int			prom_parent_node;
+	int			dac_rev;
+	int			board_type;
+	struct list_head	list;
+};
+
+#undef FFB_DO_DEBUG_LOG
+
+#ifdef FFB_DO_DEBUG_LOG
+#define FFB_DEBUG_LOG_ENTS	32
+static struct ffb_log {
+	int op;
+#define OP_FILLRECT	1
+#define OP_IMAGEBLIT	2
+
+	int depth, x, y, w, h;
+} ffb_debug_log[FFB_DEBUG_LOG_ENTS];
+static int ffb_debug_log_ent;
+
+static void ffb_do_log(unsigned long unused)
+{
+	int i;
+
+	for (i = 0; i < FFB_DEBUG_LOG_ENTS; i++) {
+		struct ffb_log *p = &ffb_debug_log[i];
+
+		printk("FFB_LOG: OP[%s] depth(%d) x(%d) y(%d) w(%d) h(%d)\n",
+		       (p->op == OP_FILLRECT ? "FILLRECT" : "IMAGEBLIT"),
+		       p->depth, p->x, p->y, p->w, p->h);
+	}
+}
+static struct timer_list ffb_log_timer =
+	TIMER_INITIALIZER(ffb_do_log, 0, 0);
+
+static void ffb_log(int op, int depth, int x, int y, int w, int h)
+{
+	if (ffb_debug_log_ent < FFB_DEBUG_LOG_ENTS) {
+		struct ffb_log *p = &ffb_debug_log[ffb_debug_log_ent];
+
+		if (ffb_debug_log_ent != 0 &&
+		    p[-1].op == op && p[-1].depth == depth)
+			return;
+		p->op = op;
+		p->depth = depth;
+		p->x = x;
+		p->y = y;
+		p->w = w;
+		p->h = h;
+
+		if (++ffb_debug_log_ent == FFB_DEBUG_LOG_ENTS) {
+			ffb_log_timer.expires = jiffies + 2;
+			add_timer(&ffb_log_timer);
+		}
+	}
+}
+#else
+#define ffb_log(a,b,c,d,e,f)	do { } while(0)
+#endif
+
+#undef FORCE_WAIT_EVERY_ROP
+
+static void FFBFifo(struct ffb_par *par, int n)
+{
+	struct ffb_fbc *fbc;
+	int cache = par->fifo_cache;
+
+	if (cache - n < 0) {
+		fbc = par->fbc;
+		do {	cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK) - 8;
+		} while (cache - n < 0);
+	}
+	par->fifo_cache = cache - n;
+}
+
+static void FFBWait(struct ffb_par *par)
+{
+	struct ffb_fbc *fbc;
+	int limit = 10000;
+
+	fbc = par->fbc;
+	do {
+		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
+			break;
+		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
+			upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+		}
+		udelay(10);
+	} while(--limit > 0);
+}
+
+static int ffb_sync(struct fb_info *p)
+{
+	struct ffb_par *par = (struct ffb_par *) p->par;
+
+	FFBWait(par);
+	return 0;
+}
+
+static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
+{
+	if (par->rop_cache != rop) {
+		FFBFifo(par, 1);
+		upa_writel(rop, &par->fbc->rop);
+		par->rop_cache = rop;
+	}
+}
+
+static void ffb_switch_from_graph(struct ffb_par *par)
+{
+	struct ffb_fbc *fbc = par->fbc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&par->lock, flags);
+	FFBWait(par);
+	par->fifo_cache = 0;
+	FFBFifo(par, 7);
+	upa_writel(FFB_PPC_VCE_DISABLE|FFB_PPC_TBE_OPAQUE|
+		   FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
+		   &fbc->ppc);
+	upa_writel(0x2000707f, &fbc->fbc);
+	upa_writel(par->rop_cache, &fbc->rop);
+	upa_writel(0xffffffff, &fbc->pmask);
+	upa_writel((0 << 16) | (32 << 0), &fbc->fontinc);
+	upa_writel(par->fg_cache, &fbc->fg);
+	upa_writel(par->bg_cache, &fbc->bg);
+	FFBWait(par);
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      ffb_fillrect - REQUIRED function. Can use generic routines if 
+ *                     non acclerated hardware and packed pixel based.
+ *                     Draws a rectangle on the screen.               
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @rect: structure defining the rectagle and operation.
+ */
+static void ffb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	unsigned long flags;
+	u32 fg;
+
+	if (rect->rop != ROP_COPY && rect->rop != ROP_XOR)
+		BUG();
+
+	ffb_log(OP_FILLRECT, 0, rect->dx, rect->dy, rect->width, rect->height);
+
+	fg = ((u32 *)info->pseudo_palette)[rect->color];
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	if (fg != par->fg_cache) {
+		FFBFifo(par, 1);
+		upa_writel(fg, &fbc->fg);
+		par->fg_cache = fg;
+	}
+
+	ffb_rop(par, (rect->rop == ROP_COPY ?
+		      FFB_ROP_NEW :
+		      FFB_ROP_NEW_XOR_OLD));
+
+	FFBFifo(par, 5);
+	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
+	upa_writel(rect->dy, &fbc->by);
+	upa_writel(rect->dx, &fbc->bx);
+	upa_writel(rect->height, &fbc->bh);
+	upa_writel(rect->width, &fbc->bw);
+#ifdef FORCE_WAIT_EVERY_ROP
+	FFBWait(par);
+#endif
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      ffb_copyarea - REQUIRED function. Can use generic routines if
+ *                     non acclerated hardware and packed pixel based.
+ *                     Copies on area of the screen to another area.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @area: structure defining the source and destination.
+ */
+
+static void
+ffb_copyarea(struct fb_info *info, struct fb_copyarea *area) 
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	unsigned long flags;
+
+	if (area->dx != area->sx ||
+	    area->dy == area->dy) {
+		cfb_copyarea(info, area);
+		return;
+	}
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	ffb_rop(par, FFB_ROP_OLD);
+
+	FFBFifo(par, 7);
+	upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);
+	upa_writel(area->sy, &fbc->by);
+	upa_writel(area->sx, &fbc->bx);
+	upa_writel(area->dy, &fbc->dy);
+	upa_writel(area->dx, &fbc->dx);
+	upa_writel(area->height, &fbc->bh);
+	upa_writel(area->width, &fbc->bw);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      ffb_imageblit - REQUIRED function. Can use generic routines if
+ *                      non acclerated hardware and packed pixel based.
+ *                      Copies a image from system memory to the screen. 
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void ffb_imageblit(struct fb_info *info, struct fb_image *image)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_fbc *fbc = par->fbc;
+	u8 *data = (u8 *) image->data;
+	unsigned long flags;
+	u32 fg, bg, xy;
+	u64 fgbg;
+	int i, width;
+
+	ffb_log(OP_IMAGEBLIT, image->depth,
+		image->dx, image->dy, image->width, image->height);
+
+	if (image->depth > 1) {
+		cfb_imageblit(info, image);
+		return;
+	}
+
+	fg = ((u32 *)info->pseudo_palette)[image->fg_color];
+	bg = ((u32 *)info->pseudo_palette)[image->bg_color];
+	fgbg = ((u64) fg << 32) | (u64) bg;
+	xy = (image->dy << 16) | image->dx;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	if (fgbg != *(u64 *)&par->fg_cache) {
+		FFBFifo(par, 2);
+		upa_writeq(fgbg, &fbc->fg);
+		*(u64 *)&par->fg_cache = fgbg;
+	}
+
+	ffb_rop(par, FFB_ROP_NEW);
+
+	for (i = 0; i < image->height; i++) {
+		width = image->width;
+
+		FFBFifo(par, 1);
+		upa_writel(xy, &fbc->fontxy);
+		xy += (1 << 16);
+
+		while (width >= 32) {
+			u32 val;
+
+			FFBFifo(par, 2);
+			upa_writel(32, &fbc->fontw);
+
+			val = ((u32)data[0] << 24) |
+			      ((u32)data[1] << 16) |
+			      ((u32)data[2] <<  8) |
+			      ((u32)data[3] <<  0);
+			upa_writel(val, &fbc->font);
+
+			data += 4;
+			width -= 32;
+		}
+
+		if (width) {
+			u32 val;
+
+			FFBFifo(par, 2);
+			upa_writel(width, &fbc->fontw);
+			if (width <= 8) {
+				val = (u32) data[0] << 24;
+				data += 1;
+			} else if (width <= 16) {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16);
+				data += 2;
+			} else {
+				val = ((u32) data[0] << 24) |
+				      ((u32) data[1] << 16) |
+				      ((u32) data[2] <<  8);
+				data += 3;
+			}
+			upa_writel(val, &fbc->font);
+		}
+	}
+#ifdef FORCE_WAIT_EVERY_ROP
+	FFBWait(par);
+#endif
+
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
+{
+	var->red.offset = 0;
+	var->red.length = 8;
+	var->green.offset = 8;
+	var->green.length = 8;
+	var->blue.offset = 16;
+	var->blue.length = 8;
+	var->transp.offset = 0;
+	var->transp.length = 0;
+}
+
+/**
+ *      ffb_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int ffb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 32)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	ffb_fixup_var_rgb(var);
+
+	return 0;
+}
+
+/**
+ *      ffb_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+ffb_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      ffb_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int ffb_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	u32 value;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	value = (blue << 16) | (green << 8) | red;
+	((u32 *)info->pseudo_palette)[regno] = value;
+
+	return 0;
+}
+
+/**
+ *      ffb_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+ffb_blank(int blank, struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *) info->par;
+	struct ffb_dac *dac = par->dac;
+	unsigned long flags;
+	u32 tmp;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	FFBWait(par);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		upa_writel(0x6000, &dac->type);
+		tmp = (upa_readl(&dac->value) | 0x1);
+		upa_writel(0x6000, &dac->type);
+		upa_writel(tmp, &dac->value);
+		par->flags &= ~FFB_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+	case 2: /* VESA blank (vsync off) */
+	case 3: /* VESA blank (hsync off) */
+	case 4: /* Poweroff */
+		upa_writel(0x6000, &dac->type);
+		tmp = (upa_readl(&dac->value) & ~0x1);
+		upa_writel(0x6000, &dac->type);
+		upa_writel(tmp, &dac->value);
+		par->flags |= FFB_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map ffb_mmap_map[] = {
+	{ FFB_SFB8R_VOFF,	FFB_SFB8R_POFF,		0x0400000 },
+	{ FFB_SFB8G_VOFF,	FFB_SFB8G_POFF,		0x0400000 },
+	{ FFB_SFB8B_VOFF,	FFB_SFB8B_POFF,		0x0400000 },
+	{ FFB_SFB8X_VOFF,	FFB_SFB8X_POFF,		0x0400000 },
+	{ FFB_SFB32_VOFF,	FFB_SFB32_POFF,		0x1000000 },
+	{ FFB_SFB64_VOFF,	FFB_SFB64_POFF,		0x2000000 },
+	{ FFB_FBC_REGS_VOFF,	FFB_FBC_REGS_POFF,	0x0002000 },
+	{ FFB_BM_FBC_REGS_VOFF,	FFB_BM_FBC_REGS_POFF,	0x0002000 },
+	{ FFB_DFB8R_VOFF,	FFB_DFB8R_POFF,		0x0400000 },
+	{ FFB_DFB8G_VOFF,	FFB_DFB8G_POFF,		0x0400000 },
+	{ FFB_DFB8B_VOFF,	FFB_DFB8B_POFF,		0x0400000 },
+	{ FFB_DFB8X_VOFF,	FFB_DFB8X_POFF,		0x0400000 },
+	{ FFB_DFB24_VOFF,	FFB_DFB24_POFF,		0x1000000 },
+	{ FFB_DFB32_VOFF,	FFB_DFB32_POFF,		0x1000000 },
+	{ FFB_FBC_KREGS_VOFF,	FFB_FBC_KREGS_POFF,	0x0002000 },
+	{ FFB_DAC_VOFF,		FFB_DAC_POFF,		0x0002000 },
+	{ FFB_PROM_VOFF,	FFB_PROM_POFF,		0x0010000 },
+	{ FFB_EXP_VOFF,		FFB_EXP_POFF,		0x0002000 },
+	{ FFB_DFB422A_VOFF,	FFB_DFB422A_POFF,	0x0800000 },
+	{ FFB_DFB422AD_VOFF,	FFB_DFB422AD_POFF,	0x0800000 },
+	{ FFB_DFB24B_VOFF,	FFB_DFB24B_POFF,	0x1000000 },
+	{ FFB_DFB422B_VOFF,	FFB_DFB422B_POFF,	0x0800000 },
+	{ FFB_DFB422BD_VOFF,	FFB_DFB422BD_POFF,	0x0800000 },
+	{ FFB_SFB16Z_VOFF,	FFB_SFB16Z_POFF,	0x0800000 },
+	{ FFB_SFB8Z_VOFF,	FFB_SFB8Z_POFF,		0x0800000 },
+	{ FFB_SFB422_VOFF,	FFB_SFB422_POFF,	0x0800000 },
+	{ FFB_SFB422D_VOFF,	FFB_SFB422D_POFF,	0x0800000 },
+	{ 0,			0,			0	  }
+};
+
+static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct ffb_par *par = (struct ffb_par *)info->par;
+
+	return sbusfb_mmap_helper(ffb_mmap_map,
+				  par->physbase, par->fbsize,
+				  0, vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+ffb_init_fix(struct fb_info *info)
+{
+	struct ffb_par *par = (struct ffb_par *)info->par;
+	const char *ffb_type_name;
+
+	if (!(par->flags & FFB_FLAG_AFB)) {
+		if ((par->board_type & 0x7) == 0x3)
+			ffb_type_name = "Creator 3D";
+		else
+			ffb_type_name = "Creator";
+	} else
+		ffb_type_name = "Elite 3D";
+
+	strncpy(info->fix.id, ffb_type_name, sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	/* Framebuffer length is the same regardless of resolution. */
+	info->fix.line_length = 8192;
+
+	info->fix.accel = FB_ACCEL_SUN_CREATOR;
+}
+
+static int ffb_apply_upa_parent_ranges(int parent,
+				       struct linux_prom64_registers *regs)
+{
+	struct linux_prom64_ranges ranges[PROMREG_MAX];
+	char name[128];
+	int len, i;
+
+	prom_getproperty(parent, "name", name, sizeof(name));
+	if (strcmp(name, "upa") != 0)
+		return 0;
+
+	len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
+	if (len <= 0)
+		return 1;
+
+	len /= sizeof(struct linux_prom64_ranges);
+	for (i = 0; i < len; i++) {
+		struct linux_prom64_ranges *rng = &ranges[i];
+		u64 phys_addr = regs->phys_addr;
+
+		if (phys_addr >= rng->ot_child_base &&
+		    phys_addr < (rng->ot_child_base + rng->or_size)) {
+			regs->phys_addr -= rng->ot_child_base;
+			regs->phys_addr += rng->ot_parent_base;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct ffb_par par;
+	u32 pseudo_palette[256];
+	struct list_head list;
+};
+static LIST_HEAD(ffb_list);
+
+static void ffb_init_one(int node, int parent)
+{
+	struct linux_prom64_registers regs[2*PROMREG_MAX];
+	struct ffb_fbc *fbc;
+	struct ffb_dac *dac;
+	struct all_info *all;
+
+	if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) {
+		printk("ffb: Cannot get reg device node property.\n");
+		return;
+	}
+
+	if (ffb_apply_upa_parent_ranges(parent, &regs[0])) {
+		printk("ffb: Cannot apply parent ranges to regs.\n");
+		return;
+	}
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "ffb: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);	
+
+	spin_lock_init(&all->par.lock);
+	all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
+	all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
+	all->par.rop_cache = FFB_ROP_NEW;
+	all->par.physbase = regs[0].phys_addr;
+	all->par.prom_node = node;
+	all->par.prom_parent_node = parent;
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &ffb_ops;
+	all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+	all->info.pseudo_palette = all->pseudo_palette;
+
+	sbusfb_fill_var(&all->info.var, all->par.prom_node, 32);
+	all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
+				     all->info.var.yres *
+				     4);
+	ffb_fixup_var_rgb(&all->info.var);
+
+	all->info.var.accel_flags = FB_ACCELF_TEXT;
+
+	prom_getstring(node, "name", all->par.name, sizeof(all->par.name));
+	if (!strcmp(all->par.name, "SUNW,afb"))
+		all->par.flags |= FFB_FLAG_AFB;
+
+	all->par.board_type = prom_getintdefault(node, "board_type", 0);
+
+	fbc = all->par.fbc;
+	if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
+		upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
+
+	ffb_switch_from_graph(&all->par);
+
+	dac = all->par.dac;
+	upa_writel(0x8000, &dac->type);
+	all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+
+	/* Elite3D has different DAC revision numbering, and no DAC revisions
+	 * have the reversed meaning of cursor enable.
+	 */
+	if (all->par.flags & FFB_FLAG_AFB)
+		all->par.dac_rev = 10;
+
+	/* Unblank it just to be sure.  When there are multiple
+	 * FFB/AFB cards in the system, or it is not the OBP
+	 * chosen console, it will have video outputs off in
+	 * the DAC.
+	 */
+	ffb_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "ffb: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	ffb_set_par(&all->info);
+	ffb_init_fix(&all->info);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "ffb: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &ffb_list);
+
+	printk("ffb: %s at %016lx type %d DAC %d\n",
+	       ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+	       regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+}
+
+static void ffb_scan_siblings(int root)
+{
+	int node, child;
+
+	child = prom_getchild(root);
+	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+		ffb_init_one(node, root);
+	for (node = prom_searchsiblings(child, "SUNW,afb"); node;
+	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
+		ffb_init_one(node, root);
+}
+
+int __init ffb_init(void)
+{
+	int root;
+
+	ffb_scan_siblings(prom_root_node);
+
+	root = prom_getchild(prom_root_node);
+	for (root = prom_searchsiblings(root, "upa"); root;
+	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
+		ffb_scan_siblings(root);
+
+	return 0;
+}
+
+void __exit ffb_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &ffb_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+ffb_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(ffb_init);
+module_exit(ffb_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/p9100.c linux-2.5.63-bk7/drivers/video/p9100.c
--- linux-2.5.63-bk6/drivers/video/p9100.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/p9100.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,405 @@
+/* p9100.c: P9100 frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int p9100_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int p9100_set_par(struct fb_info *);
+static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			   unsigned, struct fb_info *);
+static int p9100_blank(int, struct fb_info *);
+
+static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops p9100_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= p9100_check_var,
+	.fb_set_par		= p9100_set_par,
+	.fb_setcolreg		= p9100_setcolreg,
+	.fb_blank		= p9100_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= p9100_mmap,
+	.fb_cursor		= soft_cursor,
+};
+
+/* P9100 control registers */
+#define P9100_SYSCTL_OFF	0x0UL
+#define P9100_VIDEOCTL_OFF	0x100UL
+#define P9100_VRAMCTL_OFF 	0x180UL
+#define P9100_RAMDAC_OFF 	0x200UL
+#define P9100_VIDEOCOPROC_OFF 	0x400UL
+
+/* P9100 command registers */
+#define P9100_CMD_OFF 0x0UL
+
+/* P9100 framebuffer memory */
+#define P9100_FB_OFF 0x0UL
+
+/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
+#define SYS_CONFIG_PIXELSIZE_SHIFT 26 
+
+#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
+
+struct p9100_regs {
+	/* Registers for the system control */
+	volatile u32 sys_base;
+	volatile u32 sys_config;
+	volatile u32 sys_intr;
+	volatile u32 sys_int_ena;
+	volatile u32 sys_alt_rd;
+	volatile u32 sys_alt_wr;
+	volatile u32 sys_xxx[58];
+
+	/* Registers for the video control */
+	volatile u32 vid_base;
+	volatile u32 vid_hcnt;
+	volatile u32 vid_htotal;
+	volatile u32 vid_hsync_rise;
+	volatile u32 vid_hblank_rise;
+	volatile u32 vid_hblank_fall;
+	volatile u32 vid_hcnt_preload;
+	volatile u32 vid_vcnt;
+	volatile u32 vid_vlen;
+	volatile u32 vid_vsync_rise;
+	volatile u32 vid_vblank_rise;
+	volatile u32 vid_vblank_fall;
+	volatile u32 vid_vcnt_preload;
+	volatile u32 vid_screenpaint_addr;
+	volatile u32 vid_screenpaint_timectl1;
+	volatile u32 vid_screenpaint_qsfcnt;
+	volatile u32 vid_screenpaint_timectl2;
+	volatile u32 vid_xxx[15];
+
+	/* Registers for the video control */
+	volatile u32 vram_base;
+	volatile u32 vram_memcfg;
+	volatile u32 vram_refresh_pd;
+	volatile u32 vram_refresh_cnt;
+	volatile u32 vram_raslo_max;
+	volatile u32 vram_raslo_cur;
+	volatile u32 pwrup_cfg;
+	volatile u32 vram_xxx[25];
+
+	/* Registers for IBM RGB528 Palette */
+	volatile u32 ramdac_cmap_wridx; 
+	volatile u32 ramdac_palette_data;
+	volatile u32 ramdac_pixel_mask;
+	volatile u32 ramdac_palette_rdaddr;
+	volatile u32 ramdac_idx_lo;
+	volatile u32 ramdac_idx_hi;
+	volatile u32 ramdac_idx_data;
+	volatile u32 ramdac_idx_ctl;
+	volatile u32 ramdac_xxx[1784];
+};
+
+struct p9100_cmd_parameng {
+	volatile u32 parameng_status;
+	volatile u32 parameng_bltcmd;
+	volatile u32 parameng_quadcmd;
+};
+
+struct p9100_par {
+	spinlock_t		lock;
+	struct p9100_regs	*regs;
+
+	u32			flags;
+#define P9100_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/**
+ *      p9100_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int p9100_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      p9100_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+p9100_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      p9100_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int p9100_setcolreg(unsigned regno,
+			   unsigned red, unsigned green, unsigned blue,
+			   unsigned transp, struct fb_info *info)
+{
+	struct p9100_par *par = (struct p9100_par *) info->par;
+	struct p9100_regs *regs = par->regs;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel((regno << 16), &regs->ramdac_cmap_wridx);
+	sbus_writel((red << 16), &regs->ramdac_palette_data);
+	sbus_writel((green << 16), &regs->ramdac_palette_data);
+	sbus_writel((blue << 16), &regs->ramdac_palette_data);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      p9100_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+p9100_blank(int blank, struct fb_info *info)
+{
+	struct p9100_par *par = (struct p9100_par *) info->par;
+	struct p9100_regs *regs = par->regs;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		val = sbus_readl(&regs->vid_screenpaint_timectl1);
+		val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
+		sbus_writel(val, &regs->vid_screenpaint_timectl1);
+		par->flags &= ~P9100_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+	case 2: /* VESA blank (vsync off) */
+	case 3: /* VESA blank (hsync off) */
+	case 4: /* Poweroff */
+		val = sbus_readl(&regs->vid_screenpaint_timectl1);
+		val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
+		sbus_writel(val, &regs->vid_screenpaint_timectl1);
+		par->flags |= P9100_FLAG_BLANKED;
+		break;
+	}
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map p9100_mmap_map[] = {
+	{ CG3_MMAP_OFFSET,	0,		SBUS_MMAP_FBSIZE(1) },
+	{ 0,			0,		0		    }
+};
+
+static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct p9100_par *par = (struct p9100_par *)info->par;
+
+	return sbusfb_mmap_helper(p9100_mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+p9100_init_fix(struct fb_info *info, int linebytes)
+{
+	struct p9100_par *par = (struct p9100_par *)info->par;
+
+	strncpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct p9100_par par;
+	struct list_head list;
+};
+static LIST_HEAD(p9100_list);
+
+static void p9100_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "p9100: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	/* This is the framebuffer and the only resource apps can mmap.  */
+	all->par.physbase = sdev->reg_addrs[2].phys_addr;
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.regs = (struct p9100_regs *)
+		sbus_ioremap(&sdev->resource[0], 0,
+			     sizeof(struct p9100_regs), "p9100 regs");
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &p9100_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = (char *)
+			sbus_ioremap(&sdev->resource[2], 0,
+				     all->par.fbsize, "p9100 ram");
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	p9100_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "p9100: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	p9100_set_par(&all->info);
+	p9100_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "p9100: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &p9100_list);
+
+	printk("p9100: %s at %lx:%lx\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr);
+}
+
+int __init p9100_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "p9100"))
+			p9100_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit p9100_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &p9100_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+p9100_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(p9100_init);
+module_exit(p9100_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/p9100.h linux-2.5.63-bk7/drivers/video/p9100.h
--- linux-2.5.63-bk6/drivers/video/p9100.h	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/drivers/video/p9100.h	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-/*
- * Register information for the Weitek P9100 as found
- * on the Tadpole Sparcbook 3 laptops.
- * 
- * From the technical specification document provided by Tadpole.
- *
- * Derrick J Brashear (shadow@dementia.org)
- */
-
-#ifndef _P9100_H_
-#define _P9100_H_
-
-/* P9100 control registers */
-#define P9100_SYSCTL_OFF	0x0UL
-#define P9100_VIDEOCTL_OFF	0x100UL
-#define P9100_VRAMCTL_OFF 	0x180UL
-#define P9100_RAMDAC_OFF 	0x200UL
-#define P9100_VIDEOCOPROC_OFF 	0x400UL
-
-/* P9100 command registers */
-#define P9100_CMD_OFF 0x0UL
-
-/* P9100 framebuffer memory */
-#define P9100_FB_OFF 0x0UL
-
-
-/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
-#define SYS_CONFIG_PIXELSIZE_SHIFT 26 
-
-#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
-
-struct p9100_ctrl {
-  /* Registers for the system control */
-  __volatile__ __u32 sys_base;
-  __volatile__ __u32 sys_config;
-  __volatile__ __u32 sys_intr;
-  __volatile__ __u32 sys_int_ena;
-  __volatile__ __u32 sys_alt_rd;
-  __volatile__ __u32 sys_alt_wr;
-  __volatile__ __u32 sys_xxx[58];
-  /* Registers for the video control */
-  __volatile__ __u32 vid_base;
-  __volatile__ __u32 vid_hcnt;
-  __volatile__ __u32 vid_htotal;
-  __volatile__ __u32 vid_hsync_rise;
-  __volatile__ __u32 vid_hblank_rise;
-  __volatile__ __u32 vid_hblank_fall;
-  __volatile__ __u32 vid_hcnt_preload;
-  __volatile__ __u32 vid_vcnt;
-  __volatile__ __u32 vid_vlen;
-  __volatile__ __u32 vid_vsync_rise;
-  __volatile__ __u32 vid_vblank_rise;
-  __volatile__ __u32 vid_vblank_fall;
-  __volatile__ __u32 vid_vcnt_preload;
-  __volatile__ __u32 vid_screenpaint_addr;
-  __volatile__ __u32 vid_screenpaint_timectl1;
-  __volatile__ __u32 vid_screenpaint_qsfcnt;
-  __volatile__ __u32 vid_screenpaint_timectl2;
-  __volatile__ __u32 vid_xxx[15];
-  /* Registers for the video control */
-  __volatile__ __u32 vram_base;
-  __volatile__ __u32 vram_memcfg;
-  __volatile__ __u32 vram_refresh_pd;
-  __volatile__ __u32 vram_refresh_cnt;
-  __volatile__ __u32 vram_raslo_max;
-  __volatile__ __u32 vram_raslo_cur;
-  __volatile__ __u32 pwrup_cfg;
-  __volatile__ __u32 vram_xxx[25];
-  /* Registers for IBM RGB528 Palette */
-  __volatile__ __u32 ramdac_cmap_wridx; 
-  __volatile__ __u32 ramdac_palette_data;
-  __volatile__ __u32 ramdac_pixel_mask;
-  __volatile__ __u32 ramdac_palette_rdaddr;
-  __volatile__ __u32 ramdac_idx_lo;
-  __volatile__ __u32 ramdac_idx_hi;
-  __volatile__ __u32 ramdac_idx_data;
-  __volatile__ __u32 ramdac_idx_ctl;
-  __volatile__ __u32 ramdac_xxx[1784];
-};
-
-struct p9100_cmd_parameng {
-  __volatile__ __u32 parameng_status;
-  __volatile__ __u32 parameng_bltcmd;
-  __volatile__ __u32 parameng_quadcmd;
-};
-
-#endif /* _P9100_H_ */
diff -urN linux-2.5.63-bk6/drivers/video/p9100fb.c linux-2.5.63-bk7/drivers/video/p9100fb.c
--- linux-2.5.63-bk6/drivers/video/p9100fb.c	Mon Feb 24 11:05:47 2003
+++ linux-2.5.63-bk7/drivers/video/p9100fb.c	Wed Dec 31 16:00:00 1969
@@ -1,195 +0,0 @@
-/* $id: p9100fb.c,v 1.4 1999/08/18 10:55:01 shadow Exp $
- * p9100fb.c: P9100 frame buffer driver
- *
- * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-
-#include <video/fbcon-cfb8.h>
-
-#include "p9100.h"
-
-static struct sbus_mmap_map p9100_mmap_map[] = {
-#if 0 /* For now, play we're a dumb color fb */
-  { P9100_CTL_OFF, 0x38000000, 0x2000 },
-  { P9100_CMD_OFF, 0x38002000, 0x2000 },
-  { P9100_FB_OFF, 0x38800000, 0x200000 },
-  { CG3_MMAP_OFFSET, 0x38800000, SBUS_MMAP_FBSIZE(1) },
-#else
-  { CG3_MMAP_OFFSET, 0x0, SBUS_MMAP_FBSIZE(1) },
-#endif
-  { 0, 0, 0 }
-};
-
-#define _READCTL(member, out) \
-{ \
-  struct p9100_ctrl *actual; \
-  actual = (struct p9100_ctrl *)fb->s.p9100.ctrl; \
-  out = sbus_readl(&actual-> ## member ); \
-}
-
-#define READCTL(member, out) \
-{ \
-  struct p9100_ctrl *enab, *actual; \
-  actual = (struct p9100_ctrl *)fb->s.p9100.ctrl; \
-  enab = (struct p9100_ctrl *)fb->s.p9100.fbmem; \
-  out = sbus_readl(&enab-> ## member ); \
-  out = sbus_readl(&actual-> ## member ); \
-}
-
-#define WRITECTL(member, val) \
-{ \
-  u32 __writetmp; \
-  struct p9100_ctrl *enab, *actual; \
-  actual = (struct p9100_ctrl *)fb->s.p9100.ctrl; \
-  enab = (struct p9100_ctrl *)fb->s.p9100.fbmem; \
-  __writetmp = sbus_readl(&enab-> ## member ); \
-  sbus_writel(val, &actual-> ## member ); \
-}
-
-static void p9100_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
-	unsigned long flags;
-	u32 tmp;
-	int i;
-
-	spin_lock_irqsave(&fb->lock, flags);
-
-	_READCTL(pwrup_cfg, tmp);
-	WRITECTL(ramdac_cmap_wridx, (index << 16));
-
-	for (i = index; count--; i++){
-		_READCTL(pwrup_cfg, tmp);
-		WRITECTL(ramdac_palette_data, (fb->color_map CM(i,0) << 16));
-		_READCTL(pwrup_cfg, tmp);
-		WRITECTL(ramdac_palette_data, (fb->color_map CM(i,1) << 16));
-		_READCTL(pwrup_cfg, tmp);
-		WRITECTL(ramdac_palette_data, (fb->color_map CM(i,2) << 16));
-	}
-
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int p9100_blank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 val;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	READCTL(vid_screenpaint_timectl1, val);
-	val &= ~ SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
-	WRITECTL(vid_screenpaint_timectl1, val);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static int p9100_unblank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 val;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	READCTL(vid_screenpaint_timectl1, val);
-	val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
-	WRITECTL(vid_screenpaint_timectl1, val);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static void p9100_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
-  fb->info.screen_base += (y_margin - fb->y_margin) * p->line_length + 
-    (x_margin - fb->x_margin);
-}
-
-static char idstring[60] __initdata = { 0 };
-
-char * __init p9100fb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->fix;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	struct sbus_dev *sdev = fb->sbdp;
-	unsigned long phys = sdev->reg_addrs[2].phys_addr;
-	int tmp;
-
-#ifndef FBCON_HAS_CFB8
-	return NULL;
-#endif
-
-	/* Control regs: fb->sbdp->reg_addrs[0].phys_addr 
-	 * Command regs: fb->sbdp->reg_addrs[1].phys_addr 
-	 * Frame buffer: fb->sbdp->reg_addrs[2].phys_addr 
-         */
-
-	if (!fb->s.p9100.ctrl) {
-		fb->s.p9100.ctrl = (struct p9100_ctrl *)
-			sbus_ioremap(&sdev->resource[0], 0,
-				     sdev->reg_addrs[0].reg_size, "p9100 ctrl");
-	}
-
-	strcpy(fb->info.modename, "p9100");
-	strcpy(fix->id, "p9100");
-	fix->accel = FB_ACCEL_SUN_CGTHREE;
-	fix->line_length = fb->var.xres_virtual;
-
-	disp->scrollmode = SCROLL_YREDRAW;
-	if (!fb->info.screen_base)
-		fb->info.screen_base = (char *)
-			sbus_ioremap(&sdev->resource[2], 0,
-				     type->fb_size, "p9100 ram");
-	fb->s.p9100.fbmem = (volatile u32 *)fb->info.screen_base;
-	fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
-
-	READCTL(sys_config, tmp);
-        switch ((tmp >> SYS_CONFIG_PIXELSIZE_SHIFT) & 7) {
-	case 7: 
-	  type->fb_depth = 24; 
-	  break;
-	case 5: 
-	  type->fb_depth = 32;
-	  break;
-	case 3: 
-	  type->fb_depth = 16; 
-	  break;
-	case 2: 
-	  type->fb_depth = 8; 
-	  break;
-	default: 
-	  printk("p9100: screen depth unknown: 0x%x", tmp);
-	  return NULL;
-        }
-
-	fb->dispsw = fbcon_cfb8;
-
-	fb->margins = p9100_margins;
-	fb->loadcmap = p9100_loadcmap;
-	fb->blank = p9100_blank;
-	fb->unblank = p9100_unblank;
-	
-	fb->physbase = phys;
-	fb->mmap_map = p9100_mmap_map;
-	
-	sprintf(idstring, "%s at 0x%x", "p9100", 
-		(unsigned int)fb->info.screen_base);
-
-	return idstring;
-}
-
diff -urN linux-2.5.63-bk6/drivers/video/sbusfb.c linux-2.5.63-bk7/drivers/video/sbusfb.c
--- linux-2.5.63-bk6/drivers/video/sbusfb.c	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/drivers/video/sbusfb.c	Wed Dec 31 16:00:00 1969
@@ -1,1165 +0,0 @@
-/*
- *  linux/drivers/video/sbusfb.c -- SBUS or UPA based frame buffer device
- *
- *	Copyright (C) 1998 Jakub Jelinek
- *
- *  This driver is partly based on the Open Firmware console driver
- *
- *	Copyright (C) 1997 Geert Uytterhoeven
- *
- *  and SPARC console subsystem
- *
- *      Copyright (C) 1995 Peter Zaitcev (zaitcev@yahoo.com)
- *      Copyright (C) 1995-1997 David S. Miller (davem@caip.rutgers.edu)
- *      Copyright (C) 1995-1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- *      Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
- *      Copyright (C) 1996-1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *      Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License. See the file COPYING in the main directory of this archive for
- *  more details.
- */
-
-#include <linux/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/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/selection.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>	/* io_remap_page_range() */
-
-#include <video/sbusfb.h>
-
-#define DEFAULT_CURSOR_BLINK_RATE       (2*HZ/5)
-
-#define CURSOR_SHAPE			1
-#define CURSOR_BLINK			2
-
-    /*
-     *  Interface used by the world
-     */
-
-int sbusfb_init(void);
-int sbusfb_setup(char*);
-
-static int defx_margin = -1, defy_margin = -1;
-static char fontname[40] __initdata = { 0 };
-static int curblink __initdata = 1;
-static struct {
-	int depth;
-	int xres, yres;
-	int x_margin, y_margin;
-} def_margins [] = {
-	{ 8, 1280, 1024, 64, 80 },
-	{ 8, 1152, 1024, 64, 80 },
-	{ 8, 1152, 900,  64, 18 },
-	{ 8, 1024, 768,  0,  0 },
-	{ 8, 800, 600, 16, 12 },
-	{ 8, 640, 480, 0, 0 },
-	{ 1, 1152, 900,  8,  18 },
-	{ 0 },
-};
-
-static int sbusfb_open(struct fb_info *info, int user);
-static int sbusfb_release(struct fb_info *info, int user);
-static int sbusfb_mmap(struct fb_info *info, struct file *file, 
-			struct vm_area_struct *vma);
-static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info);
-static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info);
-static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info);
-static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			    u_int transp, struct fb_info *info);
-static int sbusfb_blank(int blank, struct fb_info *info);
-static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			    u_long arg, int con, struct fb_info *info);
-static void sbusfb_cursor(struct display *p, int mode, int x, int y);
-static void sbusfb_clear_margin(struct display *p, int s);
-			    
-
-    /*
-     *  Interface to the low level console driver
-     */
-
-static int sbusfbcon_switch(int con, struct fb_info *info);
-static int sbusfbcon_updatevar(int con, struct fb_info *info);
-
-    /*
-     *  Internal routines
-     */
-
-static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			    u_int *transp, struct fb_info *info);
-
-static struct fb_ops sbusfb_ops = {
-	.owner =	THIS_MODULE,
-	.fb_open =	sbusfb_open,
-	.fb_release =	sbusfb_release,
-	.fb_set_var =	sbusfb_set_var,
-	.fb_get_cmap =	sbusfb_get_cmap,
-	.fb_set_cmap =	sbusfb_set_cmap,
-	.fb_setcolreg =	sbusfb_setcolreg,
-	.fb_blank =	sbusfb_blank,
-	.fb_ioctl =	sbusfb_ioctl,
-	.fb_mmap =	sbusfb_mmap,
-};
-
-    /*
-     *  Open/Release the frame buffer device
-     */
-
-static int sbusfb_open(struct fb_info *info, int user)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-	
-	if (user) {
-		if (fb->open == 0) {
-			fb->mmaped = 0;
-			fb->vtconsole = -1;
-		}
-		fb->open++;
-	} else
-		fb->consolecnt++;
-	return 0;
-}
-
-static int sbusfb_release(struct fb_info *info, int user)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
-	if (user) {	
-		fb->open--;
-		if (fb->open == 0) {
-			if (fb->vtconsole != -1) {
-				vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
-				if (fb->mmaped) {
-					fb->graphmode--;
-					sbusfb_clear_margin(&fb_display[fb->vtconsole], 0);
-				}
-			}
-			if (fb->reset)
-				fb->reset(fb);
-		}
-	} else
-		fb->consolecnt--;
-	return 0;
-}
-
-static unsigned long sbusfb_mmapsize(struct fb_info_sbusfb *fb, long size)
-{
-	if (size == SBUS_MMAP_EMPTY) return 0;
-	if (size >= 0) return size;
-	return fb->type.fb_size * (-size);
-}
-
-static int sbusfb_mmap(struct fb_info *info, struct file *file, 
-			struct vm_area_struct *vma)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-	unsigned int size, page, r, map_size;
-	unsigned long map_offset = 0;
-	unsigned long off;
-	int i;
-                                        
-	size = vma->vm_end - vma->vm_start;
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-		return -EINVAL;
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= (VM_SHM| VM_LOCKED);
-	
-
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ){
-		map_size = 0;
-		for (i = 0; fb->mmap_map[i].size; i++)
-			if (fb->mmap_map[i].voff == off+page) {
-				map_size = sbusfb_mmapsize(fb,fb->mmap_map[i].size);
-#ifdef __sparc_v9__
-#define POFF_MASK	(PAGE_MASK|0x1UL)
-#else
-#define POFF_MASK	(PAGE_MASK)
-#endif				
-				map_offset = (fb->physbase + fb->mmap_map[i].poff) & POFF_MASK;
-				break;
-			}
-		if (!map_size){
-			page += PAGE_SIZE;
-			continue;
-		}
-		if (page + map_size > size)
-			map_size = size - page;
-		r = io_remap_page_range(vma, vma->vm_start+page, map_offset, map_size, vma->vm_page_prot, fb->iospace);
-		if (r)
-			return -EAGAIN;
-		page += map_size;
-	}
-	
-	vma->vm_flags |= VM_IO;
-	if (!fb->mmaped) {
-		int lastconsole = 0;
-		
-		if (info->display_fg)
-			lastconsole = info->display_fg->vc_num;
-		fb->mmaped = 1;
-		if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
-			fb->vtconsole = lastconsole;
-			fb->graphmode++;
-			vt_cons [lastconsole]->vc_mode = KD_GRAPHICS;
-			vc_cons[lastconsole].d->vc_sw->con_cursor(vc_cons[lastconsole].d,CM_ERASE);
-		} else if (fb->unblank && !fb->blanked)
-			(*fb->unblank)(fb);
-	}
-	return 0;
-}
-
-static void sbusfb_clear_margin(struct display *p, int s)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
-	if (fb->switch_from_graph)
-		(*fb->switch_from_graph)(fb);
-	if (fb->fill) {
-		unsigned short rects [16];
-
-		rects [0] = 0;
-		rects [1] = 0;
-		rects [2] = fb->info.var.xres_virtual;
-		rects [3] = fb->y_margin;
-		rects [4] = 0;
-		rects [5] = fb->y_margin;
-		rects [6] = fb->x_margin;
-		rects [7] = fb->info.var.yres_virtual;
-		rects [8] = fb->info.var.xres_virtual - fb->x_margin;
-		rects [9] = fb->y_margin;
-		rects [10] = fb->info.var.xres_virtual;
-		rects [11] = fb->info.var.yres_virtual;
-		rects [12] = fb->x_margin;
-		rects [13] = fb->info.var.yres_virtual - fb->y_margin;
-		rects [14] = fb->info.var.xres_virtual - fb->x_margin;
-		rects [15] = fb->info.var.yres_virtual;
-		(*fb->fill)(fb, p, s, 4, rects);
-	} else {
-		unsigned char *fb_base = fb->info.screen_base, *q;
-		int skip_bytes = fb->y_margin * fb->info.var.xres_virtual;
-		int scr_size = fb->info.var.xres_virtual
-			* fb->info.var.yres_virtual;
-		int h, he, incr, size;
-
-		he = fb->info.var.yres;
-		if (fb->info.var.bits_per_pixel == 1) {
-			fb_base -= (skip_bytes + fb->x_margin) / 8;
-			skip_bytes /= 8;
-			scr_size /= 8;
-			fb_memset255 (fb_base, skip_bytes - fb->x_margin / 8);
-			fb_memset255 (fb_base + scr_size - skip_bytes + fb->x_margin / 8, skip_bytes - fb->x_margin / 8);
-			incr = fb->info.var.xres_virtual / 8;
-			size = fb->x_margin / 8 * 2;
-			for (q = fb_base + skip_bytes - fb->x_margin / 8, h = 0;
-			     h <= he; q += incr, h++)
-				fb_memset255 (q, size);
-		} else {
-			fb_base -= (skip_bytes + fb->x_margin);
-			fb_memset (fb_base, attr_bgcol(p,s), skip_bytes - fb->x_margin);
-			fb_memset (fb_base + scr_size - skip_bytes + fb->x_margin, attr_bgcol(p,s), skip_bytes - fb->x_margin);
-			incr = fb->info.var.xres_virtual;
-			size = fb->x_margin * 2;
-			for (q = fb_base + skip_bytes - fb->x_margin, h = 0;
-			     h <= he; q += incr, h++)
-				fb_memset (q, attr_bgcol(p,s), size);
-		}
-	}
-}
-
-static void sbusfb_disp_setup(struct display *p)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
-	if (fb->setup)
-		fb->setup(p);	
-	sbusfb_clear_margin(p, 0);
-}
-
-
-    /*
-     *  Set the User Defined Part of the Display
-     */
-
-static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
-			  struct fb_info *info)
-{
-       struct display *display;
-       int activate = var->activate;
-
-       if(con >= 0)
-               display = &fb_display[con];
-       else
-               display = info->disp;
-
-       /* simple check for equality until fully implemented -E */
-       if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-               if (display->var.xres != var->xres ||
-                       display->var.yres != var->yres ||
-                       display->var.xres_virtual != var->xres_virtual ||
-                       display->var.yres_virtual != var->yres_virtual ||
-                       display->var.bits_per_pixel != var->bits_per_pixel ||
-                       display->var.accel_flags != var->accel_flags) {
-                       return -EINVAL;
-               }
-       }
-       return 0;
-
-}
-
-    /*
-     *  Hardware cursor
-     */
-     
-static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb)
-{
-	int op;
-	int i, bytes = 0;
-	struct fbcursor f;
-	char red[2], green[2], blue[2];
-	
-	if (copy_from_user (&f, cursor, sizeof(struct fbcursor)))
-		return -EFAULT;
-	op = f.set;
-	if (op & FB_CUR_SETSHAPE){
-		if ((u32) f.size.fbx > fb->cursor.hwsize.fbx)
-			return -EINVAL;
-		if ((u32) f.size.fby > fb->cursor.hwsize.fby)
-			return -EINVAL;
-		if (f.size.fbx > 32)
-			bytes = f.size.fby << 3;
-		else
-			bytes = f.size.fby << 2;
-	}
-	if (op & FB_CUR_SETCMAP){
-		if (f.cmap.index || f.cmap.count != 2)
-			return -EINVAL;
-		if (copy_from_user (red, f.cmap.red, 2) ||
-		    copy_from_user (green, f.cmap.green, 2) ||
-		    copy_from_user (blue, f.cmap.blue, 2))
-			return -EFAULT;
-	}
-	if (op & FB_CUR_SETCMAP)
-		(*fb->setcursormap) (fb, red, green, blue);
-	if (op & FB_CUR_SETSHAPE){
-		u32 u;
-		
-		fb->cursor.size = f.size;
-		memset ((void *)&fb->cursor.bits, 0, sizeof (fb->cursor.bits));
-		if (copy_from_user (fb->cursor.bits [0], f.mask, bytes) ||
-		    copy_from_user (fb->cursor.bits [1], f.image, bytes))
-			return -EFAULT;
-		if (f.size.fbx <= 32) {
-			u = 0xffffffff << (32 - f.size.fbx);
-			for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
-				fb->cursor.bits [0][i] &= u;
-				fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
-			}
-		} else {
-			u = 0xffffffff << (64 - f.size.fbx);
-			for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
-				fb->cursor.bits [0][2*i+1] &= u;
-				fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i];
-				fb->cursor.bits [1][2*i+1] &= fb->cursor.bits [0][2*i+1];
-			}
-		}
-		(*fb->setcurshape) (fb);
-	}
-	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
-		if (op & FB_CUR_SETCUR)
-			fb->cursor.enable = f.enable;
-		if (op & FB_CUR_SETPOS)
-			fb->cursor.cpos = f.pos;
-		if (op & FB_CUR_SETHOT)
-			fb->cursor.chot = f.hot;
-		(*fb->setcursor) (fb);
-	}
-	return 0;
-}
-
-static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
-
-static void
-sbusfb_cursor_timer_handler(unsigned long dev_addr)
-{
-	struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)dev_addr;
-        
-	if (!fb->setcursor) return;
-                                
-	if (fb->cursor.mode & CURSOR_BLINK) {
-		fb->cursor.enable ^= 1;
-		fb->setcursor(fb);
-	}
-	
-	fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
-	add_timer(&fb->cursor.timer);
-}
-
-static void sbusfb_cursor(struct display *p, int mode, int x, int y)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfod(p);
-	
-	switch (mode) {
-	case CM_ERASE:
-		fb->cursor.mode &= ~CURSOR_BLINK;
-		fb->cursor.enable = 0;
-		(*fb->setcursor)(fb);
-		break;
-				  
-	case CM_MOVE:
-	case CM_DRAW:
-		if (fb->cursor.mode & CURSOR_SHAPE) {
-			fb->cursor.size.fbx = fontwidth(p);
-			fb->cursor.size.fby = fontheight(p);
-			fb->cursor.chot.fbx = 0;
-			fb->cursor.chot.fby = 0;
-			fb->cursor.enable = 1;
-			memset (fb->cursor.bits, 0, sizeof (fb->cursor.bits));
-			fb->cursor.bits[0][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
-			fb->cursor.bits[1][fontheight(p) - 2] = (0xffffffff << (32 - fontwidth(p)));
-			fb->cursor.bits[0][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
-			fb->cursor.bits[1][fontheight(p) - 1] = (0xffffffff << (32 - fontwidth(p)));
-			(*fb->setcursormap) (fb, hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
-			(*fb->setcurshape) (fb);
-		}
-		fb->cursor.mode = CURSOR_BLINK;
-		if (fontwidthlog(p))
-			fb->cursor.cpos.fbx = (x << fontwidthlog(p)) + fb->x_margin;
-		else
-			fb->cursor.cpos.fbx = (x * fontwidth(p)) + fb->x_margin;
-		if (fontheightlog(p))
-			fb->cursor.cpos.fby = (y << fontheightlog(p)) + fb->y_margin;
-		else
-			fb->cursor.cpos.fby = (y * fontheight(p)) + fb->y_margin;
-		(*fb->setcursor)(fb);
-		break;
-	}
-}
-
-    /*
-     *  Get the Colormap
-     */
-
-static int sbusfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
-{
-	if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */
-		return fb_get_cmap(cmap, kspc, sbusfb_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
-	return 0;
-}
-
-    /*
-     *  Set the Colormap
-     */
-
-static int sbusfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			 struct fb_info *info)
-{
-	int err;
-	struct display *disp;
-
-	if (con >= 0)
-		disp = &fb_display[con];
-	else
-		disp = info->disp;
-	if (!disp->cmap.len) {	/* no colormap allocated? */
-		if ((err = fb_alloc_cmap(&disp->cmap, 1<<disp->var.bits_per_pixel, 0)))
-			return err;
-	}
-	if (con == info->currcon) {			/* current console? */
-		err = fb_set_cmap(cmap, kspc, info);
-		if (!err) {
-			struct fb_info_sbusfb *fb = sbusfbinfo(info);
-			
-			if (fb->loadcmap)
-				(*fb->loadcmap)(fb, &fb_display[con], cmap->start, cmap->len);
-		}
-		return err;
-	} else
-		fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
-	return 0;
-}
-
-static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-			u_long arg, int con, struct fb_info *info)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-	int i;
-	int lastconsole;
-	
-	switch (cmd){
-	case FBIOGTYPE:		/* return frame buffer type */
-		if (copy_to_user((struct fbtype *)arg, &fb->type, sizeof(struct fbtype)))
-			return -EFAULT;
-		break;
-	case FBIOGATTR: {
-		struct fbgattr *fba = (struct fbgattr *) arg;
-		
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
-		if (i) return i;
-		if (__put_user(fb->emulations[0], &fba->real_type) ||
-		    __put_user(0, &fba->owner) ||
-		    __copy_to_user(&fba->fbtype, &fb->type,
-				   sizeof(struct fbtype)) ||
-		    __put_user(0, &fba->sattr.flags) ||
-		    __put_user(fb->type.fb_type, &fba->sattr.emu_type) ||
-		    __put_user(-1, &fba->sattr.dev_specific[0]))
-			return -EFAULT;
-		for (i = 0; i < 4; i++) {
-			if (put_user(fb->emulations[i], &fba->emu_types[i]))
-				return -EFAULT;
-		}
-		break;
-	}
-	case FBIOSATTR:
-		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbsattr));
-		if (i) return i;
-		return -EINVAL;
-	case FBIOSVIDEO:
-		if (fb->consolecnt) {
-			lastconsole = info->display_fg->vc_num;
-			if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- 				break;
- 		}
-		if (get_user(i, (int *)arg))
-			return -EFAULT;
-		if (i){
-			if (!fb->blanked || !fb->unblank)
-				break;
-			if (fb->consolecnt || (fb->open && fb->mmaped))
-				(*fb->unblank)(fb);
-			fb->blanked = 0;
-		} else {
-			if (fb->blanked || !fb->blank)
-				break;
-			(*fb->blank)(fb);
-			fb->blanked = 1;
-		}
-		break;
-	case FBIOGVIDEO:
-		if (put_user(fb->blanked, (int *) arg))
-			return -EFAULT;
-		break;
-	case FBIOGETCMAP_SPARC: {
-		char *rp, *gp, *bp;
-		int end, count, index;
-		struct fbcmap *cmap;
-
-		if (!fb->loadcmap)
-			return -EINVAL;
-		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
-		if (i) return i;
-		cmap = (struct fbcmap *) arg;
-		if (__get_user(count, &cmap->count) ||
-		    __get_user(index, &cmap->index))
-			return -EFAULT;
-		if ((index < 0) || (index > 255))
-			return -EINVAL;
-		if (index + count > 256)
-			count = 256 - index;
-		if (__get_user(rp, &cmap->red) ||
-		    __get_user(gp, &cmap->green) ||
-		    __get_user(bp, &cmap->blue))
-			return -EFAULT;
-		if (verify_area (VERIFY_WRITE, rp, count))
-			return -EFAULT;
-		if (verify_area (VERIFY_WRITE, gp, count))
-			return -EFAULT;
-		if (verify_area (VERIFY_WRITE, bp, count))
-			return -EFAULT;
-		end = index + count;
-		for (i = index; i < end; i++){
-			if (__put_user(fb->color_map CM(i,0), rp) ||
-			    __put_user(fb->color_map CM(i,1), gp) ||
-			    __put_user(fb->color_map CM(i,2), bp))
-				return -EFAULT;
-			rp++; gp++; bp++;
-		}
-		(*fb->loadcmap)(fb, NULL, index, count);
-		break;			
-	}
-	case FBIOPUTCMAP_SPARC: {	/* load color map entries */
-		char *rp, *gp, *bp;
-		int end, count, index;
-		struct fbcmap *cmap;
-		
-		if (!fb->loadcmap || !fb->color_map)
-			return -EINVAL;
-		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
-		if (i) return i;
-		cmap = (struct fbcmap *) arg;
-		if (__get_user(count, &cmap->count) ||
-		    __get_user(index, &cmap->index))
-			return -EFAULT;
-		if ((index < 0) || (index > 255))
-			return -EINVAL;
-		if (index + count > 256)
-			count = 256 - index;
-		if (__get_user(rp, &cmap->red) ||
-		    __get_user(gp, &cmap->green) ||
-		    __get_user(bp, &cmap->blue))
-			return -EFAULT;
-		if (verify_area (VERIFY_READ, rp, count))
-			return -EFAULT;
-		if (verify_area (VERIFY_READ, gp, count))
-			return -EFAULT;
-		if (verify_area (VERIFY_READ, bp, count))
-			return -EFAULT;
-
-		end = index + count;
-		for (i = index; i < end; i++){
-			if (__get_user(fb->color_map CM(i,0), rp))
-				return -EFAULT;
-			if (__get_user(fb->color_map CM(i,1), gp))
-				return -EFAULT;
-			if (__get_user(fb->color_map CM(i,2), bp))
-				return -EFAULT;
-			rp++; gp++; bp++;
-		}
-		(*fb->loadcmap)(fb, NULL, index, count);
-		break;			
-	}
-	case FBIOGCURMAX: {
-		struct fbcurpos *p = (struct fbcurpos *) arg;
-		if (!fb->setcursor) return -EINVAL;
-		if(verify_area (VERIFY_WRITE, p, sizeof (struct fbcurpos)))
-			return -EFAULT;
-		if (__put_user(fb->cursor.hwsize.fbx, &p->fbx) ||
-		    __put_user(fb->cursor.hwsize.fby, &p->fby))
-			return -EFAULT;
-		break;
-	}
-	case FBIOSCURSOR:
-		if (!fb->setcursor) return -EINVAL;
- 		if (fb->consolecnt) {
- 			lastconsole = info->display_fg->vc_num; 
- 			if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- 				return -EINVAL; /* Don't let graphics programs hide our nice text cursor */
-			fb->cursor.mode = CURSOR_SHAPE; /* Forget state of our text cursor */
-		}
-		return sbus_hw_scursor ((struct fbcursor *) arg, fb);
-
-	case FBIOSCURPOS:
-		if (!fb->setcursor) return -EINVAL;
-		/* Don't let graphics programs move our nice text cursor */
- 		if (fb->consolecnt) {
- 			lastconsole = info->display_fg->vc_num; 
- 			if (vt_cons[lastconsole]->vc_mode == KD_TEXT)
- 				return -EINVAL; /* Don't let graphics programs move our nice text cursor */
- 		}
-		if (copy_from_user(&fb->cursor.cpos, (void *)arg, sizeof(struct fbcurpos)))
-			return -EFAULT;
-		(*fb->setcursor) (fb);
-		break;
-	default:
-		if (fb->ioctl)
-			return fb->ioctl(fb, cmd, arg);
-		return -EINVAL;
-	}		
-	return 0;
-}
-
-    /*
-     *  Setup: parse used options
-     */
-
-int __init sbusfb_setup(char *options)
-{
-	char *p;
-	
-	for (p = options;;) {
-		if (!strncmp(p, "nomargins", 9)) {
-			defx_margin = 0; defy_margin = 0;
-		} else if (!strncmp(p, "margins=", 8)) {
-			int i, j;
-			char *q;
-			
-			i = simple_strtoul(p+8,&q,10);
-			if (i >= 0 && *q == 'x') {
-			    j = simple_strtoul(q+1,&q,10);
-			    if (j >= 0 && (*q == ' ' || !*q)) {
-			    	defx_margin = i; defy_margin = j;
-			    }
-			}
-		} else if (!strncmp(p, "font=", 5)) {
-			int i;
-			
-			for (i = 0; i < sizeof(fontname) - 1; i++)
-				if (p[i+5] == ' ' || !p[i+5])
-					break;
-			memcpy(fontname, p+5, i);
-			fontname[i] = 0;
-		} else if (!strncmp(p, "noblink", 7))
-			curblink = 0;
-		while (*p && *p != ' ' && *p != ',') p++;
-		if (*p != ',') break;
-		p++;
-	}
-	return 0;
-}
-
-static int sbusfbcon_switch(int con, struct fb_info *info)
-{
-	int x_margin, y_margin;
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-	int lastconsole;
-    
-	/* Do we have to save the colormap? */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, sbusfb_getcolreg, info);
-
-	if (info->display_fg) {
-		lastconsole = info->display_fg->vc_num;
-		if (lastconsole != con && 
-		    (fontwidth(&fb_display[lastconsole]) != fontwidth(&fb_display[con]) ||
-		     fontheight(&fb_display[lastconsole]) != fontheight(&fb_display[con])))
-			fb->cursor.mode |= CURSOR_SHAPE;
-	}
-	x_margin = (fb_display[con].var.xres_virtual - fb_display[con].var.xres) / 2;
-	y_margin = (fb_display[con].var.yres_virtual - fb_display[con].var.yres) / 2;
-	if (fb->margins)
-		fb->margins(fb, &fb_display[con], x_margin, y_margin);
-	if (fb->graphmode || fb->x_margin != x_margin || fb->y_margin != y_margin) {
-		fb->x_margin = x_margin; fb->y_margin = y_margin;
-		sbusfb_clear_margin(&fb_display[con], 0);
-	}
-	info->currcon = con;
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	return 0;
-}
-
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
-
-static int sbusfbcon_updatevar(int con, struct fb_info *info)
-{
-	/* Nothing */
-	return 0;
-}
-
-    /*
-     *  Blank the display.
-     */
-
-static int sbusfb_blank(int blank, struct fb_info *info)
-{
-    struct fb_info_sbusfb *fb = sbusfbinfo(info);
-    
-    if (blank && fb->blank)
-	    return fb->blank(fb);
-    else if (!blank && fb->unblank)
-	    return fb->unblank(fb);
-    return 0;
-}
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int sbusfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			  u_int *transp, struct fb_info *info)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
-	if (!fb->color_map || regno > 255)
-		return 1;
-	*red = (fb->color_map CM(regno, 0)<<8) | fb->color_map CM(regno, 0);
-	*green = (fb->color_map CM(regno, 1)<<8) | fb->color_map CM(regno, 1);
-	*blue = (fb->color_map CM(regno, 2)<<8) | fb->color_map CM(regno, 2);
-	*transp = 0;
-	return 0;
-}
-
-
-    /*
-     *  Set a single color register. The values supplied are already
-     *  rounded down to the hardware's capabilities (according to the
-     *  entries in the var structure). Return != 0 for invalid regno.
-     */
-
-static int sbusfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			    u_int transp, struct fb_info *info)
-{
-	struct fb_info_sbusfb *fb = sbusfbinfo(info);
-
-	if (!fb->color_map || regno > 255)
-		return 1;
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
-	fb->color_map CM(regno, 0) = red;
-	fb->color_map CM(regno, 1) = green;
-	fb->color_map CM(regno, 2) = blue;
-	return 0;
-}
-
-static int sbusfb_set_font(struct display *p, int width, int height)
-{
-	int margin;
-	int w = p->var.xres_virtual, h = p->var.yres_virtual;
-	int depth = p->var.bits_per_pixel;
-	struct fb_info_sbusfb *fb = sbusfbinfod(p);
-	int x_margin, y_margin;
-	
-	if (depth > 8) depth = 8;
-	x_margin = 0;
-	y_margin = 0;
-	if (defx_margin < 0 || defy_margin < 0) {
-		for (margin = 0; def_margins[margin].depth; margin++)
-			if (w == def_margins[margin].xres &&
-			    h == def_margins[margin].yres &&
-			    depth == def_margins[margin].depth) {
-				x_margin = def_margins[margin].x_margin;
-				y_margin = def_margins[margin].y_margin;
-				break;
-			}
-	} else {
-		x_margin = defx_margin;
-		y_margin = defy_margin;
-	}
-	x_margin += ((w - 2*x_margin) % width) / 2;
-	y_margin += ((h - 2*y_margin) % height) / 2;
-
-	p->var.xres = w - 2*x_margin;
-	p->var.yres = h - 2*y_margin;
-	
-	fb->cursor.mode |= CURSOR_SHAPE;
-	
-	if (fb->margins)
-		fb->margins(fb, p, x_margin, y_margin);
-	if (fb->x_margin != x_margin || fb->y_margin != y_margin) {
-		fb->x_margin = x_margin; fb->y_margin = y_margin;
-		sbusfb_clear_margin(p, 0);
-	}
-
-	return 1;
-}
-
-void sbusfb_palette(int enter)
-{
-	int i;
-	struct display *p;
-	
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		p = &fb_display[i];
-		if (p->dispsw && p->dispsw->setup == sbusfb_disp_setup &&
-		    p->fb_info->display_fg &&
-		    p->fb_info->display_fg->vc_num == i) {
-			struct fb_info_sbusfb *fb = sbusfbinfod(p);
-
-			if (fb->restore_palette) {
-				if (enter)
-					fb->restore_palette(fb);
-				else if (vt_cons[i]->vc_mode != KD_GRAPHICS)
-				         vc_cons[i].d->vc_sw->con_set_palette(vc_cons[i].d, color_table);
-			}
-		}
-	}
-}
-
-    /*
-     *  Initialisation
-     */
-     
-extern void (*prom_palette)(int);
-
-static void __init sbusfb_init_fb(int node, int parent, int fbtype,
-				  struct sbus_dev *sbdp)
-{
-	struct fb_fix_screeninfo *fix;
-	struct fb_var_screeninfo *var;
-	struct display *disp;
-	struct fb_info_sbusfb *fb;
-	struct fbtype *type;
-	int linebytes, w, h, depth;
-	char *p = NULL;
-	int margin;
-
-	fb = kmalloc(sizeof(struct fb_info_sbusfb), GFP_ATOMIC);
-	if (!fb) {
-		prom_printf("Could not allocate sbusfb structure\n");
-		return;
-	}
-	
-	if (!prom_palette)
-		prom_palette = sbusfb_palette;
-	
-	memset(fb, 0, sizeof(struct fb_info_sbusfb));
-	fix = &fb->info.fix;
-	var = &fb->info.var;
-	disp = &fb->disp;
-	type = &fb->type;
-	
-	spin_lock_init(&fb->lock);
-	fb->prom_node = node;
-	fb->prom_parent = parent;
-	fb->sbdp = sbdp;
-	if (sbdp)
-		fb->iospace = sbdp->reg_addrs[0].which_io;
-
-	type->fb_type = fbtype;
-	memset(&fb->emulations, 0xff, sizeof(fb->emulations));
-	fb->emulations[0] = fbtype;
-	
-#ifdef CONFIG_SPARC32
-	fb->info.screen_base = (unsigned char *)prom_getintdefault(node, "address", 0);
-#endif
-	
-	type->fb_height = h = prom_getintdefault(node, "height", 900);
-	type->fb_width  = w = prom_getintdefault(node, "width", 1152);
-sizechange:
-	type->fb_depth  = depth = (fbtype == FBTYPE_SUN2BW) ? 1 : 8;
-	linebytes = prom_getintdefault(node, "linebytes", w * depth / 8);
-	type->fb_size   = PAGE_ALIGN((linebytes) * h);
-	
-	if (defx_margin < 0 || defy_margin < 0) {
-		for (margin = 0; def_margins[margin].depth; margin++)
-			if (w == def_margins[margin].xres &&
-			    h == def_margins[margin].yres &&
-			    depth == def_margins[margin].depth) {
-				fb->x_margin = def_margins[margin].x_margin;
-				fb->y_margin = def_margins[margin].y_margin;
-				break;
-			}
-	} else {
-		fb->x_margin = defx_margin;
-		fb->y_margin = defy_margin;
-	}
-	fb->x_margin += ((w - 2*fb->x_margin) & 7) / 2;
-	fb->y_margin += ((h - 2*fb->y_margin) & 15) / 2;
-
-	var->xres_virtual = w;
-	var->yres_virtual = h;
-	var->xres = w - 2*fb->x_margin;
-	var->yres = h - 2*fb->y_margin;
-	
-	var->bits_per_pixel = depth;
-	var->height = var->width = -1;
-	var->pixclock = 10000;
-	var->vmode = FB_VMODE_NONINTERLACED;
-	var->red.length = var->green.length = var->blue.length = 8;
-
-	fix->line_length = linebytes;
-	fix->smem_len = type->fb_size;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	
-	fb->info.node = NODEV;
-	fb->info.fbops = &sbusfb_ops;
-	fb->info.disp = disp;
-	fb->info.currcon = -1;
-	strcpy(fb->info.fontname, fontname);
-	fb->info.changevar = NULL;
-	fb->info.switch_con = &sbusfbcon_switch;
-	fb->info.updatevar = &sbusfbcon_updatevar;
-	fb->info.flags = FBINFO_FLAG_DEFAULT;
-	
-	fb->cursor.hwsize.fbx = 32;
-	fb->cursor.hwsize.fby = 32;
-	
-	if (depth > 1 && !fb->color_map)
-		fb->color_map = kmalloc(256 * 3, GFP_ATOMIC);
-		
-	switch(fbtype) {
-#ifdef CONFIG_FB_CREATOR
-	case FBTYPE_CREATOR:
-		p = creatorfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGSIX
-	case FBTYPE_SUNFAST_COLOR:
-		p = cgsixfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGTHREE
-	case FBTYPE_SUN3COLOR:
-		p = cgthreefb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_TCX
-	case FBTYPE_TCXCOLOR:
-		p = tcxfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_LEO
-	case FBTYPE_SUNLEO:
-		p = leofb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_BWTWO
-	case FBTYPE_SUN2BW:
-		p = bwtwofb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_CGFOURTEEN
-	case FBTYPE_MDICOLOR:
-		p = cgfourteenfb_init(fb); break;
-#endif
-#ifdef CONFIG_FB_P9100
-	case FBTYPE_P9100COLOR:
-		/* Temporary crock. For now we are a cg3 */
-		p = p9100fb_init(fb); type->fb_type = FBTYPE_SUN3COLOR; break;
-#endif
-	}
-	
-	if (!p) {
-		if (fb->color_map)
-			kfree(fb->color_map);
-		kfree(fb);
-		return;
-	}
-	
-	if (p == SBUSFBINIT_SIZECHANGE)
-		goto sizechange;
-
-	disp->dispsw = &fb->dispsw;
-	if (fb->setcursor) {
-		fb->dispsw.cursor = sbusfb_cursor;
-		if (curblink) {
-			fb->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
-			init_timer(&fb->cursor.timer);
-			fb->cursor.timer.expires = jiffies + fb->cursor.blink_rate;
-			fb->cursor.timer.data = (unsigned long)fb;
-			fb->cursor.timer.function = sbusfb_cursor_timer_handler;
-			add_timer(&fb->cursor.timer);
-		}
-	}
-	fb->cursor.mode = CURSOR_SHAPE;
-	fb->dispsw.set_font = sbusfb_set_font;
-	fb->setup = fb->dispsw.setup;
-	fb->dispsw.setup = sbusfb_disp_setup;
-	fb->dispsw.clear_margins = NULL;
-
-	disp->var = *var;
-	
-	if (fb->blank)
-		disp->can_soft_blank = 1;
-
-	sbusfb_set_var(var, -1, &fb->info);
-
-	if (register_framebuffer(&fb->info) < 0) {
-		if (fb->color_map)
-			kfree(fb->color_map);
-		kfree(fb);
-		return;
-	}
-	printk(KERN_INFO "fb%d: %s\n", minor(fb->info.node), p);
-}
-
-static inline int known_card(char *name)
-{
-	char *p;
-	for (p = name; *p && *p != ','; p++);
-	if (*p == ',') name = p + 1;
-	if (!strcmp(name, "cgsix") || !strcmp(name, "cgthree+"))
-		return FBTYPE_SUNFAST_COLOR;
-	if (!strcmp(name, "cgthree") || !strcmp(name, "cgRDI"))
-		return FBTYPE_SUN3COLOR;
-	if (!strcmp(name, "cgfourteen"))
-		return FBTYPE_MDICOLOR;
-	if (!strcmp(name, "leo"))
-		return FBTYPE_SUNLEO;
-	if (!strcmp(name, "bwtwo"))
-		return FBTYPE_SUN2BW;
-	if (!strcmp(name, "tcx"))
-		return FBTYPE_TCXCOLOR;
-	if (!strcmp(name, "p9100"))
-		return FBTYPE_P9100COLOR;
-	return FBTYPE_NOTYPE;
-}
-
-#ifdef CONFIG_FB_CREATOR
-static void creator_fb_scan_siblings(int root)
-{
-	int node, child;
-
-	child = prom_getchild(root);
-	for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
-	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
-		sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL);
-	for (node = prom_searchsiblings(child, "SUNW,afb"); node;
-	     node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
-		sbusfb_init_fb(node, root, FBTYPE_CREATOR, NULL);
-}
-
-static void creator_fb_scan(void)
-{
-	int root;
-
-	creator_fb_scan_siblings(prom_root_node);
-
-	root = prom_getchild(prom_root_node);
-	for (root = prom_searchsiblings(root, "upa"); root;
-	     root = prom_searchsiblings(prom_getsibling(root), "upa"))
-		creator_fb_scan_siblings(root);
-}
-#endif
-
-int __init sbusfb_init(void)
-{
-	int type;
-	struct sbus_dev *sbdp;
-	struct sbus_bus *sbus;
-	char prom_name[40];
-	extern int con_is_present(void);
-	
-	if (!con_is_present()) return -ENXIO;
-	
-#ifdef CONFIG_FB_CREATOR
-	creator_fb_scan();
-#endif
-#ifdef CONFIG_SUN4
-	sbusfb_init_fb(0, 0, FBTYPE_SUN2BW, NULL);
-#endif
-#if defined(CONFIG_FB_CGFOURTEEN) && !defined(__sparc_v9__)
-	{
-		int root, node;
-		root = prom_getchild(prom_root_node);
-		root = prom_searchsiblings(root, "obio");
-		if (root && 
-		    (node = prom_searchsiblings(prom_getchild(root), "cgfourteen"))) {
-			sbusfb_init_fb(node, root, FBTYPE_MDICOLOR, NULL);
-		}
-	}
-#endif
-	if (sbus_root == NULL)
-		return 0;
-	for_all_sbusdev(sbdp, sbus) {
-		type = known_card(sbdp->prom_name);
-		if (type == FBTYPE_NOTYPE)
-			continue;
-		if (prom_getproperty(sbdp->prom_node, "emulation",
-				     prom_name, sizeof(prom_name)) > 0) {
-			type = known_card(prom_name);
-			if (type == FBTYPE_NOTYPE)
-				type = known_card(sbdp->prom_name);
-		}
-		sbusfb_init_fb(sbdp->prom_node, sbdp->bus->prom_node, type, sbdp);
-	}
-	return 0;
-}
-
-MODULE_LICENSE("GPL");	
diff -urN linux-2.5.63-bk6/drivers/video/sbuslib.c linux-2.5.63-bk7/drivers/video/sbuslib.c
--- linux-2.5.63-bk6/drivers/video/sbuslib.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/sbuslib.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,85 @@
+/* sbuslib.c: Helper library for SBUS framebuffer drivers.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/oplib.h>
+
+#include "sbuslib.h"
+
+void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp)
+{
+	memset(var, 0, sizeof(*var));
+
+	var->xres = prom_getintdefault(prom_node, "width", 1152);
+	var->yres = prom_getintdefault(prom_node, "height", 900);
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres;
+	var->bits_per_pixel = bpp;
+}
+
+EXPORT_SYMBOL(sbusfb_fill_var);
+
+static unsigned long sbusfb_mmapsize(long size, unsigned long fbsize)
+{
+	if (size == SBUS_MMAP_EMPTY) return 0;
+	if (size >= 0) return size;
+	return fbsize * (-size);
+}
+
+int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+		       unsigned long physbase,
+		       unsigned long fbsize,
+		       unsigned long iospace,
+		       struct vm_area_struct *vma)
+{
+	unsigned int size, page, r, map_size;
+	unsigned long map_offset = 0;
+	unsigned long off;
+	int i;
+                                        
+	size = vma->vm_end - vma->vm_start;
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= (VM_SHM | VM_IO | VM_LOCKED);
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		map_size = 0;
+		for (i = 0; map[i].size; i++)
+			if (map[i].voff == off+page) {
+				map_size = sbusfb_mmapsize(map[i].size, fbsize);
+#ifdef __sparc_v9__
+#define POFF_MASK	(PAGE_MASK|0x1UL)
+#else
+#define POFF_MASK	(PAGE_MASK)
+#endif				
+				map_offset = (physbase + map[i].poff) & POFF_MASK;
+				break;
+			}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range(vma,
+					vma->vm_start + page,
+					map_offset, map_size,
+					vma->vm_page_prot, iospace);
+		if (r)
+			return -EAGAIN;
+		page += map_size;
+	}
+
+	return 0;
+}
diff -urN linux-2.5.63-bk6/drivers/video/sbuslib.h linux-2.5.63-bk7/drivers/video/sbuslib.h
--- linux-2.5.63-bk6/drivers/video/sbuslib.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/sbuslib.h	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,21 @@
+/* sbuslib.h: SBUS fb helper library interfaces */
+#ifndef _SBUSLIB_H
+#define _SBUSLIB_H
+
+struct sbus_mmap_map {
+	unsigned long voff;
+	unsigned long poff;
+	unsigned long size;
+};
+
+#define SBUS_MMAP_FBSIZE(n) (-n)
+#define SBUS_MMAP_EMPTY	0x80000000
+
+extern void sbusfb_fill_var(struct fb_var_screeninfo *var, int prom_node, int bpp);
+struct vm_area_struct;
+extern int sbusfb_mmap_helper(struct sbus_mmap_map *map,
+			      unsigned long physbase, unsigned long fbsize,
+			      unsigned long iospace,
+			      struct vm_area_struct *vma);
+
+#endif /* _SBUSLIB_H */
diff -urN linux-2.5.63-bk6/drivers/video/tcx.c linux-2.5.63-bk7/drivers/video/tcx.c
--- linux-2.5.63-bk6/drivers/video/tcx.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/drivers/video/tcx.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,493 @@
+/* tcx.c: TCX frame buffer driver
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ *
+ * Driver layout based loosely on tgafb.c, see that file for credits.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/oplib.h>
+#include <asm/fbio.h>
+
+#include "sbuslib.h"
+
+/*
+ * Local functions.
+ */
+
+static int tcx_check_var(struct fb_var_screeninfo *, struct fb_info *);
+static int tcx_set_par(struct fb_info *);
+static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned,
+			 unsigned, struct fb_info *);
+static int tcx_blank(int, struct fb_info *);
+
+static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
+
+/*
+ *  Frame buffer operations
+ */
+
+static struct fb_ops tcx_ops = {
+	.owner			= THIS_MODULE,
+	.fb_check_var		= tcx_check_var,
+	.fb_set_par		= tcx_set_par,
+	.fb_setcolreg		= tcx_setcolreg,
+	.fb_blank		= tcx_blank,
+	.fb_fillrect		= cfb_fillrect,
+	.fb_copyarea		= cfb_copyarea,
+	.fb_imageblit		= cfb_imageblit,
+	.fb_mmap		= tcx_mmap,
+	.fb_cursor		= soft_cursor,
+};
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT       16
+#define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
+#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
+#define TCX_THC_MISC_RESET           (1 << 12)
+#define TCX_THC_MISC_VIDEO           (1 << 10)
+#define TCX_THC_MISC_SYNC            (1 << 9)
+#define TCX_THC_MISC_VSYNC           (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
+#define TCX_THC_MISC_CURS_RES        (1 << 6)
+#define TCX_THC_MISC_INT_ENAB        (1 << 5)
+#define TCX_THC_MISC_INT             (1 << 4)
+#define TCX_THC_MISC_INIT            0x9f
+#define TCX_THC_REV_REV_SHIFT        20
+#define TCX_THC_REV_REV_MASK         15
+#define TCX_THC_REV_MINREV_SHIFT     28
+#define TCX_THC_REV_MINREV_MASK      15
+
+/* The contents are unknown */
+struct tcx_tec {
+	volatile u32 tec_matrix;
+	volatile u32 tec_clip;
+	volatile u32 tec_vdc;
+};
+
+struct tcx_thc {
+	volatile u32 thc_rev;
+        u32 thc_pad0[511];
+	volatile u32 thc_hs;		/* hsync timing */
+	volatile u32 thc_hsdvs;
+	volatile u32 thc_hd;
+	volatile u32 thc_vs;		/* vsync timing */
+	volatile u32 thc_vd;
+	volatile u32 thc_refresh;
+	volatile u32 thc_misc;
+	u32 thc_pad1[56];
+	volatile u32 thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile u32 thc_cursmask[32];	/* cursor mask bits */
+	volatile u32 thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct bt_regs {
+	volatile u32 addr;
+	volatile u32 color_map;
+	volatile u32 control;
+	volatile u32 cursor;
+};
+
+#define TCX_MMAP_ENTRIES 14
+
+struct tcx_par {
+	spinlock_t		lock;
+	struct bt_regs		*bt;
+	struct tcx_thc		*thc;
+	struct tcx_tec		*tec;
+	volatile u32		*cplane;
+
+	u32			flags;
+#define TCX_FLAG_BLANKED	0x00000001
+
+	unsigned long		physbase;
+	unsigned long		fbsize;
+
+	struct sbus_mmap_map	mmap_map[TCX_MMAP_ENTRIES];
+	int			lowdepth;
+
+	struct sbus_dev		*sdev;
+	struct list_head	list;
+};
+
+/* Reset control plane so that WID is 8-bit plane. */
+static void __tcx_set_control_plane (struct tcx_par *par)
+{
+	volatile u32 *p, *pend;
+        
+	if (par->lowdepth)
+		return;
+
+	p = par->cplane;
+	if (p == NULL)
+		return;
+	for (pend = p + par->fbsize; p < pend; p++) {
+		u32 tmp = sbus_readl(p);
+
+		tmp &= 0xffffff;
+		sbus_writel(tmp, p);
+	}
+}
+                                                
+static void tcx_reset (struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	unsigned long flags;
+
+	spin_lock_irqsave(&par->lock, flags);
+	__tcx_set_control_plane(par);
+	spin_unlock_irqrestore(&par->lock, flags);
+}
+
+/**
+ *      tcx_check_var - Optional function.  Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int tcx_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->bits_per_pixel != 8)
+		return -EINVAL;
+
+	if (var->xres_virtual != var->xres || var->yres_virtual != var->yres)
+		return -EINVAL;
+	if (var->nonstd)
+		return -EINVAL;
+	if ((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+		return -EINVAL;
+
+	if (var->xres != info->var.xres || var->yres != info->var.yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+/**
+ *      tcx_set_par - Optional function.  Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tcx_set_par(struct fb_info *info)
+{
+	return 0;
+}
+
+/**
+ *      tcx_setcolreg - Optional function. Sets a color register.
+ *      @regno: boolean, 0 copy local, 1 get_user() function
+ *      @red: frame buffer colormap structure
+ *      @green: The green value which can be up to 16 bits wide
+ *      @blue:  The blue value which can be up to 16 bits wide.
+ *      @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ */
+static int tcx_setcolreg(unsigned regno,
+			 unsigned red, unsigned green, unsigned blue,
+			 unsigned transp, struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	struct bt_regs *bt = par->bt;
+	unsigned long flags;
+
+	if (regno >= 256)
+		return 1;
+
+	red >>= 8;
+	green >>= 8;
+	blue >>= 8;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	sbus_writel(regno << 24, &bt->addr);
+	sbus_writel(red << 24, &bt->color_map);
+	sbus_writel(green << 24, &bt->color_map);
+	sbus_writel(blue << 24, &bt->color_map);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+/**
+ *      tcx_blank - Optional function.  Blanks the display.
+ *      @blank_mode: the blank mode we want.
+ *      @info: frame buffer structure that represents a single frame buffer
+ */
+static int
+tcx_blank(int blank, struct fb_info *info)
+{
+	struct tcx_par *par = (struct tcx_par *) info->par;
+	struct tcx_thc *thc = par->thc;
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&par->lock, flags);
+
+	val = sbus_readl(&thc->thc_misc);
+
+	switch (blank) {
+	case 0: /* Unblanking */
+		val &= ~(TCX_THC_MISC_VSYNC_DIS |
+			 TCX_THC_MISC_HSYNC_DIS);
+		val |= TCX_THC_MISC_VIDEO;
+		par->flags &= ~TCX_FLAG_BLANKED;
+		break;
+
+	case 1: /* Normal blanking */
+		val &= ~TCX_THC_MISC_VIDEO;
+		par->flags |= TCX_FLAG_BLANKED;
+		break;
+
+	case 2: /* VESA blank (vsync off) */
+		val |= TCX_THC_MISC_VSYNC_DIS;
+		break;
+	case 3: /* VESA blank (hsync off) */
+		val |= TCX_THC_MISC_HSYNC_DIS;
+		break;
+
+	case 4: /* Poweroff */
+		break;
+	};
+
+	sbus_writel(val, &thc->thc_misc);
+
+	spin_unlock_irqrestore(&par->lock, flags);
+
+	return 0;
+}
+
+static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = {
+	{ TCX_RAM8BIT,		0,		SBUS_MMAP_FBSIZE(1) },
+	{ TCX_RAM24BIT,		0,		SBUS_MMAP_FBSIZE(4) },
+	{ TCX_UNK3,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_UNK4,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_CONTROLPLANE,	0,		SBUS_MMAP_FBSIZE(4) },
+	{ TCX_UNK6,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_UNK7,		0,		SBUS_MMAP_FBSIZE(8) },
+	{ TCX_TEC,		0,		PAGE_SIZE	    },
+	{ TCX_BTREGS,		0,		PAGE_SIZE	    },
+	{ TCX_THC,		0,		PAGE_SIZE	    },
+	{ TCX_DHC,		0,		PAGE_SIZE	    },
+	{ TCX_ALT,		0,		PAGE_SIZE	    },
+	{ TCX_UNK2,		0,		0x20000		    },
+	{ 0,			0,		0		    }
+};
+
+static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+{
+	struct tcx_par *par = (struct tcx_par *)info->par;
+
+	return sbusfb_mmap_helper(par->mmap_map,
+				  par->physbase, par->fbsize,
+				  par->sdev->reg_addrs[0].which_io,
+				  vma);
+}
+
+/*
+ *  Initialisation
+ */
+
+static void
+tcx_init_fix(struct fb_info *info, int linebytes)
+{
+	struct tcx_par *par = (struct tcx_par *)info->par;
+	const char *tcx_name;
+
+	if (par->lowdepth)
+		tcx_name = "TCX8";
+	else
+		tcx_name = "TCX24";
+
+	strncpy(info->fix.id, tcx_name, sizeof(info->fix.id) - 1);
+	info->fix.id[sizeof(info->fix.id)-1] = 0;
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+	info->fix.line_length = linebytes;
+
+	info->fix.accel = FB_ACCEL_SUN_TCX;
+}
+
+struct all_info {
+	struct fb_info info;
+	struct tcx_par par;
+	struct list_head list;
+};
+static LIST_HEAD(tcx_list);
+
+static void tcx_init_one(struct sbus_dev *sdev)
+{
+	struct all_info *all;
+	int linebytes, i;
+
+	all = kmalloc(sizeof(*all), GFP_KERNEL);
+	if (!all) {
+		printk(KERN_ERR "tcx: Cannot allocate memory.\n");
+		return;
+	}
+	memset(all, 0, sizeof(*all));
+
+	INIT_LIST_HEAD(&all->list);
+
+	spin_lock_init(&all->par.lock);
+	all->par.sdev = sdev;
+
+	all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit");
+
+	sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+
+	linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
+				       all->info.var.xres);
+	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+
+	all->par.tec = (struct tcx_tec *)
+		sbus_ioremap(&sdev->resource[7], 0,
+			     sizeof(struct tcx_tec), "tcx tec");
+	all->par.thc = (struct tcx_thc *)
+		sbus_ioremap(&sdev->resource[9], 0,
+			     sizeof(struct tcx_thc), "tcx thc");
+	all->par.bt = (struct bt_regs *)
+		sbus_ioremap(&sdev->resource[8], 0,
+			     sizeof(struct bt_regs), "tcx dac");
+	memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
+	if (!all->par.lowdepth) {
+		all->par.cplane = (volatile u32 *)
+			sbus_ioremap(&sdev->resource[4], 0,
+				     all->par.fbsize * sizeof(u32), "tcx cplane");
+	} else {
+		all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[5].size = SBUS_MMAP_EMPTY;
+		all->par.mmap_map[6].size = SBUS_MMAP_EMPTY;
+	}
+
+	all->par.physbase = 0;
+	for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
+		int j;
+
+		switch (i) {
+		case 10:
+			j = 12;
+			break;
+
+		case 11: case 12:
+			j = i - 1;
+			break;
+
+		default:
+			j = i;
+			break;
+		};
+		all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr;
+	}
+
+	all->info.node = NODEV;
+	all->info.flags = FBINFO_FLAG_DEFAULT;
+	all->info.fbops = &tcx_ops;
+#ifdef CONFIG_SPARC32
+	all->info.screen_base = (char *)
+		prom_getintdefault(sdev->prom_node, "address", 0);
+#endif
+	if (!all->info.screen_base)
+		all->info.screen_base = (char *)
+			sbus_ioremap(&sdev->resource[0], 0,
+				     all->par.fbsize, "tcx ram");
+	all->info.currcon = -1;
+	all->info.par = &all->par;
+
+	/* Initialize brooktree DAC. */
+	sbus_writel(0x04 << 24, &all->par.bt->addr);         /* color planes */
+	sbus_writel(0xff << 24, &all->par.bt->control);
+	sbus_writel(0x05 << 24, &all->par.bt->addr);
+	sbus_writel(0x00 << 24, &all->par.bt->control);
+	sbus_writel(0x06 << 24, &all->par.bt->addr);         /* overlay plane */
+	sbus_writel(0x73 << 24, &all->par.bt->control);
+	sbus_writel(0x07 << 24, &all->par.bt->addr);
+	sbus_writel(0x00 << 24, &all->par.bt->control);
+
+	tcx_reset(&all->info);
+
+	tcx_blank(0, &all->info);
+
+	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
+		printk(KERN_ERR "tcx: Could not allocate color map.\n");
+		kfree(all);
+		return;
+	}
+
+	tcx_set_par(&all->info);
+	tcx_init_fix(&all->info, linebytes);
+
+	if (register_framebuffer(&all->info) < 0) {
+		printk(KERN_ERR "tcx: Could not register framebuffer.\n");
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+		return;
+	}
+
+	list_add(&all->list, &tcx_list);
+
+	printk("tcx: %s at %lx:%lx, %s\n",
+	       sdev->prom_name,
+	       (long) sdev->reg_addrs[0].which_io,
+	       (long) sdev->reg_addrs[0].phys_addr,
+	       all->par.lowdepth ? "8-bit only" : "24-bit depth");
+}
+
+int __init tcx_init(void)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+
+	for_all_sbusdev(sdev, sbus) {
+		if (!strcmp(sdev->prom_name, "tcx"))
+			tcx_init_one(sdev);
+	}
+
+	return 0;
+}
+
+void __exit tcx_exit(void)
+{
+	struct list_head *pos, *tmp;
+
+	list_for_each_safe(pos, tmp, &tcx_list) {
+		struct all_info *all = list_entry(pos, typeof(*all), list);
+
+		unregister_framebuffer(&all->info);
+		fb_dealloc_cmap(&all->info.cmap);
+		kfree(all);
+	}
+}
+
+int __init
+tcx_setup(char *arg)
+{
+	/* No cmdline options yet... */
+	return 0;
+}
+
+#ifdef MODULE
+module_init(tcx_init);
+module_exit(tcx_exit);
+#endif
+
+MODULE_DESCRIPTION("framebuffer driver for TCX chipsets");
+MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/drivers/video/tcxfb.c linux-2.5.63-bk7/drivers/video/tcxfb.c
--- linux-2.5.63-bk6/drivers/video/tcxfb.c	Mon Feb 24 11:05:10 2003
+++ linux-2.5.63-bk7/drivers/video/tcxfb.c	Wed Dec 31 16:00:00 1969
@@ -1,368 +0,0 @@
-/* $Id: tcxfb.c,v 1.13 2001/09/19 00:04:33 davem Exp $
- * tcxfb.c: TCX 24/8bit frame buffer driver
- *
- * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/selection.h>
-
-#include <video/sbusfb.h>
-#include <asm/io.h>
-#include <asm/sbus.h>
-
-#include <video/fbcon-cfb8.h>
-
-/* THC definitions */
-#define TCX_THC_MISC_REV_SHIFT       16
-#define TCX_THC_MISC_REV_MASK        15
-#define TCX_THC_MISC_VSYNC_DIS       (1 << 25)
-#define TCX_THC_MISC_HSYNC_DIS       (1 << 24)
-#define TCX_THC_MISC_RESET           (1 << 12)
-#define TCX_THC_MISC_VIDEO           (1 << 10)
-#define TCX_THC_MISC_SYNC            (1 << 9)
-#define TCX_THC_MISC_VSYNC           (1 << 8)
-#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
-#define TCX_THC_MISC_CURS_RES        (1 << 6)
-#define TCX_THC_MISC_INT_ENAB        (1 << 5)
-#define TCX_THC_MISC_INT             (1 << 4)
-#define TCX_THC_MISC_INIT            0x9f
-#define TCX_THC_REV_REV_SHIFT        20
-#define TCX_THC_REV_REV_MASK         15
-#define TCX_THC_REV_MINREV_SHIFT     28
-#define TCX_THC_REV_MINREV_MASK      15
-
-/* The contents are unknown */
-struct tcx_tec {
-	volatile u32 tec_matrix;
-	volatile u32 tec_clip;
-	volatile u32 tec_vdc;
-};
-
-struct tcx_thc {
-	volatile u32 thc_rev;
-        u32 thc_pad0[511];
-	volatile u32 thc_hs;		/* hsync timing */
-	volatile u32 thc_hsdvs;
-	volatile u32 thc_hd;
-	volatile u32 thc_vs;		/* vsync timing */
-	volatile u32 thc_vd;
-	volatile u32 thc_refresh;
-	volatile u32 thc_misc;
-	u32 thc_pad1[56];
-	volatile u32 thc_cursxy;	/* cursor x,y position (16 bits each) */
-	volatile u32 thc_cursmask[32];	/* cursor mask bits */
-	volatile u32 thc_cursbits[32];	/* what to show where mask enabled */
-};
-
-static struct sbus_mmap_map tcx_mmap_map[] = {
-	{ TCX_RAM8BIT,		0,		SBUS_MMAP_FBSIZE(1) },
-	{ TCX_RAM24BIT,		0,		SBUS_MMAP_FBSIZE(4) },
-	{ TCX_UNK3,		0,		SBUS_MMAP_FBSIZE(8) },
-	{ TCX_UNK4,		0,		SBUS_MMAP_FBSIZE(8) },
-	{ TCX_CONTROLPLANE,	0,		SBUS_MMAP_FBSIZE(4) },
-	{ TCX_UNK6,		0,		SBUS_MMAP_FBSIZE(8) },
-	{ TCX_UNK7,		0,		SBUS_MMAP_FBSIZE(8) },
-	{ TCX_TEC,		0,		PAGE_SIZE	    },
-	{ TCX_BTREGS,		0,		PAGE_SIZE	    },
-	{ TCX_THC,		0,		PAGE_SIZE	    },
-	{ TCX_DHC,		0,		PAGE_SIZE	    },
-	{ TCX_ALT,		0,		PAGE_SIZE	    },
-	{ TCX_UNK2,		0,		0x20000		    },
-	{ 0,			0,		0		    }
-};
-
-static void __tcx_set_control_plane (struct fb_info_sbusfb *fb)
-{
-	u32 *p, *pend;
-        
-	p = fb->s.tcx.cplane;
-	if (p == NULL)
-		return;
-	for (pend = p + fb->type.fb_size; p < pend; p++) {
-		u32 tmp = sbus_readl(p);
-
-		tmp &= 0xffffff;
-		sbus_writel(tmp, p);
-	}
-}
-                                                
-static void tcx_switch_from_graph (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&fb->lock, flags);
-
-	/* Reset control plane to 8bit mode if necessary */
-	if (fb->open && fb->mmaped)
-		__tcx_set_control_plane (fb);
-
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
-{
-	struct bt_regs *bt = fb->s.tcx.bt;
-	unsigned long flags;
-	int i;
-                
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(index << 24, &bt->addr);
-	for (i = index; count--; i++){
-		sbus_writel(fb->color_map CM(i,0) << 24, &bt->color_map);
-		sbus_writel(fb->color_map CM(i,1) << 24, &bt->color_map);
-		sbus_writel(fb->color_map CM(i,2) << 24, &bt->color_map);
-	}
-	sbus_writel(0, &bt->addr);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_restore_palette (struct fb_info_sbusfb *fb)
-{
-	struct bt_regs *bt = fb->s.tcx.bt;
-	unsigned long flags;
-                
-	spin_lock_irqsave(&fb->lock, flags);
-	sbus_writel(0, &bt->addr);
-	sbus_writel(0xffffffff, &bt->color_map);
-	sbus_writel(0xffffffff, &bt->color_map);
-	sbus_writel(0xffffffff, &bt->color_map);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
-{
-        struct bt_regs *bt = fb->s.tcx.bt;
-	unsigned long flags;
-
-	spin_lock_irqsave(&fb->lock, flags);
-
-	/* Note the 2 << 24 is different from cg6's 1 << 24 */
-	sbus_writel(2 << 24, &bt->addr);
-	sbus_writel(red[0] << 24, &bt->cursor);
-	sbus_writel(green[0] << 24, &bt->cursor);
-	sbus_writel(blue[0] << 24, &bt->cursor);
-	sbus_writel(3 << 24, &bt->addr);
-	sbus_writel(red[1] << 24, &bt->cursor);
-	sbus_writel(green[1] << 24, &bt->cursor);
-	sbus_writel(blue[1] << 24, &bt->cursor);
-	sbus_writel(0, &bt->addr);
-
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Set cursor shape */
-static void tcx_setcurshape (struct fb_info_sbusfb *fb)
-{
-	struct tcx_thc *thc = fb->s.tcx.thc;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	for (i = 0; i < 32; i++){
-		sbus_writel(fb->cursor.bits[0][i], &thc->thc_cursmask[i]);
-		sbus_writel(fb->cursor.bits[1][i], &thc->thc_cursbits[i]);
-	}
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-/* Load cursor information */
-static void tcx_setcursor (struct fb_info_sbusfb *fb)
-{
-	struct cg_cursor *c = &fb->cursor;
-	unsigned long flags;
-	unsigned int v;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	if (c->enable)
-		v = ((c->cpos.fbx - c->chot.fbx) << 16)
-		    |((c->cpos.fby - c->chot.fby) & 0xffff);
-	else
-		/* Magic constant to turn off the cursor */
-		v = ((65536-32) << 16) | (65536-32);
-	sbus_writel(v, &fb->s.tcx.thc->thc_cursxy);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static int tcx_blank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readl(&fb->s.tcx.thc->thc_misc);
-	tmp &= ~TCX_THC_MISC_VIDEO;
-	/* This should put us in power-save */
-	tmp |= TCX_THC_MISC_VSYNC_DIS;
-        tmp |= TCX_THC_MISC_HSYNC_DIS;
-	sbus_writel(tmp, &fb->s.tcx.thc->thc_misc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static int tcx_unblank (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	tmp = sbus_readl(&fb->s.tcx.thc->thc_misc);
-	tmp &= ~TCX_THC_MISC_VSYNC_DIS;
-	tmp &= ~TCX_THC_MISC_HSYNC_DIS;
-	tmp |= TCX_THC_MISC_VIDEO;
-	sbus_writel(tmp, &fb->s.tcx.thc->thc_misc);
-	spin_unlock_irqrestore(&fb->lock, flags);
-	return 0;
-}
-
-static void tcx_reset (struct fb_info_sbusfb *fb)
-{
-	unsigned long flags;
-	u32 tmp;
-
-	spin_lock_irqsave(&fb->lock, flags);
-	if (fb->open && fb->mmaped)
-		__tcx_set_control_plane(fb);
-	
-	/* Turn off stuff in the Transform Engine. */
-	sbus_writel(0, &fb->s.tcx.tec->tec_matrix);
-	sbus_writel(0, &fb->s.tcx.tec->tec_clip);
-	sbus_writel(0, &fb->s.tcx.tec->tec_vdc);
-
-	/* Enable cursor in Brooktree DAC. */
-	sbus_writel(0x06 << 24, &fb->s.tcx.bt->addr);
-	tmp = sbus_readl(&fb->s.tcx.bt->control);
-	tmp |= 0x03 << 24;
-	sbus_writel(tmp, &fb->s.tcx.bt->control);
-	spin_unlock_irqrestore(&fb->lock, flags);
-}
-
-static void tcx_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
-{
-	fb->info.screen_base += (y_margin - fb->y_margin) * p->fb_info->fix.line_length + (x_margin - fb->x_margin);
-}
-
-static char idstring[60] __initdata = { 0 };
-
-char __init *tcxfb_init(struct fb_info_sbusfb *fb)
-{
-	struct fb_fix_screeninfo *fix = &fb->info.fix;
-	struct display *disp = &fb->disp;
-	struct fbtype *type = &fb->type;
-	struct sbus_dev *sdev = fb->sbdp;
-	unsigned long phys = sdev->reg_addrs[0].phys_addr;
-	int lowdepth, i, j;
-
-#ifndef FBCON_HAS_CFB8
-	return NULL;
-#endif
-
-	lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit");
-
-	if (lowdepth) {
-		strcpy(fb->info.modename, "TCX8");
-		strcpy(fix->id, "TCX8");
-	} else {
-		strcpy(fb->info.modename, "TCX24");
-		strcpy(fix->id, "TCX24");
-	}
-	fix->line_length = fb->info.var.xres_virtual;
-	fix->accel = FB_ACCEL_SUN_TCX;
-
-	disp->scrollmode = SCROLL_YREDRAW;
-	if (!fb->info.screen_base) {
-		fb->info.screen_base = (char *)
-			sbus_ioremap(&sdev->resource[0], 0,
-				     type->fb_size, "tcx ram");
-	}
-	fb->info.screen_base += fix->line_length * fb->y_margin + fb->x_margin;
-	fb->s.tcx.tec = (struct tcx_tec *)
-		sbus_ioremap(&sdev->resource[7], 0,
-			     sizeof(struct tcx_tec), "tcx tec");
-	fb->s.tcx.thc = (struct tcx_thc *)
-		sbus_ioremap(&sdev->resource[9], 0,
-			     sizeof(struct tcx_thc), "tcx thc");
-	fb->s.tcx.bt = (struct bt_regs *)
-		sbus_ioremap(&sdev->resource[8], 0, 
-			     sizeof(struct bt_regs), "tcx dac");
-	if (!lowdepth) {
-		fb->s.tcx.cplane = (u32 *)
-			sbus_ioremap(&sdev->resource[4], 0, 
-				     type->fb_size * sizeof(u32), "tcx cplane");
-		type->fb_depth = 24;
-		fb->switch_from_graph = tcx_switch_from_graph;
-	} else {
-		/* As there can be one tcx in a machine only, we can write directly into
-		   tcx_mmap_map */
-		tcx_mmap_map[1].size = SBUS_MMAP_EMPTY;
-		tcx_mmap_map[4].size = SBUS_MMAP_EMPTY;
-		tcx_mmap_map[5].size = SBUS_MMAP_EMPTY;
-		tcx_mmap_map[6].size = SBUS_MMAP_EMPTY;
-	}
-	fb->dispsw = fbcon_cfb8;
-
-	fb->margins = tcx_margins;
-	fb->loadcmap = tcx_loadcmap;
-	if (prom_getbool (fb->prom_node, "hw-cursor")) {
-		fb->setcursor = tcx_setcursor;
-		fb->setcursormap = tcx_setcursormap;
-		fb->setcurshape = tcx_setcurshape;
-	}
-	fb->restore_palette = tcx_restore_palette;
-	fb->blank = tcx_blank;
-	fb->unblank = tcx_unblank;
-	fb->reset = tcx_reset;
-
-	fb->physbase = 0;
-	for (i = 0; i < 13; i++) {
-		/* tcx_mmap_map has to be sorted by voff, while
-		   order of phys registers from PROM differs a little
-		   bit. Here is the correction */
-		switch (i) {
-		case 10: j = 12; break;
-		case 11:
-		case 12: j = i - 1; break;
-		default: j = i; break;
-		}
-		tcx_mmap_map[i].poff = fb->sbdp->reg_addrs[j].phys_addr;
-	}
-	fb->mmap_map = tcx_mmap_map;
-
-	/* Initialize Brooktree DAC */
-	sbus_writel(0x04 << 24, &fb->s.tcx.bt->addr);         /* color planes */
-	sbus_writel(0xff << 24, &fb->s.tcx.bt->control);
-	sbus_writel(0x05 << 24, &fb->s.tcx.bt->addr);
-	sbus_writel(0x00 << 24, &fb->s.tcx.bt->control);
-	sbus_writel(0x06 << 24, &fb->s.tcx.bt->addr);         /* overlay plane */
-	sbus_writel(0x73 << 24, &fb->s.tcx.bt->control);
-	sbus_writel(0x07 << 24, &fb->s.tcx.bt->addr);
-	sbus_writel(0x00 << 24, &fb->s.tcx.bt->control);
-
-	sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s",
-		fb->iospace, phys,
-		((sbus_readl(&fb->s.tcx.thc->thc_rev) >> TCX_THC_REV_REV_SHIFT) &
-		 TCX_THC_REV_REV_MASK),
-		((sbus_readl(&fb->s.tcx.thc->thc_rev) >> TCX_THC_REV_MINREV_SHIFT) &
-		 TCX_THC_REV_MINREV_MASK),
-		lowdepth ? "8-bit only" : "24-bit depth");
-		    
-	tcx_reset(fb);
-
-	return idstring;
-}
-
-MODULE_LICENSE("GPL");
diff -urN linux-2.5.63-bk6/fs/sysfs/Makefile linux-2.5.63-bk7/fs/sysfs/Makefile
--- linux-2.5.63-bk6/fs/sysfs/Makefile	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/fs/sysfs/Makefile	Mon Mar 31 12:20:15 2003
@@ -2,4 +2,4 @@
 # Makefile for the sysfs virtual filesystem
 #
 
-obj-y		:= inode.o
+obj-y		:= inode.o file.o dir.o symlink.o mount.o bin.o
diff -urN linux-2.5.63-bk6/fs/sysfs/bin.c linux-2.5.63-bk7/fs/sysfs/bin.c
--- linux-2.5.63-bk6/fs/sysfs/bin.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/bin.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,232 @@
+/*
+ * bin.c - binary file operations for sysfs.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+
+#include "sysfs.h"
+
+static struct file_operations bin_fops;
+
+static int fill_read(struct file * file, struct sysfs_bin_buffer * buffer)
+{
+	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+
+	if (!buffer->data)
+		attr->read(kobj,buffer);
+	return buffer->size ? 0 : -ENOENT;
+}
+
+static int flush_read(struct file * file, char * userbuf, 
+		      struct sysfs_bin_buffer * buffer)
+{
+	return copy_to_user(userbuf,buffer->data + buffer->offset,buffer->count) ? 
+		-EFAULT : 0;
+}
+
+static ssize_t
+read(struct file * file, char * userbuf, size_t count, loff_t * off)
+{
+	struct sysfs_bin_buffer * buffer = file->private_data;
+	int ret;
+
+	ret = fill_read(file,buffer);
+	if (ret) 
+		goto Done;
+
+	buffer->offset = *off;
+
+	if (count > (buffer->size - *off))
+		count = buffer->size - *off;
+
+	buffer->count = count;
+
+	ret = flush_read(file,userbuf,buffer);
+	if (!ret) {
+		*off += count;
+		ret = count;
+	}
+ Done:
+	return ret;
+}
+
+int alloc_buf_data(struct sysfs_bin_buffer * buffer)
+{
+	buffer->data = kmalloc(buffer->count,GFP_KERNEL);
+	if (buffer->data) {
+		memset(buffer->data,0,buffer->count);
+		return 0;
+	} else
+		return -ENOMEM;
+}
+
+static int fill_write(struct file * file, const char * userbuf, 
+		      struct sysfs_bin_buffer * buffer)
+{
+	return copy_from_user(buffer,userbuf,buffer->count) ?
+		-EFAULT : 0;
+}
+
+static int flush_write(struct file * file, const char * userbuf, 
+		       struct sysfs_bin_buffer * buffer)
+{
+	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+
+	return attr->write(kobj,buffer);
+}
+
+static ssize_t write(struct file * file, const char * userbuf,
+		     size_t count, loff_t * off)
+{
+	struct sysfs_bin_buffer * buffer = file->private_data;
+	int ret;
+
+	if (count > PAGE_SIZE)
+		count = PAGE_SIZE;
+	buffer->count = count;
+
+	ret = alloc_buf_data(buffer);
+	if (ret)
+		goto Done;
+
+	ret = fill_write(file,userbuf,buffer);
+	if (ret)
+		goto Done;
+
+	ret = flush_write(file,userbuf,buffer);
+	if (ret > 0)
+		*off += count;
+ Done:
+	if (buffer->data) {
+		kfree(buffer->data);
+		buffer->data = NULL;
+	}
+	return ret;
+}
+
+static int check_perm(struct inode * inode, struct file * file)
+{
+	struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
+	struct bin_attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_bin_buffer * buffer;
+	int error = 0;
+
+	if (!kobj || !attr)
+		goto Einval;
+
+	/* File needs write support.
+	 * The inode's perms must say it's ok, 
+	 * and we must have a store method.
+	 */
+	if (file->f_mode & FMODE_WRITE) {
+		if (!(inode->i_mode & S_IWUGO) || !attr->write)
+			goto Eaccess;
+	}
+
+	/* File needs read support.
+	 * The inode's perms must say it's ok, and we there
+	 * must be a show method for it.
+	 */
+	if (file->f_mode & FMODE_READ) {
+		if (!(inode->i_mode & S_IRUGO) || !attr->read)
+			goto Eaccess;
+	}
+
+	buffer = kmalloc(sizeof(struct sysfs_bin_buffer),GFP_KERNEL);
+	if (buffer) {
+		memset(buffer,0,sizeof(struct sysfs_bin_buffer));
+		file->private_data = buffer;
+	} else
+		error = -ENOMEM;
+	goto Done;
+
+ Einval:
+	error = -EINVAL;
+	goto Done;
+ Eaccess:
+	error = -EACCES;
+ Done:
+	if (error && kobj)
+		kobject_put(kobj);
+	return error;
+}
+
+static int open(struct inode * inode, struct file * file)
+{
+	return check_perm(inode,file);
+}
+
+static int release(struct inode * inode, struct file * file)
+{
+	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	u8 * buffer = file->private_data;
+
+	if (kobj) 
+		kobject_put(kobj);
+	if (buffer)
+		kfree(buffer);
+	return 0;
+}
+
+static struct file_operations bin_fops = {
+	.read		= read,
+	.write		= write,
+	.llseek		= generic_file_llseek,
+	.open		= open,
+	.release	= release,
+};
+
+/**
+ *	sysfs_create_bin_file - create binary file for object.
+ *	@kobj:	object.
+ *	@attr:	attribute descriptor.
+ *
+ */
+
+int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
+{
+	struct dentry * dentry;
+	struct dentry * parent;
+	int error = 0;
+
+	if (!kobj || !attr)
+		return -EINVAL;
+
+	parent = kobj->dentry;
+
+	down(&parent->d_inode->i_sem);
+	dentry = sysfs_get_dentry(parent,attr->attr.name);
+	if (!IS_ERR(dentry)) {
+		dentry->d_fsdata = (void *)attr;
+		error = sysfs_create(dentry,
+				     (attr->attr.mode & S_IALLUGO) | S_IFREG,
+				     NULL);
+		if (!error) {
+			dentry->d_inode->i_size = attr->size;
+			dentry->d_inode->i_fop = &bin_fops;
+		}
+	} else
+		error = PTR_ERR(dentry);
+	up(&parent->d_inode->i_sem);
+	return error;
+}
+
+
+/**
+ *	sysfs_remove_bin_file - remove binary file for object.
+ *	@kobj:	object.
+ *	@attr:	attribute descriptor.
+ *
+ */
+
+int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
+{
+	sysfs_hash_and_remove(kobj->dentry,attr->attr.name);
+}
+
+EXPORT_SYMBOL(sysfs_create_bin_file);
+EXPORT_SYMBOL(sysfs_remove_bin_file);
diff -urN linux-2.5.63-bk6/fs/sysfs/dir.c linux-2.5.63-bk7/fs/sysfs/dir.c
--- linux-2.5.63-bk6/fs/sysfs/dir.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/dir.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,136 @@
+/*
+ * dir.c - Operations for sysfs directories.
+ */
+
+#undef DEBUG
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include "sysfs.h"
+
+static int init_dir(struct inode * inode)
+{
+	inode->i_op = &simple_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+
+	/* directory inodes start off with i_nlink == 2 (for "." entry) */
+	inode->i_nlink++;
+	return 0;
+}
+
+/**
+ *	sysfs_create_dir - create a directory for an object.
+ *	@parent:	parent parent object.
+ *	@kobj:		object we're creating directory for. 
+ */
+
+int sysfs_create_dir(struct kobject * kobj)
+{
+	struct dentry * dentry = NULL;
+	struct dentry * parent;
+	int error = 0;
+
+	if (!kobj)
+		return -EINVAL;
+
+	if (kobj->parent)
+		parent = kobj->parent->dentry;
+	else if (sysfs_mount && sysfs_mount->mnt_sb)
+		parent = sysfs_mount->mnt_sb->s_root;
+	else
+		return -EFAULT;
+
+	down(&parent->d_inode->i_sem);
+	dentry = sysfs_get_dentry(parent,kobj->name);
+	if (!IS_ERR(dentry)) {
+		dentry->d_fsdata = (void *)kobj;
+		kobj->dentry = dentry;
+		error = sysfs_create(dentry,(S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
+				     init_dir);
+		if (!error)
+			parent->d_inode->i_nlink++;
+	} else
+		error = PTR_ERR(dentry);
+	up(&parent->d_inode->i_sem);
+
+	return error;
+}
+
+
+
+/**
+ *	sysfs_remove_dir - remove an object's directory.
+ *	@kobj:	object. 
+ *
+ *	The only thing special about this is that we remove any files in 
+ *	the directory before we remove the directory, and we've inlined
+ *	what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_dir(struct kobject * kobj)
+{
+	struct list_head * node, * next;
+	struct dentry * dentry = dget(kobj->dentry);
+	struct dentry * parent;
+
+	if (!dentry)
+		return;
+
+	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
+	parent = dget(dentry->d_parent);
+	down(&parent->d_inode->i_sem);
+	down(&dentry->d_inode->i_sem);
+
+	list_for_each_safe(node,next,&dentry->d_subdirs) {
+		struct dentry * d = dget(list_entry(node,struct dentry,d_child));
+		/** 
+		 * Make sure dentry is still there 
+		 */
+		pr_debug(" o %s: ",d->d_name.name);
+		if (d->d_inode) {
+
+			pr_debug("removing");
+			/**
+			 * Unlink and unhash.
+			 */
+			simple_unlink(dentry->d_inode,d);
+			d_delete(d);
+
+			/**
+			 * Drop reference from initial sysfs_get_dentry().
+			 */
+			dput(d);
+		}
+		pr_debug(" done (%d)\n",atomic_read(&d->d_count));
+		/**
+		 * drop reference from dget() above.
+		 */
+		dput(d);
+	}
+
+	up(&dentry->d_inode->i_sem);
+	d_invalidate(dentry);
+	simple_rmdir(parent->d_inode,dentry);
+	d_delete(dentry);
+
+	pr_debug(" o %s removing done (%d)\n",dentry->d_name.name,
+		 atomic_read(&dentry->d_count));
+	/**
+	 * Drop reference from initial sysfs_get_dentry().
+	 */
+	dput(dentry);
+
+	/**
+	 * Drop reference from dget() on entrance.
+	 */
+	dput(dentry);
+	up(&parent->d_inode->i_sem);
+	dput(parent);
+}
+
+
+EXPORT_SYMBOL(sysfs_create_dir);
+EXPORT_SYMBOL(sysfs_remove_dir);
+
diff -urN linux-2.5.63-bk6/fs/sysfs/file.c linux-2.5.63-bk7/fs/sysfs/file.c
--- linux-2.5.63-bk6/fs/sysfs/file.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/file.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,424 @@
+/*
+ * file.c - operations for regular (text) files.
+ */
+
+#include <linux/module.h>
+#include <linux/dnotify.h>
+#include <linux/kobject.h>
+
+#include "sysfs.h"
+
+static struct file_operations sysfs_file_operations;
+
+static int init_file(struct inode * inode)
+{
+	inode->i_size = PAGE_SIZE;
+	inode->i_fop = &sysfs_file_operations;
+	return 0;
+}
+
+#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
+#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
+
+/**
+ * Subsystem file operations.
+ * These operations allow subsystems to have files that can be 
+ * read/written. 
+ */
+static ssize_t 
+subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
+{
+	struct subsystem * s = to_subsys(kobj);
+	struct subsys_attribute * sattr = to_sattr(attr);
+	ssize_t ret = 0;
+
+	if (sattr->show)
+		ret = sattr->show(s,page);
+	return ret;
+}
+
+static ssize_t 
+subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
+		  const char * page, size_t count)
+{
+	struct subsystem * s = to_subsys(kobj);
+	struct subsys_attribute * sattr = to_sattr(attr);
+	ssize_t ret = 0;
+
+	if (sattr->store)
+		ret = sattr->store(s,page,count);
+	return ret;
+}
+
+static struct sysfs_ops subsys_sysfs_ops = {
+	.show	= subsys_attr_show,
+	.store	= subsys_attr_store,
+};
+
+
+struct sysfs_buffer {
+	size_t			count;
+	loff_t			pos;
+	char			* page;
+	struct sysfs_ops	* ops;
+};
+
+
+/**
+ *	fill_read_buffer - allocate and fill buffer from object.
+ *	@file:		file pointer.
+ *	@buffer:	data buffer for file.
+ *
+ *	Allocate @buffer->page, if it hasn't been already, then call the
+ *	kobject's show() method to fill the buffer with this attribute's 
+ *	data. 
+ *	This is called only once, on the file's first read. 
+ */
+static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
+{
+	struct attribute * attr = file->f_dentry->d_fsdata;
+	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_ops * ops = buffer->ops;
+	int ret = 0;
+	size_t count;
+
+	if (!buffer->page)
+		buffer->page = (char *) __get_free_page(GFP_KERNEL);
+	if (!buffer->page)
+		return -ENOMEM;
+
+	count = ops->show(kobj,attr,buffer->page);
+	if (count >= 0)
+		buffer->count = count;
+	else
+		ret = count;
+	return ret;
+}
+
+
+/**
+ *	flush_read_buffer - push buffer to userspace.
+ *	@buffer:	data buffer for file.
+ *	@userbuf:	user-passed buffer.
+ *	@count:		number of bytes requested.
+ *	@ppos:		file position.
+ *
+ *	Copy the buffer we filled in fill_read_buffer() to userspace.
+ *	This is done at the reader's leisure, copying and advancing 
+ *	the amount they specify each time.
+ *	This may be called continuously until the buffer is empty.
+ */
+static int flush_read_buffer(struct sysfs_buffer * buffer, char * buf, 
+			     size_t count, loff_t * ppos)
+{
+	int error;
+
+	if (count > (buffer->count - *ppos))
+		count = buffer->count - *ppos;
+
+	error = copy_to_user(buf,buffer->page + *ppos,count);
+	if (!error)
+		*ppos += count;
+	return error ? -EFAULT : count;
+}
+
+/**
+ *	sysfs_read_file - read an attribute. 
+ *	@file:	file pointer.
+ *	@buf:	buffer to fill.
+ *	@count:	number of bytes to read.
+ *	@ppos:	starting offset in file.
+ *
+ *	Userspace wants to read an attribute file. The attribute descriptor
+ *	is in the file's ->d_fsdata. The target object is in the directory's
+ *	->d_fsdata.
+ *
+ *	We call fill_read_buffer() to allocate and fill the buffer from the
+ *	object's show() method exactly once (if the read is happening from
+ *	the beginning of the file). That should fill the entire buffer with
+ *	all the data the object has to offer for that attribute.
+ *	We then call flush_read_buffer() to copy the buffer to userspace
+ *	in the increments specified.
+ */
+
+static ssize_t
+sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	struct sysfs_buffer * buffer = file->private_data;
+	ssize_t retval = 0;
+
+	if (!*ppos) {
+		if ((retval = fill_read_buffer(file,buffer)))
+			return retval;
+	}
+	pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
+		 __FUNCTION__,count,*ppos,buffer->page);
+	return flush_read_buffer(buffer,buf,count,ppos);
+}
+
+
+/**
+ *	fill_write_buffer - copy buffer from userspace.
+ *	@buffer:	data buffer for file.
+ *	@userbuf:	data from user.
+ *	@count:		number of bytes in @userbuf.
+ *
+ *	Allocate @buffer->page if it hasn't been already, then
+ *	copy the user-supplied buffer into it.
+ */
+
+static int 
+fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count)
+{
+	int error;
+
+	if (!buffer->page)
+		buffer->page = (char *)__get_free_page(GFP_KERNEL);
+	if (!buffer->page)
+		return -ENOMEM;
+
+	if (count >= PAGE_SIZE)
+		count = PAGE_SIZE - 1;
+	error = copy_from_user(buffer->page,buf,count);
+	return error ? -EFAULT : count;
+}
+
+
+/**
+ *	flush_write_buffer - push buffer to kobject.
+ *	@file:		file pointer.
+ *	@buffer:	data buffer for file.
+ *
+ *	Get the correct pointers for the kobject and the attribute we're
+ *	dealing with, then call the store() method for the attribute, 
+ *	passing the buffer that we acquired in fill_write_buffer().
+ */
+
+static int 
+flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count)
+{
+	struct attribute * attr = file->f_dentry->d_fsdata;
+	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct sysfs_ops * ops = buffer->ops;
+
+	return ops->store(kobj,attr,buffer->page,count);
+}
+
+
+/**
+ *	sysfs_write_file - write an attribute.
+ *	@file:	file pointer
+ *	@buf:	data to write
+ *	@count:	number of bytes
+ *	@ppos:	starting offset
+ *
+ *	Similar to sysfs_read_file(), though working in the opposite direction.
+ *	We allocate and fill the data from the user in fill_write_buffer(),
+ *	then push it to the kobject in flush_write_buffer().
+ *	There is no easy way for us to know if userspace is only doing a partial
+ *	write, so we don't support them. We expect the entire buffer to come
+ *	on the first write. 
+ *	Hint: if you're writing a value, first read the file, modify only the
+ *	the value you're changing, then write entire buffer back. 
+ */
+
+static ssize_t
+sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	struct sysfs_buffer * buffer = file->private_data;
+
+	count = fill_write_buffer(buffer,buf,count);
+	if (count > 0)
+		count = flush_write_buffer(file,buffer,count);
+	if (count > 0)
+		*ppos += count;
+	return count;
+}
+
+static int check_perm(struct inode * inode, struct file * file)
+{
+	struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
+	struct attribute * attr = file->f_dentry->d_fsdata;
+	struct sysfs_buffer * buffer;
+	struct sysfs_ops * ops = NULL;
+	int error = 0;
+
+	if (!kobj || !attr)
+		goto Einval;
+
+	/* if the kobject has no ktype, then we assume that it is a subsystem
+	 * itself, and use ops for it.
+	 */
+	if (kobj->kset && kobj->kset->ktype)
+		ops = kobj->kset->ktype->sysfs_ops;
+	else if (kobj->ktype)
+		ops = kobj->ktype->sysfs_ops;
+	else
+		ops = &subsys_sysfs_ops;
+
+	/* No sysfs operations, either from having no subsystem,
+	 * or the subsystem have no operations.
+	 */
+	if (!ops)
+		goto Eaccess;
+
+	/* File needs write support.
+	 * The inode's perms must say it's ok, 
+	 * and we must have a store method.
+	 */
+	if (file->f_mode & FMODE_WRITE) {
+
+		if (!(inode->i_mode & S_IWUGO) || !ops->store)
+			goto Eaccess;
+
+	}
+
+	/* File needs read support.
+	 * The inode's perms must say it's ok, and we there
+	 * must be a show method for it.
+	 */
+	if (file->f_mode & FMODE_READ) {
+		if (!(inode->i_mode & S_IRUGO) || !ops->show)
+			goto Eaccess;
+	}
+
+	/* No error? Great, allocate a buffer for the file, and store it
+	 * it in file->private_data for easy access.
+	 */
+	buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
+	if (buffer) {
+		memset(buffer,0,sizeof(struct sysfs_buffer));
+		buffer->ops = ops;
+		file->private_data = buffer;
+	} else
+		error = -ENOMEM;
+	goto Done;
+
+ Einval:
+	error = -EINVAL;
+	goto Done;
+ Eaccess:
+	error = -EACCES;
+ Done:
+	if (error && kobj)
+		kobject_put(kobj);
+	return error;
+}
+
+static int sysfs_open_file(struct inode * inode, struct file * filp)
+{
+	return check_perm(inode,filp);
+}
+
+static int sysfs_release(struct inode * inode, struct file * filp)
+{
+	struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
+	struct sysfs_buffer * buffer = filp->private_data;
+
+	if (kobj) 
+		kobject_put(kobj);
+
+	if (buffer) {
+		if (buffer->page)
+			free_page((unsigned long)buffer->page);
+		kfree(buffer);
+	}
+	return 0;
+}
+
+static struct file_operations sysfs_file_operations = {
+	.read		= sysfs_read_file,
+	.write		= sysfs_write_file,
+	.llseek		= generic_file_llseek,
+	.open		= sysfs_open_file,
+	.release	= sysfs_release,
+};
+
+/**
+ *	sysfs_create_file - create an attribute file for an object.
+ *	@kobj:	object we're creating for. 
+ *	@attr:	atrribute descriptor.
+ */
+
+int sysfs_create_file(struct kobject * kobj, struct attribute * attr)
+{
+	struct dentry * dentry;
+	struct dentry * parent;
+	int error = 0;
+
+	if (!kobj || !attr)
+		return -EINVAL;
+
+	parent = kobj->dentry;
+
+	down(&parent->d_inode->i_sem);
+	dentry = sysfs_get_dentry(parent,attr->name);
+	if (!IS_ERR(dentry)) {
+		dentry->d_fsdata = (void *)attr;
+		error = sysfs_create(dentry,(attr->mode & S_IALLUGO) | S_IFREG,init_file);
+	} else
+		error = PTR_ERR(dentry);
+	up(&parent->d_inode->i_sem);
+	return error;
+}
+
+
+/**
+ * sysfs_update_file - update the modified timestamp on an object attribute.
+ * @kobj: object we're acting for.
+ * @attr: attribute descriptor.
+ *
+ * Also call dnotify for the dentry, which lots of userspace programs
+ * use.
+ */
+int sysfs_update_file(struct kobject * kobj, struct attribute * attr)
+{
+	struct dentry * dir = kobj->dentry;
+	struct dentry * victim;
+	int res = -ENOENT;
+
+	down(&dir->d_inode->i_sem);
+	victim = sysfs_get_dentry(dir, attr->name);
+	if (!IS_ERR(victim)) {
+		/* make sure dentry is really there */
+		if (victim->d_inode && 
+		    (victim->d_parent->d_inode == dir->d_inode)) {
+			victim->d_inode->i_mtime = CURRENT_TIME;
+			dnotify_parent(victim, DN_MODIFY);
+
+			/**
+			 * Drop reference from initial sysfs_get_dentry().
+			 */
+			dput(victim);
+			res = 0;
+		}
+		
+		/**
+		 * Drop the reference acquired from sysfs_get_dentry() above.
+		 */
+		dput(victim);
+	}
+	up(&dir->d_inode->i_sem);
+
+	return res;
+}
+
+
+/**
+ *	sysfs_remove_file - remove an object attribute.
+ *	@kobj:	object we're acting for.
+ *	@attr:	attribute descriptor.
+ *
+ *	Hash the attribute name and kill the victim.
+ */
+
+void sysfs_remove_file(struct kobject * kobj, struct attribute * attr)
+{
+	sysfs_hash_and_remove(kobj->dentry,attr->name);
+}
+
+
+EXPORT_SYMBOL(sysfs_create_file);
+EXPORT_SYMBOL(sysfs_remove_file);
+EXPORT_SYMBOL(sysfs_update_file);
+
diff -urN linux-2.5.63-bk6/fs/sysfs/inode.c linux-2.5.63-bk7/fs/sysfs/inode.c
--- linux-2.5.63-bk6/fs/sysfs/inode.c	Mon Feb 24 11:05:41 2003
+++ linux-2.5.63-bk7/fs/sysfs/inode.c	Mon Mar 31 12:20:15 2003
@@ -1,63 +1,32 @@
 /*
- * sysfs.c - The filesystem to export kernel objects.
+ * inode.c - basic inode and dentry operations.
  *
- * Copyright (c) 2001, 2002 Patrick Mochel
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * This is a simple, ramfs-based filesystem, designed to export kernel 
- * objects, their attributes, and the linkgaes between each other.
+ * sysfs is Copyright (c) 2001-3 Patrick Mochel
  *
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #undef DEBUG 
 
-#include <linux/list.h>
-#include <linux/init.h>
 #include <linux/pagemap.h>
-#include <linux/stat.h>
-#include <linux/fs.h>
-#include <linux/dcache.h>
 #include <linux/namei.h>
-#include <linux/module.h>
-#include <linux/slab.h>
 #include <linux/backing-dev.h>
-#include <linux/kobject.h>
-#include <linux/mount.h>
-#include <linux/dnotify.h>
-#include <asm/uaccess.h>
-
-/* Random magic number */
-#define SYSFS_MAGIC 0x62656572
-
-static struct super_operations sysfs_ops;
-static struct file_operations sysfs_file_operations;
-static struct address_space_operations sysfs_aops;
+extern struct super_block * sysfs_sb;
 
-static struct vfsmount *sysfs_mount;
+static struct address_space_operations sysfs_aops = {
+	.readpage	= simple_readpage,
+	.prepare_write	= simple_prepare_write,
+	.commit_write	= simple_commit_write
+};
 
 static struct backing_dev_info sysfs_backing_dev_info = {
 	.ra_pages	= 0,	/* No readahead */
 	.memory_backed	= 1,	/* Does not contribute to dirty memory */
 };
 
-static struct inode *sysfs_get_inode(struct super_block *sb, int mode, int dev)
+struct inode * sysfs_new_inode(mode_t mode)
 {
-	struct inode *inode = new_inode(sb);
-
+	struct inode * inode = new_inode(sysfs_sb);
 	if (inode) {
 		inode->i_mode = mode;
 		inode->i_uid = current->fsuid;
@@ -68,472 +37,43 @@
 		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 		inode->i_mapping->a_ops = &sysfs_aops;
 		inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
-		switch (mode & S_IFMT) {
-		default:
-			init_special_inode(inode, mode, dev);
-			break;
-		case S_IFREG:
-			inode->i_size = PAGE_SIZE;
-			inode->i_fop = &sysfs_file_operations;
-			break;
-		case S_IFDIR:
-			inode->i_op = &simple_dir_inode_operations;
-			inode->i_fop = &simple_dir_operations;
-
-			/* directory inodes start off with i_nlink == 2 (for "." entry) */
-			inode->i_nlink++;
-			break;
-		case S_IFLNK:
-			inode->i_op = &page_symlink_inode_operations;
-			break;
-		}
 	}
 	return inode;
 }
 
-static int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
 {
-	struct inode *inode;
 	int error = 0;
-
-	if (!dentry->d_inode) {
-		inode = sysfs_get_inode(dir->i_sb, mode, dev);
-		if (inode) {
-			d_instantiate(dentry, inode);
-			dget(dentry);
-		} else
-			error = -ENOSPC;
-	} else
-		error = -EEXIST;
-	return error;
-}
-
-static int sysfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-	int res;
-	mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
- 	res = sysfs_mknod(dir, dentry, mode, 0);
- 	if (!res)
- 		dir->i_nlink++;
-	return res;
-}
-
-static int sysfs_create(struct inode *dir, struct dentry *dentry, int mode)
-{
-	int res;
-	mode = (mode & S_IALLUGO) | S_IFREG;
- 	res = sysfs_mknod(dir, dentry, mode, 0);
-	return res;
-}
-
-static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
-{
-	struct inode *inode;
-	int error = -ENOSPC;
-
-	if (dentry->d_inode)
-		return -EEXIST;
-
-	inode = sysfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
-	if (inode) {
-		int l = strlen(symname)+1;
-		error = page_symlink(inode, symname, l);
-		if (!error) {
-			d_instantiate(dentry, inode);
-			dget(dentry);
+	struct inode * inode = NULL;
+	if (dentry) {
+		if (!dentry->d_inode) {
+			if ((inode = sysfs_new_inode(mode)))
+				goto Proceed;
+			else 
+				error = -ENOMEM;
 		} else
-			iput(inode);
-	}
-	return error;
-}
-
-#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
-#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
-
-/**
- * Subsystem file operations.
- * These operations allow subsystems to have files that can be 
- * read/written. 
- */
-static ssize_t 
-subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
-{
-	struct subsystem * s = to_subsys(kobj);
-	struct subsys_attribute * sattr = to_sattr(attr);
-	ssize_t ret = 0;
-
-	if (sattr->show)
-		ret = sattr->show(s,page);
-	return ret;
-}
-
-static ssize_t 
-subsys_attr_store(struct kobject * kobj, struct attribute * attr, 
-		  const char * page, size_t count)
-{
-	struct subsystem * s = to_subsys(kobj);
-	struct subsys_attribute * sattr = to_sattr(attr);
-	ssize_t ret = 0;
-
-	if (sattr->store)
-		ret = sattr->store(s,page,count);
-	return ret;
-}
-
-static struct sysfs_ops subsys_sysfs_ops = {
-	.show	= subsys_attr_show,
-	.store	= subsys_attr_store,
-};
-
-
-struct sysfs_buffer {
-	size_t			count;
-	loff_t			pos;
-	char			* page;
-	struct sysfs_ops	* ops;
-};
-
-
-/**
- *	fill_read_buffer - allocate and fill buffer from object.
- *	@file:		file pointer.
- *	@buffer:	data buffer for file.
- *
- *	Allocate @buffer->page, if it hasn't been already, then call the
- *	kobject's show() method to fill the buffer with this attribute's 
- *	data. 
- *	This is called only once, on the file's first read. 
- */
-static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
-{
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-	struct sysfs_ops * ops = buffer->ops;
-	int ret = 0;
-	ssize_t count;
-
-	if (!buffer->page)
-		buffer->page = (char *) __get_free_page(GFP_KERNEL);
-	if (!buffer->page)
-		return -ENOMEM;
-
-	count = ops->show(kobj,attr,buffer->page);
-	if (count >= 0)
-		buffer->count = count;
-	else
-		ret = count;
-	return ret;
-}
-
-
-/**
- *	flush_read_buffer - push buffer to userspace.
- *	@buffer:	data buffer for file.
- *	@userbuf:	user-passed buffer.
- *	@count:		number of bytes requested.
- *	@ppos:		file position.
- *
- *	Copy the buffer we filled in fill_read_buffer() to userspace.
- *	This is done at the reader's leisure, copying and advancing 
- *	the amount they specify each time.
- *	This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct sysfs_buffer * buffer, char * buf, 
-			     size_t count, loff_t * ppos)
-{
-	int error;
-
-	if (count > (buffer->count - *ppos))
-		count = buffer->count - *ppos;
+			error = -EEXIST;
+	} else 
+		error = -ENOENT;
+	goto Done;
 
-	error = copy_to_user(buf,buffer->page + *ppos,count);
+ Proceed:
+	if (init)
+		error = init(inode);
 	if (!error)
-		*ppos += count;
-	return error ? -EFAULT : count;
-}
-
-/**
- *	sysfs_read_file - read an attribute. 
- *	@file:	file pointer.
- *	@buf:	buffer to fill.
- *	@count:	number of bytes to read.
- *	@ppos:	starting offset in file.
- *
- *	Userspace wants to read an attribute file. The attribute descriptor
- *	is in the file's ->d_fsdata. The target object is in the directory's
- *	->d_fsdata.
- *
- *	We call fill_read_buffer() to allocate and fill the buffer from the
- *	object's show() method exactly once (if the read is happening from
- *	the beginning of the file). That should fill the entire buffer with
- *	all the data the object has to offer for that attribute.
- *	We then call flush_read_buffer() to copy the buffer to userspace
- *	in the increments specified.
- */
-
-static ssize_t
-sysfs_read_file(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
-	struct sysfs_buffer * buffer = file->private_data;
-	ssize_t retval = 0;
-
-	if (!*ppos) {
-		if ((retval = fill_read_buffer(file,buffer)))
-			return retval;
-	}
-	pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
-		 __FUNCTION__,count,*ppos,buffer->page);
-	return flush_read_buffer(buffer,buf,count,ppos);
-}
-
-
-/**
- *	fill_write_buffer - copy buffer from userspace.
- *	@buffer:	data buffer for file.
- *	@userbuf:	data from user.
- *	@count:		number of bytes in @userbuf.
- *
- *	Allocate @buffer->page if it hasn't been already, then
- *	copy the user-supplied buffer into it.
- */
-
-static int 
-fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count)
-{
-	int error;
-
-	if (!buffer->page)
-		buffer->page = (char *)__get_free_page(GFP_KERNEL);
-	if (!buffer->page)
-		return -ENOMEM;
-
-	if (count >= PAGE_SIZE)
-		count = PAGE_SIZE - 1;
-	error = copy_from_user(buffer->page,buf,count);
-	return error ? -EFAULT : count;
-}
-
-
-/**
- *	flush_write_buffer - push buffer to kobject.
- *	@file:		file pointer.
- *	@buffer:	data buffer for file.
- *
- *	Get the correct pointers for the kobject and the attribute we're
- *	dealing with, then call the store() method for the attribute, 
- *	passing the buffer that we acquired in fill_write_buffer().
- */
-
-static int 
-flush_write_buffer(struct file * file, struct sysfs_buffer * buffer, size_t count)
-{
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
-	struct sysfs_ops * ops = buffer->ops;
-
-	return ops->store(kobj,attr,buffer->page,count);
-}
-
-
-/**
- *	sysfs_write_file - write an attribute.
- *	@file:	file pointer
- *	@buf:	data to write
- *	@count:	number of bytes
- *	@ppos:	starting offset
- *
- *	Similar to sysfs_read_file(), though working in the opposite direction.
- *	We allocate and fill the data from the user in fill_write_buffer(),
- *	then push it to the kobject in flush_write_buffer().
- *	There is no easy way for us to know if userspace is only doing a partial
- *	write, so we don't support them. We expect the entire buffer to come
- *	on the first write. 
- *	Hint: if you're writing a value, first read the file, modify only the
- *	the value you're changing, then write entire buffer back. 
- */
-
-static ssize_t
-sysfs_write_file(struct file *file, const char *buf, size_t count, loff_t *ppos)
-{
-	struct sysfs_buffer * buffer = file->private_data;
-
-	count = fill_write_buffer(buffer,buf,count);
-	if (count > 0)
-		count = flush_write_buffer(file,buffer,count);
-	if (count > 0)
-		*ppos += count;
-	return count;
-}
-
-static int check_perm(struct inode * inode, struct file * file)
-{
-	struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
-	struct attribute * attr = file->f_dentry->d_fsdata;
-	struct sysfs_buffer * buffer;
-	struct sysfs_ops * ops = NULL;
-	int error = 0;
-
-	if (!kobj || !attr)
-		goto Einval;
-
-	/* if the kobject has no ktype, then we assume that it is a subsystem
-	 * itself, and use ops for it.
-	 */
-	if (kobj->kset && kobj->kset->ktype)
-		ops = kobj->kset->ktype->sysfs_ops;
-	else if (kobj->ktype)
-		ops = kobj->ktype->sysfs_ops;
+		d_instantiate(dentry, inode);
 	else
-		ops = &subsys_sysfs_ops;
-
-	/* No sysfs operations, either from having no subsystem,
-	 * or the subsystem have no operations.
-	 */
-	if (!ops)
-		goto Eaccess;
-
-	/* File needs write support.
-	 * The inode's perms must say it's ok, 
-	 * and we must have a store method.
-	 */
-	if (file->f_mode & FMODE_WRITE) {
-
-		if (!(inode->i_mode & S_IWUGO) || !ops->store)
-			goto Eaccess;
-
-	}
-
-	/* File needs read support.
-	 * The inode's perms must say it's ok, and we there
-	 * must be a show method for it.
-	 */
-	if (file->f_mode & FMODE_READ) {
-		if (!(inode->i_mode & S_IRUGO) || !ops->show)
-			goto Eaccess;
-	}
-
-	/* No error? Great, allocate a buffer for the file, and store it
-	 * it in file->private_data for easy access.
-	 */
-	buffer = kmalloc(sizeof(struct sysfs_buffer),GFP_KERNEL);
-	if (buffer) {
-		memset(buffer,0,sizeof(struct sysfs_buffer));
-		buffer->ops = ops;
-		file->private_data = buffer;
-	} else
-		error = -ENOMEM;
-	goto Done;
-
- Einval:
-	error = -EINVAL;
-	goto Done;
- Eaccess:
-	error = -EACCES;
+		iput(inode);
  Done:
-	if (error && kobj)
-		kobject_put(kobj);
 	return error;
 }
 
-static int sysfs_open_file(struct inode * inode, struct file * filp)
-{
-	return check_perm(inode,filp);
-}
-
-static int sysfs_release(struct inode * inode, struct file * filp)
-{
-	struct kobject * kobj = filp->f_dentry->d_parent->d_fsdata;
-	struct sysfs_buffer * buffer = filp->private_data;
-
-	if (kobj) 
-		kobject_put(kobj);
-
-	if (buffer) {
-		if (buffer->page)
-			free_page((unsigned long)buffer->page);
-		kfree(buffer);
-	}
-	return 0;
-}
-
-static struct file_operations sysfs_file_operations = {
-	.read		= sysfs_read_file,
-	.write		= sysfs_write_file,
-	.llseek		= generic_file_llseek,
-	.open		= sysfs_open_file,
-	.release	= sysfs_release,
-};
-
-static struct address_space_operations sysfs_aops = {
-	.readpage	= simple_readpage,
-	.prepare_write	= simple_prepare_write,
-	.commit_write	= simple_commit_write
-};
-
-static struct super_operations sysfs_ops = {
-	.statfs		= simple_statfs,
-	.drop_inode	= generic_delete_inode,
-};
-
-static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
-{
-	struct inode *inode;
-	struct dentry *root;
-
-	sb->s_blocksize = PAGE_CACHE_SIZE;
-	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-	sb->s_magic = SYSFS_MAGIC;
-	sb->s_op = &sysfs_ops;
-	inode = sysfs_get_inode(sb, S_IFDIR | 0755, 0);
-
-	if (!inode) {
-		pr_debug("%s: could not get inode!\n",__FUNCTION__);
-		return -ENOMEM;
-	}
-
-	root = d_alloc_root(inode);
-	if (!root) {
-		pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
-		iput(inode);
-		return -ENOMEM;
-	}
-	sb->s_root = root;
-	return 0;
-}
-
-static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
-	int flags, char *dev_name, void *data)
-{
-	return get_sb_single(fs_type, flags, data, sysfs_fill_super);
-}
-
-static struct file_system_type sysfs_fs_type = {
-	.owner		= THIS_MODULE,
-	.name		= "sysfs",
-	.get_sb		= sysfs_get_sb,
-	.kill_sb	= kill_litter_super,
-};
-
-static int __init sysfs_init(void)
+int sysfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-	int err;
-
-	err = register_filesystem(&sysfs_fs_type);
-	if (!err) {
-		sysfs_mount = kern_mount(&sysfs_fs_type);
-		if (IS_ERR(sysfs_mount)) {
-			printk(KERN_ERR "sysfs: could not mount!\n");
-			err = PTR_ERR(sysfs_mount);
-			sysfs_mount = NULL;
-		}
-	}
-	return err;
+	return sysfs_create(dentry, mode, NULL);
 }
 
-core_initcall(sysfs_init);
-
-
-static struct dentry * get_dentry(struct dentry * parent, const char * name)
+struct dentry * sysfs_get_dentry(struct dentry * parent, const char * name)
 {
 	struct qstr qstr;
 
@@ -543,157 +83,12 @@
 	return lookup_hash(&qstr,parent);
 }
 
-
-/**
- *	sysfs_create_dir - create a directory for an object.
- *	@parent:	parent parent object.
- *	@kobj:		object we're creating directory for. 
- */
-
-int sysfs_create_dir(struct kobject * kobj)
-{
-	struct dentry * dentry = NULL;
-	struct dentry * parent;
-	int error = 0;
-
-	if (!kobj)
-		return -EINVAL;
-
-	if (kobj->parent)
-		parent = kobj->parent->dentry;
-	else if (sysfs_mount && sysfs_mount->mnt_sb)
-		parent = sysfs_mount->mnt_sb->s_root;
-	else
-		return -EFAULT;
-
-	down(&parent->d_inode->i_sem);
-	dentry = get_dentry(parent,kobj->name);
-	if (!IS_ERR(dentry)) {
-		dentry->d_fsdata = (void *)kobj;
-		kobj->dentry = dentry;
-		error = sysfs_mkdir(parent->d_inode,dentry,
-				    (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO));
-	} else
-		error = PTR_ERR(dentry);
-	up(&parent->d_inode->i_sem);
-
-	return error;
-}
-
-
-/**
- *	sysfs_create_file - create an attribute file for an object.
- *	@kobj:	object we're creating for. 
- *	@attr:	atrribute descriptor.
- */
-
-int sysfs_create_file(struct kobject * kobj, struct attribute * attr)
-{
-	struct dentry * dentry;
-	struct dentry * parent;
-	int error = 0;
-
-	if (!kobj || !attr)
-		return -EINVAL;
-
-	parent = kobj->dentry;
-
-	down(&parent->d_inode->i_sem);
-	dentry = get_dentry(parent,attr->name);
-	if (!IS_ERR(dentry)) {
-		dentry->d_fsdata = (void *)attr;
-		error = sysfs_create(parent->d_inode,dentry,attr->mode);
-	} else
-		error = PTR_ERR(dentry);
-	up(&parent->d_inode->i_sem);
-	return error;
-}
-
-
-static int object_depth(struct kobject * kobj)
-{
-	struct kobject * p = kobj;
-	int depth = 0;
-	do { depth++; } while ((p = p->parent));
-	return depth;
-}
-
-static int object_path_length(struct kobject * kobj)
-{
-	struct kobject * p = kobj;
-	int length = 1;
-	do {
-		length += strlen(p->name) + 1;
-		p = p->parent;
-	} while (p);
-	return length;
-}
-
-static void fill_object_path(struct kobject * kobj, char * buffer, int length)
-{
-	struct kobject * p;
-
-	--length;
-	for (p = kobj; p; p = p->parent) {
-		int cur = strlen(p->name);
-
-		/* back up enough to print this bus id with '/' */
-		length -= cur;
-		strncpy(buffer + length,p->name,cur);
-		*(buffer + --length) = '/';
-	}
-}
-
-/**
- *	sysfs_create_link - create symlink between two objects.
- *	@kobj:	object whose directory we're creating the link in.
- *	@target:	object we're pointing to.
- *	@name:		name of the symlink.
- */
-int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
-{
-	struct dentry * dentry = kobj->dentry;
-	struct dentry * d;
-	int error = 0;
-	int size;
-	int depth;
-	char * path;
-	char * s;
-
-	depth = object_depth(kobj);
-	size = object_path_length(target) + depth * 3 - 1;
-	if (size > PATH_MAX)
-		return -ENAMETOOLONG;
-	pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
-
-	path = kmalloc(size,GFP_KERNEL);
-	if (!path)
-		return -ENOMEM;
-	memset(path,0,size);
-
-	for (s = path; depth--; s += 3)
-		strcpy(s,"../");
-
-	fill_object_path(target,path,size);
-	pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
-
-	down(&dentry->d_inode->i_sem);
-	d = get_dentry(dentry,name);
-	if (!IS_ERR(d))
-		error = sysfs_symlink(dentry->d_inode,d,path);
-	else
-		error = PTR_ERR(d);
-	up(&dentry->d_inode->i_sem);
-	kfree(path);
-	return error;
-}
-
-static void hash_and_remove(struct dentry * dir, const char * name)
+void sysfs_hash_and_remove(struct dentry * dir, const char * name)
 {
 	struct dentry * victim;
 
 	down(&dir->d_inode->i_sem);
-	victim = get_dentry(dir,name);
+	victim = sysfs_get_dentry(dir,name);
 	if (!IS_ERR(victim)) {
 		/* make sure dentry is really there */
 		if (victim->d_inode && 
@@ -703,161 +98,18 @@
 
 			pr_debug("sysfs: Removing %s (%d)\n", victim->d_name.name,
 				 atomic_read(&victim->d_count));
-			/**
-			 * Drop reference from initial get_dentry().
-			 */
-			dput(victim);
-		}
-		
-		/**
-		 * Drop the reference acquired from get_dentry() above.
-		 */
-		dput(victim);
-	}
-	up(&dir->d_inode->i_sem);
-}
-
-/**
- * sysfs_update_file - update the modified timestamp on an object attribute.
- * @kobj: object we're acting for.
- * @attr: attribute descriptor.
- *
- * Also call dnotify for the dentry, which lots of userspace programs
- * use.
- */
-int sysfs_update_file(struct kobject * kobj, struct attribute * attr)
-{
-	struct dentry * dir = kobj->dentry;
-	struct dentry * victim;
-	int res = -ENOENT;
-
-	down(&dir->d_inode->i_sem);
-	victim = get_dentry(dir, attr->name);
-	if (!IS_ERR(victim)) {
-		/* make sure dentry is really there */
-		if (victim->d_inode && 
-		    (victim->d_parent->d_inode == dir->d_inode)) {
-			victim->d_inode->i_mtime = CURRENT_TIME;
-			dnotify_parent(victim, DN_MODIFY);
-
-			/**
-			 * Drop reference from initial get_dentry().
+			/*
+			 * Drop reference from initial sysfs_get_dentry().
 			 */
 			dput(victim);
-			res = 0;
 		}
 		
 		/**
-		 * Drop the reference acquired from get_dentry() above.
+		 * Drop the reference acquired from sysfs_get_dentry() above.
 		 */
 		dput(victim);
 	}
 	up(&dir->d_inode->i_sem);
-
-	return res;
 }
 
 
-/**
- *	sysfs_remove_file - remove an object attribute.
- *	@kobj:	object we're acting for.
- *	@attr:	attribute descriptor.
- *
- *	Hash the attribute name and kill the victim.
- */
-
-void sysfs_remove_file(struct kobject * kobj, struct attribute * attr)
-{
-	hash_and_remove(kobj->dentry,attr->name);
-}
-
-
-/**
- *	sysfs_remove_link - remove symlink in object's directory.
- *	@kobj:	object we're acting for.
- *	@name:	name of the symlink to remove.
- */
-
-void sysfs_remove_link(struct kobject * kobj, char * name)
-{
-	hash_and_remove(kobj->dentry,name);
-}
-
-
-/**
- *	sysfs_remove_dir - remove an object's directory.
- *	@kobj:	object. 
- *
- *	The only thing special about this is that we remove any files in 
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_dir(struct kobject * kobj)
-{
-	struct list_head * node, * next;
-	struct dentry * dentry = dget(kobj->dentry);
-	struct dentry * parent;
-
-	if (!dentry)
-		return;
-
-	pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
-	parent = dget(dentry->d_parent);
-	down(&parent->d_inode->i_sem);
-	down(&dentry->d_inode->i_sem);
-
-	list_for_each_safe(node,next,&dentry->d_subdirs) {
-		struct dentry * d = dget(list_entry(node,struct dentry,d_child));
-		/** 
-		 * Make sure dentry is still there 
-		 */
-		pr_debug(" o %s: ",d->d_name.name);
-		if (d->d_inode) {
-
-			pr_debug("removing");
-			/**
-			 * Unlink and unhash.
-			 */
-			simple_unlink(dentry->d_inode,d);
-			d_delete(d);
-
-			/**
-			 * Drop reference from initial get_dentry().
-			 */
-			dput(d);
-		}
-		pr_debug(" done (%d)\n",atomic_read(&d->d_count));
-		/**
-		 * drop reference from dget() above.
-		 */
-		dput(d);
-	}
-
-	up(&dentry->d_inode->i_sem);
-	d_invalidate(dentry);
-	simple_rmdir(parent->d_inode,dentry);
-	d_delete(dentry);
-
-	pr_debug(" o %s removing done (%d)\n",dentry->d_name.name,
-		 atomic_read(&dentry->d_count));
-	/**
-	 * Drop reference from initial get_dentry().
-	 */
-	dput(dentry);
-
-	/**
-	 * Drop reference from dget() on entrance.
-	 */
-	dput(dentry);
-	up(&parent->d_inode->i_sem);
-	dput(parent);
-}
-
-EXPORT_SYMBOL(sysfs_create_file);
-EXPORT_SYMBOL(sysfs_update_file);
-EXPORT_SYMBOL(sysfs_remove_file);
-EXPORT_SYMBOL(sysfs_create_link);
-EXPORT_SYMBOL(sysfs_remove_link);
-EXPORT_SYMBOL(sysfs_create_dir);
-EXPORT_SYMBOL(sysfs_remove_dir);
diff -urN linux-2.5.63-bk6/fs/sysfs/mount.c linux-2.5.63-bk7/fs/sysfs/mount.c
--- linux-2.5.63-bk6/fs/sysfs/mount.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/mount.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,84 @@
+/*
+ * mount.c - operations for initializing and mounting sysfs.
+ */
+
+#define DEBUG 
+
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+
+#include "sysfs.h"
+
+/* Random magic number */
+#define SYSFS_MAGIC 0x62656572
+
+struct vfsmount *sysfs_mount;
+struct super_block * sysfs_sb = NULL;
+
+static struct super_operations sysfs_ops = {
+	.statfs		= simple_statfs,
+	.drop_inode	= generic_delete_inode,
+};
+
+static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct inode *inode;
+	struct dentry *root;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = SYSFS_MAGIC;
+	sb->s_op = &sysfs_ops;
+	sysfs_sb = sb;
+
+	inode = sysfs_new_inode(S_IFDIR | S_IRUGO | S_IWUSR);
+	if (inode) {
+		inode->i_op = &simple_dir_inode_operations;
+		inode->i_fop = &simple_dir_operations;
+		/* directory inodes start off with i_nlink == 2 (for "." entry) */
+		inode->i_nlink++;	
+	} else {
+		pr_debug("sysfs: could not get root inode\n");
+		return -ENOMEM;
+	}
+
+	root = d_alloc_root(inode);
+	if (!root) {
+		pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
+		iput(inode);
+		return -ENOMEM;
+	}
+	sb->s_root = root;
+	return 0;
+}
+
+static struct super_block *sysfs_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, sysfs_fill_super);
+}
+
+static struct file_system_type sysfs_fs_type = {
+	.name		= "sysfs",
+	.get_sb		= sysfs_get_sb,
+	.kill_sb	= kill_litter_super,
+};
+
+static int __init sysfs_init(void)
+{
+	int err;
+
+	err = register_filesystem(&sysfs_fs_type);
+	if (!err) {
+		sysfs_mount = kern_mount(&sysfs_fs_type);
+		if (IS_ERR(sysfs_mount)) {
+			printk(KERN_ERR "sysfs: could not mount!\n");
+			err = PTR_ERR(sysfs_mount);
+			sysfs_mount = NULL;
+		}
+	}
+	return err;
+}
+
+core_initcall(sysfs_init);
diff -urN linux-2.5.63-bk6/fs/sysfs/symlink.c linux-2.5.63-bk7/fs/sysfs/symlink.c
--- linux-2.5.63-bk6/fs/sysfs/symlink.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/symlink.c	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,125 @@
+/*
+ * symlink.c - operations for sysfs symlinks.
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+
+#include "sysfs.h"
+
+
+static int init_symlink(struct inode * inode)
+{
+	inode->i_op = &page_symlink_inode_operations;
+	return 0;
+}
+
+static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	int error;
+
+	error = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
+	if (!error) {
+		int l = strlen(symname)+1;
+		error = page_symlink(dentry->d_inode, symname, l);
+		if (error)
+			iput(dentry->d_inode);
+	}
+	return error;
+}
+
+static int object_depth(struct kobject * kobj)
+{
+	struct kobject * p = kobj;
+	int depth = 0;
+	do { depth++; } while ((p = p->parent));
+	return depth;
+}
+
+static int object_path_length(struct kobject * kobj)
+{
+	struct kobject * p = kobj;
+	int length = 1;
+	do {
+		length += strlen(p->name) + 1;
+		p = p->parent;
+	} while (p);
+	return length;
+}
+
+static void fill_object_path(struct kobject * kobj, char * buffer, int length)
+{
+	struct kobject * p;
+
+	--length;
+	for (p = kobj; p; p = p->parent) {
+		int cur = strlen(p->name);
+
+		/* back up enough to print this bus id with '/' */
+		length -= cur;
+		strncpy(buffer + length,p->name,cur);
+		*(buffer + --length) = '/';
+	}
+}
+
+/**
+ *	sysfs_create_link - create symlink between two objects.
+ *	@kobj:	object whose directory we're creating the link in.
+ *	@target:	object we're pointing to.
+ *	@name:		name of the symlink.
+ */
+int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
+{
+	struct dentry * dentry = kobj->dentry;
+	struct dentry * d;
+	int error = 0;
+	int size;
+	int depth;
+	char * path;
+	char * s;
+
+	depth = object_depth(kobj);
+	size = object_path_length(target) + depth * 3 - 1;
+	if (size > PATH_MAX)
+		return -ENAMETOOLONG;
+	pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
+
+	path = kmalloc(size,GFP_KERNEL);
+	if (!path)
+		return -ENOMEM;
+	memset(path,0,size);
+
+	for (s = path; depth--; s += 3)
+		strcpy(s,"../");
+
+	fill_object_path(target,path,size);
+	pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
+
+	down(&dentry->d_inode->i_sem);
+	d = sysfs_get_dentry(dentry,name);
+	if (!IS_ERR(d))
+		error = sysfs_symlink(dentry->d_inode,d,path);
+	else
+		error = PTR_ERR(d);
+	up(&dentry->d_inode->i_sem);
+	kfree(path);
+	return error;
+}
+
+
+/**
+ *	sysfs_remove_link - remove symlink in object's directory.
+ *	@kobj:	object we're acting for.
+ *	@name:	name of the symlink to remove.
+ */
+
+void sysfs_remove_link(struct kobject * kobj, char * name)
+{
+	sysfs_hash_and_remove(kobj->dentry,name);
+}
+
+
+EXPORT_SYMBOL(sysfs_create_link);
+EXPORT_SYMBOL(sysfs_remove_link);
+
diff -urN linux-2.5.63-bk6/fs/sysfs/sysfs.h linux-2.5.63-bk7/fs/sysfs/sysfs.h
--- linux-2.5.63-bk6/fs/sysfs/sysfs.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/fs/sysfs/sysfs.h	Mon Mar 31 12:20:15 2003
@@ -0,0 +1,10 @@
+
+extern struct vfsmount * sysfs_mount;
+
+extern struct inode * sysfs_new_inode(mode_t mode);
+extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
+
+extern struct dentry * sysfs_get_dentry(struct dentry *, char *);
+
+extern void sysfs_hash_and_remove(struct dentry * dir, const char * name);
+
diff -urN linux-2.5.63-bk6/fs/ufs/util.h linux-2.5.63-bk7/fs/ufs/util.h
--- linux-2.5.63-bk6/fs/ufs/util.h	Mon Feb 24 11:05:32 2003
+++ linux-2.5.63-bk7/fs/ufs/util.h	Mon Mar 31 12:20:15 2003
@@ -25,7 +25,7 @@
 
 
 /*
- * macros used for accesing structures
+ * macros used for accessing structures
  */
 static inline s32
 ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1,
diff -urN linux-2.5.63-bk6/include/asm-sparc/ioctl.h linux-2.5.63-bk7/include/asm-sparc/ioctl.h
--- linux-2.5.63-bk6/include/asm-sparc/ioctl.h	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/include/asm-sparc/ioctl.h	Mon Mar 31 12:20:17 2003
@@ -2,23 +2,35 @@
 #ifndef _SPARC_IOCTL_H
 #define _SPARC_IOCTL_H
 
+/*
+ * Our DIR and SIZE overlap in order to simulteneously provide
+ * a non-zero _IOC_NONE (for binary compatibility) and
+ * 14 bits of size as on i386. Here's the layout:
+ *
+ *   0xE0000000   DIR
+ *   0x80000000     DIR = WRITE
+ *   0x40000000     DIR = READ
+ *   0x20000000     DIR = NONE
+ *   0x3FFF0000   SIZE (overlaps NONE bit)
+ *   0x0000FF00   TYPE
+ *   0x000000FF   NR (CMD)
+ */
+
 #define _IOC_NRBITS      8
 #define _IOC_TYPEBITS    8
-#define _IOC_SIZEBITS    8
-#define _IOC_RESVBITS    5
+#define _IOC_SIZEBITS   13	/* Actually 14, see below. */
 #define _IOC_DIRBITS     3
 
 #define _IOC_NRMASK      ((1 << _IOC_NRBITS)-1)
 #define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_RESVMASK    ((1 << _IOC_RESVBITS)-1)
 #define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_XSIZEMASK   ((1 << (_IOC_SIZEBITS+1))-1)
 #define _IOC_DIRMASK     ((1 << _IOC_DIRBITS)-1)
 
 #define _IOC_NRSHIFT     0
 #define _IOC_TYPESHIFT   (_IOC_NRSHIFT + _IOC_NRBITS)
 #define _IOC_SIZESHIFT   (_IOC_TYPESHIFT + _IOC_TYPEBITS)
-#define _IOC_RESVSHIFT   (_IOC_SIZESHIFT + _IOC_SIZEBITS)
-#define _IOC_DIRSHIFT    (_IOC_RESVSHIFT + _IOC_RESVBITS)
+#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT + _IOC_SIZEBITS)
 
 #define _IOC_NONE        1U
 #define _IOC_READ        2U
@@ -35,17 +47,20 @@
 #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
 
-#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+/* Used to decode ioctl numbers in drivers despite the leading underscore... */
+#define _IOC_DIR(nr)    \
+ ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)?   \
+                            (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)):  \
+                            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) )
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
-#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-/* ...and for the PCMCIA... */
+#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)
 
+/* ...and for the PCMCIA and sound. */
 #define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
 #define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
 #define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
-#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_MASK    (_IOC_XSIZEMASK << _IOC_SIZESHIFT)
 #define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC_IOCTL_H) */
diff -urN linux-2.5.63-bk6/include/asm-sparc64/hardirq.h linux-2.5.63-bk7/include/asm-sparc64/hardirq.h
--- linux-2.5.63-bk6/include/asm-sparc64/hardirq.h	Mon Feb 24 11:05:38 2003
+++ linux-2.5.63-bk7/include/asm-sparc64/hardirq.h	Mon Mar 31 12:20:17 2003
@@ -10,6 +10,7 @@
 #include <linux/threads.h>
 #include <linux/brlock.h>
 #include <linux/spinlock.h>
+#include <linux/cache.h>
 
 /* entry.S is sensitive to the offsets of these fields */
 /* rtrap.S is sensitive to the size of this structure */
diff -urN linux-2.5.63-bk6/include/asm-sparc64/ioctl.h linux-2.5.63-bk7/include/asm-sparc64/ioctl.h
--- linux-2.5.63-bk6/include/asm-sparc64/ioctl.h	Mon Feb 24 11:05:41 2003
+++ linux-2.5.63-bk7/include/asm-sparc64/ioctl.h	Mon Mar 31 12:20:17 2003
@@ -2,23 +2,35 @@
 #ifndef _SPARC64_IOCTL_H
 #define _SPARC64_IOCTL_H
 
+/*
+ * Our DIR and SIZE overlap in order to simulteneously provide
+ * a non-zero _IOC_NONE (for binary compatibility) and
+ * 14 bits of size as on i386. Here's the layout:
+ *
+ *   0xE0000000   DIR
+ *   0x80000000     DIR = WRITE
+ *   0x40000000     DIR = READ
+ *   0x20000000     DIR = NONE
+ *   0x3FFF0000   SIZE (overlaps NONE bit)
+ *   0x0000FF00   TYPE
+ *   0x000000FF   NR (CMD)
+ */
+
 #define _IOC_NRBITS      8
 #define _IOC_TYPEBITS    8
-#define _IOC_SIZEBITS    8
-#define _IOC_RESVBITS    5
+#define _IOC_SIZEBITS   13	/* Actually 14, see below. */
 #define _IOC_DIRBITS     3
 
 #define _IOC_NRMASK      ((1 << _IOC_NRBITS)-1)
 #define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_RESVMASK    ((1 << _IOC_RESVBITS)-1)
 #define _IOC_SIZEMASK    ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_XSIZEMASK   ((1 << (_IOC_SIZEBITS+1))-1)
 #define _IOC_DIRMASK     ((1 << _IOC_DIRBITS)-1)
 
 #define _IOC_NRSHIFT     0
 #define _IOC_TYPESHIFT   (_IOC_NRSHIFT + _IOC_NRBITS)
 #define _IOC_SIZESHIFT   (_IOC_TYPESHIFT + _IOC_TYPEBITS)
-#define _IOC_RESVSHIFT   (_IOC_SIZESHIFT + _IOC_SIZEBITS)
-#define _IOC_DIRSHIFT    (_IOC_RESVSHIFT + _IOC_RESVBITS)
+#define _IOC_DIRSHIFT    (_IOC_SIZESHIFT + _IOC_SIZEBITS)
 
 #define _IOC_NONE        1U
 #define _IOC_READ        2U
@@ -35,17 +47,20 @@
 #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
 #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
 
-#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+/* Used to decode ioctl numbers in drivers despite the leading underscore... */
+#define _IOC_DIR(nr)    \
+ ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)?   \
+                            (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)):  \
+                            (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) )
 #define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
 #define _IOC_NR(nr)         (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
-#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
-
-/* ...and for the PCMCIA... */
+#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)
 
+/* ...and for the PCMCIA and sound. */
 #define IOC_IN          (_IOC_WRITE << _IOC_DIRSHIFT)
 #define IOC_OUT         (_IOC_READ << _IOC_DIRSHIFT)
 #define IOC_INOUT       ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
-#define IOCSIZE_MASK    (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_MASK    (_IOC_XSIZEMASK << _IOC_SIZESHIFT)
 #define IOCSIZE_SHIFT   (_IOC_SIZESHIFT)
 
 #endif /* !(_SPARC64_IOCTL_H) */
diff -urN linux-2.5.63-bk6/include/linux/cpufreq.h linux-2.5.63-bk7/include/linux/cpufreq.h
--- linux-2.5.63-bk6/include/linux/cpufreq.h	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/include/linux/cpufreq.h	Mon Mar 31 12:20:17 2003
@@ -67,7 +67,8 @@
         unsigned int            policy; /* see above */
 	struct cpufreq_governor *governor; /* see below */
 	struct cpufreq_cpuinfo  cpuinfo;     /* see above */
-	struct intf_data        intf;   /* interface data */
+	struct device		* dev;
+	struct kobject		kobj;
 };
 
 #define CPUFREQ_ADJUST          (0)
diff -urN linux-2.5.63-bk6/include/linux/device.h linux-2.5.63-bk7/include/linux/device.h
--- linux-2.5.63-bk6/include/linux/device.h	Mon Feb 24 11:05:43 2003
+++ linux-2.5.63-bk7/include/linux/device.h	Mon Mar 31 12:20:18 2003
@@ -27,9 +27,9 @@
 #include <linux/ioport.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
-#include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include <asm/semaphore.h>
 #include <asm/atomic.h>
 
 #define DEVICE_NAME_SIZE	50
@@ -207,8 +207,6 @@
  * it supports the device.
  */
 
-struct intf_data;
-
 struct device_interface {
 	char			* name;
 	struct device_class	* devclass;
@@ -217,41 +215,19 @@
 	u32			devnum;
 
 	int (*add_device)	(struct device *);
-	int (*remove_device)	(struct intf_data *);
+	int (*remove_device)	(struct device *);
 };
 
 extern int interface_register(struct device_interface *);
 extern void interface_unregister(struct device_interface *);
 
 
-/*
- * intf_data - per-device data for an interface
- * Each interface typically has a per-device data structure 
- * that it allocates. It should embed one of these structures 
- * in that structure and call interface_add_data() to add it
- * to the device's list.
- * That will also enumerate the device within the interface
- * and create a driverfs symlink for it.
- */
-struct intf_data {
-	struct device_interface	* intf;
-	struct device		* dev;
-	u32			intf_num;
-	struct list_head	dev_entry;
-	struct kobject		kobj;
-};
-
-extern int interface_add_data(struct intf_data *);
-
-
-
 struct device {
 	struct list_head node;		/* node in sibling list */
 	struct list_head bus_list;	/* node in bus's list */
 	struct list_head class_list;
 	struct list_head driver_list;
 	struct list_head children;
-	struct list_head intf_list;
 	struct device 	* parent;
 
 	struct kobject kobj;
diff -urN linux-2.5.63-bk6/include/linux/fcdevice.h linux-2.5.63-bk7/include/linux/fcdevice.h
--- linux-2.5.63-bk6/include/linux/fcdevice.h	Mon Feb 24 11:05:14 2003
+++ linux-2.5.63-bk7/include/linux/fcdevice.h	Mon Mar 31 12:20:18 2003
@@ -31,7 +31,7 @@
 				   unsigned short type, void *daddr,
 				   void *saddr, unsigned len);
 extern int		fc_rebuild_header(struct sk_buff *skb);
-//extern unsigned short	fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
+extern unsigned short	fc_type_trans(struct sk_buff *skb, struct net_device *dev); 
 
 extern struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv);
 extern struct net_device *alloc_fcdev(int sizeof_priv);
diff -urN linux-2.5.63-bk6/include/linux/kobject.h linux-2.5.63-bk7/include/linux/kobject.h
--- linux-2.5.63-bk6/include/linux/kobject.h	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/include/linux/kobject.h	Mon Mar 31 12:20:18 2003
@@ -73,7 +73,7 @@
 
 static inline struct kset * to_kset(struct kobject * kobj)
 {
-	return container_of(kobj,struct kset,kobj);
+	return kobj ? container_of(kobj,struct kset,kobj) : NULL;
 }
 
 static inline struct kset * kset_get(struct kset * k)
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.5.63-bk7/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Feb 24 11:05:44 2003
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv4/ip_conntrack.h	Mon Mar 31 12:20:18 2003
@@ -6,6 +6,7 @@
 
 #include <linux/config.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
+#include <linux/bitops.h>
 #include <asm/atomic.h>
 
 enum ip_conntrack_info
@@ -41,6 +42,10 @@
 	/* Conntrack should never be early-expired. */
 	IPS_ASSURED_BIT = 2,
 	IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+	/* Connection is confirmed: originating packet has left box */
+	IPS_CONFIRMED_BIT = 3,
+	IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
 };
 
 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
@@ -159,7 +164,7 @@
 	struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
 
 	/* Have we seen traffic both ways yet? (bitset) */
-	volatile unsigned long status;
+	unsigned long status;
 
 	/* Timer function; drops refcnt when it goes off. */
 	struct timer_list timeout;
@@ -229,7 +234,8 @@
 /* decrement reference count on an expectation */
 void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
 
-extern struct module *ip_conntrack_module;
+/* call to create an explicit dependency on ip_conntrack. */
+extern void need_ip_conntrack(void);
 
 extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
 			  const struct ip_conntrack_tuple *orig);
@@ -254,7 +260,7 @@
 /* It's confirmed if it is, or has been in the hash table. */
 static inline int is_confirmed(struct ip_conntrack *ct)
 {
-	return ct->tuplehash[IP_CT_DIR_ORIGINAL].list.next != NULL;
+	return test_bit(IPS_CONFIRMED_BIT, &ct->status);
 }
 
 extern unsigned int ip_conntrack_htable_size;
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_ah.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_ah.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_ah.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_ah.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,30 @@
+#ifndef _IP6T_AH_H
+#define _IP6T_AH_H
+
+struct ip6t_ah
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  hdrres;			/* Test of the Reserved Filed */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define IP6T_AH_SPI 0x01
+#define IP6T_AH_LEN 0x02
+#define IP6T_AH_RES 0x04
+
+/* Values for "invflags" field in struct ip6t_ah. */
+#define IP6T_AH_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IP6T_AH_INV_LEN		0x02	/* Invert the sense of length. */
+#define IP6T_AH_INV_MASK	0x03	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_AH_H*/
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_esp.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_esp.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_esp.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_esp.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,23 @@
+#ifndef _IP6T_ESP_H
+#define _IP6T_ESP_H
+
+struct ip6t_esp
+{
+	u_int32_t spis[2];			/* Security Parameter Index */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+/* Values for "invflags" field in struct ip6t_esp. */
+#define IP6T_ESP_INV_SPI		0x01	/* Invert the sense of spi. */
+#define IP6T_ESP_INV_MASK	0x01	/* All possible flags. */
+
+#endif /*_IP6T_ESP_H*/
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_frag.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_frag.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_frag.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_frag.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,33 @@
+#ifndef _IP6T_FRAG_H
+#define _IP6T_FRAG_H
+
+struct ip6t_frag
+{
+	u_int32_t ids[2];			/* Security Parameter Index */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  flags;			/*  */
+	u_int8_t  invflags;			/* Inverse flags */
+};
+
+#define IP6T_FRAG_IDS 		0x01
+#define IP6T_FRAG_LEN 		0x02
+#define IP6T_FRAG_RES 		0x04
+#define IP6T_FRAG_FST 		0x08
+#define IP6T_FRAG_MF  		0x10
+#define IP6T_FRAG_NMF  		0x20
+
+/* Values for "invflags" field in struct ip6t_frag. */
+#define IP6T_FRAG_INV_IDS	0x01	/* Invert the sense of ids. */
+#define IP6T_FRAG_INV_LEN	0x02	/* Invert the sense of length. */
+#define IP6T_FRAG_INV_MASK	0x03	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_FRAG_H*/
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_hl.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_hl.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_hl.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_hl.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,22 @@
+/* ip6tables module for matching the Hop Limit value
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl module */
+
+#ifndef _IP6T_HL_H
+#define _IP6T_HL_H
+
+enum {
+	IP6T_HL_EQ = 0,		/* equals */
+	IP6T_HL_NE,		/* not equals */
+	IP6T_HL_LT,		/* less than */
+	IP6T_HL_GT,		/* greater than */
+};
+
+
+struct ip6t_hl_info {
+	u_int8_t	mode;
+	u_int8_t	hop_limit;
+};
+
+
+#endif
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_ipv6header.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_ipv6header.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_ipv6header.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_ipv6header.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,27 @@
+/* ipv6header match - matches IPv6 packets based
+on whether they contain certain headers */
+
+/* Original idea: Brad Chapman 
+ * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
+
+
+#ifndef __IPV6HEADER_H
+#define __IPV6HEADER_H
+
+struct ip6t_ipv6header_info
+{
+	u_int8_t matchflags;
+	u_int8_t invflags;
+	u_int8_t modeflag;
+};
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /* __IPV6HEADER_H */
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_opts.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_opts.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_opts.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_opts.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,32 @@
+#ifndef _IP6T_OPTS_H
+#define _IP6T_OPTS_H
+
+#define IP6T_OPTS_OPTSNR 16
+
+struct ip6t_opts
+{
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t flags;				/*  */
+	u_int8_t invflags;			/* Inverse flags */
+	u_int16_t opts[IP6T_OPTS_OPTSNR];	/* opts */
+	u_int8_t optsnr;			/* Nr of OPts */
+};
+
+#define IP6T_OPTS_LEN 		0x01
+#define IP6T_OPTS_OPTS 		0x02
+#define IP6T_OPTS_NSTRICT	0x04
+
+/* Values for "invflags" field in struct ip6t_rt. */
+#define IP6T_OPTS_INV_LEN	0x01	/* Invert the sense of length. */
+#define IP6T_OPTS_INV_MASK	0x01	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_OPTS_H*/
diff -urN linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_rt.h linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_rt.h
--- linux-2.5.63-bk6/include/linux/netfilter_ipv6/ip6t_rt.h	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/include/linux/netfilter_ipv6/ip6t_rt.h	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,42 @@
+#ifndef _IP6T_RT_H
+#define _IP6T_RT_H
+
+/*#include <linux/in6.h>*/
+
+#define IP6T_RT_HOPS 16
+
+struct ip6t_rt
+{
+	u_int32_t rt_type;			/* Routing Type */
+	u_int32_t segsleft[2];			/* Segments Left */
+	u_int32_t hdrlen;			/* Header Length */
+	u_int8_t  flags;			/*  */
+	u_int8_t  invflags;			/* Inverse flags */
+	struct in6_addr addrs[IP6T_RT_HOPS];	/* Hops */
+	u_int8_t addrnr;			/* Nr of Addresses */
+};
+
+#define IP6T_RT_TYP 		0x01
+#define IP6T_RT_SGS 		0x02
+#define IP6T_RT_LEN 		0x04
+#define IP6T_RT_RES 		0x08
+#define IP6T_RT_FST_MASK	0x30
+#define IP6T_RT_FST 		0x10
+#define IP6T_RT_FST_NSTRICT	0x20
+
+/* Values for "invflags" field in struct ip6t_rt. */
+#define IP6T_RT_INV_TYP		0x01	/* Invert the sense of type. */
+#define IP6T_RT_INV_SGS		0x02	/* Invert the sense of Segments. */
+#define IP6T_RT_INV_LEN		0x04	/* Invert the sense of length. */
+#define IP6T_RT_INV_MASK	0x07	/* All possible flags. */
+
+#define MASK_HOPOPTS    128
+#define MASK_DSTOPTS    64
+#define MASK_ROUTING    32
+#define MASK_FRAGMENT   16
+#define MASK_AH         8
+#define MASK_ESP        4
+#define MASK_NONE       2
+#define MASK_PROTO      1
+
+#endif /*_IP6T_RT_H*/
diff -urN linux-2.5.63-bk6/include/linux/pnpbios.h linux-2.5.63-bk7/include/linux/pnpbios.h
--- linux-2.5.63-bk6/include/linux/pnpbios.h	Mon Feb 24 11:05:16 2003
+++ linux-2.5.63-bk7/include/linux/pnpbios.h	Mon Mar 31 12:20:18 2003
@@ -85,8 +85,8 @@
 #define PNPBIOS_BOOTABLE		0x0010
 #define PNPBIOS_DOCK			0x0020
 #define PNPBIOS_REMOVABLE		0x0040
-#define pnpbios_is_static(x) ((x)->flags & 0x0100) == 0x0000
-#define pnpbios_is_dynamic(x) (x)->flags & 0x0080
+#define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000)
+#define pnpbios_is_dynamic(x) ((x)->flags & 0x0080)
 
 /* 0x8000 through 0xffff are OEM defined */
 
diff -urN linux-2.5.63-bk6/include/linux/sysfs.h linux-2.5.63-bk7/include/linux/sysfs.h
--- linux-2.5.63-bk6/include/linux/sysfs.h	Mon Feb 24 11:05:16 2003
+++ linux-2.5.63-bk7/include/linux/sysfs.h	Mon Mar 31 12:20:18 2003
@@ -16,6 +16,20 @@
 	mode_t			mode;
 };
 
+struct sysfs_bin_buffer {
+	u8 * 	data;
+	size_t	size;
+	size_t	count;
+	loff_t	offset;
+};
+
+struct bin_attribute {
+	struct attribute	attr;
+	size_t			size;
+	ssize_t (*read)(struct kobject *, struct sysfs_bin_buffer *);
+	ssize_t (*write)(struct kobject *, struct sysfs_bin_buffer *);
+};
+
 struct sysfs_ops {
 	ssize_t	(*show)(struct kobject *, struct attribute *,char *);
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
diff -urN linux-2.5.63-bk6/include/net/sctp/command.h linux-2.5.63-bk7/include/net/sctp/command.h
--- linux-2.5.63-bk6/include/net/sctp/command.h	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/include/net/sctp/command.h	Mon Mar 31 12:20:18 2003
@@ -68,7 +68,6 @@
 	SCTP_CMD_INIT_RESTART,  /* High level, do init timer work. */
 	SCTP_CMD_INIT_FAILED,   /* High level, do init failure work. */
 	SCTP_CMD_REPORT_DUP,	/* Report a duplicate TSN.  */
-	SCTP_CMD_REPORT_BIGGAP, /* Narc on a TSN (it was too high).  */
 	SCTP_CMD_STRIKE,	/* Mark a strike against a transport.  */
 	SCTP_CMD_TRANSMIT,      /* Transmit the outqueue. */
 	SCTP_CMD_HB_TIMERS_START,    /* Start the heartbeat timers. */
@@ -86,7 +85,8 @@
 	SCTP_CMD_PURGE_OUTQUEUE, /* Purge all data waiting to be sent. */
 	SCTP_CMD_SETUP_T2,       /* Hi-level, setup T2-shutdown parms.  */
 	SCTP_CMD_RTO_PENDING,	 /* Set transport's rto_pending. */
-
+	SCTP_CMD_PART_DELIVER,	 /* Partial data delivery considerations. */
+	SCTP_CMD_RENEGE,         /* Renege data on an association. */
 	SCTP_CMD_LAST
 } sctp_verb_t;
 
@@ -115,7 +115,7 @@
 	struct sctp_transport *transport;
 	sctp_bind_addr_t  *bp;
 	sctp_init_chunk_t *init;
-	sctp_ulpevent_t *ulpevent;
+	struct sctp_ulpevent *ulpevent;
 	sctp_packet_t *packet;
 	sctp_sackhdr_t *sackh;
 } sctp_arg_t;
@@ -163,7 +163,7 @@
 SCTP_ARG_CONSTRUCTOR(TRANSPORT,	struct sctp_transport *, transport)
 SCTP_ARG_CONSTRUCTOR(BA,	sctp_bind_addr_t *, bp)
 SCTP_ARG_CONSTRUCTOR(PEER_INIT,	sctp_init_chunk_t *, init)
-SCTP_ARG_CONSTRUCTOR(ULPEVENT,  sctp_ulpevent_t *, ulpevent)
+SCTP_ARG_CONSTRUCTOR(ULPEVENT,  struct sctp_ulpevent *, ulpevent)
 SCTP_ARG_CONSTRUCTOR(PACKET,	sctp_packet_t *, packet)
 SCTP_ARG_CONSTRUCTOR(SACKH,	sctp_sackhdr_t *, sackh)
 
diff -urN linux-2.5.63-bk6/include/net/sctp/sctp.h linux-2.5.63-bk7/include/net/sctp/sctp.h
--- linux-2.5.63-bk6/include/net/sctp/sctp.h	Mon Feb 24 11:05:14 2003
+++ linux-2.5.63-bk7/include/net/sctp/sctp.h	Mon Mar 31 12:20:18 2003
@@ -214,6 +214,7 @@
 #define SCTP_INC_STATS(field)		SNMP_INC_STATS(sctp_statistics, field)
 #define SCTP_INC_STATS_BH(field)	SNMP_INC_STATS_BH(sctp_statistics, field)
 #define SCTP_INC_STATS_USER(field)	SNMP_INC_STATS_USER(sctp_statistics, field)
+#define SCTP_DEC_STATS(field)		SNMP_DEC_STATS(sctp_statistics, field)
 
 /* Determine if this is a valid kernel address.  */
 static inline int sctp_is_valid_kaddr(unsigned long addr)
diff -urN linux-2.5.63-bk6/include/net/sctp/structs.h linux-2.5.63-bk7/include/net/sctp/structs.h
--- linux-2.5.63-bk6/include/net/sctp/structs.h	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/include/net/sctp/structs.h	Mon Mar 31 12:20:18 2003
@@ -2,7 +2,7 @@
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 Intel Corp.
- * Copyright (c) 2001-2002 International Business Machines Corp.
+ * Copyright (c) 2001-2003 International Business Machines Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
  *
@@ -73,27 +73,25 @@
 
 /* Forward declarations for data structures. */
 struct sctp_protocol;
-struct SCTP_endpoint;
-struct SCTP_association;
+struct sctp_endpoint;
+struct sctp_association;
 struct sctp_transport;
-struct SCTP_packet;
-struct SCTP_chunk;
-struct SCTP_inqueue;
+struct sctp_packet;
+struct sctp_chunk;
+struct sctp_inq;
 struct sctp_outq;
-struct SCTP_bind_addr;
+struct sctp_bind_addr;
 struct sctp_ulpq;
 struct sctp_opt;
 struct sctp_endpoint_common;
 struct sctp_ssnmap;
 
 typedef struct sctp_protocol sctp_protocol_t;
-typedef struct SCTP_endpoint sctp_endpoint_t;
-typedef struct SCTP_association sctp_association_t;
-typedef struct SCTP_packet sctp_packet_t;
-typedef struct SCTP_chunk sctp_chunk_t;
-typedef struct SCTP_inqueue sctp_inqueue_t;
-typedef struct SCTP_bind_addr sctp_bind_addr_t;
-typedef struct sctp_opt sctp_opt_t;
+typedef struct sctp_endpoint sctp_endpoint_t;
+typedef struct sctp_association sctp_association_t;
+typedef struct sctp_packet sctp_packet_t;
+typedef struct sctp_chunk sctp_chunk_t;
+typedef struct sctp_bind_addr sctp_bind_addr_t;
 typedef struct sctp_endpoint_common sctp_endpoint_common_t;
 
 #include <net/sctp/tsnmap.h>
@@ -218,10 +216,10 @@
 					 int optname,
 					 char *optval,
 					 int *optlen);
-	struct dst_entry *(*get_dst)	(sctp_association_t *asoc,
+	struct dst_entry *(*get_dst)	(struct sctp_association *asoc,
 					 union sctp_addr *daddr,
 					 union sctp_addr *saddr);
-	void 		(*get_saddr)	(sctp_association_t *asoc,
+	void 		(*get_saddr)	(struct sctp_association *asoc,
 					 struct dst_entry *dst,
 					 union sctp_addr *daddr,
 				 	 union sctp_addr *saddr);	 
@@ -257,7 +255,7 @@
 
 /* Protocol family functions. */
 struct sctp_pf {
-	void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
+	void (*event_msgname)(struct sctp_ulpevent *, char *, int *);
 	void (*skb_msgname)  (struct sk_buff *, char *, int *);
 	int  (*af_supported) (sa_family_t);
 	int  (*cmp_addr) (const union sctp_addr *,
@@ -279,6 +277,9 @@
 	/* What kind of a socket is this? */
 	sctp_socket_type_t type;
 
+	/* PF_ family specific functions.  */
+	struct sctp_pf *pf;
+
 	/* What is our base endpointer? */
 	sctp_endpoint_t *ep;
 
@@ -292,7 +293,10 @@
 	__u32 autoclose;
 	__u8 nodelay;
 	__u8 disable_fragments;
-	struct sctp_pf *pf;
+	__u8 pd_mode;
+
+	/* Receive to here while partial delivery is in effect. */
+	struct sk_buff_head pd_lobby;
 };
 
 
@@ -452,7 +456,7 @@
  * As a matter of convenience, we remember the SCTP common header for
  * each chunk as well as a few other header pointers...
  */
-struct SCTP_chunk {
+struct sctp_chunk {
 	/* These first three elements MUST PRECISELY match the first
 	 * three elements of struct sk_buff.  This allows us to reuse
 	 * all the skb_* queue management functions.
@@ -562,7 +566,7 @@
 /* This structure holds lists of chunks as we are assembling for
  * transmission.
  */
-struct SCTP_packet {
+struct sctp_packet {
 	/* These are the SCTP header values (host order) for the packet. */
 	__u16 source_port;
 	__u16 destination_port;
@@ -814,8 +818,8 @@
 /* This is the structure we use to queue packets as they come into
  * SCTP.  We write packets to it and read chunks from it.
  */
-struct SCTP_inqueue {
-	/* This is actually a queue of sctp_chunk_t each
+struct sctp_inq {
+	/* This is actually a queue of sctp_chunk each
 	 * containing a partially decoded packet.
 	 */
 	struct sk_buff_head in;
@@ -832,13 +836,12 @@
 	int malloced;        /* Is this structure kfree()able?  */
 };
 
-sctp_inqueue_t *sctp_inqueue_new(void);
-void sctp_inqueue_init(sctp_inqueue_t *);
-void sctp_inqueue_free(sctp_inqueue_t *);
-void sctp_push_inqueue(sctp_inqueue_t *, sctp_chunk_t *packet);
-sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *);
-void sctp_inqueue_set_th_handler(sctp_inqueue_t *,
-                                 void (*)(void *), void *);
+struct sctp_inq *sctp_inq_new(void);
+void sctp_inq_init(struct sctp_inq *);
+void sctp_inq_free(struct sctp_inq *);
+void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet);
+struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
+void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
 
 /* This is the structure we use to hold outbound chunks.  You push
  * chunks in and they automatically pop out the other end as bundled
@@ -922,7 +925,7 @@
 
 
 /* These bind address data fields common between endpoints and associations */
-struct SCTP_bind_addr {
+struct sctp_bind_addr {
 
 	/* RFC 2960 12.1 Parameters necessary for the SCTP instance
 	 *
@@ -1011,7 +1014,7 @@
 	struct sock *sk;
 
 	/* This is where we receive inbound chunks.  */
-	sctp_inqueue_t   inqueue;
+	struct sctp_inq   inqueue;
 
 	/* This substructure includes the defining parameters of the
 	 * endpoint:
@@ -1044,7 +1047,7 @@
  * off one of these.
  */
 
-struct SCTP_endpoint {
+struct sctp_endpoint {
 	/* Common substructure for endpoint and association. */
 	sctp_endpoint_common_t base;
 
@@ -1140,7 +1143,7 @@
 
 
 /* Here we have information about each individual association. */
-struct SCTP_association {
+struct sctp_association {
 
 	/* A base structure common to endpoint and association.
 	 * In this context, it represents the associations's view
@@ -1256,19 +1259,11 @@
 		 * used in the bulk of the text.  This value is hidden
 		 * in tsn_map--we get it by calling sctp_tsnmap_get_ctsn().
 		 */
-		sctp_tsnmap_t tsn_map;
+		struct sctp_tsnmap tsn_map;
 		__u8 _map[sctp_tsnmap_storage_size(SCTP_TSN_MAP_SIZE)];
 
-		/* We record duplicate TSNs here.  We clear this after
-		 * every SACK.
-		 * FIXME: We should move this into the tsnmap? --jgrimm
-		 */
-		sctp_dup_tsn_t dup_tsns[SCTP_MAX_DUP_TSNS];
-		int next_dup_tsn;
-
 		/* Do we need to sack the peer? */
-		uint8_t sack_needed;
-
+		__u8    sack_needed;
 		/* These are capabilities which our peer advertised.  */
 		__u8	ecn_capable;     /* Can peer do ECN? */
 		__u8	ipv4_address;    /* Peer understands IPv4 addresses? */
@@ -1425,7 +1420,10 @@
 
 	struct {
 		__u16 stream;
+		__u16 flags;
 		__u32 ppid;
+		__u32 context;
+		__u32 timetolive;
 	} defaults;
 
 	/* This tracks outbound ssn for a given stream.  */
@@ -1583,6 +1581,7 @@
 void sctp_association_hold(sctp_association_t *);
 
 struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *);
+void sctp_assoc_update_retran_path(sctp_association_t *);
 struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *,
 					  const union sctp_addr *);
 struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *,
diff -urN linux-2.5.63-bk6/include/net/sctp/tsnmap.h linux-2.5.63-bk7/include/net/sctp/tsnmap.h
--- linux-2.5.63-bk6/include/net/sctp/tsnmap.h	Mon Feb 24 11:05:38 2003
+++ linux-2.5.63-bk7/include/net/sctp/tsnmap.h	Mon Mar 31 12:20:18 2003
@@ -1,35 +1,40 @@
 /* SCTP kernel reference Implementation Copyright (C) 1999-2001
  * Cisco, Motorola, Intel, and International Business Machines Corp.
- * 
+ *
  * This file is part of the SCTP kernel reference Implementation
- * 
+ *
  * These are the definitions needed for the tsnmap type.  The tsnmap is used
  * to track out of order TSNs received.
- * 
- * The SCTP reference implementation  is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
- * 
- * the SCTP reference implementation  is distributed in the hope that it 
+ *
+ * The SCTP reference implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
- * Please send any bug reports or fixes you make to one of the
- * following email addresses:
- * 
- * Jon Grimm <jgrimm@us.ibm.com>
- * La Monte H.P. Yarroll <piggy@acm.org>
- * Karl Knutson <karl@athena.chicago.il.us>
- * 
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by:
+ *   Jon Grimm             <jgrimm@us.ibm.com>
+ *   La Monte H.P. Yarroll <piggy@acm.org>
+ *   Karl Knutson          <karl@athena.chicago.il.us>
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -38,8 +43,6 @@
 #ifndef __sctp_tsnmap_h__
 #define __sctp_tsnmap_h__
 
-
-
 /* RFC 2960 12.2 Parameters necessary per association (i.e. the TCB)
  * Mapping  An array of bits or bytes indicating which out of
  * Array    order TSN's have been received (relative to the
@@ -48,9 +51,7 @@
  *          will be set to all zero. This structure may be
  *          in the form of a circular buffer or bit array.
  */
-typedef struct sctp_tsnmap {
-
-
+struct sctp_tsnmap {
 	/* This array counts the number of chunks with each TSN.
 	 * It points at one of the two buffers with which we will
 	 * ping-pong between.
@@ -93,25 +94,30 @@
 	/* This is the highest TSN we've marked.  */
 	__u32 max_tsn_seen;
 
-	/* No. of data chunks pending receipt. used by SCTP_STATUS sockopt */
+	/* Data chunks pending receipt. used by SCTP_STATUS sockopt */
 	__u16 pending_data;
 
+	/* We record duplicate TSNs here.  We clear this after
+	 * every SACK.  Store up to SCTP_MAX_DUP_TSNS worth of
+	 * information.
+	 */
+	__u32 dup_tsns[SCTP_MAX_DUP_TSNS];
+	__u16 num_dup_tsns;
+
 	int malloced;
 
 	__u8 raw_map[0];
-} sctp_tsnmap_t;
+};
 
-typedef struct sctp_tsnmap_iter {
+struct sctp_tsnmap_iter {
 	__u32 start;
-} sctp_tsnmap_iter_t;
-
+};
 
 /* Create a new tsnmap.  */
-sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn,
-			       int priority);
+struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority);
 
 /* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(sctp_tsnmap_t *map);
+void sctp_tsnmap_free(struct sctp_tsnmap *);
 
 /* This macro assists in creation of external storage for variable length
  * internal buffers.  We double allocate so the overflow map works.
@@ -119,9 +125,8 @@
 #define sctp_tsnmap_storage_size(count) (sizeof(__u8) * (count) * 2)
 
 /* Initialize a block of memory as a tsnmap.  */
-sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn);
-
-
+struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *, __u16 len,
+				     __u32 initial_tsn);
 
 /* Test the tracking state of this TSN.
  * Returns:
@@ -129,31 +134,53 @@
  *  >0 if the TSN has been seen (duplicate)
  *  <0 if the TSN is invalid (too large to track)
  */
-int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn);
+int sctp_tsnmap_check(const struct sctp_tsnmap *, __u32 tsn);
 
 /* Mark this TSN as seen.  */
-void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn);
+void sctp_tsnmap_mark(struct sctp_tsnmap *, __u32 tsn);
 
 /* Retrieve the Cumulative TSN ACK Point.  */
-__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map);
+__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *);
 
 /* Retrieve the highest TSN we've seen.  */
-__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map);
+__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *);
+
+/* How many Duplicate TSNs are stored? */
+static inline __u16 sctp_tsnmap_num_dups(struct sctp_tsnmap *map)
+{
+	return map->num_dup_tsns;
+}
+
+/* Return pointer to duplicate tsn array as needed by SACK. */
+static inline __u32 *sctp_tsnmap_get_dups(struct sctp_tsnmap *map)
+{
+	map->num_dup_tsns = 0;
+	return map->dup_tsns;
+}
+
+/* Mark a duplicate TSN.  Note:  limit the storage of duplicate TSN
+ * information.
+ */
+static inline void sctp_tsnmap_mark_dup(struct sctp_tsnmap *map, __u32 tsn)
+{
+	if (map->num_dup_tsns < SCTP_MAX_DUP_TSNS)
+		map->dup_tsns[map->num_dup_tsns++] = htonl(tsn);
+}
+
+/* Renege a TSN that was seen.  */
+void sctp_tsnmap_renege(struct sctp_tsnmap *, __u32 tsn);
 
 /* Is there a gap in the TSN map? */
-int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map);
+int sctp_tsnmap_has_gap(const struct sctp_tsnmap *);
 
 /* Initialize a gap ack block interator from user-provided memory.  */
-void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter);
+void sctp_tsnmap_iter_init(const struct sctp_tsnmap *,
+			   struct sctp_tsnmap_iter *);
 
 /* Get the next gap ack blocks.  We return 0 if there are no more
  * gap ack blocks.
  */
-int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
-			     __u16 *start, __u16 *end);
-
+int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
+	struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
 
 #endif /* __sctp_tsnmap_h__ */
-
-
-
diff -urN linux-2.5.63-bk6/include/net/sctp/ulpevent.h linux-2.5.63-bk7/include/net/sctp/ulpevent.h
--- linux-2.5.63-bk6/include/net/sctp/ulpevent.h	Mon Feb 24 11:05:09 2003
+++ linux-2.5.63-bk7/include/net/sctp/ulpevent.h	Mon Mar 31 12:20:18 2003
@@ -6,34 +6,34 @@
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
  *
- * These are the definitions needed for the sctp_ulpevent type.  The 
+ * These are the definitions needed for the sctp_ulpevent type.  The
  * sctp_ulpevent type is used to carry information from the state machine
- * upwards to the ULP. 
- * 
- * The SCTP reference implementation  is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ * upwards to the ULP.
+ *
+ * The SCTP reference implementation  is free software;
+ * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
- * 
- * the SCTP reference implementation  is distributed in the hope that it 
+ *
+ * the SCTP reference implementation  is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to one of the
  * following email addresses:
- * 
+ *
  * Jon Grimm <jgrimm@us.ibm.com>
  * La Monte H.P. Yarroll <piggy@acm.org>
  * Karl Knutson <karl@athena.chicago.il.us>
- * 
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -46,85 +46,97 @@
 /* Warning: This sits inside an skb.cb[] area.  Be very careful of
  * growing this structure as it is at the maximum limit now.
  */
-typedef struct sctp_ulpevent {
-	int malloced;
-	sctp_association_t *asoc;
-	struct sk_buff *parent;
+struct sctp_ulpevent {
+	struct sctp_association *asoc;
 	struct sctp_sndrcvinfo sndrcvinfo;
-	int chunk_flags; /* Temp. until we get a new chunk_t */
 	int msg_flags;
-} sctp_ulpevent_t;
-
-
-sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority);
-
-sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event, struct sk_buff *skb, int msg_flags);
-
-void sctp_ulpevent_free(sctp_ulpevent_t *event);
-
-int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event);
-
-sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(
-				const struct SCTP_association *asoc,
-				__u16 flags,
-				__u16 state,
-				__u16 error,
-				__u16 outbound,
-				__u16 inbound,
-				int priority);
-
-sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
-				const struct SCTP_association *asoc,
-				const struct sockaddr_storage *aaddr,
-				int flags,
-				int state,
-				int error,
-				int priority);
-
-sctp_ulpevent_t *sctp_ulpevent_make_remote_error(
-				const struct SCTP_association *asoc,
-				struct SCTP_chunk *chunk,
-				__u16 flags,
-				int priority);
-sctp_ulpevent_t *sctp_ulpevent_make_send_failed(
-				const struct SCTP_association *asoc,
-				struct SCTP_chunk *chunk,
-				__u16 flags,
-				__u32 error,
-				int priority);
-
-sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
-				const struct SCTP_association *asoc,
-				__u16 flags,
-				int priority);
-
-sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(struct SCTP_association *asoc,
-					   struct SCTP_chunk *chunk,
-					   int priority);
-
-void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
-				   struct msghdr *msghdr);
-
-__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event);
+};
 
+/* Retrieve the skb this event sits inside of. */
+static inline struct sk_buff *sctp_event2skb(struct sctp_ulpevent *ev)
+{
+	return container_of((void *)ev, struct sk_buff, cb);
+}
 
+/* Retrieve & cast the event sitting inside the skb. */
+static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
+{
+	return (struct sctp_ulpevent *)skb->cb; 
+}
+	
+struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority);
+struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
+void sctp_ulpevent_free(struct sctp_ulpevent *);
+int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
+
+struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
+	const struct sctp_association *asoc,
+	__u16 flags,
+	__u16 state,
+	__u16 error,
+	__u16 outbound,
+	__u16 inbound,
+	int priority);
+
+struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
+	const struct sctp_association *asoc,
+	const struct sockaddr_storage *aaddr,
+	int flags,
+	int state,
+	int error,
+	int priority);
+
+struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
+	const struct sctp_association *asoc,
+	struct sctp_chunk *chunk,
+	__u16 flags,
+	int priority);
+struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
+	const struct sctp_association *asoc,
+	struct sctp_chunk *chunk,
+	__u16 flags,
+	__u32 error,
+	int priority);
+
+struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
+	const struct sctp_association *asoc,
+	__u16 flags,
+	int priority);
+
+struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
+	const struct sctp_association *asoc,
+	__u32 indication, int priority);
+
+struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
+	struct sctp_chunk *chunk,
+	int priority);
+
+void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
+	struct msghdr *);
+__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event);
+
+/* Is this event type enabled? */
+static inline int sctp_ulpevent_type_enabled(__u16 sn_type,
+					     struct sctp_event_subscribe *mask)
+{
+	char *amask = (char *) mask;
+	return amask[sn_type - SCTP_SN_TYPE_BASE];
+}
 
 /* Given an event subscription, is this event enabled? */
-static inline int sctp_ulpevent_is_enabled(const sctp_ulpevent_t *event,
-					   const struct sctp_event_subscribe *mask)
+static inline int sctp_ulpevent_is_enabled(const struct sctp_ulpevent *event,
+					   struct sctp_event_subscribe *mask)
 {
-	const char *amask = (const char *) mask;
 	__u16 sn_type;
 	int enabled = 1;
 
 	if (sctp_ulpevent_is_notification(event)) {
 		sn_type = sctp_ulpevent_get_notification_type(event);
-		enabled = amask[sn_type - SCTP_SN_TYPE_BASE];
+		enabled = sctp_ulpevent_type_enabled(sn_type, mask);
 	}
 	return enabled;
 }
 
-
 #endif /* __sctp_ulpevent_h__ */
 
 
diff -urN linux-2.5.63-bk6/include/net/sctp/ulpqueue.h linux-2.5.63-bk7/include/net/sctp/ulpqueue.h
--- linux-2.5.63-bk6/include/net/sctp/ulpqueue.h	Mon Feb 24 11:05:14 2003
+++ linux-2.5.63-bk7/include/net/sctp/ulpqueue.h	Mon Mar 31 12:20:18 2003
@@ -48,7 +48,8 @@
 
 /* A structure to carry information to the ULP (e.g. Sockets API) */
 struct sctp_ulpq {
-	int malloced;
+	char malloced;
+	char pd_mode;
 	sctp_association_t *asoc;
 	struct sk_buff_head reasm;
 	struct sk_buff_head lobby;
@@ -60,13 +61,22 @@
 void sctp_ulpq_free(struct sctp_ulpq *);
 
 /* Add a new DATA chunk for processing. */
-int sctp_ulpq_tail_data(struct sctp_ulpq *, sctp_chunk_t *chunk, int priority);
+int sctp_ulpq_tail_data(struct sctp_ulpq *, struct sctp_chunk *, int);
 
 /* Add a new event for propagation to the ULP. */
 int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
 
-/* Is the ulpqueue empty. */
-int sctp_ulpqueue_is_empty(struct sctp_ulpq *);
+/* Renege previously received chunks.  */
+void sctp_ulpq_renege(struct sctp_ulpq *, struct sctp_chunk *, int);
+
+/* Perform partial delivery. */
+void sctp_ulpq_partial_delivery(struct sctp_ulpq *, struct sctp_chunk *, int);
+
+/* Abort the partial delivery. */
+void sctp_ulpq_abort_pd(struct sctp_ulpq *, int);
+
+/* Clear the partial data delivery condition on this socket. */
+int sctp_clear_pd(struct sock *sk);
 
 #endif /* __sctp_ulpqueue_h__ */
 
diff -urN linux-2.5.63-bk6/include/net/sctp/user.h linux-2.5.63-bk7/include/net/sctp/user.h
--- linux-2.5.63-bk6/include/net/sctp/user.h	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/include/net/sctp/user.h	Mon Mar 31 12:20:18 2003
@@ -166,6 +166,7 @@
 	__u32 sinfo_context;
 	__u32 sinfo_timetolive;
 	__u32 sinfo_tsn;
+	__u32 sinfo_cumtsn;
 	sctp_assoc_t sinfo_assoc_id;
 };
 
@@ -367,6 +368,7 @@
 	sctp_assoc_t pdapi_assoc_id;
 };
 
+enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, };
 
 /*
  * Described in Section 7.3
@@ -414,8 +416,8 @@
 	SCTP_SN_TYPE_BASE     = (1<<15),
 	SCTP_ASSOC_CHANGE,
 	SCTP_PEER_ADDR_CHANGE,
-	SCTP_REMOTE_ERROR,
 	SCTP_SEND_FAILED,
+	SCTP_REMOTE_ERROR,
 	SCTP_SHUTDOWN_EVENT,
 	SCTP_PARTIAL_DELIVERY_EVENT,
 	SCTP_ADAPTION_INDICATION,
diff -urN linux-2.5.63-bk6/include/video/sbusfb.h linux-2.5.63-bk7/include/video/sbusfb.h
--- linux-2.5.63-bk6/include/video/sbusfb.h	Mon Feb 24 11:05:47 2003
+++ linux-2.5.63-bk7/include/video/sbusfb.h	Wed Dec 31 16:00:00 1969
@@ -1,147 +0,0 @@
-#include <linux/timer.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
-#include <asm/fbio.h>
-
-#include <video/fbcon.h>
-
-struct bt_regs {
-	volatile unsigned int addr;           /* address register */
-	volatile unsigned int color_map;      /* color map */
-	volatile unsigned int control;        /* control register */
-	volatile unsigned int cursor;         /* cursor map register */
-};
-
-struct fb_info_creator {
-	struct ffb_fbc *fbc;
-	struct ffb_dac *dac;
-	int xy_margin;
-	int fifo_cache;
-	u64 yx_margin;
-	int fg_cache;
-	int bg_cache;
-	int dac_rev;
-};
-struct fb_info_cgsix {
-	struct bt_regs *bt;
-	struct cg6_fbc *fbc;
-	struct cg6_thc *thc;
-	struct cg6_tec *tec;
-	volatile u32 *fhc;
-};
-struct fb_info_bwtwo {
-	struct bw2_regs *regs;
-};
-struct fb_info_cgthree {
-	struct cg3_regs *regs;
-};
-struct fb_info_tcx {
-	struct bt_regs *bt;
-	struct tcx_thc *thc;
-	struct tcx_tec *tec;
-	u32 *cplane;
-};
-struct fb_info_leo {
-	struct leo_lx_krn *lx_krn;
-	struct leo_lc_ss0_usr *lc_ss0_usr;
-	struct leo_ld_ss0 *ld_ss0;
-	struct leo_ld_ss1 *ld_ss1;
-	struct leo_cursor *cursor;
-	unsigned int extent;
-};
-struct fb_info_cgfourteen {
-	struct cg14_regs *regs;
-	struct cg14_cursor *cursor;
-	struct cg14_clut *clut;
-	int ramsize;
-	int mode;
-};
-struct fb_info_p9100 {
-	struct p9100_ctrl *ctrl;
-	volatile u32 *fbmem;
-};
-
-struct cg_cursor {
-	char	enable;         /* cursor is enabled */
-	char	mode;		/* cursor mode */
-	struct	fbcurpos cpos;  /* position */
-	struct	fbcurpos chot;  /* hot-spot */
-	struct	fbcurpos size;  /* size of mask & image fields */
-	struct	fbcurpos hwsize; /* hw max size */
-	int	bits[2][128];   /* space for mask & image bits */
-	char	color [6];      /* cursor colors */
-	struct	timer_list timer; /* cursor timer */
-	int	blink_rate;	/* cursor blink rate */
-};
-
-struct sbus_mmap_map {
-	unsigned long voff;
-	unsigned long poff;
-	unsigned long size;
-};
-
-#define SBUS_MMAP_FBSIZE(n) (-n)
-#define SBUS_MMAP_EMPTY	0x80000000
-
-struct fb_info_sbusfb {
-	struct fb_info info;
-	struct display disp;
-	struct display_switch dispsw;
-	struct fbtype type;
-	struct sbus_dev *sbdp;
-	spinlock_t lock;
-	int prom_node, prom_parent;
-	union {
-		struct fb_info_creator ffb;
-		struct fb_info_cgsix cg6;
-		struct fb_info_bwtwo bw2;
-		struct fb_info_cgthree cg3;
-		struct fb_info_tcx tcx;
-		struct fb_info_leo leo;
-		struct fb_info_cgfourteen cg14;
-		struct fb_info_p9100 p9100;
-	} s;
-	unsigned char *color_map;
-	struct cg_cursor cursor;
-	unsigned char open;
-	unsigned char mmaped;
-	unsigned char blanked;
-	int x_margin;
-	int y_margin;
-	int vtconsole;
-	int consolecnt;
-	int graphmode;
-	int emulations[4];
-	struct sbus_mmap_map *mmap_map;
-	unsigned long physbase;
-	int iospace;
-	/* Methods */
-	void (*setup)(struct display *);
-	void (*setcursor)(struct fb_info_sbusfb *);
-	void (*setcurshape)(struct fb_info_sbusfb *);
-	void (*setcursormap)(struct fb_info_sbusfb *, unsigned char *, unsigned char *, unsigned char *);
-	void (*loadcmap)(struct fb_info_sbusfb *, struct display *, int, int);
-	int (*blank)(struct fb_info_sbusfb *);
-	int (*unblank)(struct fb_info_sbusfb *);
-	void (*margins)(struct fb_info_sbusfb *, struct display *, int, int);
-	void (*reset)(struct fb_info_sbusfb *);
-	void (*fill)(struct fb_info_sbusfb *, struct display *, int, int, unsigned short *);
-	void (*switch_from_graph)(struct fb_info_sbusfb *);
-	void (*restore_palette)(struct fb_info_sbusfb *);
-	int (*ioctl)(struct fb_info_sbusfb *, unsigned int, unsigned long);
-};
-
-extern char *creatorfb_init(struct fb_info_sbusfb *);
-extern char *cgsixfb_init(struct fb_info_sbusfb *);
-extern char *cgthreefb_init(struct fb_info_sbusfb *);
-extern char *tcxfb_init(struct fb_info_sbusfb *);
-extern char *leofb_init(struct fb_info_sbusfb *);
-extern char *bwtwofb_init(struct fb_info_sbusfb *);
-extern char *cgfourteenfb_init(struct fb_info_sbusfb *);
-extern char *p9100fb_init(struct fb_info_sbusfb *);
-
-#define sbusfbinfod(disp) ((struct fb_info_sbusfb *)(disp->fb_info))
-#define sbusfbinfo(info) ((struct fb_info_sbusfb *)(info))
-#define CM(i, j) [3*(i)+(j)]
-
-#define SBUSFBINIT_SIZECHANGE ((char *)-1)
diff -urN linux-2.5.63-bk6/kernel/cpufreq.c linux-2.5.63-bk7/kernel/cpufreq.c
--- linux-2.5.63-bk6/kernel/cpufreq.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/kernel/cpufreq.c	Mon Mar 31 12:20:18 2003
@@ -88,7 +88,7 @@
 
 /* forward declarations */
 static int cpufreq_add_dev (struct device * dev);
-static int cpufreq_remove_dev (struct intf_data * dev);
+static int cpufreq_remove_dev (struct device * dev);
 
 /* drivers/base/cpu.c */
 extern struct device_class cpu_devclass;
@@ -116,70 +116,59 @@
  * "unsigned int".
  */
 
-#define cpufreq_per_cpu_attr_read(file_name, object) 			\
+#define show_one(file_name, object)		 			\
 static ssize_t show_##file_name 					\
-(struct device *dev, char *buf)						\
+(struct cpufreq_policy * policy, char *buf)				\
 {									\
 	unsigned int value = 0;						\
 									\
-	if (!dev)							\
-		return 0;						\
-									\
 	down(&cpufreq_driver_sem);					\
 	if (cpufreq_driver)						\
-		value = cpufreq_driver->policy[to_cpu_nr(dev)].object;	\
+		value = policy->object;					\
 	up(&cpufreq_driver_sem);					\
 									\
 	return sprintf (buf, "%u\n", value);				\
 }
 
+show_one(cpuinfo_min_freq, cpuinfo.min_freq);
+show_one(cpuinfo_max_freq, cpuinfo.max_freq);
+show_one(scaling_min_freq, min);
+show_one(scaling_max_freq, max);
 
 /**
  * cpufreq_per_cpu_attr_write() / store_##file_name() - sysfs write access
  */
-#define cpufreq_per_cpu_attr_write(file_name, object)			\
+#define store_one(file_name, object)			\
 static ssize_t store_##file_name					\
-(struct device *dev, const char *buf, size_t count)			\
+(struct cpufreq_policy * policy, const char *buf, size_t count)		\
 {									\
 	unsigned int ret = -EINVAL;					\
-	struct cpufreq_policy policy;					\
-									\
-	if (!dev)							\
-		return 0;						\
 									\
-	ret = cpufreq_get_policy(&policy, to_cpu_nr(dev));		\
-	if (ret)							\
-		return ret;						\
-									\
-	ret = sscanf (buf, "%u", &policy.object);			\
+	ret = sscanf (buf, "%u", &policy->object);			\
 	if (ret != 1)							\
 		return -EINVAL;						\
 									\
-	ret = cpufreq_set_policy(&policy);				\
-	if (ret)							\
-		return ret;						\
+	ret = cpufreq_set_policy(policy);				\
 									\
-	return count;							\
+	return ret ? ret : count;					\
 }
 
+store_one(scaling_min_freq,min);
+store_one(scaling_max_freq,max);
 
 /**
  * show_scaling_governor - show the current policy for the specified CPU
  */
-static ssize_t show_scaling_governor (struct device *dev, char *buf)
+static ssize_t show_scaling_governor (struct cpufreq_policy * policy, char *buf)
 {
 	unsigned int value = 0;
 	char value2[CPUFREQ_NAME_LEN];
 
-
-	if (!dev)
-		return 0;
-
 	down(&cpufreq_driver_sem);
 	if (cpufreq_driver)
-		value = cpufreq_driver->policy[to_cpu_nr(dev)].policy;
+		value = policy->policy;
 	if (value == CPUFREQ_POLICY_GOVERNOR)
-		strncpy(value2, cpufreq_driver->policy[to_cpu_nr(dev)].governor->name, CPUFREQ_NAME_LEN);
+		strncpy(value2, policy->governor->name, CPUFREQ_NAME_LEN);
 	up(&cpufreq_driver_sem);
 
 	switch (value) {
@@ -198,34 +187,88 @@
 /**
  * store_scaling_governor - store policy for the specified CPU
  */
-static ssize_t 
-store_scaling_governor (struct device *dev, const char *buf, size_t count) 
+static ssize_t store_scaling_governor (struct cpufreq_policy * policy, 
+				       const char *buf, size_t count) 
 {
 	unsigned int ret = -EINVAL;
 	char	str_governor[16];
-	struct cpufreq_policy policy;
-
-	if (!dev)
-		return 0;
-
-	ret = cpufreq_get_policy(&policy, to_cpu_nr(dev));
-	if (ret)
-		return ret;
 
 	ret = sscanf (buf, "%15s", str_governor);
 	if (ret != 1)
 		return -EINVAL;
 
-	if (cpufreq_parse_governor(str_governor, &policy.policy, &policy.governor))
+	if (cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor))
 		return -EINVAL;
 
-	ret = cpufreq_set_policy(&policy);
-	if (ret)
-		return ret;
+	ret = cpufreq_set_policy(policy);
+
+	return ret ? ret : count;
+}
+
+
+struct freq_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct cpufreq_policy *, char *);
+	ssize_t (*store)(struct cpufreq_policy *, const char *, size_t count);
+};
+
+#define define_one_ro(_name) \
+struct freq_attr _name = { \
+	.attr = { .name = __stringify(_name), .mode = 0444 }, \
+	.show = show_##_name, \
+}
+
+#define define_one_rw(_name) \
+struct freq_attr _name = { \
+	.attr = { .name = __stringify(_name), .mode = 0644 }, \
+	.show = show_##_name, \
+	.store = store_##_name, \
+}
+
+define_one_ro(cpuinfo_min_freq);
+define_one_ro(cpuinfo_max_freq);
+define_one_rw(scaling_min_freq);
+define_one_rw(scaling_max_freq);
+define_one_rw(scaling_governor);
+
+static struct attribute * default_attrs[] = {
+	&cpuinfo_min_freq.attr,
+	&cpuinfo_max_freq.attr,
+	&scaling_min_freq.attr,
+	&scaling_max_freq.attr,
+	&scaling_governor.attr,
+	NULL
+};
+
+
+#define to_policy(k) container_of(k,struct cpufreq_policy,kobj)
+#define to_attr(a) container_of(a,struct freq_attr,attr)
 
-	return count;
+static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf)
+{
+	struct cpufreq_policy * policy = to_policy(kobj);
+	struct freq_attr * fattr = to_attr(attr);
+	return fattr->show ? fattr->show(policy,buf) : 0;
+}
+
+static ssize_t store(struct kobject * kobj, struct attribute * attr, 
+		     const char * buf, size_t count)
+{
+	struct cpufreq_policy * policy = to_policy(kobj);
+	struct freq_attr * fattr = to_attr(attr);
+	return fattr->store ? fattr->store(policy,buf,count) : 0;
 }
 
+static struct sysfs_ops sysfs_ops = {
+	.show	= show,
+	.store	= store,
+};
+
+static struct kobj_type ktype_cpufreq = {
+	.sysfs_ops	= &sysfs_ops,
+	.default_attrs	= default_attrs,
+};
+
 
 /**
  * show_scaling_governor - show the current policy for the specified CPU
@@ -274,34 +317,9 @@
 }
 
 
-/**
- * cpufreq_per_cpu_attr_ro - read-only cpufreq per-CPU file
- */
-#define cpufreq_per_cpu_attr_ro(file_name, object)			\
-cpufreq_per_cpu_attr_read(file_name, object) 				\
-static DEVICE_ATTR(file_name, S_IRUGO, show_##file_name, NULL);
-
-
-/**
- * cpufreq_per_cpu_attr_rw - read-write cpufreq per-CPU file
- */
-#define cpufreq_per_cpu_attr_rw(file_name, object) 			\
-cpufreq_per_cpu_attr_read(file_name, object) 				\
-cpufreq_per_cpu_attr_write(file_name, object) 				\
-static DEVICE_ATTR(file_name, (S_IRUGO | S_IWUSR), show_##file_name, store_##file_name);
-
-
-/* create the file functions */
-cpufreq_per_cpu_attr_ro(cpuinfo_min_freq, cpuinfo.min_freq);
-cpufreq_per_cpu_attr_ro(cpuinfo_max_freq, cpuinfo.max_freq);
-cpufreq_per_cpu_attr_rw(scaling_min_freq, min);
-cpufreq_per_cpu_attr_rw(scaling_max_freq, max);
-
-static DEVICE_ATTR(scaling_governor, (S_IRUGO | S_IWUSR), show_scaling_governor, store_scaling_governor);
 static DEVICE_ATTR(scaling_driver, S_IRUGO, show_scaling_driver, NULL);
 static DEVICE_ATTR(available_scaling_governors, S_IRUGO, show_available_govs, NULL);
 
-
 /**
  * cpufreq_add_dev - add a CPU device
  *
@@ -346,28 +364,13 @@
 	down(&cpufreq_driver_sem);
 
 	/* prepare interface data */
-	cpufreq_driver->policy[cpu].intf.dev  = dev;
-	cpufreq_driver->policy[cpu].intf.intf = &cpufreq_interface;
-	strncpy(cpufreq_driver->policy[cpu].intf.kobj.name, cpufreq_interface.name, KOBJ_NAME_LEN);
-	cpufreq_driver->policy[cpu].intf.kobj.parent = &(dev->kobj);
-	cpufreq_driver->policy[cpu].intf.kobj.kset = &(cpufreq_interface.kset);
-
-	/* add interface */
-	/* currently commented out due to deadlock */
-	//ret = interface_add_data(&(cpufreq_driver->policy[cpu].intf));
-	if (ret) {
-		up(&cpufreq_driver_sem);
-		return ret;
-	}
+	policy.kobj.parent = &dev->kobj;
+	policy.kobj.ktype = &ktype_cpufreq;
+	policy.dev = dev;
+	strncpy(policy.kobj.name, 
+		cpufreq_interface.name, KOBJ_NAME_LEN);
 
-	/* create files */
-	device_create_file (dev, &dev_attr_cpuinfo_min_freq);
-	device_create_file (dev, &dev_attr_cpuinfo_max_freq);
-	device_create_file (dev, &dev_attr_scaling_min_freq);
-	device_create_file (dev, &dev_attr_scaling_max_freq);
-	device_create_file (dev, &dev_attr_scaling_governor);
-	device_create_file (dev, &dev_attr_scaling_driver);
-	device_create_file (dev, &dev_attr_available_scaling_governors);
+	ret = kobject_register(&policy.kobj);
 
 	up(&cpufreq_driver_sem);
 	return ret;
@@ -380,9 +383,8 @@
  * Removes the cpufreq interface for a CPU device. Is called with
  * cpufreq_driver_sem locked.
  */
-static int cpufreq_remove_dev (struct intf_data *intf)
+static int cpufreq_remove_dev (struct device * dev)
 {
-	struct device * dev = intf->dev;
 	unsigned int cpu = to_cpu_nr(dev);
 
 	if (cpufreq_driver->target)
@@ -391,13 +393,7 @@
 	if (cpufreq_driver->exit)
 		cpufreq_driver->exit(&cpufreq_driver->policy[cpu]);
 
-	device_remove_file (dev, &dev_attr_cpuinfo_min_freq);
-	device_remove_file (dev, &dev_attr_cpuinfo_max_freq);
-	device_remove_file (dev, &dev_attr_scaling_min_freq);
-	device_remove_file (dev, &dev_attr_scaling_max_freq);
-	device_remove_file (dev, &dev_attr_scaling_governor);
-	device_remove_file (dev, &dev_attr_scaling_driver);
-	device_remove_file (dev, &dev_attr_available_scaling_governors);
+	kobject_unregister(&cpufreq_driver->policy[cpu].kobj);
 
 	return 0;
 }
@@ -851,15 +847,6 @@
 		return -EINVAL;
 	}
 
-	/* remove this workaround as soon as interface_add_data works */
-	{
-		unsigned int i;
-		for (i=0; i<NR_CPUS; i++) {
-			if (cpu_online(i)) 
-				cpufreq_remove_dev(&cpufreq_driver->policy[i].intf);
-		}
-	}
-
 	interface_unregister(&cpufreq_interface);
 
 	if (driver)
diff -urN linux-2.5.63-bk6/net/802/fc.c linux-2.5.63-bk7/net/802/fc.c
--- linux-2.5.63-bk6/net/802/fc.c	Mon Feb 24 11:05:47 2003
+++ linux-2.5.63-bk7/net/802/fc.c	Mon Mar 31 12:20:18 2003
@@ -95,4 +95,37 @@
 	return 0;
 #endif
 }
-	
+
+unsigned short
+fc_type_trans(struct sk_buff *skb, struct net_device *dev)
+{
+	struct fch_hdr *fch = (struct fch_hdr *)skb->data;
+	struct fcllc *fcllc;
+
+	skb->mac.raw = skb->data;
+	fcllc = (struct fcllc *)(skb->data + sizeof (struct fch_hdr) + 2);
+	skb_pull(skb, sizeof (struct fch_hdr) + 2);
+
+	if (*fch->daddr & 1) {
+		if (!memcmp(fch->daddr, dev->broadcast, FC_ALEN))
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	} else if (dev->flags & IFF_PROMISC) {
+		if (memcmp(fch->daddr, dev->dev_addr, FC_ALEN))
+			skb->pkt_type = PACKET_OTHERHOST;
+	}
+
+	/*
+	 * Strip the SNAP header from ARP packets since we don't pass
+	 * them through to the 802.2/SNAP layers.
+	 */
+	if (fcllc->dsap == EXTENDED_SAP &&
+	    (fcllc->ethertype == ntohs(ETH_P_IP) ||
+	     fcllc->ethertype == ntohs(ETH_P_ARP))) {
+		skb_pull(skb, sizeof (struct fcllc));
+		return fcllc->ethertype;
+	}
+
+	return ntohs(ETH_P_802_2);
+}
diff -urN linux-2.5.63-bk6/net/atm/lec.c linux-2.5.63-bk7/net/atm/lec.c
--- linux-2.5.63-bk6/net/atm/lec.c	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/net/atm/lec.c	Mon Mar 31 12:20:18 2003
@@ -223,7 +223,8 @@
         struct lecdatahdr_8023 *lec_h;
         struct atm_vcc *send_vcc;
 	struct lec_arp_table *entry;
-        unsigned char *nb, *dst;
+        unsigned char *dst;
+	int min_frame_size;
 #ifdef CONFIG_TR
         unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
 #endif
@@ -294,26 +295,24 @@
 #endif /* DUMP_PACKETS > 0 */
 
         /* Minimum ethernet-frame size */
-        if (skb->len <62) {
-                if (skb->truesize < 62) {
-                        printk("%s:data packet %d / %d\n",
-                               dev->name,
-                               skb->len,skb->truesize);
-                        nb=(unsigned char*)kmalloc(64, GFP_ATOMIC);
-                        if (nb == NULL) {
+#ifdef CONFIG_TR
+        if (priv->is_trdev)
+                min_frame_size = LEC_MINIMUM_8025_SIZE;
+	else
+#endif
+        min_frame_size = LEC_MINIMUM_8023_SIZE;
+        if (skb->len < min_frame_size) {
+                if (skb->truesize < min_frame_size) {
+                        skb2 = skb_copy_expand(skb, 0,
+                            min_frame_size - skb->truesize, GFP_ATOMIC);
                                 dev_kfree_skb(skb);
+                        if (skb2 == NULL) {
+                                priv->stats.tx_dropped++;
                                 return 0;
                         }
-                        memcpy(nb,skb->data,skb->len);
-                        kfree(skb->head);
-                        skb->head = skb->data = nb;
-                        skb->tail = nb+62;
-                        skb->end = nb+64;
-                        skb->len=62;
-                        skb->truesize = 64;
-                } else {
-                        skb->len = 62;
+                        skb = skb2;
                 }
+		skb_put(skb, min_frame_size - skb->len);
         }
         
         /* Send to right vcc */
@@ -618,6 +617,14 @@
         return 0;
 }
 
+static void lec_set_multicast_list(struct net_device *dev)
+{
+	/* by default, all multicast frames arrive over the bus.
+         * eventually support selective multicast service
+         */
+        return;
+}
+
 static void 
 lec_init(struct net_device *dev)
 {
@@ -627,7 +634,7 @@
         dev->hard_start_xmit = lec_send_packet;
 
         dev->get_stats = lec_get_stats;
-        dev->set_multicast_list = NULL;
+        dev->set_multicast_list = lec_set_multicast_list;
         dev->do_ioctl  = NULL;
         printk("%s: Initialized!\n",dev->name);
         return;
@@ -706,7 +713,7 @@
                         lec_arp_check_empties(priv, vcc, skb);
                 }
                 skb->dev = dev;
-                skb->data += 2; /* skip lec_id */
+                skb_pull(skb, 2); /* skip lec_id */
 #ifdef CONFIG_TR
                 if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
                 else
diff -urN linux-2.5.63-bk6/net/atm/lec.h linux-2.5.63-bk7/net/atm/lec.h
--- linux-2.5.63-bk6/net/atm/lec.h	Mon Feb 24 11:05:15 2003
+++ linux-2.5.63-bk7/net/atm/lec.h	Mon Mar 31 12:20:18 2003
@@ -38,6 +38,9 @@
   unsigned char h_source[ETH_ALEN];
 };
 
+#define LEC_MINIMUM_8023_SIZE   62
+#define LEC_MINIMUM_8025_SIZE   16
+
 /*
  * Operations that LANE2 capable device can do. Two first functions
  * are used to make the device do things. See spec 3.1.3 and 3.1.4.
diff -urN linux-2.5.63-bk6/net/bridge/netfilter/ebtable_broute.c linux-2.5.63-bk7/net/bridge/netfilter/ebtable_broute.c
--- linux-2.5.63-bk6/net/bridge/netfilter/ebtable_broute.c	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/net/bridge/netfilter/ebtable_broute.c	Mon Mar 31 12:20:18 2003
@@ -18,13 +18,20 @@
 
 // EBT_ACCEPT means the frame will be bridged
 // EBT_DROP means the frame will be routed
-static struct ebt_entries initial_chain =
-  {0, "BROUTING", 0, EBT_ACCEPT, 0};
+static struct ebt_entries initial_chain = {
+	.name	= "BROUTING",
+	.policy	= EBT_ACCEPT,
+};
 
 static struct ebt_replace initial_table =
 {
-  "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries),
-  { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain
+	.name		= "broute",
+	.valid_hooks	= 1 << NF_BR_BROUTING,
+	.entries_size	= sizeof(struct ebt_entries),
+	.hook_entry	= {
+		[NF_BR_BROUTING]	= &initial_chain,
+	},
+	.entries	= (char *)&initial_chain
 };
 
 static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
@@ -36,8 +43,11 @@
 
 static struct ebt_table broute_table =
 {
-  {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING,
-  RW_LOCK_UNLOCKED, check, NULL
+	.name		= "broute",
+	.table		= &initial_table,
+	.valid_hooks	= 1 << NF_BR_BROUTING,
+	.lock		= RW_LOCK_UNLOCKED,
+	.check		= check,
 };
 
 static int ebt_broute(struct sk_buff **pskb)
diff -urN linux-2.5.63-bk6/net/bridge/netfilter/ebtable_filter.c linux-2.5.63-bk7/net/bridge/netfilter/ebtable_filter.c
--- linux-2.5.63-bk6/net/bridge/netfilter/ebtable_filter.c	Mon Feb 24 11:05:43 2003
+++ linux-2.5.63-bk7/net/bridge/netfilter/ebtable_filter.c	Mon Mar 31 12:20:18 2003
@@ -16,16 +16,31 @@
 
 static struct ebt_entries initial_chains[] =
 {
-  {0, "INPUT", 0, EBT_ACCEPT, 0},
-  {0, "FORWARD", 0, EBT_ACCEPT, 0},
-  {0, "OUTPUT", 0, EBT_ACCEPT, 0}
+	{
+		.name	= "INPUT",
+		.policy	= EBT_ACCEPT,
+	},
+	{
+		.name	= "FORWARD",
+		.policy	= EBT_ACCEPT,
+	},
+	{
+		.name	= "OUTPUT",
+		.policy	= EBT_ACCEPT,
+	}
 };
 
 static struct ebt_replace initial_table =
 {
-  "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
-  { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1],
-    [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains
+	.name		= "filter",
+	.valid_hooks	= FILTER_VALID_HOOKS,
+	.entries_size	= 3 * sizeof(struct ebt_entries),
+  	.hook_entry	= {
+		[NF_BR_LOCAL_IN]	= &initial_chains[0],
+		[NF_BR_FORWARD]		= &initial_chains[1],
+    		[NF_BR_LOCAL_OUT]	= &initial_chains[2],
+	},
+	.entries	= (char *)initial_chains
 };
 
 static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
@@ -37,8 +52,11 @@
 
 static struct ebt_table frame_filter =
 { 
-  {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, 
-  RW_LOCK_UNLOCKED, check, NULL
+	.name		= "filter",
+	.table		= &initial_table,
+	.valid_hooks	= FILTER_VALID_HOOKS, 
+	.lock		= RW_LOCK_UNLOCKED,
+	.check		= check,
 };
 
 static unsigned int
@@ -49,12 +67,24 @@
 }
 
 static struct nf_hook_ops ebt_ops_filter[] = {
-	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN,
-	   NF_BR_PRI_FILTER_BRIDGED},
-	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD,
-	   NF_BR_PRI_FILTER_BRIDGED},
-	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT,
-	   NF_BR_PRI_FILTER_OTHER}
+	{
+		.hook		= ebt_hook,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_LOCAL_IN,
+		.priority	= NF_BR_PRI_FILTER_BRIDGED,
+	},
+	{
+		.hook		= ebt_hook,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_FORWARD,
+		.priority	= NF_BR_PRI_FILTER_BRIDGED
+	},
+	{
+		.hook		= ebt_hook,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_LOCAL_OUT,
+		.priority	= NF_BR_PRI_FILTER_OTHER
+	}
 };
 
 static int __init init(void)
diff -urN linux-2.5.63-bk6/net/bridge/netfilter/ebtable_nat.c linux-2.5.63-bk7/net/bridge/netfilter/ebtable_nat.c
--- linux-2.5.63-bk6/net/bridge/netfilter/ebtable_nat.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/net/bridge/netfilter/ebtable_nat.c	Mon Mar 31 12:20:18 2003
@@ -15,16 +15,31 @@
 
 static struct ebt_entries initial_chains[] =
 {
-  {0, "PREROUTING", 0, EBT_ACCEPT, 0},
-  {0, "OUTPUT", 0, EBT_ACCEPT, 0},
-  {0, "POSTROUTING", 0, EBT_ACCEPT, 0}
+	{
+		.name	= "PREROUTING",
+		.policy	= EBT_ACCEPT,
+	},
+	{
+		.name	= "OUTPUT",
+		.policy	= EBT_ACCEPT,
+	},
+	{
+		.name	= "POSTROUTING",
+		.policy	= EBT_ACCEPT,
+	}
 };
 
 static struct ebt_replace initial_table =
 {
-  "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
-  { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1],
-    [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains
+	.name		= "nat",
+	.valid_hooks	= NAT_VALID_HOOKS,
+	.entries_size	= 3 * sizeof(struct ebt_entries),
+	.hook_entry	= {
+		[NF_BR_PRE_ROUTING]	= &initial_chains[0],
+		[NF_BR_LOCAL_OUT]	= &initial_chains[1],
+		[NF_BR_POST_ROUTING]	= &initial_chains[2],
+	},
+	.entries	= (char *)initial_chains
 };
 
 static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
@@ -36,8 +51,11 @@
 
 static struct ebt_table frame_nat =
 {
-  {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS,
-  RW_LOCK_UNLOCKED, check, NULL
+	.name		= "nat",
+	.table		= &initial_table,
+	.valid_hooks	= NAT_VALID_HOOKS,
+	.lock		= RW_LOCK_UNLOCKED,
+	.check		= check,
 };
 
 static unsigned int
@@ -55,12 +73,24 @@
 }
 
 static struct nf_hook_ops ebt_ops_nat[] = {
-	{ { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT,
-	   NF_BR_PRI_NAT_DST_OTHER},
-	{ { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING,
-	   NF_BR_PRI_NAT_SRC},
-	{ { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING,
-	   NF_BR_PRI_NAT_DST_BRIDGED},
+	{
+		.hook		= ebt_nat_dst,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_LOCAL_OUT,
+		.priority	= NF_BR_PRI_NAT_DST_OTHER
+	},
+	{
+		.hook		= ebt_nat_src,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_POST_ROUTING,
+		.priority	= NF_BR_PRI_NAT_SRC
+	},
+	{
+		.hook		= ebt_nat_dst,
+		.pf		= PF_BRIDGE,
+		.hooknum	= NF_BR_PRE_ROUTING,
+		.priority	= NF_BR_PRI_NAT_DST_BRIDGED
+	},
 };
 
 static int __init init(void)
diff -urN linux-2.5.63-bk6/net/ipv4/esp.c linux-2.5.63-bk7/net/ipv4/esp.c
--- linux-2.5.63-bk6/net/ipv4/esp.c	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/net/ipv4/esp.c	Mon Mar 31 12:20:18 2003
@@ -360,7 +360,7 @@
 	esp = x->data;
 	alen = esp->auth.icv_trunc_len;
 	tfm = esp->conf.tfm;
-	blksize = crypto_tfm_alg_blocksize(tfm);
+	blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3;
 	clen = (clen + 2 + blksize-1)&~(blksize-1);
 	if (esp->conf.padlen)
 		clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/arp_tables.c linux-2.5.63-bk7/net/ipv4/netfilter/arp_tables.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/arp_tables.c	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/arp_tables.c	Mon Mar 31 12:20:18 2003
@@ -539,8 +539,10 @@
 		duprintf("check_entry: `%s' not found\n", t->u.user.name);
 		goto out;
 	}
-	if (target->me)
-		__MOD_INC_USE_COUNT(target->me);
+	if (!try_module_get((target->me))) {
+		ret = -ENOENT;
+		goto out_unlock;
+	}
 	t->u.kernel.target = target;
 	up(&arpt_mutex);
 
@@ -554,8 +556,7 @@
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		if (t->u.kernel.target->me)
-			__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
+		module_put(t->u.kernel.target->me);
 		duprintf("arp_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
@@ -565,6 +566,8 @@
 	(*i)++;
 	return 0;
 
+out_unlock:
+	up(&arpt_mutex);
 out:
 	return ret;
 }
@@ -622,9 +625,7 @@
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->data,
 					    t->u.target_size - sizeof(*t));
-	if (t->u.kernel.target->me)
-		__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
-
+	module_put(t->u.kernel.target->me);
 	return 0;
 }
 
@@ -1110,17 +1111,14 @@
 {
 	int ret;
 
-	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&arpt_mutex);
-	if (ret != 0) {
-		MOD_DEC_USE_COUNT;
+	if (ret != 0)
 		return ret;
-	}
+
 	if (!list_named_insert(&arpt_target, target)) {
 		duprintf("arpt_register_target: `%s' already in list!\n",
 			 target->name);
 		ret = -EINVAL;
-		MOD_DEC_USE_COUNT;
 	}
 	up(&arpt_mutex);
 	return ret;
@@ -1131,7 +1129,6 @@
 	down(&arpt_mutex);
 	LIST_DELETE(&arpt_target, target);
 	up(&arpt_mutex);
-	MOD_DEC_USE_COUNT;
 }
 
 int arpt_register_table(struct arpt_table *table)
@@ -1141,12 +1138,10 @@
 	static struct arpt_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
-	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct arpt_table_info)
 			  + SMP_ALIGN(table->table->size) * NR_CPUS);
 	if (!newinfo) {
 		ret = -ENOMEM;
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 	memcpy(newinfo->entries, table->table->entries, table->table->size);
@@ -1159,14 +1154,12 @@
 	duprintf("arpt_register_table: translate table gives %d\n", ret);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
 	ret = down_interruptible(&arpt_mutex);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
@@ -1196,7 +1189,6 @@
 
  free_unlock:
 	vfree(newinfo);
-	MOD_DEC_USE_COUNT;
 	goto unlock;
 }
 
@@ -1210,7 +1202,6 @@
 	ARPT_ENTRY_ITERATE(table->private->entries, table->private->size,
 			   cleanup_entry, NULL);
 	vfree(table->private);
-	MOD_DEC_USE_COUNT;
 }
 
 /* The built-in targets: standard (NULL) and error. */
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_core.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_core.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_core.c	Mon Mar 31 12:20:18 2003
@@ -290,9 +290,6 @@
 {
 	DEBUGP("clean_from_lists(%p)\n", ct);
 	MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
-	/* Remove from both hash lists: must not NULL out next ptrs,
-           otherwise we'll look unconfirmed.  Fortunately, LIST_DELETE
-           doesn't do this. --RR */
 	LIST_DELETE(&ip_conntrack_hash
 		    [hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)],
 		    &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
@@ -465,6 +462,7 @@
 		ct->timeout.expires += jiffies;
 		add_timer(&ct->timeout);
 		atomic_inc(&ct->ct_general.use);
+		set_bit(IPS_CONFIRMED_BIT, &ct->status);
 		WRITE_UNLOCK(&ip_conntrack_lock);
 		return NF_ACCEPT;
 	}
@@ -583,7 +581,7 @@
    connection.  Too bad: we're in trouble anyway. */
 static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
 {
-	return !(i->ctrack->status & IPS_ASSURED);
+	return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
 }
 
 static int early_drop(struct list_head *chain)
@@ -718,7 +716,7 @@
 			conntrack, expected);
 		/* Welcome, Mr. Bond.  We've been expecting you... */
 		IP_NF_ASSERT(master_ct(conntrack));
-		conntrack->status = IPS_EXPECTED;
+		__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
 		conntrack->master = expected;
 		expected->sibling = conntrack;
 		LIST_DELETE(&ip_conntrack_expect_list, expected);
@@ -766,11 +764,11 @@
 		*set_reply = 1;
 	} else {
 		/* Once we've had two way comms, always ESTABLISHED. */
-		if (h->ctrack->status & IPS_SEEN_REPLY) {
+		if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
 			DEBUGP("ip_conntrack_in: normal packet for %p\n",
 			       h->ctrack);
 		        *ctinfo = IP_CT_ESTABLISHED;
-		} else if (h->ctrack->status & IPS_EXPECTED) {
+		} else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
 			DEBUGP("ip_conntrack_in: related packet for %p\n",
 			       h->ctrack);
 			*ctinfo = IP_CT_RELATED;
@@ -1128,8 +1126,6 @@
 
 int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
 {
-	MOD_INC_USE_COUNT;
-
 	WRITE_LOCK(&ip_conntrack_lock);
 	list_prepend(&helpers, me);
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -1166,8 +1162,6 @@
 	/* Someone could be still looking at the helper in a bh. */
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
-
-	MOD_DEC_USE_COUNT;
 }
 
 /* Refresh conntrack for this many jiffies. */
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_ftp.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_ftp.c	Mon Mar 31 12:20:18 2003
@@ -32,7 +32,7 @@
 
 static int try_rfc959(const char *, size_t, u_int32_t [], char);
 static int try_eprt(const char *, size_t, u_int32_t [], char);
-static int try_espv_response(const char *, size_t, u_int32_t [], char);
+static int try_epsv_response(const char *, size_t, u_int32_t [], char);
 
 static struct ftp_search {
 	enum ip_conntrack_dir dir;
@@ -65,7 +65,7 @@
 		IP_CT_DIR_REPLY,
 		"229 ", sizeof("229 ") - 1, '(', ')',
 		IP_CT_FTP_EPSV,
-		try_espv_response,
+		try_epsv_response,
 	},
 };
 
@@ -157,7 +157,7 @@
 }
 
 /* Returns 0, or length of numbers: |||6446| */
-static int try_espv_response(const char *data, size_t dlen, u_int32_t array[6],
+static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6],
 			     char term)
 {
 	char delim;
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	Mon Mar 31 12:20:18 2003
@@ -190,7 +190,7 @@
 	   have an established connection: this is a fairly common
 	   problem case, so we can delete the conntrack
 	   immediately.  --RR */
-	if (!(conntrack->status & IPS_SEEN_REPLY) && tcph->rst) {
+	if (!test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) && tcph->rst) {
 		WRITE_UNLOCK(&tcp_lock);
 		if (del_timer(&conntrack->timeout))
 			conntrack->timeout.function((unsigned long)conntrack);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Mon Feb 24 11:05:04 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_proto_udp.c	Mon Mar 31 12:20:18 2003
@@ -51,7 +51,7 @@
 {
 	/* If we've seen traffic both ways, this is some kind of UDP
 	   stream.  Extend timeout. */
-	if (conntrack->status & IPS_SEEN_REPLY) {
+	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
 		ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
 		/* Also, more likely to be important, and not a probe */
 		set_bit(IPS_ASSURED_BIT, &conntrack->status);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Feb 24 11:05:31 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_conntrack_standalone.c	Mon Mar 31 12:20:18 2003
@@ -33,7 +33,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-struct module *ip_conntrack_module = THIS_MODULE;
 MODULE_LICENSE("GPL");
 
 static int kill_proto(const struct ip_conntrack *i, void *data)
@@ -77,7 +76,7 @@
 }
 
 static unsigned int
-print_conntrack(char *buffer, const struct ip_conntrack *conntrack)
+print_conntrack(char *buffer, struct ip_conntrack *conntrack)
 {
 	unsigned int len;
 	struct ip_conntrack_protocol *proto
@@ -95,12 +94,12 @@
 	len += print_tuple(buffer + len,
 			   &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
 			   proto);
-	if (!(conntrack->status & IPS_SEEN_REPLY))
+	if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
 		len += sprintf(buffer + len, "[UNREPLIED] ");
 	len += print_tuple(buffer + len,
 			   &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
 			   proto);
-	if (conntrack->status & IPS_ASSURED)
+	if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
 		len += sprintf(buffer + len, "[ASSURED] ");
 	len += sprintf(buffer + len, "use=%u ",
 		       atomic_read(&conntrack->ct_general.use));
@@ -310,7 +309,6 @@
 	}
 
 	list_prepend(&protocol_list, proto);
-	MOD_INC_USE_COUNT;
 
  out:
 	WRITE_UNLOCK(&ip_conntrack_lock);
@@ -332,8 +330,6 @@
 
 	/* Remove all contrack entries for this protocol */
 	ip_ct_selective_cleanup(kill_proto, &proto->proto);
-
-	MOD_DEC_USE_COUNT;
 }
 
 static int __init init(void)
@@ -349,13 +345,19 @@
 module_init(init);
 module_exit(fini);
 
+/* Some modules need us, but don't depend directly on any symbol.
+   They should call this. */
+void need_ip_conntrack(void)
+{
+}
+
 EXPORT_SYMBOL(ip_conntrack_protocol_register);
 EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
 EXPORT_SYMBOL(invert_tuplepr);
 EXPORT_SYMBOL(ip_conntrack_alter_reply);
 EXPORT_SYMBOL(ip_conntrack_destroyed);
 EXPORT_SYMBOL(ip_conntrack_get);
-EXPORT_SYMBOL(ip_conntrack_module);
+EXPORT_SYMBOL(need_ip_conntrack);
 EXPORT_SYMBOL(ip_conntrack_helper_register);
 EXPORT_SYMBOL(ip_conntrack_helper_unregister);
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_core.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_core.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_core.c	Mon Mar 31 12:20:18 2003
@@ -913,7 +913,7 @@
 		   packet, except it was never src/dst reversed, so
 		   where we would normally apply a dst manip, we apply
 		   a src, and vice versa. */
-		if (info->manips[i].hooknum == opposite_hook[hooknum]) {
+		if (info->manips[i].hooknum == hooknum) {
 			DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
 			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
 			       ? "DST" : "SRC",
@@ -924,9 +924,9 @@
 				  &info->manips[i].manip,
 				  !info->manips[i].maniptype,
 				  &skb->nfcache);
-		/* Outer packet needs to have IP header NATed like
-                   it's a reply. */
-		} else if (info->manips[i].hooknum == hooknum) {
+			/* Outer packet needs to have IP header NATed like
+	                   it's a reply. */
+
 			/* Use mapping to map outer packet: 0 give no
                            per-proto mapping */
 			DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_helper.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_helper.c	Mon Feb 24 11:05:10 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_helper.c	Mon Mar 31 12:20:18 2003
@@ -478,9 +478,9 @@
 	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
 		struct ip_conntrack_helper *ct_helper;
 		
-		if ((ct_helper = ip_ct_find_helper(&me->tuple))
-		    && ct_helper->me) {
-			__MOD_INC_USE_COUNT(ct_helper->me);
+		if ((ct_helper = ip_ct_find_helper(&me->tuple))) {
+			if (!try_module_get(ct_helper->me))
+				return -EBUSY;
 		} else {
 			/* We are a NAT helper for protocol X.  If we need
 			 * respective conntrack helper for protoccol X, compute
@@ -498,9 +498,9 @@
 			sprintf(name, "ip_conntrack%s", tmp);
 #ifdef CONFIG_KMOD
 			if (!request_module(name)
-			    && (ct_helper = ip_ct_find_helper(&me->tuple))
-			    && ct_helper->me) {
-				__MOD_INC_USE_COUNT(ct_helper->me);
+			    && (ct_helper = ip_ct_find_helper(&me->tuple))) {
+				if (!try_module_get(ct_helper->me))
+					return -EBUSY;
 			} else {
 				printk("unable to load module %s\n", name);
 				return -EBUSY;
@@ -516,10 +516,8 @@
 	WRITE_LOCK(&ip_nat_lock);
 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple))
 		ret = -EBUSY;
-	else {
+	else
 		list_prepend(&helpers, me);
-		MOD_INC_USE_COUNT;
-	}
 	WRITE_UNLOCK(&ip_nat_lock);
 
 	return ret;
@@ -539,13 +537,10 @@
 
 void ip_nat_helper_unregister(struct ip_nat_helper *me)
 {
-	int found = 0;
-	
 	WRITE_LOCK(&ip_nat_lock);
 	/* Autoloading conntrack helper might have failed */
 	if (LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,&me->tuple)) {
 		LIST_DELETE(&helpers, me);
-		found = 1;
 	}
 	WRITE_UNLOCK(&ip_nat_lock);
 
@@ -562,18 +557,13 @@
 	   worse. --RR */
 	ip_ct_selective_cleanup(kill_helper, me);
 
-	if (found)
-		MOD_DEC_USE_COUNT;
-
 	/* If we are no standalone NAT helper, we need to decrement usage count
 	 * on our conntrack helper */
 	if (me->me && !(me->flags & IP_NAT_HELPER_F_STANDALONE)) {
 		struct ip_conntrack_helper *ct_helper;
 		
-		if ((ct_helper = ip_ct_find_helper(&me->tuple))
-		    && ct_helper->me) {
-			__MOD_DEC_USE_COUNT(ct_helper->me);
-		}
+		if ((ct_helper = ip_ct_find_helper(&me->tuple)))
+			module_put(ct_helper->me);
 #ifdef CONFIG_MODULES
 		else 
 			printk("%s: unable to decrement usage count"
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_standalone.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_nat_standalone.c	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_nat_standalone.c	Mon Mar 31 12:20:18 2003
@@ -255,8 +255,6 @@
 	}
 
 	list_prepend(&protos, proto);
-	MOD_INC_USE_COUNT;
-
  out:
 	WRITE_UNLOCK(&ip_nat_lock);
 	return ret;
@@ -272,14 +270,14 @@
 	/* Someone could be still looking at the proto in a bh. */
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
-
-	MOD_DEC_USE_COUNT;
 }
 
 static int init_or_cleanup(int init)
 {
 	int ret = 0;
 
+	need_ip_conntrack();
+
 	if (!init) goto cleanup;
 
 	ret = ip_nat_rule_init();
@@ -314,13 +312,9 @@
 		goto cleanup_localoutops;
 	}
 #endif
-	if (ip_conntrack_module)
-		__MOD_INC_USE_COUNT(ip_conntrack_module);
 	return ret;
 
  cleanup:
-	if (ip_conntrack_module)
-		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 #ifdef CONFIG_IP_NF_NAT_LOCAL
 	nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ip_tables.c linux-2.5.63-bk7/net/ipv4/netfilter/ip_tables.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ip_tables.c	Mon Feb 24 11:05:12 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ip_tables.c	Mon Mar 31 12:20:18 2003
@@ -598,10 +598,7 @@
 	if (m->u.kernel.match->destroy)
 		m->u.kernel.match->destroy(m->data,
 					   m->u.match_size - sizeof(*m));
-
-	if (m->u.kernel.match->me)
-		__MOD_DEC_USE_COUNT(m->u.kernel.match->me);
-
+	module_put(m->u.kernel.match->me);
 	return 0;
 }
 
@@ -650,8 +647,10 @@
 		duprintf("check_match: `%s' not found\n", m->u.user.name);
 		return ret;
 	}
-	if (match->me)
-		__MOD_INC_USE_COUNT(match->me);
+	if (!try_module_get(match->me)) {
+		up(&ipt_mutex);
+		return -ENOENT;
+	}
 	m->u.kernel.match = match;
 	up(&ipt_mutex);
 
@@ -659,8 +658,7 @@
 	    && !m->u.kernel.match->checkentry(name, ip, m->data,
 					      m->u.match_size - sizeof(*m),
 					      hookmask)) {
-		if (m->u.kernel.match->me)
-			__MOD_DEC_USE_COUNT(m->u.kernel.match->me);
+		module_put(m->u.kernel.match->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 m->u.kernel.match->name);
 		return -EINVAL;
@@ -697,8 +695,11 @@
 		duprintf("check_entry: `%s' not found\n", t->u.user.name);
 		goto cleanup_matches;
 	}
-	if (target->me)
-		__MOD_INC_USE_COUNT(target->me);
+	if (!try_module_get(target->me)) {
+		up(&ipt_mutex);
+		ret = -ENOENT;
+		goto cleanup_matches;
+	}
 	t->u.kernel.target = target;
 	up(&ipt_mutex);
 
@@ -712,8 +713,7 @@
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		if (t->u.kernel.target->me)
-			__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
+		module_put(t->u.kernel.target->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
@@ -785,9 +785,7 @@
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->data,
 					    t->u.target_size - sizeof(*t));
-	if (t->u.kernel.target->me)
-		__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
-
+	module_put(t->u.kernel.target->me);
 	return 0;
 }
 
@@ -1319,17 +1317,14 @@
 {
 	int ret;
 
-	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0) {
-		MOD_DEC_USE_COUNT;
+	if (ret != 0)
 		return ret;
-	}
+
 	if (!list_named_insert(&ipt_target, target)) {
 		duprintf("ipt_register_target: `%s' already in list!\n",
 			 target->name);
 		ret = -EINVAL;
-		MOD_DEC_USE_COUNT;
 	}
 	up(&ipt_mutex);
 	return ret;
@@ -1341,7 +1336,6 @@
 	down(&ipt_mutex);
 	LIST_DELETE(&ipt_target, target);
 	up(&ipt_mutex);
-	MOD_DEC_USE_COUNT;
 }
 
 int
@@ -1349,16 +1343,13 @@
 {
 	int ret;
 
-	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ipt_mutex);
-	if (ret != 0) {
-		MOD_DEC_USE_COUNT;
+	if (ret != 0)
 		return ret;
-	}
+
 	if (!list_named_insert(&ipt_match, match)) {
 		duprintf("ipt_register_match: `%s' already in list!\n",
 			 match->name);
-		MOD_DEC_USE_COUNT;
 		ret = -EINVAL;
 	}
 	up(&ipt_mutex);
@@ -1372,7 +1363,6 @@
 	down(&ipt_mutex);
 	LIST_DELETE(&ipt_match, match);
 	up(&ipt_mutex);
-	MOD_DEC_USE_COUNT;
 }
 
 int ipt_register_table(struct ipt_table *table)
@@ -1382,14 +1372,11 @@
 	static struct ipt_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { } };
 
-	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ipt_table_info)
 			  + SMP_ALIGN(table->table->size) * NR_CPUS);
-	if (!newinfo) {
-		ret = -ENOMEM;
-		MOD_DEC_USE_COUNT;
-		return ret;
-	}
+	if (!newinfo)
+		return -ENOMEM;
+
 	memcpy(newinfo->entries, table->table->entries, table->table->size);
 
 	ret = translate_table(table->name, table->valid_hooks,
@@ -1399,14 +1386,12 @@
 			      table->table->underflow);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
 	ret = down_interruptible(&ipt_mutex);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
@@ -1436,7 +1421,6 @@
 
  free_unlock:
 	vfree(newinfo);
-	MOD_DEC_USE_COUNT;
 	goto unlock;
 }
 
@@ -1450,7 +1434,6 @@
 	IPT_ENTRY_ITERATE(table->private->entries, table->private->size,
 			  cleanup_entry, NULL);
 	vfree(table->private);
-	MOD_DEC_USE_COUNT;
 }
 
 /* Returns 1 if the port is matched by the range, 0 otherwise */
@@ -1628,7 +1611,7 @@
 		     u_int8_t type, u_int8_t code,
 		     int invert)
 {
-	return (type == test_type && code >= min_code && code <= max_code)
+	return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
 		^ invert;
 }
 
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ipchains_core.c linux-2.5.63-bk7/net/ipv4/netfilter/ipchains_core.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ipchains_core.c	Mon Feb 24 11:05:41 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ipchains_core.c	Mon Mar 31 12:20:18 2003
@@ -1566,16 +1566,8 @@
 
 /* File offset is actually in records, not bytes. */
 static int ip_chain_procinfo(char *buffer, char **start,
-			     off_t offset, int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			     , int reset
-#endif
-	)
+			     off_t offset, int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
 	struct ip_chain *i;
 	struct ip_fwkernel *j = ip_fw_chains->chain;
 	unsigned long flags;
@@ -1612,9 +1604,6 @@
 				len = last_len;
 				goto outside;
 			}
-			else if (reset)
-				memset(j->counters, 0,
-				       sizeof(struct ip_counters)*NUM_SLOTS);
 		}
 	}
 outside:
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ipfwadm_core.c linux-2.5.63-bk7/net/ipv4/netfilter/ipfwadm_core.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ipfwadm_core.c	Mon Feb 24 11:05:16 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ipfwadm_core.c	Mon Mar 31 12:20:18 2003
@@ -1113,9 +1113,8 @@
 #endif /* CONFIG_IP_FIREWALL */
 
 #if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT)
-
 static int ip_chain_procinfo(int stage, char *buffer, char **start,
-			     off_t offset, int length, int reset)
+			     off_t offset, int length)
 {
 	off_t pos=0, begin=0;
 	struct ip_fw *i;
@@ -1184,15 +1183,6 @@
 			len = last_len;
 			break;
 		}
-/* Not possible in 2.3.29+, also allowing read lock instead of write -- JM */
-#if 0
-		else if(reset)
-		{
-			/* This needs to be done at this specific place! */
-			i->fw_pcnt=0L;
-			i->fw_bcnt=0L;
-		}
-#endif
 		last_len = len;
 		i=i->fw_next;
 	}
@@ -1206,69 +1196,30 @@
 #endif
 
 #ifdef CONFIG_IP_ACCT
-
 static int ip_acct_procinfo(char *buffer, char **start, off_t offset,
-			    int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
+			    int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length,
-				 reset);
+	return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length);
 }
-
 #endif
 
 #ifdef CONFIG_IP_FIREWALL
-
 static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			     , int reset
-#endif
-	)
+			      int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length,
-				 reset);
+	return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length);
 }
 
 static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
+			      int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length,
-				 reset);
+	return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length);
 }
 
 static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset,
-			      int length
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,29)
-			    , int reset
-#endif
-	)
+			      int length)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,29)
-	/* FIXME: No more `atomic' read and reset.  Wonderful 8-( --RR */
-	int reset = 0;
-#endif
-	return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length,
-				 reset);
+	return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length);
 }
 #endif
 
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ipt_conntrack.c linux-2.5.63-bk7/net/ipv4/netfilter/ipt_conntrack.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ipt_conntrack.c	Mon Feb 24 11:05:43 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ipt_conntrack.c	Mon Mar 31 12:20:18 2003
@@ -105,17 +105,13 @@
 
 static int __init init(void)
 {
-	/* NULL if ip_conntrack not a module */
-	if (ip_conntrack_module)
-		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	need_ip_conntrack();
 	return ipt_register_match(&conntrack_match);
 }
 
 static void __exit fini(void)
 {
 	ipt_unregister_match(&conntrack_match);
-	if (ip_conntrack_module)
-		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 }
 
 module_init(init);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ipt_helper.c linux-2.5.63-bk7/net/ipv4/netfilter/ipt_helper.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ipt_helper.c	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ipt_helper.c	Mon Mar 31 12:20:18 2003
@@ -94,17 +94,13 @@
 
 static int __init init(void)
 {
-	/* NULL if ip_conntrack not a module */
-	if (ip_conntrack_module)
-		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	need_ip_conntrack();
 	return ipt_register_match(&helper_match);
 }
 
 static void __exit fini(void)
 {
 	ipt_unregister_match(&helper_match);
-	if (ip_conntrack_module)
-		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 }
 
 module_init(init);
diff -urN linux-2.5.63-bk6/net/ipv4/netfilter/ipt_state.c linux-2.5.63-bk7/net/ipv4/netfilter/ipt_state.c
--- linux-2.5.63-bk6/net/ipv4/netfilter/ipt_state.c	Mon Feb 24 11:06:02 2003
+++ linux-2.5.63-bk7/net/ipv4/netfilter/ipt_state.c	Mon Mar 31 12:20:18 2003
@@ -46,17 +46,13 @@
 
 static int __init init(void)
 {
-	/* NULL if ip_conntrack not a module */
-	if (ip_conntrack_module)
-		__MOD_INC_USE_COUNT(ip_conntrack_module);
+	need_ip_conntrack();
 	return ipt_register_match(&state_match);
 }
 
 static void __exit fini(void)
 {
 	ipt_unregister_match(&state_match);
-	if (ip_conntrack_module)
-		__MOD_DEC_USE_COUNT(ip_conntrack_module);
 }
 
 module_init(init);
diff -urN linux-2.5.63-bk6/net/ipv6/addrconf.c linux-2.5.63-bk7/net/ipv6/addrconf.c
--- linux-2.5.63-bk6/net/ipv6/addrconf.c	Mon Feb 24 11:05:44 2003
+++ linux-2.5.63-bk7/net/ipv6/addrconf.c	Mon Mar 31 12:20:18 2003
@@ -2015,6 +2015,9 @@
 		write_lock(&addrconf_hash_lock);
 		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
 			unsigned long age;
+#ifdef CONFIG_IPV6_PRIVACY
+			unsigned long regen_advance;
+#endif
 
 			if (ifp->flags & IFA_F_PERMANENT)
 				continue;
@@ -2022,6 +2025,12 @@
 			spin_lock(&ifp->lock);
 			age = (now - ifp->tstamp) / HZ;
 
+#ifdef CONFIG_IPV6_PRIVACY
+			regen_advance = ifp->idev->cnf.regen_max_retry * 
+					ifp->idev->cnf.dad_transmits * 
+					ifp->idev->nd_parms->retrans_time / HZ;
+#endif
+
 			if (age >= ifp->valid_lft) {
 				spin_unlock(&ifp->lock);
 				in6_ifa_hold(ifp);
@@ -2050,6 +2059,28 @@
 					in6_ifa_put(ifp);
 					goto restart;
 				}
+#ifdef CONFIG_IPV6_PRIVACY
+			} else if ((ifp->flags&IFA_F_TEMPORARY) &&
+				   !(ifp->flags&IFA_F_TENTATIVE)) {
+				if (age >= ifp->prefered_lft - regen_advance) {
+					struct inet6_ifaddr *ifpub = ifp->ifpub;
+					if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
+						next = ifp->tstamp + ifp->prefered_lft * HZ;
+					if (!ifp->regen_count && ifpub) {
+						ifp->regen_count++;
+						in6_ifa_hold(ifp);
+						in6_ifa_hold(ifpub);
+						spin_unlock(&ifp->lock);
+						write_unlock(&addrconf_hash_lock);
+						ipv6_create_tempaddr(ifpub, ifp);
+						in6_ifa_put(ifpub);
+						in6_ifa_put(ifp);
+						goto restart;
+					}
+				} else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next))
+					next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ;
+				spin_unlock(&ifp->lock);
+#endif
 			} else {
 				/* ifp->prefered_lft <= ifp->valid_lft */
 				if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
@@ -2288,75 +2319,163 @@
 	ctl_table addrconf_proto_dir[2];
 	ctl_table addrconf_root_dir[2];
 } addrconf_sysctl = {
-	NULL,
-        {{NET_IPV6_FORWARDING, "forwarding",
-         &ipv6_devconf.forwarding, sizeof(int), 0644, NULL,
-         &addrconf_sysctl_forward},
-
-	{NET_IPV6_HOP_LIMIT, "hop_limit",
-         &ipv6_devconf.hop_limit, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_MTU, "mtu",
-         &ipv6_devconf.mtu6, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_ACCEPT_RA, "accept_ra",
-         &ipv6_devconf.accept_ra, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_ACCEPT_REDIRECTS, "accept_redirects",
-         &ipv6_devconf.accept_redirects, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_AUTOCONF, "autoconf",
-         &ipv6_devconf.autoconf, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_DAD_TRANSMITS, "dad_transmits",
-         &ipv6_devconf.dad_transmits, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_RTR_SOLICITS, "router_solicitations",
-         &ipv6_devconf.rtr_solicits, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-
-	{NET_IPV6_RTR_SOLICIT_INTERVAL, "router_solicitation_interval",
-         &ipv6_devconf.rtr_solicit_interval, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies},
-
-	{NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay",
-         &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies},
-
+	.sysctl_header = NULL,
+	.addrconf_vars = {
+        	{
+			.ctl_name	=	NET_IPV6_FORWARDING,
+			.procname	=	"forwarding",
+         		.data		=	&ipv6_devconf.forwarding,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&addrconf_sysctl_forward,
+		},
+		{
+			.ctl_name	=	NET_IPV6_HOP_LIMIT,
+			.procname	=	"hop_limit",
+         		.data		=	&ipv6_devconf.hop_limit,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+			.proc_handler	=	proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_MTU,
+			.procname	=	"mtu",
+			.data		=	&ipv6_devconf.mtu6,
+         		.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_ACCEPT_RA,
+			.procname	=	"accept_ra",
+         		.data		=	&ipv6_devconf.accept_ra,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_ACCEPT_REDIRECTS,
+			.procname	=	"accept_redirects",
+         		.data		=	&ipv6_devconf.accept_redirects,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_AUTOCONF,
+			.procname	=	"autoconf",
+         		.data		=	&ipv6_devconf.autoconf,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_DAD_TRANSMITS,
+			.procname	=	"dad_transmits",
+         		.data		=	&ipv6_devconf.dad_transmits,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_RTR_SOLICITS,
+			.procname	=	"router_solicitations",
+         		.data		=	&ipv6_devconf.rtr_solicits,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_RTR_SOLICIT_INTERVAL,
+			.procname	=	"router_solicitation_interval",
+         		.data		=	&ipv6_devconf.rtr_solicit_interval,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec_jiffies,
+		},
+		{
+			.ctl_name	=	NET_IPV6_RTR_SOLICIT_DELAY,
+			.procname	=	"router_solicitation_delay",
+         		.data		=	&ipv6_devconf.rtr_solicit_delay,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+         		.proc_handler	=	&proc_dointvec_jiffies,
+		},
 #ifdef CONFIG_IPV6_PRIVACY
-	{NET_IPV6_USE_TEMPADDR, "use_tempaddr",
-	 &ipv6_devconf.use_tempaddr, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-
-	{NET_IPV6_TEMP_VALID_LFT, "temp_valid_lft",
-	 &ipv6_devconf.temp_valid_lft, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-
-	{NET_IPV6_TEMP_PREFERED_LFT, "temp_prefered_lft",
-	 &ipv6_devconf.temp_prefered_lft, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-
-	{NET_IPV6_REGEN_MAX_RETRY, "regen_max_retry",
-	 &ipv6_devconf.regen_max_retry, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-
-	{NET_IPV6_MAX_DESYNC_FACTOR, "max_desync_factor",
-	 &ipv6_devconf.max_desync_factor, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
+		{
+			.ctl_name	=	NET_IPV6_USE_TEMPADDR,
+			.procname	=	"use_tempaddr",
+	 		.data		=	&ipv6_devconf.use_tempaddr,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+	 		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_TEMP_VALID_LFT,
+			.procname	=	"temp_valid_lft",
+	 		.data		=	&ipv6_devconf.temp_valid_lft,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+	 		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_TEMP_PREFERED_LFT,
+			.procname	=	"temp_prefered_lft",
+	 		.data		=	&ipv6_devconf.temp_prefered_lft,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+	 		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_REGEN_MAX_RETRY,
+			.procname	=	"regen_max_retry",
+	 		.data		=	&ipv6_devconf.regen_max_retry,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+	 		.proc_handler	=	&proc_dointvec,
+		},
+		{
+			.ctl_name	=	NET_IPV6_MAX_DESYNC_FACTOR,
+			.procname	=	"max_desync_factor",
+	 		.data		=	&ipv6_devconf.max_desync_factor,
+			.maxlen		=	sizeof(int),
+			.mode		=	0644,
+	 		.proc_handler	=	&proc_dointvec,
+		},
 #endif
-
-	{0}},
-
-	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}},
-	{{NET_IPV6_CONF, "conf", NULL, 0, 0555, addrconf_sysctl.addrconf_dev},{0}},
-	{{NET_IPV6, "ipv6", NULL, 0, 0555, addrconf_sysctl.addrconf_conf_dir},{0}},
-	{{CTL_NET, "net", NULL, 0, 0555, addrconf_sysctl.addrconf_proto_dir},{0}}
+	},
+	.addrconf_dev = {
+		{
+			.ctl_name	=	NET_PROTO_CONF_ALL,
+			.procname	=	"all",
+			.mode		=	0555,
+			.child		=	addrconf_sysctl.addrconf_vars,
+		},
+	},
+	.addrconf_conf_dir = {
+		{
+			.ctl_name	=	NET_IPV6_CONF,
+			.procname	=	"conf",
+			.mode		=	0555,
+			.child		=	addrconf_sysctl.addrconf_dev,
+		},
+	},
+	.addrconf_proto_dir = {
+		{
+			.ctl_name	=	NET_IPV6,
+			.procname	=	"ipv6",
+			.mode		=	0555,
+			.child		=	addrconf_sysctl.addrconf_conf_dir,
+		},
+	},
+	.addrconf_root_dir = {
+		{
+			.ctl_name	=	CTL_NET,
+			.procname	=	"net",
+			.mode		=	0555,
+			.child		=	addrconf_sysctl.addrconf_proto_dir,
+		},
+	},
 };
 
 static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf *p)
diff -urN linux-2.5.63-bk6/net/ipv6/ipv6_syms.c linux-2.5.63-bk7/net/ipv6/ipv6_syms.c
--- linux-2.5.63-bk6/net/ipv6/ipv6_syms.c	Mon Feb 24 11:05:38 2003
+++ linux-2.5.63-bk7/net/ipv6/ipv6_syms.c	Mon Mar 31 12:20:18 2003
@@ -29,3 +29,5 @@
 EXPORT_SYMBOL(inet6_ioctl);
 EXPORT_SYMBOL(ipv6_get_saddr);
 EXPORT_SYMBOL(ipv6_chk_addr);
+EXPORT_SYMBOL(in6addr_any);
+EXPORT_SYMBOL(in6addr_loopback);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/Kconfig linux-2.5.63-bk7/net/ipv6/netfilter/Kconfig
--- linux-2.5.63-bk6/net/ipv6/netfilter/Kconfig	Mon Feb 24 11:05:42 2003
+++ linux-2.5.63-bk7/net/ipv6/netfilter/Kconfig	Mon Mar 31 12:20:18 2003
@@ -60,6 +60,46 @@
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
+config IP6_NF_MATCH_RT
+	tristate "Routing header match support"
+	depends on IP6_NF_IPTABLES && EXPERIMENTAL
+	help
+	  rt matching allows you to match packets based on the routing
+	  header of the packet.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config IP6_NF_MATCH_OPTS
+	tristate "Hop-by-hop and Dst opts header match support"
+	depends on IP6_NF_IPTABLES && EXPERIMENTAL
+	help
+	  This allows one to match packets based on the hop-by-hop
+	  and destination options headers of a packet.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config IP6_NF_MATCH_FRAG
+	tristate "Fragmentation header match support"
+	depends on IP6_NF_IPTABLES && EXPERIMENTAL
+	help
+	  frag matching allows you to match packets based on the fragmentation
+	  header of the packet.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config IP6_NF_MATCH_HL
+	tristate "HL match support"
+	depends on IP6_NF_IPTABLES
+	help
+	  HL matching allows you to match packets based on the hop
+	  limit of the packet.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
 config IP6_NF_MATCH_MULTIPORT
 	tristate "Multiple port match support"
 	depends on IP6_NF_IPTABLES
@@ -92,6 +132,25 @@
 
 	  If you want to compile it as a module, say M here and read
 	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config IP6_NF_MATCH_IPV6HEADER
+	tristate "IPv6 Extension Headers Match (EXPERIMENTAL)"
+	depends on IP6_NF_IPTABLES && EXPERIMENTAL
+	help
+	  This module allows one to match packets based upon
+	  the ipv6 extension headers.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+config IP6_NF_MATCH_AHESP
+	tristate "AH/ESP match support (EXPERIMENTAL)"
+	depends on IP6_NF_IPTABLES && EXPERIMENTAL
+	help
+	  This module allows one to match AH and ESP packets.
+
+	  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  If unsure, say `N'.
 
 config IP6_NF_MATCH_LENGTH
 	tristate "Packet Length match support"
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/Makefile linux-2.5.63-bk7/net/ipv6/netfilter/Makefile
--- linux-2.5.63-bk6/net/ipv6/netfilter/Makefile	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/net/ipv6/netfilter/Makefile	Mon Mar 31 12:20:18 2003
@@ -8,6 +8,11 @@
 obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
 obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
 obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
+obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
+obj-$(CONFIG_IP6_NF_MATCH_AHESP) += ip6t_esp.o ip6t_ah.o
 obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
 obj-$(CONFIG_IP6_NF_MATCH_MULTIPORT) += ip6t_multiport.o
 obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o
@@ -16,3 +21,4 @@
 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
+obj-$(CONFIG_IP_NF_MATCH_HL) += ip6t_hl.o
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6_tables.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6_tables.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6_tables.c	Mon Feb 24 11:05:43 2003
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6_tables.c	Mon Mar 31 12:20:18 2003
@@ -671,10 +671,7 @@
 	if (m->u.kernel.match->destroy)
 		m->u.kernel.match->destroy(m->data,
 					   m->u.match_size - sizeof(*m));
-
-	if (m->u.kernel.match->me)
-		__MOD_DEC_USE_COUNT(m->u.kernel.match->me);
-
+	module_put(m->u.kernel.match->me);
 	return 0;
 }
 
@@ -723,8 +720,10 @@
 	  //		duprintf("check_match: `%s' not found\n", m->u.name);
 		return ret;
 	}
-	if (match->me)
-		__MOD_INC_USE_COUNT(match->me);
+	if (!try_module_get(match->me)) {
+		up(&ip6t_mutex);
+		return -ENOENT;
+	}
 	m->u.kernel.match = match;
 	up(&ip6t_mutex);
 
@@ -732,8 +731,7 @@
 	    && !m->u.kernel.match->checkentry(name, ipv6, m->data,
 					      m->u.match_size - sizeof(*m),
 					      hookmask)) {
-		if (m->u.kernel.match->me)
-			__MOD_DEC_USE_COUNT(m->u.kernel.match->me);
+		module_put(m->u.kernel.match->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 m->u.kernel.match->name);
 		return -EINVAL;
@@ -770,11 +768,17 @@
 		duprintf("check_entry: `%s' not found\n", t->u.user.name);
 		goto cleanup_matches;
 	}
-	if (target->me)
-		__MOD_INC_USE_COUNT(target->me);
+	if (!try_module_get(target->me)) {
+		up(&ip6t_mutex);
+		ret = -ENOENT;
+		goto cleanup_matches;
+	}
 	t->u.kernel.target = target;
 	up(&ip6t_mutex);
-
+	if (!t->u.kernel.target) {
+		ret = -EBUSY;
+		goto cleanup_matches;
+	}
 	if (t->u.kernel.target == &ip6t_standard_target) {
 		if (!standard_check(t, size)) {
 			ret = -EINVAL;
@@ -785,8 +789,7 @@
 						      t->u.target_size
 						      - sizeof(*t),
 						      e->comefrom)) {
-		if (t->u.kernel.target->me)
-			__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
+		module_put(t->u.kernel.target->me);
 		duprintf("ip_tables: check failed for `%s'.\n",
 			 t->u.kernel.target->name);
 		ret = -EINVAL;
@@ -858,9 +861,7 @@
 	if (t->u.kernel.target->destroy)
 		t->u.kernel.target->destroy(t->data,
 					    t->u.target_size - sizeof(*t));
-	if (t->u.kernel.target->me)
-		__MOD_DEC_USE_COUNT(t->u.kernel.target->me);
-
+	module_put(t->u.kernel.target->me);
 	return 0;
 }
 
@@ -1388,17 +1389,14 @@
 {
 	int ret;
 
-	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ip6t_mutex);
-	if (ret != 0) {
-		MOD_DEC_USE_COUNT;
+	if (ret != 0)
 		return ret;
-	}
+
 	if (!list_named_insert(&ip6t_target, target)) {
 		duprintf("ip6t_register_target: `%s' already in list!\n",
 			 target->name);
 		ret = -EINVAL;
-		MOD_DEC_USE_COUNT;
 	}
 	up(&ip6t_mutex);
 	return ret;
@@ -1410,7 +1408,6 @@
 	down(&ip6t_mutex);
 	LIST_DELETE(&ip6t_target, target);
 	up(&ip6t_mutex);
-	MOD_DEC_USE_COUNT;
 }
 
 int
@@ -1418,16 +1415,13 @@
 {
 	int ret;
 
-	MOD_INC_USE_COUNT;
 	ret = down_interruptible(&ip6t_mutex);
-	if (ret != 0) {
-		MOD_DEC_USE_COUNT;
+	if (ret != 0)
 		return ret;
-	}
+
 	if (!list_named_insert(&ip6t_match, match)) {
 		duprintf("ip6t_register_match: `%s' already in list!\n",
 			 match->name);
-		MOD_DEC_USE_COUNT;
 		ret = -EINVAL;
 	}
 	up(&ip6t_mutex);
@@ -1441,7 +1435,6 @@
 	down(&ip6t_mutex);
 	LIST_DELETE(&ip6t_match, match);
 	up(&ip6t_mutex);
-	MOD_DEC_USE_COUNT;
 }
 
 int ip6t_register_table(struct ip6t_table *table)
@@ -1451,14 +1444,11 @@
 	static struct ip6t_table_info bootstrap
 		= { 0, 0, 0, { 0 }, { 0 }, { }, { } };
 
-	MOD_INC_USE_COUNT;
 	newinfo = vmalloc(sizeof(struct ip6t_table_info)
 			  + SMP_ALIGN(table->table->size) * NR_CPUS);
-	if (!newinfo) {
-		ret = -ENOMEM;
-		MOD_DEC_USE_COUNT;
-		return ret;
-	}
+	if (!newinfo)
+		return -ENOMEM;
+
 	memcpy(newinfo->entries, table->table->entries, table->table->size);
 
 	ret = translate_table(table->name, table->valid_hooks,
@@ -1468,14 +1458,12 @@
 			      table->table->underflow);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
 	ret = down_interruptible(&ip6t_mutex);
 	if (ret != 0) {
 		vfree(newinfo);
-		MOD_DEC_USE_COUNT;
 		return ret;
 	}
 
@@ -1505,7 +1493,6 @@
 
  free_unlock:
 	vfree(newinfo);
-	MOD_DEC_USE_COUNT;
 	goto unlock;
 }
 
@@ -1519,7 +1506,6 @@
 	IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
 			  cleanup_entry, NULL);
 	vfree(table->private);
-	MOD_DEC_USE_COUNT;
 }
 
 /* Returns 1 if the port is matched by the range, 0 otherwise */
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_ah.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_ah.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_ah.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_ah.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,218 @@
+/* Kernel module to match AH parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ah.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 AH match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct ahhdr {
+       __u8    nexthdr;
+       __u8    hdrlen;
+       __u16   reserved;
+       __u32   spi;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* 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;
+       DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,spi,max);
+       r=(spi >= min && spi <= max) ^ invert;
+       DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+       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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ahhdr *ah = NULL;
+       const struct ip6t_ah *ahinfo = matchinfo;
+       unsigned int temp;
+       int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+
+       /*DEBUGP("IPv6 AH entered\n");*/
+       /* if (opt->auth == 0) return 0;
+       * It does not filled on output */
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_ah header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* AH -> evaluate */
+                if (nexthdr == NEXTHDR_AUTH) {
+                     temp |= MASK_AH;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_ah: new pointer too large! \n");
+			break;
+		}
+        }
+
+       /* AH header not found */
+       if ( temp != MASK_AH ) return 0;
+
+       if (len < (int)sizeof(struct ahhdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       ah=skb->data+ptr;
+
+       DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
+       DEBUGP("RES %04X ", ah->reserved);
+       DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
+
+       DEBUGP("IPv6 AH spi %02X ",
+       		(spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                           ntohl(ah->spi),
+                           !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
+       DEBUGP("len %02X %04X %02X ",
+       		ahinfo->hdrlen, hdrlen,
+       		(!ahinfo->hdrlen ||
+                           (ahinfo->hdrlen == hdrlen) ^
+                           !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
+       DEBUGP("res %02X %04X %02X\n", 
+       		ahinfo->hdrres, ah->reserved,
+       		!(ahinfo->hdrres && ah->reserved));
+
+       return (ah != NULL)
+              &&
+              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
+                           ntohl(ah->spi),
+                           !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
+              &&
+              (!ahinfo->hdrlen ||
+                           (ahinfo->hdrlen == hdrlen) ^
+                           !!(ahinfo->invflags & IP6T_AH_INV_LEN))
+              &&
+              !(ahinfo->hdrres && ah->reserved);
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_ah *ahinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_ah))) {
+              DEBUGP("ip6t_ah: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_ah)));
+              return 0;
+       }
+       if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
+              DEBUGP("ip6t_ah: unknown flags %X\n",
+                      ahinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match ah_match
+= { { NULL, NULL }, "ah", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&ah_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&ah_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_dst.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_dst.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_dst.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_dst.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,287 @@
+/* Kernel module to match Hop-by-Hop and Destination parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+
+#define LOW(n)		(n & 0x00FF)
+
+#define HOPBYHOP	0
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+#if HOPBYHOP
+MODULE_DESCRIPTION("IPv6 HbH match");
+#else
+MODULE_DESCRIPTION("IPv6 DST match");
+#endif
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * (Type & 0xC0) >> 6
+ * 	0	-> ignorable
+ * 	1	-> must drop the packet
+ * 	2	-> send ICMP PARM PROB regardless and drop packet
+ * 	3	-> Send ICMP if not a multicast address and drop packet
+ *  (Type & 0x20) >> 5
+ *  	0	-> invariant
+ *  	1	-> can change the routing
+ *  (Type & 0x1F) Type
+ *      0	-> PAD0 (only 1 byte!)
+ *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
+ *      5	-> RTALERT 2 x x
+ */
+
+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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_opt_hdr *optsh = NULL;
+       const struct ip6t_opts *optinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+       u_int16_t *optdesc = NULL;
+       
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_opts header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(void *)(skb->data)+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* OPTS -> evaluate */
+#if HOPBYHOP
+                if (nexthdr == NEXTHDR_HOP) {
+                     temp |= MASK_HOPOPTS;
+#else
+                if (nexthdr == NEXTHDR_DEST) {
+                     temp |= MASK_DSTOPTS;
+#endif
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_opts: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* OPTIONS header not found */
+#if HOPBYHOP
+       if ( temp != MASK_HOPOPTS ) return 0;
+#else
+       if ( temp != MASK_DSTOPTS ) return 0;
+#endif
+
+       if (len < (int)sizeof(struct ipv6_opt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Packet smaller than it's length field */
+       		return 0;
+       }
+
+       optsh=(void *)(skb->data)+ptr;
+
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+
+       DEBUGP("len %02X %04X %02X ",
+       		optinfo->hdrlen, hdrlen,
+       		(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+
+       ret = (optsh != NULL)
+       		&&
+	      	(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
+
+       temp = len = 0;
+       ptr += 2;
+       hdrlen -= 2;
+       if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
+	       return ret;
+	} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
+		DEBUGP("Not strict - not implemented");
+	} else {
+		DEBUGP("Strict ");
+		DEBUGP("#%d ",optinfo->optsnr);
+		for(temp=0; temp<optinfo->optsnr; temp++){
+			optdesc = (void *)(skb->data)+ptr;
+			/* Type check */
+			if ( (unsigned char)*optdesc != 
+				(optinfo->opts[temp] & 0xFF00)>>8 ){
+				DEBUGP("Tbad %02X %02X\n",
+						(unsigned char)*optdesc,
+						(optinfo->opts[temp] &
+						 0xFF00)>>8);
+				return 0;
+			} else {
+				DEBUGP("Tok ");
+			}
+			/* Length check */
+			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
+				(unsigned char)*optdesc != 0){
+				if ( ntohs((u16)*optdesc) != 
+						optinfo->opts[temp] ){
+					DEBUGP("Lbad %02X %04X %04X\n",
+							(unsigned char)*optdesc,
+							ntohs((u16)*optdesc),
+							optinfo->opts[temp]);
+					return 0;
+				} else {
+					DEBUGP("Lok ");
+				}
+			}
+			/* Step to the next */
+			if ((unsigned char)*optdesc == 0){
+				DEBUGP("PAD0 \n");
+				ptr++;
+				hdrlen--;
+			} else {
+				ptr += LOW(ntohs(*optdesc));
+				hdrlen -= LOW(ntohs(*optdesc));
+				DEBUGP("len%04X \n", 
+					LOW(ntohs(*optdesc)));
+			}
+			if (ptr > skb->len || ( !hdrlen && 
+				(temp != optinfo->optsnr - 1))) {
+				DEBUGP("new pointer is too large! \n");
+				break;
+			}
+		}
+		if (temp == optinfo->optsnr)
+			return ret;
+		else return 0;
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_opts *optsinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
+              DEBUGP("ip6t_opts: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
+              return 0;
+       }
+       if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
+              DEBUGP("ip6t_opts: unknown flags %X\n",
+                      optsinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match opts_match
+#if HOPBYHOP
+= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+#else
+= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+#endif
+
+static int __init init(void)
+{
+       return ip6t_register_match(&opts_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&opts_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_esp.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_esp.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_esp.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_esp.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,186 @@
+/* Kernel module to match ESP parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_esp.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 ESP match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+struct esphdr {
+	__u32   spi;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* 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;
+        DEBUGP("esp spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+        	min,spi,max);
+	r=(spi >= min && spi <= max) ^ invert;
+	DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+	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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+	struct esphdr *esp = NULL;
+	const struct ip6t_esp *espinfo = matchinfo;
+	unsigned int temp;
+	int len;
+	u8 nexthdr;
+	unsigned int ptr;
+
+	/* Make sure this isn't an evil packet */
+	/*DEBUGP("ipv6_esp entered \n");*/
+
+	/* type of the 1st exthdr */
+	nexthdr = skb->nh.ipv6h->nexthdr;
+	/* pointer to the 1st exthdr */
+	ptr = sizeof(struct ipv6hdr);
+	/* available length */
+	len = skb->len - ptr;
+	temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+        	struct ipv6_opt_hdr *hdr;
+        	int hdrlen;
+
+		DEBUGP("ipv6_esp header iteration \n");
+
+		/* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+		/* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+			break;
+		}
+		/* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+			temp |= MASK_ESP;
+			break;
+		}
+
+		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+		/* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+		/* set the flag */
+		switch (nexthdr){
+			case NEXTHDR_HOP:
+			case NEXTHDR_ROUTING:
+			case NEXTHDR_FRAGMENT:
+			case NEXTHDR_AUTH:
+			case NEXTHDR_DEST:
+				break;
+			default:
+				DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
+				return 0;
+				break;
+		}
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_esp: new pointer too large! \n");
+			break;
+		}
+        }
+
+	/* ESP header not found */
+	if ( temp != MASK_ESP ) return 0;
+
+       if (len < (int)sizeof(struct esphdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+	esp=skb->data+ptr;
+
+	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
+
+	return (esp != NULL)
+		&& spi_match(espinfo->spis[0], espinfo->spis[1],
+			      ntohl(esp->spi),
+			      !!(espinfo->invflags & IP6T_ESP_INV_SPI));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+	   const struct ip6t_ip6 *ip,
+	   void *matchinfo,
+	   unsigned int matchinfosize,
+	   unsigned int hook_mask)
+{
+	const struct ip6t_esp *espinfo = matchinfo;
+
+	if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_esp))) {
+		DEBUGP("ip6t_esp: matchsize %u != %u\n",
+			 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_esp)));
+		return 0;
+	}
+	if (espinfo->invflags & ~IP6T_ESP_INV_MASK) {
+		DEBUGP("ip6t_esp: unknown flags %X\n",
+			 espinfo->invflags);
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct ip6t_match esp_match
+= { { NULL, NULL }, "esp", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&esp_match);
+}
+
+static void __exit cleanup(void)
+{
+	ip6t_unregister_match(&esp_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_frag.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_frag.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_frag.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_frag.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,250 @@
+/* Kernel module to match FRAG parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_frag.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 FRAG match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+#if 0
+#if     BYTE_ORDER == BIG_ENDIAN
+#define IP6F_OFF_MASK       0xfff8  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0006  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0001  /* more-fragments flag */
+#else   /* BYTE_ORDER == LITTLE_ENDIAN */
+#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
+#endif
+#endif
+
+#define IP6F_OFF_MASK       0xf8ff  /* mask out offset from _offlg */
+#define IP6F_RESERVED_MASK  0x0600  /* reserved bits in ip6f_offlg */
+#define IP6F_MORE_FRAG      0x0100  /* more-fragments flag */
+
+struct fraghdr {
+       __u8    nexthdr;
+       __u8    hdrlen;
+       __u16   info;
+       __u32   id;
+};
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the id is matched by the range, 0 otherwise */
+static inline int
+id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+{
+       int r=0;
+       DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,id,max);
+       r=(id >= min && id <= max) ^ invert;
+       DEBUGP(" 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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct fraghdr *frag = NULL;
+       const struct ip6t_frag *fraginfo = matchinfo;
+       unsigned int temp;
+       int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_frag header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* FRAG -> evaluate */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                     temp |= MASK_FRAGMENT;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_frag: new pointer too large! \n");
+			break;
+		}
+        }
+
+       /* FRAG header not found */
+       if ( temp != MASK_FRAGMENT ) return 0;
+
+       if (len < (int)sizeof(struct fraghdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       frag=skb->data+ptr;
+
+       DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
+       DEBUGP("INFO %04X ", frag->info);
+       DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
+       DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
+       DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
+       DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
+
+       DEBUGP("IPv6 FRAG id %02X ",
+       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
+                           ntohl(frag->id),
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
+       DEBUGP("len %02X %04X %02X ",
+       		fraginfo->hdrlen, hdrlen,
+       		(!fraginfo->hdrlen ||
+                           (fraginfo->hdrlen == hdrlen) ^
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
+       DEBUGP("res %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
+       		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
+       DEBUGP("first %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
+       		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
+       DEBUGP("mf %02X %02X %02X ", 
+       		(fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
+       		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
+       DEBUGP("last %02X %02X %02X\n", 
+       		(fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
+       		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
+
+       return (frag != NULL)
+       		&&
+       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
+                           ntohl(frag->id),
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
+		&&
+	      	(!fraginfo->hdrlen ||
+                           (fraginfo->hdrlen == hdrlen) ^
+                           !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
+		&&
+		!((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_frag *fraginfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
+              DEBUGP("ip6t_frag: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
+              return 0;
+       }
+       if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
+              DEBUGP("ip6t_frag: unknown flags %X\n",
+                      fraginfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match frag_match
+= { { NULL, NULL }, "frag", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&frag_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&frag_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_hbh.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_hbh.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_hbh.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_hbh.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,287 @@
+/* Kernel module to match Hop-by-Hop and Destination parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_opts.h>
+
+#define LOW(n)		(n & 0x00FF)
+
+#define HOPBYHOP	1
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+#if HOPBYHOP
+MODULE_DESCRIPTION("IPv6 HbH match");
+#else
+MODULE_DESCRIPTION("IPv6 DST match");
+#endif
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * (Type & 0xC0) >> 6
+ * 	0	-> ignorable
+ * 	1	-> must drop the packet
+ * 	2	-> send ICMP PARM PROB regardless and drop packet
+ * 	3	-> Send ICMP if not a multicast address and drop packet
+ *  (Type & 0x20) >> 5
+ *  	0	-> invariant
+ *  	1	-> can change the routing
+ *  (Type & 0x1F) Type
+ *      0	-> PAD0 (only 1 byte!)
+ *      1	-> PAD1 LENGTH info (total length = length + 2)
+ *      C0 | 2	-> JUMBO 4 x x x x ( xxxx > 64k )
+ *      5	-> RTALERT 2 x x
+ */
+
+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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_opt_hdr *optsh = NULL;
+       const struct ip6t_opts *optinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+       u_int16_t *optdesc = NULL;
+       
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_opts header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(void *)(skb->data)+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* OPTS -> evaluate */
+#if HOPBYHOP
+                if (nexthdr == NEXTHDR_HOP) {
+                     temp |= MASK_HOPOPTS;
+#else
+                if (nexthdr == NEXTHDR_DEST) {
+                     temp |= MASK_DSTOPTS;
+#endif
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_opts: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* OPTIONS header not found */
+#if HOPBYHOP
+       if ( temp != MASK_HOPOPTS ) return 0;
+#else
+       if ( temp != MASK_DSTOPTS ) return 0;
+#endif
+
+       if (len < (int)sizeof(struct ipv6_opt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Packet smaller than it's length field */
+       		return 0;
+       }
+
+       optsh=(void *)(skb->data)+ptr;
+
+       DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
+
+       DEBUGP("len %02X %04X %02X ",
+       		optinfo->hdrlen, hdrlen,
+       		(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+
+       ret = (optsh != NULL)
+       		&&
+	      	(!(optinfo->flags & IP6T_OPTS_LEN) ||
+                           ((optinfo->hdrlen == hdrlen) ^
+                           !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
+
+       temp = len = 0;
+       ptr += 2;
+       hdrlen -= 2;
+       if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
+	       return ret;
+	} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
+		DEBUGP("Not strict - not implemented");
+	} else {
+		DEBUGP("Strict ");
+		DEBUGP("#%d ",optinfo->optsnr);
+		for(temp=0; temp<optinfo->optsnr; temp++){
+			optdesc = (void *)(skb->data)+ptr;
+			/* Type check */
+			if ( (unsigned char)*optdesc != 
+				(optinfo->opts[temp] & 0xFF00)>>8 ){
+				DEBUGP("Tbad %02X %02X\n",
+						(unsigned char)*optdesc,
+						(optinfo->opts[temp] &
+						 0xFF00)>>8);
+				return 0;
+			} else {
+				DEBUGP("Tok ");
+			}
+			/* Length check */
+			if (((optinfo->opts[temp] & 0x00FF) != 0xFF) &&
+				(unsigned char)*optdesc != 0){
+				if ( ntohs((u16)*optdesc) != 
+						optinfo->opts[temp] ){
+					DEBUGP("Lbad %02X %04X %04X\n",
+							(unsigned char)*optdesc,
+							ntohs((u16)*optdesc),
+							optinfo->opts[temp]);
+					return 0;
+				} else {
+					DEBUGP("Lok ");
+				}
+			}
+			/* Step to the next */
+			if ((unsigned char)*optdesc == 0){
+				DEBUGP("PAD0 \n");
+				ptr++;
+				hdrlen--;
+			} else {
+				ptr += LOW(ntohs(*optdesc));
+				hdrlen -= LOW(ntohs(*optdesc));
+				DEBUGP("len%04X \n", 
+					LOW(ntohs(*optdesc)));
+			}
+			if (ptr > skb->len || ( !hdrlen && 
+				(temp != optinfo->optsnr - 1))) {
+				DEBUGP("new pointer is too large! \n");
+				break;
+			}
+		}
+		if (temp == optinfo->optsnr)
+			return ret;
+		else return 0;
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_opts *optsinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) {
+              DEBUGP("ip6t_opts: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts)));
+              return 0;
+       }
+       if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
+              DEBUGP("ip6t_opts: unknown flags %X\n",
+                      optsinfo->invflags);
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match opts_match
+#if HOPBYHOP
+= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE };
+#else
+= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE };
+#endif
+
+static int __init init(void)
+{
+       return ip6t_register_match(&opts_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&opts_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_hl.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_hl.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_hl.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_hl.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,74 @@
+/*
+ * Hop Limit matching module
+ * Maciej Soltysiak <solt@dns.toxicfilms.tv>
+ * Based on HW's ttl module
+ *
+ * This software is distributed under the terms  GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter_ipv6/ip6t_hl.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+
+MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
+MODULE_DESCRIPTION("IP tables Hop Limit matching module");
+MODULE_LICENSE("GPL");
+
+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 ip6t_hl_info *info = matchinfo;
+	const struct ipv6hdr *ip6h = skb->nh.ipv6h;
+
+	switch (info->mode) {
+		case IP6T_HL_EQ:
+			return (ip6h->hop_limit == info->hop_limit);
+			break;
+		case IP6T_HL_NE:
+			return (!(ip6h->hop_limit == info->hop_limit));
+			break;
+		case IP6T_HL_LT:
+			return (ip6h->hop_limit < info->hop_limit);
+			break;
+		case IP6T_HL_GT:
+			return (ip6h->hop_limit > info->hop_limit);
+			break;
+		default:
+			printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", 
+				info->mode);
+			return 0;
+	}
+
+	return 0;
+}
+
+static int checkentry(const char *tablename, const struct ip6t_ip6 *ip,
+		      void *matchinfo, unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_hl_info)))
+		return 0;
+
+	return 1;
+}
+
+static struct ip6t_match hl_match = { { NULL, NULL }, "hl", &match,
+		&checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+	return ip6t_register_match(&hl_match);
+}
+
+static void __exit fini(void)
+{
+	ip6t_unregister_match(&hl_match);
+
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_ipv6header.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_ipv6header.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_ipv6header.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_ipv6header.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,222 @@
+/* ipv6header match - matches IPv6 packets based
+on whether they contain certain headers */
+
+/* Original idea: Brad Chapman 
+ * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_ipv6header.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 headers match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+static int
+ipv6header_match(const struct sk_buff *skb,
+		 const struct net_device *in,
+		 const struct net_device *out,
+		 const void *matchinfo,
+		 int offset,
+		 const void *protohdr,
+		 u_int16_t datalen,
+		 int *hotdrop)
+{
+	const struct ip6t_ipv6header_info *info = matchinfo;
+	unsigned int temp;
+	int len;
+	u8 nexthdr;
+	unsigned int ptr;
+        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
+
+	/* Make sure this isn't an evil packet */
+	DEBUGP("ipv6_header entered \n");
+
+	/* type of the 1st exthdr */
+	nexthdr = skb->nh.ipv6h->nexthdr;
+	/* pointer to the 1st exthdr */
+	ptr = sizeof(struct ipv6hdr);
+	/* available length */
+	len = skb->len - ptr;
+	temp = 0;
+
+	DEBUGP("ipv6_header nexthdr %02X \n",nexthdr);
+	DEBUGP("ipv6_header ptr %08X \n",ptr);
+	DEBUGP("ipv6_header skblen %04X \n",skb->len);
+	DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len);
+	DEBUGP("ipv6_header len %04X \n",len);
+#if 0
+	for (temp=0;temp<skb->len;temp++){
+		if (!(temp % 16 )) DEBUGP("\nipv6_header data ");
+		DEBUGP("%02X ",skb->data[temp]);
+	}
+#endif
+	DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n",
+			skb->h.raw[0],
+			skb->h.raw[1],
+			skb->h.raw[2],
+			skb->h.raw[3]);
+	DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n",
+			skb->nh.raw[0],
+			skb->nh.raw[1],
+			skb->nh.raw[2],
+			skb->nh.raw[3]);
+	DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n",
+			opt->iif,
+			opt->ra,
+			opt->hop,
+			opt->auth,
+			opt->dst0,
+			opt->srcrt,
+			opt->dst1);
+
+	temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+        	struct ipv6_opt_hdr *hdr;
+        	int hdrlen;
+
+		DEBUGP("ipv6_header header iteration \n");
+
+		/* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+		/* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+			temp |= MASK_NONE;
+			break;
+		}
+		/* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+			temp |= MASK_ESP;
+			break;
+		}
+
+		hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+		/* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+		DEBUGP("ipv6_header hdrlen %04X \n",hdrlen);
+
+		/* set the flag */
+		switch (nexthdr){
+			case NEXTHDR_HOP:
+				temp |= MASK_HOPOPTS;
+				break;
+			case NEXTHDR_ROUTING:
+				temp |= MASK_ROUTING;
+				break;
+			case NEXTHDR_FRAGMENT:
+				temp |= MASK_FRAGMENT;
+				break;
+			case NEXTHDR_AUTH:
+				temp |= MASK_AH;
+				break;
+			case NEXTHDR_DEST:
+				temp |= MASK_DSTOPTS;
+				break;
+			default:
+				DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr);
+				return 0;
+				break;
+		}
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_header new ptr %04X \n",ptr);
+			break;
+		}
+        }
+
+	if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
+		temp |= MASK_PROTO;
+
+	DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags);
+
+	if (info->modeflag)
+		return (!( (temp & info->matchflags)
+			^ info->matchflags) ^ info->invflags);
+	else
+		return (!( temp ^ info->matchflags) ^ info->invflags);
+}
+
+static int
+ipv6header_checkentry(const char *tablename,
+		      const struct ip6t_ip6 *ip,
+		      void *matchinfo,
+		      unsigned int matchsize,
+		      unsigned int hook_mask)
+{
+	/* Check for obvious errors */
+	/* This match is valid in all hooks! */
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
+		DEBUGP("ip6t_ipv6header: matchsize != %u\n",
+			 IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)));
+		return 0;
+	}
+
+	return 1;
+}
+
+static void
+ipv6header_destroy(void *matchinfo,
+		   unsigned int matchinfosize)
+{
+	return;
+}
+
+static struct ip6t_match
+ip6t_ipv6header_match = {
+	{ NULL, NULL },
+	"ipv6header",
+	&ipv6header_match,
+	&ipv6header_checkentry,
+	&ipv6header_destroy,
+	THIS_MODULE
+};
+
+static int  __init ipv6header_init(void)
+{
+	return ip6t_register_match(&ip6t_ipv6header_match);
+}
+
+static void __exit ipv6header_exit(void)
+{
+	ip6t_unregister_match(&ip6t_ipv6header_match);
+}
+
+module_init(ipv6header_init);
+module_exit(ipv6header_exit);
+
diff -urN linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_rt.c linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_rt.c
--- linux-2.5.63-bk6/net/ipv6/netfilter/ip6t_rt.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/ipv6/netfilter/ip6t_rt.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,305 @@
+/* Kernel module to match ROUTING parameters. */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <linux/types.h>
+#include <net/checksum.h>
+#include <net/ipv6.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_rt.h>
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IPv6 RT match");
+MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+        return ( (nexthdr == NEXTHDR_HOP)       ||
+                 (nexthdr == NEXTHDR_ROUTING)   ||
+                 (nexthdr == NEXTHDR_FRAGMENT)  ||
+                 (nexthdr == NEXTHDR_AUTH)      ||
+                 (nexthdr == NEXTHDR_ESP)       ||
+                 (nexthdr == NEXTHDR_NONE)      ||
+                 (nexthdr == NEXTHDR_DEST) );
+}
+
+/* Returns 1 if the id is matched by the range, 0 otherwise */
+static inline int
+segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+{
+       int r=0;
+       DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
+              min,id,max);
+       r=(id >= min && id <= max) ^ invert;
+       DEBUGP(" 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 *protohdr,
+      u_int16_t datalen,
+      int *hotdrop)
+{
+       struct ipv6_rt_hdr *route = NULL;
+       const struct ip6t_rt *rtinfo = matchinfo;
+       unsigned int temp;
+       unsigned int len;
+       u8 nexthdr;
+       unsigned int ptr;
+       unsigned int hdrlen = 0;
+       unsigned int ret = 0;
+
+       /* type of the 1st exthdr */
+       nexthdr = skb->nh.ipv6h->nexthdr;
+       /* pointer to the 1st exthdr */
+       ptr = sizeof(struct ipv6hdr);
+       /* available length */
+       len = skb->len - ptr;
+       temp = 0;
+
+        while (ipv6_ext_hdr(nexthdr)) {
+               struct ipv6_opt_hdr *hdr;
+
+              DEBUGP("ipv6_rt header iteration \n");
+
+              /* Is there enough space for the next ext header? */
+                if (len < (int)sizeof(struct ipv6_opt_hdr))
+                        return 0;
+              /* No more exthdr -> evaluate */
+                if (nexthdr == NEXTHDR_NONE) {
+                     break;
+              }
+              /* ESP -> evaluate */
+                if (nexthdr == NEXTHDR_ESP) {
+                     break;
+              }
+
+              hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
+
+              /* Calculate the header length */
+                if (nexthdr == NEXTHDR_FRAGMENT) {
+                        hdrlen = 8;
+                } else if (nexthdr == NEXTHDR_AUTH)
+                        hdrlen = (hdr->hdrlen+2)<<2;
+                else
+                        hdrlen = ipv6_optlen(hdr);
+
+              /* ROUTING -> evaluate */
+                if (nexthdr == NEXTHDR_ROUTING) {
+                     temp |= MASK_ROUTING;
+                     break;
+              }
+
+
+              /* set the flag */
+              switch (nexthdr){
+                     case NEXTHDR_HOP:
+                     case NEXTHDR_ROUTING:
+                     case NEXTHDR_FRAGMENT:
+                     case NEXTHDR_AUTH:
+                     case NEXTHDR_DEST:
+                            break;
+                     default:
+                            DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr);
+                            return 0;
+                            break;
+              }
+
+                nexthdr = hdr->nexthdr;
+                len -= hdrlen;
+                ptr += hdrlen;
+		if ( ptr > skb->len ) {
+			DEBUGP("ipv6_rt: new pointer is too large! \n");
+			break;
+		}
+        }
+
+       /* ROUTING header not found */
+       if ( temp != MASK_ROUTING ) return 0;
+
+       if (len < (int)sizeof(struct ipv6_rt_hdr)){
+	       *hotdrop = 1;
+       		return 0;
+       }
+
+       if (len < hdrlen){
+	       /* Pcket smaller than its length field */
+       		return 0;
+       }
+
+       route=skb->data+ptr;
+
+       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
+       DEBUGP("TYPE %04X ", route->type);
+       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));
+
+       DEBUGP("IPv6 RT segsleft %02X ",
+       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
+                           ntohl(route->segments_left),
+                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
+       DEBUGP("type %02X %02X %02X ",
+       		rtinfo->rt_type, route->type, 
+       		(!(rtinfo->flags & IP6T_RT_TYP) ||
+                           ((rtinfo->rt_type == route->type) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
+       DEBUGP("len %02X %04X %02X ",
+       		rtinfo->hdrlen, hdrlen,
+       		(!(rtinfo->flags & IP6T_RT_LEN) ||
+                           ((rtinfo->hdrlen == hdrlen) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
+       DEBUGP("res %02X %02X %02X ", 
+       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
+       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));
+
+       ret = (route != NULL)
+       		&&
+       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
+                           ntohl(route->segments_left),
+                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
+		&&
+	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
+                           ((rtinfo->hdrlen == hdrlen) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
+		&&
+       		(!(rtinfo->flags & IP6T_RT_TYP) ||
+                           ((rtinfo->rt_type == route->type) ^
+                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)))
+		&&
+       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap));
+
+	DEBUGP("#%d ",rtinfo->addrnr);
+       temp = len = ptr = 0;
+       if ( !(rtinfo->flags & IP6T_RT_FST) ){
+	       return ret;
+	} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
+		DEBUGP("Not strict ");
+		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
+			DEBUGP("There isn't enough space\n");
+			return 0;
+		} else {
+			DEBUGP("#%d ",rtinfo->addrnr);
+			ptr = 0;
+			for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){
+				len = 0;
+				while ((u8)(((struct rt0_hdr *)route)->
+						addr[temp].s6_addr[len]) ==
+					(u8)(rtinfo->addrs[ptr].s6_addr[len])){
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
+					len++;
+					if ( len == 16 ) break;
+				}
+				if (len==16) {
+					DEBUGP("ptr=%d temp=%d;\n",ptr,temp);
+					ptr++;
+				} else {
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[ptr].s6_addr[len]));
+					DEBUGP("!ptr=%d temp=%d;\n",ptr,temp);
+				}
+				if (ptr==rtinfo->addrnr) break;
+			}
+			DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr);
+			if ( (len == 16) && (ptr == rtinfo->addrnr))
+				return ret;
+			else return 0;
+		}
+	} else {
+		DEBUGP("Strict ");
+		if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){
+			DEBUGP("There isn't enough space\n");
+			return 0;
+		} else {
+			DEBUGP("#%d ",rtinfo->addrnr);
+			for(temp=0; temp<rtinfo->addrnr; temp++){
+				len = 0;
+				while ((u8)(((struct rt0_hdr *)route)->
+						addr[temp].s6_addr[len]) ==
+					(u8)(rtinfo->addrs[temp].s6_addr[len])){
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[temp].s6_addr[len]));
+					len++;
+					if ( len == 16 ) break;
+				}
+				if (len!=16) {
+					DEBUGP("%02X?%02X ",
+		(u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]),
+					(u8)(rtinfo->addrs[temp].s6_addr[len]));
+					DEBUGP("!len=%d temp=%d;\n",len,temp);
+					break;
+				}
+			}
+			DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr);
+			if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16)))
+				return ret;
+			else return 0;
+		}
+	}
+
+	return 0;
+}
+
+/* Called when user tries to insert an entry of this type. */
+static int
+checkentry(const char *tablename,
+          const struct ip6t_ip6 *ip,
+          void *matchinfo,
+          unsigned int matchinfosize,
+          unsigned int hook_mask)
+{
+       const struct ip6t_rt *rtinfo = matchinfo;
+
+       if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_rt))) {
+              DEBUGP("ip6t_rt: matchsize %u != %u\n",
+                      matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_rt)));
+              return 0;
+       }
+       if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
+              DEBUGP("ip6t_rt: unknown flags %X\n",
+                      rtinfo->invflags);
+              return 0;
+       }
+       if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) && 
+		       (!(rtinfo->flags & IP6T_RT_TYP) || 
+		       (rtinfo->rt_type != 0) || 
+		       (rtinfo->invflags & IP6T_RT_INV_TYP)) ) {
+	      DEBUGP("`--rt-type 0' required before `--rt-0-*'");
+              return 0;
+       }
+
+       return 1;
+}
+
+static struct ip6t_match rt_match
+= { { NULL, NULL }, "rt", &match, &checkentry, NULL, THIS_MODULE };
+
+static int __init init(void)
+{
+       return ip6t_register_match(&rt_match);
+}
+
+static void __exit cleanup(void)
+{
+       ip6t_unregister_match(&rt_match);
+}
+
+module_init(init);
+module_exit(cleanup);
diff -urN linux-2.5.63-bk6/net/ipv6/route.c linux-2.5.63-bk7/net/ipv6/route.c
--- linux-2.5.63-bk6/net/ipv6/route.c	Mon Feb 24 11:05:39 2003
+++ linux-2.5.63-bk7/net/ipv6/route.c	Mon Mar 31 12:20:18 2003
@@ -1777,34 +1777,84 @@
 }
 
 ctl_table ipv6_route_table[] = {
-        {NET_IPV6_ROUTE_FLUSH, "flush",
-         &flush_delay, sizeof(int), 0644, NULL,
-         &ipv6_sysctl_rtcache_flush},
-	{NET_IPV6_ROUTE_GC_THRESH, "gc_thresh",
-         &ip6_dst_ops.gc_thresh, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV6_ROUTE_MAX_SIZE, "max_size",
-         &ip6_rt_max_size, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval",
-         &ip6_rt_gc_min_interval, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	{NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout",
-         &ip6_rt_gc_timeout, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	{NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval",
-         &ip6_rt_gc_interval, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	{NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity",
-         &ip6_rt_gc_elasticity, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	{NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires",
-         &ip6_rt_mtu_expires, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	{NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss",
-         &ip6_rt_min_advmss, sizeof(int), 0644, NULL,
-         &proc_dointvec_jiffies, &sysctl_jiffies},
-	 {0}
+        {
+		.ctl_name	=	NET_IPV6_ROUTE_FLUSH, 
+		.procname	=	"flush",
+         	.data		=	&flush_delay,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&ipv6_sysctl_rtcache_flush
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_THRESH,
+		.procname	=	"gc_thresh",
+         	.data		=	&ip6_dst_ops.gc_thresh,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_MAX_SIZE,
+		.procname	=	"max_size",
+         	.data		=	&ip6_rt_max_size,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_MIN_INTERVAL,
+		.procname	=	"gc_min_interval",
+         	.data		=	&ip6_rt_gc_min_interval,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_TIMEOUT,
+		.procname	=	"gc_timeout",
+         	.data		=	&ip6_rt_gc_timeout,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_INTERVAL,
+		.procname	=	"gc_interval",
+         	.data		=	&ip6_rt_gc_interval,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_GC_ELASTICITY,
+		.procname	=	"gc_elasticity",
+         	.data		=	&ip6_rt_gc_elasticity,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_MTU_EXPIRES,
+		.procname	=	"mtu_expires",
+         	.data		=	&ip6_rt_mtu_expires,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
+	{
+		.ctl_name	=	NET_IPV6_ROUTE_MIN_ADVMSS,
+		.procname	=	"min_adv_mss",
+         	.data		=	&ip6_rt_min_advmss,
+		.maxlen		=	sizeof(int),
+		.mode		=	0644,
+         	.proc_handler	=	&proc_dointvec_jiffies,
+		.strategy	=	&sysctl_jiffies,
+	},
 };
 
 #endif
diff -urN linux-2.5.63-bk6/net/ipv6/sit.c linux-2.5.63-bk7/net/ipv6/sit.c
--- linux-2.5.63-bk6/net/ipv6/sit.c	Mon Feb 24 11:05:44 2003
+++ linux-2.5.63-bk7/net/ipv6/sit.c	Mon Mar 31 12:20:18 2003
@@ -68,7 +68,8 @@
 };
 
 static struct ip_tunnel ipip6_fb_tunnel = {
-	NULL, &ipip6_fb_tunnel_dev, {0, }, 0, 0, 0, 0, 0, 0, 0, {"sit0", }
+	.dev = &ipip6_fb_tunnel_dev,
+	.parms = { .name = "sit0" }
 };
 
 static struct ip_tunnel *tunnels_r_l[HASH_SIZE];
diff -urN linux-2.5.63-bk6/net/sctp/Makefile linux-2.5.63-bk7/net/sctp/Makefile
--- linux-2.5.63-bk6/net/sctp/Makefile	Mon Feb 24 11:06:02 2003
+++ linux-2.5.63-bk7/net/sctp/Makefile	Mon Mar 31 12:20:18 2003
@@ -10,7 +10,7 @@
 	  inqueue.o outqueue.o ulpqueue.o command.o \
 	  tsnmap.o bind_addr.o socket.o primitive.o \
 	  output.o input.o hashdriver.o sla1.o \
-	  debug.o ssnmap.o
+	  debug.o ssnmap.o proc.o
 
 ifeq ($(CONFIG_SCTP_ADLER32), y)
 sctp-y += adler32.o
diff -urN linux-2.5.63-bk6/net/sctp/associola.c linux-2.5.63-bk7/net/sctp/associola.c
--- linux-2.5.63-bk6/net/sctp/associola.c	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/net/sctp/associola.c	Mon Mar 31 12:20:18 2003
@@ -95,7 +95,7 @@
 					  sctp_scope_t scope,
 					  int priority)
 {
-	sctp_opt_t *sp;
+	struct sctp_opt *sp;
 	int i;
 
 	/* Retrieve the SCTP per socket area.  */
@@ -241,8 +241,8 @@
 	asoc->peer.sack_needed = 1;
 
 	/* Create an input queue.  */
-	sctp_inqueue_init(&asoc->base.inqueue);
-	sctp_inqueue_set_th_handler(&asoc->base.inqueue,
+	sctp_inq_init(&asoc->base.inqueue);
+	sctp_inq_set_th_handler(&asoc->base.inqueue,
 				    (void (*)(void *))sctp_assoc_bh_rcv,
 				    asoc);
 
@@ -260,7 +260,6 @@
 
 	/* Set up the tsn tracking. */
 	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE, 0);
-	asoc->peer.next_dup_tsn = 0;
 
 	skb_queue_head_init(&asoc->addip_chunks);
 
@@ -311,7 +310,7 @@
 	sctp_ulpq_free(&asoc->ulpq);
 
 	/* Dispose of any pending chunks on the inqueue. */
-	sctp_inqueue_free(&asoc->base.inqueue);
+	sctp_inq_free(&asoc->base.inqueue);
 
 	/* Free ssnmap storage. */
 	sctp_ssnmap_free(asoc->ssnmap);
@@ -368,7 +367,7 @@
 					   int priority)
 {
 	struct sctp_transport *peer;
-	sctp_opt_t *sp;
+	struct sctp_opt *sp;
 	unsigned short port;
 
 	/* AF_INET and AF_INET6 share common port field. */
@@ -505,7 +504,7 @@
 	struct sctp_transport *t = NULL;
 	struct sctp_transport *first;
 	struct sctp_transport *second;
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct list_head *pos;
 	int spc_state = 0;
 
@@ -776,7 +775,7 @@
 	sctp_endpoint_t *ep;
 	sctp_chunk_t *chunk;
 	struct sock *sk;
-	sctp_inqueue_t *inqueue;
+	struct sctp_inq *inqueue;
 	int state, subtype;
 	sctp_assoc_t associd = sctp_assoc2id(asoc);
 	int error = 0;
@@ -786,7 +785,7 @@
 	sk = asoc->base.sk;
 
 	inqueue = &asoc->base.inqueue;
-	while (NULL != (chunk = sctp_pop_inqueue(inqueue))) {
+	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
 		state = asoc->state;
 		subtype = chunk->chunk_hdr->type;
 
@@ -795,6 +794,8 @@
 		 */
 		if (sctp_chunk_is_data(chunk))
 			asoc->peer.last_data_from = chunk->transport;
+		else
+			SCTP_INC_STATS(SctpInCtrlChunks);
 
 		if (chunk->transport)
 			chunk->transport->last_time_heard = jiffies;
@@ -819,7 +820,7 @@
 /* This routine moves an association from its old sk to a new sk.  */
 void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
 {
-	sctp_opt_t *newsp = sctp_sk(newsk);
+	struct sctp_opt *newsp = sctp_sk(newsk);
 
 	/* Delete the association from the old endpoint's list of
 	 * associations.
@@ -848,7 +849,6 @@
 	/* Copy in new parameters of peer. */
 	asoc->c = new->c;
 	asoc->peer.rwnd = new->peer.rwnd;
-	asoc->peer.next_dup_tsn = new->peer.next_dup_tsn;
 	asoc->peer.sack_needed = new->peer.sack_needed;
 	asoc->peer.i = new->peer.i;
 	sctp_tsnmap_init(&asoc->peer.tsn_map, SCTP_TSN_MAP_SIZE,
@@ -887,26 +887,19 @@
 
 }
 
-/* Choose the transport for sending a shutdown packet.
+/* Update the retran path for sending a retransmitted packet.
  * Round-robin through the active transports, else round-robin
  * through the inactive transports as this is the next best thing
  * we can try.
  */
-struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
+void sctp_assoc_update_retran_path(sctp_association_t *asoc)
 {
 	struct sctp_transport *t, *next;
 	struct list_head *head = &asoc->peer.transport_addr_list;
 	struct list_head *pos;
 
-	/* If this is the first time SHUTDOWN is sent, use the active
-	 * path.
-	 */
-	if (!asoc->shutdown_last_sent_to)
-		return asoc->peer.active_path;
-
-	/* Otherwise, find the next transport in a round-robin fashion. */
-
-	t = asoc->shutdown_last_sent_to;
+	/* Find the next transport in a round-robin fashion. */
+	t = asoc->peer.retran_path;
 	pos = &t->transports;
 	next = NULL;
 
@@ -935,13 +928,30 @@
 		 * other active transports.  If so, use the next
 		 * transport.
 		 */
-		if (t == asoc->shutdown_last_sent_to) {
+		if (t == asoc->peer.retran_path) {
 			t = next;
 			break;
 		}
 	}
 
-	return t;
+	asoc->peer.retran_path = t;
+}
+
+/* Choose the transport for sending a SHUTDOWN packet.  */
+struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
+{
+	/* If this is the first time SHUTDOWN is sent, use the active path,
+	 * else use the retran path. If the last SHUTDOWN was sent over the
+	 * retran path, update the retran path and use it. 
+	 */
+	if (!asoc->shutdown_last_sent_to)
+		return asoc->peer.active_path;
+	else {
+		if (asoc->shutdown_last_sent_to == asoc->peer.retran_path)
+			sctp_assoc_update_retran_path(asoc);
+		return asoc->peer.retran_path;
+	}
+
 }
 
 /* Update the association's pmtu and frag_point by going through all the
@@ -990,13 +1000,13 @@
 		asoc->rwnd += len;
 	}
 
-	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) - %u\n",
-			  __FUNCTION__, asoc, len, asoc->rwnd, asoc->rwnd_over,
-			  asoc->a_rwnd);
+	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
+			  "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
+			  asoc->rwnd_over, asoc->a_rwnd);
 
 	/* Send a window update SACK if the rwnd has increased by at least the
 	 * minimum of the association's PMTU and half of the receive buffer.
-	 * The algorithm used is similar to the one described in 
+	 * The algorithm used is similar to the one described in
 	 * Section 4.2.3.3 of RFC 1122.
 	 */
 	if ((asoc->state == SCTP_STATE_ESTABLISHED) &&
@@ -1004,17 +1014,16 @@
 	    ((asoc->rwnd - asoc->a_rwnd) >=
 		     min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) {
 		SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
-				  "rwnd: %u a_rwnd: %u\n",
-				  __FUNCTION__, asoc, asoc->rwnd, asoc->a_rwnd);
-		sack = sctp_make_sack(asoc); 
+				  "rwnd: %u a_rwnd: %u\n", __FUNCTION__,
+				  asoc, asoc->rwnd, asoc->a_rwnd);
+		sack = sctp_make_sack(asoc);
 		if (!sack)
-			return;	
+			return;
 
 		/* Update the last advertised rwnd value. */
 		asoc->a_rwnd = asoc->rwnd;
 
 		asoc->peer.sack_needed = 0;
-		asoc->peer.next_dup_tsn = 0;
 
 		sctp_outq_tail(&asoc->outqueue, sack);
 
@@ -1022,7 +1031,7 @@
 		timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
 		if (timer_pending(timer) && del_timer(timer))
 			sctp_association_put(asoc);
-	} 
+	}
 }
 
 /* Decrease asoc's rwnd by len. */
diff -urN linux-2.5.63-bk6/net/sctp/endpointola.c linux-2.5.63-bk7/net/sctp/endpointola.c
--- linux-2.5.63-bk6/net/sctp/endpointola.c	Mon Feb 24 11:05:09 2003
+++ linux-2.5.63-bk7/net/sctp/endpointola.c	Mon Mar 31 12:20:18 2003
@@ -92,7 +92,7 @@
 sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
 				    struct sock *sk, int priority)
 {
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_opt *sp = sctp_sk(sk);
 	memset(ep, 0, sizeof(sctp_endpoint_t));
 
 	/* Initialize the base structure. */
@@ -105,10 +105,10 @@
 	ep->base.malloced = 1;
 
 	/* Create an input queue.  */
-	sctp_inqueue_init(&ep->base.inqueue);
+	sctp_inq_init(&ep->base.inqueue);
 
 	/* Set its top-half handler */
-	sctp_inqueue_set_th_handler(&ep->base.inqueue,
+	sctp_inq_set_th_handler(&ep->base.inqueue,
 				    (void (*)(void *))sctp_endpoint_bh_rcv,
 				    ep);
 
@@ -198,7 +198,7 @@
 	sctp_unhash_endpoint(ep);
 
 	/* Cleanup the inqueue. */
-	sctp_inqueue_free(&ep->base.inqueue);
+	sctp_inq_free(&ep->base.inqueue);
 
 	sctp_bind_addr_free(&ep->base.bind_addr);
 
@@ -333,7 +333,7 @@
 	struct sock *sk;
 	struct sctp_transport *transport;
 	sctp_chunk_t *chunk;
-	sctp_inqueue_t *inqueue;
+	struct sctp_inq *inqueue;
 	sctp_subtype_t subtype;
 	sctp_state_t state;
 	int error = 0;
@@ -345,7 +345,7 @@
 	inqueue = &ep->base.inqueue;
 	sk = ep->base.sk;
 
-	while (NULL != (chunk = sctp_pop_inqueue(inqueue))) {		
+	while (NULL != (chunk = sctp_inq_pop(inqueue))) {		
 		subtype.chunk = chunk->chunk_hdr->type;
 
 		/* We might have grown an association since last we
@@ -369,6 +369,8 @@
 		 */
 		if (asoc && sctp_chunk_is_data(chunk))
 			asoc->peer.last_data_from = chunk->transport;
+		else
+			SCTP_INC_STATS(SctpInCtrlChunks);
 
 		if (chunk->transport)
 			chunk->transport->last_time_heard = jiffies;
diff -urN linux-2.5.63-bk6/net/sctp/input.c linux-2.5.63-bk7/net/sctp/input.c
--- linux-2.5.63-bk6/net/sctp/input.c	Mon Feb 24 11:05:06 2003
+++ linux-2.5.63-bk7/net/sctp/input.c	Mon Mar 31 12:20:18 2003
@@ -90,6 +90,7 @@
 
 	if (val != cmp) {
 		/* CRC failure, dump it. */
+		SCTP_INC_STATS_BH(SctpChecksumErrors);
 		return -1;
 	}
 	return 0;
@@ -115,6 +116,8 @@
 	if (skb->pkt_type!=PACKET_HOST)
 		goto discard_it;
 
+	SCTP_INC_STATS_BH(SctpInSCTPPacks);
+
 	sh = (struct sctphdr *) skb->h.raw;
 
 	/* Pull up the IP and SCTP headers. */
@@ -160,8 +163,10 @@
 	 */
 	if (!asoc) {
 		ep = __sctp_rcv_lookup_endpoint(&dest);
-		if (sctp_rcv_ootb(skb))
+		if (sctp_rcv_ootb(skb)) {
+			SCTP_INC_STATS_BH(SctpOutOfBlues);
 			goto discard_release;
+		}
 	}
 
 	/* Retrieve the common input handling substructure. */
@@ -248,7 +253,7 @@
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
 	sctp_chunk_t *chunk;
-	sctp_inqueue_t *inqueue;
+	struct sctp_inq *inqueue;
 
 	/* One day chunk will live inside the skb, but for
 	 * now this works.
@@ -256,7 +261,7 @@
 	chunk = (sctp_chunk_t *) skb;
 	inqueue = &chunk->rcvr->inqueue;
 
-	sctp_push_inqueue(inqueue, chunk);
+	sctp_inq_push(inqueue, chunk);
         return 0;
 }
 
diff -urN linux-2.5.63-bk6/net/sctp/inqueue.c linux-2.5.63-bk7/net/sctp/inqueue.c
--- linux-2.5.63-bk6/net/sctp/inqueue.c	Mon Feb 24 11:05:38 2003
+++ linux-2.5.63-bk7/net/sctp/inqueue.c	Mon Mar 31 12:20:18 2003
@@ -47,8 +47,8 @@
 #include <net/sctp/sm.h>
 #include <linux/interrupt.h>
 
-/* Initialize an SCTP_inqueue.  */
-void sctp_inqueue_init(sctp_inqueue_t *queue)
+/* Initialize an SCTP inqueue.  */
+void sctp_inq_init(struct sctp_inq *queue)
 {
 	skb_queue_head_init(&queue->in);
 	queue->in_progress = NULL;
@@ -59,21 +59,21 @@
 	queue->malloced = 0;
 }
 
-/* Create an initialized SCTP_inqueue.  */
-sctp_inqueue_t *sctp_inqueue_new(void)
+/* Create an initialized sctp_inq.  */
+struct sctp_inq *sctp_inq_new(void)
 {
-	sctp_inqueue_t *retval;
+	struct sctp_inq *retval;
 
-	retval = t_new(sctp_inqueue_t, GFP_ATOMIC);
+	retval = t_new(struct sctp_inq, GFP_ATOMIC);
 	if (retval) {
-		sctp_inqueue_init(retval);
+		sctp_inq_init(retval);
 		retval->malloced = 1;
 	}
         return retval;
 }
 
 /* Release the memory associated with an SCTP inqueue.  */
-void sctp_inqueue_free(sctp_inqueue_t *queue)
+void sctp_inq_free(struct sctp_inq *queue)
 {
 	sctp_chunk_t *chunk;
 
@@ -96,7 +96,7 @@
 /* Put a new packet in an SCTP inqueue.
  * We assume that packet->sctp_hdr is set and in host byte order.
  */
-void sctp_push_inqueue(sctp_inqueue_t *q, sctp_chunk_t *packet)
+void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet)
 {
 	/* Directly call the packet handling routine. */
 
@@ -114,7 +114,7 @@
  * WARNING:  If you need to put the chunk on another queue, you need to
  * make a shallow copy (clone) of it.
  */
-sctp_chunk_t *sctp_pop_inqueue(sctp_inqueue_t *queue)
+sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue)
 {
 	sctp_chunk_t *chunk;
 	sctp_chunkhdr_t *ch = NULL;
@@ -172,7 +172,7 @@
 		chunk->end_of_packet = 1;
 	}
 
-	SCTP_DEBUG_PRINTK("+++sctp_pop_inqueue+++ chunk %p[%s],"
+	SCTP_DEBUG_PRINTK("+++sctp_inq_pop+++ chunk %p[%s],"
 			  " length %d, skb->len %d\n",chunk,
 			  sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)),
 			  ntohs(chunk->chunk_hdr->length), chunk->skb->len);
@@ -182,12 +182,12 @@
 /* Set a top-half handler.
  *
  * Originally, we the top-half handler was scheduled as a BH.  We now
- * call the handler directly in sctp_push_inqueue() at a time that
+ * call the handler directly in sctp_inq_push() at a time that
  * we know we are lock safe.
  * The intent is that this routine will pull stuff out of the
  * inqueue and process it.
  */
-void sctp_inqueue_set_th_handler(sctp_inqueue_t *q,
+void sctp_inq_set_th_handler(struct sctp_inq *q,
 				 void (*callback)(void *), void *arg)
 {
 	INIT_WORK(&q->immediate, callback, arg);
diff -urN linux-2.5.63-bk6/net/sctp/ipv6.c linux-2.5.63-bk7/net/sctp/ipv6.c
--- linux-2.5.63-bk6/net/sctp/ipv6.c	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/net/sctp/ipv6.c	Mon Mar 31 12:20:18 2003
@@ -131,6 +131,8 @@
 			  __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
 			  NIP6(fl.fl6_dst));
 
+	SCTP_INC_STATS(SctpOutSCTPPacks);
+
 	return ip6_xmit(sk, skb, &fl, np->opt);
 }
 
@@ -443,7 +445,7 @@
 }
 
 /* Initialize a PF_INET msgname from a ulpevent. */
-static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname,
+static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, char *msgname,
 				     int *addrlen)
 {
 	struct sockaddr_in6 *sin6, *sin6from;
diff -urN linux-2.5.63-bk6/net/sctp/output.c linux-2.5.63-bk7/net/sctp/output.c
--- linux-2.5.63-bk6/net/sctp/output.c	Mon Feb 24 11:05:11 2003
+++ linux-2.5.63-bk7/net/sctp/output.c	Mon Mar 31 12:20:18 2003
@@ -419,6 +419,7 @@
 	dst = transport->dst;
 	/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
 	if (!dst || (dst->obsolete > 1)) {
+		dst_release(dst);
 		sctp_transport_route(transport, NULL, sctp_sk(sk));
 		sctp_assoc_sync_pmtu(asoc);
 	}
diff -urN linux-2.5.63-bk6/net/sctp/outqueue.c linux-2.5.63-bk7/net/sctp/outqueue.c
--- linux-2.5.63-bk6/net/sctp/outqueue.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/sctp/outqueue.c	Mon Mar 31 12:20:18 2003
@@ -193,11 +193,17 @@
 			  : "Illegal Chunk");
 
 			skb_queue_tail(&q->out, (struct sk_buff *) chunk);
+			if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+				SCTP_INC_STATS(SctpOutUnorderChunks);
+			else
+				SCTP_INC_STATS(SctpOutOrderChunks);
 			q->empty = 0;
 			break;
 		};
-	} else
+	} else {
 		skb_queue_tail(&q->control, (struct sk_buff *) chunk);
+		SCTP_INC_STATS(SctpOutCtrlChunks);
+	}
 
 	if (error < 0)
 		return error;
@@ -315,6 +321,11 @@
 	switch(reason) {
 	case SCTP_RETRANSMIT_T3_RTX:
 		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
+		/* Update the retran path if the T3-rtx timer has expired for
+		 * the current retran path.
+		 */
+		if (transport == transport->asoc->peer.retran_path)
+			sctp_assoc_update_retran_path(transport->asoc);
 		break;
 	case SCTP_RETRANSMIT_FAST_RTX:
 		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
diff -urN linux-2.5.63-bk6/net/sctp/proc.c linux-2.5.63-bk7/net/sctp/proc.c
--- linux-2.5.63-bk6/net/sctp/proc.c	Wed Dec 31 16:00:00 1969
+++ linux-2.5.63-bk7/net/sctp/proc.c	Mon Mar 31 12:20:18 2003
@@ -0,0 +1,129 @@
+/* SCTP kernel reference Implementation
+ * Copyright (c) 2003 International Business Machines, Corp.
+ *
+ * This file is part of the SCTP kernel reference Implementation
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP reference implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ *                 ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by:
+ *    Sridhar Samudrala <sri@us.ibm.com>
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ */
+
+#include <linux/types.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <net/sctp/sctp.h>
+
+static char *sctp_snmp_list[] = {
+#define SCTP_SNMP_ENTRY(x) #x 
+	SCTP_SNMP_ENTRY(SctpCurrEstab),
+	SCTP_SNMP_ENTRY(SctpActiveEstabs),
+	SCTP_SNMP_ENTRY(SctpPassiveEstabs),
+	SCTP_SNMP_ENTRY(SctpAborteds),
+	SCTP_SNMP_ENTRY(SctpShutdowns),
+	SCTP_SNMP_ENTRY(SctpOutOfBlues),
+	SCTP_SNMP_ENTRY(SctpChecksumErrors),
+	SCTP_SNMP_ENTRY(SctpOutCtrlChunks),
+	SCTP_SNMP_ENTRY(SctpOutOrderChunks),
+	SCTP_SNMP_ENTRY(SctpOutUnorderChunks),
+	SCTP_SNMP_ENTRY(SctpInCtrlChunks),
+	SCTP_SNMP_ENTRY(SctpInOrderChunks),
+	SCTP_SNMP_ENTRY(SctpInUnorderChunks),
+	SCTP_SNMP_ENTRY(SctpFragUsrMsgs),
+	SCTP_SNMP_ENTRY(SctpReasmUsrMsgs),
+	SCTP_SNMP_ENTRY(SctpOutSCTPPacks),
+	SCTP_SNMP_ENTRY(SctpInSCTPPacks),
+#undef SCTP_SNMP_ENTRY
+};
+
+/* Return the current value of a particular entry in the mib by adding its
+ * per cpu counters.
+ */ 
+static unsigned long
+fold_field(void *mib[], int nr)
+{
+	unsigned long res = 0;
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!cpu_possible(i))
+			continue;
+		res +=
+		    *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) +
+					 sizeof (unsigned long) * nr));
+		res +=
+		    *((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) +
+					 sizeof (unsigned long) * nr));
+	}
+	return res;
+}
+
+/* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
+static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
+{
+	int i;
+
+	for (i = 0; i < sizeof(sctp_snmp_list) / sizeof(char *); i++)
+		seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i],
+			   fold_field((void **)sctp_statistics, i));
+
+	return 0;
+}
+
+/* Initialize the seq file operations for 'snmp' object. */
+static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, sctp_snmp_seq_show, NULL);
+}
+
+static struct file_operations sctp_snmp_seq_fops = {
+	.open	 = sctp_snmp_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = single_release,
+};
+
+/* Set up the proc fs entry for 'snmp' object. */
+int __init sctp_snmp_proc_init(void)
+{
+	struct proc_dir_entry *p;
+
+	p = create_proc_entry("snmp", S_IRUGO, proc_net_sctp);
+	if (!p)
+		return -ENOMEM;
+
+	p->proc_fops = &sctp_snmp_seq_fops;
+
+	return 0;
+}
+
+/* Cleanup the proc fs entry for 'snmp' object. */
+void sctp_snmp_proc_exit(void)
+{
+	remove_proc_entry("snmp", proc_net_sctp);
+}
diff -urN linux-2.5.63-bk6/net/sctp/protocol.c linux-2.5.63-bk7/net/sctp/protocol.c
--- linux-2.5.63-bk6/net/sctp/protocol.c	Mon Feb 24 11:05:34 2003
+++ linux-2.5.63-bk7/net/sctp/protocol.c	Mon Mar 31 12:20:18 2003
@@ -75,6 +75,9 @@
 
 extern struct net_proto_family inet_family_ops;
 
+extern int sctp_snmp_proc_init(void);
+extern int sctp_snmp_proc_exit(void);
+
 /* Return the address of the control sock. */
 struct sock *sctp_get_ctl_sock(void)
 {
@@ -82,21 +85,32 @@
 }
 
 /* Set up the proc fs entry for the SCTP protocol. */
-__init void sctp_proc_init(void)
+__init int sctp_proc_init(void)
 {
+	int rc = 0;
+
 	if (!proc_net_sctp) {
 		struct proc_dir_entry *ent;
 		ent = proc_mkdir("net/sctp", 0);
 		if (ent) {
 			ent->owner = THIS_MODULE;
 			proc_net_sctp = ent;
-		}
+		} else
+			rc = -ENOMEM;
 	}
+
+	if (sctp_snmp_proc_init())
+		rc = -ENOMEM;
+
+	return rc;
 }
 
 /* Clean up the proc fs entry for the SCTP protocol. */
 void sctp_proc_exit(void)
 {
+
+	sctp_snmp_proc_exit();
+
 	if (proc_net_sctp) {
 		proc_net_sctp = NULL;
 		remove_proc_entry("net/sctp", 0);
@@ -124,7 +138,6 @@
 		/* Add the address to the local list.  */
 		addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
 		if (addr) {
-			INIT_LIST_HEAD(&addr->list);
 			addr->a.v4.sin_family = AF_INET;
 			addr->a.v4.sin_port = 0;
 			addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
@@ -436,7 +449,6 @@
 
 		if (AF_INET == laddr->a.sa.sa_family) {
 			fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
-			dst = sctp_v4_get_dst(asoc, daddr, &laddr->a);
 			if (!ip_route_output_key(&rt, &fl)) {
 				dst = &rt->u.dst;
 				goto out_unlock;
@@ -557,7 +569,7 @@
 }
 
 /* Copy the primary address of the peer primary address as the msg_name. */
-static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname,
+static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname,
 				    int *addr_len)
 {
 	struct sockaddr_in *sin, *sinfrom;
@@ -628,6 +640,7 @@
 			  NIPQUAD(((struct rtable *)skb->dst)->rt_src),
 			  NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
 
+	SCTP_INC_STATS(SctpOutSCTPPacks);
 	return ip_queue_xmit(skb, ipfragok);
 }
 
diff -urN linux-2.5.63-bk6/net/sctp/sm_make_chunk.c linux-2.5.63-bk7/net/sctp/sm_make_chunk.c
--- linux-2.5.63-bk6/net/sctp/sm_make_chunk.c	Mon Feb 24 11:05:10 2003
+++ linux-2.5.63-bk7/net/sctp/sm_make_chunk.c	Mon Mar 31 12:20:18 2003
@@ -222,9 +222,7 @@
 
 	sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param);
 	sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types);
-
 	sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
-
 nodata:
 	if (addrs.v)
 		kfree(addrs.v);
@@ -245,7 +243,8 @@
 
 	retval = NULL;
 
-	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, priority);
+	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, 
+				       priority);
 	if (!addrs.v)
 		goto nomem_rawaddr;
 
@@ -586,14 +585,12 @@
 	sctp_gap_ack_block_t gab;
 	int length;
 	__u32 ctsn;
-	sctp_tsnmap_iter_t iter;
-	__u16 num_gabs;
-	__u16 num_dup_tsns = asoc->peer.next_dup_tsn;
-	const sctp_tsnmap_t *map = &asoc->peer.tsn_map;
+	struct sctp_tsnmap_iter iter;
+	__u16 num_gabs, num_dup_tsns;
+	struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
 
 	ctsn = sctp_tsnmap_get_ctsn(map);
-	SCTP_DEBUG_PRINTK("make_sack: sackCTSNAck sent is 0x%x.\n",
-			  ctsn);
+	SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
 
 	/* Count the number of Gap Ack Blocks.  */
 	sctp_tsnmap_iter_init(map, &iter);
@@ -603,15 +600,17 @@
 		/* Do nothing. */
 	}
 
+	num_dup_tsns = sctp_tsnmap_num_dups(map);
+
 	/* Initialize the SACK header.  */
 	sack.cum_tsn_ack	    = htonl(ctsn);
 	sack.a_rwnd 		    = htonl(asoc->rwnd);
 	sack.num_gap_ack_blocks     = htons(num_gabs);
-	sack.num_dup_tsns  = htons(num_dup_tsns);
+	sack.num_dup_tsns           = htons(num_dup_tsns);
 
 	length = sizeof(sack)
 		+ sizeof(sctp_gap_ack_block_t) * num_gabs
-		+ sizeof(sctp_dup_tsn_t) * num_dup_tsns;
+		+ sizeof(__u32) * num_dup_tsns;
 
 	/* Create the chunk.  */
 	retval = sctp_make_chunk(asoc, SCTP_CID_SACK, 0, length);
@@ -658,21 +657,18 @@
 	while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) {
 		gab.start = htons(gab.start);
 		gab.end = htons(gab.end);
-		sctp_addto_chunk(retval,
-				 sizeof(sctp_gap_ack_block_t),
-				 &gab);
+		sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab);
 	}
 
 	/* Register the duplicates.  */
-	sctp_addto_chunk(retval,
-			 sizeof(sctp_dup_tsn_t) * num_dup_tsns,
-			 &asoc->peer.dup_tsns);
+	sctp_addto_chunk(retval, sizeof(__u32) * num_dup_tsns,
+			 sctp_tsnmap_get_dups(map));
 
 nodata:
 	return retval;
 }
 
-/* FIXME: Comments. */
+/* Make a SHUTDOWN chunk. */
 sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
 {
 	sctp_chunk_t *retval;
@@ -689,7 +685,6 @@
 
 	retval->subh.shutdown_hdr =
 		sctp_addto_chunk(retval, sizeof(shut), &shut);
-
 nodata:
 	return retval;
 }
@@ -1180,6 +1175,9 @@
 	over = msg_len % max;
 	offset = 0;
 
+	if (whole && over)
+		SCTP_INC_STATS_USER(SctpFragUsrMsgs);
+
 	/* Create chunks for all the full sized DATA chunks. */
 	for (i=0, len=first_len; i < whole; i++) {
 		frag = SCTP_DATA_MIDDLE_FRAG;
diff -urN linux-2.5.63-bk6/net/sctp/sm_sideeffect.c linux-2.5.63-bk7/net/sctp/sm_sideeffect.c
--- linux-2.5.63-bk6/net/sctp/sm_sideeffect.c	Mon Feb 24 11:05:36 2003
+++ linux-2.5.63-bk7/net/sctp/sm_sideeffect.c	Mon Mar 31 12:20:18 2003
@@ -253,7 +253,7 @@
 {
 	int error = 0;
 	int force;
-	sctp_cmd_t *command;
+	sctp_cmd_t *cmd;
 	sctp_chunk_t *new_obj;
 	sctp_chunk_t *chunk = NULL;
 	sctp_packet_t *packet;
@@ -273,22 +273,22 @@
 	 *         cmd->handle(x, y, z)
 	 * --jgrimm
 	 */
-	while (NULL != (command = sctp_next_cmd(commands))) {
-		switch (command->verb) {
+	while (NULL != (cmd = sctp_next_cmd(commands))) {
+		switch (cmd->verb) {
 		case SCTP_CMD_NOP:
 			/* Do nothing. */
 			break;
 
 		case SCTP_CMD_NEW_ASOC:
 			/* Register a new association.  */
-			asoc = command->obj.ptr;
+			asoc = cmd->obj.ptr;
 			/* Register with the endpoint.  */
 			sctp_endpoint_add_asoc(ep, asoc);
 			sctp_hash_established(asoc);
 			break;
 
 		case SCTP_CMD_UPDATE_ASSOC:
-		       sctp_assoc_update(asoc, command->obj.ptr);
+		       sctp_assoc_update(asoc, cmd->obj.ptr);
 		       break;
 
 		case SCTP_CMD_PURGE_OUTQUEUE:
@@ -304,13 +304,12 @@
 
 		case SCTP_CMD_NEW_STATE:
 			/* Enter a new state.  */
-			sctp_cmd_new_state(commands, asoc, command->obj.state);
+			sctp_cmd_new_state(commands, asoc, cmd->obj.state);
 			break;
 
 		case SCTP_CMD_REPORT_TSN:
 			/* Record the arrival of a TSN.  */
-			sctp_tsnmap_mark(&asoc->peer.tsn_map,
-					 command->obj.u32);
+			sctp_tsnmap_mark(&asoc->peer.tsn_map, cmd->obj.u32);
 			break;
 
 		case SCTP_CMD_GEN_SACK:
@@ -319,14 +318,14 @@
 			 * the packet and MAYBE generate a SACK, or
 			 * force a SACK out.
 			 */
-			force = command->obj.i32;
+			force = cmd->obj.i32;
 			error = sctp_gen_sack(asoc, force, commands);
 			break;
 
 		case SCTP_CMD_PROCESS_SACK:
 			/* Process an inbound SACK.  */
 			error = sctp_cmd_process_sack(commands, asoc,
-						      command->obj.ptr);
+						      cmd->obj.ptr);
 			break;
 
 		case SCTP_CMD_GEN_INIT_ACK:
@@ -347,16 +346,15 @@
 			 * layer which will bail.
 			 */
 			error = sctp_cmd_process_init(commands, asoc, chunk,
-						      command->obj.ptr,
-						      priority);
+						      cmd->obj.ptr, priority);
 			break;
 
 		case SCTP_CMD_GEN_COOKIE_ECHO:
 			/* Generate a COOKIE ECHO chunk.  */
 			new_obj = sctp_make_cookie_echo(asoc, chunk);
 			if (!new_obj) {
-				if (command->obj.ptr)
-					sctp_free_chunk(command->obj.ptr);
+				if (cmd->obj.ptr)
+					sctp_free_chunk(cmd->obj.ptr);
 				goto nomem;
 			}
 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
@@ -365,9 +363,9 @@
 			/* If there is an ERROR chunk to be sent along with
 			 * the COOKIE_ECHO, send it, too.
 			 */
-			if (command->obj.ptr)
+			if (cmd->obj.ptr)
 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
-						SCTP_CHUNK(command->obj.ptr));
+						SCTP_CHUNK(cmd->obj.ptr));
 			break;
 
 		case SCTP_CMD_GEN_SHUTDOWN:
@@ -387,43 +385,36 @@
 		case SCTP_CMD_CHUNK_ULP:
 			/* Send a chunk to the sockets layer.  */
 			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
-					  "chunk_up:",
-					  command->obj.ptr,
-					  "ulpq:",
-					  &asoc->ulpq);
-			sctp_ulpq_tail_data(&asoc->ulpq,
-					    command->obj.ptr,
+					  "chunk_up:", cmd->obj.ptr,
+					  "ulpq:", &asoc->ulpq);
+			sctp_ulpq_tail_data(&asoc->ulpq, cmd->obj.ptr,
 					    GFP_ATOMIC);
 			break;
 
 		case SCTP_CMD_EVENT_ULP:
 			/* Send a notification to the sockets layer.  */
 			SCTP_DEBUG_PRINTK("sm_sideff: %s %p, %s %p.\n",
-					  "event_up:",
-					  command->obj.ptr,
-					  "ulpq:",
-					  &asoc->ulpq);
-			sctp_ulpq_tail_event(&asoc->ulpq,
-					     command->obj.ptr);
+					  "event_up:",cmd->obj.ptr,
+					  "ulpq:",&asoc->ulpq);
+			sctp_ulpq_tail_event(&asoc->ulpq, cmd->obj.ptr);
 			break;
 
 		case SCTP_CMD_REPLY:
 			/* Send a chunk to our peer.  */
 			error = sctp_outq_tail(&asoc->outqueue,
-					       command->obj.ptr);
+					       cmd->obj.ptr);
 			break;
 
 		case SCTP_CMD_SEND_PKT:
 			/* Send a full packet to our peer.  */
-			packet = command->obj.ptr;
+			packet = cmd->obj.ptr;
 			sctp_packet_transmit(packet);
 			sctp_ootb_pkt_free(packet);
 			break;
 
 		case SCTP_CMD_RETRAN:
 			/* Mark a transport for retransmission.  */
-			sctp_retransmit(&asoc->outqueue,
-					command->obj.transport,
+			sctp_retransmit(&asoc->outqueue, cmd->obj.transport,
 					SCTP_RETRANSMIT_T3_RTX);
 			break;
 
@@ -434,32 +425,30 @@
 
 		case SCTP_CMD_ECN_CE:
 			/* Do delayed CE processing.   */
-			sctp_do_ecn_ce_work(asoc, command->obj.u32);
+			sctp_do_ecn_ce_work(asoc, cmd->obj.u32);
 			break;
 
 		case SCTP_CMD_ECN_ECNE:
 			/* Do delayed ECNE processing. */
-			new_obj = sctp_do_ecn_ecne_work(asoc,
-							command->obj.u32,
+			new_obj = sctp_do_ecn_ecne_work(asoc, cmd->obj.u32,
 							chunk);
-			if (new_obj) {
+			if (new_obj)
 				sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
 						SCTP_CHUNK(new_obj));
-			}
 			break;
 
 		case SCTP_CMD_ECN_CWR:
 			/* Do delayed CWR processing.  */
-			sctp_do_ecn_cwr_work(asoc, command->obj.u32);
+			sctp_do_ecn_cwr_work(asoc, cmd->obj.u32);
 			break;
 
 		case SCTP_CMD_SETUP_T2:
-			sctp_cmd_setup_t2(commands, asoc, command->obj.ptr);
+			sctp_cmd_setup_t2(commands, asoc, cmd->obj.ptr);
 			break;
 
 		case SCTP_CMD_TIMER_START:
-			timer = &asoc->timers[command->obj.to];
-			timeout = asoc->timeouts[command->obj.to];
+			timer = &asoc->timers[cmd->obj.to];
+			timeout = asoc->timeouts[cmd->obj.to];
 			if (!timeout)
 				BUG();
 
@@ -469,29 +458,28 @@
 			break;
 
 		case SCTP_CMD_TIMER_RESTART:
-			timer = &asoc->timers[command->obj.to];
-			timeout = asoc->timeouts[command->obj.to];
+			timer = &asoc->timers[cmd->obj.to];
+			timeout = asoc->timeouts[cmd->obj.to];
 			if (!mod_timer(timer, jiffies + timeout))
 				sctp_association_hold(asoc);
 			break;
 
 		case SCTP_CMD_TIMER_STOP:
-			timer = &asoc->timers[command->obj.to];
+			timer = &asoc->timers[cmd->obj.to];
 			if (timer_pending(timer) && del_timer(timer))
 				sctp_association_put(asoc);
 			break;
 
 		case SCTP_CMD_INIT_RESTART:
-
 			/* Do the needed accounting and updates
 			 * associated with restarting an initialization
 			 * timer.
 			 */
 			asoc->counters[SCTP_COUNTER_INIT_ERROR]++;
-			asoc->timeouts[command->obj.to] *= 2;
-			if (asoc->timeouts[command->obj.to] >
+			asoc->timeouts[cmd->obj.to] *= 2;
+			if (asoc->timeouts[cmd->obj.to] >
 			    asoc->max_init_timeo) {
-				asoc->timeouts[command->obj.to] =
+				asoc->timeouts[cmd->obj.to] =
 					asoc->max_init_timeo;
 			}
 
@@ -506,7 +494,7 @@
 
 			sctp_add_cmd_sf(commands,
 					SCTP_CMD_TIMER_RESTART,
-					SCTP_TO(command->obj.to));
+					SCTP_TO(cmd->obj.to));
 			break;
 
 		case SCTP_CMD_INIT_FAILED:
@@ -519,25 +507,16 @@
 			break;
 
 		case SCTP_CMD_COUNTER_INC:
-			asoc->counters[command->obj.counter]++;
+			asoc->counters[cmd->obj.counter]++;
 			break;
 
 		case SCTP_CMD_COUNTER_RESET:
-			asoc->counters[command->obj.counter] = 0;
+			asoc->counters[cmd->obj.counter] = 0;
 			break;
 
 		case SCTP_CMD_REPORT_DUP:
-			if (asoc->peer.next_dup_tsn < SCTP_MAX_DUP_TSNS) {
-				asoc->peer.dup_tsns[asoc->peer.next_dup_tsn++] =
-					ntohl(command->obj.u32);
-			}
-			break;
-
-		case SCTP_CMD_REPORT_BIGGAP:
-			SCTP_DEBUG_PRINTK("Big gap: %x to %x\n",
-					  sctp_tsnmap_get_ctsn(
-						  &asoc->peer.tsn_map),
-					  command->obj.u32);
+			sctp_tsnmap_mark_dup(&asoc->peer.tsn_map, 
+					     cmd->obj.u32);
 			break;
 
 		case SCTP_CMD_REPORT_BAD_TAG:
@@ -546,17 +525,16 @@
 
 		case SCTP_CMD_STRIKE:
 			/* Mark one strike against a transport.  */
-			sctp_do_8_2_transport_strike(asoc,
-						     command->obj.transport);
+			sctp_do_8_2_transport_strike(asoc, cmd->obj.transport);
 			break;
 
 		case SCTP_CMD_TRANSPORT_RESET:
-			t = command->obj.transport;
+			t = cmd->obj.transport;
 			sctp_cmd_transport_reset(commands, asoc, t);
 			break;
 
 		case SCTP_CMD_TRANSPORT_ON:
-			t = command->obj.transport;
+			t = cmd->obj.transport;
 			sctp_cmd_transport_on(commands, asoc, t, chunk);
 			break;
 
@@ -565,7 +543,7 @@
 			break;
 
 		case SCTP_CMD_HB_TIMER_UPDATE:
-			t = command->obj.transport;
+			t = cmd->obj.transport;
 			sctp_cmd_hb_timer_update(commands, asoc, t);
 			break;
 
@@ -574,17 +552,16 @@
 			break;
 
 		case SCTP_CMD_REPORT_ERROR:
-			error = command->obj.error;
+			error = cmd->obj.error;
 			break;
 
 		case SCTP_CMD_PROCESS_CTSN:
 			/* Dummy up a SACK for processing. */
-			sackh.cum_tsn_ack = command->obj.u32;
+			sackh.cum_tsn_ack = cmd->obj.u32;
 			sackh.a_rwnd = 0;
 			sackh.num_gap_ack_blocks = 0;
 			sackh.num_dup_tsns = 0;
-			sctp_add_cmd_sf(commands,
-					SCTP_CMD_PROCESS_SACK,
+			sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK,
 					SCTP_SACKH(&sackh));
 			break;
 
@@ -594,13 +571,23 @@
 			break;
 
 		case SCTP_CMD_RTO_PENDING:
-			t = command->obj.transport;
+			t = cmd->obj.transport;
 			t->rto_pending = 1;
 			break;
 
+		case SCTP_CMD_PART_DELIVER:
+			sctp_ulpq_partial_delivery(&asoc->ulpq, cmd->obj.ptr,
+						   GFP_ATOMIC);
+			break;
+
+		case SCTP_CMD_RENEGE:
+			sctp_ulpq_renege(&asoc->ulpq, cmd->obj.ptr,
+					 GFP_ATOMIC);
+			break;
+
 		default:
 			printk(KERN_WARNING "Impossible command: %u, %p\n",
-			       command->verb, command->obj.ptr);
+			       cmd->verb, cmd->obj.ptr);
 			break;
 		};
 		if (error)
@@ -737,7 +724,6 @@
 		asoc->a_rwnd = asoc->rwnd;
 
 		asoc->peer.sack_needed = 0;
-		asoc->peer.next_dup_tsn = 0;
 
 		error = sctp_outq_tail(&asoc->outqueue, sack);
 
@@ -1014,7 +1000,7 @@
 static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
 				 sctp_association_t *asoc)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 
 	event = sctp_ulpevent_make_assoc_change(asoc,
 						0,
@@ -1041,7 +1027,7 @@
 				  sctp_subtype_t subtype,
 				  sctp_chunk_t *chunk)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	__u16 error = 0;
 
 	switch(event_type) {
@@ -1061,12 +1047,11 @@
 		break;
 	}
 
-	event = sctp_ulpevent_make_assoc_change(asoc,
-						0,
-						SCTP_COMM_LOST,
-						error, 0, 0,
-						GFP_ATOMIC);
+	/* Cancel any partial delivery in progress. */
+	sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
 
+	event = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_LOST,
+						error, 0, 0, GFP_ATOMIC);
 	if (event)
 		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
 				SCTP_ULPEVENT(event));
@@ -1141,7 +1126,7 @@
 		if (del_timer(&t->hb_timer))
 			sctp_transport_put(t);
 	}
-} 
+}
 
 /* Helper function to update the heartbeat timer. */
 static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
diff -urN linux-2.5.63-bk6/net/sctp/sm_statefuns.c linux-2.5.63-bk7/net/sctp/sm_statefuns.c
--- linux-2.5.63-bk6/net/sctp/sm_statefuns.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/sctp/sm_statefuns.c	Mon Mar 31 12:20:18 2003
@@ -102,7 +102,7 @@
 				  sctp_cmd_seq_t *commands)
 {
 	sctp_chunk_t *chunk = arg;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 
 	/* RFC 2960 6.10 Bundling
 	 *
@@ -146,6 +146,9 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
 
+	SCTP_INC_STATS(SctpShutdowns);
+	SCTP_DEC_STATS(SctpCurrEstab);
+
 	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
 	return SCTP_DISPOSITION_DELETE_TCB;
@@ -223,6 +226,7 @@
 			if (packet) {
 				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 						SCTP_PACKET(packet));
+				SCTP_INC_STATS(SctpOutCtrlChunks);
 				return SCTP_DISPOSITION_CONSUME;
 			} else {
 				return SCTP_DISPOSITION_NOMEM;
@@ -264,7 +268,7 @@
 
 	if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0)
 		goto nomem_ack;
-	
+
 	repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len);
 	if (!repl)
 		goto nomem_ack;
@@ -379,6 +383,7 @@
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
 		sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 				SCTP_STATE(SCTP_STATE_CLOSED));
+		SCTP_INC_STATS(SctpAborteds);
 		sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
@@ -388,6 +393,9 @@
 	if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
 			      (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
 			      &err_chunk)) {
+
+		SCTP_INC_STATS(SctpAborteds);
+
 		/* This chunk contains fatal error. It is to be discarded.
 		 * Send an ABORT, with causes if there is any.
 		 */
@@ -403,6 +411,7 @@
 			if (packet) {
 				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 						SCTP_PACKET(packet));
+				SCTP_INC_STATS(SctpOutCtrlChunks);
 				sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 						SCTP_STATE(SCTP_STATE_CLOSED));
 				sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB,
@@ -504,7 +513,7 @@
 	sctp_association_t *new_asoc;
 	sctp_init_chunk_t *peer_init;
 	sctp_chunk_t *repl;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 	int error = 0;
 	sctp_chunk_t *err_chk_p;
 
@@ -557,6 +566,8 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_ESTABLISHED));
+	SCTP_INC_STATS(SctpCurrEstab);
+	SCTP_INC_STATS(SctpPassiveEstabs);
 	sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
 	if (new_asoc->autoclose)
@@ -636,7 +647,7 @@
 				      const sctp_subtype_t type, void *arg,
 				      sctp_cmd_seq_t *commands)
 {
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 
 	/* RFC 2960 5.1 Normal Establishment of an Association
 	 *
@@ -648,6 +659,8 @@
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_ESTABLISHED));
+	SCTP_INC_STATS(SctpCurrEstab);
+	SCTP_INC_STATS(SctpActiveEstabs);
 	sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 	if (asoc->autoclose)
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
@@ -669,7 +682,6 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
 
 	return SCTP_DISPOSITION_CONSUME;
-
 nomem:
 	return SCTP_DISPOSITION_NOMEM;
 }
@@ -719,6 +731,8 @@
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
 
@@ -929,6 +943,8 @@
 		goto out;
 	sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
 
+	SCTP_INC_STATS(SctpOutCtrlChunks);
+
 	/* Discard the rest of the inbound packet. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
 
@@ -1125,6 +1141,7 @@
 			if (packet) {
 				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 						SCTP_PACKET(packet));
+				SCTP_INC_STATS(SctpOutCtrlChunks);
 				retval = SCTP_DISPOSITION_CONSUME;
 			} else {
 				retval = SCTP_DISPOSITION_NOMEM;
@@ -1355,7 +1372,7 @@
 					       sctp_association_t *new_asoc)
 {
 	sctp_init_chunk_t *peer_init;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 	sctp_chunk_t *repl;
 
 	/* new_asoc is a brand-new association, so these are not yet
@@ -1421,7 +1438,7 @@
 					       sctp_association_t *new_asoc)
 {
 	sctp_init_chunk_t *peer_init;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 	sctp_chunk_t *repl;
 
 	/* new_asoc is a brand-new association, so these are not yet
@@ -1436,6 +1453,7 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_ESTABLISHED));
+	SCTP_INC_STATS(SctpCurrEstab);
 	sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
 	repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1503,7 +1521,7 @@
 					       sctp_cmd_seq_t *commands,
 					       sctp_association_t *new_asoc)
 {
-	sctp_ulpevent_t *ev = NULL;
+	struct sctp_ulpevent *ev = NULL;
 	sctp_chunk_t *repl;
 
 	/* Clarification from Implementor's Guide:
@@ -1519,6 +1537,7 @@
 				SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
 		sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 				SCTP_STATE(SCTP_STATE_ESTABLISHED));
+		SCTP_INC_STATS(SctpCurrEstab);
 		sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START,
 				SCTP_NULL());
 
@@ -1540,11 +1559,11 @@
 				SCTP_ULPEVENT(ev));
 	}
 	sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
-	
+
 	repl = sctp_make_cookie_ack(new_asoc, chunk);
 	if (!repl)
 		goto nomem;
-	
+
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 	sctp_add_cmd_sf(commands, SCTP_CMD_TRANSMIT, SCTP_NULL());
 
@@ -1925,6 +1944,8 @@
 
  	/* ASSOC_FAILED will DELETE_TCB. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+	SCTP_INC_STATS(SctpAborteds);
+	SCTP_DEC_STATS(SctpCurrEstab);
 
 	/* BUG?  This does not look complete... */
 	return SCTP_DISPOSITION_ABORT;
@@ -1948,6 +1969,7 @@
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
+	SCTP_INC_STATS(SctpAborteds);
 	sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
 
@@ -2241,6 +2263,7 @@
 	sctp_datahdr_t *data_hdr;
 	sctp_chunk_t *err;
 	size_t datalen;
+	sctp_verb_t deliver;
 	int tmp;
 	__u32 tsn;
 
@@ -2250,7 +2273,6 @@
 	 * that the value in the Verification Tag field of the
 	 * received SCTP packet matches its own Tag.
 	 */
-
 	if (ntohl(chunk->sctp_hdr->vtag) != asoc->c.my_vtag) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
 				SCTP_NULL());
@@ -2307,10 +2329,40 @@
 	datalen = ntohs(chunk->chunk_hdr->length);
 	datalen -= sizeof(sctp_data_chunk_t);
 
+	deliver = SCTP_CMD_CHUNK_ULP;
+
+	/* Think about partial delivery. */
+	if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
+
+		/* Even if we don't accept this chunk there is
+		 * memory pressure.
+		 */
+		sctp_add_cmd_sf(commands, SCTP_CMD_PART_DELIVER, SCTP_NULL());
+	}
+
+        /* Spill over rwnd a little bit.  Note: While allowed, this spill over
+	 * seems a bit troublesome in that frag_point varies based on
+	 * PMTU.  In cases, such as loopback, this might be a rather
+	 * large spill over.
+	 */
 	if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) {
-		SCTP_DEBUG_PRINTK("Discarding tsn: %u datalen: %Zd, "
-				  "rwnd: %d\n", tsn, datalen, asoc->rwnd);
-		goto discard_force;
+
+		/* If this is the next TSN, consider reneging to make
+		 * room.   Note: Playing nice with a confused sender.  A
+		 * malicious sender can still eat up all our buffer
+		 * space and in the future we may want to detect and
+		 * do more drastic reneging. 
+		 */
+		if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
+		    (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
+			SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
+			deliver = SCTP_CMD_RENEGE;
+		} else {
+			SCTP_DEBUG_PRINTK("Discard tsn: %u len: %Zd, "
+					  "rwnd: %d\n", tsn, datalen,
+					  asoc->rwnd);
+			goto discard_force;
+		}
 	}
 
 	/*
@@ -2332,13 +2384,24 @@
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
-	/* We are accepting this DATA chunk.  */
+	/* If definately accepting the DATA chunk, record its TSN, otherwise
+	 * wait for renege processing.
+	 */
+	if (SCTP_CMD_CHUNK_ULP == deliver)
+		sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
 
-	/* Record the fact that we have received this TSN.  */
-	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
+	/* Note: Some chunks may get overcounted (if we drop) or overcounted
+	 * if we renege and the chunk arrives again.
+	 */
+	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+		SCTP_INC_STATS(SctpInUnorderChunks);
+	else
+		SCTP_INC_STATS(SctpInOrderChunks);
 
 	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
 	 *
@@ -2352,10 +2415,9 @@
 		err = sctp_make_op_error(asoc, chunk, SCTP_ERROR_INV_STRM,
 					 &data_hdr->stream,
 					 sizeof(data_hdr->stream));
-		if (err) {
+		if (err)
 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
 					SCTP_CHUNK(err));
-		}
 		goto discard_noforce;
 	}
 
@@ -2363,7 +2425,8 @@
 	 * SCTP_CMD_CHUNK_ULP cmd before the SCTP_CMD_GEN_SACK, as the SACK
 	 * chunk needs the updated rwnd.
 	 */
-	sctp_add_cmd_sf(commands, SCTP_CMD_CHUNK_ULP, SCTP_CHUNK(chunk));
+	sctp_add_cmd_sf(commands, deliver, SCTP_CHUNK(chunk));
+
 	if (asoc->autoclose) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
 				SCTP_TO(SCTP_EVENT_TIMEOUT_AUTOCLOSE));
@@ -2536,6 +2599,8 @@
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
@@ -2544,6 +2609,11 @@
 	/* Record the fact that we have received this TSN.  */
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
 
+	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+		SCTP_INC_STATS(SctpInUnorderChunks);
+	else
+		SCTP_INC_STATS(SctpInOrderChunks);
+
 	/* RFC 2960 6.5 Stream Identifier and Stream Sequence Number
 	 *
 	 * If an endpoint receive a DATA chunk with an invalid stream
@@ -2705,6 +2775,8 @@
 		sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 				SCTP_PACKET(packet));
 
+		SCTP_INC_STATS(SctpOutCtrlChunks);
+
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
@@ -2726,7 +2798,7 @@
 					sctp_cmd_seq_t *commands)
 {
 	sctp_chunk_t *chunk = arg;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 
 	while (chunk->chunk_end > chunk->skb->data) {
 		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
@@ -2764,7 +2836,7 @@
 {
 	sctp_chunk_t *chunk = arg;
 	sctp_chunk_t *reply;
-	sctp_ulpevent_t *ev;
+	struct sctp_ulpevent *ev;
 
 	/* 10.2 H) SHUTDOWN COMPLETE notification
 	 *
@@ -2794,6 +2866,8 @@
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
+	SCTP_INC_STATS(SctpShutdowns);
+	SCTP_DEC_STATS(SctpCurrEstab);
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
 
 	/* ...and remove all record of the association. */
@@ -2834,6 +2908,8 @@
 	__u8 *ch_end;
 	int ootb_shut_ack = 0;
 
+	SCTP_INC_STATS(SctpOutOfBlues);
+
 	ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
 	do {
 		ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
@@ -2901,6 +2977,8 @@
 		sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 				SCTP_PACKET(packet));
 
+		SCTP_INC_STATS(SctpOutCtrlChunks);
+
 		return SCTP_DISPOSITION_CONSUME;
 	}
 
@@ -3472,6 +3550,10 @@
 
 	/* Delete the established association. */
 	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+
+	SCTP_INC_STATS(SctpAborteds);
+	SCTP_DEC_STATS(SctpCurrEstab);
+
 	return retval;
 }
 
@@ -3527,6 +3609,8 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
 
+	SCTP_INC_STATS(SctpShutdowns);
+
 	sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
 	return SCTP_DISPOSITION_DELETE_TCB;
@@ -3597,6 +3681,8 @@
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
 			SCTP_STATE(SCTP_STATE_CLOSED));
 
+	SCTP_INC_STATS(SctpAborteds);
+
 	/* Even if we can't send the ABORT due to low memory delete the
 	 * TCB.  This is a departure from our typical NOMEM handling.
 	 */
@@ -3929,6 +4015,8 @@
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
 
@@ -4096,6 +4184,8 @@
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
 		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_NULL());
+		SCTP_INC_STATS(SctpAborteds);
+		SCTP_DEC_STATS(SctpCurrEstab);
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
 
@@ -4271,6 +4361,9 @@
 	__u16 num_blocks;
 	__u16 num_dup_tsns;
 
+	/* FIXME:  Protect ourselves from reading too far into
+	 * the skb from a bogus sender.
+	 */
 	sack = (sctp_sackhdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_sackhdr_t));
 
@@ -4401,6 +4494,7 @@
 			sctp_packet_append_chunk(packet, err_chunk);
 			sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
 					SCTP_PACKET(packet));
+			SCTP_INC_STATS(SctpOutCtrlChunks);
 		} else
 			sctp_free_chunk (err_chunk);
 	}
diff -urN linux-2.5.63-bk6/net/sctp/socket.c linux-2.5.63-bk7/net/sctp/socket.c
--- linux-2.5.63-bk6/net/sctp/socket.c	Mon Feb 24 11:06:03 2003
+++ linux-2.5.63-bk7/net/sctp/socket.c	Mon Mar 31 12:20:18 2003
@@ -81,13 +81,13 @@
 
 /* Forward declarations for internal helper functions. */
 static int sctp_writeable(struct sock *sk);
-static inline int sctp_wspace(sctp_association_t *asoc);
+static inline int sctp_wspace(struct sctp_association *asoc);
 static inline void sctp_set_owner_w(sctp_chunk_t *chunk);
 static void sctp_wfree(struct sk_buff *skb);
-static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
+static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
 				int msg_len);
 static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
-static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p);
+static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
 static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
 static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
@@ -158,7 +158,7 @@
 /* Bind a local address either to an endpoint or to an association.  */
 SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 {
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_opt *sp = sctp_sk(sk);
 	sctp_endpoint_t *ep = sp->ep;
 	sctp_bind_addr_t *bp = &ep->base.bind_addr;
 	struct sctp_af *af;
@@ -454,7 +454,7 @@
  */
 int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
 {
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_opt *sp = sctp_sk(sk);
 	sctp_endpoint_t *ep = sp->ep;
 	int cnt;
 	sctp_bind_addr_t *bp = &ep->base.bind_addr;
@@ -662,6 +662,7 @@
 
 	/* Clean up any skbs sitting on the receive queue.  */
 	skb_queue_purge(&sk->receive_queue);
+	skb_queue_purge(&sctp_sk(sk)->pd_lobby);
 
 	/* This will run the backlog queue.  */
 	sctp_release_sock(sk);
@@ -714,7 +715,7 @@
 SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			     struct msghdr *msg, int msg_len)
 {
-	sctp_opt_t *sp;
+	struct sctp_opt *sp;
 	sctp_endpoint_t *ep;
 	sctp_association_t *new_asoc=NULL, *asoc=NULL;
 	struct sctp_transport *transport;
@@ -939,6 +940,19 @@
 	/* ASSERT: we have a valid association at this point.  */
 	SCTP_DEBUG_PRINTK("We have a valid association.\n");
 
+	if (!sinfo) {
+		/* If the user didn't specify SNDRCVINFO, make up one with
+		 * some defaults.
+		 */
+		default_sinfo.sinfo_stream = asoc->defaults.stream;
+		default_sinfo.sinfo_flags = asoc->defaults.flags;
+		default_sinfo.sinfo_ppid = asoc->defaults.ppid;
+		default_sinfo.sinfo_context = asoc->defaults.context;
+		default_sinfo.sinfo_timetolive = asoc->defaults.timetolive;
+		default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
+		sinfo = &default_sinfo;
+	}
+
 	/* API 7.1.7, the sndbuf size per association bounds the
 	 * maximum size of data that can be sent in a single send call.
 	 */
@@ -963,13 +977,6 @@
 			err = -EINVAL;
 			goto out_free;
 		}
-	} else {
-		/* If the user didn't specify SNDRCVINFO, make up one with
-		 * some defaults.
-		 */
-		default_sinfo.sinfo_stream = asoc->defaults.stream;
-		default_sinfo.sinfo_ppid = asoc->defaults.ppid;
-		sinfo = &default_sinfo;
 	}
 
 	timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
@@ -979,21 +986,6 @@
 			goto out_free;
 	}
 
-#if 0
-	/* FIXME: This looks wrong so I'll comment out.
-	 * We should be able to use this same technique for
-	 * primary address override!  --jgrimm
-	 */
-	/* If the user gave us an address, copy it in.  */
-	if (msg->msg_name) {
-		chunk->transport = sctp_assoc_lookup_paddr(asoc, &to);
-		if (!chunk->transport) {
-			err = -EINVAL;
-			goto out_free;
-		}
-	}
-#endif /* 0 */
-
 	/* Break the message into multiple chunks of maximum size. */
 	skb_queue_head_init(&chunks);
 	err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks);
@@ -1013,6 +1005,23 @@
 
 		/* Do accounting for the write space.  */
 		sctp_set_owner_w(chunk);
+
+		/* This flag, in the UDP model, requests the SCTP stack to
+		 * override the primary destination address with the 
+		 * address found with the sendto/sendmsg call.
+		 */
+		if (sinfo_flags & MSG_ADDR_OVER) {
+			if (!msg->msg_name) {
+				err = -EINVAL;
+				goto out_free;
+			}
+			chunk->transport = sctp_assoc_lookup_paddr(asoc, &to);
+			if (!chunk->transport) {
+				err = -EINVAL;
+				goto out_free;
+			}
+		}
+
 		/* Send it to the lower layers.  */
 		sctp_primitive_SEND(asoc, chunk);
 		SCTP_DEBUG_PRINTK("We sent primitively.\n");
@@ -1110,8 +1119,8 @@
 SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 			     int len, int noblock, int flags, int *addr_len)
 {
-	sctp_ulpevent_t *event = NULL;
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_ulpevent *event = NULL;
+	struct sctp_opt *sp = sctp_sk(sk);
 	struct sk_buff *skb;
 	int copied;
 	int err = 0;
@@ -1143,7 +1152,7 @@
 
 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
-	event = (sctp_ulpevent_t *) skb->cb;
+	event = sctp_skb2event(skb);
 
 	if (err)
 		goto out_free;
@@ -1170,7 +1179,6 @@
 	/* If skb's length exceeds the user's buffer, update the skb and
 	 * push it back to the receive_queue so that the next call to
 	 * recvmsg() will return the remaining data. Don't set MSG_EOR.
-	 * Otherwise, set MSG_EOR indicating the end of a message.
 	 */
 	if (skb_len > copied) {
 		msg->msg_flags &= ~MSG_EOR;
@@ -1178,6 +1186,7 @@
 			goto out_free;
 		sctp_skb_pull(skb, copied);
 		skb_queue_head(&sk->receive_queue, skb);
+
 		/* When only partial message is copied to the user, increase
 		 * rwnd by that amount. If all the data in the skb is read,
 		 * rwnd is updated when the skb's destructor is called via
@@ -1185,9 +1194,11 @@
 		 */
 		sctp_assoc_rwnd_increase(event->asoc, copied);
 		goto out;
-	} else {
-		 msg->msg_flags |= MSG_EOR;
-	}
+	} else if ((event->msg_flags & MSG_NOTIFICATION) ||
+		   (event->msg_flags & MSG_EOR))
+		msg->msg_flags |= MSG_EOR;
+	else
+		msg->msg_flags &= ~MSG_EOR;
 
 out_free:
 	sctp_ulpevent_free(event); /* Free the skb. */
@@ -1225,7 +1236,7 @@
 static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
 					    int optlen)
 {
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_opt *sp = sctp_sk(sk);
 
 	/* Applicable to UDP-style socket only */
 	if (SCTP_SOCKET_TCP == sp->type)
@@ -1310,6 +1321,44 @@
 	return 0;
 }
 
+/*
+ *
+ * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
+ *
+ *   Applications that wish to use the sendto() system call may wish to
+ *   specify a default set of parameters that would normally be supplied
+ *   through the inclusion of ancillary data.  This socket option allows
+ *   such an application to set the default sctp_sndrcvinfo structure.
+ *   The application that wishes to use this socket option simply passes
+ *   in to this call the sctp_sndrcvinfo structure defined in Section
+ *   5.2.2) The input parameters accepted by this call include
+ *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
+ *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
+ *   to this call if the caller is using the UDP model.
+ */
+static inline int sctp_setsockopt_set_default_send_param(struct sock *sk,
+						char *optval, int optlen)
+{
+	struct sctp_sndrcvinfo info;
+	sctp_association_t *asoc;
+
+	if (optlen != sizeof(struct sctp_sndrcvinfo))
+		return -EINVAL;
+	if (copy_from_user(&info, optval, optlen))
+		return -EFAULT;
+
+	asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
+	if (!asoc)
+		return -EINVAL;
+
+	asoc->defaults.stream = info.sinfo_stream;
+	asoc->defaults.flags = info.sinfo_flags;
+	asoc->defaults.ppid = info.sinfo_ppid;
+	asoc->defaults.context = info.sinfo_context;
+	asoc->defaults.timetolive = info.sinfo_timetolive;
+	return 0;
+}
+
 /* API 6.2 setsockopt(), getsockopt()
  *
  * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -1401,6 +1450,11 @@
 		retval = sctp_setsockopt_initmsg(sk, optval, optlen);
 		break;
 
+	case SCTP_SET_DEFAULT_SEND_PARAM:
+		retval = sctp_setsockopt_set_default_send_param(sk,
+							optval, optlen);
+		break;
+
 	default:
 		retval = -ENOPROTOOPT;
 		break;
@@ -1432,7 +1486,7 @@
 SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
 			     int addr_len)
 {
-	sctp_opt_t *sp;
+	struct sctp_opt *sp;
 	sctp_endpoint_t *ep;
 	sctp_association_t *asoc;
 	struct sctp_transport *transport;
@@ -1554,7 +1608,7 @@
 {
 	sctp_endpoint_t *ep;
 	sctp_protocol_t *proto;
-	sctp_opt_t *sp;
+	struct sctp_opt *sp;
 
 	SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk);
 
@@ -1583,7 +1637,7 @@
 
 	/* Initialize default RTO related parameters.  These parameters can
 	 * be modified for with the SCTP_RTOINFO socket option.
-	 * FIXME: This are not used yet.
+	 * FIXME: These are not used yet.
 	 */
 	sp->rtoinfo.srto_initial = proto->rto_initial;
 	sp->rtoinfo.srto_max     = proto->rto_max;
@@ -1620,6 +1674,11 @@
 	 */
 	sp->autoclose         = 0;
 	sp->pf = sctp_get_pf_specific(sk->family);
+
+	/* Control variables for partial data delivery. */
+	sp->pd_mode           = 0;
+	skb_queue_head_init(&sp->pd_lobby);
+
 	/* Create a per socket endpoint structure.  Even if we
 	 * change the data structure relationships, this may still
 	 * be useful for storing pre-connect address information.
@@ -1774,10 +1833,10 @@
 	struct sock *newsk;
 	struct socket *tmpsock;
 	sctp_endpoint_t *newep;
-	sctp_opt_t *oldsp = sctp_sk(oldsk);
-	sctp_opt_t *newsp;
+	struct sctp_opt *oldsp = sctp_sk(oldsk);
+	struct sctp_opt *newsp;
 	struct sk_buff *skb, *tmp;
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	int err = 0;
 
 	/* An association cannot be branched off from an already peeled-off
@@ -1811,13 +1870,50 @@
 	 * peeled off association to the new socket's receive queue.
 	 */
 	sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) {
-		event = (sctp_ulpevent_t *)skb->cb;
+		event = sctp_skb2event(skb);
 		if (event->asoc == assoc) {
 			__skb_unlink(skb, skb->list);
 			__skb_queue_tail(&newsk->receive_queue, skb);
 		}
 	}
 
+	/* Clean up an messages pending delivery due to partial
+	 * delivery.   Three cases:
+	 * 1) No partial deliver;  no work.
+	 * 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
+	 * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
+	 */
+	skb_queue_head_init(&newsp->pd_lobby);
+	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;;
+
+	if (sctp_sk(oldsk)->pd_mode) {
+		struct sk_buff_head *queue;
+
+		/* Decide which queue to move pd_lobby skbs to. */
+		if (assoc->ulpq.pd_mode) {
+			queue = &newsp->pd_lobby;
+		} else
+			queue = &newsk->receive_queue;
+
+		/* Walk through the pd_lobby, looking for skbs that
+		 * need moved to the new socket.
+		 */
+		sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
+			event = sctp_skb2event(skb);
+			if (event->asoc == assoc) {
+				__skb_unlink(skb, skb->list);
+				__skb_queue_tail(queue, skb);
+			}
+		}
+
+		/* Clear up any skbs waiting for the partial
+		 * delivery to finish.
+		 */
+		if (assoc->ulpq.pd_mode)
+			sctp_clear_pd(oldsk);
+
+	}
+
 	/* Set the type of socket to indicate that it is peeled off from the
 	 * original socket.
 	 */
@@ -2087,6 +2183,50 @@
 	return 0;
 }
 
+/*
+ *
+ * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
+ *
+ *   Applications that wish to use the sendto() system call may wish to
+ *   specify a default set of parameters that would normally be supplied
+ *   through the inclusion of ancillary data.  This socket option allows
+ *   such an application to set the default sctp_sndrcvinfo structure.
+ *   The application that wishes to use this socket option simply passes
+ *   in to this call the sctp_sndrcvinfo structure defined in Section
+ *   5.2.2) The input parameters accepted by this call include
+ *   sinfo_stream, sinfo_flags, sinfo_ppid, sinfo_context,
+ *   sinfo_timetolive.  The user must provide the sinfo_assoc_id field in
+ *   to this call if the caller is using the UDP model.
+ *
+ *   For getsockopt, it get the default sctp_sndrcvinfo structure.
+ */
+static inline int sctp_getsockopt_set_default_send_param(struct sock *sk,
+					int len, char *optval, int *optlen)
+{
+	struct sctp_sndrcvinfo info;
+	sctp_association_t *asoc;
+
+	if (len != sizeof(struct sctp_sndrcvinfo))
+		return -EINVAL;
+	if (copy_from_user(&info, optval, sizeof(struct sctp_sndrcvinfo)))
+		return -EFAULT;
+
+	asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
+	if (!asoc)
+		return -EINVAL;
+
+	info.sinfo_stream = asoc->defaults.stream;
+	info.sinfo_flags = asoc->defaults.flags;
+	info.sinfo_ppid = asoc->defaults.ppid;
+	info.sinfo_context = asoc->defaults.context;
+	info.sinfo_timetolive = asoc->defaults.timetolive;
+
+	if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo)))
+		return -EFAULT;
+
+	return 0;
+}
+
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
 				char *optval, int *optlen)
 {
@@ -2164,6 +2304,11 @@
 							      optlen);
 		break;
 
+	case SCTP_SET_DEFAULT_SEND_PARAM:
+		retval = sctp_getsockopt_set_default_send_param(sk, len,
+							optval, optlen);
+		break;
+
 	default:
 		retval = -ENOPROTOOPT;
 		break;
@@ -2389,7 +2534,7 @@
  */
 SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
 {
-	sctp_opt_t *sp = sctp_sk(sk);
+	struct sctp_opt *sp = sctp_sk(sk);
 	sctp_endpoint_t *ep = sp->ep;
 
 	/* Only UDP style sockets that are not peeled off are allowed to
diff -urN linux-2.5.63-bk6/net/sctp/tsnmap.c linux-2.5.63-bk7/net/sctp/tsnmap.c
--- linux-2.5.63-bk6/net/sctp/tsnmap.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/net/sctp/tsnmap.c	Mon Mar 31 12:20:18 2003
@@ -3,40 +3,40 @@
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2001 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
- * 
+ *
  * This file is part of the SCTP kernel reference Implementation
- * 
+ *
  * These functions manipulate sctp tsn mapping array.
- * 
- * The SCTP reference implementation is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
- * 
- * The SCTP reference implementation is distributed in the hope that it 
+ *
+ * The SCTP reference implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to the
  * email address(es):
  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
- * 
+ *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
  *
- * Written or modified by: 
+ * Written or modified by:
  *    La Monte H.P. Yarroll <piggy@acm.org>
  *    Jon Grimm             <jgrimm@us.ibm.com>
  *    Karl Knutson          <karl@athena.chicago.il.us>
- * 
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -45,21 +45,21 @@
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
-static void _sctp_tsnmap_update(sctp_tsnmap_t *map);
-static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map);
-static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
-				      __u16 len, __u16 base,
-				      int *started, __u16 *start,
-				      int *ended, __u16 *end);
+static void sctp_tsnmap_update(struct sctp_tsnmap *map);
+static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map);
+static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
+				     __u16 len, __u16 base,
+				     int *started, __u16 *start,
+				     int *ended, __u16 *end);
 
 /* Create a new sctp_tsnmap.
  * Allocate room to store at least 'len' contiguous TSNs.
  */
-sctp_tsnmap_t *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
+struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
 {
-	sctp_tsnmap_t *retval;
+	struct sctp_tsnmap *retval;
 
-	retval = kmalloc(sizeof(sctp_tsnmap_t) +
+	retval = kmalloc(sizeof(struct sctp_tsnmap) +
 			 sctp_tsnmap_storage_size(len),
 			 priority);
 	if (!retval)
@@ -72,13 +72,13 @@
 
 fail_map:
 	kfree(retval);
-
 fail:
 	return NULL;
 }
 
 /* Initialize a block of memory as a tsnmap.  */
-sctp_tsnmap_t *sctp_tsnmap_init(sctp_tsnmap_t *map, __u16 len, __u32 initial_tsn)
+struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
+				     __u32 initial_tsn)
 {
 	map->tsn_map = map->raw_map;
 	map->overflow_map = map->tsn_map + len;
@@ -94,6 +94,7 @@
 	map->max_tsn_seen = map->cumulative_tsn_ack_point;
 	map->malloced = 0;
 	map->pending_data = 0;
+	map->num_dup_tsns = 0;
 
 	return map;
 }
@@ -104,7 +105,7 @@
  *  >0 if the TSN has been seen (duplicate)
  *  <0 if the TSN is invalid (too large to track)
  */
-int sctp_tsnmap_check(const sctp_tsnmap_t *map, __u32 tsn)
+int sctp_tsnmap_check(const struct sctp_tsnmap *map, __u32 tsn)
 {
 	__s32 gap;
 	int dup;
@@ -136,7 +137,7 @@
 }
 
 /* Is there a gap in the TSN map?  */
-int sctp_tsnmap_has_gap(const sctp_tsnmap_t *map)
+int sctp_tsnmap_has_gap(const struct sctp_tsnmap *map)
 {
 	int has_gap;
 
@@ -145,7 +146,7 @@
 }
 
 /* Mark this TSN as seen.  */
-void sctp_tsnmap_mark(sctp_tsnmap_t *map, __u32 tsn)
+void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
 {
 	__s32 gap;
 
@@ -173,40 +174,45 @@
 	/* Go fixup any internal TSN mapping variables including
 	 * cumulative_tsn_ack_point.
 	 */
-	_sctp_tsnmap_update(map);
+	sctp_tsnmap_update(map);
+}
+
+void sctp_tsnmap_report_dup(struct sctp_tsnmap *map, __u32 tsn)
+{
 }
 
 /* Retrieve the Cumulative TSN Ack Point. */
-__u32 sctp_tsnmap_get_ctsn(const sctp_tsnmap_t *map)
+__u32 sctp_tsnmap_get_ctsn(const struct sctp_tsnmap *map)
 {
 	return map->cumulative_tsn_ack_point;
 }
 
 /* Retrieve the highest TSN we've seen.  */
-__u32 sctp_tsnmap_get_max_tsn_seen(const sctp_tsnmap_t *map)
+__u32 sctp_tsnmap_get_max_tsn_seen(const struct sctp_tsnmap *map)
 {
 	return map->max_tsn_seen;
 }
 
 /* Dispose of a tsnmap.  */
-void sctp_tsnmap_free(sctp_tsnmap_t *map)
+void sctp_tsnmap_free(struct sctp_tsnmap *map)
 {
 	if (map->malloced)
 		kfree(map);
 }
 
 /* Initialize a Gap Ack Block iterator from memory being provided.  */
-void sctp_tsnmap_iter_init(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter)
+void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
+			   struct sctp_tsnmap_iter *iter)
 {
 	/* Only start looking one past the Cumulative TSN Ack Point.  */
 	iter->start = map->cumulative_tsn_ack_point + 1;
 }
 
-/* Get the next Gap Ack Blocks. Returns 0 if there was not
- * another block to get.
+/* Get the next Gap Ack Blocks. Returns 0 if there was not another block
+ * to get.
  */
-int sctp_tsnmap_next_gap_ack(const sctp_tsnmap_t *map, sctp_tsnmap_iter_t *iter,
-			     __u16 *start, __u16 *end)
+int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
+	struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
 {
 	int started, ended;
 	__u16 _start, _end, offset;
@@ -216,12 +222,10 @@
 
 	/* Search the first mapping array.  */
 	if (iter->start - map->base_tsn < map->len) {
+
 		offset = iter->start - map->base_tsn;
-		_sctp_tsnmap_find_gap_ack(map->tsn_map,
-					  offset,
-					  map->len, 0,
-					  &started, &_start,
-					  &ended, &_end);
+		sctp_tsnmap_find_gap_ack(map->tsn_map, offset, map->len, 0,
+					 &started, &_start, &ended, &_end);
 	}
 
 	/* Do we need to check the overflow map? */
@@ -235,12 +239,12 @@
 			offset = iter->start - map->base_tsn - map->len;
 
 		/* Search the overflow map.  */
-		_sctp_tsnmap_find_gap_ack(map->overflow_map,
-					  offset,
-					  map->len,
-					  map->len,
-					  &started, &_start,
-					  &ended, &_end);
+		sctp_tsnmap_find_gap_ack(map->overflow_map,
+					 offset,
+					 map->len,
+					 map->len,
+					 &started, &_start,
+					 &ended, &_end);
 	}
 
 	/* The Gap Ack Block happens to end at the end of the
@@ -278,7 +282,7 @@
 /* This private helper function updates the tsnmap buffers and
  * the Cumulative TSN Ack Point.
  */
-static void _sctp_tsnmap_update(sctp_tsnmap_t *map)
+static void sctp_tsnmap_update(struct sctp_tsnmap *map)
 {
 	__u32 ctsn;
 
@@ -301,10 +305,10 @@
 	} while (map->tsn_map[ctsn - map->base_tsn]);
 
 	map->cumulative_tsn_ack_point = ctsn - 1; /* Back up one. */
-	_sctp_tsnmap_update_pending_data(map);
+	sctp_tsnmap_update_pending_data(map);
 }
 
-static void _sctp_tsnmap_update_pending_data(sctp_tsnmap_t *map)
+static void sctp_tsnmap_update_pending_data(struct sctp_tsnmap *map)
 {
 	__u32 cum_tsn = map->cumulative_tsn_ack_point;
 	__u32 max_tsn = map->max_tsn_seen;
@@ -324,7 +328,7 @@
 	for (i = start; i < end; i++) {
 		if (map->tsn_map[i])
 			pending_data--;
-	} 
+	}
 
 	if (gap >= map->len) {
 		start = 0;
@@ -345,14 +349,14 @@
  * The flags "started" and "ended" tell is if we found the beginning
  * or (respectively) the end of a Gap Ack Block.
  */
-static void _sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
-				      __u16 len, __u16 base,
-				      int *started, __u16 *start,
-				      int *ended, __u16 *end)
+static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
+				     __u16 len, __u16 base,
+				     int *started, __u16 *start,
+				     int *ended, __u16 *end)
 {
 	int i = off;
 
-	/* Let's look through the entire array, but break out
+	/* Look through the entire array, but break out
 	 * early if we have found the end of the Gap Ack Block.
 	 */
 
@@ -381,3 +385,23 @@
 		}
 	}
 }
+
+/* Renege that we have seen a TSN.  */
+void sctp_tsnmap_renege(struct sctp_tsnmap *map, __u32 tsn)
+{
+	__s32 gap;
+
+	if (TSN_lt(tsn, map->base_tsn))
+		return;
+	if (!TSN_lt(tsn, map->base_tsn + map->len + map->len))
+		return;
+	
+	/* Assert: TSN is in range.  */
+	gap = tsn - map->base_tsn;
+
+	/* Pretend we never saw the TSN.  */
+	if (gap < map->len)
+		map->tsn_map[gap] = 0;
+	else
+		map->overflow_map[gap - map->len] = 0;
+}
diff -urN linux-2.5.63-bk6/net/sctp/ulpevent.c linux-2.5.63-bk7/net/sctp/ulpevent.c
--- linux-2.5.63-bk6/net/sctp/ulpevent.c	Mon Mar 31 12:20:06 2003
+++ linux-2.5.63-bk7/net/sctp/ulpevent.c	Mon Mar 31 12:20:18 2003
@@ -5,37 +5,37 @@
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
- * 
- * These functions manipulate an sctp event.   The sctp_ulpevent_t is used
- * to carry notifications and data to the ULP (sockets).  
- * The SCTP reference implementation is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ *
+ * These functions manipulate an sctp event.   The struct ulpevent is used
+ * to carry notifications and data to the ULP (sockets).
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
  * the GNU General Public License as published by
  * the Free Software Foundation; either version 2, or (at your option)
  * any later version.
- * 
- * The SCTP reference implementation is distributed in the hope that it 
+ *
+ * The SCTP reference implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to the
  * email address(es):
  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
- * 
+ *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
  *
- * Written or modified by: 
+ * Written or modified by:
  *    Jon Grimm             <jgrimm@us.ibm.com>
  *    La Monte H.P. Yarroll <piggy@acm.org>
- * 
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -47,58 +47,51 @@
 #include <net/sctp/sm.h>
 
 static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
-				      sctp_association_t *asoc);
-static void
-sctp_ulpevent_set_owner(struct sk_buff *skb, const sctp_association_t *asoc);
+				      struct sctp_association *asoc);
+static void sctp_ulpevent_set_owner(struct sk_buff *skb,
+				    const struct sctp_association *asoc);
 
 /* Create a new sctp_ulpevent.  */
-sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority)
+struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sk_buff *skb;
 
 	skb = alloc_skb(size, priority);
 	if (!skb)
 		goto fail;
 
-	event = (sctp_ulpevent_t *) skb->cb;
-	event = sctp_ulpevent_init(event, skb, msg_flags);
+	event = sctp_skb2event(skb);
+	event = sctp_ulpevent_init(event, msg_flags);
 	if (!event)
 		goto fail_init;
-
-	event->malloced = 1;
 	return event;
 
 fail_init:
-	kfree_skb(event->parent);
-
+	kfree_skb(skb);
 fail:
 	return NULL;
 }
 
 /* Initialize an ULP event from an given skb.  */
-sctp_ulpevent_t *sctp_ulpevent_init(sctp_ulpevent_t *event,
-				    struct sk_buff *parent,
-				    int msg_flags)
+struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *event,
+					 int msg_flags)
 {
-	memset(event, sizeof(sctp_ulpevent_t), 0x00);
+	memset(event, sizeof(struct sctp_ulpevent), 0x00);
 	event->msg_flags = msg_flags;
-	event->parent = parent;
-	event->malloced = 0;
 	return event;
 }
 
 /* Dispose of an event.  */
-void sctp_ulpevent_free(sctp_ulpevent_t *event)
+void sctp_ulpevent_free(struct sctp_ulpevent *event)
 {
-	if (event->malloced)
-		kfree_skb(event->parent);
+	kfree_skb(sctp_event2skb(event));
 }
 
 /* Is this a MSG_NOTIFICATION?  */
-int sctp_ulpevent_is_notification(const sctp_ulpevent_t *event)
+int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
 {
-	return event->msg_flags & MSG_NOTIFICATION;
+	return MSG_NOTIFICATION == (event->msg_flags & MSG_NOTIFICATION);
 }
 
 /* Create and initialize an SCTP_ASSOC_CHANGE event.
@@ -112,24 +105,22 @@
  * Note: There is no field checking here.  If a field is unused it will be
  * zero'd out.
  */
-sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
-						 __u16 flags,
-						 __u16 state,
-						 __u16 error,
-						 __u16 outbound,
-						 __u16 inbound,
-						 int priority)
+struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
+	const sctp_association_t *asoc,
+	__u16 flags, __u16 state, __u16 error, __u16 outbound,
+	__u16 inbound, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sctp_assoc_change *sac;
+	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
 				  MSG_NOTIFICATION, priority);
 	if (!event)
 		goto fail;
-
+	skb = sctp_event2skb(event);
 	sac = (struct sctp_assoc_change *)
-		skb_put(event->parent, sizeof(struct sctp_assoc_change));
+		skb_put(skb, sizeof(struct sctp_assoc_change));
 
 	/* Socket Extensions for SCTP
 	 * 5.3.1.1 SCTP_ASSOC_CHANGE
@@ -198,13 +189,13 @@
 	 * All notifications for a given association have the same association
 	 * identifier.  For TCP style socket, this field is ignored.
 	 */
-	sctp_ulpevent_set_owner(event->parent, asoc);
+	sctp_ulpevent_set_owner(skb, asoc);
 	sac->sac_assoc_id = sctp_assoc2id(asoc);
 
 	return event;
 
 fail:
-	return NULL;	
+	return NULL;
 }
 
 /* Create and initialize an SCTP_PEER_ADDR_CHANGE event.
@@ -215,24 +206,22 @@
  * When a destination address on a multi-homed peer encounters a change
  * an interface details event is sent.
  */
-sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
-				const sctp_association_t *asoc,
-				const struct sockaddr_storage *aaddr,
-				int flags,
-				int state,
-				int error,
-				int priority)
+struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
+	const sctp_association_t *asoc, const struct sockaddr_storage *aaddr,
+	int flags, int state, int error, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sctp_paddr_change  *spc;
+	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
 				  MSG_NOTIFICATION, priority);
 	if (!event)
 		goto fail;
 
+	skb = sctp_event2skb(event);
 	spc = (struct sctp_paddr_change *)
-		skb_put(event->parent, sizeof(struct sctp_paddr_change));
+		skb_put(skb, sizeof(struct sctp_paddr_change));
 
 	/* Sockets API Extensions for SCTP
 	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
@@ -265,7 +254,7 @@
 	 * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
 	 *
 	 * spc_state:  32 bits (signed integer)
-	 * 
+	 *
 	 * This field holds one of a number of values that communicate the
 	 * event that happened to the address.
 	 */
@@ -291,7 +280,7 @@
 	 * All notifications for a given association have the same association
 	 * identifier.  For TCP style socket, this field is ignored.
 	 */
-	sctp_ulpevent_set_owner(event->parent, asoc);
+	sctp_ulpevent_set_owner(skb, asoc);
 	spc->spc_assoc_id = sctp_assoc2id(asoc);
 
 	/* Sockets API Extensions for SCTP
@@ -325,12 +314,11 @@
  * specification [SCTP] and any extensions for a list of possible
  * error formats.
  */
-sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
-						 sctp_chunk_t *chunk,
-						 __u16 flags,
-						 int priority)
+struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
+	const sctp_association_t *asoc, sctp_chunk_t *chunk,
+	__u16 flags, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sctp_remote_error *sre;
 	struct sk_buff *skb;
 	sctp_errhdr_t *ch;
@@ -358,13 +346,12 @@
 		goto fail;
 
 	/* Embed the event fields inside the cloned skb.  */
-	event = (sctp_ulpevent_t *) skb->cb;
-	event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION);
+	event = sctp_skb2event(skb);
+	event = sctp_ulpevent_init(event, MSG_NOTIFICATION);
 
 	if (!event)
 		goto fail;
 
-	event->malloced = 1;
 	sre = (struct sctp_remote_error *)
 		skb_push(skb, sizeof(struct sctp_remote_error));
 
@@ -416,7 +403,8 @@
 	 * All notifications for a given association have the same association
 	 * identifier.  For TCP style socket, this field is ignored.
 	 */
-	sctp_ulpevent_set_owner(event->parent, asoc);
+	skb = sctp_event2skb(event);
+	sctp_ulpevent_set_owner(skb, asoc);
 	sre->sre_assoc_id = sctp_assoc2id(asoc);
 
 	return event;
@@ -430,13 +418,11 @@
  * Socket Extensions for SCTP - draft-01
  * 5.3.1.4 SCTP_SEND_FAILED
  */
-sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
-						sctp_chunk_t *chunk,
-						__u16 flags,
-						__u32 error,
-						int priority)
+struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
+	const sctp_association_t *asoc, sctp_chunk_t *chunk,
+	__u16 flags, __u32 error, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sctp_send_failed *ssf;
 	struct sk_buff *skb;
 
@@ -452,16 +438,11 @@
 	skb_pull(skb, sizeof(sctp_data_chunk_t));
 
 	/* Embed the event fields inside the cloned skb.  */
-	event = (sctp_ulpevent_t *) skb->cb;
-	event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION);
+	event = sctp_skb2event(skb);
+	event = sctp_ulpevent_init(event, MSG_NOTIFICATION);
 	if (!event)
 		goto fail;
 
-	/* Mark as malloced, even though the constructor was not
-	 * called.
-	 */
-	event->malloced = 1;
-
 	ssf = (struct sctp_send_failed *)
 		skb_push(skb, sizeof(struct sctp_send_failed));
 
@@ -525,7 +506,8 @@
 	 * same association identifier.  For TCP style socket, this field is
 	 * ignored.
 	 */
-	sctp_ulpevent_set_owner(event->parent, asoc);
+	skb = sctp_event2skb(event);
+	sctp_ulpevent_set_owner(skb, asoc);
 	ssf->ssf_assoc_id = sctp_assoc2id(asoc);
 	return event;
 
@@ -538,21 +520,22 @@
  * Socket Extensions for SCTP - draft-01
  * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  */
-sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
+struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
 	const sctp_association_t *asoc,
-	__u16 flags,
-	int priority)
+	__u16 flags, int priority)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 	struct sctp_shutdown_event *sse;
+	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
 				  MSG_NOTIFICATION, priority);
 	if (!event)
 		goto fail;
 
+	skb = sctp_event2skb(event);
 	sse = (struct sctp_shutdown_event *)
-		skb_put(event->parent, sizeof(struct sctp_shutdown_event));
+		skb_put(skb, sizeof(struct sctp_shutdown_event));
 
 	/* Socket Extensions for SCTP
 	 * 5.3.1.5 SCTP_SHUTDOWN_EVENT
@@ -587,7 +570,7 @@
 	 * All notifications for a given association have the same association
 	 * identifier.  For TCP style socket, this field is ignored.
 	 */
-	sctp_ulpevent_set_owner(event->parent, asoc);
+	sctp_ulpevent_set_owner(skb, asoc);
 	sse->sse_assoc_id = sctp_assoc2id(asoc);
 
 	return event;
@@ -600,13 +583,13 @@
  * to pass it to the upper layers.  Go ahead and calculate the sndrcvinfo
  * even if filtered out later.
  *
- * Socket Extensions for SCTP - draft-01
+ * Socket Extensions for SCTP
  * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
  */
-sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
-					   sctp_chunk_t *chunk, int priority)
+struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
+		   sctp_chunk_t *chunk, int priority)
 {
-	sctp_ulpevent_t *event, *levent;
+	struct sctp_ulpevent *event;
 	struct sctp_sndrcvinfo *info;
 	struct sk_buff *skb, *list;
 	size_t padding, len;
@@ -638,24 +621,19 @@
 	sctp_ulpevent_set_owner_r(skb, asoc);
 
 	/* Embed the event fields inside the cloned skb.  */
-	event = (sctp_ulpevent_t *) skb->cb;
+	event = sctp_skb2event(skb);
 
 	/* Initialize event with flags 0.  */
-	event = sctp_ulpevent_init(event, skb, 0);
+	event = sctp_ulpevent_init(event, 0);
 	if (!event)
 		goto fail_init;
 
-	event->malloced = 1;
-
-	for (list = skb_shinfo(skb)->frag_list; list; list = list->next) {
+	/* Note:  Not clearing the entire event struct as
+	 * this is just a fragment of the real event.  However,
+	 * we still need to do rwnd accounting. 
+	 */
+	for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
 		sctp_ulpevent_set_owner_r(list, asoc);
-		/* Initialize event with flags 0.  */
-		levent = sctp_ulpevent_init(event, skb, 0);
-		if (!levent)
-			goto fail_init;
-
-		levent->malloced = 1;
-	}
 
 	info = (struct sctp_sndrcvinfo *) &event->sndrcvinfo;
 
@@ -707,18 +685,26 @@
 	 * MSG_UNORDERED - This flag is present when the message was sent
 	 *                 non-ordered.
 	 */
-	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
+	if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
 		info->sinfo_flags |= MSG_UNORDERED;
 
-	/* FIXME:  For reassembly, we need to have the fragmentation bits.
-	 * This really does not belong in the event structure, but
-	 * its difficult to fix everything at the same time.   Eventually,
-	 * we should create and skb based chunk structure.   This structure
-	 * storage can be converted to an event.  --jgrimm
+		/* sinfo_cumtsn: 32 bit (unsigned integer)
+		 *  
+		 * This field will hold the current cumulative TSN as 
+		 * known by the underlying SCTP layer.  Note this field is 
+		 * ignored when sending and only valid for a receive 
+		 * operation when sinfo_flags are set to MSG_UNORDERED.
+		 */
+		info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
+	}
+
+	/* Note:  For reassembly, we need to have the fragmentation bits. 
+	 * For now, merge these into the msg_flags, since those bit
+	 * possitions are not used.
 	 */
-	event->chunk_flags = chunk->chunk_hdr->flags;
+	event->msg_flags |= chunk->chunk_hdr->flags;
 
-	/* With -04 draft, tsn moves into sndrcvinfo. */
+	/* With 04 draft, tsn moves into sndrcvinfo. */
 	info->sinfo_tsn = ntohl(chunk->subh.data_hdr->tsn);
 
 	/* Context is not used on receive. */
@@ -745,19 +731,79 @@
 	return NULL;
 }
 
+/* Create a partial delivery related event. 
+ *
+ * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
+ *
+ *   When a reciever is engaged in a partial delivery of a
+ *   message this notification will be used to inidicate
+ *   various events.
+ */
+struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
+	const sctp_association_t *asoc, __u32 indication, int priority)
+{
+	struct sctp_ulpevent *event;
+	struct sctp_rcv_pdapi_event *pd;
+	struct sk_buff *skb;
+
+	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
+				  MSG_NOTIFICATION, priority);
+	if (!event)
+		goto fail;
+
+	skb = sctp_event2skb(event);
+	pd = (struct sctp_rcv_pdapi_event *)
+		skb_put(skb, sizeof(struct sctp_rcv_pdapi_event));
+
+	/* pdapi_type
+	 *   It should be SCTP_PARTIAL_DELIVERY_EVENT
+	 *
+	 * pdapi_flags: 16 bits (unsigned integer)
+	 *   Currently unused.
+	 */
+	pd->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT;
+	pd->pdapi_flags = 0;
+
+	/* pdapi_length: 32 bits (unsigned integer)
+	 *
+	 * This field is the total length of the notification data, including
+	 * the notification header.  It will generally be sizeof (struct
+	 * sctp_rcv_pdapi_event).
+	 */
+	pd->pdapi_length = sizeof(struct sctp_rcv_pdapi_event);
+
+        /*  pdapi_indication: 32 bits (unsigned integer)
+	 *
+	 * This field holds the indication being sent to the application.
+	 */
+	pd->pdapi_indication = indication;
+
+	/*  pdapi_assoc_id: sizeof (sctp_assoc_t)
+	 * 
+	 * The association id field, holds the identifier for the association.
+	 */
+	pd->pdapi_assoc_id = sctp_assoc2id(asoc);
+
+	return event;
+fail:
+	return NULL;
+}
+
 /* Return the notification type, assuming this is a notification
  * event.
  */
-__u16 sctp_ulpevent_get_notification_type(const sctp_ulpevent_t *event)
+__u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event)
 {
 	union sctp_notification *notification;
+	struct sk_buff *skb;
 
-	notification = (union sctp_notification *) event->parent->data;
+	skb = sctp_event2skb((struct sctp_ulpevent *)event);
+	notification = (union sctp_notification *) skb->data;
 	return notification->h.sn_type;
 }
 
 /* Copy out the sndrcvinfo into a msghdr.  */
-void sctp_ulpevent_read_sndrcvinfo(const sctp_ulpevent_t *event,
+void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
 				   struct msghdr *msghdr)
 {
 	if (!sctp_ulpevent_is_notification(event)) {
@@ -771,7 +817,7 @@
 static void sctp_rcvmsg_rfree(struct sk_buff *skb)
 {
 	sctp_association_t *asoc;
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 
 	/* Current stack structures assume that the rcv buffer is
 	 * per socket.   For UDP style sockets this is not true as
@@ -779,16 +825,17 @@
 	 * Use the local private area of the skb to track the owning
 	 * association.
 	 */
-	event = (sctp_ulpevent_t *) skb->cb;
+	event = sctp_skb2event(skb);
 	asoc = event->asoc;
 	sctp_assoc_rwnd_increase(asoc, skb_headlen(skb));
 	sctp_association_put(asoc);
 }
 
 /* Charge receive window for bytes received.  */
-static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *asoc)
+static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
+				      sctp_association_t *asoc)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 
 	/* The current stack structures assume that the rcv buffer is
 	 * per socket.  For UDP-style sockets this is not true as
@@ -798,7 +845,7 @@
 	 */
 	sctp_association_hold(asoc);
 	skb->sk = asoc->base.sk;
-	event = (sctp_ulpevent_t *) skb->cb;
+	event = sctp_skb2event(skb);
 	event->asoc = asoc;
 
 	skb->destructor = sctp_rcvmsg_rfree;
@@ -809,26 +856,26 @@
 /* A simple destructor to give up the reference to the association. */
 static void sctp_ulpevent_rfree(struct sk_buff *skb)
 {
-	sctp_ulpevent_t *event;	
-	
-	event = (sctp_ulpevent_t *)skb->cb;
+	struct sctp_ulpevent *event;
+
+	event = sctp_skb2event(skb);
 	sctp_association_put(event->asoc);
 }
 
-/* Hold the association in case the msg_name needs read out of 
- * the association. 
+/* Hold the association in case the msg_name needs read out of
+ * the association.
  */
 static void sctp_ulpevent_set_owner(struct sk_buff *skb,
-				    const sctp_association_t *asoc)
+				    const struct sctp_association *asoc)
 {
-	sctp_ulpevent_t *event;
+	struct sctp_ulpevent *event;
 
 	/* Cast away the const, as we are just wanting to
 	 * bump the reference count.
 	 */
-	sctp_association_hold((sctp_association_t *)asoc);
+	sctp_association_hold((struct sctp_association *)asoc);
 	skb->sk = asoc->base.sk;
-	event = (sctp_ulpevent_t *)skb->cb;
-	event->asoc = (sctp_association_t *)asoc;
+	event = sctp_skb2event(skb);
+	event->asoc = (struct sctp_association *)asoc;
 	skb->destructor = sctp_ulpevent_rfree;
 }
diff -urN linux-2.5.63-bk6/net/sctp/ulpqueue.c linux-2.5.63-bk7/net/sctp/ulpqueue.c
--- linux-2.5.63-bk6/net/sctp/ulpqueue.c	Mon Feb 24 11:05:44 2003
+++ linux-2.5.63-bk7/net/sctp/ulpqueue.c	Mon Mar 31 12:20:18 2003
@@ -84,6 +84,7 @@
 	ulpq->asoc = asoc;
 	skb_queue_head_init(&ulpq->reasm);
 	skb_queue_head_init(&ulpq->lobby);
+	ulpq->pd_mode  = 0;
 	ulpq->malloced = 0;
 
 	return ulpq;
@@ -96,15 +97,16 @@
 	struct sk_buff *skb;
 	struct sctp_ulpevent *event;
 
-	while ((skb = skb_dequeue(&ulpq->lobby))) {
-		event = (struct sctp_ulpevent *) skb->cb;
+	while ((skb = __skb_dequeue(&ulpq->lobby))) {
+		event = sctp_skb2event(skb);
 		sctp_ulpevent_free(event);
 	}
 
-	while ((skb = skb_dequeue(&ulpq->reasm))) {
-		event = (struct sctp_ulpevent *) skb->cb;
+	while ((skb = __skb_dequeue(&ulpq->reasm))) {
+		event = sctp_skb2event(skb);
 		sctp_ulpevent_free(event);
 	}
+
 }
 
 /* Dispose of a ulpqueue.  */
@@ -117,7 +119,7 @@
 
 /* Process an incoming DATA chunk.  */
 int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
-			    int priority)
+			int priority)
 {
 	struct sk_buff_head temp;
 	sctp_data_chunk_t *hdr;
@@ -125,12 +127,7 @@
 
 	hdr = (sctp_data_chunk_t *) chunk->chunk_hdr;
 
-	/* FIXME: Instead of event being the skb clone, we really should
-	 * have a new skb based chunk structure that we can convert to
-	 * an event.  Temporarily, I'm carrying a few chunk fields in
-	 * the event to allow reassembly.  Its too painful to change
-	 * everything at once.  --jgrimm
-	 */
+	/* Create an event from the incoming chunk. */
 	event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority);
 	if (!event)
 		return -ENOMEM;
@@ -139,10 +136,10 @@
 	event = sctp_ulpq_reasm(ulpq, event);
 
 	/* Do ordering if needed.  */
-	if (event) {
+	if ((event) && (event->msg_flags & MSG_EOR)){
 		/* Create a temporary list to collect chunks on.  */
 		skb_queue_head_init(&temp);
-		skb_queue_tail(&temp, event->parent);
+		__skb_queue_tail(&temp, sctp_event2skb(event));
 
 		event = sctp_ulpq_order(ulpq, event);
 	}
@@ -155,9 +152,39 @@
 }
 
 /* Add a new event for propagation to the ULP.  */
+/* Clear the partial delivery mode for this socket.   Note: This
+ * assumes that no association is currently in partial delivery mode.
+ */
+int sctp_clear_pd(struct sock *sk)
+{
+	struct sctp_opt *sp;
+	sp = sctp_sk(sk);
+
+	sp->pd_mode = 0;
+	if (!skb_queue_empty(&sp->pd_lobby)) {
+		struct list_head *list;
+		sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue);
+		list = (struct list_head *)&sctp_sk(sk)->pd_lobby;
+		INIT_LIST_HEAD(list);
+		return 1;
+	}
+	return 0;
+}
+
+/* Clear the pd_mode and restart any pending messages waiting for delivery. */
+static int sctp_ulpq_clear_pd(struct sctp_ulpq *ulpq)
+{
+	ulpq->pd_mode = 0;
+	return sctp_clear_pd(ulpq->asoc->base.sk);
+}
+
+
+
 int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
 {
 	struct sock *sk = ulpq->asoc->base.sk;
+	struct sk_buff_head *queue;
+	int clear_pd = 0;
 
 	/* If the socket is just going to throw this away, do not
 	 * even try to deliver it.
@@ -169,29 +196,55 @@
 	if (!sctp_ulpevent_is_enabled(event, &sctp_sk(sk)->subscribe))
 		goto out_free;
 
+	/* If we are in partial delivery mode, post to the lobby until
+	 * partial delivery is cleared, unless, of course _this_ is
+	 * the association the cause of the partial delivery.
+	 */
+
+	if (!sctp_sk(sk)->pd_mode) {
+		queue = &sk->receive_queue;
+	} else if (ulpq->pd_mode) {
+		if (event->msg_flags & MSG_NOTIFICATION)
+		       	queue = &sctp_sk(sk)->pd_lobby;
+		else {
+			clear_pd = event->msg_flags & MSG_EOR;
+			queue = &sk->receive_queue;
+		}
+	} else
+		queue = &sctp_sk(sk)->pd_lobby;
+
+
 	/* If we are harvesting multiple skbs they will be
 	 * collected on a list.
 	 */
-	if (event->parent->list)
-		sctp_skb_list_tail(event->parent->list, &sk->receive_queue);
+	if (sctp_event2skb(event)->list)
+		sctp_skb_list_tail(sctp_event2skb(event)->list, queue);
 	else
-		skb_queue_tail(&sk->receive_queue, event->parent);
+		skb_queue_tail(queue, sctp_event2skb(event));
+
+	/* Did we just complete partial delivery and need to get
+	 * rolling again?  Move pending data to the receive
+	 * queue.
+	 */
+	if (clear_pd)
+		sctp_ulpq_clear_pd(ulpq);
 
-	wake_up_interruptible(sk->sleep);
+	if (queue == &sk->receive_queue)
+		wake_up_interruptible(sk->sleep);
 	return 1;
 
 out_free:
-	if (event->parent->list)
-		skb_queue_purge(event->parent->list);
+	if (sctp_event2skb(event)->list)
+		skb_queue_purge(sctp_event2skb(event)->list);
 	else
-		kfree_skb(event->parent);
+		kfree_skb(sctp_event2skb(event));
 	return 0;
 }
 
 /* 2nd Level Abstractions */
 
 /* Helper function to store chunks that need to be reassembled.  */
-static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq, 
+static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
 					 struct sctp_ulpevent *event)
 {
 	struct sk_buff *pos, *tmp;
@@ -202,7 +255,7 @@
 
 	/* Find the right place in this list. We store them by TSN.  */
 	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
-		cevent = (struct sctp_ulpevent *)pos->cb;
+		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
 		if (TSN_lt(tsn, ctsn))
@@ -211,9 +264,10 @@
 
 	/* If the queue is empty, we have a different function to call.  */
 	if (skb_peek(&ulpq->reasm))
-		__skb_insert(event->parent, pos->prev, pos, &ulpq->reasm);
+		__skb_insert(sctp_event2skb(event), pos->prev, pos,
+			     &ulpq->reasm);
 	else
-		__skb_queue_tail(&ulpq->reasm, event->parent);
+		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
 }
 
 /* Helper function to return an event corresponding to the reassembled
@@ -231,7 +285,10 @@
 	struct sk_buff *list = skb_shinfo(f_frag)->frag_list;
 
 	/* Store the pointer to the 2nd skb */
-	pos = f_frag->next;
+	if (f_frag == l_frag)
+		pos = NULL;
+	else
+		pos = f_frag->next;
 
 	/* Get the last skb in the f_frag's frag_list if present. */
 	for (last = list; list; last = list, list = list->next);
@@ -246,7 +303,8 @@
 
 	/* Remove the first fragment from the reassembly queue.  */
 	__skb_unlink(f_frag, f_frag->list);
-	do {
+	while (pos) {
+
 		pnext = pos->next;
 
 		/* Update the len and data_len fields of the first fragment. */
@@ -262,25 +320,27 @@
 
 		pos->next = pnext;
 		pos = pnext;
-	} while (1);
+	};
 
-	event = (sctp_ulpevent_t *) f_frag->cb;
+	event = sctp_skb2event(f_frag);
+	SCTP_INC_STATS(SctpReasmUsrMsgs);
 
 	return event;
 }
 
+
 /* Helper function to check if an incoming chunk has filled up the last
  * missing fragment in a SCTP datagram and return the corresponding event.
  */
-static inline sctp_ulpevent_t *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq)
+static inline struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ulpq)
 {
 	struct sk_buff *pos, *tmp;
-	sctp_ulpevent_t *cevent;
+	struct sctp_ulpevent *cevent;
 	struct sk_buff *first_frag = NULL;
 	__u32 ctsn, next_tsn;
-	sctp_ulpevent_t *retval = NULL;
+	struct sctp_ulpevent *retval = NULL;
 
-	/* Initialized to 0 just to avoid compiler warning message. Will
+	/* Initialized to 0 just to avoid compiler warning message.  Will
 	 * never be used with this value. It is referenced only after it
 	 * is set when we find the first fragment of a message.
 	 */
@@ -296,10 +356,10 @@
 	 * start the next pass when we find another first fragment.
 	 */
 	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
-		cevent = (sctp_ulpevent_t *) pos->cb;
+		cevent = sctp_skb2event(pos);
 		ctsn = cevent->sndrcvinfo.sinfo_tsn;
 
-		switch (cevent->chunk_flags & SCTP_DATA_FRAG_MASK) {
+		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
 		case SCTP_DATA_FIRST_FRAG:
 			first_frag = pos;
 			next_tsn = ctsn + 1;
@@ -313,7 +373,7 @@
 			break;
 
 		case SCTP_DATA_LAST_FRAG:
-			if ((first_frag) && (ctsn == next_tsn))
+			if (first_frag && (ctsn == next_tsn))
 				retval = sctp_make_reassembled_event(
 						first_frag, pos);
 			else
@@ -324,42 +384,170 @@
 		/* We have the reassembled event. There is no need to look
 		 * further.
 		 */
-		if (retval)
+		if (retval) {
+			retval->msg_flags |= MSG_EOR;
 			break;
+		}
 	}
 
 	return retval;
 }
 
-/* Helper function to reassemble chunks. Hold chunks on the reasm queue that
- * need reassembling.
- */
-static inline sctp_ulpevent_t *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
-						   sctp_ulpevent_t *event)
+/* Retrieve the next set of fragments of a partial message. */
+static inline struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq)
 {
-	sctp_ulpevent_t *retval = NULL;
+	struct sk_buff *pos, *tmp, *last_frag, *first_frag;
+	struct sctp_ulpevent *cevent;
+	__u32 ctsn, next_tsn;
+	int is_last;
+	struct sctp_ulpevent *retval;
+
+	/* The chunks are held in the reasm queue sorted by TSN.
+	 * Walk through the queue sequentially and look for the first
+	 * sequence of fragmented chunks.
+	 */
+
+	if (skb_queue_empty(&ulpq->reasm))
+		return NULL;
 
-	/* FIXME: We should be using some new chunk structure here
-	 * instead of carrying chunk fields in the event structure.
-	 * This is temporary as it is too painful to change everything
-	 * at once.
+	last_frag = first_frag = NULL;
+	retval = NULL;
+	next_tsn = 0;
+	is_last = 0;
+
+	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+		cevent = sctp_skb2event(pos);
+		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+
+		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
+		case SCTP_DATA_MIDDLE_FRAG:
+			if (!first_frag) {
+				first_frag = pos;
+				next_tsn = ctsn + 1;
+				last_frag = pos;
+			} else if (next_tsn == ctsn)
+				next_tsn++;
+			else
+				goto done;
+			break;
+		case SCTP_DATA_LAST_FRAG:
+			if (!first_frag)
+				first_frag = pos;
+			else if (ctsn != next_tsn)
+				goto done;
+			last_frag = pos;
+			is_last = 1;
+			goto done;
+		default:
+			return NULL;
+		};
+	}
+
+	/* We have the reassembled event. There is no need to look
+	 * further.
 	 */
+done:
+	retval = sctp_make_reassembled_event(first_frag, last_frag);
+	if (is_last)
+		retval->msg_flags |= MSG_EOR;
+
+	return retval;
+}
+
+
+/* Helper function to reassemble chunks.  Hold chunks on the reasm queue that
+ * need reassembling.
+ */
+static inline struct sctp_ulpevent *sctp_ulpq_reasm(struct sctp_ulpq *ulpq,
+						   struct sctp_ulpevent *event)
+{
+	struct sctp_ulpevent *retval = NULL;
 
 	/* Check if this is part of a fragmented message.  */
-	if (SCTP_DATA_NOT_FRAG == (event->chunk_flags & SCTP_DATA_FRAG_MASK))
+	if (SCTP_DATA_NOT_FRAG == (event->msg_flags & SCTP_DATA_FRAG_MASK)) {
+		event->msg_flags |= MSG_EOR;
 		return event;
+	}
 
 	sctp_ulpq_store_reasm(ulpq, event);
-	retval = sctp_ulpq_retrieve_reassembled(ulpq);
+	if (!ulpq->pd_mode)
+		retval = sctp_ulpq_retrieve_reassembled(ulpq);
+	else {
+		__u32 ctsn, ctsnap;
+
+		/* Do not even bother unless this is the next tsn to
+		 * be delivered.
+		 */
+		ctsn = event->sndrcvinfo.sinfo_tsn;
+		ctsnap = sctp_tsnmap_get_ctsn(&ulpq->asoc->peer.tsn_map);
+		if (TSN_lte(ctsn, ctsnap))
+			retval = sctp_ulpq_retrieve_partial(ulpq);
+	}
 
 	return retval;
 }
 
+/* Retrieve the first part (sequential fragments) for partial delivery.  */
+static inline struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq)
+{
+	struct sk_buff *pos, *tmp, *last_frag, *first_frag;
+	struct sctp_ulpevent *cevent;
+	__u32 ctsn, next_tsn;
+	struct sctp_ulpevent *retval;
+
+	/* The chunks are held in the reasm queue sorted by TSN.
+	 * Walk through the queue sequentially and look for a sequence of
+	 * fragmented chunks that start a datagram.
+	 */
+
+	if (skb_queue_empty(&ulpq->reasm))
+		return NULL;
+
+	last_frag = first_frag = NULL;
+	retval = NULL;
+	next_tsn = 0;
+
+	sctp_skb_for_each(pos, &ulpq->reasm, tmp) {
+		cevent = sctp_skb2event(pos);
+		ctsn = cevent->sndrcvinfo.sinfo_tsn;
+
+		switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
+		case SCTP_DATA_FIRST_FRAG:
+			if (!first_frag) {
+				first_frag = pos;
+				next_tsn = ctsn + 1;
+				last_frag = pos;
+			} else
+				goto done;
+			break;
+
+		case SCTP_DATA_MIDDLE_FRAG:
+			if (!first_frag)
+				return NULL;
+			if (ctsn == next_tsn) {
+				next_tsn++;
+				last_frag = pos;
+			} else
+				goto done;
+			break;
+		default:
+			return NULL;
+		};
+	}
+
+	/* We have the reassembled event. There is no need to look
+	 * further.
+	 */
+done:
+	retval = sctp_make_reassembled_event(first_frag, last_frag);
+	return retval;
+}
+
 /* Helper function to gather skbs that have possibly become
  * ordered by an an incoming chunk.
  */
 static inline void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
-					      sctp_ulpevent_t *event)
+					      struct sctp_ulpevent *event)
 {
 	struct sk_buff *pos, *tmp;
 	struct sctp_ulpevent *cevent;
@@ -373,7 +561,7 @@
 
 	/* We are holding the chunks by stream, by SSN.  */
 	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
-		cevent = (sctp_ulpevent_t *) pos->cb;
+		cevent = (struct sctp_ulpevent *) pos->cb;
 		csid = cevent->sndrcvinfo.sinfo_stream;
 		cssn = cevent->sndrcvinfo.sinfo_ssn;
 
@@ -390,32 +578,31 @@
 
 		/* Found it, so mark in the ssnmap. */
 		sctp_ssn_next(in, sid);
-	       
+
 		__skb_unlink(pos, pos->list);
 
 		/* Attach all gathered skbs to the event.  */
-		__skb_queue_tail(event->parent->list, pos);
+		__skb_queue_tail(sctp_event2skb(event)->list, pos);
 	}
 }
 
 /* Helper function to store chunks needing ordering.  */
 static inline void sctp_ulpq_store_ordered(struct sctp_ulpq *ulpq,
-					   sctp_ulpevent_t *event)
+					   struct sctp_ulpevent *event)
 {
 	struct sk_buff *pos, *tmp;
-	sctp_ulpevent_t *cevent;
+	struct sctp_ulpevent *cevent;
 	__u16 sid, csid;
 	__u16 ssn, cssn;
 
 	sid = event->sndrcvinfo.sinfo_stream;
 	ssn = event->sndrcvinfo.sinfo_ssn;
 
-
 	/* Find the right place in this list.  We store them by
 	 * stream ID and then by SSN.
 	 */
 	sctp_skb_for_each(pos, &ulpq->lobby, tmp) {
-		cevent = (sctp_ulpevent_t *) pos->cb;
+		cevent = (struct sctp_ulpevent *) pos->cb;
 		csid = cevent->sndrcvinfo.sinfo_stream;
 		cssn = cevent->sndrcvinfo.sinfo_ssn;
 
@@ -427,25 +614,20 @@
 
 	/* If the queue is empty, we have a different function to call.  */
 	if (skb_peek(&ulpq->lobby))
-		__skb_insert(event->parent, pos->prev, pos, &ulpq->lobby);
+		__skb_insert(sctp_event2skb(event), pos->prev, pos,
+			     &ulpq->lobby);
 	else
-		__skb_queue_tail(&ulpq->lobby, event->parent);
+		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
 }
 
-static inline sctp_ulpevent_t *sctp_ulpq_order(struct sctp_ulpq *ulpq,
-					       sctp_ulpevent_t *event)
+static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
+					struct sctp_ulpevent *event)
 {
 	__u16 sid, ssn;
 	struct sctp_stream *in;
 
-	/* FIXME: We should be using some new chunk structure here
-	 * instead of carrying chunk fields in the event structure.
-	 * This is temporary as it is too painful to change everything
-	 * at once.
-	 */
-
 	/* Check if this message needs ordering.  */
-	if (SCTP_DATA_UNORDERED & event->chunk_flags)
+	if (SCTP_DATA_UNORDERED & event->msg_flags)
 		return event;
 
 	/* Note: The stream ID must be verified before this routine.  */
@@ -472,3 +654,141 @@
 
 	return event;
 }
+
+/* Renege 'needed' bytes from the ordering queue. */
+static __u16 sctp_ulpq_renege_order(struct sctp_ulpq *ulpq, __u16 needed)
+{
+	__u16 freed = 0;
+	__u32 tsn;
+	struct sk_buff *skb;
+	struct sctp_ulpevent *event;
+	struct sctp_tsnmap *tsnmap;
+
+	tsnmap = &ulpq->asoc->peer.tsn_map;
+
+	while ((skb = __skb_dequeue_tail(&ulpq->lobby))) {
+		freed += skb_headlen(skb);
+		event = sctp_skb2event(skb);
+		tsn = event->sndrcvinfo.sinfo_tsn;
+
+		sctp_ulpevent_free(event);
+		sctp_tsnmap_renege(tsnmap, tsn);
+		if (freed >= needed)
+			return freed;
+	}
+
+	return freed;
+}
+
+/* Renege 'needed' bytes from the reassembly queue. */
+static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed)
+{
+	__u16 freed = 0;
+	__u32 tsn;
+	struct sk_buff *skb;
+	struct sctp_ulpevent *event;
+	struct sctp_tsnmap *tsnmap;
+
+	tsnmap = &ulpq->asoc->peer.tsn_map;
+
+	/* Walk backwards through the list, reneges the newest tsns. */
+	while ((skb = __skb_dequeue_tail(&ulpq->reasm))) {
+		freed += skb_headlen(skb);
+		event = sctp_skb2event(skb);
+		tsn = event->sndrcvinfo.sinfo_tsn;
+
+		sctp_ulpevent_free(event);
+		sctp_tsnmap_renege(tsnmap, tsn);
+		if (freed >= needed)
+			return freed;
+	}
+
+	return freed;
+}
+
+/* Partial deliver the first message as there is pressure on rwnd. */
+void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
+				struct sctp_chunk *chunk, int priority)
+{
+	struct sctp_ulpevent *event;
+	struct sctp_association *asoc;
+
+	asoc = ulpq->asoc;
+
+	/* Are we already in partial delivery mode?  */
+	if (!sctp_sk(asoc->base.sk)->pd_mode) {
+
+		/* Is partial delivery possible?  */
+		event = sctp_ulpq_retrieve_first(ulpq);
+		/* Send event to the ULP.   */
+		if (event) {
+			sctp_ulpq_tail_event(ulpq, event);
+			sctp_sk(asoc->base.sk)->pd_mode = 1;
+			ulpq->pd_mode = 1;
+			return;
+		}
+	}
+}
+
+/* Renege some packets to make room for an incoming chunk.  */
+void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
+		      int priority)
+{
+	struct sctp_association *asoc;
+	__u16 needed, freed;
+
+	asoc = ulpq->asoc;
+
+	if (chunk) {
+		needed = ntohs(chunk->chunk_hdr->length);
+		needed -= sizeof(sctp_data_chunk_t);
+	} else 
+		needed = SCTP_DEFAULT_MAXWINDOW;
+
+	freed = 0;
+
+	if (skb_queue_empty(&asoc->base.sk->receive_queue)) {
+		freed = sctp_ulpq_renege_order(ulpq, needed);
+		if (freed < needed) {
+			freed += sctp_ulpq_renege_frags(ulpq, needed - freed);
+		}
+	}
+	/* If able to free enough room, accept this chunk. */
+	if (chunk && (freed >= needed)) {
+		__u32 tsn;
+		tsn = ntohl(chunk->subh.data_hdr->tsn);
+		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
+		sctp_ulpq_tail_data(ulpq, chunk, priority);
+		
+		sctp_ulpq_partial_delivery(ulpq, chunk, priority);
+	}
+
+	return;
+}
+
+
+
+/* Notify the application if an association is aborted and in
+ * partial delivery mode.  Send up any pending received messages.
+ */
+void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
+{
+	struct sctp_ulpevent *ev = NULL;
+	struct sock *sk;
+
+	if (!ulpq->pd_mode)
+		return;
+
+	sk = ulpq->asoc->base.sk;
+	if (sctp_ulpevent_type_enabled(SCTP_PARTIAL_DELIVERY_EVENT,
+				       &sctp_sk(sk)->subscribe))
+		ev = sctp_ulpevent_make_pdapi(ulpq->asoc,
+					      SCTP_PARTIAL_DELIVERY_ABORTED,
+					      priority);
+	if (ev)
+		skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
+
+	/* If there is data waiting, send it up the socket now. */
+	if (sctp_ulpq_clear_pd(ulpq) || ev)
+		wake_up_interruptible(sk->sleep);
+}
diff -urN linux-2.5.63-bk6/sound/isa/opl3sa2.c linux-2.5.63-bk7/sound/isa/opl3sa2.c
--- linux-2.5.63-bk6/sound/isa/opl3sa2.c	Mon Feb 24 11:06:01 2003
+++ linux-2.5.63-bk7/sound/isa/opl3sa2.c	Mon Mar 31 12:20:18 2003
@@ -268,7 +268,7 @@
 		snd_printd("OPL3-SA [0x%lx] detect (1) = 0x%x (0x%x)\n", port, tmp, tmp1);
 		return -ENODEV;
 	}
-	/* try if the MIC register is accesible */
+	/* try if the MIC register is accessible */
 	tmp = snd_opl3sa2_read(chip, OPL3SA2_MIC);
 	snd_opl3sa2_write(chip, OPL3SA2_MIC, 0x8a);
 	if (((tmp1 = snd_opl3sa2_read(chip, OPL3SA2_MIC)) & 0x9f) != 0x8a) {
diff -urN linux-2.5.63-bk6/sound/pci/cs46xx/dsp_spos.h linux-2.5.63-bk7/sound/pci/cs46xx/dsp_spos.h
--- linux-2.5.63-bk6/sound/pci/cs46xx/dsp_spos.h	Mon Feb 24 11:05:05 2003
+++ linux-2.5.63-bk7/sound/pci/cs46xx/dsp_spos.h	Mon Mar 31 12:20:18 2003
@@ -173,7 +173,7 @@
 #define BG_INTERVAL_TIMER_PERIOD                0x0100
 
 
-/* Only SP accesible registers */
+/* Only SP accessible registers */
 #define SP_ASER_COUNTDOWN 0x8040
 #define SP_SPDOUT_FIFO    0x0108
 #define SP_SPDIN_MI_FIFO  0x01E0
