fresh diffs for linux-mips (26.3 cvs) and ebtables (15.3)
authorWaldemar Brodkorb <mail@waldemar-brodkorb.de>
Sat, 26 Mar 2005 11:09:35 +0000 (11:09 +0000)
committerWaldemar Brodkorb <mail@waldemar-brodkorb.de>
Sat, 26 Mar 2005 11:09:35 +0000 (11:09 +0000)
SVN-Revision: 461

openwrt/package/linux/kernel-patches/000-linux-mips-cvs
openwrt/package/linux/kernel-patches/302-ebtables

index dbd23de9738da5c159f8eccb81e5fa9a10a1b278..8a4a7d6ae4fbea431309c7df09d4ba6e89e58dc5 100644 (file)
-diff -Nur linux-2.4.29/Makefile linux-mips/Makefile
---- linux-2.4.29/Makefile      2005-01-19 15:10:14.000000000 +0100
-+++ linux-mips/Makefile        2005-01-20 03:19:21.000000000 +0100
-@@ -5,7 +5,7 @@
- KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
--ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
-+ARCH = mips
- KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
- CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
-@@ -462,10 +462,11 @@
-       $(MAKE) -C Documentation/DocBook mrproper
- distclean: mrproper
--      rm -f core `find . \( -not -type d \) -and \
--              \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
--              -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
--              -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
-+      find . \( -not -type d \) -and \
-+              \( -name core -o -name '*.orig' -o -name '*.rej' \
-+              -o -name '*~' -o -name '*.bak' -o -name '#*#' \
-+              -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \
-+              -o -name TAGS -o -name tags \) -print | env -i xargs rm -f
- backup: mrproper
-       cd .. && tar cf - linux/ | gzip -9 > backup.gz
-@@ -492,7 +493,7 @@
-       $(MAKE) -C Documentation/DocBook man
- sums:
--      find . -type f -print | sort | xargs sum > .SUMS
-+      find . -type f -print | sort | env -i xargs sum > .SUMS
- dep-files: scripts/mkdep archdep include/linux/version.h
-       rm -f .depend .hdepend
-diff -Nur linux-2.4.29/arch/mips/Makefile linux-mips/arch/mips/Makefile
---- linux-2.4.29/arch/mips/Makefile    2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/Makefile      2005-01-31 12:59:28.000000000 +0100
-@@ -211,7 +211,7 @@
- endif
- #
--# Au1000 (Alchemy Semi PB1000) eval board
-+# Au1x AMD Alchemy eval boards
- #
- ifdef CONFIG_MIPS_PB1000
- LIBS          += arch/mips/au1000/pb1000/pb1000.o \
-@@ -220,9 +220,6 @@
- LOADADDR      := 0x80100000
- endif
--#
--# Au1100 (Alchemy Semi PB1100) eval board
--#
- ifdef CONFIG_MIPS_PB1100
- LIBS          += arch/mips/au1000/pb1100/pb1100.o \
-                  arch/mips/au1000/common/au1000.o
-@@ -230,9 +227,6 @@
- LOADADDR      += 0x80100000
- endif
--#
--# Au1500 (Alchemy Semi PB1500) eval board
--#
- ifdef CONFIG_MIPS_PB1500
- LIBS          += arch/mips/au1000/pb1500/pb1500.o \
-                  arch/mips/au1000/common/au1000.o
-@@ -240,9 +234,6 @@
- LOADADDR      := 0x80100000
- endif
--#
--# Au1x00 (AMD/Alchemy) eval boards
--#
- ifdef CONFIG_MIPS_DB1000
- LIBS          += arch/mips/au1000/db1x00/db1x00.o \
-                  arch/mips/au1000/common/au1000.o
-@@ -313,6 +304,27 @@
- LOADADDR      += 0x80100000
- endif
+diff -Nur linux-2.4.29/arch/i386/kernel/acpi.c linux-mips/arch/i386/kernel/acpi.c
+--- linux-2.4.29/arch/i386/kernel/acpi.c       2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/arch/i386/kernel/acpi.c 2005-03-26 11:47:12.638577463 +0100
+@@ -55,6 +55,7 @@
+ acpi_interrupt_flags acpi_sci_flags __initdata;
+ int acpi_sci_override_gsi __initdata;
++int acpi_skip_timer_override __initdata;
+ /* --------------------------------------------------------------------------
+                               Boot-time Configuration
+    -------------------------------------------------------------------------- */
+@@ -320,6 +321,12 @@
+               return 0;
+       }
  
-+ifdef CONFIG_MIPS_PB1200
-+LIBS          += arch/mips/au1000/pb1200/pb1200.o \
-+                 arch/mips/au1000/common/au1000.o
-+SUBDIRS       += arch/mips/au1000/pb1200 arch/mips/au1000/common
-+LOADADDR      += 0x80100000
-+endif
-+
-+ifdef CONFIG_MIPS_DB1200
-+LIBS          += arch/mips/au1000/pb1200/pb1200.o \
-+                 arch/mips/au1000/common/au1000.o
-+SUBDIRS       += arch/mips/au1000/pb1200 arch/mips/au1000/common
-+LOADADDR      += 0x80100000
-+endif
-+
-+ifdef CONFIG_MIPS_FICMMP
-+LIBS          += arch/mips/au1000/ficmmp/ficmmp.o \
-+                 arch/mips/au1000/common/au1000.o
-+SUBDIRS       += arch/mips/au1000/ficmmp arch/mips/au1000/common
-+LOADADDR      += 0x80100000
-+endif
++      if (acpi_skip_timer_override &&
++              intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
++              printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
++              return 0;
++      }
 +
+       mp_override_legacy_irq (
+               intsrc->bus_irq,
+               intsrc->flags.polarity,
+@@ -433,6 +440,10 @@
+               return result;
+       }
  
- #
- # Cogent CSB250
-diff -Nur linux-2.4.29/arch/mips/au1000/common/Makefile linux-mips/arch/mips/au1000/common/Makefile
---- linux-2.4.29/arch/mips/au1000/common/Makefile      2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/common/Makefile        2005-01-31 12:59:30.000000000 +0100
-@@ -19,9 +19,9 @@
- export-objs           = prom.o clocks.o power.o usbdev.o
++#ifdef CONFIG_X86_IOAPIC
++      check_acpi_pci();
++#endif
++      
+       result = acpi_blacklisted();
+       if (result) {
+               printk(KERN_NOTICE PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
+diff -Nur linux-2.4.29/arch/i386/kernel/earlyquirk.c linux-mips/arch/i386/kernel/earlyquirk.c
+--- linux-2.4.29/arch/i386/kernel/earlyquirk.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/arch/i386/kernel/earlyquirk.c   2005-03-18 13:13:20.000000000 +0100
+@@ -0,0 +1,53 @@
++/* 
++ * Do early PCI probing for bug detection when the main PCI subsystem is 
++ * not up yet.
++ */
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <asm/pci-direct.h>
++#include <asm/acpi.h>
++
++#ifdef CONFIG_ACPI
++static int __init check_bridge(int vendor, int device) 
++{
++      /* According to Nvidia all timer overrides are bogus. Just ignore
++         them all. */
++      if (vendor == PCI_VENDOR_ID_NVIDIA) { 
++              acpi_skip_timer_override = 1;           
++      }
++      return 0;
++}
++   
++void __init check_acpi_pci(void) 
++{ 
++      int num,slot,func; 
++
++      /* Assume the machine supports type 1. If not it will 
++         always read ffffffff and should not have any side effect. */
++
++      /* Poor man's PCI discovery */
++      for (num = 0; num < 32; num++) { 
++              for (slot = 0; slot < 32; slot++) { 
++                      for (func = 0; func < 8; func++) { 
++                              u32 class;
++                              u32 vendor;
++                              class = read_pci_config(num,slot,func,
++                                                      PCI_CLASS_REVISION);
++                              if (class == 0xffffffff)
++                                      break; 
++
++                              if ((class >> 16) != PCI_CLASS_BRIDGE_PCI)
++                                      continue; 
++                              
++                              vendor = read_pci_config(num, slot, func, 
++                                                       PCI_VENDOR_ID);
++                              
++                              if (check_bridge(vendor&0xffff, vendor >> 16))
++                                      return; 
++                      } 
++                      
++              }
++      }
++}
++#endif /* CONFIG_ACPI */
+diff -Nur linux-2.4.29/arch/i386/kernel/Makefile linux-mips/arch/i386/kernel/Makefile
+--- linux-2.4.29/arch/i386/kernel/Makefile     2003-11-28 19:26:19.000000000 +0100
++++ linux-mips/arch/i386/kernel/Makefile       2005-03-26 11:47:12.567589113 +0100
+@@ -40,7 +40,7 @@
+ obj-$(CONFIG_ACPI_SLEEP)      += acpi_wakeup.o
+ obj-$(CONFIG_SMP)             += smp.o smpboot.o trampoline.o
+ obj-$(CONFIG_X86_LOCAL_APIC)  += mpparse.o apic.o nmi.o
+-obj-$(CONFIG_X86_IO_APIC)     += io_apic.o
++obj-$(CONFIG_X86_IO_APIC)     += io_apic.o earlyquirk.o
+ obj-$(CONFIG_X86_VISWS_APIC)  += visws_apic.o
+ obj-$(CONFIG_EDD)                     += edd.o
+diff -Nur linux-2.4.29/arch/i386/kernel/pci-irq.c linux-mips/arch/i386/kernel/pci-irq.c
+--- linux-2.4.29/arch/i386/kernel/pci-irq.c    2005-01-19 15:09:25.000000000 +0100
++++ linux-mips/arch/i386/kernel/pci-irq.c      2005-03-26 11:47:12.808549566 +0100
+@@ -1120,13 +1120,15 @@
+ void pcibios_enable_irq(struct pci_dev *dev)
+ {
+       u8 pin;
+-      extern int interrupt_line_quirk;
++      extern int via_interrupt_line_quirk;
+       struct pci_dev *temp_dev;
+       
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+               char *msg;
  
- obj-y := prom.o int-handler.o irq.o puts.o time.o reset.o cputable.o \
--      au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o
-+      au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o gpio.o
-   
--export-objs += dma.o dbdma.o
-+export-objs += dma.o dbdma.o gpio.o
++              pin--;          /* interrupt pins are numbered starting from 1 */
++
+               /* With IDE legacy devices the IRQ lookup failure is not a problem.. */
+               if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5))
+                       return;
+@@ -1134,46 +1136,43 @@
+               if (io_apic_assign_pci_irqs) {
+                       int irq;
+-                      if (pin) {
+-                              pin--;          /* interrupt pins are numbered starting from 1 */
+-                              irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
+-                              /*
+-                               * Busses behind bridges are typically not listed in the MP-table.
+-                               * In this case we have to look up the IRQ based on the parent bus,
+-                               * parent slot, and pin number. The SMP code detects such bridged
+-                               * busses itself so we should get into this branch reliably.
+-                               */
+-                              temp_dev = dev;
+-                              while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
+-                                      struct pci_dev * bridge = dev->bus->self;
++                      irq = IO_APIC_get_PCI_irq_vector(dev->bus->number, PCI_SLOT(dev->devfn), pin);
++                      /*
++                       * Busses behind bridges are typically not listed in the MP-table.
++                       * In this case we have to look up the IRQ based on the parent bus,
++                       * parent slot, and pin number. The SMP code detects such bridged
++                       * busses itself so we should get into this branch reliably.
++                       */
++                      temp_dev = dev;
++                      while (irq < 0 && dev->bus->parent) { /* go back to the bridge */
++                              struct pci_dev * bridge = dev->bus->self;
+-                                      pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+-                                      irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
+-                                                      PCI_SLOT(bridge->devfn), pin);
+-                                      if (irq >= 0)
+-                                              printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
+-                                                      bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
+-                                      dev = bridge;
+-                              }
+-                              dev = temp_dev;
+-                              if (irq >= 0) {
+-                                      printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+-                                              dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
+-                                      dev->irq = irq;
+-                                      return;
+-                              } else
+-                                      msg = " Probably buggy MP table.";
++                              pin = (pin + PCI_SLOT(dev->devfn)) % 4;
++                              irq = IO_APIC_get_PCI_irq_vector(bridge->bus->number, 
++                                              PCI_SLOT(bridge->devfn), pin);
++                              if (irq >= 0)
++                                      printk(KERN_WARNING "PCI: using PPB(B%d,I%d,P%d) to get irq %d\n", 
++                                              bridge->bus->number, PCI_SLOT(bridge->devfn), pin, irq);
++                              dev = bridge;
+                       }
++                      dev = temp_dev;
++                      if (irq >= 0) {
++                              printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
++                                      dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
++                              dev->irq = irq;
++                              return;
++                      } else
++                              msg = " Probably buggy MP table.";
+               } else if (pci_probe & PCI_BIOS_IRQ_SCAN)
+                       msg = "";
+               else
+                       msg = " Please try using pci=biosirq.";
+               printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
+-                     'A' + pin - 1, dev->slot_name, msg);
++                     'A' + pin, dev->slot_name, msg);
+       }
+       /* VIA bridges use interrupt line for apic/pci steering across
+          the V-Link */
+-      else if (interrupt_line_quirk)
++      else if (via_interrupt_line_quirk)
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq & 15);
+               
+ }
+diff -Nur linux-2.4.29/arch/i386/kernel/setup.c linux-mips/arch/i386/kernel/setup.c
+--- linux-2.4.29/arch/i386/kernel/setup.c      2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/arch/i386/kernel/setup.c        2005-03-26 11:47:12.810549238 +0100
+@@ -354,7 +354,8 @@
+ struct resource standard_io_resources[] = {
+       { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+       { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+-      { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
++      { "timer0", 0x40, 0x43, IORESOURCE_BUSY },
++      { "timer1", 0x50, 0x53, IORESOURCE_BUSY },
+       { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+       { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+       { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+diff -Nur linux-2.4.29/arch/i386/lib/usercopy.c linux-mips/arch/i386/lib/usercopy.c
+--- linux-2.4.29/arch/i386/lib/usercopy.c      2003-06-13 16:51:29.000000000 +0200
++++ linux-mips/arch/i386/lib/usercopy.c        2005-03-26 11:47:12.859541197 +0100
+@@ -14,6 +14,7 @@
+ unsigned long
+ __generic_copy_to_user(void *to, const void *from, unsigned long n)
+ {
++      BUG_ON((long) n < 0);
+       if (access_ok(VERIFY_WRITE, to, n))
+       {
+               if(n<512)
+@@ -27,6 +28,7 @@
+ unsigned long
+ __generic_copy_from_user(void *to, const void *from, unsigned long n)
+ {
++      BUG_ON((long) n < 0);
+       if (access_ok(VERIFY_READ, from, n))
+       {
+               if(n<512)
+@@ -44,6 +46,7 @@
+ unsigned long
+ __generic_copy_to_user(void *to, const void *from, unsigned long n)
+ {
++      BUG_ON((long) n < 0);
+       prefetch(from);
+       if (access_ok(VERIFY_WRITE, to, n))
+               __copy_user(to,from,n);
+@@ -53,6 +56,7 @@
+ unsigned long
+ __generic_copy_from_user(void *to, const void *from, unsigned long n)
+ {
++      BUG_ON((long) n < 0);
+       prefetchw(to);
+       if (access_ok(VERIFY_READ, from, n))
+               __copy_user_zeroing(to,from,n);
+diff -Nur linux-2.4.29/arch/ia64/ia32/sys_ia32.c linux-mips/arch/ia64/ia32/sys_ia32.c
+--- linux-2.4.29/arch/ia64/ia32/sys_ia32.c     2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/ia64/ia32/sys_ia32.c       2005-03-26 11:47:12.934528890 +0100
+@@ -1649,7 +1649,8 @@
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+ static void
+-cmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++cmsg32_recvmsg_fixup (struct msghdr *kmsg, unsigned long orig_cmsg_uptr,
++              __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -1683,6 +1684,9 @@
+                       goto fail2;
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -1812,6 +1816,7 @@
+       struct iovec *iov=iovstack;
+       struct msghdr msg_sys;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, iov_size, total_len, len;
+       struct scm_cookie scm;
+@@ -1856,6 +1861,7 @@
+       total_len=err;
+       cmsg_ptr = (unsigned long)msg_sys.msg_control;
++      cmsg_len = msg_sys.msg_controllen;
+       msg_sys.msg_flags = 0;
+       if (sock->file->f_flags & O_NONBLOCK)
+@@ -1882,7 +1888,8 @@
+                        * fix it up before we tack on more stuff.
+                        */
+                       if ((unsigned long) msg_sys.msg_control != cmsg_ptr)
+-                              cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr);
++                              cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr,
++                                              cmsg_len);
  
- obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
- obj-$(CONFIG_KGDB) += dbg_io.o
+                       /* Wheee... */
+                       if (sock->passcred)
 diff -Nur linux-2.4.29/arch/mips/au1000/common/au1xxx_irqmap.c linux-mips/arch/mips/au1000/common/au1xxx_irqmap.c
 --- linux-2.4.29/arch/mips/au1000/common/au1xxx_irqmap.c       2005-01-19 15:09:26.000000000 +0100
 +++ linux-mips/arch/mips/au1000/common/au1xxx_irqmap.c 2005-01-31 12:59:30.000000000 +0100
@@ -184,7 +357,7 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/cputable.c linux-mips/arch/mips/a
  
 diff -Nur linux-2.4.29/arch/mips/au1000/common/dbdma.c linux-mips/arch/mips/au1000/common/dbdma.c
 --- linux-2.4.29/arch/mips/au1000/common/dbdma.c       2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/common/dbdma.c 2005-02-12 04:05:28.000000000 +0100
++++ linux-mips/arch/mips/au1000/common/dbdma.c 2005-03-26 11:47:17.214826394 +0100
 @@ -41,6 +41,8 @@
  #include <asm/au1xxx_dbdma.h>
  #include <asm/system.h>
@@ -887,8 +1060,40 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/gpio.c linux-mips/arch/mips/au100
 +EXPORT_SYMBOL(au1xxx_gpio_read);
 diff -Nur linux-2.4.29/arch/mips/au1000/common/irq.c linux-mips/arch/mips/au1000/common/irq.c
 --- linux-2.4.29/arch/mips/au1000/common/irq.c 2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/common/irq.c   2005-01-31 12:59:30.000000000 +0100
-@@ -508,6 +508,7 @@
++++ linux-mips/arch/mips/au1000/common/irq.c   2005-03-26 11:47:17.215826230 +0100
+@@ -303,8 +303,30 @@
+ };
+ #ifdef CONFIG_PM
+-void startup_match20_interrupt(void)
++void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *))
+ {
++      static struct irqaction action;
++      /* This is a big problem.... since we didn't use request_irq
++         when kernel/irq.c calls probe_irq_xxx this interrupt will
++         be probed for usage. This will end up disabling the device :(
++
++       Give it a bogus "action" pointer -- this will keep it from
++         getting auto-probed!
++
++       By setting the status to match that of request_irq() we
++       can avoid it.  --cgray
++      */
++      action.dev_id = handler;
++      action.flags = 0;
++      action.mask = 0;
++      action.name = "Au1xxx TOY";
++      action.handler = handler;
++      action.next = NULL;
++
++      irq_desc[AU1000_TOY_MATCH2_INT].action = &action; 
++      irq_desc[AU1000_TOY_MATCH2_INT].status 
++               &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
++
+       local_enable_irq(AU1000_TOY_MATCH2_INT);
+ }
+ #endif
+@@ -508,6 +530,7 @@
  
        if (!intc0_req0) return;
  
@@ -896,7 +1101,7 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/irq.c linux-mips/arch/mips/au1000
        /*
         * Because of the tight timing of SETUP token to reply
         * transactions, the USB devices-side packet complete
-@@ -518,6 +519,7 @@
+@@ -518,6 +541,7 @@
                do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
                return;
        }
@@ -904,6 +1109,40 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/irq.c linux-mips/arch/mips/au1000
  
        irq = au_ffs(intc0_req0) - 1;
        intc0_req0 &= ~(1<<irq);
+@@ -536,17 +560,7 @@
+       irq = au_ffs(intc0_req1) - 1;
+       intc0_req1 &= ~(1<<irq);
+-#ifdef CONFIG_PM
+-      if (irq == AU1000_TOY_MATCH2_INT) {
+-              mask_and_ack_rise_edge_irq(irq);
+-              counter0_irq(irq, NULL, regs);
+-              local_enable_irq(irq);
+-      }
+-      else
+-#endif
+-      {
+-              do_IRQ(irq, regs);
+-      }
++      do_IRQ(irq, regs);
+ }
+diff -Nur linux-2.4.29/arch/mips/au1000/common/Makefile linux-mips/arch/mips/au1000/common/Makefile
+--- linux-2.4.29/arch/mips/au1000/common/Makefile      2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/common/Makefile        2005-01-31 12:59:30.000000000 +0100
+@@ -19,9 +19,9 @@
+ export-objs           = prom.o clocks.o power.o usbdev.o
+ obj-y := prom.o int-handler.o irq.o puts.o time.o reset.o cputable.o \
+-      au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o
++      au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o gpio.o
+   
+-export-objs += dma.o dbdma.o
++export-objs += dma.o dbdma.o gpio.o
+ obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
+ obj-$(CONFIG_KGDB) += dbg_io.o
 diff -Nur linux-2.4.29/arch/mips/au1000/common/pci_fixup.c linux-mips/arch/mips/au1000/common/pci_fixup.c
 --- linux-2.4.29/arch/mips/au1000/common/pci_fixup.c   2005-01-19 15:09:26.000000000 +0100
 +++ linux-mips/arch/mips/au1000/common/pci_fixup.c     2004-12-03 09:00:32.000000000 +0100
@@ -925,7 +1164,7 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/pci_fixup.c linux-mips/arch/mips/
  
 diff -Nur linux-2.4.29/arch/mips/au1000/common/pci_ops.c linux-mips/arch/mips/au1000/common/pci_ops.c
 --- linux-2.4.29/arch/mips/au1000/common/pci_ops.c     2004-02-18 14:36:30.000000000 +0100
-+++ linux-mips/arch/mips/au1000/common/pci_ops.c       2005-01-31 12:59:30.000000000 +0100
++++ linux-mips/arch/mips/au1000/common/pci_ops.c       2005-03-26 11:47:17.258819174 +0100
 @@ -162,6 +162,7 @@
  static int config_access(unsigned char access_type, struct pci_dev *dev, 
                         unsigned char where, u32 * data)
@@ -942,7 +1181,19 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/pci_ops.c linux-mips/arch/mips/au
        unsigned long entryLo0, entryLo1;
  
        if (device > 19) {
-@@ -271,8 +271,11 @@
+@@ -205,9 +205,8 @@
+               last_entryLo0  = last_entryLo1 = 0xffffffff;
+       }
+-      /* Since the Au1xxx doesn't do the idsel timing exactly to spec,
+-       * many board vendors implement their own off-chip idsel, so call
+-       * it now.  If it doesn't succeed, may as well bail out at this point.
++      /* Allow board vendors to implement their own off-chip idsel.  
++       * If it doesn't succeed, may as well bail out at this point.
+        */
+       if (board_pci_idsel) {
+               if (board_pci_idsel(device, 1) == 0) {
+@@ -271,8 +270,11 @@
        }
  
        local_irq_restore(flags);
@@ -1168,6 +1419,89 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/power.c linux-mips/arch/mips/au10
        {0}
  };
  
+diff -Nur linux-2.4.29/arch/mips/au1000/common/reset.c linux-mips/arch/mips/au1000/common/reset.c
+--- linux-2.4.29/arch/mips/au1000/common/reset.c       2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/common/reset.c 2005-03-26 11:47:17.264818189 +0100
+@@ -37,8 +37,6 @@
+ #include <asm/system.h>
+ #include <asm/au1000.h>
+-extern int au_sleep(void);
+-
+ void au1000_restart(char *command)
+ {
+       /* Set all integrated peripherals to disabled states */
+@@ -144,6 +142,26 @@
+               au_writel(0x00, 0xb1900064); /* sys_auxpll */
+               au_writel(0x00, 0xb1900100); /* sys_pininputen */
+               break;
++      case 0x04000000: /* Au1200 */
++              au_writel(0x00, 0xb400300c); /* ddma */
++              au_writel(0x00, 0xb1a00004); /* psc 0 */
++              au_writel(0x00, 0xb1b00004); /* psc 1 */
++              au_writel(0x00d02000, 0xb4020004); /* ehci, ohci, udc, otg */
++              au_writel(0x00, 0xb5000004); /* lcd */
++              au_writel(0x00, 0xb060000c); /* sd0 */
++              au_writel(0x00, 0xb068000c); /* sd1 */
++              au_writel(0x00, 0xb1100100); /* swcnt */
++              au_writel(0x00, 0xb0300000); /* aes */
++              au_writel(0x00, 0xb4004000); /* cim */
++              au_writel(0x00, 0xb1100100); /* uart0_enable */
++              au_writel(0x00, 0xb1200100); /* uart1_enable */
++              au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
++              au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
++              au_writel(0x00, 0xb1900028); /* sys_clksrc */
++              au_writel(0x10, 0xb1900060); /* sys_cpupll */
++              au_writel(0x00, 0xb1900064); /* sys_auxpll */
++              au_writel(0x00, 0xb1900100); /* sys_pininputen */
++              break;
+       default:
+               break;
+@@ -163,32 +181,23 @@
+ void au1000_halt(void)
+ {
+-#if defined(CONFIG_MIPS_PB1550)
+-      /* power off system */
+-      printk("\n** Powering off Pb1550\n");
+-      au_writew(au_readw(0xAF00001C) | (3<<14), 0xAF00001C); 
+-      au_sync();
+-      while(1); /* should not get here */
+-#endif
+-      printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+-#ifdef CONFIG_MIPS_MIRAGE
+-      au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT);
+-#endif
+-#ifdef CONFIG_PM
+-      au_sleep();
+-
+-      /* should not get here */
+-      printk(KERN_ERR "Unable to put cpu in sleep mode\n");
+-      while(1);
+-#else
+-      while (1)
++      /* Use WAIT in a low-power infinite spin loop */
++      while (1) {
+               __asm__(".set\tmips3\n\t"
+                       "wait\n\t"
+                       ".set\tmips0");
+-#endif
++      }
+ }
+ void au1000_power_off(void)
+ {
++      extern void board_power_off (void);
++
++      printk(KERN_NOTICE "\n** You can safely turn off the power\n");
++
++      /* Give board a chance to power-off */
++      board_power_off();
++
++      /* If board can't power-off, spin forever */
+       au1000_halt();
+ }
 diff -Nur linux-2.4.29/arch/mips/au1000/common/setup.c linux-mips/arch/mips/au1000/common/setup.c
 --- linux-2.4.29/arch/mips/au1000/common/setup.c       2005-01-19 15:09:26.000000000 +0100
 +++ linux-mips/arch/mips/au1000/common/setup.c 2005-01-31 12:59:30.000000000 +0100
@@ -1538,8 +1872,25 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/sleeper.S linux-mips/arch/mips/au
 +
 diff -Nur linux-2.4.29/arch/mips/au1000/common/time.c linux-mips/arch/mips/au1000/common/time.c
 --- linux-2.4.29/arch/mips/au1000/common/time.c        2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/common/time.c  2005-01-31 12:59:30.000000000 +0100
-@@ -437,9 +437,6 @@
++++ linux-mips/arch/mips/au1000/common/time.c  2005-03-26 11:47:17.265818025 +0100
+@@ -50,7 +50,6 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/timex.h>
+-extern void startup_match20_interrupt(void);
+ extern void do_softirq(void);
+ extern volatile unsigned long wall_jiffies;
+ unsigned long missed_heart_beats = 0;
+@@ -66,7 +65,7 @@
+ #ifdef CONFIG_PM
+ #define MATCH20_INC 328
+-extern void startup_match20_interrupt(void);
++extern void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *));
+ static unsigned long last_pc0, last_match20;
+ #endif
+@@ -437,9 +436,6 @@
                au_writel(0, SYS_TOYWRITE);
                while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
  
@@ -1549,24 +1900,18 @@ diff -Nur linux-2.4.29/arch/mips/au1000/common/time.c linux-mips/arch/mips/au100
                while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
  
                /* setup match20 to interrupt once every 10ms */
-diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/Makefile linux-mips/arch/mips/au1000/db1x00/Makefile
---- linux-2.4.29/arch/mips/au1000/db1x00/Makefile      2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/db1x00/Makefile        2005-01-31 12:59:30.000000000 +0100
-@@ -17,4 +17,11 @@
- obj-y := init.o board_setup.o irqmap.o
- obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o
+@@ -447,7 +443,7 @@
+               au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
+               au_sync();
+               while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+-              startup_match20_interrupt();
++              startup_match20_interrupt(counter0_irq);
+               do_gettimeoffset = do_fast_pm_gettimeoffset;
  
-+ifdef CONFIG_MIPS_DB1100
-+ifdef CONFIG_MMC
-+obj-y += mmc_support.o
-+export-objs += mmc_support.o
-+endif
-+endif
-+
- include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/board_setup.c linux-mips/arch/mips/au1000/db1x00/board_setup.c
 --- linux-2.4.29/arch/mips/au1000/db1x00/board_setup.c 2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/db1x00/board_setup.c   2005-01-31 12:59:30.000000000 +0100
++++ linux-mips/arch/mips/au1000/db1x00/board_setup.c   2005-03-26 11:47:17.271817041 +0100
 @@ -46,10 +46,22 @@
  #include <asm/au1000.h>
  #include <asm/db1x00.h>
@@ -1593,7 +1938,21 @@ diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/board_setup.c linux-mips/arch/mip
  
  void board_reset (void)
  {
-@@ -108,8 +120,42 @@
+@@ -57,6 +69,13 @@
+       au_writel(0x00000000, 0xAE00001C);
+ }
++void board_power_off (void)
++{
++#ifdef CONFIG_MIPS_MIRAGE
++      au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT);
++#endif
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func;
+@@ -108,8 +127,42 @@
        au_writel(0x02000200, GPIO2_OUTPUT);
  #endif
  
@@ -1647,13 +2006,28 @@ diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/irqmap.c linux-mips/arch/mips/au1
  #else
        { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 Fully_Interted#
        { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 STSCHG#
-diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/mmc_support.c linux-mips/arch/mips/au1000/db1x00/mmc_support.c
---- linux-2.4.29/arch/mips/au1000/db1x00/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/au1000/db1x00/mmc_support.c   2005-01-30 09:07:01.000000000 +0100
-@@ -0,0 +1,126 @@
-+/*
-+ * BRIEF MODULE DESCRIPTION
-+ *
+diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/Makefile linux-mips/arch/mips/au1000/db1x00/Makefile
+--- linux-2.4.29/arch/mips/au1000/db1x00/Makefile      2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/db1x00/Makefile        2005-01-31 12:59:30.000000000 +0100
+@@ -17,4 +17,11 @@
+ obj-y := init.o board_setup.o irqmap.o
+ obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o
++ifdef CONFIG_MIPS_DB1100
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs += mmc_support.o
++endif
++endif
++
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/mmc_support.c linux-mips/arch/mips/au1000/db1x00/mmc_support.c
+--- linux-2.4.29/arch/mips/au1000/db1x00/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/arch/mips/au1000/db1x00/mmc_support.c   2005-01-30 09:07:01.000000000 +0100
+@@ -0,0 +1,126 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *
 + *    MMC support routines for DB1100.
 + *
 + *
@@ -1777,35 +2151,6 @@ diff -Nur linux-2.4.29/arch/mips/au1000/db1x00/mmc_support.c linux-mips/arch/mip
 +EXPORT_SYMBOL(mmc_power_on);
 +EXPORT_SYMBOL(mmc_power_off);
 +
-diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/Makefile linux-mips/arch/mips/au1000/ficmmp/Makefile
---- linux-2.4.29/arch/mips/au1000/ficmmp/Makefile      1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/au1000/ficmmp/Makefile        2005-01-30 09:01:27.000000000 +0100
-@@ -0,0 +1,25 @@
-+#
-+#  Copyright 2000 MontaVista Software Inc.
-+#  Author: MontaVista Software, Inc.
-+#             ppopov@mvista.com or source@mvista.com
-+#
-+# Makefile for the Alchemy Semiconductor FIC board.
-+#
-+# Note! Dependencies are done automagically by 'make dep', which also
-+# removes any old dependencies. DON'T put your own dependencies here
-+# unless it's something special (ie not a .c file).
-+#
-+
-+USE_STANDARD_AS_RULE := true
-+
-+O_TARGET := ficmmp.o
-+
-+obj-y := init.o board_setup.o irqmap.o au1200_ibutton.o au1xxx_dock.o
-+
-+ifdef CONFIG_MMC
-+obj-y += mmc_support.o
-+export-objs +=mmc_support.o
-+endif
-+
-+
-+include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/au1200_ibutton.c linux-mips/arch/mips/au1000/ficmmp/au1200_ibutton.c
 --- linux-2.4.29/arch/mips/au1000/ficmmp/au1200_ibutton.c      1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/arch/mips/au1000/ficmmp/au1200_ibutton.c        2005-02-03 07:35:29.000000000 +0100
@@ -2347,8 +2692,8 @@ diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/au1xxx_dock.c linux-mips/arch/mip
 +module_exit(au1xxx_dock_exit);
 diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/board_setup.c linux-mips/arch/mips/au1000/ficmmp/board_setup.c
 --- linux-2.4.29/arch/mips/au1000/ficmmp/board_setup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/au1000/ficmmp/board_setup.c   2005-01-30 09:01:27.000000000 +0100
-@@ -0,0 +1,191 @@
++++ linux-mips/arch/mips/au1000/ficmmp/board_setup.c   2005-03-19 08:17:51.000000000 +0100
+@@ -0,0 +1,226 @@
 +/*
 + *
 + * BRIEF MODULE DESCRIPTION
@@ -2425,6 +2770,10 @@ diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/board_setup.c linux-mips/arch/mip
 +      au_writel(0, 0xAD80001C);
 +}
 +
++void board_power_off (void)
++{
++}
++
 +void __init board_setup(void)
 +{
 +      char *argptr = NULL;
@@ -2485,7 +2834,7 @@ diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/board_setup.c linux-mips/arch/mip
 +
 +#ifdef CONFIG_FB_AU1200
 +      argptr = prom_getcmdline();
-+      strcat(argptr, " video=au1200fb:panel:s11");
++      strcat(argptr, " video=au1200fb:");
 +#endif
 +
 +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
@@ -2540,6 +2889,37 @@ diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/board_setup.c linux-mips/arch/mip
 +      printk("B190002C: %X\n", *((volatile u32*)0xB190002C));
 +}
 +
++int
++board_au1200fb_panel (void)
++{
++      au1xxx_gpio_tristate(6);
++
++      if (au1xxx_gpio_read(12) == 0)
++              return 9; /* FS453_640x480 (Composite/S-Video) */
++      else
++              return 7; /* Sharp 320x240 TFT */
++}
++
++int
++board_au1200fb_panel_init (void)
++{
++      /*Enable data buffers*/
++      ficmmp_config_clear(FICMMP_CONFIG_LCMDATAOUT);
++      /*Take LCD out of reset*/
++      ficmmp_config_set(FICMMP_CONFIG_LCMPWREN | FICMMP_CONFIG_LCMEN);
++      return 0;
++}
++
++int 
++board_au1200fb_panel_shutdown (void)
++{
++      /*Disable data buffers*/
++      ficmmp_config_set(FICMMP_CONFIG_LCMDATAOUT);
++      /*Put LCD in reset, remove power*/
++      ficmmp_config_clear(FICMMP_CONFIG_LCMEN | FICMMP_CONFIG_LCMPWREN);
++      return 0;
++}
++
 diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/init.c linux-mips/arch/mips/au1000/ficmmp/init.c
 --- linux-2.4.29/arch/mips/au1000/ficmmp/init.c        1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/arch/mips/au1000/ficmmp/init.c  2005-01-30 09:01:27.000000000 +0100
@@ -2685,26 +3065,49 @@ diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/irqmap.c linux-mips/arch/mips/au1
 +
 +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
 +
-diff -Nur linux-2.4.29/arch/mips/au1000/hydrogen3/Makefile linux-mips/arch/mips/au1000/hydrogen3/Makefile
---- linux-2.4.29/arch/mips/au1000/hydrogen3/Makefile   2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/hydrogen3/Makefile     2005-02-12 04:05:28.000000000 +0100
-@@ -14,6 +14,11 @@
- O_TARGET := hydrogen3.o
--obj-y := init.o board_setup.o irqmap.o
-+obj-y := init.o board_setup.o irqmap.o buttons.o
+diff -Nur linux-2.4.29/arch/mips/au1000/ficmmp/Makefile linux-mips/arch/mips/au1000/ficmmp/Makefile
+--- linux-2.4.29/arch/mips/au1000/ficmmp/Makefile      1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/arch/mips/au1000/ficmmp/Makefile        2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,25 @@
++#
++#  Copyright 2000 MontaVista Software Inc.
++#  Author: MontaVista Software, Inc.
++#             ppopov@mvista.com or source@mvista.com
++#
++# Makefile for the Alchemy Semiconductor FIC board.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET := ficmmp.o
++
++obj-y := init.o board_setup.o irqmap.o au1200_ibutton.o au1xxx_dock.o
 +
 +ifdef CONFIG_MMC
 +obj-y += mmc_support.o
 +export-objs +=mmc_support.o
 +endif
- include $(TOPDIR)/Rules.make
++
++
++include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/hydrogen3/board_setup.c linux-mips/arch/mips/au1000/hydrogen3/board_setup.c
 --- linux-2.4.29/arch/mips/au1000/hydrogen3/board_setup.c      2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/hydrogen3/board_setup.c        2005-01-31 12:59:30.000000000 +0100
-@@ -57,6 +57,9 @@
++++ linux-mips/arch/mips/au1000/hydrogen3/board_setup.c        2005-03-26 11:47:17.377799647 +0100
+@@ -51,12 +51,19 @@
+ {
+ }
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func;
  
        rtc_ops = &no_rtc_ops;
  
@@ -3026,6 +3429,22 @@ diff -Nur linux-2.4.29/arch/mips/au1000/hydrogen3/buttons.c linux-mips/arch/mips
 +
 +module_init(hydrogen3_buttons_init);
 +module_exit(hydrogen3_buttons_exit);
+diff -Nur linux-2.4.29/arch/mips/au1000/hydrogen3/Makefile linux-mips/arch/mips/au1000/hydrogen3/Makefile
+--- linux-2.4.29/arch/mips/au1000/hydrogen3/Makefile   2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/hydrogen3/Makefile     2005-03-26 11:47:17.372800467 +0100
+@@ -14,6 +14,11 @@
+ O_TARGET := hydrogen3.o
+-obj-y := init.o board_setup.o irqmap.o
++obj-y := init.o board_setup.o irqmap.o buttons.o
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs +=mmc_support.o
++endif
+ include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/hydrogen3/mmc_support.c linux-mips/arch/mips/au1000/hydrogen3/mmc_support.c
 --- linux-2.4.29/arch/mips/au1000/hydrogen3/mmc_support.c      1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/arch/mips/au1000/hydrogen3/mmc_support.c        2005-02-02 05:27:06.000000000 +0100
@@ -3153,6 +3572,34 @@ diff -Nur linux-2.4.29/arch/mips/au1000/mtx-1/irqmap.c linux-mips/arch/mips/au10
        };
        const long min_idsel = 0, max_idsel = 3, irqs_per_slot = 4;
        return PCI_IRQ_TABLE_LOOKUP;
+diff -Nur linux-2.4.29/arch/mips/au1000/pb1000/board_setup.c linux-mips/arch/mips/au1000/pb1000/board_setup.c
+--- linux-2.4.29/arch/mips/au1000/pb1000/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/pb1000/board_setup.c   2005-03-26 11:47:17.413793739 +0100
+@@ -58,6 +58,10 @@
+ {
+ }
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func, static_cfg0;
+diff -Nur linux-2.4.29/arch/mips/au1000/pb1100/board_setup.c linux-mips/arch/mips/au1000/pb1100/board_setup.c
+--- linux-2.4.29/arch/mips/au1000/pb1100/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/pb1100/board_setup.c   2005-03-26 11:47:17.418792919 +0100
+@@ -62,6 +62,10 @@
+     au_writel(0x00000000, 0xAE00001C);
+ }
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func;
 diff -Nur linux-2.4.29/arch/mips/au1000/pb1100/Makefile linux-mips/arch/mips/au1000/pb1100/Makefile
 --- linux-2.4.29/arch/mips/au1000/pb1100/Makefile      2003-08-25 13:44:39.000000000 +0200
 +++ linux-mips/arch/mips/au1000/pb1100/Makefile        2005-01-31 12:59:30.000000000 +0100
@@ -3297,39 +3744,10 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1100/mmc_support.c linux-mips/arch/mip
 +EXPORT_SYMBOL(mmc_power_on);
 +EXPORT_SYMBOL(mmc_power_off);
 +
-diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/Makefile linux-mips/arch/mips/au1000/pb1200/Makefile
---- linux-2.4.29/arch/mips/au1000/pb1200/Makefile      1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/au1000/pb1200/Makefile        2005-01-30 09:01:27.000000000 +0100
-@@ -0,0 +1,25 @@
-+#
-+#  Copyright 2000 MontaVista Software Inc.
-+#  Author: MontaVista Software, Inc.
-+#             ppopov@mvista.com or source@mvista.com
-+#
-+# Makefile for the Alchemy Semiconductor PB1000 board.
-+#
-+# Note! Dependencies are done automagically by 'make dep', which also
-+# removes any old dependencies. DON'T put your own dependencies here
-+# unless it's something special (ie not a .c file).
-+#
-+
-+USE_STANDARD_AS_RULE := true
-+
-+O_TARGET := pb1200.o
-+
-+obj-y := init.o board_setup.o irqmap.o
-+
-+ifdef CONFIG_MMC
-+obj-y += mmc_support.o
-+export-objs +=mmc_support.o
-+endif
-+
-+
-+include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/board_setup.c linux-mips/arch/mips/au1000/pb1200/board_setup.c
 --- linux-2.4.29/arch/mips/au1000/pb1200/board_setup.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/au1000/pb1200/board_setup.c   2005-01-30 09:01:28.000000000 +0100
-@@ -0,0 +1,190 @@
++++ linux-mips/arch/mips/au1000/pb1200/board_setup.c   2005-03-19 08:17:51.000000000 +0100
+@@ -0,0 +1,221 @@
 +/*
 + *
 + * BRIEF MODULE DESCRIPTION
@@ -3413,6 +3831,11 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/board_setup.c linux-mips/arch/mip
 +      bcsr->resets = 0;
 +}
 +
++void board_power_off (void)
++{
++      bcsr->resets = 0xC000;
++}
++
 +void __init board_setup(void)
 +{
 +      char *argptr = NULL;
@@ -3471,12 +3894,7 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/board_setup.c linux-mips/arch/mip
 +
 +#ifdef CONFIG_FB_AU1200
 +      argptr = prom_getcmdline();
-+#ifdef CONFIG_MIPS_PB1200
-+      strcat(argptr, " video=au1200fb:panel:s11");
-+#endif
-+#ifdef CONFIG_MIPS_DB1200
-+      strcat(argptr, " video=au1200fb:panel:s7");
-+#endif
++      strcat(argptr, " video=au1200fb:");
 +#endif
 +
 +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
@@ -3520,6 +3938,37 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/board_setup.c linux-mips/arch/mip
 +              board_init_irq = _board_init_irq;
 +      }
 +}
++
++int
++board_au1200fb_panel (void)
++{
++      BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++      int p;
++
++      p = bcsr->switches;
++      p >>= 8;
++      p &= 0x0F;
++      return p;
++}
++
++int
++board_au1200fb_panel_init (void)
++{
++      /* Apply power */
++    BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++      bcsr->board |= (BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
++      return 0;
++}
++
++int
++board_au1200fb_panel_shutdown (void)
++{
++      /* Remove power */
++    BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++      bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
++      return 0;
++}
++
 diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/init.c linux-mips/arch/mips/au1000/pb1200/init.c
 --- linux-2.4.29/arch/mips/au1000/pb1200/init.c        1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/arch/mips/au1000/pb1200/init.c  2005-01-30 09:01:28.000000000 +0100
@@ -3780,6 +4229,35 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/irqmap.c linux-mips/arch/mips/au1
 +      request of any source attached to the cascade */
 +}
 +
+diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/Makefile linux-mips/arch/mips/au1000/pb1200/Makefile
+--- linux-2.4.29/arch/mips/au1000/pb1200/Makefile      1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/arch/mips/au1000/pb1200/Makefile        2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,25 @@
++#
++#  Copyright 2000 MontaVista Software Inc.
++#  Author: MontaVista Software, Inc.
++#             ppopov@mvista.com or source@mvista.com
++#
++# Makefile for the Alchemy Semiconductor PB1000 board.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET := pb1200.o
++
++obj-y := init.o board_setup.o irqmap.o
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs +=mmc_support.o
++endif
++
++
++include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/mmc_support.c linux-mips/arch/mips/au1000/pb1200/mmc_support.c
 --- linux-2.4.29/arch/mips/au1000/pb1200/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/arch/mips/au1000/pb1200/mmc_support.c   2005-01-30 09:01:28.000000000 +0100
@@ -3925,10 +4403,24 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1200/mmc_support.c linux-mips/arch/mip
 +EXPORT_SYMBOL(mmc_power_on);
 +EXPORT_SYMBOL(mmc_power_off);
 +
+diff -Nur linux-2.4.29/arch/mips/au1000/pb1500/board_setup.c linux-mips/arch/mips/au1000/pb1500/board_setup.c
+--- linux-2.4.29/arch/mips/au1000/pb1500/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/au1000/pb1500/board_setup.c   2005-03-26 11:47:17.496780119 +0100
+@@ -62,6 +62,10 @@
+     au_writel(0x00000000, 0xAE00001C);
+ }
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func;
 diff -Nur linux-2.4.29/arch/mips/au1000/pb1550/board_setup.c linux-mips/arch/mips/au1000/pb1550/board_setup.c
 --- linux-2.4.29/arch/mips/au1000/pb1550/board_setup.c 2005-01-19 15:09:26.000000000 +0100
-+++ linux-mips/arch/mips/au1000/pb1550/board_setup.c   2005-01-31 12:59:30.000000000 +0100
-@@ -48,6 +48,16 @@
++++ linux-mips/arch/mips/au1000/pb1550/board_setup.c   2005-03-26 11:47:17.496780119 +0100
+@@ -48,12 +48,31 @@
  
  extern struct rtc_ops no_rtc_ops;
  
@@ -3945,7 +4437,22 @@ diff -Nur linux-2.4.29/arch/mips/au1000/pb1550/board_setup.c linux-mips/arch/mip
  void board_reset (void)
  {
      /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
-@@ -78,5 +88,36 @@
+       au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C);
+ }
++void board_power_off (void)
++{
++      /* power off system */
++      printk("\n** Powering off Pb1550\n");
++      au_writew(au_readw(0xAF00001C) | (3<<14), 0xAF00001C); 
++      au_sync();
++      while(1); /* should not get here */
++}
++
+ void __init board_setup(void)
+ {
+       u32 pin_func;
+@@ -78,5 +97,36 @@
        au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
        au_sync();
  
@@ -4120,11 +4627,21 @@ diff -Nur linux-2.4.29/arch/mips/config-shared.in linux-mips/arch/mips/config-sh
       "$CONFIG_NINO" = "y" -o \
 diff -Nur linux-2.4.29/arch/mips/defconfig linux-mips/arch/mips/defconfig
 --- linux-2.4.29/arch/mips/defconfig   2005-01-19 15:09:27.000000000 +0100
-+++ linux-mips/arch/mips/defconfig     2005-01-09 20:33:59.000000000 +0100
-@@ -235,11 +235,6 @@
- #
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
++++ linux-mips/arch/mips/defconfig     2005-03-26 11:47:13.509434535 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -235,11 +235,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
 -
 -#
 -# Appletalk devices
@@ -4133,7 +4650,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -319,6 +314,7 @@
+@@ -319,9 +314,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -4141,9 +4658,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig linux-mips/arch/mips/defconfig
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -465,7 +462,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-atlas linux-mips/arch/mips/defconfig-atlas
 --- linux-2.4.29/arch/mips/defconfig-atlas     2005-01-19 15:09:27.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-atlas       2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-atlas       2005-03-26 11:47:13.579423048 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -235,11 +235,6 @@
  #
  # CONFIG_IPX is not set
@@ -4156,7 +4695,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-atlas linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -317,6 +312,7 @@
+@@ -317,9 +312,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -4164,10 +4703,50 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-atlas linux-mips/arch/mips/defconfig-
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -528,7 +525,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-bosporus linux-mips/arch/mips/defconfig-bosporus
 --- linux-2.4.29/arch/mips/defconfig-bosporus  2005-01-19 15:09:27.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-bosporus    2005-01-31 12:59:28.000000000 +0100
-@@ -373,11 +373,6 @@
++++ linux-mips/arch/mips/defconfig-bosporus    2005-03-26 11:47:13.674407459 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -208,9 +208,7 @@
+ CONFIG_MTD_BOSPORUS=y
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -229,7 +227,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -373,11 +370,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -4179,7 +4758,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-bosporus linux-mips/arch/mips/defconf
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -457,6 +452,7 @@
+@@ -457,9 +449,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -4187,18 +4766,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-bosporus linux-mips/arch/mips/defconf
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
-@@ -899,7 +895,7 @@
- # CONFIG_USB_UHCI is not set
- # CONFIG_USB_UHCI_ALT is not set
- CONFIG_USB_OHCI=y
--
-+CONFIG_USB_NON_PCI_OHCI=y
- #
- # USB Device Class drivers
- #
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -681,7 +675,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-capcella linux-mips/arch/mips/defconfig-capcella
 --- linux-2.4.29/arch/mips/defconfig-capcella  2005-01-19 15:09:27.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-capcella    2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-capcella    2005-03-26 11:47:13.739396793 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -228,11 +228,6 @@
  #
  # CONFIG_IPX is not set
@@ -4211,9 +4803,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-capcella linux-mips/arch/mips/defconf
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -472,7 +467,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-cobalt linux-mips/arch/mips/defconfig-cobalt
 --- linux-2.4.29/arch/mips/defconfig-cobalt    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-cobalt      2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-cobalt      2005-03-26 11:47:13.804386126 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -222,11 +222,6 @@
  #
  # CONFIG_IPX is not set
@@ -4226,9 +4836,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-cobalt linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -505,7 +500,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=16
 diff -Nur linux-2.4.29/arch/mips/defconfig-csb250 linux-mips/arch/mips/defconfig-csb250
 --- linux-2.4.29/arch/mips/defconfig-csb250    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-csb250      2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-csb250      2005-03-26 11:47:13.887372506 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ CONFIG_COGENT_CSB250=y
 @@ -268,11 +268,6 @@
  #
  # CONFIG_IPX is not set
@@ -4241,31 +4869,48 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-csb250 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -556,7 +551,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-db1000 linux-mips/arch/mips/defconfig-db1000
 --- linux-2.4.29/arch/mips/defconfig-db1000    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-db1000      2005-02-12 04:05:27.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- CONFIG_MIPS_DB1000=y
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-db1000      2005-03-26 11:47:13.987356097 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -342,11 +345,6 @@
+@@ -214,11 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-CONFIG_MTD_DB1X00=y
+-CONFIG_MTD_DB1X00_BOOT=y
+-CONFIG_MTD_DB1X00_USER=y
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -237,7 +233,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -342,11 +337,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -4277,31 +4922,48 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1000 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -636,7 +626,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-db1100 linux-mips/arch/mips/defconfig-db1100
 --- linux-2.4.29/arch/mips/defconfig-db1100    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-db1100      2005-02-12 04:05:27.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- CONFIG_MIPS_DB1100=y
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-db1100      2005-03-26 11:47:14.088339523 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -342,11 +345,6 @@
+@@ -214,11 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-CONFIG_MTD_DB1X00=y
+-# CONFIG_MTD_DB1X00_BOOT is not set
+-CONFIG_MTD_DB1X00_USER=y
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -237,7 +233,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -342,11 +337,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -4313,10 +4975,34 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1100 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -636,7 +626,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+@@ -884,6 +873,7 @@
+ # CONFIG_FB_PM2 is not set
+ # CONFIG_FB_PM3 is not set
+ # CONFIG_FB_CYBER2000 is not set
++CONFIG_FB_AU1100=y
+ # CONFIG_FB_MATROX is not set
+ # CONFIG_FB_ATY is not set
+ # CONFIG_FB_RADEON is not set
+@@ -895,7 +885,6 @@
+ # CONFIG_FB_VOODOO1 is not set
+ # CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_E1356 is not set
+-CONFIG_FB_AU1100=y
+ # CONFIG_FB_IT8181 is not set
+ # CONFIG_FB_VIRTUAL is not set
+ CONFIG_FBCON_ADVANCED=y
 diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig-db1200
 --- linux-2.4.29/arch/mips/defconfig-db1200    1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-db1200      2005-01-30 09:01:26.000000000 +0100
-@@ -0,0 +1,1051 @@
++++ linux-mips/arch/mips/defconfig-db1200      2005-03-26 11:47:14.182324098 +0100
+@@ -0,0 +1,1032 @@
 +#
 +# Automatically generated make config: don't edit
 +#
@@ -4341,18 +5027,15 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +#
 +# CONFIG_ACER_PICA_61 is not set
 +# CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
 +# CONFIG_MIPS_MIRAGE is not set
 +# CONFIG_MIPS_DB1000 is not set
 +# CONFIG_MIPS_DB1100 is not set
 +# CONFIG_MIPS_DB1500 is not set
 +# CONFIG_MIPS_DB1550 is not set
-+CONFIG_MIPS_DB1200=y
 +# CONFIG_MIPS_PB1000 is not set
 +# CONFIG_MIPS_PB1100 is not set
 +# CONFIG_MIPS_PB1500 is not set
 +# CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
 +# CONFIG_MIPS_XXS1500 is not set
 +# CONFIG_MIPS_MTX1 is not set
@@ -4399,10 +5082,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_HIGHMEM is not set
 +CONFIG_RWSEM_GENERIC_SPINLOCK=y
 +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-+CONFIG_SOC_AU1X00=y
-+CONFIG_SOC_AU1200=y
-+CONFIG_NONCOHERENT_IO=y
-+CONFIG_PC_KEYB=y
 +# CONFIG_MIPS_AU1000 is not set
 +
 +#
@@ -4461,7 +5140,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_TCIC is not set
 +# CONFIG_I82092 is not set
 +# CONFIG_I82365 is not set
-+CONFIG_PCMCIA_AU1X00=m
 +
 +#
 +# PCI Hotplug Support
@@ -4488,7 +5166,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_OOM_KILLER is not set
 +CONFIG_CMDLINE_BOOL=y
 +CONFIG_CMDLINE="mem=96M"
-+# CONFIG_PM is not set
 +
 +#
 +# Memory Technology Devices (MTD)
@@ -4710,6 +5387,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_SCSI_SATA_SVW is not set
 +# CONFIG_SCSI_ATA_PIIX is not set
 +# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
 +# CONFIG_SCSI_SATA_PROMISE is not set
 +# CONFIG_SCSI_SATA_SX4 is not set
 +# CONFIG_SCSI_SATA_SIL is not set
@@ -4798,7 +5476,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# Ethernet (10 or 100Mbit)
 +#
 +CONFIG_NET_ETHERNET=y
-+# CONFIG_MIPS_AU1X00_ENET is not set
 +# CONFIG_SUNLANCE is not set
 +# CONFIG_HAPPYMEAL is not set
 +# CONFIG_SUNBMAC is not set
@@ -4911,12 +5588,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_SERIAL_TX3912_CONSOLE is not set
 +# CONFIG_SERIAL_TXX9 is not set
 +# CONFIG_SERIAL_TXX9_CONSOLE is not set
-+CONFIG_AU1X00_UART=y
-+CONFIG_AU1X00_SERIAL_CONSOLE=y
-+# CONFIG_AU1X00_USB_TTY is not set
-+# CONFIG_AU1X00_USB_RAW is not set
 +# CONFIG_TXX927_SERIAL is not set
-+# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_UNIX98_PTY_COUNT=256
 +
@@ -5001,8 +5673,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +#
 +# CONFIG_PCMCIA_SERIAL_CS is not set
 +# CONFIG_SYNCLINK_CS is not set
-+# CONFIG_AU1X00_GPIO is not set
-+# CONFIG_TS_AU1X00_ADS7846 is not set
 +
 +#
 +# File systems
@@ -5224,9 +5894,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_SOUND_ICH is not set
 +# CONFIG_SOUND_RME96XX is not set
 +# CONFIG_SOUND_SONICVIBES is not set
-+# CONFIG_SOUND_AU1X00 is not set
-+CONFIG_SOUND_AU1550_PSC=y
-+# CONFIG_SOUND_AU1550_I2S is not set
 +# CONFIG_SOUND_TRIDENT is not set
 +# CONFIG_SOUND_MSNDCLAS is not set
 +# CONFIG_SOUND_MSNDPIN is not set
@@ -5370,29 +6037,18 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1200 linux-mips/arch/mips/defconfig
 +# CONFIG_FW_LOADER is not set
 diff -Nur linux-2.4.29/arch/mips/defconfig-db1500 linux-mips/arch/mips/defconfig-db1500
 --- linux-2.4.29/arch/mips/defconfig-db1500    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-db1500      2005-02-12 04:05:27.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- CONFIG_MIPS_DB1500=y
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-db1500      2005-03-26 11:47:14.271309493 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -267,11 +270,6 @@
+@@ -267,11 +267,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -5404,31 +6060,48 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1500 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -555,7 +550,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-db1550 linux-mips/arch/mips/defconfig-db1550
 --- linux-2.4.29/arch/mips/defconfig-db1550    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-db1550      2005-02-12 04:05:27.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- CONFIG_MIPS_DB1550=y
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-db1550      2005-03-26 11:47:14.372292920 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -343,11 +346,6 @@
+@@ -213,11 +213,9 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ CONFIG_MTD_PB1550=y
+ CONFIG_MTD_PB1550_BOOT=y
+ CONFIG_MTD_PB1550_USER=y
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -343,11 +340,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -5440,9 +6113,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-db1550 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -633,7 +625,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ddb5476 linux-mips/arch/mips/defconfig-ddb5476
 --- linux-2.4.29/arch/mips/defconfig-ddb5476   2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ddb5476     2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-ddb5476     2005-03-26 11:47:14.442281433 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -226,11 +226,6 @@
  #
  # CONFIG_IPX is not set
@@ -5455,9 +6146,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ddb5476 linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -517,7 +512,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ddb5477 linux-mips/arch/mips/defconfig-ddb5477
 --- linux-2.4.29/arch/mips/defconfig-ddb5477   2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ddb5477     2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-ddb5477     2005-03-26 11:47:14.507270767 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -226,11 +226,6 @@
  #
  # CONFIG_IPX is not set
@@ -5470,9 +6179,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ddb5477 linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -434,7 +429,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-decstation linux-mips/arch/mips/defconfig-decstation
 --- linux-2.4.29/arch/mips/defconfig-decstation        2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-decstation  2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-decstation  2005-03-26 11:47:14.573259936 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -223,11 +223,6 @@
  #
  # CONFIG_IPX is not set
@@ -5485,7 +6212,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-decstation linux-mips/arch/mips/defco
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -306,6 +301,7 @@
+@@ -306,9 +301,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -5493,9 +6220,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-decstation linux-mips/arch/mips/defco
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ CONFIG_SERIAL_DEC_CONSOLE=y
+ CONFIG_DZ=y
+ CONFIG_ZS=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-e55 linux-mips/arch/mips/defconfig-e55
 --- linux-2.4.29/arch/mips/defconfig-e55       2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-e55 2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-e55 2005-03-26 11:47:14.632250255 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -222,11 +222,6 @@
  #
  # CONFIG_IPX is not set
@@ -5508,10 +6257,57 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-e55 linux-mips/arch/mips/defconfig-e5
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -426,7 +421,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-eagle linux-mips/arch/mips/defconfig-eagle
 --- linux-2.4.29/arch/mips/defconfig-eagle     2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-eagle       2005-01-09 20:33:59.000000000 +0100
-@@ -327,11 +327,6 @@
++++ linux-mips/arch/mips/defconfig-eagle       2005-03-26 11:47:14.721235650 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -208,8 +208,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=1c000000
+-CONFIG_MTD_PHYSMAP_LEN=2000000
++CONFIG_MTD_PHYSMAP_START=0x1c000000
++CONFIG_MTD_PHYSMAP_LEN=0x2000000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -217,9 +217,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -238,7 +236,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -327,11 +324,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -5523,13 +6319,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-eagle linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -587,7 +579,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ev64120 linux-mips/arch/mips/defconfig-ev64120
 --- linux-2.4.29/arch/mips/defconfig-ev64120   2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ev64120     2005-01-09 20:33:59.000000000 +0100
-@@ -230,11 +230,6 @@
- #
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
++++ linux-mips/arch/mips/defconfig-ev64120     2005-03-26 11:47:14.780225968 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -230,11 +230,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
 -
 -#
 -# Appletalk devices
@@ -5538,9 +6352,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ev64120 linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -443,7 +438,6 @@
+ # CONFIG_SERIAL_CONSOLE is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ev96100 linux-mips/arch/mips/defconfig-ev96100
 --- linux-2.4.29/arch/mips/defconfig-ev96100   2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ev96100     2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-ev96100     2005-03-26 11:47:14.833217271 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -232,11 +232,6 @@
  #
  # CONFIG_IPX is not set
@@ -5553,10 +6385,18 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ev96100 linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -441,7 +436,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig-ficmmp
 --- linux-2.4.29/arch/mips/defconfig-ficmmp    1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ficmmp      2005-02-12 04:05:27.000000000 +0100
-@@ -0,0 +1,880 @@
++++ linux-mips/arch/mips/defconfig-ficmmp      2005-03-26 11:47:14.922202667 +0100
+@@ -0,0 +1,862 @@
 +#
 +# Automatically generated make config: don't edit
 +#
@@ -5581,18 +6421,15 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +#
 +# CONFIG_ACER_PICA_61 is not set
 +# CONFIG_MIPS_BOSPORUS is not set
-+CONFIG_MIPS_FICMMP=y
 +# CONFIG_MIPS_MIRAGE is not set
 +# CONFIG_MIPS_DB1000 is not set
 +# CONFIG_MIPS_DB1100 is not set
 +# CONFIG_MIPS_DB1500 is not set
 +# CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
 +# CONFIG_MIPS_PB1000 is not set
 +# CONFIG_MIPS_PB1100 is not set
 +# CONFIG_MIPS_PB1500 is not set
 +# CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
 +# CONFIG_MIPS_XXS1500 is not set
 +# CONFIG_MIPS_MTX1 is not set
@@ -5639,10 +6476,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# CONFIG_HIGHMEM is not set
 +CONFIG_RWSEM_GENERIC_SPINLOCK=y
 +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-+CONFIG_SOC_AU1X00=y
-+CONFIG_SOC_AU1200=y
-+CONFIG_NONCOHERENT_IO=y
-+CONFIG_PC_KEYB=y
 +# CONFIG_MIPS_AU1000 is not set
 +
 +#
@@ -5708,7 +6541,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# CONFIG_OOM_KILLER is not set
 +CONFIG_CMDLINE_BOOL=y
 +CONFIG_CMDLINE="ide3=dma mem=96M root=/dev/hda2 rootflags=data=journal"
-+# CONFIG_PM is not set
 +
 +#
 +# Memory Technology Devices (MTD)
@@ -5925,6 +6757,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# CONFIG_SCSI_SATA_SVW is not set
 +# CONFIG_SCSI_ATA_PIIX is not set
 +# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
 +# CONFIG_SCSI_SATA_PROMISE is not set
 +# CONFIG_SCSI_SATA_SX4 is not set
 +# CONFIG_SCSI_SATA_SIL is not set
@@ -5985,7 +6818,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# Ethernet (10 or 100Mbit)
 +#
 +CONFIG_NET_ETHERNET=y
-+# CONFIG_MIPS_AU1X00_ENET is not set
 +# CONFIG_SUNLANCE is not set
 +# CONFIG_SUNBMAC is not set
 +# CONFIG_SUNQE is not set
@@ -6091,12 +6923,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# CONFIG_SERIAL_TX3912_CONSOLE is not set
 +# CONFIG_SERIAL_TXX9 is not set
 +# CONFIG_SERIAL_TXX9_CONSOLE is not set
-+CONFIG_AU1X00_UART=y
-+CONFIG_AU1X00_SERIAL_CONSOLE=y
-+# CONFIG_AU1X00_USB_TTY is not set
-+# CONFIG_AU1X00_USB_RAW is not set
 +# CONFIG_TXX927_SERIAL is not set
-+# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_UNIX98_PTY_COUNT=256
 +
@@ -6180,8 +7007,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# Direct Rendering Manager (XFree86 DRI support)
 +#
 +# CONFIG_DRM is not set
-+# CONFIG_AU1X00_GPIO is not set
-+# CONFIG_TS_AU1X00_ADS7846 is not set
 +
 +#
 +# File systems
@@ -6386,9 +7211,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +# CONFIG_SOUND_ICH is not set
 +# CONFIG_SOUND_RME96XX is not set
 +# CONFIG_SOUND_SONICVIBES is not set
-+# CONFIG_SOUND_AU1X00 is not set
-+# CONFIG_SOUND_AU1550_PSC is not set
-+# CONFIG_SOUND_AU1550_I2S is not set
 +# CONFIG_SOUND_TRIDENT is not set
 +# CONFIG_SOUND_MSNDCLAS is not set
 +# CONFIG_SOUND_MSNDPIN is not set
@@ -6439,8 +7261,47 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ficmmp linux-mips/arch/mips/defconfig
 +CONFIG_ZLIB_DEFLATE=m
 diff -Nur linux-2.4.29/arch/mips/defconfig-hp-lj linux-mips/arch/mips/defconfig-hp-lj
 --- linux-2.4.29/arch/mips/defconfig-hp-lj     2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-hp-lj       2005-01-09 20:33:59.000000000 +0100
-@@ -304,11 +304,6 @@
++++ linux-mips/arch/mips/defconfig-hp-lj       2005-03-26 11:47:14.993191016 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -184,8 +184,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=10040000
+-CONFIG_MTD_PHYSMAP_LEN=00fc0000
++CONFIG_MTD_PHYSMAP_START=0x10040000
++CONFIG_MTD_PHYSMAP_LEN=0x00fc0000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -193,9 +193,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -214,7 +212,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -304,11 +301,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6452,80 +7313,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-hp-lj linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -604,7 +596,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
 diff -Nur linux-2.4.29/arch/mips/defconfig-hydrogen3 linux-mips/arch/mips/defconfig-hydrogen3
 --- linux-2.4.29/arch/mips/defconfig-hydrogen3 2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-hydrogen3   2005-01-31 12:59:29.000000000 +0100
-@@ -22,6 +22,7 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
-@@ -30,9 +31,11 @@
++++ linux-mips/arch/mips/defconfig-hydrogen3   2005-03-26 11:47:15.093174606 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -CONFIG_MIPS_HYDROGEN3=y
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +CONFIG_MIPS_HYDROGEN3=y
  # CONFIG_MIPS_XXS1500 is not set
-+# CONFIG_MIPS_EP1000 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
- # CONFIG_BAGET_MIPS is not set
-@@ -185,6 +188,7 @@
- CONFIG_MTD_BLOCK=y
- # CONFIG_FTL is not set
- # CONFIG_NFTL is not set
-+# CONFIG_INFTL is not set
- #
- # RAM/ROM/Flash chip drivers
-@@ -196,6 +200,7 @@
- # CONFIG_MTD_CFI_INTELEXT is not set
- CONFIG_MTD_CFI_AMDSTD=y
- # CONFIG_MTD_CFI_STAA is not set
-+CONFIG_MTD_CFI_UTIL=y
- # CONFIG_MTD_RAM is not set
- # CONFIG_MTD_ROM is not set
- # CONFIG_MTD_ABSENT is not set
-@@ -207,17 +212,12 @@
- #
- # Mapping drivers for chip access
- #
-+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
- # CONFIG_MTD_PHYSMAP is not set
--# CONFIG_MTD_PB1000 is not set
--# CONFIG_MTD_PB1500 is not set
--# CONFIG_MTD_PB1100 is not set
--# CONFIG_MTD_BOSPORUS is not set
--# CONFIG_MTD_XXS1500 is not set
--# CONFIG_MTD_MTX1 is not set
+@@ -214,9 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
 -# CONFIG_MTD_DB1X00 is not set
  # CONFIG_MTD_PB1550 is not set
 -CONFIG_MTD_HYDROGEN3=y
--# CONFIG_MTD_MIRAGE is not set
-+# CONFIG_MTD_DB1550 is not set
-+# CONFIG_MTD_PB1200 is not set
-+# CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MIRAGE is not set
  # CONFIG_MTD_CSTM_MIPS_IXX is not set
  # CONFIG_MTD_OCELOT is not set
- # CONFIG_MTD_LASAT is not set
-@@ -235,9 +235,9 @@
+@@ -235,7 +233,6 @@
  #
  # Disk-On-Chip Device Drivers
  #
 -# CONFIG_MTD_DOC1000 is not set
  # CONFIG_MTD_DOC2000 is not set
  # CONFIG_MTD_DOC2001 is not set
-+# CONFIG_MTD_DOC2001PLUS is not set
  # CONFIG_MTD_DOCPROBE is not set
- #
-@@ -340,11 +340,6 @@
+@@ -340,11 +337,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6537,23 +7364,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-hydrogen3 linux-mips/arch/mips/defcon
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -386,6 +381,7 @@
- #
- # Please see Documentation/ide.txt for help/info on IDE drives
- #
-+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
- # CONFIG_BLK_DEV_HD_IDE is not set
- # CONFIG_BLK_DEV_HD is not set
- # CONFIG_BLK_DEV_IDE_SATA is not set
-@@ -403,6 +399,7 @@
- #
- # IDE chipset support/bugfixes
- #
-+# CONFIG_BLK_DEV_IDE_AU1XXX is not set
- # CONFIG_BLK_DEV_CMD640 is not set
- # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
- # CONFIG_BLK_DEV_ISAPNP is not set
-@@ -590,7 +587,6 @@
+@@ -590,7 +582,6 @@
  # CONFIG_AU1X00_USB_TTY is not set
  # CONFIG_AU1X00_USB_RAW is not set
  # CONFIG_TXX927_SERIAL is not set
@@ -6561,34 +7372,15 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-hydrogen3 linux-mips/arch/mips/defcon
  CONFIG_UNIX98_PTYS=y
  CONFIG_UNIX98_PTY_COUNT=256
  
-@@ -677,6 +673,12 @@
- # CONFIG_SYNCLINK_CS is not set
- # CONFIG_AU1X00_GPIO is not set
- # CONFIG_TS_AU1X00_ADS7846 is not set
-+# CONFIG_AU1550_PSC_SPI is not set
-+# CONFIG_AU1XXX_MAE is not set
-+# CONFIG_AU1XXX_AES is not set
-+# CONFIG_AU1XXX_CIM is not set
-+# CONFIG_AU1XXX_AES_TEST is not set
-+CONFIG_AU1XXX_BUTTONS=y
- #
- # File systems
-@@ -838,18 +840,20 @@
+@@ -838,6 +829,7 @@
  # CONFIG_FB_PM2 is not set
  # CONFIG_FB_PM3 is not set
  # CONFIG_FB_CYBER2000 is not set
 +CONFIG_FB_AU1100=y
-+# CONFIG_FOCUS_ENHANCEMENTS is not set
  # CONFIG_FB_MATROX is not set
  # CONFIG_FB_ATY is not set
  # CONFIG_FB_RADEON is not set
- # CONFIG_FB_ATY128 is not set
- # CONFIG_FB_INTEL is not set
- # CONFIG_FB_SIS is not set
-+# CONFIG_FB_SMI501 is not set
- # CONFIG_FB_NEOMAGIC is not set
- # CONFIG_FB_3DFX is not set
+@@ -849,7 +841,6 @@
  # CONFIG_FB_VOODOO1 is not set
  # CONFIG_FB_TRIDENT is not set
  # CONFIG_FB_E1356 is not set
@@ -6596,21 +7388,19 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-hydrogen3 linux-mips/arch/mips/defcon
  # CONFIG_FB_IT8181 is not set
  # CONFIG_FB_VIRTUAL is not set
  CONFIG_FBCON_ADVANCED=y
-@@ -923,9 +927,11 @@
- # USB Host Controller Drivers
- #
- # CONFIG_USB_EHCI_HCD is not set
-+# CONFIG_USB_NON_PCI_EHCI is not set
- # CONFIG_USB_UHCI is not set
- # CONFIG_USB_UHCI_ALT is not set
- CONFIG_USB_OHCI=y
-+CONFIG_USB_NON_PCI_OHCI=y
- #
- # USB Device Class drivers
 diff -Nur linux-2.4.29/arch/mips/defconfig-ip22 linux-mips/arch/mips/defconfig-ip22
 --- linux-2.4.29/arch/mips/defconfig-ip22      2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ip22        2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-ip22        2005-03-26 11:47:15.165162791 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -235,11 +235,6 @@
  #
  # CONFIG_IPX is not set
@@ -6623,7 +7413,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ip22 linux-mips/arch/mips/defconfig-i
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -319,6 +314,7 @@
+@@ -319,9 +314,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -6631,10 +7421,61 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ip22 linux-mips/arch/mips/defconfig-i
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -465,7 +462,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-it8172 linux-mips/arch/mips/defconfig-it8172
 --- linux-2.4.29/arch/mips/defconfig-it8172    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-it8172      2005-01-09 20:33:59.000000000 +0100
-@@ -304,11 +304,6 @@
++++ linux-mips/arch/mips/defconfig-it8172      2005-03-26 11:47:15.242150156 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -186,8 +186,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=8000000
+-CONFIG_MTD_PHYSMAP_LEN=2000000
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x2000000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -195,9 +195,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -216,7 +214,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -304,11 +301,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6646,9 +7487,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-it8172 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -592,7 +584,6 @@
+ CONFIG_PC_KEYB=y
+ # CONFIG_IT8172_SCR0 is not set
+ # CONFIG_IT8172_SCR1 is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ivr linux-mips/arch/mips/defconfig-ivr
 --- linux-2.4.29/arch/mips/defconfig-ivr       2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ivr 2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-ivr 2005-03-26 11:47:15.318137685 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -226,11 +226,6 @@
  #
  # CONFIG_IPX is not set
@@ -6661,9 +7520,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ivr linux-mips/arch/mips/defconfig-iv
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -516,7 +511,6 @@
+ CONFIG_QTRONIX_KEYBOARD=y
+ CONFIG_IT8172_CIR=y
+ # CONFIG_IT8172_SCR0 is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-jmr3927 linux-mips/arch/mips/defconfig-jmr3927
 --- linux-2.4.29/arch/mips/defconfig-jmr3927   2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-jmr3927     2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-jmr3927     2005-03-26 11:47:15.384126854 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -225,11 +225,6 @@
  #
  # CONFIG_IPX is not set
@@ -6676,10 +7553,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-jmr3927 linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -454,7 +449,6 @@
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ CONFIG_TXX927_SERIAL=y
+ CONFIG_TXX927_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
 diff -Nur linux-2.4.29/arch/mips/defconfig-lasat linux-mips/arch/mips/defconfig-lasat
 --- linux-2.4.29/arch/mips/defconfig-lasat     2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-lasat       2005-01-09 20:33:59.000000000 +0100
-@@ -303,11 +303,6 @@
++++ linux-mips/arch/mips/defconfig-lasat       2005-03-26 11:47:15.455115204 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -198,9 +198,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -219,7 +217,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -303,11 +300,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6691,9 +7604,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-lasat linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -584,7 +576,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-malta linux-mips/arch/mips/defconfig-malta
 --- linux-2.4.29/arch/mips/defconfig-malta     2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-malta       2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-malta       2005-03-26 11:47:15.526103553 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -237,11 +237,6 @@
  #
  # CONFIG_IPX is not set
@@ -6706,7 +7637,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-malta linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -319,6 +314,7 @@
+@@ -319,9 +314,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -6714,10 +7645,50 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-malta linux-mips/arch/mips/defconfig-
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -524,7 +521,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-mirage linux-mips/arch/mips/defconfig-mirage
 --- linux-2.4.29/arch/mips/defconfig-mirage    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-mirage      2005-01-31 12:59:29.000000000 +0100
-@@ -335,11 +335,6 @@
++++ linux-mips/arch/mips/defconfig-mirage      2005-03-26 11:47:15.615088948 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -209,9 +209,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ CONFIG_MTD_MIRAGE=y
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -230,7 +228,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -335,11 +332,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6729,18 +7700,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-mirage linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -863,7 +858,7 @@
- # CONFIG_USB_UHCI is not set
- # CONFIG_USB_UHCI_ALT is not set
- CONFIG_USB_OHCI=y
--
-+CONFIG_USB_NON_PCI_OHCI=y
- #
- # USB Device Class drivers
- #
+@@ -560,7 +552,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-mpc30x linux-mips/arch/mips/defconfig-mpc30x
 --- linux-2.4.29/arch/mips/defconfig-mpc30x    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-mpc30x      2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-mpc30x      2005-03-26 11:47:15.680078282 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -228,11 +228,6 @@
  #
  # CONFIG_IPX is not set
@@ -6753,10 +7733,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-mpc30x linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -400,7 +395,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-mtx-1 linux-mips/arch/mips/defconfig-mtx-1
 --- linux-2.4.29/arch/mips/defconfig-mtx-1     2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-mtx-1       2005-01-20 03:19:22.000000000 +0100
-@@ -371,11 +371,6 @@
++++ linux-mips/arch/mips/defconfig-mtx-1       2005-03-26 11:47:15.793059739 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ CONFIG_MIPS_MTX1=y
+ # CONFIG_COGENT_CSB250 is not set
+@@ -193,9 +193,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ CONFIG_MTD_MTX1=y
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -214,7 +212,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -371,11 +368,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6768,7 +7784,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-mtx-1 linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  CONFIG_BRIDGE=m
  # CONFIG_X25 is not set
-@@ -479,6 +474,7 @@
+@@ -479,9 +471,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -6776,9 +7792,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-mtx-1 linux-mips/arch/mips/defconfig-
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -700,7 +694,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-nino linux-mips/arch/mips/defconfig-nino
 --- linux-2.4.29/arch/mips/defconfig-nino      2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-nino        2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-nino        2005-03-26 11:47:15.849050550 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -226,11 +226,6 @@
  #
  # CONFIG_IPX is not set
@@ -6791,10 +7829,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-nino linux-mips/arch/mips/defconfig-n
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-diff -Nur linux-2.4.29/arch/mips/defconfig-ocelot linux-mips/arch/mips/defconfig-ocelot
+@@ -339,7 +334,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
+diff -Nur linux-2.4.29/arch/mips/defconfig-ocelot linux-mips/arch/mips/defconfig-ocelot
 --- linux-2.4.29/arch/mips/defconfig-ocelot    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ocelot      2005-01-09 20:33:59.000000000 +0100
-@@ -307,11 +307,6 @@
++++ linux-mips/arch/mips/defconfig-ocelot      2005-03-26 11:47:15.909040704 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -194,9 +194,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ CONFIG_MTD_OCELOT=y
+@@ -215,7 +213,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ CONFIG_MTD_DOC2000=y
+ # CONFIG_MTD_DOC2001 is not set
+ CONFIG_MTD_DOCPROBE=y
+@@ -307,11 +304,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6806,9 +7880,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ocelot linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -513,7 +505,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-osprey linux-mips/arch/mips/defconfig-osprey
 --- linux-2.4.29/arch/mips/defconfig-osprey    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-osprey      2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-osprey      2005-03-26 11:47:15.963031843 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -227,11 +227,6 @@
  #
  # CONFIG_IPX is not set
@@ -6821,31 +7913,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-osprey linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -388,7 +383,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-pb1000 linux-mips/arch/mips/defconfig-pb1000
 --- linux-2.4.29/arch/mips/defconfig-pb1000    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-pb1000      2005-02-12 04:05:27.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-pb1000      2005-03-26 11:47:16.057016418 +0100
+@@ -30,8 +30,8 @@
  CONFIG_MIPS_PB1000=y
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -324,11 +327,6 @@
+@@ -215,9 +215,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -324,11 +321,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6857,7 +7964,15 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1000 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -707,7 +705,7 @@
+@@ -622,7 +614,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+@@ -707,7 +698,7 @@
  #
  # CONFIG_PCMCIA_SERIAL_CS is not set
  # CONFIG_SYNCLINK_CS is not set
@@ -6868,29 +7983,36 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1000 linux-mips/arch/mips/defconfig
  #
 diff -Nur linux-2.4.29/arch/mips/defconfig-pb1100 linux-mips/arch/mips/defconfig-pb1100
 --- linux-2.4.29/arch/mips/defconfig-pb1100    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-pb1100      2005-02-12 04:05:28.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-pb1100      2005-03-26 11:47:16.158999680 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  CONFIG_MIPS_PB1100=y
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -324,11 +327,6 @@
+@@ -198,9 +198,7 @@
+ # CONFIG_MTD_MTX1 is not set
+ CONFIG_MTD_PB1500_BOOT=y
+ CONFIG_MTD_PB1500_USER=y
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -219,7 +217,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -324,11 +321,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -6902,10 +8024,34 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1100 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -613,7 +605,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+@@ -859,6 +850,7 @@
+ # CONFIG_FB_PM2 is not set
+ # CONFIG_FB_PM3 is not set
+ # CONFIG_FB_CYBER2000 is not set
++CONFIG_FB_AU1100=y
+ # CONFIG_FB_MATROX is not set
+ # CONFIG_FB_ATY is not set
+ # CONFIG_FB_RADEON is not set
+@@ -870,7 +862,6 @@
+ # CONFIG_FB_VOODOO1 is not set
+ # CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_E1356 is not set
+-CONFIG_FB_AU1100=y
+ # CONFIG_FB_IT8181 is not set
+ # CONFIG_FB_VIRTUAL is not set
+ CONFIG_FBCON_ADVANCED=y
 diff -Nur linux-2.4.29/arch/mips/defconfig-pb1200 linux-mips/arch/mips/defconfig-pb1200
 --- linux-2.4.29/arch/mips/defconfig-pb1200    1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-pb1200      2005-01-30 09:01:27.000000000 +0100
-@@ -0,0 +1,1063 @@
++++ linux-mips/arch/mips/defconfig-pb1200      2005-03-26 11:47:16.258983270 +0100
+@@ -0,0 +1,1060 @@
 +#
 +# Automatically generated make config: don't edit
 +#
@@ -6930,18 +8076,15 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1200 linux-mips/arch/mips/defconfig
 +#
 +# CONFIG_ACER_PICA_61 is not set
 +# CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
 +# CONFIG_MIPS_MIRAGE is not set
 +# CONFIG_MIPS_DB1000 is not set
 +# CONFIG_MIPS_DB1100 is not set
 +# CONFIG_MIPS_DB1500 is not set
 +# CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
 +# CONFIG_MIPS_PB1000 is not set
 +# CONFIG_MIPS_PB1100 is not set
 +# CONFIG_MIPS_PB1500 is not set
 +# CONFIG_MIPS_PB1550 is not set
-+CONFIG_MIPS_PB1200=y
 +# CONFIG_MIPS_HYDROGEN3 is not set
 +# CONFIG_MIPS_XXS1500 is not set
 +# CONFIG_MIPS_MTX1 is not set
@@ -7299,6 +8442,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1200 linux-mips/arch/mips/defconfig
 +# CONFIG_SCSI_SATA_SVW is not set
 +# CONFIG_SCSI_ATA_PIIX is not set
 +# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
 +# CONFIG_SCSI_SATA_PROMISE is not set
 +# CONFIG_SCSI_SATA_SX4 is not set
 +# CONFIG_SCSI_SATA_SIL is not set
@@ -7512,7 +8656,6 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1200 linux-mips/arch/mips/defconfig
 +# CONFIG_AU1X00_USB_TTY is not set
 +# CONFIG_AU1X00_USB_RAW is not set
 +# CONFIG_TXX927_SERIAL is not set
-+# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_UNIX98_PTY_COUNT=256
 +
@@ -7971,29 +9114,36 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1200 linux-mips/arch/mips/defconfig
 +# CONFIG_FW_LOADER is not set
 diff -Nur linux-2.4.29/arch/mips/defconfig-pb1500 linux-mips/arch/mips/defconfig-pb1500
 --- linux-2.4.29/arch/mips/defconfig-pb1500    2005-01-19 15:09:28.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-pb1500      2005-02-12 04:05:28.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-pb1500      2005-03-26 11:47:16.365965712 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  CONFIG_MIPS_PB1500=y
 -# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_PB1550 is not set
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -341,11 +344,6 @@
+@@ -215,9 +215,7 @@
+ # CONFIG_MTD_MTX1 is not set
+ CONFIG_MTD_PB1500_BOOT=y
+ # CONFIG_MTD_PB1500_USER is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -341,11 +338,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -8005,31 +9155,48 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1500 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -675,7 +667,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-pb1550 linux-mips/arch/mips/defconfig-pb1550
 --- linux-2.4.29/arch/mips/defconfig-pb1550    2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-pb1550      2005-02-12 04:05:28.000000000 +0100
-@@ -22,16 +22,19 @@
- #
- # CONFIG_ACER_PICA_61 is not set
- # CONFIG_MIPS_BOSPORUS is not set
-+# CONFIG_MIPS_FICMMP is not set
- # CONFIG_MIPS_MIRAGE is not set
- # CONFIG_MIPS_DB1000 is not set
- # CONFIG_MIPS_DB1100 is not set
- # CONFIG_MIPS_DB1500 is not set
- # CONFIG_MIPS_DB1550 is not set
-+# CONFIG_MIPS_DB1200 is not set
++++ linux-mips/arch/mips/defconfig-pb1550      2005-03-26 11:47:16.471948318 +0100
+@@ -30,8 +30,8 @@
  # CONFIG_MIPS_PB1000 is not set
  # CONFIG_MIPS_PB1100 is not set
  # CONFIG_MIPS_PB1500 is not set
 -# CONFIG_MIPS_HYDROGEN3 is not set
  CONFIG_MIPS_PB1550=y
-+# CONFIG_MIPS_PB1200 is not set
 +# CONFIG_MIPS_HYDROGEN3 is not set
  # CONFIG_MIPS_XXS1500 is not set
  # CONFIG_MIPS_MTX1 is not set
  # CONFIG_COGENT_CSB250 is not set
-@@ -343,11 +346,6 @@
+@@ -213,11 +213,9 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ CONFIG_MTD_PB1550=y
+ CONFIG_MTD_PB1550_BOOT=y
+ CONFIG_MTD_PB1550_USER=y
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -343,11 +340,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -8041,9 +9208,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-pb1550 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -633,7 +625,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-rbtx4927 linux-mips/arch/mips/defconfig-rbtx4927
 --- linux-2.4.29/arch/mips/defconfig-rbtx4927  2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-rbtx4927    2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-rbtx4927    2005-03-26 11:47:16.531938472 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -223,11 +223,6 @@
  #
  # CONFIG_IPX is not set
@@ -8056,9 +9241,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-rbtx4927 linux-mips/arch/mips/defconf
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -466,7 +461,6 @@
+ CONFIG_SERIAL_TXX9=y
+ CONFIG_SERIAL_TXX9_CONSOLE=y
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
 diff -Nur linux-2.4.29/arch/mips/defconfig-rm200 linux-mips/arch/mips/defconfig-rm200
 --- linux-2.4.29/arch/mips/defconfig-rm200     2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-rm200       2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-rm200       2005-03-26 11:47:16.579930595 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -229,11 +229,6 @@
  #
  # CONFIG_IPX is not set
@@ -8071,9 +9274,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-rm200 linux-mips/arch/mips/defconfig-
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -340,7 +335,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-sb1250-swarm linux-mips/arch/mips/defconfig-sb1250-swarm
 --- linux-2.4.29/arch/mips/defconfig-sb1250-swarm      2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-sb1250-swarm        2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-sb1250-swarm        2005-03-26 11:47:16.645919765 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -90,6 +90,7 @@
  # CONFIG_SIBYTE_TBPROF is not set
  CONFIG_SIBYTE_GENBUS_IDE=y
@@ -8094,9 +9315,48 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-sb1250-swarm linux-mips/arch/mips/def
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -469,7 +465,6 @@
+ CONFIG_SIBYTE_SB1250_DUART=y
+ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+ CONFIG_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.29/arch/mips/defconfig-sead linux-mips/arch/mips/defconfig-sead
+--- linux-2.4.29/arch/mips/defconfig-sead      2005-01-19 15:09:29.000000000 +0100
++++ linux-mips/arch/mips/defconfig-sead        2005-03-26 11:47:16.686913037 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -244,7 +244,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
 diff -Nur linux-2.4.29/arch/mips/defconfig-stretch linux-mips/arch/mips/defconfig-stretch
 --- linux-2.4.29/arch/mips/defconfig-stretch   2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-stretch     2005-01-09 20:33:59.000000000 +0100
++++ linux-mips/arch/mips/defconfig-stretch     2005-03-26 11:47:16.751902371 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -240,11 +240,6 @@
  #
  # CONFIG_IPX is not set
@@ -8109,7 +9369,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-stretch linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -324,6 +319,7 @@
+@@ -324,9 +319,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -8117,9 +9377,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-stretch linux-mips/arch/mips/defconfi
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -516,7 +513,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-tb0226 linux-mips/arch/mips/defconfig-tb0226
 --- linux-2.4.29/arch/mips/defconfig-tb0226    2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-tb0226      2005-01-09 20:34:00.000000000 +0100
++++ linux-mips/arch/mips/defconfig-tb0226      2005-03-26 11:47:16.828889735 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -228,11 +228,6 @@
  #
  # CONFIG_IPX is not set
@@ -8132,7 +9414,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-tb0226 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -312,6 +307,7 @@
+@@ -312,9 +307,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -8140,9 +9422,31 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-tb0226 linux-mips/arch/mips/defconfig
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -518,7 +515,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-tb0229 linux-mips/arch/mips/defconfig-tb0229
 --- linux-2.4.29/arch/mips/defconfig-tb0229    2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-tb0229      2005-01-09 20:34:00.000000000 +0100
++++ linux-mips/arch/mips/defconfig-tb0229      2005-03-26 11:47:16.893879069 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -230,11 +230,6 @@
  #
  # CONFIG_IPX is not set
@@ -8155,10 +9459,46 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-tb0229 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -445,7 +440,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-ti1500 linux-mips/arch/mips/defconfig-ti1500
 --- linux-2.4.29/arch/mips/defconfig-ti1500    2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-ti1500      2005-01-09 20:34:00.000000000 +0100
-@@ -339,11 +339,6 @@
++++ linux-mips/arch/mips/defconfig-ti1500      2005-03-26 11:47:16.995862331 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ CONFIG_MIPS_XXS1500=y
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,9 +213,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ CONFIG_MTD_XXS1500=y
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -234,7 +232,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -339,11 +336,6 @@
  #
  # CONFIG_IPX is not set
  # CONFIG_ATALK is not set
@@ -8170,9 +9510,27 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-ti1500 linux-mips/arch/mips/defconfig
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -600,7 +592,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-workpad linux-mips/arch/mips/defconfig-workpad
 --- linux-2.4.29/arch/mips/defconfig-workpad   2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-workpad     2005-01-09 20:34:00.000000000 +0100
++++ linux-mips/arch/mips/defconfig-workpad     2005-03-26 11:47:17.054852650 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -222,11 +222,6 @@
  #
  # CONFIG_IPX is not set
@@ -8185,24 +9543,78 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-workpad linux-mips/arch/mips/defconfi
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -426,7 +421,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-xxs1500 linux-mips/arch/mips/defconfig-xxs1500
 --- linux-2.4.29/arch/mips/defconfig-xxs1500   2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-xxs1500     2005-01-09 20:34:00.000000000 +0100
-@@ -339,11 +339,6 @@
++++ linux-mips/arch/mips/defconfig-xxs1500     2005-03-26 11:47:17.143838045 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ CONFIG_MIPS_XXS1500=y
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,9 +213,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ CONFIG_MTD_XXS1500=y
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -234,7 +232,6 @@
  #
- # CONFIG_IPX is not set
- # CONFIG_ATALK is not set
--
--#
--# Appletalk devices
--#
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -339,11 +336,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
 -# CONFIG_DEV_APPLETALK is not set
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -671,7 +663,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/defconfig-yosemite linux-mips/arch/mips/defconfig-yosemite
 --- linux-2.4.29/arch/mips/defconfig-yosemite  2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/defconfig-yosemite    2005-01-09 20:34:00.000000000 +0100
++++ linux-mips/arch/mips/defconfig-yosemite    2005-03-26 11:47:17.208827379 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -227,11 +227,6 @@
  #
  # CONFIG_IPX is not set
@@ -8215,7 +9627,7 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-yosemite linux-mips/arch/mips/defconf
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -310,6 +305,7 @@
+@@ -310,9 +305,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -8223,6 +9635,18 @@ diff -Nur linux-2.4.29/arch/mips/defconfig-yosemite linux-mips/arch/mips/defconf
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips/kernel/cpu-probe.c linux-mips/arch/mips/kernel/cpu-probe.c
 --- linux-2.4.29/arch/mips/kernel/cpu-probe.c  2005-01-19 15:09:29.000000000 +0100
 +++ linux-mips/arch/mips/kernel/cpu-probe.c    2005-01-31 12:59:30.000000000 +0100
@@ -8407,7 +9831,7 @@ diff -Nur linux-2.4.29/arch/mips/kernel/head.S linux-mips/arch/mips/kernel/head.
  
 diff -Nur linux-2.4.29/arch/mips/kernel/scall_o32.S linux-mips/arch/mips/kernel/scall_o32.S
 --- linux-2.4.29/arch/mips/kernel/scall_o32.S  2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/kernel/scall_o32.S    2005-02-12 04:05:33.000000000 +0100
++++ linux-mips/arch/mips/kernel/scall_o32.S    2005-03-26 11:47:17.566768632 +0100
 @@ -121,15 +121,14 @@
  
  trace_a_syscall:
@@ -8555,39 +9979,76 @@ diff -Nur linux-2.4.29/arch/mips/lib/rtc-std.c linux-mips/arch/mips/lib/rtc-std.
  };
 -
 -EXPORT_SYMBOL(rtc_ops);
-diff -Nur linux-2.4.29/arch/mips/mm/c-r4k.c linux-mips/arch/mips/mm/c-r4k.c
---- linux-2.4.29/arch/mips/mm/c-r4k.c  2005-01-19 15:09:29.000000000 +0100
-+++ linux-mips/arch/mips/mm/c-r4k.c    2005-02-12 04:05:35.000000000 +0100
-@@ -867,9 +867,16 @@
-        * normally they'd suffer from aliases but magic in the hardware deals
-        * with that for us so we don't need to take care ourselves.
-        */
--      if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
--              if (c->dcache.waysize > PAGE_SIZE)
--                      c->dcache.flags |= MIPS_CACHE_ALIASES;
-+      switch (c->cputype) {
-+      case CPU_R10000:
-+      case CPU_R12000:
-+              break;
-+      case CPU_24K:
-+              if (!(read_c0_config7() & (1 << 16)))
-+      default:
-+                      if (c->dcache.waysize > PAGE_SIZE)
-+                              c->dcache.flags |= MIPS_CACHE_ALIASES;
-+      }
+diff -Nur linux-2.4.29/arch/mips/Makefile linux-mips/arch/mips/Makefile
+--- linux-2.4.29/arch/mips/Makefile    2005-01-19 15:09:26.000000000 +0100
++++ linux-mips/arch/mips/Makefile      2005-01-31 12:59:28.000000000 +0100
+@@ -211,7 +211,7 @@
+ endif
  
-       switch (c->cputype) {
-       case CPU_20KC:
-@@ -1069,9 +1076,6 @@
-       probe_pcache();
-       setup_scache();
+ #
+-# Au1000 (Alchemy Semi PB1000) eval board
++# Au1x AMD Alchemy eval boards
+ #
+ ifdef CONFIG_MIPS_PB1000
+ LIBS          += arch/mips/au1000/pb1000/pb1000.o \
+@@ -220,9 +220,6 @@
+ LOADADDR      := 0x80100000
+ endif
  
--      if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
--              c->dcache.flags |= MIPS_CACHE_ALIASES;
--
-       r4k_blast_dcache_page_setup();
-       r4k_blast_dcache_page_indexed_setup();
-       r4k_blast_dcache_setup();
+-#
+-# Au1100 (Alchemy Semi PB1100) eval board
+-#
+ ifdef CONFIG_MIPS_PB1100
+ LIBS          += arch/mips/au1000/pb1100/pb1100.o \
+                  arch/mips/au1000/common/au1000.o
+@@ -230,9 +227,6 @@
+ LOADADDR      += 0x80100000
+ endif
+-#
+-# Au1500 (Alchemy Semi PB1500) eval board
+-#
+ ifdef CONFIG_MIPS_PB1500
+ LIBS          += arch/mips/au1000/pb1500/pb1500.o \
+                  arch/mips/au1000/common/au1000.o
+@@ -240,9 +234,6 @@
+ LOADADDR      := 0x80100000
+ endif
+-#
+-# Au1x00 (AMD/Alchemy) eval boards
+-#
+ ifdef CONFIG_MIPS_DB1000
+ LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                  arch/mips/au1000/common/au1000.o
+@@ -313,6 +304,27 @@
+ LOADADDR      += 0x80100000
+ endif
++ifdef CONFIG_MIPS_PB1200
++LIBS          += arch/mips/au1000/pb1200/pb1200.o \
++                 arch/mips/au1000/common/au1000.o
++SUBDIRS       += arch/mips/au1000/pb1200 arch/mips/au1000/common
++LOADADDR      += 0x80100000
++endif
++
++ifdef CONFIG_MIPS_DB1200
++LIBS          += arch/mips/au1000/pb1200/pb1200.o \
++                 arch/mips/au1000/common/au1000.o
++SUBDIRS       += arch/mips/au1000/pb1200 arch/mips/au1000/common
++LOADADDR      += 0x80100000
++endif
++
++ifdef CONFIG_MIPS_FICMMP
++LIBS          += arch/mips/au1000/ficmmp/ficmmp.o \
++                 arch/mips/au1000/common/au1000.o
++SUBDIRS       += arch/mips/au1000/ficmmp arch/mips/au1000/common
++LOADADDR      += 0x80100000
++endif
++
+ #
+ # Cogent CSB250
 diff -Nur linux-2.4.29/arch/mips/mm/cerr-sb1.c linux-mips/arch/mips/mm/cerr-sb1.c
 --- linux-2.4.29/arch/mips/mm/cerr-sb1.c       2004-02-18 14:36:30.000000000 +0100
 +++ linux-mips/arch/mips/mm/cerr-sb1.c 2004-12-13 18:37:23.000000000 +0100
@@ -8635,6 +10096,122 @@ diff -Nur linux-2.4.29/arch/mips/mm/cerr-sb1.c linux-mips/arch/mips/mm/cerr-sb1.
                if (way == 0) {
                        lru = (taghi >> 14) & 0xff;
                        prom_printf("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
+diff -Nur linux-2.4.29/arch/mips/mm/c-r4k.c linux-mips/arch/mips/mm/c-r4k.c
+--- linux-2.4.29/arch/mips/mm/c-r4k.c  2005-01-19 15:09:29.000000000 +0100
++++ linux-mips/arch/mips/mm/c-r4k.c    2005-03-26 11:47:17.585765515 +0100
+@@ -867,9 +867,16 @@
+        * normally they'd suffer from aliases but magic in the hardware deals
+        * with that for us so we don't need to take care ourselves.
+        */
+-      if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
+-              if (c->dcache.waysize > PAGE_SIZE)
+-                      c->dcache.flags |= MIPS_CACHE_ALIASES;
++      switch (c->cputype) {
++      case CPU_R10000:
++      case CPU_R12000:
++              break;
++      case CPU_24K:
++              if (!(read_c0_config7() & (1 << 16)))
++      default:
++                      if (c->dcache.waysize > PAGE_SIZE)
++                              c->dcache.flags |= MIPS_CACHE_ALIASES;
++      }
+       switch (c->cputype) {
+       case CPU_20KC:
+@@ -1069,9 +1076,6 @@
+       probe_pcache();
+       setup_scache();
+-      if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
+-              c->dcache.flags |= MIPS_CACHE_ALIASES;
+-
+       r4k_blast_dcache_page_setup();
+       r4k_blast_dcache_page_indexed_setup();
+       r4k_blast_dcache_setup();
+diff -Nur linux-2.4.29/arch/mips/mm/tlbex-mips32.S linux-mips/arch/mips/mm/tlbex-mips32.S
+--- linux-2.4.29/arch/mips/mm/tlbex-mips32.S   2004-02-18 14:36:30.000000000 +0100
++++ linux-mips/arch/mips/mm/tlbex-mips32.S     2004-11-29 00:33:15.000000000 +0100
+@@ -196,7 +196,7 @@
+       .set    noat; \
+       SAVE_ALL; \
+       mfc0    a2, CP0_BADVADDR; \
+-      STI; \
++      KMODE; \
+       .set    at; \
+       move    a0, sp; \
+       jal     do_page_fault; \
+diff -Nur linux-2.4.29/arch/mips/mm/tlbex-r4k.S linux-mips/arch/mips/mm/tlbex-r4k.S
+--- linux-2.4.29/arch/mips/mm/tlbex-r4k.S      2004-02-18 14:36:30.000000000 +0100
++++ linux-mips/arch/mips/mm/tlbex-r4k.S        2004-11-25 23:18:38.000000000 +0100
+@@ -184,13 +184,10 @@
+       P_MTC0  k0, CP0_ENTRYLO0                # load it
+       PTE_SRL k1, k1, 6                       # convert to entrylo1
+       P_MTC0  k1, CP0_ENTRYLO1                # load it
+-      b       1f
+-      rm9000_tlb_hazard
++      mtc0_tlbw_hazard
+       tlbwr                                   # write random tlb entry
+-1:
+-      nop
+-      rm9000_tlb_hazard
+-      eret                                    # return from trap
++      tlbw_eret_hazard
++      eret
+       END(except_vec0_r4000)
+       /* TLB refill, EXL == 0, R4600 version */
+@@ -468,13 +465,10 @@
+       PTE_PRESENT(k0, k1, nopage_tlbl)
+       PTE_MAKEVALID(k0, k1)
+       PTE_RELOAD(k1, k0)
+-      rm9000_tlb_hazard
+-      nop
+-      b       1f
+-       tlbwi
+-1:
++      mtc0_tlbw_hazard
++      tlbwi
+       nop
+-      rm9000_tlb_hazard
++      tlbw_eret_hazard
+       .set    mips3
+       eret
+       .set    mips0
+@@ -496,13 +490,10 @@
+       PTE_WRITABLE(k0, k1, nopage_tlbs)
+       PTE_MAKEWRITE(k0, k1)
+       PTE_RELOAD(k1, k0)
+-      rm9000_tlb_hazard
+-      nop
+-      b       1f
+-       tlbwi
+-1:
++      mtc0_tlbw_hazard
++      tlbwi
+       nop
+-      rm9000_tlb_hazard
++      tlbw_eret_hazard
+       .set    mips3
+       eret
+       .set    mips0
+@@ -529,13 +520,10 @@
+       /* Now reload the entry into the tlb. */
+       PTE_RELOAD(k1, k0)
+-      rm9000_tlb_hazard
+-      nop
+-      b       1f
+-       tlbwi
+-1:
+-      rm9000_tlb_hazard
++      mtc0_tlbw_hazard
++      tlbwi
+       nop
++      tlbw_eret_hazard
+       .set    mips3
+       eret
+       .set    mips0
 diff -Nur linux-2.4.29/arch/mips/mm/tlb-r4k.c linux-mips/arch/mips/mm/tlb-r4k.c
 --- linux-2.4.29/arch/mips/mm/tlb-r4k.c        2005-01-19 15:09:29.000000000 +0100
 +++ linux-mips/arch/mips/mm/tlb-r4k.c  2004-11-25 23:18:38.000000000 +0100
@@ -8964,93 +10541,20 @@ diff -Nur linux-2.4.29/arch/mips/mm/tlb-r4k.c linux-mips/arch/mips/mm/tlb-r4k.c
  
        /*
         * You should never change this register:
-diff -Nur linux-2.4.29/arch/mips/mm/tlbex-mips32.S linux-mips/arch/mips/mm/tlbex-mips32.S
---- linux-2.4.29/arch/mips/mm/tlbex-mips32.S   2004-02-18 14:36:30.000000000 +0100
-+++ linux-mips/arch/mips/mm/tlbex-mips32.S     2004-11-29 00:33:15.000000000 +0100
-@@ -196,7 +196,7 @@
-       .set    noat; \
-       SAVE_ALL; \
-       mfc0    a2, CP0_BADVADDR; \
--      STI; \
-+      KMODE; \
-       .set    at; \
-       move    a0, sp; \
-       jal     do_page_fault; \
-diff -Nur linux-2.4.29/arch/mips/mm/tlbex-r4k.S linux-mips/arch/mips/mm/tlbex-r4k.S
---- linux-2.4.29/arch/mips/mm/tlbex-r4k.S      2004-02-18 14:36:30.000000000 +0100
-+++ linux-mips/arch/mips/mm/tlbex-r4k.S        2004-11-25 23:18:38.000000000 +0100
-@@ -184,13 +184,10 @@
-       P_MTC0  k0, CP0_ENTRYLO0                # load it
-       PTE_SRL k1, k1, 6                       # convert to entrylo1
-       P_MTC0  k1, CP0_ENTRYLO1                # load it
--      b       1f
--      rm9000_tlb_hazard
-+      mtc0_tlbw_hazard
-       tlbwr                                   # write random tlb entry
--1:
--      nop
--      rm9000_tlb_hazard
--      eret                                    # return from trap
-+      tlbw_eret_hazard
-+      eret
-       END(except_vec0_r4000)
-       /* TLB refill, EXL == 0, R4600 version */
-@@ -468,13 +465,10 @@
-       PTE_PRESENT(k0, k1, nopage_tlbl)
-       PTE_MAKEVALID(k0, k1)
-       PTE_RELOAD(k1, k0)
--      rm9000_tlb_hazard
--      nop
--      b       1f
--       tlbwi
--1:
-+      mtc0_tlbw_hazard
-+      tlbwi
-       nop
--      rm9000_tlb_hazard
-+      tlbw_eret_hazard
-       .set    mips3
-       eret
-       .set    mips0
-@@ -496,13 +490,10 @@
-       PTE_WRITABLE(k0, k1, nopage_tlbs)
-       PTE_MAKEWRITE(k0, k1)
-       PTE_RELOAD(k1, k0)
--      rm9000_tlb_hazard
--      nop
--      b       1f
--       tlbwi
--1:
-+      mtc0_tlbw_hazard
-+      tlbwi
-       nop
--      rm9000_tlb_hazard
-+      tlbw_eret_hazard
-       .set    mips3
-       eret
-       .set    mips0
-@@ -529,13 +520,10 @@
-       /* Now reload the entry into the tlb. */
-       PTE_RELOAD(k1, k0)
--      rm9000_tlb_hazard
--      nop
--      b       1f
--       tlbwi
--1:
--      rm9000_tlb_hazard
-+      mtc0_tlbw_hazard
-+      tlbwi
-       nop
-+      tlbw_eret_hazard
-       .set    mips3
-       eret
-       .set    mips0
 diff -Nur linux-2.4.29/arch/mips64/defconfig linux-mips/arch/mips64/defconfig
 --- linux-2.4.29/arch/mips64/defconfig 2005-01-19 15:09:30.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig   2005-01-20 03:19:22.000000000 +0100
-@@ -470,6 +470,7 @@
++++ linux-mips/arch/mips64/defconfig   2005-03-26 11:47:17.749738603 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -470,9 +470,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9058,9 +10562,31 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig linux-mips/arch/mips64/defconfig
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -658,7 +660,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-atlas linux-mips/arch/mips64/defconfig-atlas
 --- linux-2.4.29/arch/mips64/defconfig-atlas   2005-01-19 15:09:30.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-atlas     2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-atlas     2005-03-26 11:47:17.816727608 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -232,11 +232,6 @@
  #
  # CONFIG_IPX is not set
@@ -9073,7 +10599,7 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-atlas linux-mips/arch/mips64/defcon
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -314,6 +309,7 @@
+@@ -314,9 +309,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9081,9 +10607,31 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-atlas linux-mips/arch/mips64/defcon
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -474,7 +471,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-decstation linux-mips/arch/mips64/defconfig-decstation
 --- linux-2.4.29/arch/mips64/defconfig-decstation      2005-01-19 15:09:30.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-decstation        2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-decstation        2005-03-26 11:47:17.884716450 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -224,11 +224,6 @@
  #
  # CONFIG_IPX is not set
@@ -9096,7 +10644,7 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-decstation linux-mips/arch/mips64/d
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -307,6 +302,7 @@
+@@ -307,9 +302,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9104,9 +10652,31 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-decstation linux-mips/arch/mips64/d
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ CONFIG_SERIAL_DEC_CONSOLE=y
+ # CONFIG_DZ is not set
+ CONFIG_ZS=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-ip22 linux-mips/arch/mips64/defconfig-ip22
 --- linux-2.4.29/arch/mips64/defconfig-ip22    2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-ip22      2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-ip22      2005-03-26 11:47:17.955704799 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -235,11 +235,6 @@
  #
  # CONFIG_IPX is not set
@@ -9119,7 +10689,7 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-ip22 linux-mips/arch/mips64/defconf
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -319,6 +314,7 @@
+@@ -319,9 +314,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9127,10 +10697,32 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-ip22 linux-mips/arch/mips64/defconf
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -488,7 +485,6 @@
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+ CONFIG_IP22_SERIAL=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-ip27 linux-mips/arch/mips64/defconfig-ip27
 --- linux-2.4.29/arch/mips64/defconfig-ip27    2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-ip27      2005-01-20 03:19:22.000000000 +0100
-@@ -470,6 +470,7 @@
++++ linux-mips/arch/mips64/defconfig-ip27      2005-03-26 11:47:18.038691179 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -470,9 +470,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9138,9 +10730,31 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-ip27 linux-mips/arch/mips64/defconf
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -658,7 +660,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-jaguar linux-mips/arch/mips64/defconfig-jaguar
 --- linux-2.4.29/arch/mips64/defconfig-jaguar  2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-jaguar    2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-jaguar    2005-03-26 11:47:18.091682482 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -227,11 +227,6 @@
  #
  # CONFIG_IPX is not set
@@ -9153,9 +10767,27 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-jaguar linux-mips/arch/mips64/defco
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -403,7 +398,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-malta linux-mips/arch/mips64/defconfig-malta
 --- linux-2.4.29/arch/mips64/defconfig-malta   2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-malta     2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-malta     2005-03-26 11:47:18.150672800 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -235,11 +235,6 @@
  #
  # CONFIG_IPX is not set
@@ -9168,7 +10800,7 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-malta linux-mips/arch/mips64/defcon
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
-@@ -317,6 +312,7 @@
+@@ -317,9 +312,11 @@
  # CONFIG_SCSI_MEGARAID is not set
  # CONFIG_SCSI_MEGARAID2 is not set
  # CONFIG_SCSI_SATA is not set
@@ -9176,9 +10808,31 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-malta linux-mips/arch/mips64/defcon
  # CONFIG_SCSI_SATA_SVW is not set
  # CONFIG_SCSI_ATA_PIIX is not set
  # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-ocelotc linux-mips/arch/mips64/defconfig-ocelotc
 --- linux-2.4.29/arch/mips64/defconfig-ocelotc 2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-ocelotc   2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-ocelotc   2005-03-26 11:47:18.209663119 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -231,11 +231,6 @@
  #
  # CONFIG_IPX is not set
@@ -9191,9 +10845,27 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-ocelotc linux-mips/arch/mips64/defc
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -453,7 +448,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
 diff -Nur linux-2.4.29/arch/mips64/defconfig-sb1250-swarm linux-mips/arch/mips64/defconfig-sb1250-swarm
 --- linux-2.4.29/arch/mips64/defconfig-sb1250-swarm    2005-01-19 15:09:31.000000000 +0100
-+++ linux-mips/arch/mips64/defconfig-sb1250-swarm      2005-01-09 20:34:01.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-sb1250-swarm      2005-03-26 11:47:18.269653273 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
 @@ -90,6 +90,7 @@
  # CONFIG_SIBYTE_TBPROF is not set
  CONFIG_SIBYTE_GENBUS_IDE=y
@@ -9214,6 +10886,35 @@ diff -Nur linux-2.4.29/arch/mips64/defconfig-sb1250-swarm linux-mips/arch/mips64
  # CONFIG_DECNET is not set
  # CONFIG_BRIDGE is not set
  # CONFIG_X25 is not set
+@@ -432,7 +428,6 @@
+ CONFIG_SIBYTE_SB1250_DUART=y
+ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+ CONFIG_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.29/arch/mips64/defconfig-sead linux-mips/arch/mips64/defconfig-sead
+--- linux-2.4.29/arch/mips64/defconfig-sead    2005-01-19 15:09:31.000000000 +0100
++++ linux-mips/arch/mips64/defconfig-sead      2005-03-26 11:47:18.311646381 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -242,7 +242,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+ #
 diff -Nur linux-2.4.29/arch/mips64/kernel/binfmt_elfn32.c linux-mips/arch/mips64/kernel/binfmt_elfn32.c
 --- linux-2.4.29/arch/mips64/kernel/binfmt_elfn32.c    2003-08-25 13:44:40.000000000 +0200
 +++ linux-mips/arch/mips64/kernel/binfmt_elfn32.c      2005-01-31 12:59:30.000000000 +0100
@@ -9335,9 +11036,150 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/ioctl32.c linux-mips/arch/mips64/kerne
        IOCTL32_DEFAULT(AUTOFS_IOC_ASKREGHOST),
        IOCTL32_DEFAULT(AUTOFS_IOC_TOGGLEREGHOST),
        IOCTL32_DEFAULT(AUTOFS_IOC_ASKUMOUNT),
+diff -Nur linux-2.4.29/arch/mips64/kernel/linux32.c linux-mips/arch/mips64/kernel/linux32.c
+--- linux-2.4.29/arch/mips64/kernel/linux32.c  2005-01-19 15:09:32.000000000 +0100
++++ linux-mips/arch/mips64/kernel/linux32.c    2005-03-26 11:47:18.669587634 +0100
+@@ -1088,11 +1088,9 @@
+               i--;
+       }
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      retval = locks_verify_area((type == VERIFY_WRITE
+-                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                                 inode, file, file->f_pos, tot_len);
++      retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                                 file, &file->f_pos, tot_len);
+       if (retval) {
+               if (iov != iovstack)
+                       kfree(iov);
+@@ -1189,72 +1187,19 @@
+    lseek back to original location.  They fail just like lseek does on
+    non-seekable files.  */
+-asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf,
+-                             size_t count, u32 unused, u64 a4, u64 a5)
++asmlinkage ssize_t sys32_pread(unsigned int fd, char *buf,
++                                 size_t count, u32 unused, u64 a4, u64 a5)
+ {
+-      ssize_t ret;
+-      struct file * file;
+-      ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+-      loff_t pos;
+-
+-      ret = -EBADF;
+-      file = fget(fd);
+-      if (!file)
+-              goto bad_file;
+-      if (!(file->f_mode & FMODE_READ))
+-              goto out;
+-      pos = merge_64(a4, a5);
+-      ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+-                              file, pos, count);
+-      if (ret)
+-              goto out;
+-      ret = -EINVAL;
+-      if (!file->f_op || !(read = file->f_op->read))
+-              goto out;
+-      if (pos < 0)
+-              goto out;
+-      ret = read(file, buf, count, &pos);
+-      if (ret > 0)
+-              dnotify_parent(file->f_dentry, DN_ACCESS);
+-out:
+-      fput(file);
+-bad_file:
+-      return ret;
++      return sys_pread(fd, buf, count, merge_64(a4, a5));
+ }
+ asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf,
+                               size_t count, u32 unused, u64 a4, u64 a5)
+ {
+-      ssize_t ret;
+-      struct file * file;
+-      ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+-      loff_t pos;
++      return sys_pwrite(fd, buf, count, merge_64(a4, a5));
++}
+-      ret = -EBADF;
+-      file = fget(fd);
+-      if (!file)
+-              goto bad_file;
+-      if (!(file->f_mode & FMODE_WRITE))
+-              goto out;
+-      pos = merge_64(a4, a5);
+-      ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+-                              file, pos, count);
+-      if (ret)
+-              goto out;
+-      ret = -EINVAL;
+-      if (!file->f_op || !(write = file->f_op->write))
+-              goto out;
+-      if (pos < 0)
+-              goto out;
+-      ret = write(file, buf, count, &pos);
+-      if (ret > 0)
+-              dnotify_parent(file->f_dentry, DN_MODIFY);
+-out:
+-      fput(file);
+-bad_file:
+-      return ret;
+-}
+ /*
+  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
+  * 64-bit unsigned longs.
+@@ -2792,7 +2737,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -2823,6 +2769,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -2908,6 +2857,7 @@
+       struct sockaddr *uaddr;
+       int *uaddr_len;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, total_len, len = 0;
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+@@ -2923,6 +2873,7 @@
+       total_len = err;
+       cmsg_ptr = (unsigned long) kern_msg.msg_control;
++      cmsg_len = kern_msg.msg_controllen;
+       kern_msg.msg_flags = 0;
+       sock = sockfd_lookup(fd, &err);
+@@ -2948,7 +2899,8 @@
+                                * to fix it up before we tack on more stuff.
+                                */
+                               if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+-                                      cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
++                                      cmsg32_recvmsg_fixup(&kern_msg,
++                                                      cmsg_ptr, cmsg_len);
+                               /* Wheee... */
+                               if(sock->passcred)
 diff -Nur linux-2.4.29/arch/mips64/kernel/scall_64.S linux-mips/arch/mips64/kernel/scall_64.S
 --- linux-2.4.29/arch/mips64/kernel/scall_64.S 2005-01-19 15:09:32.000000000 +0100
-+++ linux-mips/arch/mips64/kernel/scall_64.S   2005-02-12 04:05:40.000000000 +0100
++++ linux-mips/arch/mips64/kernel/scall_64.S   2005-03-26 11:47:18.698582876 +0100
 @@ -102,15 +102,14 @@
  
  trace_a_syscall:
@@ -9358,7 +11200,7 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/scall_64.S linux-mips/arch/mips64/kern
        sltu    t0, t0, v0
 diff -Nur linux-2.4.29/arch/mips64/kernel/scall_n32.S linux-mips/arch/mips64/kernel/scall_n32.S
 --- linux-2.4.29/arch/mips64/kernel/scall_n32.S        2005-01-19 15:09:32.000000000 +0100
-+++ linux-mips/arch/mips64/kernel/scall_n32.S  2005-02-12 04:05:40.000000000 +0100
++++ linux-mips/arch/mips64/kernel/scall_n32.S  2005-03-26 11:47:18.734576968 +0100
 @@ -106,15 +106,14 @@
  
  trace_a_syscall:
@@ -9379,7 +11221,7 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/scall_n32.S linux-mips/arch/mips64/ker
        sltu    t0, t0, v0
 diff -Nur linux-2.4.29/arch/mips64/kernel/scall_o32.S linux-mips/arch/mips64/kernel/scall_o32.S
 --- linux-2.4.29/arch/mips64/kernel/scall_o32.S        2005-01-19 15:09:32.000000000 +0100
-+++ linux-mips/arch/mips64/kernel/scall_o32.S  2005-02-12 04:05:41.000000000 +0100
++++ linux-mips/arch/mips64/kernel/scall_o32.S  2005-03-26 11:47:18.788568107 +0100
 @@ -118,9 +118,8 @@
        sd      a6, PT_R10(sp)
        sd      a7, PT_R11(sp)
@@ -9400,6 +11242,15 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/scall_o32.S linux-mips/arch/mips64/ker
  
        li      t0, -EMAXERRNO - 1      # error?
        sltu    t0, t0, v0
+@@ -576,6 +575,8 @@
+ sys_call_table:
+       syscalltable
++      .purgem sys
++
+       .macro  sys function, nargs
+       .byte   \nargs
+       .endm
 diff -Nur linux-2.4.29/arch/mips64/kernel/setup.c linux-mips/arch/mips64/kernel/setup.c
 --- linux-2.4.29/arch/mips64/kernel/setup.c    2005-01-19 15:09:32.000000000 +0100
 +++ linux-mips/arch/mips64/kernel/setup.c      2004-11-22 14:38:26.000000000 +0100
@@ -9420,7 +11271,7 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/setup.c linux-mips/arch/mips64/kernel/
  
 diff -Nur linux-2.4.29/arch/mips64/kernel/signal_n32.c linux-mips/arch/mips64/kernel/signal_n32.c
 --- linux-2.4.29/arch/mips64/kernel/signal_n32.c       2005-01-19 15:09:33.000000000 +0100
-+++ linux-mips/arch/mips64/kernel/signal_n32.c 2005-02-12 04:05:41.000000000 +0100
++++ linux-mips/arch/mips64/kernel/signal_n32.c 2005-03-26 11:47:18.811564333 +0100
 @@ -68,7 +68,7 @@
  };
  
@@ -9490,39 +11341,6 @@ diff -Nur linux-2.4.29/arch/mips64/kernel/traps.c linux-mips/arch/mips64/kernel/
 -      current->active_mm = &init_mm;
 +      per_cpu_trap_init();
  }
-diff -Nur linux-2.4.29/arch/mips64/mm/c-r4k.c linux-mips/arch/mips64/mm/c-r4k.c
---- linux-2.4.29/arch/mips64/mm/c-r4k.c        2005-01-19 15:09:33.000000000 +0100
-+++ linux-mips/arch/mips64/mm/c-r4k.c  2005-02-12 04:05:41.000000000 +0100
-@@ -867,9 +867,16 @@
-        * normally they'd suffer from aliases but magic in the hardware deals
-        * with that for us so we don't need to take care ourselves.
-        */
--      if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
--              if (c->dcache.waysize > PAGE_SIZE)
--                      c->dcache.flags |= MIPS_CACHE_ALIASES;
-+      switch (c->cputype) {
-+      case CPU_R10000:
-+      case CPU_R12000:
-+              break;
-+      case CPU_24K:
-+              if (!(read_c0_config7() & (1 << 16)))
-+      default:
-+                      if (c->dcache.waysize > PAGE_SIZE)
-+                              c->dcache.flags |= MIPS_CACHE_ALIASES;
-+      }
-       switch (c->cputype) {
-       case CPU_20KC:
-@@ -1070,9 +1077,6 @@
-       setup_scache();
-       coherency_setup();
--      if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
--              c->dcache.flags |= MIPS_CACHE_ALIASES;
--
-       r4k_blast_dcache_page_setup();
-       r4k_blast_dcache_page_indexed_setup();
-       r4k_blast_dcache_setup();
 diff -Nur linux-2.4.29/arch/mips64/mm/cerr-sb1.c linux-mips/arch/mips64/mm/cerr-sb1.c
 --- linux-2.4.29/arch/mips64/mm/cerr-sb1.c     2004-02-18 14:36:30.000000000 +0100
 +++ linux-mips/arch/mips64/mm/cerr-sb1.c       2004-12-13 18:37:26.000000000 +0100
@@ -9570,18 +11388,110 @@ diff -Nur linux-2.4.29/arch/mips64/mm/cerr-sb1.c linux-mips/arch/mips64/mm/cerr-
                if (way == 0) {
                        lru = (taghi >> 14) & 0xff;
                        prom_printf("[Bank %d Set 0x%02x]  LRU > %d %d %d %d > MRU\n",
-diff -Nur linux-2.4.29/arch/mips64/mm/tlb-r4k.c linux-mips/arch/mips64/mm/tlb-r4k.c
---- linux-2.4.29/arch/mips64/mm/tlb-r4k.c      2005-01-19 15:09:33.000000000 +0100
-+++ linux-mips/arch/mips64/mm/tlb-r4k.c        2004-11-25 23:18:38.000000000 +0100
-@@ -1,24 +1,12 @@
- /*
-- * Carsten Langgaard, carstenl@mips.com
-- * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
-- *
-- * This program is free software; you can distribute it and/or modify it
-- * under the terms of the GNU General Public License (Version 2) as
-- * published by the Free Software Foundation.
-- *
+diff -Nur linux-2.4.29/arch/mips64/mm/c-r4k.c linux-mips/arch/mips64/mm/c-r4k.c
+--- linux-2.4.29/arch/mips64/mm/c-r4k.c        2005-01-19 15:09:33.000000000 +0100
++++ linux-mips/arch/mips64/mm/c-r4k.c  2005-03-26 11:47:18.942542836 +0100
+@@ -867,9 +867,16 @@
+        * normally they'd suffer from aliases but magic in the hardware deals
+        * with that for us so we don't need to take care ourselves.
+        */
+-      if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
+-              if (c->dcache.waysize > PAGE_SIZE)
+-                      c->dcache.flags |= MIPS_CACHE_ALIASES;
++      switch (c->cputype) {
++      case CPU_R10000:
++      case CPU_R12000:
++              break;
++      case CPU_24K:
++              if (!(read_c0_config7() & (1 << 16)))
++      default:
++                      if (c->dcache.waysize > PAGE_SIZE)
++                              c->dcache.flags |= MIPS_CACHE_ALIASES;
++      }
+       switch (c->cputype) {
+       case CPU_20KC:
+@@ -1070,9 +1077,6 @@
+       setup_scache();
+       coherency_setup();
+-      if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
+-              c->dcache.flags |= MIPS_CACHE_ALIASES;
+-
+       r4k_blast_dcache_page_setup();
+       r4k_blast_dcache_page_indexed_setup();
+       r4k_blast_dcache_setup();
+diff -Nur linux-2.4.29/arch/mips64/mm/tlbex-r4k.S linux-mips/arch/mips64/mm/tlbex-r4k.S
+--- linux-2.4.29/arch/mips64/mm/tlbex-r4k.S    2004-02-18 14:36:30.000000000 +0100
++++ linux-mips/arch/mips64/mm/tlbex-r4k.S      2004-11-25 23:18:38.000000000 +0100
+@@ -151,11 +151,9 @@
+       ld      k0, 0(k1)                       # get even pte
+       ld      k1, 8(k1)                       # get odd pte
+       PTE_RELOAD k0 k1
+-      rm9000_tlb_hazard
+-      b       1f
+-       tlbwr
+-1:    nop
+-      rm9000_tlb_hazard
++      mtc0_tlbw_hazard
++      tlbwr
++1:    tlbw_eret_hazard
+       eret
+ 9:                                            # handle the vmalloc range
+@@ -163,11 +161,9 @@
+       ld      k0, 0(k1)                       # get even pte
+       ld      k1, 8(k1)                       # get odd pte
+       PTE_RELOAD k0 k1
+-      rm9000_tlb_hazard
+-      b       1f
+-       tlbwr
+-1:    nop
+-      rm9000_tlb_hazard
++      mtc0_tlbw_hazard
++      tlbwr
++1:    tlbw_eret_hazard
+       eret
+ END(handle_vec1_r4k)
+@@ -195,10 +191,9 @@
+       ld      k0, 0(k1)                       # get even pte
+       ld      k1, 8(k1)                       # get odd pte
+       PTE_RELOAD k0 k1
+-      rm9000_tlb_hazard
+-      nop
++      mtc0_tlbw_hazard
+       tlbwr
+-      rm9000_tlb_hazard
++      tlbw_eret_hazard
+       eret
+ 9:                                            # handle the vmalloc range
+@@ -206,10 +201,9 @@
+       ld      k0, 0(k1)                       # get even pte
+       ld      k1, 8(k1)                       # get odd pte
+       PTE_RELOAD k0 k1
+-      rm9000_tlb_hazard
+-      nop
++      mtc0_tlbw_hazard
+       tlbwr
+-      rm9000_tlb_hazard
++      tlbw_eret_hazard
+       eret
+ END(handle_vec1_r10k)
+diff -Nur linux-2.4.29/arch/mips64/mm/tlb-r4k.c linux-mips/arch/mips64/mm/tlb-r4k.c
+--- linux-2.4.29/arch/mips64/mm/tlb-r4k.c      2005-01-19 15:09:33.000000000 +0100
++++ linux-mips/arch/mips64/mm/tlb-r4k.c        2004-11-25 23:18:38.000000000 +0100
+@@ -1,24 +1,12 @@
+ /*
+- * Carsten Langgaard, carstenl@mips.com
+- * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
 - * This program is distributed in the hope 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
@@ -9924,156 +11834,1598 @@ diff -Nur linux-2.4.29/arch/mips64/mm/tlb-r4k.c linux-mips/arch/mips64/mm/tlb-r4
        probe_tlb(config);
        write_c0_pagemask(PM_DEFAULT_MASK);
        write_c0_wired(0);
-diff -Nur linux-2.4.29/arch/mips64/mm/tlbex-r4k.S linux-mips/arch/mips64/mm/tlbex-r4k.S
---- linux-2.4.29/arch/mips64/mm/tlbex-r4k.S    2004-02-18 14:36:30.000000000 +0100
-+++ linux-mips/arch/mips64/mm/tlbex-r4k.S      2004-11-25 23:18:38.000000000 +0100
-@@ -151,11 +151,9 @@
-       ld      k0, 0(k1)                       # get even pte
-       ld      k1, 8(k1)                       # get odd pte
-       PTE_RELOAD k0 k1
--      rm9000_tlb_hazard
--      b       1f
--       tlbwr
--1:    nop
--      rm9000_tlb_hazard
-+      mtc0_tlbw_hazard
-+      tlbwr
-+1:    tlbw_eret_hazard
-       eret
+diff -Nur linux-2.4.29/arch/parisc/kernel/sys_parisc32.c linux-mips/arch/parisc/kernel/sys_parisc32.c
+--- linux-2.4.29/arch/parisc/kernel/sys_parisc32.c     2005-01-19 15:09:35.000000000 +0100
++++ linux-mips/arch/parisc/kernel/sys_parisc32.c       2005-03-26 11:47:18.967538734 +0100
+@@ -1671,11 +1671,9 @@
+               i--;
+       }
  
- 9:                                            # handle the vmalloc range
-@@ -163,11 +161,9 @@
-       ld      k0, 0(k1)                       # get even pte
-       ld      k1, 8(k1)                       # get odd pte
-       PTE_RELOAD k0 k1
--      rm9000_tlb_hazard
--      b       1f
--       tlbwr
--1:    nop
--      rm9000_tlb_hazard
-+      mtc0_tlbw_hazard
-+      tlbwr
-+1:    tlbw_eret_hazard
-       eret
- END(handle_vec1_r4k)
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      retval = locks_verify_area((type == VERIFY_WRITE
+-                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                                 inode, file, file->f_pos, tot_len);
++      retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                                 file, &file->f_pos, tot_len);
+       if (retval) {
+               if (iov != iovstack)
+                       kfree(iov);
+@@ -2108,7 +2106,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -2139,6 +2138,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -2224,6 +2226,7 @@
+       struct sockaddr *uaddr;
+       int *uaddr_len;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, total_len, len = 0;
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+@@ -2239,6 +2242,7 @@
+       total_len = err;
+       cmsg_ptr = (unsigned long) kern_msg.msg_control;
++      cmsg_len = kern_msg.msg_controllen;
+       kern_msg.msg_flags = 0;
+       sock = sockfd_lookup(fd, &err);
+@@ -2264,7 +2268,8 @@
+                                * to fix it up before we tack on more stuff.
+                                */
+                               if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+-                                      cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
++                                      cmsg32_recvmsg_fixup(&kern_msg,
++                                                      cmsg_ptr, cmsg_len);
+                               /* Wheee... */
+                               if(sock->passcred)
+diff -Nur linux-2.4.29/arch/ppc/kernel/cputable.c linux-mips/arch/ppc/kernel/cputable.c
+--- linux-2.4.29/arch/ppc/kernel/cputable.c    2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/arch/ppc/kernel/cputable.c      2005-03-26 11:47:18.990534959 +0100
+@@ -480,8 +480,8 @@
+         32, 32,
+         0, /*__setup_cpu_440 */
+     },
+-    { /* 440GX Rev. B1 (2.1) */
+-        0xf0000fff, 0x50000852, "440GX Rev. B1 (2.1)",
++    { /* 440GX Rev. C */
++        0xf0000fff, 0x50000892, "440GX Rev. C",
+         CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+         PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+         32, 32,
+diff -Nur linux-2.4.29/arch/ppc/kernel/head_8xx.S linux-mips/arch/ppc/kernel/head_8xx.S
+--- linux-2.4.29/arch/ppc/kernel/head_8xx.S    2004-02-18 14:36:30.000000000 +0100
++++ linux-mips/arch/ppc/kernel/head_8xx.S      2005-03-26 11:47:18.992534631 +0100
+@@ -338,13 +338,13 @@
+ 3:
+       lwz     r21, 0(r20)     /* Get the level 1 entry */
+       rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
+-      beq     2f              /* If zero, don't try to find a pte */
+       /* We have a pte table, so load the MI_TWC with the attributes
+        * for this "segment."
+        */
+       tophys(r21,r21)
+       ori     r21,r21,1               /* Set valid bit */
++      beq-    2f                      /* If zero, don't try to find a pte */
+ #ifdef CONFIG_8xx_CPU6
+       li      r3, 0x2b80
+       stw     r3, 12(r0)
+@@ -369,7 +369,7 @@
+        * set.  All other Linux PTE bits control the behavior
+        * of the MMU.
+        */
+-      li      r21, 0x00f0
++2:    li      r21, 0x00f0
+       rlwimi  r20, r21, 0, 24, 28     /* Set 24-27, clear 28 */
  
-@@ -195,10 +191,9 @@
-       ld      k0, 0(k1)                       # get even pte
-       ld      k1, 8(k1)                       # get odd pte
-       PTE_RELOAD k0 k1
--      rm9000_tlb_hazard
--      nop
-+      mtc0_tlbw_hazard
-       tlbwr
--      rm9000_tlb_hazard
-+      tlbw_eret_hazard
-       eret
+ #ifdef CONFIG_8xx_CPU6
+@@ -388,15 +388,6 @@
+ #endif
+       rfi
+-2:    mfspr   r20, M_TW       /* Restore registers */
+-      lwz     r21, 0(r0)
+-      mtcr    r21
+-      lwz     r21, 4(r0)
+-#ifdef CONFIG_8xx_CPU6
+-      lwz     r3, 8(r0)
+-#endif
+-      b       InstructionAccess
+-
+       . = 0x1200
+ DataStoreTLBMiss:
+ #ifdef CONFIG_8xx_CPU6
+@@ -422,12 +413,12 @@
+ 3:
+       lwz     r21, 0(r20)     /* Get the level 1 entry */
+       rlwinm. r20, r21,0,0,19 /* Extract page descriptor page address */
+-      beq     2f              /* If zero, don't try to find a pte */
+       /* We have a pte table, so load fetch the pte from the table.
+        */
+       tophys(r21, r21)
+       ori     r21, r21, 1     /* Set valid bit in physical L2 page */
++      beq-    2f              /* If zero, don't try to find a pte */
+ #ifdef CONFIG_8xx_CPU6
+       li      r3, 0x3b80
+       stw     r3, 12(r0)
+@@ -461,7 +452,7 @@
+        * set.  All other Linux PTE bits control the behavior
+        * of the MMU.
+        */
+-      li      r21, 0x00f0
++2:    li      r21, 0x00f0
+       rlwimi  r20, r21, 0, 24, 28     /* Set 24-27, clear 28 */
  
- 9:                                            # handle the vmalloc range
-@@ -206,10 +201,9 @@
-       ld      k0, 0(k1)                       # get even pte
-       ld      k1, 8(k1)                       # get odd pte
-       PTE_RELOAD k0 k1
--      rm9000_tlb_hazard
--      nop
-+      mtc0_tlbw_hazard
-       tlbwr
--      rm9000_tlb_hazard
-+      tlbw_eret_hazard
-       eret
- END(handle_vec1_r10k)
+ #ifdef CONFIG_8xx_CPU6
+@@ -480,24 +471,6 @@
+ #endif
+       rfi
  
-diff -Nur linux-2.4.29/drivers/char/Config.in linux-mips/drivers/char/Config.in
---- linux-2.4.29/drivers/char/Config.in        2004-08-08 01:26:04.000000000 +0200
-+++ linux-mips/drivers/char/Config.in  2005-02-12 04:06:18.000000000 +0100
-@@ -313,14 +313,11 @@
- if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
-    bool 'Tadpole ANA H8 Support (OBSOLETE)'  CONFIG_H8
- fi
--if [ "$CONFIG_MIPS" = "y" -a "$CONFIG_NEW_TIME_C" = "y" ]; then
--   tristate 'Generic MIPS RTC Support' CONFIG_MIPS_RTC
--fi
- if [ "$CONFIG_SGI_IP22" = "y" ]; then
--   bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286
-+   tristate 'Dallas DS1286 RTC support' CONFIG_DS1286
- fi
- if [ "$CONFIG_SGI_IP27" = "y" ]; then
--   bool 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
-+   tristate 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
- fi
- if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
-    tristate 'Dallas DS1742 RTC support' CONFIG_DS1742
-@@ -383,6 +380,11 @@
-       source drivers/char/drm/Config.in
-    fi
- fi
+-2:
+-      /* Copy 20 msb from MD_EPN to DAR since the dcxx instructions fail
+-       * to update DAR when they cause a DTLB miss.
+-       */
+-      mfspr   r21, MD_EPN
+-      mfspr   r20, DAR
+-      rlwimi  r20, r21, 0, 0, 19
+-      mtspr   DAR, r20
+-
+-      mfspr   r20, M_TW       /* Restore registers */
+-      lwz     r21, 0(r0)
+-      mtcr    r21
+-      lwz     r21, 4(r0)
+-#ifdef CONFIG_8xx_CPU6
+-      lwz     r3, 8(r0)
+-#endif
+-      b       DataAccess
+-
+ /* This is an instruction TLB error on the MPC8xx.  This could be due
+  * to many reasons, such as executing guarded memory or illegal instruction
+  * addresses.  There is nothing to do but handle a big time error fault.
+diff -Nur linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c linux-mips/arch/ppc64/kernel/sys_ppc32.c
+--- linux-2.4.29/arch/ppc64/kernel/sys_ppc32.c 2005-01-19 15:09:37.000000000 +0100
++++ linux-mips/arch/ppc64/kernel/sys_ppc32.c   2005-03-26 11:47:19.016530693 +0100
+@@ -183,11 +183,9 @@
+               i--;
+       }
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      retval = locks_verify_area((type == VERIFY_WRITE
+-                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                                 inode, file, file->f_pos, tot_len);
++      retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                                 file, &file->f_pos, tot_len);
+       if (retval) {
+               if (iov != iovstack)
+                       kfree(iov);
+@@ -3666,7 +3664,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -3697,6 +3696,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -3753,6 +3755,7 @@
+       struct sockaddr *uaddr;
+       int *uaddr_len;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, total_len, len = 0;
+       
+       PPCDBG(PPCDBG_SYS32, "sys32_recvmsg - entered - fd=%x, user_msg@=%p, user_flags=%x \n", fd, user_msg, user_flags);
+@@ -3770,6 +3773,7 @@
+       total_len = err;
+       cmsg_ptr = (unsigned long) kern_msg.msg_control;
++      cmsg_len = kern_msg.msg_controllen;
+       kern_msg.msg_flags = 0;
+       sock = sockfd_lookup(fd, &err);
+@@ -3795,7 +3799,8 @@
+                                * to fix it up before we tack on more stuff.
+                                */
+                               if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+-                                      cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
++                                      cmsg32_recvmsg_fixup(&kern_msg,
++                                                      cmsg_ptr, cmsg_len);
+                               /* Wheee... */
+                               if(sock->passcred)
+diff -Nur linux-2.4.29/arch/s390x/kernel/linux32.c linux-mips/arch/s390x/kernel/linux32.c
+--- linux-2.4.29/arch/s390x/kernel/linux32.c   2005-01-19 15:09:38.000000000 +0100
++++ linux-mips/arch/s390x/kernel/linux32.c     2005-03-26 11:47:19.529446512 +0100
+@@ -1108,7 +1108,6 @@
+       unsigned long tot_len;
+       struct iovec iovstack[UIO_FASTIOV];
+       struct iovec *iov=iovstack, *ivp;
+-      struct inode *inode;
+       long retval, i;
+       io_fn_t fn;
+       iov_fn_t fnv;
+@@ -1145,11 +1144,9 @@
+               i--;
+       }
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      retval = locks_verify_area((type == VERIFY_WRITE
+-                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                                 inode, file, file->f_pos, tot_len);
++      retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                                 file, &file->f_pos, tot_len);
+       if (retval)
+               goto out;
+@@ -2600,7 +2597,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -2631,6 +2629,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -2890,7 +2891,8 @@
+ static __inline__ void
+ scm_recv32(struct socket *sock, struct msghdr *msg,
+-              struct scm_cookie *scm, int flags, unsigned long cmsg_ptr)
++              struct scm_cookie *scm, int flags, unsigned long cmsg_ptr,
++              __kernel_size_t cmsg_len)
+ {
+       if(!msg->msg_control)
+       {
+@@ -2905,7 +2907,7 @@
+        * to fix it up before we tack on more stuff.
+        */
+       if((unsigned long) msg->msg_control != cmsg_ptr)
+-              cmsg32_recvmsg_fixup(msg, cmsg_ptr);
++              cmsg32_recvmsg_fixup(msg, cmsg_ptr, cmsg_len);
+       /* Wheee... */
+       if(sock->passcred)
+               put_cmsg32(msg,
+@@ -2919,14 +2921,14 @@
+ static int  
+ sock_recvmsg32(struct socket *sock, struct msghdr *msg, int size, int flags,
+-               unsigned long cmsg_ptr)
++               unsigned long cmsg_ptr, __kernel_size_t cmsg_len)
+ {
+       struct scm_cookie scm;
+       memset(&scm, 0, sizeof(scm));
+       size = sock->ops->recvmsg(sock, msg, size, flags, &scm);
+       if (size >= 0)
+-              scm_recv32(sock, msg, &scm, flags, cmsg_ptr);
++              scm_recv32(sock, msg, &scm, flags, cmsg_ptr, cmsg_len);
+       return size;
+ }
+@@ -2943,6 +2945,7 @@
+       struct iovec *iov=iovstack;
+       struct msghdr msg_sys;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, iov_size, total_len, len;
+       /* kernel mode address */
+@@ -2986,11 +2989,12 @@
+       total_len=err;
+       cmsg_ptr = (unsigned long)msg_sys.msg_control;
++      cmsg_len = msg_sys.msg_controllen;
+       msg_sys.msg_flags = 0;
+       
+       if (sock->file->f_flags & O_NONBLOCK)
+               flags |= MSG_DONTWAIT;
+-      err = sock_recvmsg32(sock, &msg_sys, total_len, flags, cmsg_ptr);
++      err = sock_recvmsg32(sock, &msg_sys, total_len, flags, cmsg_ptr, cmsg_len);
+       if (err < 0)
+               goto out_freeiov;
+       len = err;
+diff -Nur linux-2.4.29/arch/sparc/kernel/muldiv.c linux-mips/arch/sparc/kernel/muldiv.c
+--- linux-2.4.29/arch/sparc/kernel/muldiv.c    1998-01-13 00:15:43.000000000 +0100
++++ linux-mips/arch/sparc/kernel/muldiv.c      2005-03-26 11:47:19.631429774 +0100
+@@ -4,6 +4,9 @@
+  *
+  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
++ *
++ * 2004-12-25 Krzysztof Helt (krzysztof.h1@wp.pl) 
++ *            - fixed registers constrains in inline assembly declarations
+  */
+ #include <linux/kernel.h>
+@@ -125,7 +128,7 @@
+                       "mov    %%o0, %0\n\t"
+                       "mov    %%o1, %1\n\t"
+                       : "=r" (rs1), "=r" (rs2)
+-                      :
++                      : "0" (rs1), "1" (rs2)
+                       : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
+ #ifdef DEBUG_MULDIV
+               printk ("0x%x%08x\n", rs2, rs1);
+@@ -145,7 +148,7 @@
+                       "mov    %%o0, %0\n\t"
+                       "mov    %%o1, %1\n\t"
+                       : "=r" (rs1), "=r" (rs2)
+-                      :
++                      : "0" (rs1), "1" (rs2)
+                       : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc");
+ #ifdef DEBUG_MULDIV
+               printk ("0x%x%08x\n", rs2, rs1);
+@@ -174,7 +177,7 @@
+                       "mov    %%o1, %0\n\t"
+                       "mov    %%o0, %1\n\t"
+                       : "=r" (rs1), "=r" (rs2)
+-                      : "r" (regs->y)
++                      : "r" (regs->y), "0" (rs1), "1" (rs2)
+                       : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+                         "g1", "g2", "g3", "cc");
+ #ifdef DEBUG_MULDIV
+@@ -203,7 +206,7 @@
+                       "mov    %%o1, %0\n\t"
+                       "mov    %%o0, %1\n\t"
+                       : "=r" (rs1), "=r" (rs2)
+-                      : "r" (regs->y)
++                      : "r" (regs->y), "0" (rs1), "1" (rs2)
+                       : "o0", "o1", "o2", "o3", "o4", "o5", "o7",
+                         "g1", "g2", "g3", "cc");
+ #ifdef DEBUG_MULDIV
+diff -Nur linux-2.4.29/arch/sparc/kernel/process.c linux-mips/arch/sparc/kernel/process.c
+--- linux-2.4.29/arch/sparc/kernel/process.c   2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/arch/sparc/kernel/process.c     2005-03-26 11:47:19.632429610 +0100
+@@ -512,6 +512,11 @@
+               }
+       }
++#ifdef CONFIG_SMP
++      /* FPU must be disabled on SMP. */
++      childregs->psr &= ~PSR_EF;
++#endif
 +
-+if [ "$CONFIG_X86" = "y" ]; then
-+   tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
-+fi
+       /* Set the return value for the child. */
+       childregs->u_regs[UREG_I0] = current->pid;
+       childregs->u_regs[UREG_I1] = 1;
+diff -Nur linux-2.4.29/arch/sparc64/kernel/ioctl32.c linux-mips/arch/sparc64/kernel/ioctl32.c
+--- linux-2.4.29/arch/sparc64/kernel/ioctl32.c 2005-01-19 15:09:39.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/ioctl32.c   2005-03-26 11:47:19.641428133 +0100
+@@ -562,6 +562,8 @@
+       if (!(current->thread.flags & SPARC_FLAG_32BIT))
+               usp += STACK_BIAS;
++      else
++              usp &= 0xffffffffUL;
+       return (void *) (usp - len);
+ }
+@@ -696,6 +698,7 @@
+       set_fs (old_fs);
+       if (!err) {
+               switch (cmd) {
++              case TUNSETIFF:
+               case SIOCGIFFLAGS:
+               case SIOCGIFMETRIC:
+               case SIOCGIFMTU:
+diff -Nur linux-2.4.29/arch/sparc64/kernel/pci_schizo.c linux-mips/arch/sparc64/kernel/pci_schizo.c
+--- linux-2.4.29/arch/sparc64/kernel/pci_schizo.c      2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/pci_schizo.c        2005-03-26 11:47:19.646427312 +0100
+@@ -388,9 +388,9 @@
+       return ret;
+ }
+-static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,
+-                                          struct pci_dev *pdev,
+-                                          unsigned int ino)
++static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
++                                   struct pci_dev *pdev,
++                                   unsigned int ino)
+ {
+       struct ino_bucket *bucket;
+       unsigned long imap, iclr;
+@@ -444,19 +444,57 @@
+ static unsigned long stc_tag_buf[16];
+ static unsigned long stc_line_buf[16];
+-/* These offsets look weird because I keep in pbm->controller_regs
+- * the second PROM register property minus 0x10000 which is the
+- * base of the Safari and UPA64S registers of SCHIZO.
+- */
+-#define SCHIZO_PBM_A_REGS_OFF (0x600000UL - 0x400000UL)
+-#define SCHIZO_PBM_B_REGS_OFF (0x700000UL - 0x400000UL)
++#define SCHIZO_UE_INO         0x30 /* Uncorrectable ECC error */
++#define SCHIZO_CE_INO         0x31 /* Correctable ECC error */
++#define SCHIZO_PCIERR_A_INO   0x32 /* PBM A PCI bus error */
++#define SCHIZO_PCIERR_B_INO   0x33 /* PBM B PCI bus error */
++#define SCHIZO_SERR_INO               0x34 /* Safari interface error */
++
++struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
++{
++      ino &= IMAP_INO;
++      if (p->pbm_A.ino_bitmap & (1UL << ino))
++              return &p->pbm_A;
++      if (p->pbm_B.ino_bitmap & (1UL << ino))
++              return &p->pbm_B;
++
++      printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
++             "PBM_A[%016lx] PBM_B[%016lx]",
++             p->index, ino,
++             p->pbm_A.ino_bitmap,
++             p->pbm_B.ino_bitmap);
++      printk("PCI%d: Using PBM_A, report this problem immediately.\n",
++             p->index);
++
++      return &p->pbm_A;
++}
+-static void schizo_clear_other_err_intr(int irq)
++static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq)
+ {
+-      struct ino_bucket *bucket = __bucket(irq);
+-      unsigned long iclr = bucket->iclr;
++      struct pci_pbm_info *pbm;
++      struct ino_bucket *bucket;
++      unsigned long iclr;
 +
- endmenu
++      /* Do not clear the interrupt for the other PCI bus.
++       *
++       * This "ACK both PBM IRQs" only needs to be performed
++       * for chip-wide error interrupts.
++       */
++      if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO ||
++          (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO)
++              return;
++
++      pbm = pbm_for_ino(p, irq);
++      if (pbm == &p->pbm_A)
++              pbm = &p->pbm_B;
++      else
++              pbm = &p->pbm_A;
++
++      irq = schizo_irq_build(pbm, NULL,
++                             (pbm->portid << 6) | (irq & IMAP_INO));
++      bucket = __bucket(irq);
++      iclr = bucket->iclr;
  
- if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
-@@ -391,6 +393,7 @@
- if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
-    tristate ' Alchemy Au1x00 GPIO device support' CONFIG_AU1X00_GPIO
-    tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1X00_ADS7846
-+   #tristate ' Alchemy Au1550 PSC SPI support' CONFIG_AU1550_PSC_SPI
- fi
- if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
-   tristate ' ITE GPIO' CONFIG_ITE_GPIO
-diff -Nur linux-2.4.29/drivers/char/Makefile linux-mips/drivers/char/Makefile
---- linux-2.4.29/drivers/char/Makefile 2004-08-08 01:26:04.000000000 +0200
-+++ linux-mips/drivers/char/Makefile   2005-02-12 04:06:18.000000000 +0100
-@@ -48,7 +48,12 @@
-     KEYBD    =
-   endif
-   ifeq ($(CONFIG_VR41XX_KIU),y)
--    KEYMAP   =
-+    ifeq ($(CONFIG_IBM_WORKPAD),y)
-+      KEYMAP = ibm_workpad_keymap.o
-+    endif
-+    ifeq ($(CONFIG_VICTOR_MPC30X),y)
-+      KEYMAP = victor_mpc30x_keymap.o
-+    endif
-     KEYBD    = vr41xx_keyb.o
-   endif
- endif
-@@ -251,7 +256,6 @@
- obj-$(CONFIG_RTC) += rtc.o
- obj-$(CONFIG_GEN_RTC) += genrtc.o
- obj-$(CONFIG_EFI_RTC) += efirtc.o
--obj-$(CONFIG_SGI_DS1286) += ds1286.o
- obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
- obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
- ifeq ($(CONFIG_PPC),)
-@@ -259,6 +263,7 @@
- endif
- obj-$(CONFIG_TOSHIBA) += toshiba.o
- obj-$(CONFIG_I8K) += i8k.o
-+obj-$(CONFIG_DS1286) += ds1286.o
- obj-$(CONFIG_DS1620) += ds1620.o
- obj-$(CONFIG_DS1742) += ds1742.o
- obj-$(CONFIG_INTEL_RNG) += i810_rng.o
-@@ -269,6 +274,7 @@
+-      iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF);
+       upa_writel(ICLR_IDLE, iclr);
+ }
  
- obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
- obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o
-+obj-$(CONFIG_AU1550_PSC_SPI) += au1550_psc_spi.o
- obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o
- obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o
- obj-$(CONFIG_COBALT_LCD) += lcd.o
-@@ -353,3 +359,9 @@
+@@ -790,7 +828,7 @@
+       /* Interrogate IOMMU for error status. */
+       schizo_check_iommu_error(p, UE_ERR);
  
- qtronixmap.c: qtronixmap.map
-       set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+-      schizo_clear_other_err_intr(irq);
++      schizo_clear_other_err_intr(p, irq);
+ }
+ #define SCHIZO_CE_AFSR        0x10040UL
+@@ -879,7 +917,7 @@
+               printk("(none)");
+       printk("]\n");
+-      schizo_clear_other_err_intr(irq);
++      schizo_clear_other_err_intr(p, irq);
+ }
+ #define SCHIZO_PCI_AFSR       0x2010UL
+@@ -914,9 +952,9 @@
+ #define SCHIZO_PCICTRL_SBH_ERR        (1UL << 35UL) /* Safari */
+ #define SCHIZO_PCICTRL_SERR   (1UL << 34UL) /* Safari/Tomatillo */
+ #define SCHIZO_PCICTRL_PCISPD (1UL << 33UL) /* Safari */
+-#define SCHIZO_PCICTRL_MRM_PREF       (1UL << 28UL) /* Tomatillo */
+-#define SCHIZO_PCICTRL_RDO_PREF       (1UL << 27UL) /* Tomatillo */
+-#define SCHIZO_PCICTRL_RDL_PREF       (1UL << 26UL) /* Tomatillo */
++#define SCHIZO_PCICTRL_MRM_PREF       (1UL << 30UL) /* Tomatillo */
++#define SCHIZO_PCICTRL_RDO_PREF       (1UL << 29UL) /* Tomatillo */
++#define SCHIZO_PCICTRL_RDL_PREF       (1UL << 28UL) /* Tomatillo */
+ #define SCHIZO_PCICTRL_PTO    (3UL << 24UL) /* Safari/Tomatillo */
+ #define SCHIZO_PCICTRL_PTO_SHIFT 24UL
+ #define SCHIZO_PCICTRL_TRWSW  (7UL << 21UL) /* Tomatillo */
+@@ -1094,7 +1132,7 @@
+       if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
+               pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+-      schizo_clear_other_err_intr(irq);
++      schizo_clear_other_err_intr(p, irq);
+ }
+ #define SCHIZO_SAFARI_ERRLOG  0x10018UL
+@@ -1149,7 +1187,7 @@
+               printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
+                      p->index, errlog);
+-              schizo_clear_other_err_intr(irq);
++              schizo_clear_other_err_intr(p, irq);
+               return;
+       }
+@@ -1157,7 +1195,7 @@
+              p->index);
+       schizo_check_iommu_error(p, SAFARI_ERR);
+-      schizo_clear_other_err_intr(irq);
++      schizo_clear_other_err_intr(p, irq);
+ }
+ /* Nearly identical to PSYCHO equivalents... */
+@@ -1171,26 +1209,6 @@
+ #define SCHIZO_SAFARI_IRQCTRL 0x10010UL
+ #define  SCHIZO_SAFIRQCTRL_EN  0x8000000000000000UL
+-#define SCHIZO_UE_INO         0x30 /* Uncorrectable ECC error */
+-#define SCHIZO_CE_INO         0x31 /* Correctable ECC error */
+-#define SCHIZO_PCIERR_A_INO   0x32 /* PBM A PCI bus error */
+-#define SCHIZO_PCIERR_B_INO   0x33 /* PBM B PCI bus error */
+-#define SCHIZO_SERR_INO               0x34 /* Safari interface error */
+-
+-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
+-{
+-      ino &= IMAP_INO;
+-      if (p->pbm_A.ino_bitmap & (1UL << ino))
+-              return &p->pbm_A;
+-      if (p->pbm_B.ino_bitmap & (1UL << ino))
+-              return &p->pbm_B;
+-      prom_printf("TOMATILLO%d: No entry in ino bitmap for %d\n",
+-                  p->index, ino);
+-      prom_halt();
+-      /* NOTREACHED */
+-      return NULL;
+-}
+-
+ /* How the Tomatillo IRQs are routed around is pure guesswork here.
+  *
+  * All the Tomatillo devices I see in prtconf dumps seem to have only
+@@ -1964,7 +1982,7 @@
+       tmp &= ~SCHIZO_PCICTRL_PTO;
+       if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
+-          pbm->chip_version == 0x2)
++          pbm->chip_version >= 0x2)
+               tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
+       else
+               tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
+@@ -1972,8 +1990,16 @@
+       if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
+               tmp |= SCHIZO_PCICTRL_PARK;
++      if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
++          pbm->chip_version <= 0x1)
++              tmp |= (1UL << 61);
++      else
++              tmp &= ~(1UL << 61);
 +
-+ibm_workpad_keymap.c: ibm_workpad_keymap.map
-+      set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+       if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+-              tmp |= SCHIZO_PCICTRL_MRM_PREF;
++              tmp |= (SCHIZO_PCICTRL_MRM_PREF |
++                      SCHIZO_PCICTRL_RDO_PREF |
++                      SCHIZO_PCICTRL_RDL_PREF);
+       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+diff -Nur linux-2.4.29/arch/sparc64/kernel/smp.c linux-mips/arch/sparc64/kernel/smp.c
+--- linux-2.4.29/arch/sparc64/kernel/smp.c     2005-01-19 15:09:39.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/smp.c       2005-03-26 11:47:19.647427148 +0100
+@@ -1034,7 +1034,7 @@
+ void smp_capture(void)
+ {
+       if (smp_processors_ready) {
+-              int result = __atomic_add(1, &smp_capture_depth);
++              int result = atomic_add_ret(1, &smp_capture_depth);
+               membar("#StoreStore | #LoadStore");
+               if (result == 1) {
+diff -Nur linux-2.4.29/arch/sparc64/kernel/sparc64_ksyms.c linux-mips/arch/sparc64/kernel/sparc64_ksyms.c
+--- linux-2.4.29/arch/sparc64/kernel/sparc64_ksyms.c   2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/sparc64_ksyms.c     2005-03-26 11:47:19.648426984 +0100
+@@ -173,18 +173,21 @@
+ EXPORT_SYMBOL(__up);
+ /* Atomic counter implementation. */
+-EXPORT_SYMBOL(__atomic_add);
+-EXPORT_SYMBOL(__atomic_sub);
++EXPORT_SYMBOL(atomic_add);
++EXPORT_SYMBOL(atomic_add_ret);
++EXPORT_SYMBOL(atomic_sub);
++EXPORT_SYMBOL(atomic_sub_ret);
+ #ifdef CONFIG_SMP
+ EXPORT_SYMBOL(atomic_dec_and_lock);
+ #endif
+ /* Atomic bit operations. */
+-EXPORT_SYMBOL(___test_and_set_bit);
+-EXPORT_SYMBOL(___test_and_clear_bit);
+-EXPORT_SYMBOL(___test_and_change_bit);
+-EXPORT_SYMBOL(___test_and_set_le_bit);
+-EXPORT_SYMBOL(___test_and_clear_le_bit);
++EXPORT_SYMBOL(test_and_set_bit);
++EXPORT_SYMBOL(test_and_clear_bit);
++EXPORT_SYMBOL(test_and_change_bit);
++EXPORT_SYMBOL(set_bit);
++EXPORT_SYMBOL(clear_bit);
++EXPORT_SYMBOL(change_bit);
+ EXPORT_SYMBOL(ivector_table);
+ EXPORT_SYMBOL(enable_irq);
+diff -Nur linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c linux-mips/arch/sparc64/kernel/sys_sparc32.c
+--- linux-2.4.29/arch/sparc64/kernel/sys_sparc32.c     2005-01-19 15:09:39.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/sys_sparc32.c       2005-03-26 11:47:19.669423538 +0100
+@@ -505,25 +505,32 @@
+       return err;
+ }
+-static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
++static int do_sys32_msgsnd(int first, int second, int third, void *uptr)
+ {
+-      struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_USER);
+-      struct msgbuf32 *up = (struct msgbuf32 *)uptr;
++      struct msgbuf *p;
++      struct msgbuf32 *up;
+       mm_segment_t old_fs;
+       int err;
++      if (second < 0)
++              return -EINVAL;
 +
-+victor_mpc30x_keymap.c: victor_mpc30x_keymap.map
-+      set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++      p = kmalloc(second + sizeof (struct msgbuf), GFP_USER);
+       if (!p)
+               return -ENOMEM;
++
++      up = (struct msgbuf32 *)uptr;
+       err = -EFAULT;
+-      if (get_user (p->mtype, &up->mtype) ||
+-          __copy_from_user (p->mtext, &up->mtext, second))
++      if (get_user(p->mtype, &up->mtype) ||
++          __copy_from_user(p->mtext, up->mtext, second))
+               goto out;
+-      old_fs = get_fs ();
+-      set_fs (KERNEL_DS);
+-      err = sys_msgsnd (first, p, second, third);
+-      set_fs (old_fs);
++
++      old_fs = get_fs();
++      set_fs(KERNEL_DS);
++      err = sys_msgsnd(first, p, second, third);
++      set_fs(old_fs);
+ out:
+-      kfree (p);
++      kfree(p);
+       return err;
+ }
+@@ -535,6 +542,9 @@
+       mm_segment_t old_fs;
+       int err;
++      if (second < 0)
++              return -EINVAL;
++
+       if (!version) {
+               struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+               struct ipc_kludge ipck;
+@@ -560,7 +570,7 @@
+               goto free_then_out;
+       up = (struct msgbuf32 *)uptr;
+       if (put_user (p->mtype, &up->mtype) ||
+-          __copy_to_user (&up->mtext, p->mtext, err))
++          __copy_to_user (up->mtext, p->mtext, err))
+               err = -EFAULT;
+ free_then_out:
+       kfree (p);
+@@ -647,18 +657,18 @@
+       return err;
+ }
+-static int do_sys32_shmat (int first, int second, int third, int version, void *uptr)
++static int do_sys32_shmat(int first, int second, u32 third, int version, void *uptr)
+ {
+       unsigned long raddr;
+-      u32 *uaddr = (u32 *)A((u32)third);
++      u32 *uaddr = (u32 *)A(third);
+       int err = -EINVAL;
+       if (version == 1)
+               goto out;
+-      err = sys_shmat (first, uptr, second, &raddr);
++      err = sys_shmat(first, uptr, second, &raddr);
+       if (err)
+               goto out;
+-      err = put_user (raddr, uaddr);
++      err = put_user(raddr, uaddr);
+ out:
+       return err;
+ }
+@@ -770,6 +780,8 @@
+       if (!(current->thread.flags & SPARC_FLAG_32BIT))
+               usp += STACK_BIAS;
++      else
++              usp &= 0xffffffffUL;
+       return (void *) (usp - len);
+ }
+@@ -795,9 +807,11 @@
+       return sys_semtimedop(semid, tsems, nsems, t64);
+ }
+-asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
++asmlinkage int sys32_ipc (u32 call, u32 first, u32 second, u32 third, s32 __ptr, s32 __fifth)
+ {
+       int version, err;
++      u32 ptr = (u32) __ptr;
++      u32 fifth = (u32) __fifth;
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+@@ -806,15 +820,23 @@
+               switch (call) {
+               case SEMOP:
+                       /* struct sembuf is the same on 32 and 64bit :)) */
+-                      err = sys_semtimedop (first, (struct sembuf *)AA(ptr), second, NULL);
++                      err = sys_semtimedop((int)first,
++                                           (struct sembuf *)A(ptr),
++                                           second, NULL);
+                       goto out;
+               case SEMTIMEDOP:
+-                      err = sys32_semtimedop (first, (struct sembuf *)AA(ptr), second, (const struct timespec32 *) AA(fifth));
++                      err = sys32_semtimedop((int)first,
++                                             (struct sembuf *)A(ptr),
++                                             second,
++                                             (const struct timespec32 *)
++                                             A(third));
+               case SEMGET:
+-                      err = sys_semget (first, second, third);
++                      err = sys_semget((key_t)first, (int)second,
++                                       (int)third);
+                       goto out;
+               case SEMCTL:
+-                      err = do_sys32_semctl (first, second, third, (void *)AA(ptr));
++                      err = do_sys32_semctl((int)first, (int)second,
++                                            (int)third, (void *) A(ptr));
+                       goto out;
+               default:
+                       err = -ENOSYS;
+@@ -823,17 +845,20 @@
+       if (call <= MSGCTL) 
+               switch (call) {
+               case MSGSND:
+-                      err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr));
++                      err = do_sys32_msgsnd((int)first, (int)second,
++                                            (int)third, (void *)A(ptr));
+                       goto out;
+               case MSGRCV:
+-                      err = do_sys32_msgrcv (first, second, fifth, third,
+-                                             version, (void *)AA(ptr));
++                      err = do_sys32_msgrcv((int)first, (int)second,
++                                            (int)fifth, (int)third,
++                                            version, (void *)A(ptr));
+                       goto out;
+               case MSGGET:
+-                      err = sys_msgget ((key_t) first, second);
++                      err = sys_msgget((key_t)first, (int)second);
+                       goto out;
+               case MSGCTL:
+-                      err = do_sys32_msgctl (first, second, (void *)AA(ptr));
++                      err = do_sys32_msgctl((int)first, (int)second,
++                                            (void *)A(ptr));
+                       goto out;
+               default:
+                       err = -ENOSYS;
+@@ -842,17 +867,18 @@
+       if (call <= SHMCTL) 
+               switch (call) {
+               case SHMAT:
+-                      err = do_sys32_shmat (first, second, third,
+-                                            version, (void *)AA(ptr));
++                      err = do_sys32_shmat((int)first, (int)second, third,
++                                           version, (void *)A(ptr));
+                       goto out;
+               case SHMDT: 
+-                      err = sys_shmdt ((char *)AA(ptr));
++                      err = sys_shmdt((char *)A(ptr));
+                       goto out;
+               case SHMGET:
+-                      err = sys_shmget (first, second, third);
++                      err = sys_shmget((key_t)first, second, (int)third);
+                       goto out;
+               case SHMCTL:
+-                      err = do_sys32_shmctl (first, second, (void *)AA(ptr));
++                      err = do_sys32_shmctl((int)first, (int)second,
++                                            (void *)A(ptr));
+                       goto out;
+               default:
+                       err = -ENOSYS;
+@@ -1093,7 +1119,6 @@
+       __kernel_ssize_t32 tot_len;
+       struct iovec iovstack[UIO_FASTIOV];
+       struct iovec *iov=iovstack, *ivp;
+-      struct inode *inode;
+       long retval, i;
+       io_fn_t fn;
+       iov_fn_t fnv;
+@@ -1140,11 +1165,9 @@
+               i--;
+       }
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      retval = locks_verify_area((type == VERIFY_WRITE
+-                                  ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                                 inode, file, file->f_pos, tot_len);
++      retval = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                                 file, &file->f_pos, tot_len);
+       if (retval)
+               goto out;
+@@ -2160,9 +2183,6 @@
+                       timeout = (timespec_to_jiffies(&ts)
+                                  + (ts.tv_sec || ts.tv_nsec));
+-              current->state = TASK_INTERRUPTIBLE;
+-              timeout = schedule_timeout(timeout);
+-
+               if (timeout) {
+                       /* None ready -- temporarily unblock those we're
+                        * interested while we are sleeping in so that we'll
+@@ -2648,7 +2668,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -2679,6 +2700,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               if (kcmsg32->cmsg_level == SOL_SOCKET &&
+                       kcmsg32->cmsg_type == SO_TIMESTAMP) {
+                       struct timeval tv;
+@@ -2782,6 +2806,7 @@
+       struct sockaddr *uaddr;
+       int *uaddr_len;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, total_len, len = 0;
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+@@ -2797,6 +2822,7 @@
+       total_len = err;
+       cmsg_ptr = (unsigned long) kern_msg.msg_control;
++      cmsg_len = kern_msg.msg_controllen;
+       kern_msg.msg_flags = 0;
+       sock = sockfd_lookup(fd, &err);
+@@ -2822,7 +2848,8 @@
+                                * to fix it up before we tack on more stuff.
+                                */
+                               if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+-                                      cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
++                                      cmsg32_recvmsg_fixup(&kern_msg,
++                                                      cmsg_ptr, cmsg_len);
+                               /* Wheee... */
+                               if(sock->passcred)
+diff -Nur linux-2.4.29/arch/sparc64/kernel/time.c linux-mips/arch/sparc64/kernel/time.c
+--- linux-2.4.29/arch/sparc64/kernel/time.c    2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/arch/sparc64/kernel/time.c      2005-03-26 11:47:19.670423374 +0100
+@@ -770,6 +770,7 @@
+                   strcmp(model, "mk48t59") &&
+                   strcmp(model, "m5819") &&
+                   strcmp(model, "m5819p") &&
++                  strcmp(model, "m5823") &&
+                   strcmp(model, "ds1287")) {
+                       if (cbus != NULL) {
+                               prom_printf("clock_probe: Central bus lacks timer chip.\n");
+@@ -829,7 +830,8 @@
+                       if (!strcmp(model, "ds1287") ||
+                           !strcmp(model, "m5819") ||
+-                          !strcmp(model, "m5819p")) {
++                          !strcmp(model, "m5819p") ||
++                          !strcmp(model, "m5823")) {
+                               ds1287_regs = edev->resource[0].start;
+                       } else {
+                               mstk48t59_regs = edev->resource[0].start;
+@@ -850,7 +852,8 @@
+                       }
+                       if (!strcmp(model, "ds1287") ||
+                           !strcmp(model, "m5819") ||
+-                          !strcmp(model, "m5819p")) {
++                          !strcmp(model, "m5819p") ||
++                          !strcmp(model, "m5823")) {
+                               ds1287_regs = isadev->resource.start;
+                       } else {
+                               mstk48t59_regs = isadev->resource.start;
+diff -Nur linux-2.4.29/arch/sparc64/lib/atomic.S linux-mips/arch/sparc64/lib/atomic.S
+--- linux-2.4.29/arch/sparc64/lib/atomic.S     2001-12-21 18:41:53.000000000 +0100
++++ linux-mips/arch/sparc64/lib/atomic.S       2005-03-26 11:47:19.671423210 +0100
+@@ -4,33 +4,83 @@
+  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+  */
++#include <linux/config.h>
+ #include <asm/asi.h>
++      /* On SMP we need to use memory barriers to ensure
++       * correct memory operation ordering, nop these out
++       * for uniprocessor.
++       */
++#ifdef CONFIG_SMP
++#define ATOMIC_PRE_BARRIER    membar #StoreLoad | #LoadLoad
++#define ATOMIC_POST_BARRIER   membar #StoreLoad | #StoreStore
++#else
++#define ATOMIC_PRE_BARRIER    nop
++#define ATOMIC_POST_BARRIER   nop
++#endif
++
+       .text
+-      .align  64
+       .globl  atomic_impl_begin, atomic_impl_end
+-
+-      .globl  __atomic_add
+ atomic_impl_begin:
+-__atomic_add: /* %o0 = increment, %o1 = atomic_ptr */
+-      lduw    [%o1], %g5
++      /* Two versions of the atomic routines, one that
++       * does not return a value and does not perform
++       * memory barriers, and a second which returns
++       * a value and does the barriers.
++       */
++      .globl  atomic_add
++      .type   atomic_add,#function
++atomic_add: /* %o0 = increment, %o1 = atomic_ptr */
++1:    lduw    [%o1], %g5
++      add     %g5, %o0, %g7
++      cas     [%o1], %g5, %g7
++      cmp     %g5, %g7
++      bne,pn  %icc, 1b
++       nop
++      retl
++       nop
++      .size   atomic_add, .-atomic_add
++
++      .globl  atomic_sub
++      .type   atomic_sub,#function
++atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
++1:    lduw    [%o1], %g5
++      sub     %g5, %o0, %g7
++      cas     [%o1], %g5, %g7
++      cmp     %g5, %g7
++      bne,pn  %icc, 1b
++       nop
++      retl
++       nop
++      .size   atomic_sub, .-atomic_sub
++
++      .globl  atomic_add_ret
++      .type   atomic_add_ret,#function
++atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
++      ATOMIC_PRE_BARRIER
++1:    lduw    [%o1], %g5
+       add     %g5, %o0, %g7
+       cas     [%o1], %g5, %g7
+       cmp     %g5, %g7
+-      bne,pn  %icc, __atomic_add
+-       membar #StoreLoad | #StoreStore
++      bne,pn  %icc, 1b
++       add    %g7, %o0, %g7
++      ATOMIC_POST_BARRIER
+       retl
+-       add    %g7, %o0, %o0
++       sra    %g7, 0, %o0
++      .size   atomic_add_ret, .-atomic_add_ret
+-      .globl  __atomic_sub
+-__atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */
+-      lduw    [%o1], %g5
++      .globl  atomic_sub_ret
++      .type   atomic_sub_ret,#function
++atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
++      ATOMIC_PRE_BARRIER
++1:    lduw    [%o1], %g5
+       sub     %g5, %o0, %g7
+       cas     [%o1], %g5, %g7
+       cmp     %g5, %g7
+-      bne,pn  %icc, __atomic_sub
+-       membar #StoreLoad | #StoreStore
++      bne,pn  %icc, 1b
++       sub    %g7, %o0, %g7
++      ATOMIC_POST_BARRIER
+       retl
+-       sub    %g7, %o0, %o0
++       sra    %g7, 0, %o0
++      .size   atomic_sub_ret, .-atomic_sub_ret
+ atomic_impl_end:
+diff -Nur linux-2.4.29/arch/sparc64/lib/bitops.S linux-mips/arch/sparc64/lib/bitops.S
+--- linux-2.4.29/arch/sparc64/lib/bitops.S     2001-12-21 18:41:53.000000000 +0100
++++ linux-mips/arch/sparc64/lib/bitops.S       2005-03-26 11:47:19.683421241 +0100
+@@ -4,107 +4,149 @@
+  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+  */
++#include <linux/config.h>
+ #include <asm/asi.h>
++      /* On SMP we need to use memory barriers to ensure
++       * correct memory operation ordering, nop these out
++       * for uniprocessor.
++       */
++#ifdef CONFIG_SMP
++#define BITOP_PRE_BARRIER     membar #StoreLoad | #LoadLoad
++#define BITOP_POST_BARRIER    membar #StoreLoad | #StoreStore
++#else
++#define BITOP_PRE_BARRIER     nop
++#define BITOP_POST_BARRIER    nop
++#endif
++
+       .text
+-      .align  64
++
+       .globl  __bitops_begin
+ __bitops_begin:
+-      .globl  ___test_and_set_bit
+-___test_and_set_bit:  /* %o0=nr, %o1=addr */
++
++      .globl  test_and_set_bit
++      .type   test_and_set_bit,#function
++test_and_set_bit:     /* %o0=nr, %o1=addr */
++      BITOP_PRE_BARRIER
+       srlx    %o0, 6, %g1
+       mov     1, %g5
+       sllx    %g1, 3, %g3
+       and     %o0, 63, %g2
+       sllx    %g5, %g2, %g5
+       add     %o1, %g3, %o1
+-      ldx     [%o1], %g7
+-1:    andcc   %g7, %g5, %o0
+-      bne,pn  %xcc, 2f
+-       xor    %g7, %g5, %g1
++1:    ldx     [%o1], %g7
++      or      %g7, %g5, %g1
+       casx    [%o1], %g7, %g1
+       cmp     %g7, %g1
+-      bne,a,pn %xcc, 1b
+-       ldx    [%o1], %g7
+-2:    retl
+-       membar #StoreLoad | #StoreStore
+-
+-      .globl  ___test_and_clear_bit
+-___test_and_clear_bit:        /* %o0=nr, %o1=addr */
++      bne,pn  %xcc, 1b
++       and    %g7, %g5, %g2
++      BITOP_POST_BARRIER
++      clr     %o0
++      retl
++       movrne %g2, 1, %o0
++      .size   test_and_set_bit, .-test_and_set_bit
++
++      .globl  test_and_clear_bit
++      .type   test_and_clear_bit,#function
++test_and_clear_bit:   /* %o0=nr, %o1=addr */
++      BITOP_PRE_BARRIER
+       srlx    %o0, 6, %g1
+       mov     1, %g5
+       sllx    %g1, 3, %g3
+       and     %o0, 63, %g2
+       sllx    %g5, %g2, %g5
+       add     %o1, %g3, %o1
+-      ldx     [%o1], %g7
+-1:    andcc   %g7, %g5, %o0
+-      be,pn   %xcc, 2f
+-       xor    %g7, %g5, %g1
++1:    ldx     [%o1], %g7
++      andn    %g7, %g5, %g1
+       casx    [%o1], %g7, %g1
+       cmp     %g7, %g1
+-      bne,a,pn %xcc, 1b
+-       ldx    [%o1], %g7
+-2:    retl
+-       membar #StoreLoad | #StoreStore
+-
+-      .globl  ___test_and_change_bit
+-___test_and_change_bit:       /* %o0=nr, %o1=addr */
++      bne,pn  %xcc, 1b
++       and    %g7, %g5, %g2
++      BITOP_POST_BARRIER
++      clr     %o0
++      retl
++       movrne %g2, 1, %o0
++      .size   test_and_clear_bit, .-test_and_clear_bit
++
++      .globl  test_and_change_bit
++      .type   test_and_change_bit,#function
++test_and_change_bit:  /* %o0=nr, %o1=addr */
++      BITOP_PRE_BARRIER
++      srlx    %o0, 6, %g1
++      mov     1, %g5
++      sllx    %g1, 3, %g3
++      and     %o0, 63, %g2
++      sllx    %g5, %g2, %g5
++      add     %o1, %g3, %o1
++1:    ldx     [%o1], %g7
++      xor     %g7, %g5, %g1
++      casx    [%o1], %g7, %g1
++      cmp     %g7, %g1
++      bne,pn  %xcc, 1b
++       and    %g7, %g5, %g2
++      BITOP_POST_BARRIER
++      clr     %o0
++      retl
++       movrne %g2, 1, %o0
++      .size   test_and_change_bit, .-test_and_change_bit
++
++      .globl  set_bit
++      .type   set_bit,#function
++set_bit:              /* %o0=nr, %o1=addr */
++      srlx    %o0, 6, %g1
++      mov     1, %g5
++      sllx    %g1, 3, %g3
++      and     %o0, 63, %g2
++      sllx    %g5, %g2, %g5
++      add     %o1, %g3, %o1
++1:    ldx     [%o1], %g7
++      or      %g7, %g5, %g1
++      casx    [%o1], %g7, %g1
++      cmp     %g7, %g1
++      bne,pn  %xcc, 1b
++       nop
++      retl
++       nop
++      .size   set_bit, .-set_bit
++
++      .globl  clear_bit
++      .type   clear_bit,#function
++clear_bit:            /* %o0=nr, %o1=addr */
++      srlx    %o0, 6, %g1
++      mov     1, %g5
++      sllx    %g1, 3, %g3
++      and     %o0, 63, %g2
++      sllx    %g5, %g2, %g5
++      add     %o1, %g3, %o1
++1:    ldx     [%o1], %g7
++      andn    %g7, %g5, %g1
++      casx    [%o1], %g7, %g1
++      cmp     %g7, %g1
++      bne,pn  %xcc, 1b
++       nop
++      retl
++       nop
++      .size   clear_bit, .-clear_bit
++
++      .globl  change_bit
++      .type   change_bit,#function
++change_bit:           /* %o0=nr, %o1=addr */
+       srlx    %o0, 6, %g1
+       mov     1, %g5
+       sllx    %g1, 3, %g3
+       and     %o0, 63, %g2
+       sllx    %g5, %g2, %g5
+       add     %o1, %g3, %o1
+-      ldx     [%o1], %g7
+-1:    and     %g7, %g5, %o0
++1:    ldx     [%o1], %g7
+       xor     %g7, %g5, %g1
+       casx    [%o1], %g7, %g1
+       cmp     %g7, %g1
+-      bne,a,pn %xcc, 1b
+-       ldx    [%o1], %g7
+-2:    retl
+-       membar #StoreLoad | #StoreStore
+-      nop
+-
+-      .globl  ___test_and_set_le_bit
+-___test_and_set_le_bit:       /* %o0=nr, %o1=addr */
+-      srlx    %o0, 5, %g1
+-      mov     1, %g5
+-      sllx    %g1, 2, %g3
+-      and     %o0, 31, %g2
+-      sllx    %g5, %g2, %g5
+-      add     %o1, %g3, %o1
+-      lduwa   [%o1] ASI_PL, %g7
+-1:    andcc   %g7, %g5, %o0
+-      bne,pn  %icc, 2f
+-       xor    %g7, %g5, %g1
+-      casa    [%o1] ASI_PL, %g7, %g1
+-      cmp     %g7, %g1
+-      bne,a,pn %icc, 1b
+-       lduwa  [%o1] ASI_PL, %g7
+-2:    retl
+-       membar #StoreLoad | #StoreStore
+-
+-      .globl  ___test_and_clear_le_bit
+-___test_and_clear_le_bit:     /* %o0=nr, %o1=addr */
+-      srlx    %o0, 5, %g1
+-      mov     1, %g5
+-      sllx    %g1, 2, %g3
+-      and     %o0, 31, %g2
+-      sllx    %g5, %g2, %g5
+-      add     %o1, %g3, %o1
+-      lduwa   [%o1] ASI_PL, %g7
+-1:    andcc   %g7, %g5, %o0
+-      be,pn   %icc, 2f
+-       xor    %g7, %g5, %g1
+-      casa    [%o1] ASI_PL, %g7, %g1
+-      cmp     %g7, %g1
+-      bne,a,pn %icc, 1b
+-       lduwa  [%o1] ASI_PL, %g7
+-2:    retl
+-       membar #StoreLoad | #StoreStore
++      bne,pn  %xcc, 1b
++       nop
++      retl
++       nop
++      .size   change_bit, .-change_bit
+       .globl  __bitops_end
+ __bitops_end:
+diff -Nur linux-2.4.29/arch/sparc64/lib/debuglocks.c linux-mips/arch/sparc64/lib/debuglocks.c
+--- linux-2.4.29/arch/sparc64/lib/debuglocks.c 2001-12-21 18:41:53.000000000 +0100
++++ linux-mips/arch/sparc64/lib/debuglocks.c   2005-03-26 11:47:19.684421077 +0100
+@@ -162,6 +162,7 @@
+ runlock_again:
+       /* Spin trying to decrement the counter using casx.  */
+       __asm__ __volatile__(
++"     membar  #StoreLoad | #LoadLoad\n"
+ "     ldx     [%0], %%g5\n"
+ "     sub     %%g5, 1, %%g7\n"
+ "     casx    [%0], %%g5, %%g7\n"
+@@ -276,6 +277,7 @@
+       current->thread.smp_lock_count--;
+ wlock_again:
+       __asm__ __volatile__(
++"     membar  #StoreLoad | #LoadLoad\n"
+ "     mov     1, %%g3\n"
+ "     sllx    %%g3, 63, %%g3\n"
+ "     ldx     [%0], %%g5\n"
+diff -Nur linux-2.4.29/arch/sparc64/lib/rwlock.S linux-mips/arch/sparc64/lib/rwlock.S
+--- linux-2.4.29/arch/sparc64/lib/rwlock.S     2000-09-09 02:55:17.000000000 +0200
++++ linux-mips/arch/sparc64/lib/rwlock.S       2005-03-26 11:47:19.689420256 +0100
+@@ -24,12 +24,13 @@
+ 99:   retl
+        nop
+ __read_unlock: /* %o0 = lock_ptr */
++      membar          #StoreLoad | #LoadLoad
+       lduw            [%o0], %g5
+       sub             %g5, 1, %g7
+       cas             [%o0], %g5, %g7
+       cmp             %g5, %g7
+       be,pt           %xcc, 99b
+-       membar         #StoreLoad | #StoreStore
++       nop
+       ba,a,pt         %xcc, __read_unlock
+ __read_wait_for_writer:
+diff -Nur linux-2.4.29/arch/x86_64/ia32/socket32.c linux-mips/arch/x86_64/ia32/socket32.c
+--- linux-2.4.29/arch/x86_64/ia32/socket32.c   2005-01-19 15:09:39.000000000 +0100
++++ linux-mips/arch/x86_64/ia32/socket32.c     2005-03-26 11:47:19.905384811 +0100
+@@ -302,7 +302,8 @@
+  *            IPV6_RTHDR      ipv6 routing exthdr     32-bit clean
+  *            IPV6_AUTHHDR    ipv6 auth exthdr        32-bit clean
+  */
+-static void cmsg32_recvmsg_fixup(struct msghdr *kmsg, unsigned long orig_cmsg_uptr)
++static void cmsg32_recvmsg_fixup(struct msghdr *kmsg,
++              unsigned long orig_cmsg_uptr, __kernel_size_t orig_cmsg_len)
+ {
+       unsigned char *workbuf, *wp;
+       unsigned long bufsz, space_avail;
+@@ -333,6 +334,9 @@
+               __get_user(kcmsg32->cmsg_type, &ucmsg->cmsg_type);
+               clen64 = kcmsg32->cmsg_len;
++              if ((clen64 < CMSG_ALIGN(sizeof(*ucmsg))) ||
++                              (clen64 > (orig_cmsg_len + wp - workbuf)))
++                      break;
+               copy_from_user(CMSG32_DATA(kcmsg32), CMSG_DATA(ucmsg),
+                              clen64 - CMSG_ALIGN(sizeof(*ucmsg)));
+               clen32 = ((clen64 - CMSG_ALIGN(sizeof(*ucmsg))) +
+@@ -418,6 +422,7 @@
+       struct sockaddr *uaddr;
+       int *uaddr_len;
+       unsigned long cmsg_ptr;
++      __kernel_size_t cmsg_len;
+       int err, total_len, len = 0;
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
+@@ -433,6 +438,7 @@
+       total_len = err;
+       cmsg_ptr = (unsigned long) kern_msg.msg_control;
++      cmsg_len = kern_msg.msg_controllen;
+       kern_msg.msg_flags = 0;
+       sock = sockfd_lookup(fd, &err);
+@@ -458,7 +464,8 @@
+                                * to fix it up before we tack on more stuff.
+                                */
+                               if((unsigned long) kern_msg.msg_control != cmsg_ptr)
+-                                      cmsg32_recvmsg_fixup(&kern_msg, cmsg_ptr);
++                                      cmsg32_recvmsg_fixup(&kern_msg,
++                                                      cmsg_ptr, cmsg_len);
+                               /* Wheee... */
+                               if(sock->passcred)
+diff -Nur linux-2.4.29/arch/x86_64/kernel/acpi.c linux-mips/arch/x86_64/kernel/acpi.c
+--- linux-2.4.29/arch/x86_64/kernel/acpi.c     2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/arch/x86_64/kernel/acpi.c       2005-03-26 11:47:19.976373161 +0100
+@@ -53,6 +53,7 @@
+ acpi_interrupt_flags acpi_sci_flags __initdata;
+ int acpi_sci_override_gsi __initdata;
++int acpi_skip_timer_override __initdata;
+ /* --------------------------------------------------------------------------
+                               Boot-time Configuration
+    -------------------------------------------------------------------------- */
+@@ -333,6 +334,12 @@
+               return 0;
+       }
++      if (acpi_skip_timer_override &&
++              intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
++              printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
++              return 0;
++      }
++
+       mp_override_legacy_irq (
+               intsrc->bus_irq,
+               intsrc->flags.polarity,
+diff -Nur linux-2.4.29/arch/x86_64/kernel/io_apic.c linux-mips/arch/x86_64/kernel/io_apic.c
+--- linux-2.4.29/arch/x86_64/kernel/io_apic.c  2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/arch/x86_64/kernel/io_apic.c    2005-03-26 11:47:19.977372996 +0100
+@@ -259,10 +259,14 @@
+                               case PCI_VENDOR_ID_VIA:
+                                       return;
+                               case PCI_VENDOR_ID_NVIDIA: 
++#ifdef CONFIG_ACPI
++                              /* All timer overrides on Nvidia
++                                 seem to be wrong. Skip them. */
++                                      acpi_skip_timer_override = 1;
+                                       printk(KERN_INFO 
+-     "PCI bridge %02x:%02x from %x found. Setting \"noapic\". Overwrite with \"apic\"\n",
+-                                             num,slot,vendor); 
+-                                      skip_ioapic_setup = 1;
++                      "Nvidia board detected. Ignoring ACPI timer override.\n");
++#endif
++                                      /* RED-PEN skip them on mptables too? */
+                                       return;
+                               } 
+diff -Nur linux-2.4.29/arch/x86_64/kernel/pci-irq.c linux-mips/arch/x86_64/kernel/pci-irq.c
+--- linux-2.4.29/arch/x86_64/kernel/pci-irq.c  2003-08-25 13:44:40.000000000 +0200
++++ linux-mips/arch/x86_64/kernel/pci-irq.c    2005-03-26 11:47:20.061359212 +0100
+@@ -742,7 +742,7 @@
+ void pcibios_enable_irq(struct pci_dev *dev)
+ {
+               u8 pin;
+-      extern int interrupt_line_quirk;
++      extern int via_interrupt_line_quirk;
+               pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) {
+@@ -762,6 +762,6 @@
+       }
+       /* VIA bridges use interrupt line for apic/pci steering across
+          the V-Link */
+-      else if (interrupt_line_quirk)
++      else if (via_interrupt_line_quirk)
+               pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ }
+diff -Nur linux-2.4.29/arch/x86_64/kernel/setup.c linux-mips/arch/x86_64/kernel/setup.c
+--- linux-2.4.29/arch/x86_64/kernel/setup.c    2005-01-19 15:09:39.000000000 +0100
++++ linux-mips/arch/x86_64/kernel/setup.c      2005-03-26 11:47:20.069357900 +0100
+@@ -93,7 +93,8 @@
+ struct resource standard_io_resources[] = {
+       { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+       { "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+-      { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
++      { "timer0", 0x40, 0x43, IORESOURCE_BUSY },
++      { "timer1", 0x50, 0x53, IORESOURCE_BUSY },
+       { "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+       { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+       { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+diff -Nur linux-2.4.29/Documentation/Changes linux-mips/Documentation/Changes
+--- linux-2.4.29/Documentation/Changes 2005-01-19 15:09:22.000000000 +0100
++++ linux-mips/Documentation/Changes   2005-03-26 11:47:05.688718095 +0100
+@@ -341,7 +341,7 @@
+ JFSutils
+ ---------
+-o  <http://oss.software.ibm.com/jfs/>
++o  <http://jfs.sourceforge.net/>
+ Reiserfsprogs
+ -------------
+diff -Nur linux-2.4.29/Documentation/Configure.help linux-mips/Documentation/Configure.help
+--- linux-2.4.29/Documentation/Configure.help  2005-01-19 15:09:22.000000000 +0100
++++ linux-mips/Documentation/Configure.help    2005-03-26 11:47:12.272637522 +0100
+@@ -9345,6 +9345,11 @@
+   If unsure, say N.
++CONFIG_SCSI_SATA_QSTOR
++  This option enables support for Pacific Digital Serial ATA QStor.
++
++  If unsure, say N.
++
+ CONFIG_SCSI_SATA_SX4
+   This option enables support for Promise Serial ATA SX4.
+diff -Nur linux-2.4.29/Documentation/filesystems/jfs.txt linux-mips/Documentation/filesystems/jfs.txt
+--- linux-2.4.29/Documentation/filesystems/jfs.txt     2003-11-28 19:26:19.000000000 +0100
++++ linux-mips/Documentation/filesystems/jfs.txt       2005-03-26 11:47:12.320629645 +0100
+@@ -1,13 +1,6 @@
+ IBM's Journaled File System (JFS) for Linux
+-JFS Homepage:  http://oss.software.ibm.com/jfs/
+-
+-Team members
+-------------
+-Dave Kleikamp      shaggy@austin.ibm.com  
+-Dave Blaschke      blaschke@us.ibm.com
+-Steve Best         sbest@us.ibm.com
+-Barry Arndt        barndt@us.ibm.com
++JFS Homepage:  http://jfs.sourceforge.net/
+ The following mount options are supported:
+@@ -15,7 +8,8 @@
+               ASCII.  The default is compiled into the kernel as
+               CONFIG_NLS_DEFAULT.  Use iocharset=utf8 for UTF8
+               translations.  This requires CONFIG_NLS_UTF8 to be set
+-              in the kernel .config file.
++              in the kernel .config file.  Specify iocharset=none for
++              no conversion (default linux-2.6 behavior).
+ resize=value  Resize the volume to <value> blocks.  JFS only supports
+               growing a volume, not shrinking it.  This option is only
+@@ -51,4 +45,4 @@
+ Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
+ The JFS mailing list can be subscribed to by using the link labeled
+-"Mail list Subscribe" at our web page http://oss.software.ibm.com/jfs/.
++"Mail list Subscribe" at our web page http://jfs.sourceforge.net/.
+diff -Nur linux-2.4.29/Documentation/i2c/writing-clients linux-mips/Documentation/i2c/writing-clients
+--- linux-2.4.29/Documentation/i2c/writing-clients     2004-11-17 12:54:20.000000000 +0100
++++ linux-mips/Documentation/i2c/writing-clients       2005-03-26 11:47:12.338626691 +0100
+@@ -380,9 +380,6 @@
+ For now, you can ignore the `flags' parameter. It is there for future use.
+-  /* Unique ID allocation */
+-  static int foo_id = 0;
+-
+   int foo_detect_client(struct i2c_adapter *adapter, int address, 
+                         unsigned short flags, int kind)
+   {
+@@ -518,7 +515,6 @@
+     data->type = kind;
+     /* SENSORS ONLY END */
+-    new_client->id = foo_id++; /* Automatically unique */
+     data->valid = 0; /* Only if you use this field */
+     init_MUTEX(&data->update_lock); /* Only if you use this field */
+diff -Nur linux-2.4.29/drivers/acpi/pci_irq.c linux-mips/drivers/acpi/pci_irq.c
+--- linux-2.4.29/drivers/acpi/pci_irq.c        2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/drivers/acpi/pci_irq.c  2005-03-26 11:47:20.083355602 +0100
+@@ -335,6 +335,7 @@
+ {
+       int                     irq = 0;
+       u8                      pin = 0;
++      extern int via_interrupt_line_quirk;
+       ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
+@@ -383,6 +384,9 @@
+               }
+       }
++      if (via_interrupt_line_quirk)
++              pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15);
++
+       dev->irq = irq;
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ %d\n", dev->slot_name, dev->irq));
+diff -Nur linux-2.4.29/drivers/block/nbd.c linux-mips/drivers/block/nbd.c
+--- linux-2.4.29/drivers/block/nbd.c   2003-08-25 13:44:41.000000000 +0200
++++ linux-mips/drivers/block/nbd.c     2005-03-26 11:47:20.373308014 +0100
+@@ -408,10 +408,7 @@
+       int dev, error, temp;
+       struct request sreq ;
+-      /* Anyone capable of this syscall can do *real bad* things */
+-      if (!capable(CAP_SYS_ADMIN))
+-              return -EPERM;
+       if (!inode)
+               return -EINVAL;
+       dev = MINOR(inode->i_rdev);
+@@ -419,6 +416,20 @@
+               return -ENODEV;
+       lo = &nbd_dev[dev];
++
++      /* these are innocent, but.... */
++      switch (cmd) {
++      case BLKGETSIZE:
++              return put_user(nbd_bytesizes[dev] >> 9, (unsigned long *) arg);
++      case BLKGETSIZE64:
++              return put_user((u64)nbd_bytesizes[dev], (u64 *) arg);
++      }
++
++      /* ... anyone capable of any of the below ioctls can do *real bad* 
++         things */
++      if (!capable(CAP_SYS_ADMIN))
++              return -EPERM;
++
+       switch (cmd) {
+       case NBD_DISCONNECT:
+               printk("NBD_DISCONNECT\n");
+@@ -524,10 +535,6 @@
+                      dev, lo->queue_head.next, lo->queue_head.prev, requests_in, requests_out);
+               return 0;
+ #endif
+-      case BLKGETSIZE:
+-              return put_user(nbd_bytesizes[dev] >> 9, (unsigned long *) arg);
+-      case BLKGETSIZE64:
+-              return put_user((u64)nbd_bytesizes[dev], (u64 *) arg);
+       }
+       return -EINVAL;
+ }
 diff -Nur linux-2.4.29/drivers/char/au1000_gpio.c linux-mips/drivers/char/au1000_gpio.c
 --- linux-2.4.29/drivers/char/au1000_gpio.c    2003-08-25 13:44:41.000000000 +0200
 +++ linux-mips/drivers/char/au1000_gpio.c      2003-12-20 14:18:51.000000000 +0100
@@ -10088,7 +13440,7 @@ diff -Nur linux-2.4.29/drivers/char/au1000_gpio.c linux-mips/drivers/char/au1000
  };
 diff -Nur linux-2.4.29/drivers/char/au1550_psc_spi.c linux-mips/drivers/char/au1550_psc_spi.c
 --- linux-2.4.29/drivers/char/au1550_psc_spi.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/char/au1550_psc_spi.c   2005-02-12 04:06:18.000000000 +0100
++++ linux-mips/drivers/char/au1550_psc_spi.c   2005-03-26 11:47:20.510285533 +0100
 @@ -0,0 +1,466 @@
 +/*
 + *  Driver for Alchemy Au1550 SPI on the PSC.
@@ -10556,6 +13908,46 @@ diff -Nur linux-2.4.29/drivers/char/au1550_psc_spi.c linux-mips/drivers/char/au1
 +
 +module_init(au1550spi_init);
 +module_exit(au1550spi_exit);
+diff -Nur linux-2.4.29/drivers/char/Config.in linux-mips/drivers/char/Config.in
+--- linux-2.4.29/drivers/char/Config.in        2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/drivers/char/Config.in  2005-03-26 11:47:20.469292261 +0100
+@@ -313,14 +313,11 @@
+ if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
+    bool 'Tadpole ANA H8 Support (OBSOLETE)'  CONFIG_H8
+ fi
+-if [ "$CONFIG_MIPS" = "y" -a "$CONFIG_NEW_TIME_C" = "y" ]; then
+-   tristate 'Generic MIPS RTC Support' CONFIG_MIPS_RTC
+-fi
+ if [ "$CONFIG_SGI_IP22" = "y" ]; then
+-   bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286
++   tristate 'Dallas DS1286 RTC support' CONFIG_DS1286
+ fi
+ if [ "$CONFIG_SGI_IP27" = "y" ]; then
+-   bool 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
++   tristate 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
+ fi
+ if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
+    tristate 'Dallas DS1742 RTC support' CONFIG_DS1742
+@@ -383,6 +380,11 @@
+       source drivers/char/drm/Config.in
+    fi
+ fi
++
++if [ "$CONFIG_X86" = "y" ]; then
++   tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
++fi
++
+ endmenu
+ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+@@ -391,6 +393,7 @@
+ if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+    tristate ' Alchemy Au1x00 GPIO device support' CONFIG_AU1X00_GPIO
+    tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1X00_ADS7846
++   #tristate ' Alchemy Au1550 PSC SPI support' CONFIG_AU1550_PSC_SPI
+ fi
+ if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
+   tristate ' ITE GPIO' CONFIG_ITE_GPIO
 diff -Nur linux-2.4.29/drivers/char/decserial.c linux-mips/drivers/char/decserial.c
 --- linux-2.4.29/drivers/char/decserial.c      2003-08-25 13:44:41.000000000 +0200
 +++ linux-mips/drivers/char/decserial.c        2004-09-28 02:53:01.000000000 +0200
@@ -12544,22 +15936,136 @@ diff -Nur linux-2.4.29/drivers/char/ip27-rtc.c linux-mips/drivers/char/ip27-rtc.
 +MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
 +MODULE_DESCRIPTION("SGI IP27 M48T35 RTC driver");
 +MODULE_LICENSE("GPL");
-diff -Nur linux-2.4.29/drivers/char/mips_rtc.c linux-mips/drivers/char/mips_rtc.c
---- linux-2.4.29/drivers/char/mips_rtc.c       2004-01-05 14:53:56.000000000 +0100
-+++ linux-mips/drivers/char/mips_rtc.c 2004-06-28 14:54:53.000000000 +0200
-@@ -53,14 +53,6 @@
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <asm/system.h>
+diff -Nur linux-2.4.29/drivers/char/lcd.c linux-mips/drivers/char/lcd.c
+--- linux-2.4.29/drivers/char/lcd.c    2005-01-19 15:09:46.000000000 +0100
++++ linux-mips/drivers/char/lcd.c      2005-03-26 11:47:20.582273718 +0100
+@@ -386,6 +386,8 @@
+               int ctr=0;
++              if (!capable(CAP_SYS_ADMIN)) return -EPERM;
++
+                   // Chip Erase Sequence
+               WRITE_FLASH( kFlash_Addr1, kFlash_Data1 );
+               WRITE_FLASH( kFlash_Addr2, kFlash_Data2 );
+@@ -422,6 +424,8 @@
+                 struct lcd_display display;
++              if (!capable(CAP_SYS_ADMIN)) return -EPERM;
++
+                 if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
+                 return -EFAULT;
+               rom = (unsigned char *) kmalloc((128),GFP_ATOMIC);
+@@ -434,8 +438,10 @@
+               save_flags(flags);
+               for (i=0; i<FLASH_SIZE; i=i+128) {
+-                      if(copy_from_user(rom, display.RomImage + i, 128))
++                      if(copy_from_user(rom, display.RomImage + i, 128)) {
++                         kfree(rom);
+                          return -EFAULT;
++                      }
+                       burn_addr = kFlashBase + i;
+                       cli();
+                       for ( index = 0; index < ( 128 ) ; index++ ) 
+diff -Nur linux-2.4.29/drivers/char/lp.c linux-mips/drivers/char/lp.c
+--- linux-2.4.29/drivers/char/lp.c     2005-01-19 15:09:46.000000000 +0100
++++ linux-mips/drivers/char/lp.c       2005-03-26 11:47:20.584273390 +0100
+@@ -314,12 +314,14 @@
+       if (copy_size > LP_BUFFER_SIZE)
+               copy_size = LP_BUFFER_SIZE;
+-      if (copy_from_user (kbuf, buf, copy_size))
+-              return -EFAULT;
 -
--/*
-- * Check machine
-- */
--#if !defined(CONFIG_MIPS) || !defined(CONFIG_NEW_TIME_C)
--#error "This driver is for MIPS machines with CONFIG_NEW_TIME_C defined"
--#endif
+       if (down_interruptible (&lp_table[minor].port_mutex))
+               return -EINTR;
++      if (copy_from_user (kbuf, buf, copy_size)) {
++              retv = -EFAULT;
++              goto out_unlock;
++      }
++
+       /* Claim Parport or sleep until it becomes available
+        */
+       lp_claim_parport_or_block (&lp_table[minor]);
+@@ -398,7 +400,7 @@
+               lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
+               lp_release_parport (&lp_table[minor]);
+       }
 -
- #include <asm/time.h>
++out_unlock:
+       up (&lp_table[minor].port_mutex);
+       return retv;
+diff -Nur linux-2.4.29/drivers/char/Makefile linux-mips/drivers/char/Makefile
+--- linux-2.4.29/drivers/char/Makefile 2004-08-08 01:26:04.000000000 +0200
++++ linux-mips/drivers/char/Makefile   2005-03-26 11:47:20.471291933 +0100
+@@ -48,7 +48,12 @@
+     KEYBD    =
+   endif
+   ifeq ($(CONFIG_VR41XX_KIU),y)
+-    KEYMAP   =
++    ifeq ($(CONFIG_IBM_WORKPAD),y)
++      KEYMAP = ibm_workpad_keymap.o
++    endif
++    ifeq ($(CONFIG_VICTOR_MPC30X),y)
++      KEYMAP = victor_mpc30x_keymap.o
++    endif
+     KEYBD    = vr41xx_keyb.o
+   endif
+ endif
+@@ -251,7 +256,6 @@
+ obj-$(CONFIG_RTC) += rtc.o
+ obj-$(CONFIG_GEN_RTC) += genrtc.o
+ obj-$(CONFIG_EFI_RTC) += efirtc.o
+-obj-$(CONFIG_SGI_DS1286) += ds1286.o
+ obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
+ ifeq ($(CONFIG_PPC),)
+@@ -259,6 +263,7 @@
+ endif
+ obj-$(CONFIG_TOSHIBA) += toshiba.o
+ obj-$(CONFIG_I8K) += i8k.o
++obj-$(CONFIG_DS1286) += ds1286.o
+ obj-$(CONFIG_DS1620) += ds1620.o
+ obj-$(CONFIG_DS1742) += ds1742.o
+ obj-$(CONFIG_INTEL_RNG) += i810_rng.o
+@@ -269,6 +274,7 @@
+ obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
+ obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o
++obj-$(CONFIG_AU1550_PSC_SPI) += au1550_psc_spi.o
+ obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o
+ obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o
+ obj-$(CONFIG_COBALT_LCD) += lcd.o
+@@ -353,3 +359,9 @@
+ qtronixmap.c: qtronixmap.map
+       set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++ibm_workpad_keymap.c: ibm_workpad_keymap.map
++      set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++victor_mpc30x_keymap.c: victor_mpc30x_keymap.map
++      set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+diff -Nur linux-2.4.29/drivers/char/mips_rtc.c linux-mips/drivers/char/mips_rtc.c
+--- linux-2.4.29/drivers/char/mips_rtc.c       2004-01-05 14:53:56.000000000 +0100
++++ linux-mips/drivers/char/mips_rtc.c 2004-06-28 14:54:53.000000000 +0200
+@@ -53,14 +53,6 @@
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+-
+-/*
+- * Check machine
+- */
+-#if !defined(CONFIG_MIPS) || !defined(CONFIG_NEW_TIME_C)
+-#error "This driver is for MIPS machines with CONFIG_NEW_TIME_C defined"
+-#endif
+-
+ #include <asm/time.h>
  
  static unsigned long rtc_status = 0;  /* bitmapped status byte.       */
 diff -Nur linux-2.4.29/drivers/char/sb1250_duart.c linux-mips/drivers/char/sb1250_duart.c
@@ -12667,6 +16173,34 @@ diff -Nur linux-2.4.29/drivers/char/serial.c linux-mips/drivers/char/serial.c
  
  /*
   * We used to support using pause I/O for certain machines.  We
+diff -Nur linux-2.4.29/drivers/char/synclinkmp.c linux-mips/drivers/char/synclinkmp.c
+--- linux-2.4.29/drivers/char/synclinkmp.c     2005-01-19 15:09:53.000000000 +0100
++++ linux-mips/drivers/char/synclinkmp.c       2005-03-26 11:47:20.653262067 +0100
+@@ -1,5 +1,5 @@
+ /*
+- * $Id$
++ * $Id$
+  *
+  * Device driver for Microgate SyncLink Multiport
+  * high speed multiprotocol serial adapter.
+@@ -504,7 +504,7 @@
+ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
+ static char *driver_name = "SyncLink MultiPort driver";
+-static char *driver_version = "$Revision$";
++static char *driver_version = "$Revision$";
+ static int __devinit synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
+ static void __devexit synclinkmp_remove_one(struct pci_dev *dev);
+@@ -4482,7 +4482,7 @@
+        * 07..05  Reserved, must be 0
+        * 04..00  RRC<4..0> Rx FIFO trigger active 0x00 = 1 byte
+        */
+-      write_reg(info, TRC0, 0x00);
++      write_reg(info, RRC, 0x00);
+       /* TRC0 Transmit Ready Control 0
+        *
 diff -Nur linux-2.4.29/drivers/char/victor_mpc30x_keymap.map linux-mips/drivers/char/victor_mpc30x_keymap.map
 --- linux-2.4.29/drivers/char/victor_mpc30x_keymap.map 1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/drivers/char/victor_mpc30x_keymap.map   2004-02-05 18:04:42.000000000 +0100
@@ -12796,7 +16330,7 @@ diff -Nur linux-2.4.29/drivers/char/vr41xx_keyb.c linux-mips/drivers/char/vr41xx
  
 diff -Nur linux-2.4.29/drivers/i2c/Config.in linux-mips/drivers/i2c/Config.in
 --- linux-2.4.29/drivers/i2c/Config.in 2004-04-14 15:05:29.000000000 +0200
-+++ linux-mips/drivers/i2c/Config.in   2005-02-12 04:06:32.000000000 +0100
++++ linux-mips/drivers/i2c/Config.in   2005-03-26 11:47:20.974209393 +0100
 @@ -57,6 +57,10 @@
     if [ "$CONFIG_SGI_IP22" = "y" ]; then
        dep_tristate 'I2C SGI interfaces' CONFIG_I2C_ALGO_SGI $CONFIG_I2C
@@ -12806,31 +16340,11 @@ diff -Nur linux-2.4.29/drivers/i2c/Config.in linux-mips/drivers/i2c/Config.in
 +      dep_tristate 'Au1550/Au1200 SMBus interface' CONFIG_I2C_ALGO_AU1550 $CONFIG_I2C
 +   fi
   
- # This is needed for automatic patch generation: sensors code starts here
- # This is needed for automatic patch generation: sensors code ends here
-diff -Nur linux-2.4.29/drivers/i2c/Makefile linux-mips/drivers/i2c/Makefile
---- linux-2.4.29/drivers/i2c/Makefile  2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/i2c/Makefile    2005-02-12 04:06:32.000000000 +0100
-@@ -6,7 +6,7 @@
- export-objs   := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
-                  i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
--                 i2c-proc.o
-+                 i2c-algo-au1550.o i2c-proc.o i2c-au1550.o
- obj-$(CONFIG_I2C)             += i2c-core.o
- obj-$(CONFIG_I2C_CHARDEV)     += i2c-dev.o
-@@ -25,6 +25,7 @@
- obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o
- obj-$(CONFIG_I2C_MAX1617)     += i2c-max1617.o
- obj-$(CONFIG_I2C_ALGO_SGI)    += i2c-algo-sgi.o
-+obj-$(CONFIG_I2C_ALGO_AU1550) += i2c-algo-au1550.o i2c-au1550.o
  # This is needed for automatic patch generation: sensors code starts here
  # This is needed for automatic patch generation: sensors code ends here
 diff -Nur linux-2.4.29/drivers/i2c/i2c-algo-au1550.c linux-mips/drivers/i2c/i2c-algo-au1550.c
 --- linux-2.4.29/drivers/i2c/i2c-algo-au1550.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/i2c/i2c-algo-au1550.c   2005-02-12 04:06:32.000000000 +0100
++++ linux-mips/drivers/i2c/i2c-algo-au1550.c   2005-03-26 11:47:21.004204470 +0100
 @@ -0,0 +1,340 @@
 +/*
 + * i2c-algo-au1550.c: SMBus (i2c) driver algorithms for Alchemy PSC interface
@@ -13172,9 +16686,70 @@ diff -Nur linux-2.4.29/drivers/i2c/i2c-algo-au1550.c linux-mips/drivers/i2c/i2c-
 +MODULE_AUTHOR("Dan Malek <dan@embeddededge.com>");
 +MODULE_DESCRIPTION("SMBus Au1550 algorithm");
 +MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.29/drivers/i2c/i2c-algo-bit.c linux-mips/drivers/i2c/i2c-algo-bit.c
+--- linux-2.4.29/drivers/i2c/i2c-algo-bit.c    2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/i2c/i2c-algo-bit.c      2005-03-26 11:47:21.069193803 +0100
+@@ -28,14 +28,12 @@
+ #include <linux/delay.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+-#include <asm/uaccess.h>
+-#include <linux/ioport.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+-
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-bit.h>
++
+ /* ----- global defines ----------------------------------------------- */
+ #define DEB(x) if (i2c_debug>=1) x;
+ #define DEB2(x) if (i2c_debug>=2) x;
+@@ -522,8 +520,8 @@
+ static u32 bit_func(struct i2c_adapter *adap)
+ {
+-      return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+-             I2C_FUNC_PROTOCOL_MANGLING;
++      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
++             I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+ }
+diff -Nur linux-2.4.29/drivers/i2c/i2c-algo-pcf.c linux-mips/drivers/i2c/i2c-algo-pcf.c
+--- linux-2.4.29/drivers/i2c/i2c-algo-pcf.c    2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/i2c/i2c-algo-pcf.c      2005-03-26 11:47:21.128184122 +0100
+@@ -32,15 +32,13 @@
+ #include <linux/delay.h>
+ #include <linux/slab.h>
+ #include <linux/init.h>
+-#include <asm/uaccess.h>
+-#include <linux/ioport.h>
+ #include <linux/errno.h>
+ #include <linux/sched.h>
+-
+ #include <linux/i2c.h>
+ #include <linux/i2c-algo-pcf.h>
+ #include "i2c-pcf8584.h"
++
+ /* ----- global defines ----------------------------------------------- */
+ #define DEB(x) if (i2c_debug>=1) x
+ #define DEB2(x) if (i2c_debug>=2) x
+@@ -435,8 +433,8 @@
+ static u32 pcf_func(struct i2c_adapter *adap)
+ {
+-      return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | 
+-             I2C_FUNC_PROTOCOL_MANGLING; 
++      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
++             I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+ }
+ /* -----exported algorithm data: -------------------------------------        */
 diff -Nur linux-2.4.29/drivers/i2c/i2c-au1550.c linux-mips/drivers/i2c/i2c-au1550.c
 --- linux-2.4.29/drivers/i2c/i2c-au1550.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/i2c/i2c-au1550.c        2005-02-12 04:06:32.000000000 +0100
++++ linux-mips/drivers/i2c/i2c-au1550.c        2005-03-26 11:47:21.146181168 +0100
 @@ -0,0 +1,154 @@
 +/*
 + * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
@@ -13354,6 +16929,115 @@ diff -Nur linux-2.4.29/drivers/i2c/i2c-core.c linux-mips/drivers/i2c/i2c-core.c
        /* -------------- proc interface ---- */
  #ifdef CONFIG_I2C_PROC
        sensors_init();
+diff -Nur linux-2.4.29/drivers/i2c/Makefile linux-mips/drivers/i2c/Makefile
+--- linux-2.4.29/drivers/i2c/Makefile  2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/i2c/Makefile    2005-03-26 11:47:20.975209228 +0100
+@@ -6,7 +6,7 @@
+ export-objs   := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
+                  i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
+-                 i2c-proc.o
++                 i2c-algo-au1550.o i2c-proc.o i2c-au1550.o
+ obj-$(CONFIG_I2C)             += i2c-core.o
+ obj-$(CONFIG_I2C_CHARDEV)     += i2c-dev.o
+@@ -25,6 +25,7 @@
+ obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o
+ obj-$(CONFIG_I2C_MAX1617)     += i2c-max1617.o
+ obj-$(CONFIG_I2C_ALGO_SGI)    += i2c-algo-sgi.o
++obj-$(CONFIG_I2C_ALGO_AU1550) += i2c-algo-au1550.o i2c-au1550.o
+ # This is needed for automatic patch generation: sensors code starts here
+ # This is needed for automatic patch generation: sensors code ends here
+diff -Nur linux-2.4.29/drivers/ide/ide-cd.c linux-mips/drivers/ide/ide-cd.c
+--- linux-2.4.29/drivers/ide/ide-cd.c  2003-11-28 19:26:20.000000000 +0100
++++ linux-mips/drivers/ide/ide-cd.c    2005-03-26 11:47:21.315153436 +0100
+@@ -2206,25 +2206,31 @@
+       /* Read the multisession information. */
+       if (toc->hdr.first_track != CDROM_LEADOUT) {
+               /* Read the multisession information. */
+-              stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
++              stat = cdrom_read_tocentry(drive, 0, 0, 1, (char *)&ms_tmp,
+                                          sizeof(ms_tmp), sense);
+               if (stat) return stat;
++      
++              toc->last_session_lba = be32_to_cpu(ms_tmp.ent.addr.lba);
+       } else {
+-              ms_tmp.ent.addr.msf.minute = 0;
+-              ms_tmp.ent.addr.msf.second = 2;
+-              ms_tmp.ent.addr.msf.frame  = 0;
+               ms_tmp.hdr.first_track = ms_tmp.hdr.last_track = CDROM_LEADOUT;
++              toc->last_session_lba = msf_to_lba(0, 2, 0); /* 0m 2s 0f */
+       }
+ #if ! STANDARD_ATAPI
+-      if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd)
++      if (CDROM_CONFIG_FLAGS(drive)->tocaddr_as_bcd) {
++              /* Re-read multisession information using MSF format */
++              stat = cdrom_read_tocentry(drive, 0, 1, 1, (char *)&ms_tmp,
++                                         sizeof(ms_tmp), sense);
++              if (stat)
++                      return stat;
++
+               msf_from_bcd (&ms_tmp.ent.addr.msf);
++              toc->last_session_lba = msf_to_lba(ms_tmp.ent.addr.msf.minute,
++                                                 ms_tmp.ent.addr.msf.second,
++                                                 ms_tmp.ent.addr.msf.frame);
++      }
+ #endif  /* not STANDARD_ATAPI */
+-      toc->last_session_lba = msf_to_lba (ms_tmp.ent.addr.msf.minute,
+-                                          ms_tmp.ent.addr.msf.second,
+-                                          ms_tmp.ent.addr.msf.frame);
+-
+       toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
+       /* Now try to get the total cdrom capacity. */
+diff -Nur linux-2.4.29/drivers/isdn/hisax/ipacx.c linux-mips/drivers/isdn/hisax/ipacx.c
+--- linux-2.4.29/drivers/isdn/hisax/ipacx.c    2002-11-29 00:53:13.000000000 +0100
++++ linux-mips/drivers/isdn/hisax/ipacx.c      2005-03-26 11:47:21.653097971 +0100
+@@ -152,7 +152,13 @@
+               case (HW_RESET | REQUEST):
+               case (HW_ENABLE | REQUEST):
+-                      ph_command(cs, IPACX_CMD_TIM);
++                      if ((cs->dc.isac.ph_state == IPACX_IND_RES) ||
++                      (cs->dc.isac.ph_state == IPACX_IND_DR) ||
++                              (cs->dc.isac.ph_state == IPACX_IND_DC))
++                              ph_command(cs, IPACX_CMD_TIM);
++                      else
++                              ph_command(cs, IPACX_CMD_RES);
++
+                       break;
+               case (HW_INFO3 | REQUEST):
+diff -Nur linux-2.4.29/drivers/md/lvm-snap.c linux-mips/drivers/md/lvm-snap.c
+--- linux-2.4.29/drivers/md/lvm-snap.c 2004-04-14 15:05:30.000000000 +0200
++++ linux-mips/drivers/md/lvm-snap.c   2005-03-26 11:47:21.896058096 +0100
+@@ -119,7 +119,6 @@
+       unsigned long mask = lv->lv_snapshot_hash_mask;
+       int chunk_size = lv->lv_chunk_size;
+       lv_block_exception_t *ret;
+-      int i = 0;
+       hash_table =
+           &hash_table[hashfn(org_dev, org_start, mask, chunk_size)];
+@@ -132,15 +131,9 @@
+               exception = list_entry(next, lv_block_exception_t, hash);
+               if (exception->rsector_org == org_start &&
+                   exception->rdev_org == org_dev) {
+-                      if (i) {
+-                              /* fun, isn't it? :) */
+-                              list_del(next);
+-                              list_add(next, hash_table);
+-                      }
+                       ret = exception;
+                       break;
+               }
+-              i++;
+       }
+       return ret;
+ }
 diff -Nur linux-2.4.29/drivers/media/video/indycam.c linux-mips/drivers/media/video/indycam.c
 --- linux-2.4.29/drivers/media/video/indycam.c 2004-02-18 14:36:31.000000000 +0100
 +++ linux-mips/drivers/media/video/indycam.c   2004-12-09 21:32:05.000000000 +0100
@@ -13761,33 +17445,9 @@ diff -Nur linux-2.4.29/drivers/mtd/maps/Config.in linux-mips/drivers/mtd/maps/Co
     dep_tristate '  Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS 
     if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
        hex '    Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000
-diff -Nur linux-2.4.29/drivers/mtd/maps/Makefile linux-mips/drivers/mtd/maps/Makefile
---- linux-2.4.29/drivers/mtd/maps/Makefile     2003-06-13 16:51:34.000000000 +0200
-+++ linux-mips/drivers/mtd/maps/Makefile       2004-02-26 01:46:35.000000000 +0100
-@@ -52,7 +52,13 @@
- obj-$(CONFIG_MTD_PB1000)      += pb1xxx-flash.o
- obj-$(CONFIG_MTD_PB1100)      += pb1xxx-flash.o
- obj-$(CONFIG_MTD_PB1500)      += pb1xxx-flash.o
-+obj-$(CONFIG_MTD_XXS1500)       += xxs1500.o
-+obj-$(CONFIG_MTD_MTX1)                += mtx-1.o
- obj-$(CONFIG_MTD_LASAT)               += lasat.o
-+obj-$(CONFIG_MTD_DB1X00)        += db1x00-flash.o
-+obj-$(CONFIG_MTD_PB1550)        += pb1550-flash.o
-+obj-$(CONFIG_MTD_HYDROGEN3)     += hydrogen3-flash.o
-+obj-$(CONFIG_MTD_BOSPORUS)    += pb1xxx-flash.o
- obj-$(CONFIG_MTD_AUTCPU12)    += autcpu12-nvram.o
- obj-$(CONFIG_MTD_EDB7312)     += edb7312.o
- obj-$(CONFIG_MTD_IMPA7)               += impa7.o
-@@ -61,5 +67,6 @@
- obj-$(CONFIG_MTD_UCLINUX)     += uclinux.o
- obj-$(CONFIG_MTD_NETtel)      += nettel.o
- obj-$(CONFIG_MTD_SCB2_FLASH)  += scb2_flash.o
-+obj-$(CONFIG_MTD_MIRAGE)        += mirage-flash.o
- include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/drivers/mtd/maps/db1x00-flash.c linux-mips/drivers/mtd/maps/db1x00-flash.c
 --- linux-2.4.29/drivers/mtd/maps/db1x00-flash.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/mtd/maps/db1x00-flash.c 2005-02-12 04:06:46.000000000 +0100
++++ linux-mips/drivers/mtd/maps/db1x00-flash.c 2005-03-26 11:47:22.085027082 +0100
 @@ -0,0 +1,283 @@
 +/*
 + * Flash memory access on Alchemy Db1xxx boards
@@ -14373,6 +18033,30 @@ diff -Nur linux-2.4.29/drivers/mtd/maps/lasat.c linux-mips/drivers/mtd/maps/lasa
        }
  }
  
+diff -Nur linux-2.4.29/drivers/mtd/maps/Makefile linux-mips/drivers/mtd/maps/Makefile
+--- linux-2.4.29/drivers/mtd/maps/Makefile     2003-06-13 16:51:34.000000000 +0200
++++ linux-mips/drivers/mtd/maps/Makefile       2004-02-26 01:46:35.000000000 +0100
+@@ -52,7 +52,13 @@
+ obj-$(CONFIG_MTD_PB1000)      += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_PB1100)      += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_PB1500)      += pb1xxx-flash.o
++obj-$(CONFIG_MTD_XXS1500)       += xxs1500.o
++obj-$(CONFIG_MTD_MTX1)                += mtx-1.o
+ obj-$(CONFIG_MTD_LASAT)               += lasat.o
++obj-$(CONFIG_MTD_DB1X00)        += db1x00-flash.o
++obj-$(CONFIG_MTD_PB1550)        += pb1550-flash.o
++obj-$(CONFIG_MTD_HYDROGEN3)     += hydrogen3-flash.o
++obj-$(CONFIG_MTD_BOSPORUS)    += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_AUTCPU12)    += autcpu12-nvram.o
+ obj-$(CONFIG_MTD_EDB7312)     += edb7312.o
+ obj-$(CONFIG_MTD_IMPA7)               += impa7.o
+@@ -61,5 +67,6 @@
+ obj-$(CONFIG_MTD_UCLINUX)     += uclinux.o
+ obj-$(CONFIG_MTD_NETtel)      += nettel.o
+ obj-$(CONFIG_MTD_SCB2_FLASH)  += scb2_flash.o
++obj-$(CONFIG_MTD_MIRAGE)        += mirage-flash.o
+ include $(TOPDIR)/Rules.make
 diff -Nur linux-2.4.29/drivers/mtd/maps/mirage-flash.c linux-mips/drivers/mtd/maps/mirage-flash.c
 --- linux-2.4.29/drivers/mtd/maps/mirage-flash.c       1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/drivers/mtd/maps/mirage-flash.c 2003-12-22 04:37:22.000000000 +0100
@@ -16192,1103 +19876,7914 @@ diff -Nur linux-2.4.29/drivers/net/defxx.h linux-mips/drivers/net/defxx.h
        struct pci_dev *                pci_dev;
        u32                             full_duplex_enb;                                /* FDDI Full Duplex enable (1 == on, 2 == off) */
        u32                             req_ttrt;                                       /* requested TTRT value (in 80ns units) */
-diff -Nur linux-2.4.29/drivers/net/hamradio/hdlcdrv.c linux-mips/drivers/net/hamradio/hdlcdrv.c
---- linux-2.4.29/drivers/net/hamradio/hdlcdrv.c        2002-02-25 20:37:59.000000000 +0100
-+++ linux-mips/drivers/net/hamradio/hdlcdrv.c  2004-05-04 14:04:27.000000000 +0200
-@@ -587,6 +587,8 @@
-               return -EINVAL;
-       s = (struct hdlcdrv_state *)dev->priv;
+diff -Nur linux-2.4.29/drivers/net/e1000/e1000_ethtool.c linux-mips/drivers/net/e1000/e1000_ethtool.c
+--- linux-2.4.29/drivers/net/e1000/e1000_ethtool.c     2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/e1000/e1000_ethtool.c       2005-03-26 11:47:31.355505582 +0100
+@@ -1309,7 +1309,7 @@
+       struct e1000_desc_ring *txdr = &adapter->test_tx_ring;
+       struct e1000_desc_ring *rxdr = &adapter->test_rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+-      int i;
++      int i, ret_val;
+       E1000_WRITE_REG(&adapter->hw, RDT, rxdr->count - 1);
+@@ -1329,11 +1329,12 @@
+                                           rxdr->buffer_info[i].length,
+                                           PCI_DMA_FROMDEVICE);
+-              if (!e1000_check_lbtest_frame(rxdr->buffer_info[i++].skb, 1024))
+-                      return 0;
+-      } while (i < 64);
++              ret_val = e1000_check_lbtest_frame(rxdr->buffer_info[i].skb,
++                                                 1024);
++              i++;
++      } while (ret_val != 0 && i < 64);
  
-+      netif_stop_queue(dev);
-+
-       if (s->ops && s->ops->close)
-               i = s->ops->close(dev);
-       if (s->skb)
-diff -Nur linux-2.4.29/drivers/net/irda/au1k_ir.c linux-mips/drivers/net/irda/au1k_ir.c
---- linux-2.4.29/drivers/net/irda/au1k_ir.c    2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/net/irda/au1k_ir.c      2005-02-12 04:06:52.000000000 +0100
-@@ -81,10 +81,6 @@
+-      return 13;
++      return ret_val;
+ }
  
- #define RUN_AT(x) (jiffies + (x))
+ static int
+diff -Nur linux-2.4.29/drivers/net/e1000/e1000.h linux-mips/drivers/net/e1000/e1000.h
+--- linux-2.4.29/drivers/net/e1000/e1000.h     2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/e1000/e1000.h       2005-03-26 11:47:30.488647853 +0100
+@@ -140,6 +140,7 @@
+ #define E1000_RX_BUFFER_WRITE 16      /* Must be power of 2 */
+ #define AUTO_ALL_MODES       0
++#define E1000_EEPROM_82544_APM 0x0004
+ #define E1000_EEPROM_APME    0x0400
+ #ifndef E1000_MASTER_SLAVE
+@@ -211,6 +212,7 @@
+       /* TX */
+       struct e1000_desc_ring tx_ring;
++      struct e1000_buffer previous_buffer_info;
+       spinlock_t tx_lock;
+       uint32_t txd_cmd;
+       uint32_t tx_int_delay;
+@@ -224,6 +226,7 @@
+       uint32_t tx_fifo_size;
+       atomic_t tx_fifo_stall;
+       boolean_t pcix_82544;
++      boolean_t detect_tx_hung;
+       /* RX */
+       struct e1000_desc_ring rx_ring;
+diff -Nur linux-2.4.29/drivers/net/e1000/e1000_hw.c linux-mips/drivers/net/e1000/e1000_hw.c
+--- linux-2.4.29/drivers/net/e1000/e1000_hw.c  2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/e1000/e1000_hw.c    2005-03-26 11:47:31.359504925 +0100
+@@ -1573,7 +1573,8 @@
+             if(mii_status_reg & MII_SR_LINK_STATUS) break;
+             msec_delay(100);
+         }
+-        if((i == 0) && (hw->phy_type == e1000_phy_m88)) {
++        if((i == 0) &&
++           (hw->phy_type == e1000_phy_m88)) {
+             /* We didn't get link.  Reset the DSP and wait again for link. */
+             ret_val = e1000_phy_reset_dsp(hw);
+             if(ret_val) {
+@@ -2504,7 +2505,7 @@
+         }
+     }
  
--#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
--static BCSR * const bcsr = (BCSR *)0xAE000000;
--#endif
--
- static spinlock_t ir_lock = SPIN_LOCK_UNLOCKED;
+-    ret_val = e1000_read_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
++    ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+                                     phy_data);
  
- /*
-diff -Nur linux-2.4.29/drivers/pci/pci.c linux-mips/drivers/pci/pci.c
---- linux-2.4.29/drivers/pci/pci.c     2004-11-17 12:54:21.000000000 +0100
-+++ linux-mips/drivers/pci/pci.c       2004-11-19 01:28:41.000000000 +0100
-@@ -1281,11 +1281,17 @@
+     return ret_val;
+@@ -2610,7 +2611,7 @@
+         }
+     }
+-    ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT & reg_addr,
++    ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr,
+                                      phy_data);
+     return ret_val;
+@@ -2956,8 +2957,7 @@
+     /* Check polarity status */
+     ret_val = e1000_check_polarity(hw, &polarity);
+     if(ret_val)
+-        return ret_val;
+-
++        return ret_val; 
+     phy_info->cable_polarity = polarity;
+     ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+@@ -2967,9 +2967,9 @@
+     phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+                           M88E1000_PSSR_MDIX_SHIFT;
+-    if(phy_data & M88E1000_PSSR_1000MBS) {
+-        /* Cable Length Estimation and Local/Remote Receiver Informatoion
+-         * are only valid at 1000 Mbps
++    if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
++        /* Cable Length Estimation and Local/Remote Receiver Information
++         * are only valid at 1000 Mbps.
+          */
+         phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                   M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+@@ -4641,41 +4641,44 @@
  {
-       unsigned int buses;
-       unsigned short cr;
-+      unsigned short bctl;
-       struct pci_bus *child;
-       int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+     uint32_t status;
+-    if(hw->mac_type < e1000_82543) {
++    switch (hw->mac_type) {
++    case e1000_82542_rev2_0:
++    case e1000_82542_rev2_1:
+         hw->bus_type = e1000_bus_type_unknown;
+         hw->bus_speed = e1000_bus_speed_unknown;
+         hw->bus_width = e1000_bus_width_unknown;
+-        return;
+-    }
+-
+-    status = E1000_READ_REG(hw, STATUS);
+-    hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+-                   e1000_bus_type_pcix : e1000_bus_type_pci;
++        break;
++    default:
++        status = E1000_READ_REG(hw, STATUS);
++        hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
++                       e1000_bus_type_pcix : e1000_bus_type_pci;
+-    if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+-        hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
+-                        e1000_bus_speed_66 : e1000_bus_speed_120;
+-    } else if(hw->bus_type == e1000_bus_type_pci) {
+-        hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+-                        e1000_bus_speed_66 : e1000_bus_speed_33;
+-    } else {
+-        switch (status & E1000_STATUS_PCIX_SPEED) {
+-        case E1000_STATUS_PCIX_SPEED_66:
+-            hw->bus_speed = e1000_bus_speed_66;
+-            break;
+-        case E1000_STATUS_PCIX_SPEED_100:
+-            hw->bus_speed = e1000_bus_speed_100;
+-            break;
+-        case E1000_STATUS_PCIX_SPEED_133:
+-            hw->bus_speed = e1000_bus_speed_133;
+-            break;
+-        default:
+-            hw->bus_speed = e1000_bus_speed_reserved;
+-            break;
++        if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
++            hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
++                            e1000_bus_speed_66 : e1000_bus_speed_120;
++        } else if(hw->bus_type == e1000_bus_type_pci) {
++            hw->bus_speed = (status & E1000_STATUS_PCI66) ?
++                            e1000_bus_speed_66 : e1000_bus_speed_33;
++        } else {
++            switch (status & E1000_STATUS_PCIX_SPEED) {
++            case E1000_STATUS_PCIX_SPEED_66:
++                hw->bus_speed = e1000_bus_speed_66;
++                break;
++            case E1000_STATUS_PCIX_SPEED_100:
++                hw->bus_speed = e1000_bus_speed_100;
++                break;
++            case E1000_STATUS_PCIX_SPEED_133:
++                hw->bus_speed = e1000_bus_speed_133;
++                break;
++            default:
++                hw->bus_speed = e1000_bus_speed_reserved;
++                break;
++            }
+         }
++        hw->bus_width = (status & E1000_STATUS_BUS64) ?
++                        e1000_bus_width_64 : e1000_bus_width_32;
++        break;
+     }
+-    hw->bus_width = (status & E1000_STATUS_BUS64) ?
+-                    e1000_bus_width_64 : e1000_bus_width_32;
+ }
+ /******************************************************************************
+  * Reads a value from one of the devices registers using port I/O (as opposed
+@@ -4740,6 +4743,7 @@
+     uint16_t agc_value = 0;
+     uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
+     uint16_t i, phy_data;
++    uint16_t cable_length;
+     DEBUGFUNC("e1000_get_cable_length");
+@@ -4751,10 +4755,11 @@
+                                      &phy_data);
+         if(ret_val)
+             return ret_val;
++        cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
++                       M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+         /* Convert the enum value to ranged values */
+-        switch((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+-               M88E1000_PSSR_CABLE_LENGTH_SHIFT) {
++        switch (cable_length) {
+         case e1000_cable_length_50:
+             *min_length = 0;
+             *max_length = e1000_igp_cable_length_50;
+@@ -4921,8 +4926,7 @@
+             return ret_val;
+         hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
+-    }
+-    else if(hw->phy_type == e1000_phy_m88) {
++    } else if(hw->phy_type == e1000_phy_m88) {
+         ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
+                                      &phy_data);
+         if(ret_val)
+diff -Nur linux-2.4.29/drivers/net/e1000/e1000_hw.h linux-mips/drivers/net/e1000/e1000_hw.h
+--- linux-2.4.29/drivers/net/e1000/e1000_hw.h  2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/e1000/e1000_hw.h    2005-03-26 11:47:31.362504433 +0100
+@@ -36,7 +36,6 @@
+ #include "e1000_osdep.h"
  
-       pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
-       DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
-+      /* Disable MasterAbortMode during probing to avoid reporting
-+           of bus errors (in some architectures) */
-+      pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
-+      pci_write_config_word(dev, PCI_BRIDGE_CONTROL, 
-+                            bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
-       if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
-               /*
-                * Bus already configured by firmware, process it in the first
-@@ -1351,6 +1357,7 @@
-               pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
-               pci_write_config_word(dev, PCI_COMMAND, cr);
-       }
-+      pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
-       sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
-       return max;
- }
-diff -Nur linux-2.4.29/drivers/pcmcia/Config.in linux-mips/drivers/pcmcia/Config.in
---- linux-2.4.29/drivers/pcmcia/Config.in      2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/pcmcia/Config.in        2004-02-22 06:21:34.000000000 +0100
-@@ -30,16 +30,14 @@
-       dep_tristate '  M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
-    fi
-    if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
--      dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA 
--      if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
--        bool '  Pb1x00 board support' CONFIG_PCMCIA_PB1X00
--        bool '  Db1x00 board support' CONFIG_PCMCIA_DB1X00
--        bool '  XXS1500 board support' CONFIG_PCMCIA_XXS1500
--      fi
-+      dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA
-    fi
-    if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
-       dep_bool '  SiByte PCMCIA support' CONFIG_PCMCIA_SIBYTE $CONFIG_PCMCIA $CONFIG_BLK_DEV_IDE_SIBYTE
-    fi
-+   if [ "$CONFIG_VRC4171" = "y" -o "$CONFIG_VRC4171" = "m" ]; then
-+      dep_tristate '  NEC VRC4171 Card Controllers support' CONFIG_PCMCIA_VRC4171 $CONFIG_PCMCIA
-+   fi
-    if [ "$CONFIG_VRC4173" = "y" -o "$CONFIG_VRC4173" = "m" ]; then
-       dep_tristate '  NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA
-    fi
-diff -Nur linux-2.4.29/drivers/pcmcia/Makefile linux-mips/drivers/pcmcia/Makefile
---- linux-2.4.29/drivers/pcmcia/Makefile       2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/pcmcia/Makefile 2005-02-12 04:06:57.000000000 +0100
-@@ -61,9 +61,18 @@
- obj-$(CONFIG_PCMCIA_AU1X00)                   += au1x00_ss.o
- au1000_ss-objs-y                              := au1000_generic.o
--au1000_ss-objs-$(CONFIG_PCMCIA_PB1X00)                += au1000_pb1x00.o
--au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00)                += au1000_db1x00.o
--au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500)       += au1000_xxs1500.o
-+au1000_ss-objs-$(CONFIG_MIPS_PB1000)          += au1000_pb1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_PB1100)          += au1000_pb1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_PB1500)          += au1000_pb1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_PB1550)          += au1000_pb1550.o
-+au1000_ss-objs-$(CONFIG_MIPS_PB1200)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_DB1000)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_DB1100)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_DB1500)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_DB1550)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_DB1200)          += au1000_db1x00.o
-+au1000_ss-objs-$(CONFIG_MIPS_HYDROGEN3)               += au1000_hydrogen3.o
-+au1000_ss-objs-$(CONFIG_MIPS_XXS1500)                 += au1000_xxs1500.o
  
- obj-$(CONFIG_PCMCIA_SA1100)   += sa1100_cs.o
- obj-$(CONFIG_PCMCIA_M8XX)     += m8xx_pcmcia.o
-@@ -89,6 +98,7 @@
- sa1100_cs-objs-$(CONFIG_SA1100_XP860)         += sa1100_xp860.o sa1111_generic.o
- sa1100_cs-objs-$(CONFIG_SA1100_YOPY)          += sa1100_yopy.o
+-
+ /* Forward declarations of structures used by the shared code */
+ struct e1000_hw;
+ struct e1000_hw_stats;
+@@ -370,6 +369,7 @@
+ #define E1000_DEV_ID_82546GB_SERDES      0x107B
+ #define E1000_DEV_ID_82546GB_PCIE        0x108A
+ #define E1000_DEV_ID_82547EI             0x1019
++
+ #define NODE_ADDRESS_SIZE 6
+ #define ETH_LENGTH_OF_ADDRESS 6
  
-+obj-$(CONFIG_PCMCIA_VRC4171)  += vrc4171_card.o
- obj-$(CONFIG_PCMCIA_VRC4173)  += vrc4173_cardu.o
+@@ -1735,6 +1735,9 @@
+ #define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+ #define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
  
- include $(TOPDIR)/Rules.make
-diff -Nur linux-2.4.29/drivers/pcmcia/au1000_db1x00.c linux-mips/drivers/pcmcia/au1000_db1x00.c
---- linux-2.4.29/drivers/pcmcia/au1000_db1x00.c        2005-01-19 15:09:57.000000000 +0100
-+++ linux-mips/drivers/pcmcia/au1000_db1x00.c  2005-02-12 04:06:57.000000000 +0100
-@@ -1,6 +1,6 @@
- /*
-  *
-- * Alchemy Semi Db1x00 boards specific pcmcia routines.
-+ * AMD Alchemy DUAL-SLOT Db1x00 boards' specific pcmcia routines.
-  *
-  * Copyright 2002 MontaVista Software Inc.
-  * Author: MontaVista Software, Inc.
-@@ -54,9 +54,20 @@
- #include <asm/au1000.h>
- #include <asm/au1000_pcmcia.h>
++#define MAX_PHY_REG_ADDRESS        0x1F  /* 5 bit address bus (0-0x1F) */
++#define MAX_PHY_MULTI_PAGE_REG     0xF   /* Registers equal on all pages */
++
+ /* M88E1000 Specific Registers */
+ #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+ #define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+@@ -1795,8 +1798,7 @@
  
-+#if defined(CONFIG_MIPS_PB1200)
-+#include <asm/pb1200.h>
-+#elif defined(CONFIG_MIPS_DB1200)
-+#include <asm/db1200.h>
-+#else
- #include <asm/db1x00.h>
-+#endif
+ #define IGP01E1000_ANALOG_REGS_PAGE  0x20C0
  
--static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-+#define PCMCIA_MAX_SOCK 1
-+#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
+-#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
+-#define MAX_PHY_MULTI_PAGE_REG  0xF     /*Registers that are equal on all pages*/
 +
-+/* VPP/VCC */
-+#define SET_VCC_VPP(VCC, VPP, SLOT)\
-+    ((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
+ /* PHY Control Register */
+ #define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+ #define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+@@ -2099,7 +2101,11 @@
+ #define IGP01E1000_ANALOG_FUSE_FINE_1               0x0080
+ #define IGP01E1000_ANALOG_FUSE_FINE_10              0x0500
  
- static int db1x00_pcmcia_init(struct pcmcia_init *init)
- {
-@@ -76,7 +87,7 @@
- db1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
- {
-       u32 inserted;
--      unsigned char vs;
-+      u16 vs;
++
+ /* Bit definitions for valid PHY IDs. */
++/* I = Integrated
++ * E = External
++ */
+ #define M88E1000_E_PHY_ID  0x01410C50
+ #define M88E1000_I_PHY_ID  0x01410C30
+ #define M88E1011_I_PHY_ID  0x01410C20
+diff -Nur linux-2.4.29/drivers/net/e1000/e1000_main.c linux-mips/drivers/net/e1000/e1000_main.c
+--- linux-2.4.29/drivers/net/e1000/e1000_main.c        2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/e1000/e1000_main.c  2005-03-26 11:47:31.364504105 +0100
+@@ -34,6 +34,14 @@
+  * - if_mii support and associated kcompat for older kernels
+  * - More errlogging support from Jon Mason <jonmason@us.ibm.com>
+  * - Fix TSO issues on PPC64 machines -- Jon Mason <jonmason@us.ibm.com>
++ * 5.7.1      12/16/04
++ * - Resurrect 82547EI/GI related fix in e1000_intr to avoid deadlocks. This
++ *   fix was removed as it caused system instability. The suspected cause of 
++ *   this is the called to e1000_irq_disable in e1000_intr. Inlined the 
++ *   required piece of e1000_irq_disable into e1000_intr.
++ * 5.7.0      12/10/04
++ * - include fix to the condition that determines when to quit NAPI - Robert Olsson
++ * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down
+  * 5.6.5      11/01/04
+  * - Enabling NETIF_F_SG without checksum offload is illegal - 
+      John Mason <jdmason@us.ibm.com>
+@@ -41,8 +49,13 @@
+  * - Remove redundant initialization - Jamal Hadi
+  * - Reset buffer_info->dma in tx resource cleanup logic
+  * 5.6.2      10/12/04
++ * - Avoid filling tx_ring completely - shemminger@osdl.org
++ * - Replace schedule_timeout() with msleep()/msleep_interruptible() -
++ *   nacc@us.ibm.com
+  * - Sparse cleanup - shemminger@osdl.org
+  * - Fix tx resource cleanup logic
++ * - LLTX support - ak@suse.de and hadi@cyberus.ca
++ * - {set, get}_wol is now symmetric for 82545EM adapters
+  */
  
-       if(sock > PCMCIA_MAX_SOCK) return -1;
+ char e1000_driver_name[] = "e1000";
+@@ -52,7 +65,7 @@
+ #else
+ #define DRIVERNAPI "-NAPI"
+ #endif
+-char e1000_driver_version[] = "5.6.10.1-k1"DRIVERNAPI;
++char e1000_driver_version[] = "5.7.6-k1"DRIVERNAPI;
+ char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+ /* e1000_pci_tbl - PCI Device ID Table
+@@ -76,6 +89,7 @@
+       INTEL_E1000_ETHERNET_DEVICE(0x1011),
+       INTEL_E1000_ETHERNET_DEVICE(0x1012),
+       INTEL_E1000_ETHERNET_DEVICE(0x1013),
++      INTEL_E1000_ETHERNET_DEVICE(0x1014),
+       INTEL_E1000_ETHERNET_DEVICE(0x1015),
+       INTEL_E1000_ETHERNET_DEVICE(0x1016),
+       INTEL_E1000_ETHERNET_DEVICE(0x1017),
+@@ -303,6 +317,9 @@
+       mod_timer(&adapter->watchdog_timer, jiffies);
+       e1000_irq_enable(adapter);
++#ifdef CONFIG_E1000_NAPI
++      netif_poll_enable(netdev);
++#endif
+       return 0;
+ }
  
-@@ -87,11 +98,11 @@
+@@ -316,6 +333,10 @@
+       del_timer_sync(&adapter->tx_fifo_stall_timer);
+       del_timer_sync(&adapter->watchdog_timer);
+       del_timer_sync(&adapter->phy_info_timer);
++
++#ifdef CONFIG_E1000_NAPI
++      netif_poll_disable(netdev);
++#endif
+       adapter->link_speed = 0;
+       adapter->link_duplex = 0;
+       netif_carrier_off(netdev);
+@@ -409,6 +430,7 @@
+       int i;
+       int err;
+       uint16_t eeprom_data;
++      uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
  
-       if (sock == 0) {
-               vs = bcsr->status & 0x3;
--              inserted = !(bcsr->status & (1<<4));
-+              inserted = BOARD_CARD_INSERTED(0);
-       }
-       else {
-               vs = (bcsr->status & 0xC)>>2;
--              inserted = !(bcsr->status & (1<<5));
-+              inserted = BOARD_CARD_INSERTED(1);
+       if((err = pci_enable_device(pdev)))
+               return err;
+@@ -505,9 +527,6 @@
        }
  
-       DEBUG(KERN_DEBUG "db1x00 socket %d: inserted %d, vs %d\n", 
-@@ -144,16 +155,9 @@
-       if(info->sock > PCMCIA_MAX_SOCK) return -1;
+ #ifdef NETIF_F_TSO
+-      /* Disbaled for now until root-cause is found for
+-       * hangs reported against non-IA archs.  TSO can be
+-       * enabled using ethtool -K eth<x> tso on */
+       if((adapter->hw.mac_type >= e1000_82544) &&
+          (adapter->hw.mac_type != e1000_82547))
+               netdev->features |= NETIF_F_TSO;
+@@ -576,6 +595,11 @@
+       case e1000_82542_rev2_1:
+       case e1000_82543:
+               break;
++      case e1000_82544:
++              e1000_read_eeprom(&adapter->hw,
++                      EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
++              eeprom_apme_mask = E1000_EEPROM_82544_APM;
++              break;
+       case e1000_82546:
+       case e1000_82546_rev_3:
+               if((E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
+@@ -590,7 +614,7 @@
+                       EEPROM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+               break;
+       }
+-      if(eeprom_data & E1000_EEPROM_APME)
++      if(eeprom_data & eeprom_apme_mask)
+               adapter->wol |= E1000_WUFC_MAG;
  
-       if(info->sock == 0)
--#ifdef CONFIG_MIPS_DB1550
--              info->irq = AU1000_GPIO_3;
-+              info->irq = BOARD_PC0_INT;
-       else 
--              info->irq = AU1000_GPIO_5;
--#else
--              info->irq = AU1000_GPIO_2;
--      else 
--              info->irq = AU1000_GPIO_5;
--#endif
--
-+              info->irq = BOARD_PC1_INT;
-       return 0;
+       /* reset the hardware with the new settings */
+@@ -797,6 +821,31 @@
  }
  
-diff -Nur linux-2.4.29/drivers/pcmcia/vrc4171_card.c linux-mips/drivers/pcmcia/vrc4171_card.c
---- linux-2.4.29/drivers/pcmcia/vrc4171_card.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/pcmcia/vrc4171_card.c   2004-01-19 16:54:58.000000000 +0100
-@@ -0,0 +1,886 @@
-+/*
-+ * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
-+ *
-+ * Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program is distributed in the hope that it will be useful,
-+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ *  GNU General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ */
-+#include <linux/init.h>
-+#include <linux/ioport.h>
-+#include <linux/irq.h>
-+#include <linux/module.h>
-+#include <linux/spinlock.h>
-+#include <linux/sched.h>
-+#include <linux/types.h>
+ /**
++ * e1000_check_64k_bound - check that memory doesn't cross 64kB boundary
++ * @adapter: address of board private structure
++ * @begin: address of beginning of memory
++ * @end: address of end of memory
++ **/
++static inline boolean_t
++e1000_check_64k_bound(struct e1000_adapter *adapter,
++                    void *start, unsigned long len)
++{
++      unsigned long begin = (unsigned long) start;
++      unsigned long end = begin + len;
++
++      /* first rev 82545 and 82546 need to not allow any memory
++       * write location to cross a 64k boundary due to errata 23 */
++      if (adapter->hw.mac_type == e1000_82545 ||
++          adapter->hw.mac_type == e1000_82546 ) {
++
++              /* check buffer doesn't cross 64kB */
++              return ((begin ^ (end - 1)) >> 16) != 0 ? FALSE : TRUE;
++      }
 +
-+#include <asm/io.h>
-+#include <asm/vr41xx/vrc4171.h>
++      return TRUE;
++}
 +
-+#include <pcmcia/ss.h>
++/**
+  * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
+  * @adapter: board private structure
+  *
+@@ -826,11 +875,42 @@
+       txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+       if(!txdr->desc) {
++setup_tx_desc_die:
+               DPRINTK(PROBE, ERR, 
+               "Unable to Allocate Memory for the Transmit descriptor ring\n");
+               vfree(txdr->buffer_info);
+               return -ENOMEM;
+       }
 +
-+#include "i82365.h"
++      /* fix for errata 23, cant cross 64kB boundary */
++      if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
++              void *olddesc = txdr->desc;
++              dma_addr_t olddma = txdr->dma;
++              DPRINTK(TX_ERR,ERR,"txdr align check failed: %u bytes at %p\n",
++                      txdr->size, txdr->desc);
++              /* try again, without freeing the previous */
++              txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
++              /* failed allocation, critial failure */
++              if(!txdr->desc) {
++                      pci_free_consistent(pdev, txdr->size, olddesc, olddma);
++                      goto setup_tx_desc_die;
++              }
 +
-+MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
-+MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
-+MODULE_LICENSE("GPL");
++              if (!e1000_check_64k_bound(adapter, txdr->desc, txdr->size)) {
++                      /* give up */
++                      pci_free_consistent(pdev, txdr->size,
++                           txdr->desc, txdr->dma);
++                      pci_free_consistent(pdev, txdr->size, olddesc, olddma);
++                      DPRINTK(PROBE, ERR,
++                       "Unable to Allocate aligned Memory for the Transmit"
++                       " descriptor ring\n");
++                      vfree(txdr->buffer_info);
++                      return -ENOMEM;
++              } else {
++                      /* free old, move on with the new one since its okay */
++                      pci_free_consistent(pdev, txdr->size, olddesc, olddma);
++              }
++      }
+       memset(txdr->desc, 0, txdr->size);
+       txdr->next_to_use = 0;
+@@ -948,11 +1028,43 @@
+       rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+       if(!rxdr->desc) {
++setup_rx_desc_die:
+               DPRINTK(PROBE, ERR, 
+-              "Unable to Allocate Memory for the Recieve descriptor ring\n");
++              "Unble to Allocate Memory for the Recieve descriptor ring\n");
+               vfree(rxdr->buffer_info);
+               return -ENOMEM;
+       }
 +
-+#define CARD_MAX_SLOTS                2
-+#define CARD_SLOTA            0
-+#define CARD_SLOTB            1
-+#define CARD_SLOTB_OFFSET     0x40
++      /* fix for errata 23, cant cross 64kB boundary */
++      if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
++              void *olddesc = rxdr->desc;
++              dma_addr_t olddma = rxdr->dma;
++              DPRINTK(RX_ERR,ERR,
++                      "rxdr align check failed: %u bytes at %p\n",
++                      rxdr->size, rxdr->desc);
++              /* try again, without freeing the previous */
++              rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
++              /* failed allocation, critial failure */
++              if(!rxdr->desc) {
++                      pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
++                      goto setup_rx_desc_die;
++              }
 +
-+#define CARD_MEM_START                0x10000000
-+#define CARD_MEM_END          0x13ffffff
-+#define CARD_MAX_MEM_OFFSET   0x3ffffff
-+#define CARD_MAX_MEM_SPEED    1000
++              if (!e1000_check_64k_bound(adapter, rxdr->desc, rxdr->size)) {
++                      /* give up */
++                      pci_free_consistent(pdev, rxdr->size,
++                           rxdr->desc, rxdr->dma);
++                      pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
++                      DPRINTK(PROBE, ERR, 
++                              "Unable to Allocate aligned Memory for the"
++                              " Receive descriptor ring\n");
++                      vfree(rxdr->buffer_info);
++                      return -ENOMEM;
++              } else {
++                      /* free old, move on with the new one since its okay */
++                      pci_free_consistent(pdev, rxdr->size, olddesc, olddma);
++              }
++      }
+       memset(rxdr->desc, 0, rxdr->size);
+       rxdr->next_to_clean = 0;
+@@ -1086,6 +1198,7 @@
+                       struct e1000_buffer *buffer_info)
+ {
+       struct pci_dev *pdev = adapter->pdev;
 +
-+#define CARD_CONTROLLER_INDEX 0x03e0
-+#define CARD_CONTROLLER_DATA  0x03e1
-+#define CARD_CONTROLLER_SIZE  2
-+ /* Power register */
-+  #define VPP_GET_VCC         0x01
-+  #define POWER_ENABLE                0x10
-+ #define CARD_VOLTAGE_SENSE   0x1f
-+  #define VCC_3VORXV_CAPABLE  0x00
-+  #define VCC_XV_ONLY         0x01
-+  #define VCC_3V_CAPABLE      0x02
-+  #define VCC_5V_ONLY         0x03
-+ #define CARD_VOLTAGE_SELECT  0x2f
-+  #define VCC_3V              0x01
-+  #define VCC_5V              0x00
-+  #define VCC_XV              0x02
-+  #define VCC_STATUS_3V               0x02
-+  #define VCC_STATUS_5V               0x01
-+  #define VCC_STATUS_XV               0x03
-+ #define GLOBAL_CONTROL               0x1e
-+  #define EXWRBK              0x04
-+  #define IRQPM_EN            0x08
-+  #define CLRPMIRQ            0x10
+       if(buffer_info->dma) {
+               pci_unmap_page(pdev,
+                              buffer_info->dma,
+@@ -1114,6 +1227,11 @@
+       /* Free all the Tx ring sk_buffs */
++      if (likely(adapter->previous_buffer_info.skb != NULL)) {
++              e1000_unmap_and_free_tx_resource(adapter, 
++                              &adapter->previous_buffer_info);
++      }
 +
-+#define IO_MAX_MAPS   2
-+#define MEM_MAX_MAPS  5
+       for(i = 0; i < tx_ring->count; i++) {
+               buffer_info = &tx_ring->buffer_info[i];
+               e1000_unmap_and_free_tx_resource(adapter, buffer_info);
+@@ -1415,7 +1533,6 @@
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_desc_ring *txdr = &adapter->tx_ring;
+-      unsigned int i;
+       uint32_t link;
+       e1000_check_for_link(&adapter->hw);
+@@ -1495,12 +1612,8 @@
+       /* Cause software interrupt to ensure rx ring is cleaned */
+       E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
+-      /* Early detection of hung controller */
+-      i = txdr->next_to_clean;
+-      if(txdr->buffer_info[i].dma &&
+-         time_after(jiffies, txdr->buffer_info[i].time_stamp + HZ) &&
+-         !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
+-              netif_stop_queue(netdev);
++      /* Force detection of hung controller every watchdog period*/
++      adapter->detect_tx_hung = TRUE;
+       /* Reset the timer */
+       mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+@@ -2132,10 +2245,28 @@
+               __netif_rx_schedule(netdev);
+       }
+ #else
++      /* Writing IMC and IMS is needed for 82547.
++         Due to Hub Link bus being occupied, an interrupt
++         de-assertion message is not able to be sent.
++         When an interrupt assertion message is generated later,
++         two messages are re-ordered and sent out.
++         That causes APIC to think 82547 is in de-assertion
++         state, while 82547 is in assertion state, resulting
++         in dead lock. Writing IMC forces 82547 into
++         de-assertion state.
++      */
++      if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2){
++              atomic_inc(&adapter->irq_sem);
++              E1000_WRITE_REG(&adapter->hw, IMC, ~0);
++      }
 +
-+enum {
-+      SLOTB_PROBE = 0,
-+      SLOTB_NOPROBE_IO,
-+      SLOTB_NOPROBE_MEM,
-+      SLOTB_NOPROBE_ALL
-+};
+       for(i = 0; i < E1000_MAX_INTR; i++)
+               if(unlikely(!e1000_clean_rx_irq(adapter) &
+                  !e1000_clean_tx_irq(adapter)))
+                       break;
 +
-+typedef struct vrc4171_socket {
-+      int noprobe;
-+      void (*handler)(void *, unsigned int);
-+      void *info;
-+      socket_cap_t cap;
-+      spinlock_t event_lock;
-+      uint16_t events;
-+      struct socket_info_t *pcmcia_socket;
-+      struct tq_struct tq_task;
-+      char name[24];
-+      int csc_irq;
-+      int io_irq;
-+} vrc4171_socket_t;
++      if(hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2)
++              e1000_irq_enable(adapter);
+ #endif
+       return IRQ_HANDLED;
+@@ -2155,24 +2286,21 @@
+       int tx_cleaned;
+       int work_done = 0;
+       
+-      if (!netif_carrier_ok(netdev))
+-              goto quit_polling;
+-
+       tx_cleaned = e1000_clean_tx_irq(adapter);
+       e1000_clean_rx_irq(adapter, &work_done, work_to_do);
+       *budget -= work_done;
+       netdev->quota -= work_done;
+       
+-      /* if no Rx and Tx cleanup work was done, exit the polling mode */
+-      if(!tx_cleaned || (work_done < work_to_do) || 
++      /* if no Tx and not enough Rx work done, exit the polling mode */
++      if((!tx_cleaned && (work_done < work_to_do)) || 
+                               !netif_running(netdev)) {
+-quit_polling: netif_rx_complete(netdev);
++              netif_rx_complete(netdev);
+               e1000_irq_enable(adapter);
+               return 0;
+       }
+-      return (work_done >= work_to_do);
++      return 1;
+ }
+ #endif
+@@ -2196,11 +2324,34 @@
+       eop_desc = E1000_TX_DESC(*tx_ring, eop);
+       while(eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
++              /* pre-mature writeback of Tx descriptors     */
++              /* clear (free buffers and unmap pci_mapping) */
++              /* previous_buffer_info                       */
++              if (likely(adapter->previous_buffer_info.skb != NULL)) {
++                      e1000_unmap_and_free_tx_resource(adapter, 
++                                      &adapter->previous_buffer_info);
++              }
 +
-+static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS];
-+static int vrc4171_slotb = SLOTB_IS_NONE;
-+static unsigned int vrc4171_irq;
-+static uint16_t vrc4171_irq_mask = 0xdeb8;
+               for(cleaned = FALSE; !cleaned; ) {
+                       tx_desc = E1000_TX_DESC(*tx_ring, i);
+                       buffer_info = &tx_ring->buffer_info[i];
++                      cleaned = (i == eop);
++
++                      /* pre-mature writeback of Tx descriptors */
++                      /* save the cleaning of the this for the  */
++                      /* next iteration                         */
++                      if (cleaned) {
++                              memcpy(&adapter->previous_buffer_info,
++                                      buffer_info,
++                                      sizeof(struct e1000_buffer));
++                              memset(buffer_info,
++                                      0,
++                                      sizeof(struct e1000_buffer));
++                      } else {
++                              e1000_unmap_and_free_tx_resource(adapter, 
++                                                      buffer_info);
++                      }
+-                      e1000_unmap_and_free_tx_resource(adapter, buffer_info);
+                       tx_desc->buffer_addr = 0;
+                       tx_desc->lower.data = 0;
+                       tx_desc->upper.data = 0;
+@@ -2222,6 +2373,16 @@
+               netif_wake_queue(netdev);
+       spin_unlock(&adapter->tx_lock);
++ 
++      if(adapter->detect_tx_hung) {
++              /* detect a transmit hang in hardware, this serializes the
++               * check with the clearing of time_stamp and movement of i */
++              adapter->detect_tx_hung = FALSE;
++              if(tx_ring->buffer_info[i].dma &&
++                 time_after(jiffies, tx_ring->buffer_info[i].time_stamp + HZ) &&
++                 !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
++                      netif_stop_queue(netdev);
++      }
+       return cleaned;
+ }
+@@ -2389,20 +2550,43 @@
+       struct e1000_buffer *buffer_info;
+       struct sk_buff *skb;
+       int reserve_len = 2;
+-      unsigned int i;
++      unsigned int i, bufsz;
+       i = rx_ring->next_to_use;
+       buffer_info = &rx_ring->buffer_info[i];
+       while(!buffer_info->skb) {
++              bufsz = adapter->rx_buffer_len + reserve_len;
+-              skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
+-
++              skb = dev_alloc_skb(bufsz);
+               if(unlikely(!skb)) {
+                       /* Better luck next round */
+                       break;
+               }
++              /* fix for errata 23, cant cross 64kB boundary */
++              if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
++                      struct sk_buff *oldskb = skb;
++                      DPRINTK(RX_ERR,ERR,
++                              "skb align check failed: %u bytes at %p\n",
++                              bufsz, skb->data);
++                      /* try again, without freeing the previous */
++                      skb = dev_alloc_skb(bufsz);
++                      if (!skb) {
++                              dev_kfree_skb(oldskb);
++                              break;
++                      }
++                      if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
++                              /* give up */
++                              dev_kfree_skb(skb);
++                              dev_kfree_skb(oldskb);
++                              break; /* while !buffer_info->skb */
++                      } else {
++                              /* move on with the new one */
++                              dev_kfree_skb(oldskb);
++                      }
++              }
 +
-+extern struct socket_info_t *pcmcia_register_socket(int slot,
-+                                                    struct pccard_operations *vtable,
-+                                                    int use_bus_pm);
-+extern void pcmcia_unregister_socket(struct socket_info_t *s);
+               /* Make buffer alignment 2 beyond a 16 byte boundary
+                * this will result in a 16 byte aligned IP header after
+                * the 14 byte MAC header is removed
+@@ -2418,6 +2602,25 @@
+                                                 adapter->rx_buffer_len,
+                                                 PCI_DMA_FROMDEVICE);
++              /* fix for errata 23, cant cross 64kB boundary */
++              if(!e1000_check_64k_bound(adapter,
++                                             (void *)(unsigned long)buffer_info->dma,
++                                             adapter->rx_buffer_len)) {
++                      DPRINTK(RX_ERR,ERR,
++                              "dma align check failed: %u bytes at %ld\n",
++                              adapter->rx_buffer_len, (unsigned long)buffer_info->dma);
++
++                      dev_kfree_skb(skb);
++                      buffer_info->skb = NULL;
++
++                      pci_unmap_single(pdev,
++                                       buffer_info->dma,
++                                       adapter->rx_buffer_len,
++                                       PCI_DMA_FROMDEVICE);
++
++                      break; /* while !buffer_info->skb */
++              }
 +
-+static inline uint8_t exca_read_byte(int slot, uint8_t index)
-+{
-+      if (slot == CARD_SLOTB)
-+              index += CARD_SLOTB_OFFSET;
+               rx_desc = E1000_RX_DESC(*rx_ring, i);
+               rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+diff -Nur linux-2.4.29/drivers/net/hamradio/hdlcdrv.c linux-mips/drivers/net/hamradio/hdlcdrv.c
+--- linux-2.4.29/drivers/net/hamradio/hdlcdrv.c        2002-02-25 20:37:59.000000000 +0100
++++ linux-mips/drivers/net/hamradio/hdlcdrv.c  2004-05-04 14:04:27.000000000 +0200
+@@ -587,6 +587,8 @@
+               return -EINVAL;
+       s = (struct hdlcdrv_state *)dev->priv;
++      netif_stop_queue(dev);
 +
-+      outb(index, CARD_CONTROLLER_INDEX);
-+      return inb(CARD_CONTROLLER_DATA);
-+}
+       if (s->ops && s->ops->close)
+               i = s->ops->close(dev);
+       if (s->skb)
+diff -Nur linux-2.4.29/drivers/net/irda/au1k_ir.c linux-mips/drivers/net/irda/au1k_ir.c
+--- linux-2.4.29/drivers/net/irda/au1k_ir.c    2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/net/irda/au1k_ir.c      2005-03-26 11:47:31.367503613 +0100
+@@ -81,10 +81,6 @@
+ #define RUN_AT(x) (jiffies + (x))
+-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+-static BCSR * const bcsr = (BCSR *)0xAE000000;
+-#endif
+-
+ static spinlock_t ir_lock = SPIN_LOCK_UNLOCKED;
+ /*
+diff -Nur linux-2.4.29/drivers/net/sk98lin/skvpd.c linux-mips/drivers/net/sk98lin/skvpd.c
+--- linux-2.4.29/drivers/net/sk98lin/skvpd.c   2004-04-14 15:05:30.000000000 +0200
++++ linux-mips/drivers/net/sk98lin/skvpd.c     2005-03-26 11:47:31.369503284 +0100
+@@ -466,6 +466,15 @@
+       
+       pAC->vpd.vpd_size = vpd_size;
++      /* Asus K8V Se Deluxe bugfix. Correct VPD content */
++      /* MBo April 2004 */
++      if( ((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) &&
++          ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
++          ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45) ) {
++              printk(KERN_INFO "sk98lin : humm... Asus mainboard with buggy VPD ? correcting data.\n");
++              (unsigned char)pAC->vpd.vpd_buf[0x40] = 0x38;
++      }
 +
-+static inline uint16_t exca_read_word(int slot, uint8_t index)
-+{
-+      uint16_t data;
+       /* find the end tag of the RO area */
+       if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
+               SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+diff -Nur linux-2.4.29/drivers/net/tg3.c linux-mips/drivers/net/tg3.c
+--- linux-2.4.29/drivers/net/tg3.c     2005-01-19 15:09:56.000000000 +0100
++++ linux-mips/drivers/net/tg3.c       2005-03-26 11:47:30.480649166 +0100
+@@ -59,8 +59,8 @@
+ #define DRV_MODULE_NAME               "tg3"
+ #define PFX DRV_MODULE_NAME   ": "
+-#define DRV_MODULE_VERSION    "3.15"
+-#define DRV_MODULE_RELDATE    "January 6, 2005"
++#define DRV_MODULE_VERSION    "3.24"
++#define DRV_MODULE_RELDATE    "March 4, 2005"
+ #define TG3_DEF_MAC_MODE      0
+ #define TG3_DEF_RX_MODE               0
+@@ -575,9 +575,10 @@
+       if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
+               return;
+-      tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007);
+-      tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
+-      tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4)));
++      if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) &&
++          !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val))
++              tg3_writephy(tp, MII_TG3_AUX_CTRL,
++                           (val | (1 << 15) | (1 << 4)));
+ }
+ static int tg3_bmcr_reset(struct tg3 *tp)
+@@ -618,9 +619,10 @@
+       while (limit--) {
+               u32 tmp32;
+-              tg3_readphy(tp, 0x16, &tmp32);
+-              if ((tmp32 & 0x1000) == 0)
+-                      break;
++              if (!tg3_readphy(tp, 0x16, &tmp32)) {
++                      if ((tmp32 & 0x1000) == 0)
++                              break;
++              }
+       }
+       if (limit <= 0)
+               return -EBUSY;
+@@ -672,9 +674,9 @@
+               for (i = 0; i < 6; i += 2) {
+                       u32 low, high;
+-                      tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
+-                      tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
+-                      if (tg3_wait_macro_done(tp)) {
++                      if (tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low) ||
++                          tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high) ||
++                          tg3_wait_macro_done(tp)) {
+                               *resetp = 1;
+                               return -EBUSY;
+                       }
+@@ -730,7 +732,9 @@
+               }
+               /* Disable transmitter and interrupt.  */
+-              tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
++              if (tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32))
++                      continue;
 +
-+      if (slot == CARD_SLOTB)
-+              index += CARD_SLOTB_OFFSET;
+               reg32 |= 0x3000;
+               tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+@@ -739,7 +743,9 @@
+                            BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
+               /* Set to master mode.  */
+-              tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
++              if (tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig))
++                      continue;
 +
-+      outb(index++, CARD_CONTROLLER_INDEX);
-+      data = inb(CARD_CONTROLLER_DATA);
+               tg3_writephy(tp, MII_TG3_CTRL,
+                            (MII_TG3_CTRL_AS_MASTER |
+                             MII_TG3_CTRL_ENABLE_AS_MASTER));
+@@ -777,9 +783,11 @@
+       tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
+-      tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+-      reg32 &= ~0x3000;
+-      tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
++      if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32)) {
++              reg32 &= ~0x3000;
++              tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
++      } else if (!err)
++              err = -EBUSY;
+       return err;
+ }
+@@ -843,9 +851,9 @@
+               u32 phy_reg;
+               /* Set bit 14 with read-modify-write to preserve other bits */
+-              tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007);
+-              tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg);
+-              tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
++              if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) &&
++                  !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg))
++                      tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
+       }
+       tg3_phy_set_wirespeed(tp);
+       return 0;
+@@ -877,7 +885,7 @@
+                             GRC_LCLCTRL_GPIO_OUTPUT1));
+                       udelay(100);
+               } else {
+-                      int no_gpio2;
++                      u32 no_gpio2;
+                       u32 grc_local_ctrl;
+                       if (tp_peer != tp &&
+@@ -885,8 +893,8 @@
+                               return;
+                       /* On 5753 and variants, GPIO2 cannot be used. */
+-                      no_gpio2 = (tp->nic_sram_data_cfg &
+-                                  NIC_SRAM_DATA_CFG_NO_GPIO2) != 0;
++                      no_gpio2 = tp->nic_sram_data_cfg &
++                                  NIC_SRAM_DATA_CFG_NO_GPIO2;
+                       grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+                                        GRC_LCLCTRL_GPIO_OE1 |
+@@ -898,29 +906,17 @@
+                                                   GRC_LCLCTRL_GPIO_OUTPUT2);
+                       }
+                       tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+-                             grc_local_ctrl);
++                                              grc_local_ctrl);
+                       udelay(100);
+-                      grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+-                                       GRC_LCLCTRL_GPIO_OE1 |
+-                                       GRC_LCLCTRL_GPIO_OE2 |
+-                                       GRC_LCLCTRL_GPIO_OUTPUT0 |
+-                                       GRC_LCLCTRL_GPIO_OUTPUT1 |
+-                                       GRC_LCLCTRL_GPIO_OUTPUT2;
+-                      if (no_gpio2) {
+-                              grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 |
+-                                                  GRC_LCLCTRL_GPIO_OUTPUT2);
+-                      }
++                      grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0;
++
+                       tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+-                             grc_local_ctrl);
++                                              grc_local_ctrl);
+                       udelay(100);
+-                      grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 |
+-                                       GRC_LCLCTRL_GPIO_OE1 |
+-                                       GRC_LCLCTRL_GPIO_OE2 |
+-                                       GRC_LCLCTRL_GPIO_OUTPUT0 |
+-                                       GRC_LCLCTRL_GPIO_OUTPUT1;
+                       if (!no_gpio2) {
++                              grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2;
+                               tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+                                      grc_local_ctrl);
+                               udelay(100);
+@@ -1240,7 +1236,7 @@
+       };
+ }
+-static int tg3_phy_copper_begin(struct tg3 *tp)
++static void tg3_phy_copper_begin(struct tg3 *tp)
+ {
+       u32 new_adv;
+       int i;
+@@ -1355,15 +1351,16 @@
+               if (tp->link_config.duplex == DUPLEX_FULL)
+                       bmcr |= BMCR_FULLDPLX;
+-              tg3_readphy(tp, MII_BMCR, &orig_bmcr);
+-              if (bmcr != orig_bmcr) {
++              if (!tg3_readphy(tp, MII_BMCR, &orig_bmcr) &&
++                  (bmcr != orig_bmcr)) {
+                       tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK);
+                       for (i = 0; i < 1500; i++) {
+                               u32 tmp;
+                               udelay(10);
+-                              tg3_readphy(tp, MII_BMSR, &tmp);
+-                              tg3_readphy(tp, MII_BMSR, &tmp);
++                              if (tg3_readphy(tp, MII_BMSR, &tmp) ||
++                                  tg3_readphy(tp, MII_BMSR, &tmp))
++                                      continue;
+                               if (!(tmp & BMSR_LSTATUS)) {
+                                       udelay(40);
+                                       break;
+@@ -1376,8 +1373,6 @@
+               tg3_writephy(tp, MII_BMCR,
+                            BMCR_ANENABLE | BMCR_ANRESTART);
+       }
+-
+-      return 0;
+ }
+ static int tg3_init_5401phy_dsp(struct tg3 *tp)
+@@ -1412,7 +1407,9 @@
+ {
+       u32 adv_reg, all_mask;
+-      tg3_readphy(tp, MII_ADVERTISE, &adv_reg);
++      if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
++              return 0;
 +
-+      outb(index, CARD_CONTROLLER_INDEX);
-+      data |= ((uint16_t)inb(CARD_CONTROLLER_DATA)) << 8;
+       all_mask = (ADVERTISE_10HALF | ADVERTISE_10FULL |
+                   ADVERTISE_100HALF | ADVERTISE_100FULL);
+       if ((adv_reg & all_mask) != all_mask)
+@@ -1420,7 +1417,9 @@
+       if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
+               u32 tg3_ctrl;
+-              tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl);
++              if (tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl))
++                      return 0;
 +
-+      return data;
-+}
+               all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
+                           MII_TG3_CTRL_ADV_1000_FULL);
+               if ((tg3_ctrl & all_mask) != all_mask)
+@@ -1460,8 +1459,8 @@
+            GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
+           netif_carrier_ok(tp->dev)) {
+               tg3_readphy(tp, MII_BMSR, &bmsr);
+-              tg3_readphy(tp, MII_BMSR, &bmsr);
+-              if (!(bmsr & BMSR_LSTATUS))
++              if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
++                  !(bmsr & BMSR_LSTATUS))
+                       force_reset = 1;
+       }
+       if (force_reset)
+@@ -1469,9 +1468,8 @@
+       if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
+               tg3_readphy(tp, MII_BMSR, &bmsr);
+-              tg3_readphy(tp, MII_BMSR, &bmsr);
+-
+-              if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
++              if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
++                  !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+                       bmsr = 0;
+               if (!(bmsr & BMSR_LSTATUS)) {
+@@ -1482,8 +1480,8 @@
+                       tg3_readphy(tp, MII_BMSR, &bmsr);
+                       for (i = 0; i < 1000; i++) {
+                               udelay(10);
+-                              tg3_readphy(tp, MII_BMSR, &bmsr);
+-                              if (bmsr & BMSR_LSTATUS) {
++                              if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
++                                  (bmsr & BMSR_LSTATUS)) {
+                                       udelay(40);
+                                       break;
+                               }
+@@ -1545,8 +1543,8 @@
+       bmsr = 0;
+       for (i = 0; i < 100; i++) {
+               tg3_readphy(tp, MII_BMSR, &bmsr);
+-              tg3_readphy(tp, MII_BMSR, &bmsr);
+-              if (bmsr & BMSR_LSTATUS)
++              if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
++                  (bmsr & BMSR_LSTATUS))
+                       break;
+               udelay(40);
+       }
+@@ -1557,8 +1555,8 @@
+               tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+               for (i = 0; i < 2000; i++) {
+                       udelay(10);
+-                      tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
+-                      if (aux_stat)
++                      if (!tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat) &&
++                          aux_stat)
+                               break;
+               }
+@@ -1569,7 +1567,8 @@
+               bmcr = 0;
+               for (i = 0; i < 200; i++) {
+                       tg3_readphy(tp, MII_BMCR, &bmcr);
+-                      tg3_readphy(tp, MII_BMCR, &bmcr);
++                      if (tg3_readphy(tp, MII_BMCR, &bmcr))
++                              continue;
+                       if (bmcr && bmcr != 0x7fff)
+                               break;
+                       udelay(10);
+@@ -1606,10 +1605,13 @@
+           (tp->link_config.autoneg == AUTONEG_ENABLE)) {
+               u32 local_adv, remote_adv;
+-              tg3_readphy(tp, MII_ADVERTISE, &local_adv);
++              if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
++                      local_adv = 0;
+               local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
+-              tg3_readphy(tp, MII_LPA, &remote_adv);
++              if (tg3_readphy(tp, MII_LPA, &remote_adv))
++                      remote_adv = 0;
++
+               remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
+               /* If we are not advertising full pause capability,
+@@ -1628,8 +1630,8 @@
+               tg3_phy_copper_begin(tp);
+               tg3_readphy(tp, MII_BMSR, &tmp);
+-              tg3_readphy(tp, MII_BMSR, &tmp);
+-              if (tmp & BMSR_LSTATUS)
++              if (!tg3_readphy(tp, MII_BMSR, &tmp) &&
++                  (tmp & BMSR_LSTATUS))
+                       current_link_up = 1;
+       }
+@@ -2130,8 +2132,9 @@
+               if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
+                       port_a = 0;
+-              serdes_cfg = tr32(MAC_SERDES_CFG) &
+-                      ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20));
++              /* preserve bits 0-11,13,14 for signal pre-emphasis */
++              /* preserve bits 20-23 for voltage regulator */
++              serdes_cfg = tr32(MAC_SERDES_CFG) & 0x00f06fff;
+       }
+       sg_dig_ctrl = tr32(SG_DIG_CTRL);
+@@ -2142,9 +2145,9 @@
+                               u32 val = serdes_cfg;
+                               if (port_a)
+-                                      val |= 0xc010880;
++                                      val |= 0xc010000;
+                               else
+-                                      val |= 0x4010880;
++                                      val |= 0x4010000;
+                               tw32_f(MAC_SERDES_CFG, val);
+                       }
+                       tw32_f(SG_DIG_CTRL, 0x01388400);
+@@ -2167,7 +2170,7 @@
+       if (sg_dig_ctrl != expected_sg_dig_ctrl) {
+               if (workaround)
+-                      tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011880);
++                      tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
+               udelay(5);
+               tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
+@@ -2208,9 +2211,9 @@
+                                       u32 val = serdes_cfg;
+                                       if (port_a)
+-                                              val |= 0xc010880;
++                                              val |= 0xc010000;
+                                       else
+-                                              val |= 0x4010880;
++                                              val |= 0x4010000;
+                                       tw32_f(MAC_SERDES_CFG, val);
+                               }
+@@ -2218,8 +2221,12 @@
+                               tw32_f(SG_DIG_CTRL, 0x01388400);
+                               udelay(40);
++                              /* Link parallel detection - link is up */
++                              /* only if we have PCS_SYNC and not */
++                              /* receiving config code words */
+                               mac_status = tr32(MAC_STATUS);
+-                              if (mac_status & MAC_STATUS_PCS_SYNCED) {
++                              if ((mac_status & MAC_STATUS_PCS_SYNCED) &&
++                                  !(mac_status & MAC_STATUS_RCVD_CFG)) {
+                                       tg3_setup_flow_control(tp, 0, 0);
+                                       current_link_up = 1;
+                               }
+@@ -2690,7 +2697,11 @@
+               len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
+-              if (len > RX_COPY_THRESHOLD) {
++              if (len > RX_COPY_THRESHOLD 
++                      && tp->rx_offset == 2
++                      /* rx_offset != 2 iff this is a 5701 card running
++                       * in PCI-X mode [see tg3_get_invariants()] */
++              ) {
+                       int skb_size;
+                       skb_size = tg3_alloc_rx_skb(tp, opaque_key,
+@@ -3085,11 +3096,19 @@
+               skb->nh.iph->check = 0;
+               skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
+-              skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+-                                                    skb->nh.iph->daddr,
+-                                                    0, IPPROTO_TCP, 0);
++              if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
++                      skb->h.th->check = 0;
++                      base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
++              }
++              else {
++                      skb->h.th->check =
++                              ~csum_tcpudp_magic(skb->nh.iph->saddr,
++                                                 skb->nh.iph->daddr,
++                                                 0, IPPROTO_TCP, 0);
++              }
+-              if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
++              if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
++                  (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
+                       if (tcp_opt_len || skb->nh.iph->ihl > 5) {
+                               int tsflags;
+@@ -3156,7 +3175,7 @@
+                               would_hit_hwbug = entry + 1;
+                       }
+-                      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
++                      if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+                               tg3_set_txd(tp, entry, mapping, len,
+                                           base_flags, (i == last)|(mss << 1));
+                       else
+@@ -3655,8 +3674,9 @@
+ /* tp->lock is held. */
+ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
+ {
+-      tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
+-                    NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
++      if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X))
++              tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
++                            NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
+       if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
+               switch (kind) {
+@@ -3860,19 +3880,20 @@
+               tw32_f(MAC_MODE, 0);
+       udelay(40);
+-      /* Wait for firmware initialization to complete. */
+-      for (i = 0; i < 100000; i++) {
+-              tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+-              if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+-                      break;
+-              udelay(10);
+-      }
+-      if (i >= 100000 &&
+-          !(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
+-              printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
+-                     "firmware will not restart magic=%08x\n",
+-                     tp->dev->name, val);
+-              return -ENODEV;
++      if (!(tp->tg3_flags2 & TG3_FLG2_SUN_570X)) {
++              /* Wait for firmware initialization to complete. */
++              for (i = 0; i < 100000; i++) {
++                      tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
++                      if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
++                              break;
++                      udelay(10);
++              }
++              if (i >= 100000) {
++                      printk(KERN_ERR PFX "tg3_reset_hw timed out for %s, "
++                             "firmware will not restart magic=%08x\n",
++                             tp->dev->name, val);
++                      return -ENODEV;
++              }
+       }
+       if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+@@ -4747,7 +4768,7 @@
+       unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
+       int err, i;
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
++      if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+               return 0;
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+@@ -4831,9 +4852,8 @@
+               tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
+       }
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+-          GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+-          GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
++      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 ||
++          GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+               for (i = 0; i < 12; i++) {
+                       tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high);
+                       tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low);
+@@ -4879,7 +4899,8 @@
+                     (bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
+                      maxlen_flags);
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
++      if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
++          (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750))
+               tg3_write_mem(tp,
+                             (bdinfo_addr + TG3_BDINFO_NIC_ADDR),
+                             nic_addr);
+@@ -5181,7 +5202,7 @@
+       }
+ #if TG3_TSO_SUPPORT != 0
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
++      if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+               rdmac_mode |= (1 << 27);
+ #endif
+@@ -5331,7 +5352,7 @@
+       tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
+       tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
+ #if TG3_TSO_SUPPORT != 0
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
++      if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+               tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
+ #endif
+       tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
+@@ -5381,8 +5402,10 @@
+       udelay(10);
+       if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
+-              if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
++              if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
++                      !(tp->tg3_flags2 & TG3_FLG2_SERDES_PREEMPHASIS)) {
+                       /* Set drive transmission level to 1.2V  */
++                      /* only if the signal pre-emphasis bit is not set  */
+                       val = tr32(MAC_SERDES_CFG);
+                       val &= 0xfffff000;
+                       val |= 0x880;
+@@ -5411,9 +5434,10 @@
+               u32 tmp;
+               /* Clear CRC stats. */
+-              tg3_readphy(tp, 0x1e, &tmp);
+-              tg3_writephy(tp, 0x1e, tmp | 0x8000);
+-              tg3_readphy(tp, 0x14, &tmp);
++              if (!tg3_readphy(tp, 0x1e, &tmp)) {
++                      tg3_writephy(tp, 0x1e, tmp | 0x8000);
++                      tg3_readphy(tp, 0x14, &tmp);
++              }
+       }
+       __tg3_set_rx_mode(tp->dev);
+@@ -6003,9 +6027,11 @@
+               u32 val;
+               spin_lock_irqsave(&tp->lock, flags);
+-              tg3_readphy(tp, 0x1e, &val);
+-              tg3_writephy(tp, 0x1e, val | 0x8000);
+-              tg3_readphy(tp, 0x14, &val);
++              if (!tg3_readphy(tp, 0x1e, &val)) {
++                      tg3_writephy(tp, 0x1e, val | 0x8000);
++                      tg3_readphy(tp, 0x14, &val);
++              } else
++                      val = 0;
+               spin_unlock_irqrestore(&tp->lock, flags);
+               tp->phy_crc_errors += val;
+@@ -6349,11 +6375,13 @@
+ static int tg3_get_eeprom_len(struct net_device *dev)
+ {
+-      return EEPROM_CHIP_SIZE;
++      struct tg3 *tp = netdev_priv(dev);
 +
-+static inline uint8_t exca_write_byte(int slot, uint8_t index, uint8_t data)
++      return tp->nvram_size;
+ }
+-static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
+-                                      u32 offset, u32 *val);
++static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
++
+ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
+ {
+       struct tg3 *tp = dev->priv;
+@@ -6365,10 +6393,7 @@
+       len = eeprom->len;
+       eeprom->len = 0;
+-      ret = tg3_nvram_read_using_eeprom(tp, 0, &eeprom->magic);
+-      if (ret)
+-              return ret;
+-      eeprom->magic = swab32(eeprom->magic);
++      eeprom->magic = TG3_EEPROM_MAGIC;
+       if (offset & 3) {
+               /* adjustments to start on required 4 byte boundary */
+@@ -6378,9 +6403,10 @@
+                       /* i.e. offset=1 len=2 */
+                       b_count = len;
+               }
+-              ret = tg3_nvram_read_using_eeprom(tp, offset-b_offset, &val);
++              ret = tg3_nvram_read(tp, offset-b_offset, &val);
+               if (ret)
+                       return ret;
++              val = cpu_to_le32(val);
+               memcpy(data, ((char*)&val) + b_offset, b_count);
+               len -= b_count;
+               offset += b_count;
+@@ -6390,12 +6416,13 @@
+       /* read bytes upto the last 4 byte boundary */
+       pd = &data[eeprom->len];
+       for (i = 0; i < (len - (len & 3)); i += 4) {
+-              ret = tg3_nvram_read_using_eeprom(tp, offset + i, 
+-                              (u32*)(pd + i));
++              ret = tg3_nvram_read(tp, offset + i, &val);
+               if (ret) {
+                       eeprom->len += i;
+                       return ret;
+               }
++              val = cpu_to_le32(val);
++              memcpy(pd + i, &val, 4);
+       }
+       eeprom->len += i;
+@@ -6404,15 +6431,72 @@
+               pd = &data[eeprom->len];
+               b_count = len & 3;
+               b_offset = offset + len - b_count;
+-              ret = tg3_nvram_read_using_eeprom(tp, b_offset, &val);
++              ret = tg3_nvram_read(tp, b_offset, &val);
+               if (ret)
+                       return ret;
++              val = cpu_to_le32(val);
+               memcpy(pd, ((char*)&val), b_count);
+               eeprom->len += b_count;
+       }
+       return 0;
+ }
++static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf); 
++
++static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 +{
-+      if (slot == CARD_SLOTB)
-+              index += CARD_SLOTB_OFFSET;
++      struct tg3 *tp = netdev_priv(dev);
++      int ret;
++      u32 offset, len, b_offset, odd_len, start, end;
++      u8 *buf;
 +
-+      outb(index, CARD_CONTROLLER_INDEX);
-+      outb(data, CARD_CONTROLLER_DATA);
++      if (eeprom->magic != TG3_EEPROM_MAGIC)
++              return -EINVAL;
 +
-+      return data;
-+}
++      offset = eeprom->offset;
++      len = eeprom->len;
++
++      if ((b_offset = (offset & 3))) {
++              /* adjustments to start on required 4 byte boundary */
++              ret = tg3_nvram_read(tp, offset-b_offset, &start);
++              if (ret)
++                      return ret;
++              start = cpu_to_le32(start);
++              len += b_offset;
++              offset &= ~3;
++      }
 +
-+static inline uint16_t exca_write_word(int slot, uint8_t index, uint16_t data)
-+{
-+      if (slot == CARD_SLOTB)
-+              index += CARD_SLOTB_OFFSET;
++      odd_len = 0;
++      if ((len & 3) && ((len > 4) || (b_offset == 0))) {
++              /* adjustments to end on required 4 byte boundary */
++              odd_len = 1;
++              len = (len + 3) & ~3;
++              ret = tg3_nvram_read(tp, offset+len-4, &end);
++              if (ret)
++                      return ret;
++              end = cpu_to_le32(end);
++      }
 +
-+      outb(index++, CARD_CONTROLLER_INDEX);
-+      outb(data, CARD_CONTROLLER_DATA);
++      buf = data;
++      if (b_offset || odd_len) {
++              buf = kmalloc(len, GFP_KERNEL);
++              if (buf == 0)
++                      return -ENOMEM;
++              if (b_offset)
++                      memcpy(buf, &start, 4);
++              if (odd_len)
++                      memcpy(buf+len-4, &end, 4);
++              memcpy(buf + b_offset, data, eeprom->len);
++      }
 +
-+      outb(index, CARD_CONTROLLER_INDEX);
-+      outb((uint8_t)(data >> 8), CARD_CONTROLLER_DATA);
++      ret = tg3_nvram_write_block(tp, offset, len, buf);
 +
-+      return data;
++      if (buf != data)
++              kfree(buf);
++
++      return ret;
 +}
 +
-+static inline int search_nonuse_irq(void)
+ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+       struct tg3 *tp = netdev_priv(dev);
+@@ -6561,10 +6645,10 @@
+       int r;
+   
+       spin_lock_irq(&tp->lock);
+-      tg3_readphy(tp, MII_BMCR, &bmcr);
+-      tg3_readphy(tp, MII_BMCR, &bmcr);
+       r = -EINVAL;
+-      if (bmcr & BMCR_ANENABLE) {
++      tg3_readphy(tp, MII_BMCR, &bmcr);
++      if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
++          (bmcr & BMCR_ANENABLE)) {
+               tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
+               r = 0;
+       }
+@@ -6812,6 +6896,7 @@
+       .get_link               = ethtool_op_get_link,
+       .get_eeprom_len         = tg3_get_eeprom_len,
+       .get_eeprom             = tg3_get_eeprom,
++      .set_eeprom             = tg3_set_eeprom,
+       .get_ringparam          = tg3_get_ringparam,
+       .set_ringparam          = tg3_set_ringparam,
+       .get_pauseparam         = tg3_get_pauseparam,
+@@ -6831,6 +6916,103 @@
+       .get_ethtool_stats      = tg3_get_ethtool_stats,
+ };
++static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
 +{
-+      int i;
++      u32 cursize, val;
 +
-+      for (i = 0; i < 16; i++) {
-+              if (vrc4171_irq_mask & (1 << i)) {
-+                      vrc4171_irq_mask &= ~(1 << i);
-+                      return i;
-+              }
++      tp->nvram_size = EEPROM_CHIP_SIZE;
++
++      if (tg3_nvram_read(tp, 0, &val) != 0)
++              return;
++
++      if (swab32(val) != TG3_EEPROM_MAGIC)
++              return;
++
++      /*
++       * Size the chip by reading offsets at increasing powers of two.
++       * When we encounter our validation signature, we know the addressing
++       * has wrapped around, and thus have our chip size.
++       */
++      cursize = 0x800;
++
++      while (cursize < tp->nvram_size) {
++              if (tg3_nvram_read(tp, cursize, &val) != 0)
++                      return;
++
++              if (swab32(val) == TG3_EEPROM_MAGIC)
++                      break;
++
++              cursize <<= 1;
 +      }
 +
-+      return -1;
++      tp->nvram_size = cursize;
 +}
-+
-+static int pccard_init(unsigned int slot)
++              
++static void __devinit tg3_get_nvram_size(struct tg3 *tp)
 +{
-+      vrc4171_socket_t *socket = &vrc4171_sockets[slot];
++      u32 val;
 +
-+      socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
-+      socket->cap.irq_mask = 0;
-+      socket->cap.pci_irq = vrc4171_irq;
-+      socket->cap.map_size = 0x1000;
-+      socket->events = 0;
-+      spin_lock_init(socket->event_lock);
-+      socket->csc_irq = search_nonuse_irq();
-+      socket->io_irq = search_nonuse_irq();
-+
-+      return 0;
++      if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
++              if (val != 0) {
++                      tp->nvram_size = (val >> 16) * 1024;
++                      return;
++              }
++      }
++      tp->nvram_size = 0x20000;
 +}
 +
-+static int pccard_suspend(unsigned int slot)
++static void __devinit tg3_get_nvram_info(struct tg3 *tp)
 +{
-+      return -EINVAL;
-+}
++      u32 nvcfg1;
 +
-+static int pccard_register_callback(unsigned int slot,
-+                                    void (*handler)(void *, unsigned int),
-+                                    void *info)
-+{
-+      vrc4171_socket_t *socket;
++      nvcfg1 = tr32(NVRAM_CFG1);
++      if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
++              tp->tg3_flags2 |= TG3_FLG2_FLASH;
++      }
++      else {
++              nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
++              tw32(NVRAM_CFG1, nvcfg1);
++      }
 +
-+      if (slot >= CARD_MAX_SLOTS)
-+              return -EINVAL;
++      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
++              switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
++                      case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
++                              tp->nvram_jedecnum = JEDEC_ATMEL;
++                              tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
++                              tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
++                              break;
++                      case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
++                              tp->nvram_jedecnum = JEDEC_ATMEL;
++                              tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE;
++                              break;
++                      case FLASH_VENDOR_ATMEL_EEPROM:
++                              tp->nvram_jedecnum = JEDEC_ATMEL;
++                              tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
++                              tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
++                              break;
++                      case FLASH_VENDOR_ST:
++                              tp->nvram_jedecnum = JEDEC_ST;
++                              tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
++                              tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
++                              break;
++                      case FLASH_VENDOR_SAIFUN:
++                              tp->nvram_jedecnum = JEDEC_SAIFUN;
++                              tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE;
++                              break;
++                      case FLASH_VENDOR_SST_SMALL:
++                      case FLASH_VENDOR_SST_LARGE:
++                              tp->nvram_jedecnum = JEDEC_SST;
++                              tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE;
++                              break;
++              }
++      }
++      else {
++              tp->nvram_jedecnum = JEDEC_ATMEL;
++              tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
++              tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
++      }
++}
 +
-+      socket = &vrc4171_sockets[slot];
+ /* Chips other than 5700/5701 use the NVRAM for fetching info. */
+ static void __devinit tg3_nvram_init(struct tg3 *tp)
+ {
+@@ -6855,32 +7037,27 @@
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
+-              u32 nvcfg1;
++              tp->tg3_flags |= TG3_FLAG_NVRAM;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+                       u32 nvaccess = tr32(NVRAM_ACCESS);
+-                      tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
++                      tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+               }
+-              nvcfg1 = tr32(NVRAM_CFG1);
+-
+-              tp->tg3_flags |= TG3_FLAG_NVRAM;
+-              if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
+-                      if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
+-                              tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+-              } else {
+-                      nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+-                      tw32(NVRAM_CFG1, nvcfg1);
+-              }
++              tg3_get_nvram_info(tp);
++              tg3_get_nvram_size(tp);
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+                       u32 nvaccess = tr32(NVRAM_ACCESS);
+-                      tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
++                      tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+               }
 +
-+      socket->handler = handler;
-+      socket->info = info;
+       } else {
+               tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
 +
-+      if (handler)
-+              MOD_INC_USE_COUNT;
-+      else
-+              MOD_DEC_USE_COUNT;
++              tg3_get_eeprom_size(tp);
+       }
+ }
+@@ -6918,11 +7095,30 @@
+       return 0;
+ }
+-static int __devinit tg3_nvram_read(struct tg3 *tp,
+-                                  u32 offset, u32 *val)
++#define NVRAM_CMD_TIMEOUT 10000
 +
++static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
+ {
+       int i;
++      tw32(NVRAM_CMD, nvram_cmd);
++      for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
++              udelay(10);
++              if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
++                      udelay(10);
++                      break;
++              }
++      }
++      if (i == NVRAM_CMD_TIMEOUT) {
++              return -EBUSY;
++      }
 +      return 0;
 +}
 +
-+static int pccard_inquire_socket(unsigned int slot, socket_cap_t *cap)
++static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
 +{
-+      vrc4171_socket_t *socket;
++      int ret;
 +
-+      if (slot >= CARD_MAX_SLOTS || cap == NULL)
-+              return -EINVAL;
+       if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+               printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n");
+               return -EINVAL;
+@@ -6931,10 +7127,14 @@
+       if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
+               return tg3_nvram_read_using_eeprom(tp, offset, val);
+-      if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
+-              offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
+-                        NVRAM_BUFFERED_PAGE_POS) +
+-                      (offset % NVRAM_BUFFERED_PAGE_SIZE);
++      if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
++              (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
++              (tp->nvram_jedecnum == JEDEC_ATMEL)) {
++
++              offset = ((offset / tp->nvram_pagesize) <<
++                        ATMEL_AT45DB0X1B_PAGE_POS) +
++                      (offset % tp->nvram_pagesize);
++      }
+       if (offset > NVRAM_ADDR_MSK)
+               return -EINVAL;
+@@ -6948,19 +7148,11 @@
+       }
+       tw32(NVRAM_ADDR, offset);
+-      tw32(NVRAM_CMD,
+-           NVRAM_CMD_RD | NVRAM_CMD_GO |
+-           NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
++      ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
++              NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+-      /* Wait for done bit to clear. */
+-      for (i = 0; i < 1000; i++) {
+-              udelay(10);
+-              if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
+-                      udelay(10);
+-                      *val = swab32(tr32(NVRAM_RDDATA));
+-                      break;
+-              }
+-      }
++      if (ret == 0)
++              *val = swab32(tr32(NVRAM_RDDATA));
+       tg3_nvram_unlock(tp);
+@@ -6970,10 +7162,268 @@
+               tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+       }
+-      if (i >= 1000)
+-              return -EBUSY;
++      return ret;
++}
+-      return 0;
++static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
++                                  u32 offset, u32 len, u8 *buf)
++{
++      int i, j, rc = 0;
++      u32 val;
 +
-+      socket = &vrc4171_sockets[slot];
++      for (i = 0; i < len; i += 4) {
++              u32 addr, data;
 +
-+      *cap = socket->cap;
++              addr = offset + i;
 +
-+      return 0;
-+}
++              memcpy(&data, buf + i, 4);
 +
-+static int pccard_get_status(unsigned int slot, u_int *value)
-+{
-+      uint8_t status, sense;
-+      u_int val = 0;
++              tw32(GRC_EEPROM_DATA, cpu_to_le32(data));
 +
-+      if (slot >= CARD_MAX_SLOTS || value == NULL)
-+              return -EINVAL;
++              val = tr32(GRC_EEPROM_ADDR);
++              tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
 +
-+      status = exca_read_byte(slot, I365_STATUS);
-+      if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
-+              if (status & I365_CS_STSCHG)
-+                      val |= SS_STSCHG;
-+      } else {
-+              if (!(status & I365_CS_BVD1))
-+                      val |= SS_BATDEAD;
-+              else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
-+                      val |= SS_BATWARN;
-+      }
-+      if ((status & I365_CS_DETECT) == I365_CS_DETECT)
-+              val |= SS_DETECT;
-+      if (status & I365_CS_WRPROT)
-+              val |= SS_WRPROT;
-+      if (status & I365_CS_READY)
-+              val |= SS_READY;
-+      if (status & I365_CS_POWERON)
-+              val |= SS_POWERON;
++              val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK |
++                      EEPROM_ADDR_READ);
++              tw32(GRC_EEPROM_ADDR, val |
++                      (0 << EEPROM_ADDR_DEVID_SHIFT) |
++                      (addr & EEPROM_ADDR_ADDR_MASK) |
++                      EEPROM_ADDR_START |
++                      EEPROM_ADDR_WRITE);
++              
++              for (j = 0; j < 10000; j++) {
++                      val = tr32(GRC_EEPROM_ADDR);
 +
-+      sense = exca_read_byte(slot, CARD_VOLTAGE_SENSE);
-+      switch (sense) {
-+      case VCC_3VORXV_CAPABLE:
-+              val |= SS_3VCARD | SS_XVCARD;
-+              break;
-+      case VCC_XV_ONLY:
-+              val |= SS_XVCARD;
-+              break;
-+      case VCC_3V_CAPABLE:
-+              val |= SS_3VCARD;
-+              break;
-+      default:
-+              /* 5V only */
-+              break;
++                      if (val & EEPROM_ADDR_COMPLETE)
++                              break;
++                      udelay(100);
++              }
++              if (!(val & EEPROM_ADDR_COMPLETE)) {
++                      rc = -EBUSY;
++                      break;
++              }
 +      }
 +
-+      *value = val;
-+
-+      return 0;
++      return rc;
 +}
 +
-+static inline u_char get_Vcc_value(uint8_t voltage)
++/* offset and length are dword aligned */
++static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
++              u8 *buf)
 +{
-+      switch (voltage) {
-+      case VCC_STATUS_3V:
-+              return 33;
-+      case VCC_STATUS_5V:
-+              return 50;
-+      default:
-+              break;
-+      }
++      int ret = 0;
++      u32 pagesize = tp->nvram_pagesize;
++      u32 pagemask = pagesize - 1;
++      u32 nvram_cmd;
++      u8 *tmp;
 +
-+      return 0;
-+}
++      tmp = kmalloc(pagesize, GFP_KERNEL);
++      if (tmp == NULL)
++              return -ENOMEM;
 +
-+static inline u_char get_Vpp_value(uint8_t power, u_char Vcc)
-+{
-+      if ((power & 0x03) == 0x01 || (power & 0x03) == 0x02)
-+              return Vcc;
++      while (len) {
++              int j;
++              u32 phy_addr, page_off, size, nvaccess;
 +
-+      return 0;
-+}
++              phy_addr = offset & ~pagemask;
++      
++              for (j = 0; j < pagesize; j += 4) {
++                      if ((ret = tg3_nvram_read(tp, phy_addr + j,
++                                              (u32 *) (tmp + j))))
++                              break;
++              }
++              if (ret)
++                      break;
 +
-+static int pccard_get_socket(unsigned int slot, socket_state_t *state)
-+{
-+      vrc4171_socket_t *socket;
-+      uint8_t power, voltage, control, cscint;
++              page_off = offset & pagemask;
++              size = pagesize;
++              if (len < size)
++                      size = len;
 +
-+      if (slot >= CARD_MAX_SLOTS || state == NULL)
-+              return -EINVAL;
++              len -= size;
 +
-+      socket = &vrc4171_sockets[slot];
++              memcpy(tmp + page_off, buf, size);
 +
-+      power = exca_read_byte(slot, I365_POWER);
-+      voltage = exca_read_byte(slot, CARD_VOLTAGE_SELECT);
++              offset = offset + (pagesize - page_off);
 +
-+      state->Vcc = get_Vcc_value(voltage);
-+      state->Vpp = get_Vpp_value(power, state->Vcc);
++              nvaccess = tr32(NVRAM_ACCESS);
++              tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
 +
-+      state->flags = 0;
-+      if (power & POWER_ENABLE)
-+              state->flags |= SS_PWR_AUTO;
-+      if (power & I365_PWR_OUT)
-+              state->flags |= SS_OUTPUT_ENA;
++              /*
++               * Before we can erase the flash page, we need
++               * to issue a special "write enable" command.
++               */
++              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
 +
-+      control = exca_read_byte(slot, I365_INTCTL);
-+      if (control & I365_PC_IOCARD)
-+              state->flags |= SS_IOCARD;
-+      if (!(control & I365_PC_RESET))
-+              state->flags |= SS_RESET;
++              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
++                      break;
 +
-+        cscint = exca_read_byte(slot, I365_CSCINT);
-+      state->csc_mask = 0;
-+      if (state->flags & SS_IOCARD) {
-+              if (cscint & I365_CSC_STSCHG)
-+                      state->flags |= SS_STSCHG;
-+      } else {
-+              if (cscint & I365_CSC_BVD1)  
-+                      state->csc_mask |= SS_BATDEAD;
-+              if (cscint & I365_CSC_BVD2)  
-+                      state->csc_mask |= SS_BATWARN;
-+      }
-+      if (cscint & I365_CSC_READY)
-+              state->csc_mask |= SS_READY;
-+      if (cscint & I365_CSC_DETECT)
-+              state->csc_mask |= SS_DETECT;
++              /* Erase the target page */
++              tw32(NVRAM_ADDR, phy_addr);
 +
-+      return 0;
-+}
++              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
++                      NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
 +
-+static inline uint8_t set_Vcc_value(u_char Vcc)
-+{
-+      switch (Vcc) {
-+      case 33:
-+              return VCC_3V;
-+      case 50:
-+              return VCC_5V;
++              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
++                      break;
++
++              /* Issue another write enable to start the write. */
++              nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
++
++              if (tg3_nvram_exec_cmd(tp, nvram_cmd))
++                      break;
++
++              for (j = 0; j < pagesize; j += 4) {
++                      u32 data;
++
++                      data = *((u32 *) (tmp + j));
++                      tw32(NVRAM_WRDATA, cpu_to_be32(data));
++
++                      tw32(NVRAM_ADDR, phy_addr + j);
++
++                      nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE |
++                              NVRAM_CMD_WR;
++
++                      if (j == 0)
++                              nvram_cmd |= NVRAM_CMD_FIRST;
++                      else if (j == (pagesize - 4))
++                              nvram_cmd |= NVRAM_CMD_LAST;
++
++                      if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
++                              break;
++              }
++              if (ret)
++                      break;
 +      }
 +
-+      /* Small voltage is chosen for safety. */
-+      return VCC_3V;
++      nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE;
++      tg3_nvram_exec_cmd(tp, nvram_cmd);
++
++      kfree(tmp);
++
++      return ret;
 +}
 +
-+static int pccard_set_socket(unsigned int slot, socket_state_t *state)
++/* offset and length are dword aligned */
++static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
++              u8 *buf)
 +{
-+      vrc4171_socket_t *socket;
-+      uint8_t voltage, power, control, cscint;
++      int i, ret = 0;
 +
-+      if (slot >= CARD_MAX_SLOTS ||
-+          (state->Vpp != state->Vcc && state->Vpp != 0) ||
-+          (state->Vcc != 50 && state->Vcc != 33 && state->Vcc != 0))
-+              return -EINVAL;
++      for (i = 0; i < len; i += 4, offset += 4) {
++              u32 data, page_off, phy_addr, nvram_cmd;
 +
-+      socket = &vrc4171_sockets[slot];
++              memcpy(&data, buf + i, 4);
++              tw32(NVRAM_WRDATA, cpu_to_be32(data));
 +
-+      spin_lock_irq(&socket->event_lock);
++              page_off = offset % tp->nvram_pagesize;
 +
-+      voltage = set_Vcc_value(state->Vcc);
-+      exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage);
++              if ((tp->tg3_flags2 & TG3_FLG2_FLASH) &&
++                      (tp->nvram_jedecnum == JEDEC_ATMEL)) {
 +
-+      power = POWER_ENABLE;
-+      if (state->Vpp == state->Vcc)
-+              power |= VPP_GET_VCC;
-+      if (state->flags & SS_OUTPUT_ENA)
-+              power |= I365_PWR_OUT;
-+      exca_write_byte(slot, I365_POWER, power);
++                      phy_addr = ((offset / tp->nvram_pagesize) <<
++                                  ATMEL_AT45DB0X1B_PAGE_POS) + page_off;
++              }
++              else {
++                      phy_addr = offset;
++              }
 +
-+      control = 0;
-+      if (state->io_irq != 0)
-+              control |= socket->io_irq;
-+      if (state->flags & SS_IOCARD)
-+              control |= I365_PC_IOCARD;
-+      if (state->flags & SS_RESET)
-+              control &= ~I365_PC_RESET;
-+      else
-+              control |= I365_PC_RESET;
-+      exca_write_byte(slot, I365_INTCTL, control);
-+
-+        cscint = 0;
-+        exca_write_byte(slot, I365_CSCINT, cscint);
-+      exca_read_byte(slot, I365_CSC); /* clear CardStatus change */
-+      if (state->csc_mask != 0)
-+              cscint |= socket->csc_irq << 8;
-+      if (state->flags & SS_IOCARD) {
-+              if (state->csc_mask & SS_STSCHG)
-+                      cscint |= I365_CSC_STSCHG;
-+      } else {
-+              if (state->csc_mask & SS_BATDEAD)
-+                      cscint |= I365_CSC_BVD1;
-+              if (state->csc_mask & SS_BATWARN)
-+                      cscint |= I365_CSC_BVD2;
-+      }
-+      if (state->csc_mask & SS_READY)
-+              cscint |= I365_CSC_READY;
-+      if (state->csc_mask & SS_DETECT)
-+              cscint |= I365_CSC_DETECT;
-+        exca_write_byte(slot, I365_CSCINT, cscint);
-+
-+      spin_unlock_irq(&socket->event_lock);
-+
-+      return 0;
-+}
-+
-+static int pccard_get_io_map(unsigned int slot, struct pccard_io_map *io)
-+{
-+      vrc4171_socket_t *socket;
-+      uint8_t ioctl, addrwin;
-+      u_char map;
++              tw32(NVRAM_ADDR, phy_addr);
 +
-+      if (slot >= CARD_MAX_SLOTS || io == NULL ||
-+          io->map >= IO_MAX_MAPS)
-+              return -EINVAL;
++              nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
 +
-+      socket = &vrc4171_sockets[slot];
-+      map = io->map;
++              if ((page_off == 0) || (i == 0))
++                      nvram_cmd |= NVRAM_CMD_FIRST;
++              else if (page_off == (tp->nvram_pagesize - 4))
++                      nvram_cmd |= NVRAM_CMD_LAST;
 +
-+      io->start = exca_read_word(slot, I365_IO(map)+I365_W_START);
-+      io->stop = exca_read_word(slot, I365_IO(map)+I365_W_STOP);
++              if (i == (len - 4))
++                      nvram_cmd |= NVRAM_CMD_LAST;
 +
-+      ioctl = exca_read_byte(slot, I365_IOCTL);
-+      if (io->flags & I365_IOCTL_WAIT(map))
-+              io->speed = 1;
-+      else
-+              io->speed = 0;
++              if ((tp->nvram_jedecnum == JEDEC_ST) &&
++                      (nvram_cmd & NVRAM_CMD_FIRST)) {
 +
-+      io->flags = 0;
-+      if (ioctl & I365_IOCTL_16BIT(map))
-+              io->flags |= MAP_16BIT;
-+      if (ioctl & I365_IOCTL_IOCS16(map))
-+              io->flags |= MAP_AUTOSZ;
-+      if (ioctl & I365_IOCTL_0WS(map))
-+              io->flags |= MAP_0WS;
++                      if ((ret = tg3_nvram_exec_cmd(tp,
++                              NVRAM_CMD_WREN | NVRAM_CMD_GO |
++                              NVRAM_CMD_DONE)))
 +
-+      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+      if (addrwin & I365_ENA_IO(map))
-+              io->flags |= MAP_ACTIVE;
++                              break;
++              }
++              if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
++                      /* We always do complete word writes to eeprom. */
++                      nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
++              }
 +
-+      return 0;
++              if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
++                      break;
++      }
++      return ret;
 +}
 +
-+static int pccard_set_io_map(unsigned int slot, struct pccard_io_map *io)
++/* offset and length are dword aligned */
++static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
 +{
-+      vrc4171_socket_t *socket;
-+      uint8_t ioctl, addrwin;
-+      u_char map;
++      int ret;
 +
-+      if (slot >= CARD_MAX_SLOTS ||
-+          io == NULL || io->map >= IO_MAX_MAPS ||
-+          io->start > 0xffff || io->stop > 0xffff || io->start > io->stop)
++      if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
++              printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n");
 +              return -EINVAL;
-+
-+      socket = &vrc4171_sockets[slot];
-+      map = io->map;
-+
-+      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+      if (addrwin & I365_ENA_IO(map)) {
-+              addrwin &= ~I365_ENA_IO(map);
-+              exca_write_byte(slot, I365_ADDRWIN, addrwin);
 +      }
 +
-+      exca_write_word(slot, I365_IO(map)+I365_W_START, io->start);
-+      exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop);
-+
-+      ioctl = 0;
-+      if (io->speed > 0)
-+              ioctl |= I365_IOCTL_WAIT(map);
-+      if (io->flags & MAP_16BIT)
-+              ioctl |= I365_IOCTL_16BIT(map);
-+      if (io->flags & MAP_AUTOSZ)
-+              ioctl |= I365_IOCTL_IOCS16(map);
-+      if (io->flags & MAP_0WS)
-+              ioctl |= I365_IOCTL_0WS(map);
-+      exca_write_byte(slot, I365_IOCTL, ioctl);
-+
-+      if (io->flags & MAP_ACTIVE) {
-+              addrwin |= I365_ENA_IO(map);
-+              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
++              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
++                     GRC_LCLCTRL_GPIO_OE1);
++              udelay(40);
 +      }
 +
-+      return 0;
-+}
-+
-+static int pccard_get_mem_map(unsigned int slot, struct pccard_mem_map *mem)
-+{
-+      vrc4171_socket_t *socket;
-+      uint8_t addrwin;
-+      u_long start, stop;
-+      u_int offset;
-+      u_char map;
-+
-+      if (slot >= CARD_MAX_SLOTS || mem == NULL || mem->map >= MEM_MAX_MAPS)
-+              return -EINVAL;
-+
-+      socket = &vrc4171_sockets[slot];
-+      map = mem->map;
-+
-+      mem->flags = 0;
-+      mem->speed = 0;
++      if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) {
++              ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
++      }
++      else {
++              u32 grc_mode;
 +
-+      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+      if (addrwin & I365_ENA_MEM(map))
-+              mem->flags |= MAP_ACTIVE;
++              tg3_nvram_lock(tp);
 +
-+      start = exca_read_word(slot, I365_MEM(map)+I365_W_START);
-+      if (start & I365_MEM_16BIT)
-+              mem->flags |= MAP_16BIT;
-+      mem->sys_start = (start & 0x3fffUL) << 12;
++              if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
++                      u32 nvaccess = tr32(NVRAM_ACCESS);
 +
-+      stop = exca_read_word(slot, I365_MEM(map)+I365_W_STOP);
-+      if (start & I365_MEM_WS0)
-+              mem->speed += 1;
-+      if (start & I365_MEM_WS1)
-+              mem->speed += 2;
-+      mem->sys_stop = ((stop & 0x3fffUL) << 12) + 0xfffUL;
++                      tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
 +
-+      offset = exca_read_word(slot, I365_MEM(map)+I365_W_OFF);
-+      if (offset & I365_MEM_REG)
-+              mem->flags |= MAP_ATTRIB;
-+      if (offset & I365_MEM_WRPROT)
-+              mem->flags |= MAP_WRPROT;
-+      mem->card_start = (offset & 0x3fffUL) << 12;
++                      tw32(NVRAM_WRITE1, 0x406);
++              }
 +
-+      mem->sys_start += CARD_MEM_START;
-+      mem->sys_stop += CARD_MEM_START;
++              grc_mode = tr32(GRC_MODE);
++              tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
 +
-+      return 0;
-+}
++              if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) ||
++                      !(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
 +
-+static int pccard_set_mem_map(unsigned int slot, struct pccard_mem_map *mem)
-+{
-+      vrc4171_socket_t *socket;
-+      uint16_t start, stop, offset;
-+      uint8_t addrwin;
-+      u_char map;
++                      ret = tg3_nvram_write_block_buffered(tp, offset, len,
++                              buf);
++              }
++              else {
++                      ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
++                              buf);
++              }
 +
-+      if (slot >= CARD_MAX_SLOTS ||
-+          mem == NULL || mem->map >= MEM_MAX_MAPS ||
-+          mem->sys_start < CARD_MEM_START || mem->sys_start > CARD_MEM_END ||
-+          mem->sys_stop < CARD_MEM_START || mem->sys_stop > CARD_MEM_END ||
-+          mem->sys_start > mem->sys_stop ||
-+          mem->card_start > CARD_MAX_MEM_OFFSET ||
-+          mem->speed > CARD_MAX_MEM_SPEED)
-+              return -EINVAL;
++              grc_mode = tr32(GRC_MODE);
++              tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
 +
-+      socket = &vrc4171_sockets[slot];
-+      map = mem->map;
++              if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
++                      u32 nvaccess = tr32(NVRAM_ACCESS);
 +
-+      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+      if (addrwin & I365_ENA_MEM(map)) {
-+              addrwin &= ~I365_ENA_MEM(map);
-+              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++                      tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
++              }
++              tg3_nvram_unlock(tp);
 +      }
 +
-+      start = (mem->sys_start >> 12) & 0x3fff;
-+      if (mem->flags & MAP_16BIT)
-+              start |= I365_MEM_16BIT;
-+      exca_write_word(slot, I365_MEM(map)+I365_W_START, start);
-+
-+      stop = (mem->sys_stop >> 12) & 0x3fff;
-+      switch (mem->speed) {
-+      case 0:
-+              break;
-+      case 1:
-+              stop |= I365_MEM_WS0;
-+              break;
-+      case 2:
-+              stop |= I365_MEM_WS1;
-+              break;
-+      default:
-+              stop |= I365_MEM_WS0 | I365_MEM_WS1;
-+              break;
++      if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
++              tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
++                     GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1);
++              udelay(40);
 +      }
-+      exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop);
-+
-+      offset = (mem->card_start >> 12) & 0x3fff;
-+      if (mem->flags & MAP_ATTRIB)
-+              offset |= I365_MEM_REG;
-+      if (mem->flags & MAP_WRPROT)
-+              offset |= I365_MEM_WRPROT;
-+      exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset);
 +
-+      if (mem->flags & MAP_ACTIVE) {
-+              addrwin |= I365_ENA_MEM(map);
-+              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      return ret;
+ }
+ struct subsys_tbl_ent {
+@@ -7047,11 +7497,19 @@
+       tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
+       if (val == NIC_SRAM_DATA_SIG_MAGIC) {
+               u32 nic_cfg, led_cfg;
+-              u32 nic_phy_id, cfg2;
++              u32 nic_phy_id, ver, cfg2 = 0;
+               tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
+               tp->nic_sram_data_cfg = nic_cfg;
++              tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
++              ver >>= NIC_SRAM_DATA_VER_SHIFT;
++              if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
++                  (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
++                  (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) &&
++                  (ver > 0) && (ver < 0x100))
++                      tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
++
+               eeprom_signature_found = 1;
+               if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
+@@ -7070,8 +7528,7 @@
+                       eeprom_phy_id = 0;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+-                      tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg);
+-                      led_cfg &= (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
++                      led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
+                                   SHASTA_EXT_LED_MODE_MASK);
+               } else
+                       led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK;
+@@ -7116,9 +7573,8 @@
+                   tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
+                       tp->led_ctrl = LED_CTRL_MODE_PHY_2;
+-              if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) ||
+-                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+-                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) &&
++              if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
++                  (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
+                   (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
+                       tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+@@ -7130,9 +7586,13 @@
+               if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
+                       tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
+-              tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &cfg2);
+               if (cfg2 & (1 << 17))
+                       tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
++
++              /* serdes signal pre-emphasis in register 0x590 set by */
++              /* bootcode if bit 18 is set */
++              if (cfg2 & (1 << 18))
++                      tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
+       }
+       /* Reading the PHY ID register can conflict with ASF
+@@ -7188,9 +7648,8 @@
+               u32 bmsr, adv_reg, tg3_ctrl;
+               tg3_readphy(tp, MII_BMSR, &bmsr);
+-              tg3_readphy(tp, MII_BMSR, &bmsr);
+-
+-              if (bmsr & BMSR_LSTATUS)
++              if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
++                  (bmsr & BMSR_LSTATUS))
+                       goto skip_phy_reset;
+                   
+               err = tg3_phy_reset(tp);
+@@ -7414,6 +7873,9 @@
+       tp->pci_hdr_type     = (cacheline_sz_reg >> 16) & 0xff;
+       tp->pci_bist         = (cacheline_sz_reg >> 24) & 0xff;
++      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
++              tp->tg3_flags2 |= TG3_FLG2_HW_TSO;
++
+       if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
+               tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+@@ -8302,11 +8764,13 @@
+       }
+ #if TG3_TSO_SUPPORT != 0
+-      if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
++      if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
++              tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
 +      }
++      else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+           tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 ||
+-          ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 &&
+-           GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)) {
++          (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
+               tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
+       } else {
+               tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+diff -Nur linux-2.4.29/drivers/net/tg3.h linux-mips/drivers/net/tg3.h
+--- linux-2.4.29/drivers/net/tg3.h     2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/net/tg3.h       2005-03-26 11:47:30.485648346 +0100
+@@ -1274,6 +1274,7 @@
+ #define  GRC_MODE_HOST_STACKUP                0x00010000
+ #define  GRC_MODE_HOST_SENDBDS                0x00020000
+ #define  GRC_MODE_NO_TX_PHDR_CSUM     0x00100000
++#define  GRC_MODE_NVRAM_WR_ENABLE     0x00200000
+ #define  GRC_MODE_NO_RX_PHDR_CSUM     0x00800000
+ #define  GRC_MODE_IRQ_ON_TX_CPU_ATTN  0x01000000
+ #define  GRC_MODE_IRQ_ON_RX_CPU_ATTN  0x02000000
+@@ -1366,6 +1367,8 @@
+ #define  NVRAM_CMD_ERASE               0x00000040
+ #define  NVRAM_CMD_FIRST               0x00000080
+ #define  NVRAM_CMD_LAST                        0x00000100
++#define  NVRAM_CMD_WREN                        0x00010000
++#define  NVRAM_CMD_WRDI                        0x00020000
+ #define NVRAM_STAT                    0x00007004
+ #define NVRAM_WRDATA                  0x00007008
+ #define NVRAM_ADDR                    0x0000700c
+@@ -1375,8 +1378,18 @@
+ #define  NVRAM_CFG1_FLASHIF_ENAB       0x00000001
+ #define  NVRAM_CFG1_BUFFERED_MODE      0x00000002
+ #define  NVRAM_CFG1_PASS_THRU          0x00000004
++#define  NVRAM_CFG1_STATUS_BITS                0x00000070
+ #define  NVRAM_CFG1_BIT_BANG           0x00000008
++#define  NVRAM_CFG1_FLASH_SIZE                 0x02000000
+ #define  NVRAM_CFG1_COMPAT_BYPASS      0x80000000
++#define  NVRAM_CFG1_VENDOR_MASK                0x03000003
++#define  FLASH_VENDOR_ATMEL_EEPROM     0x02000000
++#define  FLASH_VENDOR_ATMEL_FLASH_BUFFERED     0x02000003
++#define  FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED   0x00000003
++#define  FLASH_VENDOR_ST                       0x03000001
++#define  FLASH_VENDOR_SAIFUN           0x01000003
++#define  FLASH_VENDOR_SST_SMALL                0x00000001
++#define  FLASH_VENDOR_SST_LARGE                0x02000001
+ #define NVRAM_CFG2                    0x00007018
+ #define NVRAM_CFG3                    0x0000701c
+ #define NVRAM_SWARB                   0x00007020
+@@ -1396,15 +1409,16 @@
+ #define  SWARB_REQ1                    0x00002000
+ #define  SWARB_REQ2                    0x00004000
+ #define  SWARB_REQ3                    0x00008000
+-#define    NVRAM_BUFFERED_PAGE_SIZE      264
+-#define    NVRAM_BUFFERED_PAGE_POS       9
+ #define NVRAM_ACCESS                  0x00007024
+ #define  ACCESS_ENABLE                         0x00000001
+ #define  ACCESS_WR_ENABLE              0x00000002
+-/* 0x7024 --> 0x7400 unused */
++#define NVRAM_WRITE1                  0x00007028
++/* 0x702c --> 0x7400 unused */
+ /* 0x7400 --> 0x8000 unused */
++#define TG3_EEPROM_MAGIC              0x669955aa
++
+ /* 32K Window into NIC internal memory */
+ #define NIC_SRAM_WIN_BASE             0x00008000
+@@ -1438,6 +1452,9 @@
+ #define  NIC_SRAM_DATA_CFG_FIBER_WOL           0x00004000
+ #define  NIC_SRAM_DATA_CFG_NO_GPIO2            0x00100000
++#define NIC_SRAM_DATA_VER                     0x00000b5c
++#define  NIC_SRAM_DATA_VER_SHIFT               16
++
+ #define NIC_SRAM_DATA_PHY_ID          0x00000b74
+ #define  NIC_SRAM_DATA_PHY_ID1_MASK    0xffff0000
+ #define  NIC_SRAM_DATA_PHY_ID2_MASK    0x0000ffff
+@@ -2090,6 +2107,9 @@
+ #define TG3_FLG2_PHY_JUST_INITTED     0x00001000
+ #define TG3_FLG2_PHY_SERDES           0x00002000
+ #define TG3_FLG2_CAPACITIVE_COUPLING  0x00004000
++#define TG3_FLG2_FLASH                        0x00008000
++#define TG3_FLG2_HW_TSO                       0x00010000
++#define TG3_FLG2_SERDES_PREEMPHASIS   0x00020000
+       u32                             split_mode_max_reqs;
+ #define SPLIT_MODE_5704_MAX_REQ               3
+@@ -2164,6 +2184,34 @@
+       struct tg3_hw_stats             *hw_stats;
+       dma_addr_t                      stats_mapping;
+       struct tq_struct                reset_task;
++
++      u32                             nvram_size;
++      u32                             nvram_pagesize;
++      u32                             nvram_jedecnum;
++
++#define JEDEC_ATMEL                   0x1f
++#define JEDEC_ST                      0x20
++#define JEDEC_SAIFUN                  0x4f
++#define JEDEC_SST                     0xbf
++
++#define ATMEL_AT24C64_CHIP_SIZE               (64 * 1024)
++#define ATMEL_AT24C64_PAGE_SIZE               (32)
++
++#define ATMEL_AT24C512_CHIP_SIZE      (512 * 1024)
++#define ATMEL_AT24C512_PAGE_SIZE      (128)
++
++#define ATMEL_AT45DB0X1B_PAGE_POS     9
++#define ATMEL_AT45DB0X1B_PAGE_SIZE    264
++
++#define ATMEL_AT25F512_PAGE_SIZE      256
++
++#define ST_M45PEX0_PAGE_SIZE          256
++
++#define SAIFUN_SA25F0XX_PAGE_SIZE     256
++
++#define SST_25VF0X0_PAGE_SIZE         4098
 +
-+      return 0;
-+}
-+
-+static void pccard_proc_setup(unsigned int slot, struct proc_dir_entry *base)
-+{          
-+}
-+
-+static struct pccard_operations vrc4171_pccard_operations = {
-+      .init                   = pccard_init,
-+      .suspend                = pccard_suspend,
-+      .register_callback      = pccard_register_callback,
-+      .inquire_socket         = pccard_inquire_socket,
-+      .get_status             = pccard_get_status,
-+      .get_socket             = pccard_get_socket,
-+      .set_socket             = pccard_set_socket,
-+      .get_io_map             = pccard_get_io_map,
-+      .set_io_map             = pccard_set_io_map,
-+      .get_mem_map            = pccard_get_mem_map,
-+      .set_mem_map            = pccard_set_mem_map,
-+      .proc_setup             = pccard_proc_setup,
-+};
-+
-+static void pccard_bh(void *data)
-+{
-+      vrc4171_socket_t *socket = (vrc4171_socket_t *)data;
-+      uint16_t events;
-+
-+      spin_lock_irq(&socket->event_lock);
-+      events = socket->events;
-+      socket->events = 0;
-+      spin_unlock_irq(&socket->event_lock);
-+ 
-+      if (socket->handler)
-+              socket->handler(socket->info, events);
-+}
-+
-+static inline uint16_t get_events(int slot)
-+{
-+      uint16_t events = 0;
-+      uint8_t status, csc;
-+
-+      status = exca_read_byte(slot, I365_STATUS);
-+      csc = exca_read_byte(slot, I365_CSC);
 +
-+      if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
-+              if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG))
-+                      events |= SS_STSCHG;
-+      } else {
-+              if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) {
-+                      if (!(status & I365_CS_BVD1))
-+                              events |= SS_BATDEAD;
+ };
+ #endif /* !(_T3_H) */
+diff -Nur linux-2.4.29/drivers/net/tulip/21142.c linux-mips/drivers/net/tulip/21142.c
+--- linux-2.4.29/drivers/net/tulip/21142.c     2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/21142.c       2005-03-26 11:47:31.371502956 +0100
+@@ -14,8 +14,8 @@
+ */
+-#include "tulip.h"
+ #include <linux/pci.h>
++#include "tulip.h"
+ #include <linux/delay.h>
+diff -Nur linux-2.4.29/drivers/net/tulip/eeprom.c linux-mips/drivers/net/tulip/eeprom.c
+--- linux-2.4.29/drivers/net/tulip/eeprom.c    2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/eeprom.c      2005-03-26 11:47:31.372502792 +0100
+@@ -14,6 +14,7 @@
+ */
++#include <linux/pci.h>
+ #include "tulip.h"
+ #include <linux/init.h>
+ #include <asm/unaligned.h>
+diff -Nur linux-2.4.29/drivers/net/tulip/interrupt.c linux-mips/drivers/net/tulip/interrupt.c
+--- linux-2.4.29/drivers/net/tulip/interrupt.c 2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/interrupt.c   2005-03-26 11:47:31.372502792 +0100
+@@ -14,10 +14,10 @@
+ */
++#include <linux/pci.h>
+ #include "tulip.h"
+ #include <linux/config.h>
+ #include <linux/etherdevice.h>
+-#include <linux/pci.h>
+ int tulip_rx_copybreak;
+diff -Nur linux-2.4.29/drivers/net/tulip/media.c linux-mips/drivers/net/tulip/media.c
+--- linux-2.4.29/drivers/net/tulip/media.c     2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/media.c       2005-03-26 11:47:31.373502628 +0100
+@@ -18,6 +18,7 @@
+ #include <linux/mii.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
++#include <linux/pci.h>
+ #include "tulip.h"
+diff -Nur linux-2.4.29/drivers/net/tulip/pnic2.c linux-mips/drivers/net/tulip/pnic2.c
+--- linux-2.4.29/drivers/net/tulip/pnic2.c     2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/pnic2.c       2005-03-26 11:47:31.374502464 +0100
+@@ -76,8 +76,8 @@
+-#include "tulip.h"
+ #include <linux/pci.h>
++#include "tulip.h"
+ #include <linux/delay.h>
+diff -Nur linux-2.4.29/drivers/net/tulip/pnic.c linux-mips/drivers/net/tulip/pnic.c
+--- linux-2.4.29/drivers/net/tulip/pnic.c      2003-06-13 16:51:35.000000000 +0200
++++ linux-mips/drivers/net/tulip/pnic.c        2005-03-26 11:47:31.374502464 +0100
+@@ -15,6 +15,7 @@
+ */
+ #include <linux/kernel.h>
++#include <linux/pci.h>
+ #include "tulip.h"
+diff -Nur linux-2.4.29/drivers/net/tulip/timer.c linux-mips/drivers/net/tulip/timer.c
+--- linux-2.4.29/drivers/net/tulip/timer.c     2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/drivers/net/tulip/timer.c       2005-03-26 11:47:31.375502300 +0100
+@@ -14,6 +14,7 @@
+ */
++#include <linux/pci.h>
+ #include "tulip.h"
+diff -Nur linux-2.4.29/drivers/net/tulip/tulip_core.c linux-mips/drivers/net/tulip/tulip_core.c
+--- linux-2.4.29/drivers/net/tulip/tulip_core.c        2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/drivers/net/tulip/tulip_core.c  2005-03-26 11:47:31.377501972 +0100
+@@ -20,8 +20,8 @@
+ #include <linux/config.h>
+ #include <linux/module.h>
+-#include "tulip.h"
+ #include <linux/pci.h>
++#include "tulip.h"
+ #include <linux/init.h>
+ #include <linux/etherdevice.h>
+ #include <linux/delay.h>
+diff -Nur linux-2.4.29/drivers/net/tulip/tulip.h linux-mips/drivers/net/tulip/tulip.h
+--- linux-2.4.29/drivers/net/tulip/tulip.h     2002-11-29 00:53:14.000000000 +0100
++++ linux-mips/drivers/net/tulip/tulip.h       2005-03-26 11:47:31.375502300 +0100
+@@ -146,6 +146,9 @@
+       TxIntr = 0x01,
+ };
++/* bit mask for CSR5 TX/RX process state */
++#define CSR5_TS       0x00700000
++#define CSR5_RS       0x000e0000
+ enum tulip_mode_bits {
+       TxThreshold             = (1 << 22),
+@@ -484,9 +487,19 @@
+       u32 csr6 = inl(ioaddr + CSR6);
+       if (csr6 & RxTx) {
++              unsigned i=1300/10;
+               outl(csr6 & ~RxTx, ioaddr + CSR6);
+               barrier();
+-              (void) inl(ioaddr + CSR6); /* mmio sync */
++              /* wait until in-flight frame completes.
++               * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin)
++               * Typically expect this loop to end in < 50us on 100BT.
++               */
++              while (--i && (inl(ioaddr + CSR5) & (CSR5_TS|CSR5_RS))) 
++                      udelay(10);
++
++              if (!i)
++                      printk (KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
++                                      tp->pdev->slot_name);
+       }
+ }
+diff -Nur linux-2.4.29/drivers/pci/pci.c linux-mips/drivers/pci/pci.c
+--- linux-2.4.29/drivers/pci/pci.c     2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/pci/pci.c       2004-11-19 01:28:41.000000000 +0100
+@@ -1281,11 +1281,17 @@
+ {
+       unsigned int buses;
+       unsigned short cr;
++      unsigned short bctl;
+       struct pci_bus *child;
+       int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+       pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+       DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
++      /* Disable MasterAbortMode during probing to avoid reporting
++           of bus errors (in some architectures) */
++      pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
++      pci_write_config_word(dev, PCI_BRIDGE_CONTROL, 
++                            bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
+       if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
+               /*
+                * Bus already configured by firmware, process it in the first
+@@ -1351,6 +1357,7 @@
+               pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+               pci_write_config_word(dev, PCI_COMMAND, cr);
+       }
++      pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
+       sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+       return max;
+ }
+diff -Nur linux-2.4.29/drivers/pci/quirks.c linux-mips/drivers/pci/quirks.c
+--- linux-2.4.29/drivers/pci/quirks.c  2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/pci/quirks.c    2005-03-26 11:47:31.393499346 +0100
+@@ -368,9 +368,6 @@
+  * non-x86 architectures (yes Via exists on PPC among other places),
+  * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
+  * interrupts delivered properly.
+- *
+- * TODO: When we have device-specific interrupt routers,
+- * quirk_via_irqpic will go away from quirks.
+  */
+ /*
+@@ -393,22 +390,6 @@
+               d->irq = irq;
+ }
+-static void __init quirk_via_irqpic(struct pci_dev *dev)
+-{
+-      u8 irq, new_irq = dev->irq & 0xf;
+-
+-      pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
+-
+-      if (new_irq != irq) {
+-              printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n",
+-                     dev->slot_name, irq, new_irq);
+-
+-              udelay(15);
+-              pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
+-      }
+-}
+-
+-
+ /*
+  * PIIX3 USB: We have to disable USB interrupts that are
+  * hardwired to PIRQD# and may be shared with an
+@@ -639,12 +620,14 @@
+  *    VIA northbridges care about PCI_INTERRUPT_LINE
+  */
+  
+-int interrupt_line_quirk;
++int via_interrupt_line_quirk;
+ static void __init quirk_via_bridge(struct pci_dev *pdev)
+ {
+-      if(pdev->devfn == 0)
+-              interrupt_line_quirk = 1;
++      if(pdev->devfn == 0) {
++              printk(KERN_INFO "PCI: Via IRQ fixup\n");
++              via_interrupt_line_quirk = 1;
++      }
+ }
+       
+ /* 
+@@ -773,9 +756,6 @@
+ #endif
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_3,     quirk_via_acpi },
+       { PCI_FIXUP_HEADER,     PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C686_4,     quirk_via_acpi },
+-      { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C586_2,     quirk_via_irqpic },
+-      { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C686_5,     quirk_via_irqpic },
+-      { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_VIA,      PCI_DEVICE_ID_VIA_82C686_6,     quirk_via_irqpic },
+       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_AMD,      PCI_DEVICE_ID_AMD_VIPER_7410,   quirk_amd_ioapic },
+       { PCI_FIXUP_FINAL,      PCI_VENDOR_ID_AMD,      PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
+diff -Nur linux-2.4.29/drivers/pcmcia/au1000_db1x00.c linux-mips/drivers/pcmcia/au1000_db1x00.c
+--- linux-2.4.29/drivers/pcmcia/au1000_db1x00.c        2005-01-19 15:09:57.000000000 +0100
++++ linux-mips/drivers/pcmcia/au1000_db1x00.c  2005-03-26 11:47:31.434492618 +0100
+@@ -1,6 +1,6 @@
+ /*
+  *
+- * Alchemy Semi Db1x00 boards specific pcmcia routines.
++ * AMD Alchemy DUAL-SLOT Db1x00 boards' specific pcmcia routines.
+  *
+  * Copyright 2002 MontaVista Software Inc.
+  * Author: MontaVista Software, Inc.
+@@ -54,9 +54,20 @@
+ #include <asm/au1000.h>
+ #include <asm/au1000_pcmcia.h>
++#if defined(CONFIG_MIPS_PB1200)
++#include <asm/pb1200.h>
++#elif defined(CONFIG_MIPS_DB1200)
++#include <asm/db1200.h>
++#else
+ #include <asm/db1x00.h>
++#endif
+-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++#define PCMCIA_MAX_SOCK 1
++#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
++
++/* VPP/VCC */
++#define SET_VCC_VPP(VCC, VPP, SLOT)\
++    ((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
+ static int db1x00_pcmcia_init(struct pcmcia_init *init)
+ {
+@@ -76,7 +87,7 @@
+ db1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
+ {
+       u32 inserted;
+-      unsigned char vs;
++      u16 vs;
+       if(sock > PCMCIA_MAX_SOCK) return -1;
+@@ -87,11 +98,11 @@
+       if (sock == 0) {
+               vs = bcsr->status & 0x3;
+-              inserted = !(bcsr->status & (1<<4));
++              inserted = BOARD_CARD_INSERTED(0);
+       }
+       else {
+               vs = (bcsr->status & 0xC)>>2;
+-              inserted = !(bcsr->status & (1<<5));
++              inserted = BOARD_CARD_INSERTED(1);
+       }
+       DEBUG(KERN_DEBUG "db1x00 socket %d: inserted %d, vs %d\n", 
+@@ -144,16 +155,9 @@
+       if(info->sock > PCMCIA_MAX_SOCK) return -1;
+       if(info->sock == 0)
+-#ifdef CONFIG_MIPS_DB1550
+-              info->irq = AU1000_GPIO_3;
++              info->irq = BOARD_PC0_INT;
+       else 
+-              info->irq = AU1000_GPIO_5;
+-#else
+-              info->irq = AU1000_GPIO_2;
+-      else 
+-              info->irq = AU1000_GPIO_5;
+-#endif
+-
++              info->irq = BOARD_PC1_INT;
+       return 0;
+ }
+diff -Nur linux-2.4.29/drivers/pcmcia/cistpl.c linux-mips/drivers/pcmcia/cistpl.c
+--- linux-2.4.29/drivers/pcmcia/cistpl.c       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/pcmcia/cistpl.c 2005-03-26 11:47:31.435492454 +0100
+@@ -140,7 +140,6 @@
+     } else {
+       u_int inc = 1;
+       if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+-      sys += (addr & (s->cap.map_size-1));
+       mem->card_start = addr & ~(s->cap.map_size-1);
+       while (len) {
+           set_cis_map(s, mem);
+diff -Nur linux-2.4.29/drivers/pcmcia/Config.in linux-mips/drivers/pcmcia/Config.in
+--- linux-2.4.29/drivers/pcmcia/Config.in      2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/pcmcia/Config.in        2004-02-22 06:21:34.000000000 +0100
+@@ -30,16 +30,14 @@
+       dep_tristate '  M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
+    fi
+    if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+-      dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA 
+-      if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
+-        bool '  Pb1x00 board support' CONFIG_PCMCIA_PB1X00
+-        bool '  Db1x00 board support' CONFIG_PCMCIA_DB1X00
+-        bool '  XXS1500 board support' CONFIG_PCMCIA_XXS1500
+-      fi
++      dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA
+    fi
+    if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+       dep_bool '  SiByte PCMCIA support' CONFIG_PCMCIA_SIBYTE $CONFIG_PCMCIA $CONFIG_BLK_DEV_IDE_SIBYTE
+    fi
++   if [ "$CONFIG_VRC4171" = "y" -o "$CONFIG_VRC4171" = "m" ]; then
++      dep_tristate '  NEC VRC4171 Card Controllers support' CONFIG_PCMCIA_VRC4171 $CONFIG_PCMCIA
++   fi
+    if [ "$CONFIG_VRC4173" = "y" -o "$CONFIG_VRC4173" = "m" ]; then
+       dep_tristate '  NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA
+    fi
+diff -Nur linux-2.4.29/drivers/pcmcia/Makefile linux-mips/drivers/pcmcia/Makefile
+--- linux-2.4.29/drivers/pcmcia/Makefile       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/pcmcia/Makefile 2005-03-26 11:47:31.433492782 +0100
+@@ -61,9 +61,18 @@
+ obj-$(CONFIG_PCMCIA_AU1X00)                   += au1x00_ss.o
+ au1000_ss-objs-y                              := au1000_generic.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_PB1X00)                += au1000_pb1x00.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00)                += au1000_db1x00.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500)       += au1000_xxs1500.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1000)          += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1100)          += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1500)          += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1550)          += au1000_pb1550.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1200)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1000)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1100)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1500)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1550)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1200)          += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_HYDROGEN3)               += au1000_hydrogen3.o
++au1000_ss-objs-$(CONFIG_MIPS_XXS1500)                 += au1000_xxs1500.o
+ obj-$(CONFIG_PCMCIA_SA1100)   += sa1100_cs.o
+ obj-$(CONFIG_PCMCIA_M8XX)     += m8xx_pcmcia.o
+@@ -89,6 +98,7 @@
+ sa1100_cs-objs-$(CONFIG_SA1100_XP860)         += sa1100_xp860.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_YOPY)          += sa1100_yopy.o
++obj-$(CONFIG_PCMCIA_VRC4171)  += vrc4171_card.o
+ obj-$(CONFIG_PCMCIA_VRC4173)  += vrc4173_cardu.o
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.29/drivers/pcmcia/vrc4171_card.c linux-mips/drivers/pcmcia/vrc4171_card.c
+--- linux-2.4.29/drivers/pcmcia/vrc4171_card.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/drivers/pcmcia/vrc4171_card.c   2004-01-19 16:54:58.000000000 +0100
+@@ -0,0 +1,886 @@
++/*
++ * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
++ *
++ * Copyright (C) 2003  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++
++#include <asm/io.h>
++#include <asm/vr41xx/vrc4171.h>
++
++#include <pcmcia/ss.h>
++
++#include "i82365.h"
++
++MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
++MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
++MODULE_LICENSE("GPL");
++
++#define CARD_MAX_SLOTS                2
++#define CARD_SLOTA            0
++#define CARD_SLOTB            1
++#define CARD_SLOTB_OFFSET     0x40
++
++#define CARD_MEM_START                0x10000000
++#define CARD_MEM_END          0x13ffffff
++#define CARD_MAX_MEM_OFFSET   0x3ffffff
++#define CARD_MAX_MEM_SPEED    1000
++
++#define CARD_CONTROLLER_INDEX 0x03e0
++#define CARD_CONTROLLER_DATA  0x03e1
++#define CARD_CONTROLLER_SIZE  2
++ /* Power register */
++  #define VPP_GET_VCC         0x01
++  #define POWER_ENABLE                0x10
++ #define CARD_VOLTAGE_SENSE   0x1f
++  #define VCC_3VORXV_CAPABLE  0x00
++  #define VCC_XV_ONLY         0x01
++  #define VCC_3V_CAPABLE      0x02
++  #define VCC_5V_ONLY         0x03
++ #define CARD_VOLTAGE_SELECT  0x2f
++  #define VCC_3V              0x01
++  #define VCC_5V              0x00
++  #define VCC_XV              0x02
++  #define VCC_STATUS_3V               0x02
++  #define VCC_STATUS_5V               0x01
++  #define VCC_STATUS_XV               0x03
++ #define GLOBAL_CONTROL               0x1e
++  #define EXWRBK              0x04
++  #define IRQPM_EN            0x08
++  #define CLRPMIRQ            0x10
++
++#define IO_MAX_MAPS   2
++#define MEM_MAX_MAPS  5
++
++enum {
++      SLOTB_PROBE = 0,
++      SLOTB_NOPROBE_IO,
++      SLOTB_NOPROBE_MEM,
++      SLOTB_NOPROBE_ALL
++};
++
++typedef struct vrc4171_socket {
++      int noprobe;
++      void (*handler)(void *, unsigned int);
++      void *info;
++      socket_cap_t cap;
++      spinlock_t event_lock;
++      uint16_t events;
++      struct socket_info_t *pcmcia_socket;
++      struct tq_struct tq_task;
++      char name[24];
++      int csc_irq;
++      int io_irq;
++} vrc4171_socket_t;
++
++static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS];
++static int vrc4171_slotb = SLOTB_IS_NONE;
++static unsigned int vrc4171_irq;
++static uint16_t vrc4171_irq_mask = 0xdeb8;
++
++extern struct socket_info_t *pcmcia_register_socket(int slot,
++                                                    struct pccard_operations *vtable,
++                                                    int use_bus_pm);
++extern void pcmcia_unregister_socket(struct socket_info_t *s);
++
++static inline uint8_t exca_read_byte(int slot, uint8_t index)
++{
++      if (slot == CARD_SLOTB)
++              index += CARD_SLOTB_OFFSET;
++
++      outb(index, CARD_CONTROLLER_INDEX);
++      return inb(CARD_CONTROLLER_DATA);
++}
++
++static inline uint16_t exca_read_word(int slot, uint8_t index)
++{
++      uint16_t data;
++
++      if (slot == CARD_SLOTB)
++              index += CARD_SLOTB_OFFSET;
++
++      outb(index++, CARD_CONTROLLER_INDEX);
++      data = inb(CARD_CONTROLLER_DATA);
++
++      outb(index, CARD_CONTROLLER_INDEX);
++      data |= ((uint16_t)inb(CARD_CONTROLLER_DATA)) << 8;
++
++      return data;
++}
++
++static inline uint8_t exca_write_byte(int slot, uint8_t index, uint8_t data)
++{
++      if (slot == CARD_SLOTB)
++              index += CARD_SLOTB_OFFSET;
++
++      outb(index, CARD_CONTROLLER_INDEX);
++      outb(data, CARD_CONTROLLER_DATA);
++
++      return data;
++}
++
++static inline uint16_t exca_write_word(int slot, uint8_t index, uint16_t data)
++{
++      if (slot == CARD_SLOTB)
++              index += CARD_SLOTB_OFFSET;
++
++      outb(index++, CARD_CONTROLLER_INDEX);
++      outb(data, CARD_CONTROLLER_DATA);
++
++      outb(index, CARD_CONTROLLER_INDEX);
++      outb((uint8_t)(data >> 8), CARD_CONTROLLER_DATA);
++
++      return data;
++}
++
++static inline int search_nonuse_irq(void)
++{
++      int i;
++
++      for (i = 0; i < 16; i++) {
++              if (vrc4171_irq_mask & (1 << i)) {
++                      vrc4171_irq_mask &= ~(1 << i);
++                      return i;
++              }
++      }
++
++      return -1;
++}
++
++static int pccard_init(unsigned int slot)
++{
++      vrc4171_socket_t *socket = &vrc4171_sockets[slot];
++
++      socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
++      socket->cap.irq_mask = 0;
++      socket->cap.pci_irq = vrc4171_irq;
++      socket->cap.map_size = 0x1000;
++      socket->events = 0;
++      spin_lock_init(socket->event_lock);
++      socket->csc_irq = search_nonuse_irq();
++      socket->io_irq = search_nonuse_irq();
++
++      return 0;
++}
++
++static int pccard_suspend(unsigned int slot)
++{
++      return -EINVAL;
++}
++
++static int pccard_register_callback(unsigned int slot,
++                                    void (*handler)(void *, unsigned int),
++                                    void *info)
++{
++      vrc4171_socket_t *socket;
++
++      if (slot >= CARD_MAX_SLOTS)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++
++      socket->handler = handler;
++      socket->info = info;
++
++      if (handler)
++              MOD_INC_USE_COUNT;
++      else
++              MOD_DEC_USE_COUNT;
++
++      return 0;
++}
++
++static int pccard_inquire_socket(unsigned int slot, socket_cap_t *cap)
++{
++      vrc4171_socket_t *socket;
++
++      if (slot >= CARD_MAX_SLOTS || cap == NULL)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++
++      *cap = socket->cap;
++
++      return 0;
++}
++
++static int pccard_get_status(unsigned int slot, u_int *value)
++{
++      uint8_t status, sense;
++      u_int val = 0;
++
++      if (slot >= CARD_MAX_SLOTS || value == NULL)
++              return -EINVAL;
++
++      status = exca_read_byte(slot, I365_STATUS);
++      if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
++              if (status & I365_CS_STSCHG)
++                      val |= SS_STSCHG;
++      } else {
++              if (!(status & I365_CS_BVD1))
++                      val |= SS_BATDEAD;
++              else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
++                      val |= SS_BATWARN;
++      }
++      if ((status & I365_CS_DETECT) == I365_CS_DETECT)
++              val |= SS_DETECT;
++      if (status & I365_CS_WRPROT)
++              val |= SS_WRPROT;
++      if (status & I365_CS_READY)
++              val |= SS_READY;
++      if (status & I365_CS_POWERON)
++              val |= SS_POWERON;
++
++      sense = exca_read_byte(slot, CARD_VOLTAGE_SENSE);
++      switch (sense) {
++      case VCC_3VORXV_CAPABLE:
++              val |= SS_3VCARD | SS_XVCARD;
++              break;
++      case VCC_XV_ONLY:
++              val |= SS_XVCARD;
++              break;
++      case VCC_3V_CAPABLE:
++              val |= SS_3VCARD;
++              break;
++      default:
++              /* 5V only */
++              break;
++      }
++
++      *value = val;
++
++      return 0;
++}
++
++static inline u_char get_Vcc_value(uint8_t voltage)
++{
++      switch (voltage) {
++      case VCC_STATUS_3V:
++              return 33;
++      case VCC_STATUS_5V:
++              return 50;
++      default:
++              break;
++      }
++
++      return 0;
++}
++
++static inline u_char get_Vpp_value(uint8_t power, u_char Vcc)
++{
++      if ((power & 0x03) == 0x01 || (power & 0x03) == 0x02)
++              return Vcc;
++
++      return 0;
++}
++
++static int pccard_get_socket(unsigned int slot, socket_state_t *state)
++{
++      vrc4171_socket_t *socket;
++      uint8_t power, voltage, control, cscint;
++
++      if (slot >= CARD_MAX_SLOTS || state == NULL)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++
++      power = exca_read_byte(slot, I365_POWER);
++      voltage = exca_read_byte(slot, CARD_VOLTAGE_SELECT);
++
++      state->Vcc = get_Vcc_value(voltage);
++      state->Vpp = get_Vpp_value(power, state->Vcc);
++
++      state->flags = 0;
++      if (power & POWER_ENABLE)
++              state->flags |= SS_PWR_AUTO;
++      if (power & I365_PWR_OUT)
++              state->flags |= SS_OUTPUT_ENA;
++
++      control = exca_read_byte(slot, I365_INTCTL);
++      if (control & I365_PC_IOCARD)
++              state->flags |= SS_IOCARD;
++      if (!(control & I365_PC_RESET))
++              state->flags |= SS_RESET;
++
++        cscint = exca_read_byte(slot, I365_CSCINT);
++      state->csc_mask = 0;
++      if (state->flags & SS_IOCARD) {
++              if (cscint & I365_CSC_STSCHG)
++                      state->flags |= SS_STSCHG;
++      } else {
++              if (cscint & I365_CSC_BVD1)  
++                      state->csc_mask |= SS_BATDEAD;
++              if (cscint & I365_CSC_BVD2)  
++                      state->csc_mask |= SS_BATWARN;
++      }
++      if (cscint & I365_CSC_READY)
++              state->csc_mask |= SS_READY;
++      if (cscint & I365_CSC_DETECT)
++              state->csc_mask |= SS_DETECT;
++
++      return 0;
++}
++
++static inline uint8_t set_Vcc_value(u_char Vcc)
++{
++      switch (Vcc) {
++      case 33:
++              return VCC_3V;
++      case 50:
++              return VCC_5V;
++      }
++
++      /* Small voltage is chosen for safety. */
++      return VCC_3V;
++}
++
++static int pccard_set_socket(unsigned int slot, socket_state_t *state)
++{
++      vrc4171_socket_t *socket;
++      uint8_t voltage, power, control, cscint;
++
++      if (slot >= CARD_MAX_SLOTS ||
++          (state->Vpp != state->Vcc && state->Vpp != 0) ||
++          (state->Vcc != 50 && state->Vcc != 33 && state->Vcc != 0))
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++
++      spin_lock_irq(&socket->event_lock);
++
++      voltage = set_Vcc_value(state->Vcc);
++      exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage);
++
++      power = POWER_ENABLE;
++      if (state->Vpp == state->Vcc)
++              power |= VPP_GET_VCC;
++      if (state->flags & SS_OUTPUT_ENA)
++              power |= I365_PWR_OUT;
++      exca_write_byte(slot, I365_POWER, power);
++
++      control = 0;
++      if (state->io_irq != 0)
++              control |= socket->io_irq;
++      if (state->flags & SS_IOCARD)
++              control |= I365_PC_IOCARD;
++      if (state->flags & SS_RESET)
++              control &= ~I365_PC_RESET;
++      else
++              control |= I365_PC_RESET;
++      exca_write_byte(slot, I365_INTCTL, control);
++
++        cscint = 0;
++        exca_write_byte(slot, I365_CSCINT, cscint);
++      exca_read_byte(slot, I365_CSC); /* clear CardStatus change */
++      if (state->csc_mask != 0)
++              cscint |= socket->csc_irq << 8;
++      if (state->flags & SS_IOCARD) {
++              if (state->csc_mask & SS_STSCHG)
++                      cscint |= I365_CSC_STSCHG;
++      } else {
++              if (state->csc_mask & SS_BATDEAD)
++                      cscint |= I365_CSC_BVD1;
++              if (state->csc_mask & SS_BATWARN)
++                      cscint |= I365_CSC_BVD2;
++      }
++      if (state->csc_mask & SS_READY)
++              cscint |= I365_CSC_READY;
++      if (state->csc_mask & SS_DETECT)
++              cscint |= I365_CSC_DETECT;
++        exca_write_byte(slot, I365_CSCINT, cscint);
++
++      spin_unlock_irq(&socket->event_lock);
++
++      return 0;
++}
++
++static int pccard_get_io_map(unsigned int slot, struct pccard_io_map *io)
++{
++      vrc4171_socket_t *socket;
++      uint8_t ioctl, addrwin;
++      u_char map;
++
++      if (slot >= CARD_MAX_SLOTS || io == NULL ||
++          io->map >= IO_MAX_MAPS)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++      map = io->map;
++
++      io->start = exca_read_word(slot, I365_IO(map)+I365_W_START);
++      io->stop = exca_read_word(slot, I365_IO(map)+I365_W_STOP);
++
++      ioctl = exca_read_byte(slot, I365_IOCTL);
++      if (io->flags & I365_IOCTL_WAIT(map))
++              io->speed = 1;
++      else
++              io->speed = 0;
++
++      io->flags = 0;
++      if (ioctl & I365_IOCTL_16BIT(map))
++              io->flags |= MAP_16BIT;
++      if (ioctl & I365_IOCTL_IOCS16(map))
++              io->flags |= MAP_AUTOSZ;
++      if (ioctl & I365_IOCTL_0WS(map))
++              io->flags |= MAP_0WS;
++
++      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++      if (addrwin & I365_ENA_IO(map))
++              io->flags |= MAP_ACTIVE;
++
++      return 0;
++}
++
++static int pccard_set_io_map(unsigned int slot, struct pccard_io_map *io)
++{
++      vrc4171_socket_t *socket;
++      uint8_t ioctl, addrwin;
++      u_char map;
++
++      if (slot >= CARD_MAX_SLOTS ||
++          io == NULL || io->map >= IO_MAX_MAPS ||
++          io->start > 0xffff || io->stop > 0xffff || io->start > io->stop)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++      map = io->map;
++
++      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++      if (addrwin & I365_ENA_IO(map)) {
++              addrwin &= ~I365_ENA_IO(map);
++              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      }
++
++      exca_write_word(slot, I365_IO(map)+I365_W_START, io->start);
++      exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop);
++
++      ioctl = 0;
++      if (io->speed > 0)
++              ioctl |= I365_IOCTL_WAIT(map);
++      if (io->flags & MAP_16BIT)
++              ioctl |= I365_IOCTL_16BIT(map);
++      if (io->flags & MAP_AUTOSZ)
++              ioctl |= I365_IOCTL_IOCS16(map);
++      if (io->flags & MAP_0WS)
++              ioctl |= I365_IOCTL_0WS(map);
++      exca_write_byte(slot, I365_IOCTL, ioctl);
++
++      if (io->flags & MAP_ACTIVE) {
++              addrwin |= I365_ENA_IO(map);
++              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      }
++
++      return 0;
++}
++
++static int pccard_get_mem_map(unsigned int slot, struct pccard_mem_map *mem)
++{
++      vrc4171_socket_t *socket;
++      uint8_t addrwin;
++      u_long start, stop;
++      u_int offset;
++      u_char map;
++
++      if (slot >= CARD_MAX_SLOTS || mem == NULL || mem->map >= MEM_MAX_MAPS)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++      map = mem->map;
++
++      mem->flags = 0;
++      mem->speed = 0;
++
++      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++      if (addrwin & I365_ENA_MEM(map))
++              mem->flags |= MAP_ACTIVE;
++
++      start = exca_read_word(slot, I365_MEM(map)+I365_W_START);
++      if (start & I365_MEM_16BIT)
++              mem->flags |= MAP_16BIT;
++      mem->sys_start = (start & 0x3fffUL) << 12;
++
++      stop = exca_read_word(slot, I365_MEM(map)+I365_W_STOP);
++      if (start & I365_MEM_WS0)
++              mem->speed += 1;
++      if (start & I365_MEM_WS1)
++              mem->speed += 2;
++      mem->sys_stop = ((stop & 0x3fffUL) << 12) + 0xfffUL;
++
++      offset = exca_read_word(slot, I365_MEM(map)+I365_W_OFF);
++      if (offset & I365_MEM_REG)
++              mem->flags |= MAP_ATTRIB;
++      if (offset & I365_MEM_WRPROT)
++              mem->flags |= MAP_WRPROT;
++      mem->card_start = (offset & 0x3fffUL) << 12;
++
++      mem->sys_start += CARD_MEM_START;
++      mem->sys_stop += CARD_MEM_START;
++
++      return 0;
++}
++
++static int pccard_set_mem_map(unsigned int slot, struct pccard_mem_map *mem)
++{
++      vrc4171_socket_t *socket;
++      uint16_t start, stop, offset;
++      uint8_t addrwin;
++      u_char map;
++
++      if (slot >= CARD_MAX_SLOTS ||
++          mem == NULL || mem->map >= MEM_MAX_MAPS ||
++          mem->sys_start < CARD_MEM_START || mem->sys_start > CARD_MEM_END ||
++          mem->sys_stop < CARD_MEM_START || mem->sys_stop > CARD_MEM_END ||
++          mem->sys_start > mem->sys_stop ||
++          mem->card_start > CARD_MAX_MEM_OFFSET ||
++          mem->speed > CARD_MAX_MEM_SPEED)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++      map = mem->map;
++
++      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++      if (addrwin & I365_ENA_MEM(map)) {
++              addrwin &= ~I365_ENA_MEM(map);
++              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      }
++
++      start = (mem->sys_start >> 12) & 0x3fff;
++      if (mem->flags & MAP_16BIT)
++              start |= I365_MEM_16BIT;
++      exca_write_word(slot, I365_MEM(map)+I365_W_START, start);
++
++      stop = (mem->sys_stop >> 12) & 0x3fff;
++      switch (mem->speed) {
++      case 0:
++              break;
++      case 1:
++              stop |= I365_MEM_WS0;
++              break;
++      case 2:
++              stop |= I365_MEM_WS1;
++              break;
++      default:
++              stop |= I365_MEM_WS0 | I365_MEM_WS1;
++              break;
++      }
++      exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop);
++
++      offset = (mem->card_start >> 12) & 0x3fff;
++      if (mem->flags & MAP_ATTRIB)
++              offset |= I365_MEM_REG;
++      if (mem->flags & MAP_WRPROT)
++              offset |= I365_MEM_WRPROT;
++      exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset);
++
++      if (mem->flags & MAP_ACTIVE) {
++              addrwin |= I365_ENA_MEM(map);
++              exca_write_byte(slot, I365_ADDRWIN, addrwin);
++      }
++
++      return 0;
++}
++
++static void pccard_proc_setup(unsigned int slot, struct proc_dir_entry *base)
++{          
++}
++
++static struct pccard_operations vrc4171_pccard_operations = {
++      .init                   = pccard_init,
++      .suspend                = pccard_suspend,
++      .register_callback      = pccard_register_callback,
++      .inquire_socket         = pccard_inquire_socket,
++      .get_status             = pccard_get_status,
++      .get_socket             = pccard_get_socket,
++      .set_socket             = pccard_set_socket,
++      .get_io_map             = pccard_get_io_map,
++      .set_io_map             = pccard_set_io_map,
++      .get_mem_map            = pccard_get_mem_map,
++      .set_mem_map            = pccard_set_mem_map,
++      .proc_setup             = pccard_proc_setup,
++};
++
++static void pccard_bh(void *data)
++{
++      vrc4171_socket_t *socket = (vrc4171_socket_t *)data;
++      uint16_t events;
++
++      spin_lock_irq(&socket->event_lock);
++      events = socket->events;
++      socket->events = 0;
++      spin_unlock_irq(&socket->event_lock);
++ 
++      if (socket->handler)
++              socket->handler(socket->info, events);
++}
++
++static inline uint16_t get_events(int slot)
++{
++      uint16_t events = 0;
++      uint8_t status, csc;
++
++      status = exca_read_byte(slot, I365_STATUS);
++      csc = exca_read_byte(slot, I365_CSC);
++
++      if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
++              if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG))
++                      events |= SS_STSCHG;
++      } else {
++              if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) {
++                      if (!(status & I365_CS_BVD1))
++                              events |= SS_BATDEAD;
 +                      else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
 +                              events |= SS_BATWARN;
 +              }
 +      }
-+      if ((csc & I365_CSC_READY) && (status & I365_CS_READY))
-+              events |= SS_READY;
-+      if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT))
-+              events |= SS_DETECT;
++      if ((csc & I365_CSC_READY) && (status & I365_CS_READY))
++              events |= SS_READY;
++      if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT))
++              events |= SS_DETECT;
++
++      return events;
++}
++
++static void pccard_status_change(int slot, vrc4171_socket_t *socket)
++{
++      uint16_t events;
++
++      socket->tq_task.routine = pccard_bh;
++      socket->tq_task.data = socket;
++
++      events = get_events(slot);
++      if (events) {
++              spin_lock(&socket->event_lock);
++              socket->events |= events;
++              spin_unlock(&socket->event_lock);
++              schedule_task(&socket->tq_task);
++      }
++}
++
++static void pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++      vrc4171_socket_t *socket;
++      uint16_t status;
++
++      status = vrc4171_get_irq_status();
++      if (status & IRQ_A) {
++              socket = &vrc4171_sockets[CARD_SLOTA];
++              if (socket->noprobe == SLOTB_PROBE) {
++                      if (status & (1 << socket->csc_irq))
++                              pccard_status_change(CARD_SLOTA, socket);
++              }
++      }
++
++      if (status & IRQ_B) {
++              socket = &vrc4171_sockets[CARD_SLOTB];
++              if (socket->noprobe == SLOTB_PROBE) {
++                      if (status & (1 << socket->csc_irq))
++                              pccard_status_change(CARD_SLOTB, socket);
++              }
++      }
++}
++
++static inline void reserve_using_irq(int slot)
++{
++      unsigned int irq;
++
++      irq = exca_read_byte(slot, I365_INTCTL);
++      irq &= 0x0f;
++      vrc4171_irq_mask &= ~(1 << irq);
++
++      irq = exca_read_byte(slot, I365_CSCINT);
++      irq = (irq & 0xf0) >> 4;
++      vrc4171_irq_mask &= ~(1 << irq);
++}
++
++static int __devinit vrc4171_add_socket(int slot)
++{
++      vrc4171_socket_t *socket;
++
++      if (slot >= CARD_MAX_SLOTS)
++              return -EINVAL;
++
++      socket = &vrc4171_sockets[slot];
++      if (socket->noprobe != SLOTB_PROBE) {
++              uint8_t addrwin;
++
++              switch (socket->noprobe) {
++              case SLOTB_NOPROBE_MEM:
++                      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++                      addrwin &= 0x1f;
++                      exca_write_byte(slot, I365_ADDRWIN, addrwin);
++                      break;
++              case SLOTB_NOPROBE_IO:
++                      addrwin = exca_read_byte(slot, I365_ADDRWIN);
++                      addrwin &= 0xc0;
++                      exca_write_byte(slot, I365_ADDRWIN, addrwin);
++                      break;
++              default:
++                      break;
++              }
++
++              reserve_using_irq(slot);
++
++              return 0;
++      }
++
++      sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
++
++      socket->pcmcia_socket = pcmcia_register_socket(slot, &vrc4171_pccard_operations, 1);
++      if (socket->pcmcia_socket == NULL)
++              return -ENOMEM;
++
++      exca_write_byte(slot, I365_ADDRWIN, 0);
++
++      exca_write_byte(slot, GLOBAL_CONTROL, 0);
++
++      return 0;
++}
++
++static void vrc4171_remove_socket(int slot)
++{
++      vrc4171_socket_t *socket;
++
++      if (slot >= CARD_MAX_SLOTS)
++              return;
++
++      socket = &vrc4171_sockets[slot];
++
++      if (socket->pcmcia_socket != NULL) {
++              pcmcia_unregister_socket(socket->pcmcia_socket);
++              socket->pcmcia_socket = NULL;
++      }
++}
++
++static int __devinit vrc4171_card_setup(char *options)
++{
++      if (options == NULL || *options == '\0')
++              return 0;
++
++      if (strncmp(options, "irq:", 4) == 0) {
++              int irq;
++              options += 4;
++              irq = simple_strtoul(options, &options, 0);
++              if (irq >= 0 && irq < NR_IRQS)
++                      vrc4171_irq = irq;
++
++              if (*options != ',')
++                      return 0;
++              options++;
++      }
++
++      if (strncmp(options, "slota:", 6) == 0) {
++              options += 6;
++              if (*options != '\0') {
++                      if (strncmp(options, "noprobe", 7) == 0) {
++                              vrc4171_sockets[CARD_SLOTA].noprobe = 1;
++                              options += 7;
++                      }
++
++                      if (*options != ',')
++                              return 0;
++                      options++;
++              } else
++                      return 0;
++
++      }
++
++      if (strncmp(options, "slotb:", 6) == 0) {
++              options += 6;
++              if (*options != '\0') {
++                      if (strncmp(options, "pccard", 6) == 0) {
++                              vrc4171_slotb = SLOTB_IS_PCCARD;
++                              options += 6;
++                      } else if (strncmp(options, "cf", 2) == 0) {
++                              vrc4171_slotb = SLOTB_IS_CF;
++                              options += 2;
++                      } else if (strncmp(options, "flashrom", 8) == 0) {
++                              vrc4171_slotb = SLOTB_IS_FLASHROM;
++                              options += 8;
++                      } else if (strncmp(options, "none", 4) == 0) {
++                              vrc4171_slotb = SLOTB_IS_NONE;
++                              options += 4;
++                      }
++
++                      if (*options != ',')
++                              return 0;
++                      options++;
++
++                      if ( strncmp(options, "memnoprobe", 10) == 0)
++                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_MEM;
++                      if ( strncmp(options, "ionoprobe", 9) == 0)
++                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_IO;
++                      if ( strncmp(options, "noprobe", 7) == 0)
++                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_ALL;
++              }
++      }
++
++      return 0;
++}
++
++__setup("vrc4171_card=", vrc4171_card_setup);
++
++static int __devinit vrc4171_card_init(void)
++{
++      int retval, slot;
++
++      vrc4171_set_multifunction_pin(vrc4171_slotb);
++
++      if (request_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE,
++                             "NEC VRC4171 Card Controller") == NULL)
++              return -EBUSY;
++
++      for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
++              if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
++                      break;
++
++              retval = vrc4171_add_socket(slot);
++              if (retval != 0)
++                      return retval;
++      }
++
++      retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
++                           "NEC VRC4171 Card Controller", vrc4171_sockets);
++      if (retval < 0) {
++              for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
++                      vrc4171_remove_socket(slot);
++
++              return retval;
++      }
++
++      printk(KERN_INFO "NEC VRC4171 Card Controller, connected to IRQ %d\n", vrc4171_irq);
++
++      return 0;
++}
++
++static void __devexit vrc4171_card_exit(void)
++{
++      int slot;
++
++      for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
++              vrc4171_remove_socket(slot);
++
++      release_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE);
++}
++
++module_init(vrc4171_card_init);
++module_exit(vrc4171_card_exit);
+diff -Nur linux-2.4.29/drivers/sbus/audio/audio.c linux-mips/drivers/sbus/audio/audio.c
+--- linux-2.4.29/drivers/sbus/audio/audio.c    2001-10-11 08:42:46.000000000 +0200
++++ linux-mips/drivers/sbus/audio/audio.c      2005-03-26 11:47:32.089385135 +0100
+@@ -65,6 +65,14 @@
+ #define tprintk(x)
+ #endif
++static int  audio_input_buffers = 8;
++MODULE_PARM(audio_input_buffers, "i");
++MODULE_PARM_DESC(audio_input_buffers,"Number of input 8KB buffers.");
++
++static int  audio_output_buffers = 8;
++MODULE_PARM(audio_output_buffers, "i");
++MODULE_PARM_DESC(audio_output_buffers,"Number of output 8KB buffer.");
++
+ static short lis_get_elist_ent( strevent_t *list, pid_t pid );
+ static int lis_add_to_elist( strevent_t **list, pid_t pid, short events );
+ static int lis_del_from_elist( strevent_t **list, pid_t pid, short events );
+@@ -438,7 +446,7 @@
+                         m = drv->ops->get_input_balance(drv);
+                 i = OSS_TO_GAIN(k);
+                 j = OSS_TO_BAL(k);
+-                oprintk((" for stereo to do %d (bal %d):", i, j));
++                oprintk((" for stereo to do %ld (bal %ld):", i, j));
+                 if (drv->ops->set_input_volume)
+                         drv->ops->set_input_volume(drv, i);
+                 if (drv->ops->set_input_balance)
+@@ -488,7 +496,7 @@
+                 oprintk((" started as (0x%x)\n", BAL_TO_OSS(l,m)));
+                 i = OSS_TO_GAIN(k);
+                 j = OSS_TO_BAL(k);
+-                oprintk((" for stereo to %d (bal %d)\n", i, j));
++                oprintk((" for stereo to %ld (bal %ld)\n", i, j));
+                 if (drv->ops->set_output_volume)
+                         drv->ops->set_output_volume(drv, i);
+                 if (drv->ops->set_output_balance)
+@@ -565,7 +573,7 @@
+           if (k & SOUND_MASK_CD) j = AUDIO_CD;
+           if (k & SOUND_MASK_LINE) j = AUDIO_LINE_IN;
+           if (k & SOUND_MASK_MIC) j = AUDIO_MICROPHONE;
+-          oprintk(("setting inport to %d\n", j));
++          oprintk(("setting inport to %ld\n", j));
+           i = drv->ops->set_input_port(drv, j);
+     
+           return put_user(i, (int *)arg);
+@@ -798,7 +806,7 @@
+                                 retval = -EINVAL;
+                                 break;
+                         }
+-                        get_user(i, (int *)arg)
++                        get_user(i, (int *)arg);
+                         tprintk(("setting speed to %d\n", i));
+                         drv->ops->set_input_rate(drv, i);
+                         drv->ops->set_output_rate(drv, i);
+@@ -1955,8 +1963,6 @@
+          * Input buffers, on the other hand, always fill completely,
+          * so we don't need input counts - each contains input_buffer_size
+          * bytes of audio data.
+-         *
+-         * TODO: Make number of input/output buffers tunable parameters
+          */
+         init_waitqueue_head(&drv->open_wait);
+@@ -1964,7 +1970,7 @@
+         init_waitqueue_head(&drv->output_drain_wait);
+         init_waitqueue_head(&drv->input_read_wait);
+-        drv->num_output_buffers = 8;
++        drv->num_output_buffers = audio_output_buffers;
+       drv->output_buffer_size = (4096 * 2);
+       drv->playing_count = 0;
+       drv->output_offset = 0;
+@@ -1997,7 +2003,7 @@
+         }
+         /* Setup the circular queue of input buffers. */
+-        drv->num_input_buffers = 8;
++        drv->num_input_buffers = audio_input_buffers;
+       drv->input_buffer_size = (4096 * 2);
+       drv->recording_count = 0;
+         drv->input_front = 0;
+diff -Nur linux-2.4.29/drivers/sbus/audio/dbri.c linux-mips/drivers/sbus/audio/dbri.c
+--- linux-2.4.29/drivers/sbus/audio/dbri.c     2002-11-29 00:53:14.000000000 +0100
++++ linux-mips/drivers/sbus/audio/dbri.c       2005-03-26 11:47:32.378337711 +0100
+@@ -51,6 +51,7 @@
+ #include <linux/slab.h>
+ #include <linux/version.h>
+ #include <linux/delay.h>
++#include <linux/soundcard.h>
+ #include <asm/openprom.h>
+ #include <asm/oplib.h>
+ #include <asm/system.h>
+@@ -161,7 +162,7 @@
+ static void dbri_process_interrupt_buffer(struct dbri *);
+-static void dbri_cmdsend(struct dbri *dbri, volatile s32 *cmd)
++static void dbri_cmdsend(struct dbri *dbri, volatile s32 *cmd, int pause)
+ {
+       int MAXLOOPS = 1000000;
+       int maxloops = MAXLOOPS;
+@@ -181,25 +182,30 @@
+         } else if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS-1) {
+                 printk("DBRI: Command buffer overflow! (bug in driver)\n");
+         } else {
+-                *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
++                if (pause) 
++                      *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+               *(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
+               dbri->wait_seen = 0;
+                 sbus_writel(dbri->dma_dvma, dbri->regs + REG8);
+-              while ((--maxloops) > 0 &&
+-                       (sbus_readl(dbri->regs + REG0) & D_P))
+-                        barrier();
+-              if (maxloops == 0) {
+-                      printk("DBRI: Chip never completed command buffer\n");
+-              } else {
+-                      while ((--maxloops) > 0 && (! dbri->wait_seen))
+-                              dbri_process_interrupt_buffer(dbri);
++              if (pause) {
++                      while ((--maxloops) > 0 &&
++                             (sbus_readl(dbri->regs + REG0) & D_P))
++                              barrier();
+                       if (maxloops == 0) {
+-                              printk("DBRI: Chip never acked WAIT\n");
++                              printk("DBRI: Chip never completed command buffer\n");
+                       } else {
+-                              dprintk(D_INT, ("DBRI: Chip completed command "
+-                                                "buffer (%d)\n",
+-                                              MAXLOOPS - maxloops));
++                              while ((--maxloops) > 0 && (! dbri->wait_seen))
++                                      dbri_process_interrupt_buffer(dbri);
++                              if (maxloops == 0) {
++                                      printk("DBRI: Chip never acked WAIT\n");
++                              } else {
++                                      dprintk(D_INT, ("DBRI: Chip completed command "
++                                                      "buffer (%d)\n",
++                                                      MAXLOOPS - maxloops));
++                              }
+                       }
++              } else {
++                      dprintk(D_INT, ("DBRI: NO PAUSE\n"));
+               }
+         }
+@@ -257,7 +263,10 @@
+         /* We should query the openprom to see what burst sizes this
+          * SBus supports.  For now, just disable all SBus bursts */
+         tmp = sbus_readl(dbri->regs + REG0);
+-        tmp &= ~(D_G | D_S | D_E);
++      /* A brute approach - DBRI falls back to working burst size by itself
++       * On SS20 D_S does not work, so do not try so high. */
++        tmp |= D_G | D_E;
++        tmp &= ~D_S;
+         sbus_writel(tmp, dbri->regs + REG0);
+       /*
+@@ -268,7 +277,7 @@
+       *(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
+       *(cmd++) = dma_addr;
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+ }
+@@ -455,7 +464,7 @@
+                                   dbri->pipes[pipe].sdp
+                                   | D_SDP_P | D_SDP_C | D_SDP_2SAME);
+                 *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td);
+-              dbri_cmdsend(dbri, cmd);
++              dbri_cmdsend(dbri, cmd, 1);
+       }
+       if (code == D_INTR_FXDT) {
+@@ -579,7 +588,7 @@
+         cmd = dbri_cmdlock(dbri);
+         *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
+         *(cmd++) = 0;
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+       desc = dbri->pipes[pipe].desc;
+       while (desc != -1) {
+@@ -722,7 +731,7 @@
+               *(cmd++) = D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
+       }
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+ }
+ /* I don't use this function, so it's basically untested. */
+@@ -752,7 +761,7 @@
+               *(cmd++) = D_TS_NEXT(nextpipe);
+         }
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+ }
+ /* xmit_fixed() / recv_fixed()
+@@ -803,7 +812,7 @@
+         *(cmd++) = DBRI_CMD(D_SSP, 0, pipe);
+         *(cmd++) = data;
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+ }
+ static void recv_fixed(struct dbri *dbri, int pipe, volatile __u32 *ptr)
+@@ -884,7 +893,9 @@
+                 }
+                 if (len > ((1 << 13) - 1)) {
+-                        mylen = (1 << 13) - 1;
++              /* One should not leave a buffer shorter than    */
++              /* a single sample. Otherwise bad things happens.*/
++                        mylen = (1 << 13) - 4;
+                 } else {
+                         mylen = len;
+                 }
+@@ -954,7 +965,7 @@
+               cmd = dbri_cmdlock(dbri);
+               *(cmd++) = DBRI_CMD(D_CDP, 0, pipe);
+-              dbri_cmdsend(dbri,cmd);
++              dbri_cmdsend(dbri,cmd, 0);
+       } else {
+               /* Pipe isn't active - issue an SDP command to start
+                * our chain of TDs running.
+@@ -965,7 +976,7 @@
+                                   dbri->pipes[pipe].sdp
+                                   | D_SDP_P | D_SDP_EVERY | D_SDP_C);
+                 *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td);
+-              dbri_cmdsend(dbri, cmd);
++              dbri_cmdsend(dbri, cmd, 0);
+       }
+       restore_flags(flags);
+@@ -1083,7 +1094,7 @@
+       *(cmd++) = DBRI_CMD(D_SDP, 0, dbri->pipes[pipe].sdp | D_SDP_P | D_SDP_C);
+         *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_rd);
+-        dbri_cmdsend(dbri, cmd);
++        dbri_cmdsend(dbri, cmd, 1);
+ }
+@@ -1191,7 +1202,7 @@
+       *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
+       *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+-      dbri_cmdsend(dbri, cmd);
++      dbri_cmdsend(dbri, cmd, 1);
+ }
+ /*
+@@ -1538,7 +1549,6 @@
+       xmit_on_pipe(dbri, 4, buffer, count,
+                    &dbri_audio_output_callback, drv);
+-#if 0
+       /* Notify midlevel that we're a DMA-capable driver that
+        * can accept another buffer immediately.  We should probably
+        * check that we've got enough resources (i.e, descriptors)
+@@ -1551,9 +1561,14 @@
+        * DBRI with a chain of buffers, but the midlevel code is
+        * so tricky that I really don't want to deal with it.
+        */
++      /*
++       * This must be enabled otherwise the output is noisy
++       * as return to user space is done when all buffers
++       * are already played, so user space player has no time
++       * to prepare next ones without a period of silence. - Krzysztof Helt
++       */
+       sparcaudio_output_done(drv, 2);
+-#endif
+ }
+ static void dbri_stop_output(struct sparcaudio_driver *drv)
+@@ -1842,6 +1857,12 @@
+       return dbri_get_output_rate(drv);
+ }
++static int dbri_get_formats(struct sparcaudio_driver *drv)
++{
++/* 8-bit format is not working */
++        return (AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE);
++}
++
+ /******************* sparcaudio midlevel - ports ***********************/
+ static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
+@@ -1983,6 +2004,19 @@
+       dbri_get_input_ports,
+       dbri_set_output_muted,
+       dbri_get_output_muted,
++      NULL, /* dbri_set_output_pause, */
++      NULL, /* dbri_get_output_pause, */
++      NULL, /* dbri_set_input_pause, */
++      NULL, /* dbri_get_input_pause, */
++      NULL, /* dbri_set_output_samples, */
++      NULL, /* dbri_get_output_samples, */
++      NULL, /* dbri_set_input_samples, */
++      NULL, /* dbri_get_input_samples, */
++      NULL, /* dbri_set_output_error, */
++      NULL, /* dbri_get_output_error, */
++      NULL, /* dbri_set_input_error, */
++      NULL, /* dbri_get_input_error, */
++        dbri_get_formats
+ };
+@@ -2093,7 +2127,7 @@
+ #endif
+              *(cmd++) = DBRI_CMD(D_TE, 0, val);
+-             dbri_cmdsend(dbri, cmd);
++             dbri_cmdsend(dbri, cmd, 1);
+              /* Activate the interface */
+                tmp = sbus_readl(dbri->regs + REG0);
+diff -Nur linux-2.4.29/drivers/scsi/ahci.c linux-mips/drivers/scsi/ahci.c
+--- linux-2.4.29/drivers/scsi/ahci.c   2005-01-19 15:10:01.000000000 +0100
++++ linux-mips/drivers/scsi/ahci.c     2005-03-26 11:47:32.448326225 +0100
+@@ -40,8 +40,6 @@
+ #define DRV_NAME      "ahci"
+ #define DRV_VERSION   "1.00"
+-#define msleep libata_msleep   /* 2.4-specific */
+-
+ enum {
+       AHCI_PCI_BAR            = 5,
+       AHCI_MAX_SG             = 168, /* hardware max is 64K */
+@@ -180,6 +178,7 @@
+ static void ahci_host_stop(struct ata_host_set *host_set);
+ static void ahci_qc_prep(struct ata_queued_cmd *qc);
+ static u8 ahci_check_status(struct ata_port *ap);
++static u8 ahci_check_err(struct ata_port *ap);
+ static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+ static Scsi_Host_Template ahci_sht = {
+@@ -206,6 +205,8 @@
+       .port_disable           = ata_port_disable,
+       .check_status           = ahci_check_status,
++      .check_altstatus        = ahci_check_status,
++      .check_err              = ahci_check_err,
+       .dev_select             = ata_noop_dev_select,
+       .phy_reset              = ahci_phy_reset,
+@@ -248,6 +249,12 @@
+         board_ahci }, /* ICH7 */
+       { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH7M */
++      { PCI_VENDOR_ID_INTEL, 0x27c2, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH7R */
++      { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH7R */
++      { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ULi M5288 */
+       { }     /* terminate list */
+ };
+@@ -448,6 +455,13 @@
+       return readl(mmio + PORT_TFDATA) & 0xFF;
+ }
++static u8 ahci_check_err(struct ata_port *ap)
++{
++      void *mmio = (void *) ap->ioaddr.cmd_addr;
++
++      return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
++}
++
+ static void ahci_fill_sg(struct ata_queued_cmd *qc)
+ {
+       struct ahci_port_priv *pp = qc->ap->private_data;
+@@ -515,15 +529,6 @@
+       ahci_fill_sg(qc);
+ }
+-static inline void ahci_dma_complete (struct ata_port *ap,
+-                                     struct ata_queued_cmd *qc,
+-                                   int have_err)
+-{
+-      /* get drive status; clear intr; complete txn */
+-      ata_qc_complete(ata_qc_from_tag(ap, ap->active_tag),
+-                      have_err ? ATA_ERR : 0);
+-}
+-
+ static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
+ {
+       void *mmio = ap->host_set->mmio_base;
+@@ -569,7 +574,7 @@
+       writel(tmp, port_mmio + PORT_CMD);
+       readl(port_mmio + PORT_CMD); /* flush */
+-      printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->port_no);
++      printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
+ }
+ static void ahci_eng_timeout(struct ata_port *ap)
+@@ -761,10 +766,10 @@
+       using_dac = hpriv->cap & HOST_CAP_64;
+       if (using_dac &&
+-          !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
++          !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+               hpriv->flags |= HOST_CAP_64;
+       } else {
+-              rc = pci_set_dma_mask(pdev, 0xffffffffULL);
++              rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (rc) {
+                       printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n",
+                               pci_name(pdev));
+@@ -929,6 +934,7 @@
+       unsigned long base;
+       void *mmio_base;
+       unsigned int board_idx = (unsigned int) ent->driver_data;
++      int pci_dev_busy = 0;
+       int rc;
+       VPRINTK("ENTER\n");
+@@ -941,8 +947,10 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       pci_enable_intx(pdev);
+@@ -1002,7 +1010,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/aic7xxx/aic79xx_pci.c linux-mips/drivers/scsi/aic7xxx/aic79xx_pci.c
+--- linux-2.4.29/drivers/scsi/aic7xxx/aic79xx_pci.c    2003-08-25 13:44:42.000000000 +0200
++++ linux-mips/drivers/scsi/aic7xxx/aic79xx_pci.c      2005-03-26 11:47:34.828935512 +0100
+@@ -451,8 +451,10 @@
+        * or read prefetching could be initiated by the
+        * CPU or host bridge.  Our device does not support
+        * either, so look for data corruption and/or flaged
+-       * PCI errors.
++       * PCI errors.  First pause without causing another
++       * chip reset.
+        */
++      hcntrl &= ~CHIPRST;
+       ahd_outb(ahd, HCNTRL, hcntrl|PAUSE);
+       while (ahd_is_paused(ahd) == 0)
+               ;
+diff -Nur linux-2.4.29/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-mips/drivers/scsi/aic7xxx/aic7xxx_pci.c
+--- linux-2.4.29/drivers/scsi/aic7xxx/aic7xxx_pci.c    2003-08-25 13:44:42.000000000 +0200
++++ linux-mips/drivers/scsi/aic7xxx/aic7xxx_pci.c      2005-03-26 11:47:34.831935020 +0100
+@@ -1284,8 +1284,10 @@
+        * or read prefetching could be initiated by the
+        * CPU or host bridge.  Our device does not support
+        * either, so look for data corruption and/or flagged
+-       * PCI errors.
++       * PCI errors.  First pause without causing another
++       * chip reset.
+        */
++      hcntrl &= ~CHIPRST;
+       ahc_outb(ahc, HCNTRL, hcntrl|PAUSE);
+       while (ahc_is_paused(ahc) == 0)
+               ;
+diff -Nur linux-2.4.29/drivers/scsi/ata_piix.c linux-mips/drivers/scsi/ata_piix.c
+--- linux-2.4.29/drivers/scsi/ata_piix.c       2005-01-19 15:10:01.000000000 +0100
++++ linux-mips/drivers/scsi/ata_piix.c 2005-03-26 11:47:32.450325897 +0100
+@@ -139,6 +139,8 @@
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+@@ -164,6 +166,8 @@
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+diff -Nur linux-2.4.29/drivers/scsi/Config.in linux-mips/drivers/scsi/Config.in
+--- linux-2.4.29/drivers/scsi/Config.in        2005-01-19 15:09:59.000000000 +0100
++++ linux-mips/drivers/scsi/Config.in  2005-03-26 11:47:32.437328030 +0100
+@@ -73,6 +73,7 @@
+ dep_tristate '  ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SVW $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+ dep_tristate '  Intel PIIX/ICH SATA support' CONFIG_SCSI_ATA_PIIX $CONFIG_SCSI_SATA $CONFIG_PCI
+ dep_tristate '  NVIDIA SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_NV $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
++dep_tristate '  Pacific Digital SATA QStor support' CONFIG_SCSI_SATA_QSTOR $CONFIG_SCSI_SATA $CONFIG_PCI
+ dep_tristate '  Promise SATA TX2/TX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_PROMISE $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+ dep_tristate '  Promise SATA SX4 support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SX4 $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+ dep_tristate '  Silicon Image SATA support (EXPERIMENTAL)' CONFIG_SCSI_SATA_SIL $CONFIG_SCSI_SATA $CONFIG_PCI $CONFIG_EXPERIMENTAL
+diff -Nur linux-2.4.29/drivers/scsi/libata-core.c linux-mips/drivers/scsi/libata-core.c
+--- linux-2.4.29/drivers/scsi/libata-core.c    2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/libata-core.c      2005-03-26 11:47:32.481320810 +0100
+@@ -376,7 +376,7 @@
+ }
+ /**
+- *    ata_check_status - Read device status reg & clear interrupt
++ *    ata_check_status_pio - Read device status reg & clear interrupt
+  *    @ap: port where the device is
+  *
+  *    Reads ATA taskfile status register for currently-selected device
+@@ -414,6 +414,27 @@
+       return ata_check_status_pio(ap);
+ }
++u8 ata_altstatus(struct ata_port *ap)
++{
++      if (ap->ops->check_altstatus)
++              return ap->ops->check_altstatus(ap);
++
++      if (ap->flags & ATA_FLAG_MMIO)
++              return readb((void __iomem *)ap->ioaddr.altstatus_addr);
++      return inb(ap->ioaddr.altstatus_addr);
++}
++
++u8 ata_chk_err(struct ata_port *ap)
++{
++      if (ap->ops->check_err)
++              return ap->ops->check_err(ap);
++
++      if (ap->flags & ATA_FLAG_MMIO) {
++              return readb((void __iomem *) ap->ioaddr.error_addr);
++      }
++      return inb(ap->ioaddr.error_addr);
++}
++
+ /**
+  *    ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+  *    @tf: Taskfile to convert
+@@ -1160,7 +1181,6 @@
+       printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+              ap->id, device);
+ err_out:
+-      ata_irq_on(ap); /* re-enable interrupts */
+       dev->class++;   /* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
+       DPRINTK("EXIT, err\n");
+ }
+@@ -1668,7 +1688,8 @@
+               ata_dev_try_classify(ap, 1);
+       /* re-enable interrupts */
+-      ata_irq_on(ap);
++      if (ap->ioaddr.ctl_addr)        /* FIXME: hack. create a hook instead */
++              ata_irq_on(ap);
+       /* is double-select really necessary? */
+       if (ap->device[1].class != ATA_DEV_NONE)
+@@ -1699,6 +1720,69 @@
+       DPRINTK("EXIT\n");
+ }
++static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev)
++{
++      printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
++              ap->id, dev->devno);
++}
++
++static const char * ata_dma_blacklist [] = {
++      "WDC AC11000H",
++      "WDC AC22100H",
++      "WDC AC32500H",
++      "WDC AC33100H",
++      "WDC AC31600H",
++      "WDC AC32100H",
++      "WDC AC23200L",
++      "Compaq CRD-8241B",
++      "CRD-8400B",
++      "CRD-8480B",
++      "CRD-8482B",
++      "CRD-84",
++      "SanDisk SDP3B",
++      "SanDisk SDP3B-64",
++      "SANYO CD-ROM CRD",
++      "HITACHI CDR-8",
++      "HITACHI CDR-8335",
++      "HITACHI CDR-8435",
++      "Toshiba CD-ROM XM-6202B",
++      "CD-532E-A",
++      "E-IDE CD-ROM CR-840",
++      "CD-ROM Drive/F5A",
++      "WPI CDD-820",
++      "SAMSUNG CD-ROM SC-148C",
++      "SAMSUNG CD-ROM SC",
++      "SanDisk SDP3B-64",
++      "SAMSUNG CD-ROM SN-124",
++      "ATAPI CD-ROM DRIVE 40X MAXIMUM",
++      "_NEC DV5800A",
++};
++
++static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev)
++{
++      unsigned char model_num[40];
++      char *s;
++      unsigned int len;
++      int i;
++
++      ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
++                        sizeof(model_num));
++      s = &model_num[0];
++      len = strnlen(s, sizeof(model_num));
++
++      /* ATAPI specifies that empty space is blank-filled; remove blanks */
++      while ((len > 0) && (s[len - 1] == ' ')) {
++              len--;
++              s[len] = 0;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++)
++              if (!strncmp(ata_dma_blacklist[i], s, len))
++                      return 1;
++
++      return 0;
++}
++
+ static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift)
+ {
+       struct ata_device *master, *slave;
+@@ -1711,17 +1795,37 @@
+       if (shift == ATA_SHIFT_UDMA) {
+               mask = ap->udma_mask;
+-              if (ata_dev_present(master))
++              if (ata_dev_present(master)) {
+                       mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
+-              if (ata_dev_present(slave))
++                      if (ata_dma_blacklisted(ap, master)) {
++                              mask = 0;
++                              ata_pr_blacklisted(ap, master);
++                      }
++              }
++              if (ata_dev_present(slave)) {
+                       mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
++                      if (ata_dma_blacklisted(ap, slave)) {
++                              mask = 0;
++                              ata_pr_blacklisted(ap, slave);
++                      }
++              }
+       }
+       else if (shift == ATA_SHIFT_MWDMA) {
+               mask = ap->mwdma_mask;
+-              if (ata_dev_present(master))
++              if (ata_dev_present(master)) {
+                       mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
+-              if (ata_dev_present(slave))
++                      if (ata_dma_blacklisted(ap, master)) {
++                              mask = 0;
++                              ata_pr_blacklisted(ap, master);
++                      }
++              }
++              if (ata_dev_present(slave)) {
+                       mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
++                      if (ata_dma_blacklisted(ap, slave)) {
++                              mask = 0;
++                              ata_pr_blacklisted(ap, slave);
++                      }
++              }
+       }
+       else if (shift == ATA_SHIFT_PIO) {
+               mask = ap->pio_mask;
+@@ -2518,10 +2622,10 @@
+       case ATA_PROT_DMA:
+       case ATA_PROT_ATAPI_DMA:
+-              host_stat = ata_bmdma_status(ap);
++              host_stat = ap->ops->bmdma_status(ap);
+               /* before we do anything else, clear DMA-Start bit */
+-              ata_bmdma_stop(ap);
++              ap->ops->bmdma_stop(ap);
+               /* fall through */
+@@ -2530,7 +2634,7 @@
+               drv_stat = ata_chk_status(ap);
+               /* ack bmdma irq events */
+-              ata_bmdma_ack_irq(ap);
++              ap->ops->irq_clear(ap);
+               printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
+                      ap->id, qc->tf.command, drv_stat, host_stat);
+@@ -2669,6 +2773,24 @@
+ }
+ /**
++ *    ata_qc_free - free unused ata_queued_cmd
++ *    @qc: Command to complete
++ *
++ *    Designed to free unused ata_queued_cmd object
++ *    in case something prevents using it.
++ *
++ *    LOCKING:
++ *
++ */
++void ata_qc_free(struct ata_queued_cmd *qc)
++{
++      assert(qc != NULL);     /* ata_qc_from_tag _might_ return NULL */
++      assert(qc->waiting == NULL);    /* nothing should be waiting */
++
++      __ata_qc_complete(qc);
++}
++
++/**
+  *    ata_qc_complete - Complete an active ATA command
+  *    @qc: Command to complete
+  *    @drv_stat: ATA status register contents
+@@ -2717,7 +2839,7 @@
+                       return 1;
+               /* fall through */
+-
++      
+       default:
+               return 0;
+       }
+@@ -2959,7 +3081,43 @@
+ void ata_bmdma_irq_clear(struct ata_port *ap)
+ {
+-      ata_bmdma_ack_irq(ap);
++    if (ap->flags & ATA_FLAG_MMIO) {
++        void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
++        writeb(readb(mmio), mmio);
++    } else {
++        unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
++        outb(inb(addr), addr);
++    }
++
++}
++
++u8 ata_bmdma_status(struct ata_port *ap)
++{
++      u8 host_stat;
++      if (ap->flags & ATA_FLAG_MMIO) {
++              void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++              host_stat = readb(mmio + ATA_DMA_STATUS);
++      } else
++      host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
++      return host_stat;
++}
++
++void ata_bmdma_stop(struct ata_port *ap)
++{
++      if (ap->flags & ATA_FLAG_MMIO) {
++              void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
++
++              /* clear start/stop bit */
++              writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
++                      mmio + ATA_DMA_CMD);
++      } else {
++              /* clear start/stop bit */
++              outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
++                      ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
++      }
++
++      /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
++      ata_altstatus(ap);        /* dummy read */
+ }
+ /**
+@@ -2989,7 +3147,7 @@
+       case ATA_PROT_ATAPI_DMA:
+       case ATA_PROT_ATAPI:
+               /* check status of DMA engine */
+-              host_stat = ata_bmdma_status(ap);
++              host_stat = ap->ops->bmdma_status(ap);
+               VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+               /* if it's not our irq... */
+@@ -2997,7 +3155,7 @@
+                       goto idle_irq;
+               /* before we do anything else, clear DMA-Start bit */
+-              ata_bmdma_stop(ap);
++              ap->ops->bmdma_stop(ap);
+               /* fall through */
+@@ -3016,7 +3174,7 @@
+                       ap->id, qc->tf.protocol, status);
+               /* ack bmdma irq events */
+-              ata_bmdma_ack_irq(ap);
++              ap->ops->irq_clear(ap);
+               /* complete taskfile transaction */
+               ata_qc_complete(qc, status);
+@@ -3470,32 +3628,28 @@
+ }
+ static struct ata_probe_ent *
+-ata_probe_ent_alloc(int n, struct device *dev, struct ata_port_info **port)
++ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
+ {
+       struct ata_probe_ent *probe_ent;
+-      int i;
+-      probe_ent = kmalloc(sizeof(*probe_ent) * n, GFP_KERNEL);
++      probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+       if (!probe_ent) {
+               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+                      pci_name(to_pci_dev(dev)));
+               return NULL;
+       }
+-      memset(probe_ent, 0, sizeof(*probe_ent) * n);
++      memset(probe_ent, 0, sizeof(*probe_ent));
+-      for (i = 0; i < n; i++) {
+-              INIT_LIST_HEAD(&probe_ent[i].node);
+-              probe_ent[i].dev = dev;
+-
+-              probe_ent[i].sht = port[i]->sht;
+-              probe_ent[i].host_flags = port[i]->host_flags;
+-              probe_ent[i].pio_mask = port[i]->pio_mask;
+-              probe_ent[i].mwdma_mask = port[i]->mwdma_mask;
+-              probe_ent[i].udma_mask = port[i]->udma_mask;
+-              probe_ent[i].port_ops = port[i]->port_ops;
++      INIT_LIST_HEAD(&probe_ent->node);
++      probe_ent->dev = dev;
+-      }
++      probe_ent->sht = port->sht;
++      probe_ent->host_flags = port->host_flags;
++      probe_ent->pio_mask = port->pio_mask;
++      probe_ent->mwdma_mask = port->mwdma_mask;
++      probe_ent->udma_mask = port->udma_mask;
++      probe_ent->port_ops = port->port_ops;
+       return probe_ent;
+ }
+@@ -3505,7 +3659,7 @@
+ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
+ {
+       struct ata_probe_ent *probe_ent =
+-              ata_probe_ent_alloc(1, pci_dev_to_dev(pdev), port);
++              ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+       if (!probe_ent)
+               return NULL;
+@@ -3531,39 +3685,47 @@
+       return probe_ent;
+ }
+-struct ata_probe_ent *
+-ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port)
++static struct ata_probe_ent *
++ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port,
++    struct ata_probe_ent **ppe2)
+ {
+-      struct ata_probe_ent *probe_ent =
+-              ata_probe_ent_alloc(2, pci_dev_to_dev(pdev), port);
++      struct ata_probe_ent *probe_ent, *probe_ent2;
++
++      probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+       if (!probe_ent)
+               return NULL;
++      probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]);
++      if (!probe_ent2) {
++              kfree(probe_ent);
++              return NULL;
++      }
++
++      probe_ent->n_ports = 1;
++      probe_ent->irq = 14;
+-      probe_ent[0].n_ports = 1;
+-      probe_ent[0].irq = 14;
++      probe_ent->hard_port_no = 0;
++      probe_ent->legacy_mode = 1;
+-      probe_ent[0].hard_port_no = 0;
+-      probe_ent[0].legacy_mode = 1;
++      probe_ent2->n_ports = 1;
++      probe_ent2->irq = 15;
+-      probe_ent[1].n_ports = 1;
+-      probe_ent[1].irq = 15;
++      probe_ent2->hard_port_no = 1;
++      probe_ent2->legacy_mode = 1;
+-      probe_ent[1].hard_port_no = 1;
+-      probe_ent[1].legacy_mode = 1;
+-
+-      probe_ent[0].port[0].cmd_addr = 0x1f0;
+-      probe_ent[0].port[0].altstatus_addr =
+-      probe_ent[0].port[0].ctl_addr = 0x3f6;
+-      probe_ent[0].port[0].bmdma_addr = pci_resource_start(pdev, 4);
+-
+-      probe_ent[1].port[0].cmd_addr = 0x170;
+-      probe_ent[1].port[0].altstatus_addr =
+-      probe_ent[1].port[0].ctl_addr = 0x376;
+-      probe_ent[1].port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
++      probe_ent->port[0].cmd_addr = 0x1f0;
++      probe_ent->port[0].altstatus_addr =
++      probe_ent->port[0].ctl_addr = 0x3f6;
++      probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
++
++      probe_ent2->port[0].cmd_addr = 0x170;
++      probe_ent2->port[0].altstatus_addr =
++      probe_ent2->port[0].ctl_addr = 0x376;
++      probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
+-      ata_std_ports(&probe_ent[0].port[0]);
+-      ata_std_ports(&probe_ent[1].port[0]);
++      ata_std_ports(&probe_ent->port[0]);
++      ata_std_ports(&probe_ent2->port[0]);
++      *ppe2 = probe_ent2;
+       return probe_ent;
+ }
+@@ -3587,6 +3749,7 @@
+       struct ata_port_info *port[2];
+       u8 tmp8, mask;
+       unsigned int legacy_mode = 0;
++      int disable_dev_on_err = 1;
+       int rc;
+       DPRINTK("ENTER\n");
+@@ -3597,7 +3760,8 @@
+       else
+               port[1] = port[0];
+-      if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0) {
++      if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
++          && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+               /* TODO: support transitioning to native mode? */
+               pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+               mask = (1 << 2) | (1 << 0);
+@@ -3616,18 +3780,22 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              disable_dev_on_err = 0;
+               goto err_out;
++      }
+       if (legacy_mode) {
+-              if (!request_region(0x1f0, 8, "libata"))
++              if (!request_region(0x1f0, 8, "libata")) {
++                      disable_dev_on_err = 0;
+                       printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+-              else
++              } else
+                       legacy_mode |= (1 << 0);
+-              if (!request_region(0x170, 8, "libata"))
++              if (!request_region(0x170, 8, "libata")) {
++                      disable_dev_on_err = 0;
+                       printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+-              else
++              } else
+                       legacy_mode |= (1 << 1);
+       }
+@@ -3642,9 +3810,7 @@
+               goto err_out_regions;
+       if (legacy_mode) {
+-              probe_ent = ata_pci_init_legacy_mode(pdev, port);
+-              if (probe_ent)
+-                      probe_ent2 = &probe_ent[1];
++              probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2);
+       } else
+               probe_ent = ata_pci_init_native_mode(pdev, port);
+       if (!probe_ent) {
+@@ -3656,17 +3822,14 @@
+       spin_lock(&ata_module_lock);
+       if (legacy_mode) {
+-              int free = 0;
+               if (legacy_mode & (1 << 0))
+                       list_add_tail(&probe_ent->node, &ata_probe_list);
+               else
+-                      free++;
++                      kfree(probe_ent);
+               if (legacy_mode & (1 << 1))
+                       list_add_tail(&probe_ent2->node, &ata_probe_list);
+               else
+-                      free++;
+-              if (free > 1)
+-                      kfree(probe_ent);
++                      kfree(probe_ent2);
+       } else {
+               list_add_tail(&probe_ent->node, &ata_probe_list);
+       }
+@@ -3681,7 +3844,8 @@
+               release_region(0x170, 8);
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (disable_dev_on_err)
++              pci_disable_device(pdev);
+       return rc;
+ }
+@@ -3723,15 +3887,12 @@
+       if (host_set->mmio_base)
+               iounmap(host_set->mmio_base);
+-      pci_release_regions(pdev);
+-
+       for (i = 0; i < host_set->n_ports; i++) {
+-              struct ata_ioports *ioaddr;
+-
+               ap = host_set->ports[i];
+-              ioaddr = &ap->ioaddr;
+               if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
++                      struct ata_ioports *ioaddr = &ap->ioaddr;
++
+                       if (ioaddr->cmd_addr == 0x1f0)
+                               release_region(0x1f0, 8);
+                       else if (ioaddr->cmd_addr == 0x170)
+@@ -3740,6 +3901,8 @@
+       }
+       kfree(host_set);
++
++      pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       dev_set_drvdata(dev, NULL);
+ }
+@@ -3839,6 +4002,8 @@
+ EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+ EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+ EXPORT_SYMBOL_GPL(ata_check_status);
++EXPORT_SYMBOL_GPL(ata_altstatus);
++EXPORT_SYMBOL_GPL(ata_chk_err);
+ EXPORT_SYMBOL_GPL(ata_exec_command);
+ EXPORT_SYMBOL_GPL(ata_port_start);
+ EXPORT_SYMBOL_GPL(ata_port_stop);
+@@ -3847,6 +4012,8 @@
+ EXPORT_SYMBOL_GPL(ata_bmdma_setup);
+ EXPORT_SYMBOL_GPL(ata_bmdma_start);
+ EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
++EXPORT_SYMBOL_GPL(ata_bmdma_status);
++EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+ EXPORT_SYMBOL_GPL(ata_port_probe);
+ EXPORT_SYMBOL_GPL(sata_phy_reset);
+ EXPORT_SYMBOL_GPL(__sata_phy_reset);
+@@ -3857,7 +4024,6 @@
+ EXPORT_SYMBOL_GPL(ata_scsi_error);
+ EXPORT_SYMBOL_GPL(ata_scsi_detect);
+ EXPORT_SYMBOL_GPL(ata_add_to_probe_list);
+-EXPORT_SYMBOL_GPL(libata_msleep);
+ EXPORT_SYMBOL_GPL(ssleep);
+ EXPORT_SYMBOL_GPL(ata_scsi_release);
+ EXPORT_SYMBOL_GPL(ata_host_intr);
+@@ -3867,7 +4033,6 @@
+ #ifdef CONFIG_PCI
+ EXPORT_SYMBOL_GPL(pci_test_config_bits);
+-EXPORT_SYMBOL_GPL(ata_pci_init_legacy_mode);
+ EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+ EXPORT_SYMBOL_GPL(ata_pci_init_one);
+ EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+diff -Nur linux-2.4.29/drivers/scsi/libata.h linux-mips/drivers/scsi/libata.h
+--- linux-2.4.29/drivers/scsi/libata.h 2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/libata.h   2005-03-26 11:47:32.487319825 +0100
+@@ -37,6 +37,7 @@
+ /* libata-core.c */
+ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
+                                     struct ata_device *dev);
++extern void ata_qc_free(struct ata_queued_cmd *qc);
+ extern int ata_qc_issue(struct ata_queued_cmd *qc);
+ extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+ extern void ata_dev_select(struct ata_port *ap, unsigned int device,
+diff -Nur linux-2.4.29/drivers/scsi/libata-scsi.c linux-mips/drivers/scsi/libata-scsi.c
+--- linux-2.4.29/drivers/scsi/libata-scsi.c    2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/libata-scsi.c      2005-03-26 11:47:32.485320153 +0100
+@@ -203,7 +203,7 @@
+               {0x40,          MEDIUM_ERROR, 0x11, 0x04},      // Uncorrectable ECC error      Unrecovered read error
+               /* BBD - block marked bad */
+               {0x80,          MEDIUM_ERROR, 0x11, 0x04},      // Block marked bad               Medium error, unrecovered read error
+-              {0xFF, 0xFF, 0xFF, 0xFF}, // END mark 
++              {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+       };
+       static unsigned char stat_table[][4] = {
+               /* Must be first because BUSY means no other bits valid */
+@@ -211,22 +211,22 @@
+               {0x20,          HARDWARE_ERROR,  0x00, 0x00},   // Device fault
+               {0x08,          ABORTED_COMMAND, 0x47, 0x00},   // Timed out in xfer, fake parity for now
+               {0x04,          RECOVERED_ERROR, 0x11, 0x00},   // Recovered ECC error    Medium error, recovered
+-              {0xFF, 0xFF, 0xFF, 0xFF}, // END mark 
++              {0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+       };
+       int i = 0;
+       cmd->result = SAM_STAT_CHECK_CONDITION;
+-      
++
+       /*
+        *      Is this an error we can process/parse
+        */
+-       
++
+       if(drv_stat & ATA_ERR)
+               /* Read the err bits */
+               err = ata_chk_err(qc->ap);
+       /* Display the ATA level error info */
+-      
++
+       printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat);
+       if(drv_stat & 0x80)
+       {
+@@ -243,7 +243,7 @@
+               if(drv_stat & 0x01)     printk("Error ");
+       }
+       printk("}\n");
+-      
++
+       if(err)
+       {
+               printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err);
+@@ -260,11 +260,11 @@
+               if(err & 0x02)          printk("TrackZeroNotFound ");
+               if(err & 0x01)          printk("AddrMarkNotFound ");
+               printk("}\n");
+-              
++
+               /* Should we dump sector info here too ?? */
+       }
+-              
+-      
++
++
+       /* Look for err */
+       while(sense_table[i][0] != 0xFF)
+       {
+@@ -283,7 +283,8 @@
+       /* No immediate match */
+       if(err)
+               printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err);
+-      
++
++      i = 0;
+       /* Fall back to interpreting status bits */
+       while(stat_table[i][0] != 0xFF)
+       {
+@@ -301,7 +302,7 @@
+       /* No error ?? */
+       printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat);
+       /* additional-sense-code[-qualifier] */
+-      
++
+       sb[0] = 0x70;
+       sb[2] = MEDIUM_ERROR;
+       sb[7] = 0x0A;
+@@ -449,19 +450,24 @@
+       }
+       if (lba48) {
++              tf->command = ATA_CMD_VERIFY_EXT;
++
+               tf->hob_nsect = (n_sect >> 8) & 0xff;
+               tf->hob_lbah = (sect >> 40) & 0xff;
+               tf->hob_lbam = (sect >> 32) & 0xff;
+               tf->hob_lbal = (sect >> 24) & 0xff;
+-      } else
++      } else {
++              tf->command = ATA_CMD_VERIFY;
++
+               tf->device |= (sect >> 24) & 0xf;
++      }
+       tf->nsect = n_sect & 0xff;
+-      tf->hob_lbah = (sect >> 16) & 0xff;
+-      tf->hob_lbam = (sect >> 8) & 0xff;
+-      tf->hob_lbal = sect & 0xff;
++      tf->lbah = (sect >> 16) & 0xff;
++      tf->lbam = (sect >> 8) & 0xff;
++      tf->lbal = sect & 0xff;
+       return 0;
+ }
+@@ -561,7 +567,7 @@
+                               return 1;
+                       /* stores LBA27:24 in lower 4 bits of device reg */
+-                      tf->device |= scsicmd[2];
++                      tf->device |= scsicmd[6];
+                       qc->nsect = scsicmd[13];
+               }
+@@ -657,6 +663,7 @@
+       return;
+ err_out:
++      ata_qc_free(qc);
+       ata_bad_cdb(cmd, done);
+       DPRINTK("EXIT - badcmd\n");
+ }
+diff -Nur linux-2.4.29/drivers/scsi/Makefile linux-mips/drivers/scsi/Makefile
+--- linux-2.4.29/drivers/scsi/Makefile 2005-01-19 15:09:59.000000000 +0100
++++ linux-mips/drivers/scsi/Makefile   2005-03-26 11:47:32.445326717 +0100
+@@ -134,6 +134,7 @@
+ obj-$(CONFIG_SCSI_SATA_SVW)   += libata.o sata_svw.o
+ obj-$(CONFIG_SCSI_ATA_PIIX)   += libata.o ata_piix.o
+ obj-$(CONFIG_SCSI_SATA_PROMISE)       += libata.o sata_promise.o
++obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o
+ obj-$(CONFIG_SCSI_SATA_SIL)   += libata.o sata_sil.o
+ obj-$(CONFIG_SCSI_SATA_VIA)   += libata.o sata_via.o
+ obj-$(CONFIG_SCSI_SATA_VITESSE)       += libata.o sata_vsc.o
+diff -Nur linux-2.4.29/drivers/scsi/megaraid2.c linux-mips/drivers/scsi/megaraid2.c
+--- linux-2.4.29/drivers/scsi/megaraid2.c      2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/scsi/megaraid2.c        2005-03-26 11:47:33.007234495 +0100
+@@ -14,7 +14,7 @@
+  *      - speed-ups (list handling fixes, issued_list, optimizations.)
+  *      - lots of cleanups.
+  *
+- * Version : v2.10.3 (Apr 08, 2004)
++ * Version : v2.10.8.2 (July 26, 2004)
+  *
+  * Authors:   Atul Mukker <Atul.Mukker@lsil.com>
+  *            Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
+@@ -46,7 +46,7 @@
+ #include "megaraid2.h"
+-#ifdef LSI_CONFIG_COMPAT
++#if defined(__x86_64__)
+ #include <asm/ioctl32.h>
+ #endif
+@@ -90,10 +90,15 @@
+ static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
+ /*
++ * Lock to protect access to IOCTL
++ */
++static struct semaphore megaraid_ioc_mtx;
++
++/*
+  * The File Operations structure for the serial/ioctl interface of the driver
+  */
+ static struct file_operations megadev_fops = {
+-      .ioctl          = megadev_ioctl,
++      .ioctl          = megadev_ioctl_entry,
+       .open           = megadev_open,
+       .release        = megadev_close,
+       .owner          = THIS_MODULE,
+@@ -107,7 +112,7 @@
+ static struct mcontroller mcontroller[MAX_CONTROLLERS];
+ /* The current driver version */
+-static u32 driver_ver = 0x02100000;
++static u32 driver_ver = 0x02104000;
+ /* major number used by the device for character interface */
+ static int major;
+@@ -189,6 +194,11 @@
+                */
+               mega_reorder_hosts();
++              /*
++               * Initialize the IOCTL lock
++               */
++              init_MUTEX( &megaraid_ioc_mtx );
++
+ #ifdef CONFIG_PROC_FS
+               mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+@@ -223,7 +233,7 @@
+                               "MegaRAID Shutdown routine not registered!!\n");
+               }
+-#ifdef LSI_CONFIG_COMPAT
++#if defined(__x86_64__)
+               /*
+                * Register the 32-bit ioctl conversion
+                */
+@@ -273,6 +283,8 @@
+       unsigned long   tbase;
+       unsigned long   flag = 0;
+       int     i, j;
++      u8      did_int_pthru_f = 0;
++      u8      did_int_data_f  = 0;
+       while((pdev = pci_find_device(pci_vendor, pci_device, pdev))) {
+@@ -328,6 +340,7 @@
+                               (subsysvid != HP_SUBSYS_VID) &&
+                               (subsysvid != INTEL_SUBSYS_VID) &&
+                               (subsysvid != FSC_SUBSYS_VID) &&
++                              (subsysvid != ACER_SUBSYS_VID) &&
+                               (subsysvid != LSI_SUBSYS_VID) ) continue;
+@@ -465,6 +478,33 @@
+               alloc_scb_f = 1;
++              /*
++               * Allocate memory for ioctls
++               */
++              adapter->int_pthru = pci_alloc_consistent ( 
++                                      adapter->dev,
++                                      sizeof(mega_passthru),
++                                      &adapter->int_pthru_dma_hndl );
++
++              if( adapter->int_pthru == NULL ) {
++                      printk(KERN_WARNING "megaraid: out of RAM.\n");
++                      goto fail_attach;
++              }
++              else
++                      did_int_pthru_f = 1;
++
++              adapter->int_data = pci_alloc_consistent (
++                                      adapter->dev,
++                                      INT_MEMBLK_SZ,
++                                      &adapter->int_data_dma_hndl );
++
++              if( adapter->int_data == NULL ) {
++                      printk(KERN_WARNING "megaraid: out of RAM.\n");
++                      goto fail_attach;
++              }
++              else
++                      did_int_data_f = 1;
++
+               /* Request our IRQ */
+               if( adapter->flag & BOARD_MEMMAP ) {
+                       if(request_irq(irq, megaraid_isr_memmapped, SA_SHIRQ,
+@@ -676,6 +716,19 @@
+               continue;
+ fail_attach:
++              if( did_int_data_f ) {
++                      pci_free_consistent(
++                              adapter->dev, INT_MEMBLK_SZ, adapter->int_data, 
++                              adapter->int_data_dma_hndl );
++              }
++
++              if( did_int_pthru_f ) {
++                      pci_free_consistent(
++                              adapter->dev, sizeof(mega_passthru),
++                              (void*) adapter->int_pthru,
++                              adapter->int_pthru_dma_hndl );
++              }
++
+               if( did_setup_mbox_f ) {
+                       pci_free_consistent(adapter->dev, sizeof(mbox64_t),
+                                       (void *)adapter->una_mbox64,
+@@ -937,6 +990,78 @@
+ /**
++ * issue_scb()
++ * @adapter - pointer to our soft state
++ * @scb - scsi control block
++ *
++ * Post a command to the card if the mailbox is available, otherwise return
++ * busy. We also take the scb from the pending list if the mailbox is
++ * available.
++ */
++static inline int
++issue_scb(adapter_t *adapter, scb_t *scb)
++{
++      volatile mbox64_t       *mbox64 = adapter->mbox64;
++      volatile mbox_t         *mbox = adapter->mbox;
++      unsigned int    i = 0;
++
++      if(unlikely(mbox->busy)) {
++              do {
++                      udelay(1);
++                      i++;
++              } while( mbox->busy && (i < max_mbox_busy_wait) );
++
++              if(mbox->busy) return -1;
++      }
++
++      /* Copy mailbox data into host structure */
++      memcpy((char *)mbox, (char *)scb->raw_mbox, 16);
++
++      mbox->cmdid = scb->idx; /* Set cmdid */
++      mbox->busy = 1;         /* Set busy */
++
++
++      /*
++       * Increment the pending queue counter
++       */
++      atomic_inc(&adapter->pend_cmds);
++
++      switch (mbox->cmd) {
++      case MEGA_MBOXCMD_EXTPTHRU:
++              if( !adapter->has_64bit_addr ) break;
++              // else fall through
++      case MEGA_MBOXCMD_LREAD64:
++      case MEGA_MBOXCMD_LWRITE64:
++      case MEGA_MBOXCMD_PASSTHRU64:
++              mbox64->xfer_segment_lo = mbox->xferaddr;
++              mbox64->xfer_segment_hi = 0;
++              mbox->xferaddr = 0xFFFFFFFF;
++              break;
++      default:
++              mbox64->xfer_segment_lo = 0;
++              mbox64->xfer_segment_hi = 0;
++      }
++
++      /*
++       * post the command
++       */
++      scb->state |= SCB_ISSUED;
++
++      if( likely(adapter->flag & BOARD_MEMMAP) ) {
++              mbox->poll = 0;
++              mbox->ack = 0;
++              WRINDOOR(adapter, adapter->mbox_dma | 0x1);
++      }
++      else {
++              irq_enable(adapter);
++              issue_command(adapter);
++      }
++
++      return 0;
++}
++
++
++/**
+  * mega_runpendq()
+  * @adapter - pointer to our soft state
+  *
+@@ -949,52 +1074,26 @@
+               __mega_runpendq(adapter);
+ }
+-/*
+- * megaraid_queue()
+- * @scmd - Issue this scsi command
+- * @done - the callback hook into the scsi mid-layer
+- *
+- * The command queuing entry point for the mid-layer.
+- */
+-static int
+-megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
+-{
+-      adapter_t       *adapter;
+-      scb_t   *scb;
+-      int     busy=0;
+-
+-      adapter = (adapter_t *)scmd->host->hostdata;
+-
+-      scmd->scsi_done = done;
++static void
++__mega_runpendq(adapter_t *adapter)
++{
++      scb_t *scb;
++      struct list_head *pos, *next;
+-      /*
+-       * Allocate and build a SCB request
+-       * busy flag will be set if mega_build_cmd() command could not
+-       * allocate scb. We will return non-zero status in that case.
+-       * NOTE: scb can be null even though certain commands completed
+-       * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
+-       * return 0 in that case.
+-       */
++      /* Issue any pending commands to the card */
++      list_for_each_safe(pos, next, &adapter->pending_list) {
+-      scb = mega_build_cmd(adapter, scmd, &busy);
++              scb = list_entry(pos, scb_t, list);
+-      if(scb) {
+-              scb->state |= SCB_PENDQ;
+-              list_add_tail(&scb->list, &adapter->pending_list);
++              if( !(scb->state & SCB_ISSUED) ) {
+-              /*
+-               * Check if the HBA is in quiescent state, e.g., during a
+-               * delete logical drive opertion. If it is, don't run
+-               * the pending_list.
+-               */
+-              if(atomic_read(&adapter->quiescent) == 0) {
+-                      mega_runpendq(adapter);
++                      if( issue_scb(adapter, scb) != 0 )
++                              return;
+               }
+-              return 0;
+       }
+-      return busy;
++      return;
+ }
+@@ -1068,25 +1167,136 @@
+       }
+       /*
+-       * If "delete logical drive" feature is enabled on this controller.
+-       * Do only if at least one delete logical drive operation was done.
+-       *
+-       * Also, after logical drive deletion, instead of logical drive number,
++       * If "delete logical drive" feature is enabled on this controller,
+        * the value returned should be 0x80+logical drive id.
+-       *
+-       * These is valid only for IO commands.
+        */
++      if (adapter->support_random_del)
++              ldrv_num += 0x80;
+-      if (adapter->support_random_del && adapter->read_ldidmap )
+-              switch (cmd->cmnd[0]) {
+-              case READ_6:    /* fall through */
+-              case WRITE_6:   /* fall through */
+-              case READ_10:   /* fall through */
+-              case WRITE_10:
+-                      ldrv_num += 0x80;
++      return ldrv_num;
++}
++
++/*
++ * Wait until the controller's mailbox is available
++ */
++static inline int
++mega_busywait_mbox (adapter_t *adapter)
++{
++      if (adapter->mbox->busy)
++              return __mega_busywait_mbox(adapter);
++      return 0;
++}
++
++
++/**
++ * megaraid_iombox_ack_sequence - interrupt ack sequence for IO mapped HBAs
++ * @adapter   - controller's soft state
++ *
++ * Interrupt ackrowledgement sequence for IO mapped HBAs
++ */
++static inline void
++megaraid_iombox_ack_sequence(adapter_t *adapter)
++{
++      u8      status;
++      u8      nstatus;
++      u8      completed[MAX_FIRMWARE_STATUS];
++      u8      byte;
++      int     i;
++
++
++      /*
++       * loop till F/W has more commands for us to complete.
++       */
++      do {
++              /* Check if a valid interrupt is pending */
++              byte = irq_state(adapter);
++              if( (byte & VALID_INTR_BYTE) == 0 ) {
++                      return;
+               }
++              set_irq_state(adapter, byte);
+-      return ldrv_num;
++              while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
++                      cpu_relax();
++              }
++              adapter->mbox->numstatus = 0xFF;
++
++              for (i = 0; i < nstatus; i++) {
++                      while ((completed[i] = adapter->mbox->completed[i])
++                                      == 0xFF) {
++                              cpu_relax();
++                      }
++
++                      adapter->mbox->completed[i] = 0xFF;
++              }
++
++              // we must read the valid status now
++              if ((status = adapter->mbox->status) == 0xFF) {
++                      printk(KERN_WARNING
++                      "megaraid critical: status 0xFF from firmware.\n");
++              }
++              adapter->mbox->status = 0xFF;
++
++              /*
++               * decrement the pending queue counter
++               */
++              atomic_sub(nstatus, &adapter->pend_cmds);
++
++              /* Acknowledge interrupt */
++              irq_ack(adapter);
++
++              mega_cmd_done(adapter, completed, nstatus, status);
++
++      } while(1);
++}
++
++
++
++/*
++ * megaraid_queue()
++ * @scmd - Issue this scsi command
++ * @done - the callback hook into the scsi mid-layer
++ *
++ * The command queuing entry point for the mid-layer.
++ */
++static int
++megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
++{
++      adapter_t       *adapter;
++      scb_t   *scb;
++      int     busy=0;
++
++      adapter = (adapter_t *)scmd->host->hostdata;
++
++      scmd->scsi_done = done;
++
++
++      /*
++       * Allocate and build a SCB request
++       * busy flag will be set if mega_build_cmd() command could not
++       * allocate scb. We will return non-zero status in that case.
++       * NOTE: scb can be null even though certain commands completed
++       * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
++       * return 0 in that case.
++       */
++
++      scb = mega_build_cmd(adapter, scmd, &busy);
++
++      if(scb) {
++              scb->state |= SCB_PENDQ;
++              list_add_tail(&scb->list, &adapter->pending_list);
++
++              /*
++               * Check if the HBA is in quiescent state, e.g., during a
++               * delete logical drive opertion. If it is, don't run
++               * the pending_list.
++               */
++              if(atomic_read(&adapter->quiescent) == 0) {
++                      mega_runpendq(adapter);
++              }
++              return 0;
++      }
++
++      return busy;
+ }
+@@ -1112,7 +1322,6 @@
+       mbox_t  *mbox;
+       long    seg;
+       char    islogical;
+-      int     max_ldrv_num;
+       int     channel = 0;
+       int     target = 0;
+       int     ldrv_num = 0;   /* logical drive number */
+@@ -1184,24 +1393,6 @@
+               }
+               ldrv_num = mega_get_ldrv_num(adapter, cmd, channel);
+-
+-
+-              max_ldrv_num = (adapter->flag & BOARD_40LD) ?
+-                      MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD;
+-
+-              /*
+-               * max_ldrv_num increases by 0x80 if some logical drive was
+-               * deleted.
+-               */
+-              if(adapter->read_ldidmap)
+-                      max_ldrv_num += 0x80;
+-
+-              if(ldrv_num > max_ldrv_num ) {
+-                      cmd->result = (DID_BAD_TARGET << 16);
+-                      cmd->scsi_done(cmd);
+-                      return NULL;
+-              }
+-
+       }
+       else {
+               if( cmd->lun > 7) {
+@@ -1671,111 +1862,6 @@
+ }
+-static void
+-__mega_runpendq(adapter_t *adapter)
+-{
+-      scb_t *scb;
+-      struct list_head *pos, *next;
+-
+-      /* Issue any pending commands to the card */
+-      list_for_each_safe(pos, next, &adapter->pending_list) {
+-
+-              scb = list_entry(pos, scb_t, list);
+-
+-              if( !(scb->state & SCB_ISSUED) ) {
+-
+-                      if( issue_scb(adapter, scb) != 0 )
+-                              return;
+-              }
+-      }
+-
+-      return;
+-}
+-
+-
+-/**
+- * issue_scb()
+- * @adapter - pointer to our soft state
+- * @scb - scsi control block
+- *
+- * Post a command to the card if the mailbox is available, otherwise return
+- * busy. We also take the scb from the pending list if the mailbox is
+- * available.
+- */
+-static int
+-issue_scb(adapter_t *adapter, scb_t *scb)
+-{
+-      volatile mbox64_t       *mbox64 = adapter->mbox64;
+-      volatile mbox_t         *mbox = adapter->mbox;
+-      unsigned int    i = 0;
+-
+-      if(unlikely(mbox->busy)) {
+-              do {
+-                      udelay(1);
+-                      i++;
+-              } while( mbox->busy && (i < max_mbox_busy_wait) );
+-
+-              if(mbox->busy) return -1;
+-      }
+-
+-      /* Copy mailbox data into host structure */
+-      memcpy((char *)mbox, (char *)scb->raw_mbox, 16);
+-
+-      mbox->cmdid = scb->idx; /* Set cmdid */
+-      mbox->busy = 1;         /* Set busy */
+-
+-
+-      /*
+-       * Increment the pending queue counter
+-       */
+-      atomic_inc(&adapter->pend_cmds);
+-
+-      switch (mbox->cmd) {
+-      case MEGA_MBOXCMD_EXTPTHRU:
+-              if( !adapter->has_64bit_addr ) break;
+-              // else fall through
+-      case MEGA_MBOXCMD_LREAD64:
+-      case MEGA_MBOXCMD_LWRITE64:
+-      case MEGA_MBOXCMD_PASSTHRU64:
+-              mbox64->xfer_segment_lo = mbox->xferaddr;
+-              mbox64->xfer_segment_hi = 0;
+-              mbox->xferaddr = 0xFFFFFFFF;
+-              break;
+-      default:
+-              mbox64->xfer_segment_lo = 0;
+-              mbox64->xfer_segment_hi = 0;
+-      }
+-
+-      /*
+-       * post the command
+-       */
+-      scb->state |= SCB_ISSUED;
+-
+-      if( likely(adapter->flag & BOARD_MEMMAP) ) {
+-              mbox->poll = 0;
+-              mbox->ack = 0;
+-              WRINDOOR(adapter, adapter->mbox_dma | 0x1);
+-      }
+-      else {
+-              irq_enable(adapter);
+-              issue_command(adapter);
+-      }
+-
+-      return 0;
+-}
+-
+-
+-/*
+- * Wait until the controller's mailbox is available
+- */
+-static inline int
+-mega_busywait_mbox (adapter_t *adapter)
+-{
+-      if (adapter->mbox->busy)
+-              return __mega_busywait_mbox(adapter);
+-      return 0;
+-}
+-
+ /**
+  * issue_scb_block()
+  * @adapter - pointer to our soft state
+@@ -1865,77 +1951,47 @@
+       // invalidate the completed command id array. After command
+       // completion, firmware would write the valid id.
+       for (i = 0; i < MAX_FIRMWARE_STATUS; i++) {
+-              mbox->completed[i] = 0xFF;
+-      }
+-
+-      return status;
+-
+-bug_blocked_mailbox:
+-      printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n");
+-      udelay (1000);
+-      return -1;
+-}
+-
+-
+-/**
+- * megaraid_iombox_ack_sequence - interrupt ack sequence for IO mapped HBAs
+- * @adapter   - controller's soft state
+- *
+- * Interrupt ackrowledgement sequence for IO mapped HBAs
+- */
+-static inline void
+-megaraid_iombox_ack_sequence(adapter_t *adapter)
+-{
+-      u8      status;
+-      u8      nstatus;
+-      u8      completed[MAX_FIRMWARE_STATUS];
+-      u8      byte;
+-      int     i;
+-
+-
+-      /*
+-       * loop till F/W has more commands for us to complete.
+-       */
+-      do {
+-              /* Check if a valid interrupt is pending */
+-              byte = irq_state(adapter);
+-              if( (byte & VALID_INTR_BYTE) == 0 ) {
+-                      return;
+-              }
+-              set_irq_state(adapter, byte);
++              mbox->completed[i] = 0xFF;
++      }
+-              while ((nstatus = adapter->mbox->numstatus) == 0xFF) {
+-                      cpu_relax();
+-              }
+-              adapter->mbox->numstatus = 0xFF;
++      return status;
+-              for (i = 0; i < nstatus; i++) {
+-                      while ((completed[i] = adapter->mbox->completed[i])
+-                                      == 0xFF) {
+-                              cpu_relax();
+-                      }
++bug_blocked_mailbox:
++      printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n");
++      udelay (1000);
++      return -1;
++}
+-                      adapter->mbox->completed[i] = 0xFF;
+-              }
+-              // we must read the valid status now
+-              if ((status = adapter->mbox->status) == 0xFF) {
+-                      printk(KERN_WARNING
+-                      "megaraid critical: status 0xFF from firmware.\n");
+-              }
+-              adapter->mbox->status = 0xFF;
++/**
++ * megaraid_isr_iomapped()
++ * @irq - irq
++ * @devp - pointer to our soft state
++ * @regs - unused
++ *
++ * Interrupt service routine for io-mapped controllers.
++ * Find out if our device is interrupting. If yes, acknowledge the interrupt
++ * and service the completed commands.
++ */
++static void
++megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
++{
++      adapter_t       *adapter = devp;
++      unsigned long   flags;
+-              /*
+-               * decrement the pending queue counter
+-               */
+-              atomic_sub(nstatus, &adapter->pend_cmds);
+-              /* Acknowledge interrupt */
+-              irq_ack(adapter);
++      spin_lock_irqsave(adapter->host_lock, flags);
+-              mega_cmd_done(adapter, completed, nstatus, status);
++      megaraid_iombox_ack_sequence(adapter);
+-      } while(1);
++      /* Loop through any pending requests */
++      if( atomic_read(&adapter->quiescent ) == 0) {
++              mega_runpendq(adapter);
++      }
++
++      spin_unlock_irqrestore(adapter->host_lock, flags);
++
++      return;
+ }
+@@ -2007,38 +2063,6 @@
+ /**
+- * megaraid_isr_iomapped()
+- * @irq - irq
+- * @devp - pointer to our soft state
+- * @regs - unused
+- *
+- * Interrupt service routine for io-mapped controllers.
+- * Find out if our device is interrupting. If yes, acknowledge the interrupt
+- * and service the completed commands.
+- */
+-static void
+-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+-{
+-      adapter_t       *adapter = devp;
+-      unsigned long   flags;
+-
+-
+-      spin_lock_irqsave(adapter->host_lock, flags);
+-
+-      megaraid_iombox_ack_sequence(adapter);
+-
+-      /* Loop through any pending requests */
+-      if( atomic_read(&adapter->quiescent ) == 0) {
+-              mega_runpendq(adapter);
+-      }
+-
+-      spin_unlock_irqrestore(adapter->host_lock, flags);
+-
+-      return;
+-}
+-
+-
+-/**
+  * megaraid_isr_memmapped()
+  * @irq - irq
+  * @devp - pointer to our soft state
+@@ -2069,7 +2093,6 @@
+       return;
+ }
+-
+ /**
+  * mega_cmd_done()
+  * @adapter - pointer to our soft state
+@@ -2381,7 +2404,6 @@
+       list_add(&scb->list, &adapter->free_list);
+ }
+-
+ static int
+ __mega_busywait_mbox (adapter_t *adapter)
+ {
+@@ -2412,6 +2434,10 @@
+       cmd = scb->cmd;
++      /* return 0 elements if no data transfer */
++      if (!cmd->request_buffer || !cmd->request_bufflen)
++              return 0;
++
+       /* Scatter-gather not used */
+       if( !cmd->use_sg ) {
+@@ -2535,7 +2561,6 @@
+               enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i];
+ }
+-
+ static inline void
+ mega_free_sgl(adapter_t *adapter)
+ {
+@@ -2666,6 +2691,13 @@
+       pci_free_consistent(adapter->dev, sizeof(mbox64_t),
+                       (void *)adapter->una_mbox64, adapter->una_mbox64_dma);
++      pci_free_consistent( adapter->dev, sizeof(mega_passthru),
++                              (void*) adapter->int_pthru, 
++                              adapter->int_pthru_dma_hndl );
++
++      pci_free_consistent( adapter->dev, INT_MEMBLK_SZ, adapter->int_data,
++                              adapter->int_data_dma_hndl );
++
+       hba_count--;
+       if( hba_count == 0 ) {
+@@ -2694,7 +2726,7 @@
+        */
+       scsi_unregister(host);
+-#ifdef LSI_CONFIG_COMPAT
++#if defined(__x86_64__)
+       unregister_ioctl32_conversion(MEGAIOCCMD);
+ #endif
+@@ -2736,30 +2768,36 @@
+ }
+-/**
+- * megaraid_abort - abort the scsi command
+- * @scp       - command to be aborted
+- *
+- * Abort a previous SCSI request. Only commands on the pending list can be
+- * aborted. All the commands issued to the F/W must complete.
+- */
+ static int
+ megaraid_abort(Scsi_Cmnd *scp)
+ {
+       adapter_t               *adapter;
+       struct list_head        *pos, *next;
+       scb_t                   *scb;
+-      long                    iter;
+-      int                     rval = SUCCESS;
++
++      printk("megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
++              scp->serial_number, scp->cmnd[0], scp->channel,
++              scp->target, scp->lun);
+       adapter = (adapter_t *)scp->host->hostdata;
+-      ASSERT( spin_is_locked(adapter->host_lock) );
++      /*
++       * Check if hw_error flag was set in previous RESET call. If it was,
++       * then FW is hanging and unlikely to function. We can return FAILURE
++       * from here and expect the RESET handler to be called.
++       */
+-      printk("megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
+-              scp->serial_number, scp->cmnd[0], scp->channel, scp->target,
+-              scp->lun);
++      if (adapter->hw_error) {
++              printk("megaraid: hw error, cannot abort\n");
++              return FAILED;
++      }
++
++      ASSERT( spin_is_locked(adapter->host_lock) );
++      /*
++       * If cmd is waiting to be issued to FW, ABORT it with SUCEESS. If it
++       * has already been issued, return FAILURE and expect RESET later.
++       */
+       list_for_each_safe( pos, next, &adapter->pending_list ) {
+@@ -2769,15 +2807,11 @@
+                       scb->state |= SCB_ABORT;
+-                      /*
+-                       * Check if this command was never issued. If this is
+-                       * the case, take it off from the pending list and
+-                       * complete.
+-                       */
+                       if( !(scb->state & SCB_ISSUED) ) {
+-                              printk(KERN_WARNING
+-                              "megaraid: %ld:%d, driver owner.\n",
++                              /* Not issued to the FW yet; ABORT it */
++
++                              printk( "megaraid: %ld:%d, driver owner.\n",
+                                       scp->serial_number, scb->idx);
+                               scp->result = (DID_ABORT << 16);
+@@ -2786,67 +2820,31 @@
+                               scp->scsi_done(scp);
+-                              break;
++                              return SUCCESS;
++                      }
++                      else {
++                              /* Issued to the FW; can do nothing */
++                              return FAILED;
+                       }
+               }
+       }
+       /*
+-       * By this time, either all commands are completed or aborted by
+-       * mid-layer. Do not return until all the commands are actually
+-       * completed by the firmware
++       * cmd is _not_ in our pending_list. Most likely we completed the cmd
+        */
+-      iter = 0;
+-      while( atomic_read(&adapter->pend_cmds) > 0 ) {
+-              /*
+-               * Perform the ack sequence, since interrupts are not
+-               * available right now!
+-               */
+-              if( adapter->flag & BOARD_MEMMAP ) {
+-                      megaraid_memmbox_ack_sequence(adapter);
+-              }
+-              else {
+-                      megaraid_iombox_ack_sequence(adapter);
+-              }
+-
+-              /*
+-               * print a message once every second only
+-               */
+-              if( !(iter % 1000) ) {
+-                      printk(
+-                      "megaraid: Waiting for %d commands to flush: iter:%ld\n",
+-                              atomic_read(&adapter->pend_cmds), iter);
+-              }
+-
+-              if( iter++ < MBOX_ABORT_SLEEP*1000 ) {
+-                      mdelay(1);
+-              }
+-              else {
+-                      printk(KERN_WARNING
+-                              "megaraid: critical hardware error!\n");
+-
+-                      rval = FAILED;
+-
+-                      break;
+-              }
+-      }
+-
+-      if( rval == SUCCESS ) {
+-              printk(KERN_INFO
+-                      "megaraid: abort sequence successfully completed.\n");
+-      }
+-
+-      return rval;
++      return SUCCESS;
+ }
+ static int
+ megaraid_reset(Scsi_Cmnd *cmd)
+ {
+-      adapter_t       *adapter;
+-      megacmd_t       mc;
+-      long            iter;
+-      int             rval = SUCCESS;
++      DECLARE_WAIT_QUEUE_HEAD(wq);
++      int                     i;
++      scb_t                   *scb;
++      adapter_t               *adapter;
++      struct list_head        *pos, *next;
++      int                     rval;
+       adapter = (adapter_t *)cmd->host->hostdata;
+@@ -2856,31 +2854,54 @@
+               cmd->serial_number, cmd->cmnd[0], cmd->channel, cmd->target,
+               cmd->lun);
++      /*
++       * Check if hw_error flag was set in previous RESET call. If it was,
++       * then we needn't do any handling here. The controller will be marked
++       * offline soon
++       */
+-#if MEGA_HAVE_CLUSTERING
+-      mc.cmd = MEGA_CLUSTER_CMD;
+-      mc.opcode = MEGA_RESET_RESERVATIONS;
+-
+-      spin_unlock_irq(adapter->host_lock);
+-      if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+-              printk(KERN_WARNING
+-                              "megaraid: reservation reset failed.\n");
++      if (adapter->hw_error) {
++              printk("megaraid: hw error, cannot reset\n");
++              return FAILED;
+       }
+-      else {
+-              printk(KERN_INFO "megaraid: reservation reset.\n");
++
++      /*
++       * Return all the pending cmds to the mid-layer with the cmd result
++       * DID_RESET. Make sure you don't return the cmds ISSUED to FW.
++       */
++      list_for_each_safe( pos, next, &adapter->pending_list ) {
++
++              scb             = list_entry(pos, scb_t, list);
++              scb->state      |= SCB_RESET;
++
++              if( !(scb->state & SCB_ISSUED) ) {
++
++                      /* Not issued to the FW; return with RESET */
++                      cmd->result = (DID_RESET << 16);
++
++                      mega_free_scb(adapter, scb);
++                      cmd->scsi_done(cmd);
++              }
+       }
+-      spin_lock_irq(adapter->host_lock);
+-#endif
+       /*
+-       * Do not return until all the commands are actually completed by the
+-       * firmware
++       * Under exceptional conditions, FW may take up to 3 mins to complete
++       * processing all pending commands. We'll wait for maximum 3 mins to
++       * see if all outstanding commands are completed.
+        */
+-      iter = 0;
+-      while( atomic_read(&adapter->pend_cmds) > 0 ) {
++
++      if (atomic_read(&adapter->pend_cmds) == 0)
++              return SUCCESS;
++
++      printk("megaraid: %d pending cmds; max wait %d seconds\n",
++              atomic_read(&adapter->pend_cmds), MBOX_RESET_WAIT );
++
++      for(i=0; (i<MBOX_RESET_WAIT)&&(atomic_read(&adapter->pend_cmds)); i++){
++
++              ASSERT( spin_is_locked(adapter->host_lock) );
++
+               /*
+-               * Perform the ack sequence, since interrupts are not
+-               * available right now!
++               * Perform the ack sequence, since interrupts are unavailable
+                */
+               if( adapter->flag & BOARD_MEMMAP ) {
+                       megaraid_memmbox_ack_sequence(adapter);
+@@ -2889,55 +2910,35 @@
+                       megaraid_iombox_ack_sequence(adapter);
+               }
+-              /*
+-               * print a message once every second only
+-               */
+-              if( !(iter % 1000) ) {
+-                      printk(
+-                      "megaraid: Waiting for %d commands to flush: iter:%ld\n",
+-                              atomic_read(&adapter->pend_cmds), iter);
+-              }
++              spin_unlock(adapter->host_lock);
+-              if( iter++ < MBOX_RESET_SLEEP*1000 ) {
+-                      mdelay(1);
++              /* Print a message once every 5 seconds */
++              if (!(i % 5)) {
++                      printk("megaraid: pending %d; remaining %d seconds\n",
++                              atomic_read(&adapter->pend_cmds),
++                              MBOX_RESET_WAIT - i);
+               }
+-              else {
+-                      printk(KERN_WARNING
+-                              "megaraid: critical hardware error!\n");
+-                      rval = FAILED;
+-
+-                      break;
+-              }
+-      }
++              sleep_on_timeout(&wq, HZ);
+-      if( rval == SUCCESS ) {
+-              printk(KERN_INFO
+-                      "megaraid: reset sequence successfully completed.\n");
++              spin_lock(adapter->host_lock);
+       }
+-      return rval;
+-}
+-
++      /*
++       * If after 3 mins there are still outstanding cmds, set the hw_error
++       * flag so that we can return from subsequent ABORT/RESET handlers
++       * without any processing
++       */
+-/**
+- * mega_allocate_inquiry()
+- * @dma_handle - handle returned for dma address
+- * @pdev - handle to pci device
+- *
+- * allocates memory for inquiry structure
+- */
+-static inline caddr_t
+-mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev)
+-{
+-      return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle);
+-}
++      rval = SUCCESS;
++      if (atomic_read(&adapter->pend_cmds)) {
++              adapter->hw_error = 1;
++              printk("megaraid: critical hardware error!\n" );
++              rval = FAILED;
++      }
+-static inline void
+-mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
+-{
+-      pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle);
++      return rval;
+ }
+@@ -3199,6 +3200,26 @@
+       return len;
+ }
++/**
++ * mega_allocate_inquiry()
++ * @dma_handle - handle returned for dma address
++ * @pdev - handle to pci device
++ *
++ * allocates memory for inquiry structure
++ */
++static inline caddr_t
++mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev)
++{
++      return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle);
++}
++
++
++static inline void
++mega_free_inquiry(caddr_t inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
++{
++      pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle);
++}
++
+ /**
+  * proc_rebuild_rate()
+@@ -3988,6 +4009,7 @@
+ megaraid_reboot_notify (struct notifier_block *this, unsigned long code,
+               void *unused)
+ {
++      DECLARE_WAIT_QUEUE_HEAD(wq);
+       adapter_t *adapter;
+       struct Scsi_Host *host;
+       u8 raw_mbox[sizeof(mbox_t)];
+@@ -4040,10 +4062,10 @@
+       printk(KERN_INFO "megaraid: cache flush delay:   ");
+       for( i = 9; i >= 0; i-- ) {
+               printk("\b\b\b[%d]", i);
+-              mdelay(1000);
++              sleep_on_timeout(&wq, HZ);
+       }
+       printk("\b\b\b[done]\n");
+-      mdelay(1000);
++      sleep_on_timeout(&wq, HZ);
+       return NOTIFY_DONE;
+ }
+@@ -4150,17 +4172,27 @@
+ }
+-#ifdef LSI_CONFIG_COMPAT
++#if defined(__x86_64__)
+ static int
+ megadev_compat_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg,
+               struct file *filep)
+ {
+       struct inode *inode = filep->f_dentry->d_inode;
+-      return megadev_ioctl(inode, filep, cmd, arg);
++      return megadev_ioctl_entry(inode, filep, cmd, arg);
+ }
+ #endif
++static int
++megadev_ioctl_entry(struct inode *inode, struct file *filep, unsigned int cmd,
++              unsigned long arg)
++{
++      int rval;
++      down( &megaraid_ioc_mtx );
++      rval = megadev_ioctl( inode, filep, cmd, arg );
++      up( &megaraid_ioc_mtx );
++      return rval;
++}
+ /**
+  * megadev_ioctl()
+@@ -4184,9 +4216,8 @@
+       int             rval;
+       mega_passthru   *upthru;        /* user address for passthru */
+       mega_passthru   *pthru;         /* copy user passthru here */
+-      dma_addr_t      pthru_dma_hndl;
+       void            *data = NULL;   /* data to be transferred */
+-      dma_addr_t      data_dma_hndl;  /* dma handle for data xfer area */
++      dma_addr_t      data_dma_hndl = 0;
+       megacmd_t       mc;
+       megastat_t      *ustats;
+       int             num_ldrv;
+@@ -4302,7 +4333,7 @@
+               /*
+                * Which adapter
+                */
+-              if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
++              if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) 
+                       return (-ENODEV);
+               adapter = hba_soft_state[adapno];
+@@ -4358,13 +4389,7 @@
+               if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+                       /* Passthru commands */
+-                      pthru = pci_alloc_consistent(pdev,
+-                                      sizeof(mega_passthru),
+-                                      &pthru_dma_hndl);
+-
+-                      if( pthru == NULL ) {
+-                              return (-ENOMEM);
+-                      }
++                      pthru = adapter->int_pthru;
+                       /*
+                        * The user passthru structure
+@@ -4376,29 +4401,27 @@
+                        */
+                       if( copy_from_user(pthru, (char *)upthru,
+                                               sizeof(mega_passthru)) ) {
+-
+-                              pci_free_consistent(pdev,
+-                                              sizeof(mega_passthru), pthru,
+-                                              pthru_dma_hndl);
+-
+                               return (-EFAULT);
+                       }
+                       /*
+-                       * Is there a data transfer
++                       * Is there a data transfer; If the data transfer
++                       * length is <= INT_MEMBLK_SZ, usr the buffer 
++                       * allocated at the load time. Otherwise, allocate it 
++                       * here.
+                        */
+-                      if( pthru->dataxferlen ) {
+-                              data = pci_alloc_consistent(pdev,
+-                                              pthru->dataxferlen,
+-                                              &data_dma_hndl);
+-
+-                              if( data == NULL ) {
+-                                      pci_free_consistent(pdev,
+-                                                      sizeof(mega_passthru),
+-                                                      pthru,
+-                                                      pthru_dma_hndl);
++                      if (pthru->dataxferlen) {
++                              if (pthru->dataxferlen > INT_MEMBLK_SZ) {
++                                      data = pci_alloc_consistent (
++                                                      pdev,
++                                                      pthru->dataxferlen,
++                                                      &data_dma_hndl );
+-                                      return (-ENOMEM);
++                                      if (data == NULL)
++                                              return (-ENOMEM);
++                              }
++                              else {
++                                      data = adapter->int_data;
+                               }
+                               /*
+@@ -4406,7 +4429,11 @@
+                                * address at just allocated memory
+                                */
+                               uxferaddr = pthru->dataxferaddr;
+-                              pthru->dataxferaddr = data_dma_hndl;
++                              if (data_dma_hndl)
++                                      pthru->dataxferaddr = data_dma_hndl;
++                              else
++                                      pthru->dataxferaddr = 
++                                              adapter->int_data_dma_hndl;
+                       }
+@@ -4421,14 +4448,14 @@
+                                               (char *)((ulong)uxferaddr),
+                                               pthru->dataxferlen) ) {
+                                       rval = (-EFAULT);
+-                                      goto freemem_and_return;
++                                      goto freedata_and_return;
+                               }
+                       }
+                       memset(&mc, 0, sizeof(megacmd_t));
+                       mc.cmd = MEGA_MBOXCMD_PASSTHRU;
+-                      mc.xferaddr = (u32)pthru_dma_hndl;
++                      mc.xferaddr = (u32)adapter->int_pthru_dma_hndl;
+                       /*
+                        * Issue the command
+@@ -4437,7 +4464,7 @@
+                       rval = mega_n_to_m((void *)arg, &mc);
+-                      if( rval ) goto freemem_and_return;
++                      if( rval ) goto freedata_and_return;
+                       /*
+@@ -4456,18 +4483,14 @@
+                        */
+                       copy_to_user(upthru->reqsensearea,
+                                       pthru->reqsensearea, 14);
+-
+-freemem_and_return:
+-                      if( pthru->dataxferlen ) {
+-                              pci_free_consistent(pdev,
+-                                              pthru->dataxferlen, data,
+-                                              data_dma_hndl);
++freedata_and_return:
++                      if (data_dma_hndl) {
++                              pci_free_consistent( pdev, pthru->dataxferlen,
++                                                      data, data_dma_hndl );
+                       }
+-                      pci_free_consistent(pdev, sizeof(mega_passthru),
+-                                      pthru, pthru_dma_hndl);
+-
+                       return rval;
++
+               }
+               else {
+                       /* DCMD commands */
+@@ -4476,13 +4499,18 @@
+                        * Is there a data transfer
+                        */
+                       if( uioc.xferlen ) {
+-                              data = pci_alloc_consistent(pdev,
+-                                              uioc.xferlen, &data_dma_hndl);
++                              if (uioc.xferlen > INT_MEMBLK_SZ) {
++                                      data = pci_alloc_consistent(
++                                                      pdev,
++                                                      uioc.xferlen,
++                                                      &data_dma_hndl );
+-                              if( data == NULL ) {
+-                                      return (-ENOMEM);
++                                      if (data == NULL)
++                                              return (-ENOMEM);
++                              }
++                              else {
++                                      data = adapter->int_data;
+                               }
+-
+                               uxferaddr = MBOX(uioc)->xferaddr;
+                       }
+@@ -4497,9 +4525,9 @@
+                                               (char *)((ulong)uxferaddr),
+                                               uioc.xferlen) ) {
+-                                      pci_free_consistent(pdev,
+-                                              uioc.xferlen, data,
+-                                              data_dma_hndl);
++                                      pci_free_consistent(
++                                              pdev, uioc.xferlen,
++                                              data, data_dma_hndl );
+                                       return (-EFAULT);
+                               }
+@@ -4507,7 +4535,10 @@
+                       memcpy(&mc, MBOX(uioc), sizeof(megacmd_t));
+-                      mc.xferaddr = (u32)data_dma_hndl;
++                      if (data_dma_hndl )
++                              mc.xferaddr = (u32)data_dma_hndl;
++                      else
++                              mc.xferaddr = (u32)(adapter->int_data_dma_hndl);
+                       /*
+                        * Issue the command
+@@ -4517,12 +4548,10 @@
+                       rval = mega_n_to_m((void *)arg, &mc);
+                       if( rval ) {
+-                              if( uioc.xferlen ) {
+-                                      pci_free_consistent(pdev,
+-                                                      uioc.xferlen, data,
+-                                                      data_dma_hndl);
++                              if (data_dma_hndl) {
++                                      pci_free_consistent( pdev, uioc.xferlen,
++                                                      data, data_dma_hndl );
+                               }
+-
+                               return rval;
+                       }
+@@ -4537,10 +4566,9 @@
+                               }
+                       }
+-                      if( uioc.xferlen ) {
+-                              pci_free_consistent(pdev,
+-                                              uioc.xferlen, data,
+-                                              data_dma_hndl);
++                      if (data_dma_hndl) {
++                              pci_free_consistent( pdev, uioc.xferlen,
++                                                      data, data_dma_hndl );
+                       }
+                       return rval;
+@@ -4725,19 +4753,22 @@
+       else {
+               uioc_mimd = (struct uioctl_t *)arg;
+-              if( put_user(mc->status, (u8 *)&uioc_mimd->mbox[17]) )
++              if( put_user(mc->status, (u8 *)&uioc_mimd->mbox[17]) ) {
+                       return (-EFAULT);
++              }
+               if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
+                       umc = (megacmd_t *)uioc_mimd->mbox;
+-                      if (copy_from_user(&kmc, umc, sizeof(megacmd_t)))
++                      if (copy_from_user(&kmc, umc, sizeof(megacmd_t))) {
+                               return -EFAULT;
++                      }
+                       upthru = (mega_passthru *)((ulong)kmc.xferaddr);
+-                      if( put_user(mc->status, (u8 *)&upthru->scsistatus) )
++                      if( put_user(mc->status, (u8 *)&upthru->scsistatus) ){
+                               return (-EFAULT);
++                      }
+               }
+       }
+@@ -5148,7 +5179,6 @@
+ }
+-
+ /**
+  * mega_reorder_hosts()
+  *
+@@ -5363,6 +5393,7 @@
+ }
++
+ /** mega_internal_dev_inquiry()
+  * @adapter - pointer to our soft state
+  * @ch - channel for this device
+diff -Nur linux-2.4.29/drivers/scsi/megaraid2.h linux-mips/drivers/scsi/megaraid2.h
+--- linux-2.4.29/drivers/scsi/megaraid2.h      2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/scsi/megaraid2.h        2005-03-26 11:47:33.143212178 +0100
+@@ -6,7 +6,7 @@
+ #define MEGARAID_VERSION      \
+-      "v2.10.3 (Release Date: Thu Apr  8 16:16:05 EDT 2004)\n"
++      "v2.10.8.2 (Release Date: Mon Jul 26 12:15:51 EDT 2004)\n"
+ /*
+  * Driver features - change the values to enable or disable features in the
+@@ -82,6 +82,7 @@
+ #define LSI_SUBSYS_VID                        0x1000
+ #define INTEL_SUBSYS_VID              0x8086
+ #define FSC_SUBSYS_VID                        0x1734
++#define ACER_SUBSYS_VID                       0x1025
+ #define HBA_SIGNATURE                 0x3344
+ #define HBA_SIGNATURE_471             0xCCCC
+@@ -978,6 +979,15 @@
+                                                cmds */
+       int     has_cluster;    /* cluster support on this HBA */
++
++#define INT_MEMBLK_SZ         (28*1024)
++      mega_passthru           *int_pthru;             /*internal pthru*/
++      dma_addr_t              int_pthru_dma_hndl;
++      caddr_t                 int_data;               /*internal data*/
++      dma_addr_t              int_data_dma_hndl;
++
++      int                     hw_error;
++
+ }adapter_t;
+@@ -1085,18 +1095,21 @@
+ #define MBOX_ABORT_SLEEP      60
+ #define MBOX_RESET_SLEEP      30
++#define MBOX_RESET_WAIT               180
+ const char *megaraid_info (struct Scsi_Host *);
+ static int megaraid_detect(Scsi_Host_Template *);
+ static void mega_find_card(Scsi_Host_Template *, u16, u16);
+ static int mega_query_adapter(adapter_t *);
+-static int issue_scb(adapter_t *, scb_t *);
++static inline int issue_scb(adapter_t *, scb_t *);
+ static int mega_setup_mailbox(adapter_t *);
+ static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+ static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
++static inline scb_t *mega_allocate_scb(adapter_t *, Scsi_Cmnd *);
+ static void __mega_runpendq(adapter_t *);
++static inline void mega_runpendq(adapter_t *);
+ static int issue_scb_block(adapter_t *, u_char *);
+ static void megaraid_isr_memmapped(int, void *, struct pt_regs *);
+@@ -1113,6 +1126,7 @@
+ static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
+                             u32 *buffer, u32 *length);
++static inline int mega_busywait_mbox (adapter_t *);
+ static int __mega_busywait_mbox (adapter_t *);
+ static void mega_cmd_done(adapter_t *, u8 [], int, int);
+ static inline void mega_free_sgl (adapter_t *adapter);
+@@ -1123,15 +1137,13 @@
+                                  unsigned long, void *);
+ static int megadev_open (struct inode *, struct file *);
+-#if defined(CONFIG_COMPAT) || defined( __x86_64__) || defined(IA32_EMULATION)
+-#define LSI_CONFIG_COMPAT
+-#endif
+-
+-#ifdef LSI_CONFIG_COMPAT
++#if defined(__x86_64__)
+ static int megadev_compat_ioctl(unsigned int, unsigned int, unsigned long,
+       struct file *);
+ #endif
++static int megadev_ioctl_entry (struct inode *, struct file *, unsigned int,
++              unsigned long);
+ static int megadev_ioctl (struct inode *, struct file *, unsigned int,
+               unsigned long);
+ static int mega_m_to_n(void *, nitioctl_t *);
+@@ -1164,6 +1176,8 @@
+ static int mega_adapinq(adapter_t *, dma_addr_t);
+ static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
++static inline caddr_t mega_allocate_inquiry(dma_addr_t *, struct pci_dev *);
++static inline void mega_free_inquiry(caddr_t, dma_addr_t, struct pci_dev *);
+ static int mega_print_inquiry(char *, char *);
+ #endif
+@@ -1174,6 +1188,7 @@
+               scb_t *, Scsi_Cmnd *, int, int);
+ static void mega_enum_raid_scsi(adapter_t *);
+ static void mega_get_boot_drv(adapter_t *);
++static inline int mega_get_ldrv_num(adapter_t *, Scsi_Cmnd *, int);
+ static int mega_support_random_del(adapter_t *);
+ static int mega_del_logdrv(adapter_t *, int);
+ static int mega_do_del_logdrv(adapter_t *, int);
+diff -Nur linux-2.4.29/drivers/scsi/NCR53C9x.h linux-mips/drivers/scsi/NCR53C9x.h
+--- linux-2.4.29/drivers/scsi/NCR53C9x.h       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/scsi/NCR53C9x.h 2003-12-15 19:19:51.000000000 +0100
+@@ -144,12 +144,7 @@
+ #ifndef MULTIPLE_PAD_SIZES
+-#ifdef CONFIG_CPU_HAS_WB
+-#include <asm/wbflush.h>
+-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+-#else
+-#define esp_write(__reg, __val) ((__reg) = (__val))
+-#endif
++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0)
+ #define esp_read(__reg) (__reg)
+ struct ESP_regs {
+diff -Nur linux-2.4.29/drivers/scsi/osst.c linux-mips/drivers/scsi/osst.c
+--- linux-2.4.29/drivers/scsi/osst.c   2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/drivers/scsi/osst.c     2005-03-26 11:47:33.149211193 +0100
+@@ -5505,7 +5505,6 @@
+       read:           osst_read,
+       write:          osst_write,
+       ioctl:          osst_ioctl,
+-      llseek:         no_llseek,
+       open:           os_scsi_tape_open,
+       flush:          os_scsi_tape_flush,
+       release:        os_scsi_tape_close,
+diff -Nur linux-2.4.29/drivers/scsi/sata_nv.c linux-mips/drivers/scsi/sata_nv.c
+--- linux-2.4.29/drivers/scsi/sata_nv.c        2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_nv.c  2005-03-26 11:47:33.156210045 +0100
+@@ -20,6 +20,10 @@
+  *  If you do not delete the provisions above, a recipient may use your
+  *  version of this file under either the OSL or the GPL.
+  *
++ *  0.06
++ *     - Added generic SATA support by using a pci_device_id that filters on
++ *       the IDE storage class code.
++ *
+  *  0.03
+  *     - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using
+  *       mmio_base, which is only set for the CK804/MCP04 case.
+@@ -44,7 +48,7 @@
+ #include <linux/libata.h>
+ #define DRV_NAME                      "sata_nv"
+-#define DRV_VERSION                   "0.5"
++#define DRV_VERSION                   "0.6"
+ #define NV_PORTS                      2
+ #define NV_PIO_MASK                   0x1f
+@@ -95,7 +99,8 @@
+ #define NV_MCP_SATA_CFG_20_SATA_SPACE_EN      0x04
+ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+-irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
++static irqreturn_t nv_interrupt (int irq, void *dev_instance,
++                               struct pt_regs *regs);
+ static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+ static void nv_host_stop (struct ata_host_set *host_set);
+@@ -108,6 +113,7 @@
+ enum nv_host_type
+ {
++      GENERIC,
+       NFORCE2,
+       NFORCE3,
+       CK804
+@@ -128,6 +134,9 @@
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+               PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
++      { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
++              PCI_ANY_ID, PCI_ANY_ID,
++              PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
+       { 0, } /* terminate list */
+ };
+@@ -136,7 +145,6 @@
+ struct nv_host_desc
+ {
+       enum nv_host_type       host_type;
+-      unsigned long           host_flags;
+       void                    (*enable_hotplug)(struct ata_probe_ent *probe_ent);
+       void                    (*disable_hotplug)(struct ata_host_set *host_set);
+       void                    (*check_hotplug)(struct ata_host_set *host_set);
+@@ -144,21 +152,24 @@
+ };
+ static struct nv_host_desc nv_device_tbl[] = {
+       {
++              .host_type      = GENERIC,
++              .enable_hotplug = NULL,
++              .disable_hotplug= NULL,
++              .check_hotplug  = NULL,
++      },
++      {
+               .host_type      = NFORCE2,
+-              .host_flags     = 0x00000000,
+               .enable_hotplug = nv_enable_hotplug,
+               .disable_hotplug= nv_disable_hotplug,
+               .check_hotplug  = nv_check_hotplug,
+       },
+       {
+               .host_type      = NFORCE3,
+-              .host_flags     = 0x00000000,
+               .enable_hotplug = nv_enable_hotplug,
+               .disable_hotplug= nv_disable_hotplug,
+               .check_hotplug  = nv_check_hotplug,
+       },
+       {       .host_type      = CK804,
+-              .host_flags     = NV_HOST_FLAGS_SCR_MMIO,
+               .enable_hotplug = nv_enable_hotplug_ck804,
+               .disable_hotplug= nv_disable_hotplug_ck804,
+               .check_hotplug  = nv_check_hotplug_ck804,
+@@ -168,6 +179,7 @@
+ struct nv_host
+ {
+       struct nv_host_desc     *host_desc;
++      unsigned long           host_flags;
+ };
+ static struct pci_driver nv_pci_driver = {
+@@ -207,6 +219,8 @@
+       .phy_reset              = sata_phy_reset,
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+@@ -245,7 +259,8 @@
+ MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+ MODULE_VERSION(DRV_VERSION);
+-irqreturn_t nv_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t nv_interrupt (int irq, void *dev_instance,
++                               struct pt_regs *regs)
+ {
+       struct ata_host_set *host_set = dev_instance;
+       struct nv_host *host = host_set->private_data;
+@@ -285,8 +300,8 @@
+       if (sc_reg > SCR_CONTROL)
+               return 0xffffffffU;
+-      if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+-              return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
++      if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
++              return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4));
+       else
+               return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ }
+@@ -299,8 +314,8 @@
+       if (sc_reg > SCR_CONTROL)
+               return;
+-      if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+-              writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
++      if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
++              writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4));
+       else
+               outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ }
+@@ -322,7 +337,16 @@
+       struct nv_host *host;
+       struct ata_port_info *ppi;
+       struct ata_probe_ent *probe_ent;
++      int pci_dev_busy = 0;
+       int rc;
++      u32 bar;
++
++        // Make sure this is a SATA controller by counting the number of bars
++        // (NVIDIA SATA controllers will always have six bars).  Otherwise,
++        // it's an IDE controller and we ignore it.
++      for (bar=0; bar<6; bar++)
++              if (pci_resource_start(pdev, bar) == 0)
++                      return -ENODEV;
+       if (!printed_version++)
+               printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+@@ -332,8 +356,10 @@
+               goto err_out;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out_disable;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -350,11 +376,15 @@
+       if (!host)
+               goto err_out_free_ent;
++      memset(host, 0, sizeof(struct nv_host));
+       host->host_desc = &nv_device_tbl[ent->driver_data];
+       probe_ent->private_data = host;
+-      if (host->host_desc->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
++      if (pci_resource_flags(pdev, 5) & IORESOURCE_MEM)
++              host->host_flags |= NV_HOST_FLAGS_SCR_MMIO;
 +
-+      return events;
++      if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
+               unsigned long base;
+               probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
+@@ -395,7 +425,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out_disable:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+ err_out:
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_promise.c linux-mips/drivers/scsi/sata_promise.c
+--- linux-2.4.29/drivers/scsi/sata_promise.c   2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_promise.c     2005-03-26 11:47:33.159209552 +0100
+@@ -42,8 +42,6 @@
+ #define DRV_NAME      "sata_promise"
+ #define DRV_VERSION   "1.01"
+-#define msleep libata_msleep  /* 2.4-specific */
+-
+ enum {
+       PDC_PKT_SUBMIT          = 0x40, /* Command packet pointer addr */
+       PDC_INT_SEQMASK         = 0x40, /* Mask of asserted SEQ INTs */
+@@ -158,10 +156,18 @@
+         board_2037x },
+       { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_2037x },
++      { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_2037x },
++      { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_2037x },
++
+       { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20319 },
+       { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_20319 },
++      { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_20319 },
++
+       { }     /* terminate list */
+ };
+@@ -408,9 +414,11 @@
+               return IRQ_NONE;
+       }
+-        spin_lock(&host_set->lock);
++      spin_lock(&host_set->lock);
++
++      writel(mask, mmio_base + PDC_INT_SEQMASK);
+-        for (i = 0; i < host_set->n_ports; i++) {
++      for (i = 0; i < host_set->n_ports; i++) {
+               VPRINTK("port %u\n", i);
+               ap = host_set->ports[i];
+               tmp = mask & (1 << (i + 1));
+@@ -548,6 +556,7 @@
+       unsigned long base;
+       void *mmio_base;
+       unsigned int board_idx = (unsigned int) ent->driver_data;
++      int pci_dev_busy = 0;
+       int rc;
+       if (!printed_version++)
+@@ -562,8 +571,10 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -637,7 +648,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_qstor.c linux-mips/drivers/scsi/sata_qstor.c
+--- linux-2.4.29/drivers/scsi/sata_qstor.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/drivers/scsi/sata_qstor.c       2005-03-18 13:13:28.000000000 +0100
+@@ -0,0 +1,717 @@
++/*
++ *  sata_qstor.c - Pacific Digital Corporation QStor SATA
++ *
++ *  Maintained by:  Mark Lord <mlord@pobox.com>
++ *
++ *  Copyright 2005 Pacific Digital Corporation.
++ *  (OSL/GPL code release authorized by Jalil Fadavi).
++ *
++ *  The contents of this file are subject to the Open
++ *  Software License version 1.1 that can be found at
++ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
++ *  by reference.
++ *
++ *  Alternatively, the contents of this file may be used under the terms
++ *  of the GNU General Public License version 2 (the "GPL") as distributed
++ *  in the kernel source COPYING file, in which case the provisions of
++ *  the GPL are applicable instead of the above.  If you wish to allow
++ *  the use of your version of this file only under the terms of the
++ *  GPL and not to allow others to use your version of this file under
++ *  the OSL, indicate your decision by deleting the provisions above and
++ *  replace them with the notice and other provisions required by the GPL.
++ *  If you do not delete the provisions above, a recipient may use your
++ *  version of this file under either the OSL or the GPL.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include "scsi.h"
++#include <scsi/scsi_host.h>
++#include <asm/io.h>
++#include <linux/libata.h>
++
++#define DRV_NAME      "sata_qstor"
++#define DRV_VERSION   "0.04"
++
++enum {
++      QS_PORTS                = 4,
++      QS_MAX_PRD              = LIBATA_MAX_PRD,
++      QS_CPB_ORDER            = 6,
++      QS_CPB_BYTES            = (1 << QS_CPB_ORDER),
++      QS_PRD_BYTES            = QS_MAX_PRD * 16,
++      QS_PKT_BYTES            = QS_CPB_BYTES + QS_PRD_BYTES,
++
++      QS_DMA_BOUNDARY         = ~0UL,
++
++      /* global register offsets */
++      QS_HCF_CNFG3            = 0x0003, /* host configuration offset */
++      QS_HID_HPHY             = 0x0004, /* host physical interface info */
++      QS_HCT_CTRL             = 0x00e4, /* global interrupt mask offset */
++      QS_HST_SFF              = 0x0100, /* host status fifo offset */
++      QS_HVS_SERD3            = 0x0393, /* PHY enable offset */
++
++      /* global control bits */
++      QS_HPHY_64BIT           = (1 << 1), /* 64-bit bus detected */
++      QS_CNFG3_GSRST          = 0x01,     /* global chip reset */
++      QS_SERD3_PHY_ENA        = 0xf0,     /* PHY detection ENAble*/
++
++      /* per-channel register offsets */
++      QS_CCF_CPBA             = 0x0710, /* chan CPB base address */
++      QS_CCF_CSEP             = 0x0718, /* chan CPB separation factor */
++      QS_CFC_HUFT             = 0x0800, /* host upstream fifo threshold */
++      QS_CFC_HDFT             = 0x0804, /* host downstream fifo threshold */
++      QS_CFC_DUFT             = 0x0808, /* dev upstream fifo threshold */
++      QS_CFC_DDFT             = 0x080c, /* dev downstream fifo threshold */
++      QS_CCT_CTR0             = 0x0900, /* chan control-0 offset */
++      QS_CCT_CTR1             = 0x0901, /* chan control-1 offset */
++      QS_CCT_CFF              = 0x0a00, /* chan command fifo offset */
++
++      /* channel control bits */
++      QS_CTR0_REG             = (1 << 1),   /* register mode (vs. pkt mode) */
++      QS_CTR0_CLER            = (1 << 2),   /* clear channel errors */
++      QS_CTR1_RDEV            = (1 << 1),   /* sata phy/comms reset */
++      QS_CTR1_RCHN            = (1 << 4),   /* reset channel logic */
++      QS_CCF_RUN_PKT          = 0x107,      /* RUN a new dma PKT */
++
++      /* pkt sub-field headers */
++      QS_HCB_HDR              = 0x01,   /* Host Control Block header */
++      QS_DCB_HDR              = 0x02,   /* Device Control Block header */
++
++      /* pkt HCB flag bits */
++      QS_HF_DIRO              = (1 << 0),   /* data DIRection Out */
++      QS_HF_DAT               = (1 << 3),   /* DATa pkt */
++      QS_HF_IEN               = (1 << 4),   /* Interrupt ENable */
++      QS_HF_VLD               = (1 << 5),   /* VaLiD pkt */
++
++      /* pkt DCB flag bits */
++      QS_DF_PORD              = (1 << 2),   /* Pio OR Dma */
++      QS_DF_ELBA              = (1 << 3),   /* Extended LBA (lba48) */
++
++      /* PCI device IDs */
++      board_2068_idx          = 0,    /* QStor 4-port SATA/RAID */
++};
++
++typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
++
++struct qs_port_priv {
++      u8                      *pkt;
++      dma_addr_t              pkt_dma;
++      qs_state_t              state;
++};
++
++static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
++static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
++static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
++static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
++static int qs_port_start(struct ata_port *ap);
++static void qs_host_stop(struct ata_host_set *host_set);
++static void qs_port_stop(struct ata_port *ap);
++static void qs_phy_reset(struct ata_port *ap);
++static void qs_qc_prep(struct ata_queued_cmd *qc);
++static int qs_qc_issue(struct ata_queued_cmd *qc);
++static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
++static void qs_bmdma_stop(struct ata_port *ap);
++static u8 qs_bmdma_status(struct ata_port *ap);
++static void qs_irq_clear(struct ata_port *ap);
++static void qs_eng_timeout(struct ata_port *ap);
++
++static Scsi_Host_Template qs_ata_sht = {
++      .module                 = THIS_MODULE,
++      .name                   = DRV_NAME,
++      .detect                 = ata_scsi_detect,
++      .release                = ata_scsi_release,
++      .ioctl                  = ata_scsi_ioctl,
++      .queuecommand           = ata_scsi_queuecmd,
++      .eh_strategy_handler    = ata_scsi_error,
++      .can_queue              = ATA_DEF_QUEUE,
++      .this_id                = ATA_SHT_THIS_ID,
++      .sg_tablesize           = QS_MAX_PRD,
++      .max_sectors            = ATA_MAX_SECTORS,
++      .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
++      .use_new_eh_code        = ATA_SHT_NEW_EH_CODE,
++      .emulated               = ATA_SHT_EMULATED,
++      //FIXME .use_clustering         = ATA_SHT_USE_CLUSTERING,
++      .use_clustering         = ENABLE_CLUSTERING,
++      .proc_name              = DRV_NAME,
++      .bios_param             = ata_std_bios_param,
++};
++
++static struct ata_port_operations qs_ata_ops = {
++      .port_disable           = ata_port_disable,
++      .tf_load                = ata_tf_load,
++      .tf_read                = ata_tf_read,
++      .check_status           = ata_check_status,
++      .check_atapi_dma        = qs_check_atapi_dma,
++      .exec_command           = ata_exec_command,
++      .dev_select             = ata_std_dev_select,
++      .phy_reset              = qs_phy_reset,
++      .qc_prep                = qs_qc_prep,
++      .qc_issue               = qs_qc_issue,
++      .eng_timeout            = qs_eng_timeout,
++      .irq_handler            = qs_intr,
++      .irq_clear              = qs_irq_clear,
++      .scr_read               = qs_scr_read,
++      .scr_write              = qs_scr_write,
++      .port_start             = qs_port_start,
++      .port_stop              = qs_port_stop,
++      .host_stop              = qs_host_stop,
++      .bmdma_stop             = qs_bmdma_stop,
++      .bmdma_status           = qs_bmdma_status,
++};
++
++static struct ata_port_info qs_port_info[] = {
++      /* board_2068_idx */
++      {
++              .sht            = &qs_ata_sht,
++              .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
++                                ATA_FLAG_SATA_RESET |
++                                //FIXME ATA_FLAG_SRST |
++                                ATA_FLAG_MMIO,
++              .pio_mask       = 0x10, /* pio4 */
++              .udma_mask      = 0x7f, /* udma0-6 */
++              .port_ops       = &qs_ata_ops,
++      },
++};
++
++static struct pci_device_id qs_ata_pci_tbl[] = {
++      { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_2068_idx },
++
++      { }     /* terminate list */
++};
++
++static struct pci_driver qs_ata_pci_driver = {
++      .name                   = DRV_NAME,
++      .id_table               = qs_ata_pci_tbl,
++      .probe                  = qs_ata_init_one,
++      .remove                 = ata_pci_remove_one,
++};
++
++static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
++{
++      return 1;       /* ATAPI DMA not supported */
 +}
 +
-+static void pccard_status_change(int slot, vrc4171_socket_t *socket)
++static void qs_bmdma_stop(struct ata_port *ap)
 +{
-+      uint16_t events;
++      /* nothing */
++}
 +
-+      socket->tq_task.routine = pccard_bh;
-+      socket->tq_task.data = socket;
++static u8 qs_bmdma_status(struct ata_port *ap)
++{
++      return 0;
++}
 +
-+      events = get_events(slot);
-+      if (events) {
-+              spin_lock(&socket->event_lock);
-+              socket->events |= events;
-+              spin_unlock(&socket->event_lock);
-+              schedule_task(&socket->tq_task);
++static void qs_irq_clear(struct ata_port *ap)
++{
++      /* nothing */
++}
++
++static inline void qs_enter_reg_mode(struct ata_port *ap)
++{
++      u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
++
++      writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
++      readb(chan + QS_CCT_CTR0);        /* flush */
++}
++
++static inline void qs_reset_channel_logic(struct ata_port *ap)
++{
++      u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
++
++      writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
++      readb(chan + QS_CCT_CTR0);        /* flush */
++      qs_enter_reg_mode(ap);
++}
++
++static void qs_phy_reset(struct ata_port *ap)
++{
++      struct qs_port_priv *pp = ap->private_data;
++
++      pp->state = qs_state_idle;
++      qs_reset_channel_logic(ap);
++      sata_phy_reset(ap);
++}
++
++static void qs_eng_timeout(struct ata_port *ap)
++{
++      struct qs_port_priv *pp = ap->private_data;
++
++      if (pp->state != qs_state_idle) /* healthy paranoia */
++              pp->state = qs_state_mmio;
++      qs_reset_channel_logic(ap);
++      ata_eng_timeout(ap);
++}
++
++static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
++{
++      if (sc_reg > SCR_CONTROL)
++              return ~0U;
++      return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
++}
++
++static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
++{
++      if (sc_reg > SCR_CONTROL)
++              return;
++      writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
++}
++
++static void qs_fill_sg(struct ata_queued_cmd *qc)
++{
++      struct scatterlist *sg = qc->sg;
++      struct ata_port *ap = qc->ap;
++      struct qs_port_priv *pp = ap->private_data;
++      unsigned int nelem;
++      u8 *prd = pp->pkt + QS_CPB_BYTES;
++
++      assert(sg != NULL);
++      assert(qc->n_elem > 0);
++
++      for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) {
++              u64 addr;
++              u32 len;
++
++              addr = sg_dma_address(sg);
++              *(__le64 *)prd = cpu_to_le64(addr);
++              prd += sizeof(u64);
++
++              len = sg_dma_len(sg);
++              *(__le32 *)prd = cpu_to_le32(len);
++              prd += sizeof(u64);
++
++              VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
++                                      (unsigned long long)addr, len);
 +      }
 +}
 +
-+static void pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++static void qs_qc_prep(struct ata_queued_cmd *qc)
 +{
-+      vrc4171_socket_t *socket;
-+      uint16_t status;
++      struct qs_port_priv *pp = qc->ap->private_data;
++      u8 dflags = QS_DF_PORD, *buf = pp->pkt;
++      u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
++      u64 addr;
 +
-+      status = vrc4171_get_irq_status();
-+      if (status & IRQ_A) {
-+              socket = &vrc4171_sockets[CARD_SLOTA];
-+              if (socket->noprobe == SLOTB_PROBE) {
-+                      if (status & (1 << socket->csc_irq))
-+                              pccard_status_change(CARD_SLOTA, socket);
-+              }
++      VPRINTK("ENTER\n");
++
++      qs_enter_reg_mode(qc->ap);
++      if (qc->tf.protocol != ATA_PROT_DMA) {
++              ata_qc_prep(qc);
++              return;
 +      }
 +
-+      if (status & IRQ_B) {
-+              socket = &vrc4171_sockets[CARD_SLOTB];
-+              if (socket->noprobe == SLOTB_PROBE) {
-+                      if (status & (1 << socket->csc_irq))
-+                              pccard_status_change(CARD_SLOTB, socket);
++      qs_fill_sg(qc);
++
++      if ((qc->tf.flags & ATA_TFLAG_WRITE))
++              hflags |= QS_HF_DIRO;
++      if ((qc->tf.flags & ATA_TFLAG_LBA48))
++              dflags |= QS_DF_ELBA;
++
++      /* host control block (HCB) */
++      buf[ 0] = QS_HCB_HDR;
++      buf[ 1] = hflags;
++      *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
++      *(__le32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem);
++      addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
++      *(__le64 *)(&buf[16]) = cpu_to_le64(addr);
++
++      /* device control block (DCB) */
++      buf[24] = QS_DCB_HDR;
++      buf[28] = dflags;
++
++      /* frame information structure (FIS) */
++      ata_tf_to_fis(&qc->tf, &buf[32], 0);
++}
++
++static inline void qs_packet_start(struct ata_queued_cmd *qc)
++{
++      struct ata_port *ap = qc->ap;
++      u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
++
++      VPRINTK("ENTER, ap %p\n", ap);
++
++      writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
++      wmb();                             /* flush PRDs and pkt to memory */
++      writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
++      readl(chan + QS_CCT_CFF);          /* flush */
++}
++
++static int qs_qc_issue(struct ata_queued_cmd *qc)
++{
++      struct qs_port_priv *pp = qc->ap->private_data;
++
++      switch (qc->tf.protocol) {
++      case ATA_PROT_DMA:
++
++              pp->state = qs_state_pkt;
++              qs_packet_start(qc);
++              return 0;
++
++      case ATA_PROT_ATAPI_DMA:
++              BUG();
++              break;
++
++      default:
++              break;
++      }
++
++      pp->state = qs_state_mmio;
++      return ata_qc_issue_prot(qc);
++}
++
++static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
++{
++      unsigned int handled = 0;
++      u8 sFFE;
++      u8 __iomem *mmio_base = host_set->mmio_base;
++
++      do {
++              u32 sff0 = readl(mmio_base + QS_HST_SFF);
++              u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
++              u8 sEVLD = (sff1 >> 30) & 0x01; /* valid flag */
++              sFFE  = sff1 >> 31;             /* empty flag */
++
++              if (sEVLD) {
++                      u8 sDST = sff0 >> 16;   /* dev status */
++                      u8 sHST = sff1 & 0x3f;  /* host status */
++                      unsigned int port_no = (sff1 >> 8) & 0x03;
++                      struct ata_port *ap = host_set->ports[port_no];
++
++                      DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
++                                      sff1, sff0, port_no, sHST, sDST);
++                      handled = 1;
++                      if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
++                              struct ata_queued_cmd *qc;
++                              struct qs_port_priv *pp = ap->private_data;
++                              if (!pp || pp->state != qs_state_pkt)
++                                      continue;
++                              qc = ata_qc_from_tag(ap, ap->active_tag);
++                              if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
++                                      switch (sHST) {
++                                      case 0: /* sucessful CPB */
++                                      case 3: /* device error */
++                                              pp->state = qs_state_idle;
++                                              qs_enter_reg_mode(qc->ap);
++                                              ata_qc_complete(qc, sDST);
++                                              break;
++                                      default:
++                                              break;
++                                      }
++                              }
++                      }
++              }
++      } while (!sFFE);
++      return handled;
++}
++
++static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
++{
++      unsigned int handled = 0, port_no;
++
++      for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
++              struct ata_port *ap;
++              ap = host_set->ports[port_no];
++              if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
++                      struct ata_queued_cmd *qc;
++                      struct qs_port_priv *pp = ap->private_data;
++                      if (!pp || pp->state != qs_state_mmio)
++                              continue;
++                      qc = ata_qc_from_tag(ap, ap->active_tag);
++                      if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
++
++                              /* check main status, clearing INTRQ */
++                              u8 status = ata_chk_status(ap);
++                              if ((status & ATA_BUSY))
++                                      continue;
++                              DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
++                                      ap->id, qc->tf.protocol, status);
++              
++                              /* complete taskfile transaction */
++                              pp->state = qs_state_idle;
++                              ata_qc_complete(qc, status);
++                              handled = 1;
++                      }
 +              }
 +      }
++      return handled;
 +}
 +
-+static inline void reserve_using_irq(int slot)
++static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
 +{
-+      unsigned int irq;
++      struct ata_host_set *host_set = dev_instance;
++      unsigned int handled = 0;
 +
-+      irq = exca_read_byte(slot, I365_INTCTL);
-+      irq &= 0x0f;
-+      vrc4171_irq_mask &= ~(1 << irq);
++      VPRINTK("ENTER\n");
 +
-+      irq = exca_read_byte(slot, I365_CSCINT);
-+      irq = (irq & 0xf0) >> 4;
-+      vrc4171_irq_mask &= ~(1 << irq);
++      spin_lock(&host_set->lock);
++      handled  = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
++      spin_unlock(&host_set->lock);
++
++      VPRINTK("EXIT\n");
++
++      return IRQ_RETVAL(handled);
++}
++
++static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
++{
++      port->cmd_addr          =
++      port->data_addr         = base + 0x400;
++      port->error_addr        =
++      port->feature_addr      = base + 0x408; /* hob_feature = 0x409 */
++      port->nsect_addr        = base + 0x410; /* hob_nsect   = 0x411 */
++      port->lbal_addr         = base + 0x418; /* hob_lbal    = 0x419 */
++      port->lbam_addr         = base + 0x420; /* hob_lbam    = 0x421 */
++      port->lbah_addr         = base + 0x428; /* hob_lbah    = 0x429 */
++      port->device_addr       = base + 0x430;
++      port->status_addr       =
++      port->command_addr      = base + 0x438;
++      port->altstatus_addr    =
++      port->ctl_addr          = base + 0x440;
++      port->scr_addr          = base + 0xc00;
++}
++
++static int qs_port_start(struct ata_port *ap)
++{
++      struct device *dev = ap->host_set->dev;
++      struct qs_port_priv *pp;
++      void __iomem *mmio_base = ap->host_set->mmio_base;
++      void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
++      u64 addr;
++      int rc;
++
++      rc = ata_port_start(ap);
++      if (rc)
++              return rc;
++      qs_enter_reg_mode(ap);
++      pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
++      if (!pp) {
++              rc = -ENOMEM;
++              goto err_out;
++      }
++      pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
++                                                              GFP_KERNEL);
++      if (!pp->pkt) {
++              rc = -ENOMEM;
++              goto err_out_kfree;
++      }
++      memset(pp->pkt, 0, QS_PKT_BYTES);
++      ap->private_data = pp;
++
++      addr = (u64)pp->pkt_dma;
++      writel((u32) addr,        chan + QS_CCF_CPBA);
++      writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
++      return 0;
++
++err_out_kfree:
++      kfree(pp);
++err_out:
++      ata_port_stop(ap);
++      return rc;
++}
++
++static void qs_port_stop(struct ata_port *ap)
++{
++      struct device *dev = ap->host_set->dev;
++      struct qs_port_priv *pp = ap->private_data;
++
++      if (pp != NULL) {
++              ap->private_data = NULL;
++              if (pp->pkt != NULL)
++                      dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
++                                                              pp->pkt_dma);
++              kfree(pp);
++      }
++      ata_port_stop(ap);
++}
++
++static void qs_host_stop(struct ata_host_set *host_set)
++{
++      void __iomem *mmio_base = host_set->mmio_base;
++
++      writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
++      writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
++}
++
++static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
++{
++      void __iomem *mmio_base = pe->mmio_base;
++      unsigned int port_no;
++
++      writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
++      writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
++
++      /* reset each channel in turn */
++      for (port_no = 0; port_no < pe->n_ports; ++port_no) {
++              u8 __iomem *chan = mmio_base + (port_no * 0x4000);
++              writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
++              writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
++              readb(chan + QS_CCT_CTR0);        /* flush */
++      }
++      writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
++
++      for (port_no = 0; port_no < pe->n_ports; ++port_no) {
++              u8 __iomem *chan = mmio_base + (port_no * 0x4000);
++              /* set FIFO depths to same settings as Windows driver */
++              writew(32, chan + QS_CFC_HUFT);
++              writew(32, chan + QS_CFC_HDFT);
++              writew(10, chan + QS_CFC_DUFT);
++              writew( 8, chan + QS_CFC_DDFT);
++              /* set CPB size in bytes, as a power of two */
++              writeb(QS_CPB_ORDER,    chan + QS_CCF_CSEP);
++      }
++      writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
++}
++
++/*
++ * The QStor understands 64-bit buses, and uses 64-bit fields
++ * for DMA pointers regardless of bus width.  We just have to
++ * make sure our DMA masks are set appropriately for whatever
++ * bridge lies between us and the QStor, and then the DMA mapping
++ * code will ensure we only ever "see" appropriate buffer addresses.
++ * If we're 32-bit limited somewhere, then our 64-bit fields will
++ * just end up with zeros in the upper 32-bits, without any special
++ * logic required outside of this routine (below).
++ */
++static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
++{
++      u32 bus_info = readl(mmio_base + QS_HID_HPHY);
++      int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
++
++      if (have_64bit_bus &&
++          !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
++              /* do nothing */
++      } else {
++              rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
++              if (rc) {
++                      printk(KERN_ERR DRV_NAME
++                              "(%s): 32-bit DMA enable failed\n",
++                              pci_name(pdev));
++                      return rc;
++              }
++      }
++      return 0;
 +}
 +
-+static int __devinit vrc4171_add_socket(int slot)
++static int qs_ata_init_one(struct pci_dev *pdev,
++                              const struct pci_device_id *ent)
 +{
-+      vrc4171_socket_t *socket;
++      static int printed_version;
++      struct ata_probe_ent *probe_ent = NULL;
++      void __iomem *mmio_base;
++      unsigned int board_idx = (unsigned int) ent->driver_data;
++      int rc, port_no;
 +
-+      if (slot >= CARD_MAX_SLOTS)
-+              return -EINVAL;
++      if (!printed_version++)
++              printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
 +
-+      socket = &vrc4171_sockets[slot];
-+      if (socket->noprobe != SLOTB_PROBE) {
-+              uint8_t addrwin;
++      rc = pci_enable_device(pdev);
++      if (rc)
++              return rc;
 +
-+              switch (socket->noprobe) {
-+              case SLOTB_NOPROBE_MEM:
-+                      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+                      addrwin &= 0x1f;
-+                      exca_write_byte(slot, I365_ADDRWIN, addrwin);
-+                      break;
-+              case SLOTB_NOPROBE_IO:
-+                      addrwin = exca_read_byte(slot, I365_ADDRWIN);
-+                      addrwin &= 0xc0;
-+                      exca_write_byte(slot, I365_ADDRWIN, addrwin);
-+                      break;
-+              default:
-+                      break;
-+              }
++      rc = pci_request_regions(pdev, DRV_NAME);
++      if (rc)
++              goto err_out;
 +
-+              reserve_using_irq(slot);
++      if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
++              rc = -ENODEV;
++              goto err_out_regions;
++      }
 +
-+              return 0;
++      mmio_base = ioremap(pci_resource_start(pdev, 4),
++                          pci_resource_len(pdev, 4));
++      if (mmio_base == NULL) {
++              rc = -ENOMEM;
++              goto err_out_regions;
 +      }
 +
-+      sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
++      rc = qs_set_dma_masks(pdev, mmio_base);
++      if (rc)
++              goto err_out_iounmap;
 +
-+      socket->pcmcia_socket = pcmcia_register_socket(slot, &vrc4171_pccard_operations, 1);
-+      if (socket->pcmcia_socket == NULL)
-+              return -ENOMEM;
++      probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++      if (probe_ent == NULL) {
++              rc = -ENOMEM;
++              goto err_out_iounmap;
++      }
 +
-+      exca_write_byte(slot, I365_ADDRWIN, 0);
++      memset(probe_ent, 0, sizeof(*probe_ent));
++      probe_ent->dev = pci_dev_to_dev(pdev);
++      INIT_LIST_HEAD(&probe_ent->node);
++
++      probe_ent->sht          = qs_port_info[board_idx].sht;
++      probe_ent->host_flags   = qs_port_info[board_idx].host_flags;
++      probe_ent->pio_mask     = qs_port_info[board_idx].pio_mask;
++      probe_ent->mwdma_mask   = qs_port_info[board_idx].mwdma_mask;
++      probe_ent->udma_mask    = qs_port_info[board_idx].udma_mask;
++      probe_ent->port_ops     = qs_port_info[board_idx].port_ops;
++
++      probe_ent->irq          = pdev->irq;
++      probe_ent->irq_flags    = SA_SHIRQ;
++      probe_ent->mmio_base    = mmio_base;
++      probe_ent->n_ports      = QS_PORTS;
++
++      for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
++              unsigned long chan = (unsigned long)mmio_base +
++                                                      (port_no * 0x4000);
++              qs_ata_setup_port(&probe_ent->port[port_no], chan);
++      }
 +
-+      exca_write_byte(slot, GLOBAL_CONTROL, 0);
++      pci_set_master(pdev);
 +
++      /* initialize adapter */
++      qs_host_init(board_idx, probe_ent);
++
++      ata_add_to_probe_list(probe_ent);
 +      return 0;
++
++err_out_iounmap:
++      iounmap(mmio_base);
++err_out_regions:
++      pci_release_regions(pdev);
++err_out:
++      pci_disable_device(pdev);
++      return rc;
 +}
 +
-+static void vrc4171_remove_socket(int slot)
++static int __init qs_ata_init(void)
 +{
-+      vrc4171_socket_t *socket;
-+
-+      if (slot >= CARD_MAX_SLOTS)
-+              return;
++      int rc;
 +
-+      socket = &vrc4171_sockets[slot];
++      rc = pci_module_init(&qs_ata_pci_driver);
++      if (rc)
++              return rc;
 +
-+      if (socket->pcmcia_socket != NULL) {
-+              pcmcia_unregister_socket(socket->pcmcia_socket);
-+              socket->pcmcia_socket = NULL;
++      rc = scsi_register_module(MODULE_SCSI_HA, &qs_ata_sht);
++      if (rc) {
++              rc = -ENODEV;
++              goto err_out;
 +      }
++
++      return 0;
++
++err_out:
++      pci_unregister_driver(&qs_ata_pci_driver);
++      return rc;
 +}
 +
-+static int __devinit vrc4171_card_setup(char *options)
++static void __exit qs_ata_exit(void)
 +{
-+      if (options == NULL || *options == '\0')
-+              return 0;
-+
-+      if (strncmp(options, "irq:", 4) == 0) {
-+              int irq;
-+              options += 4;
-+              irq = simple_strtoul(options, &options, 0);
-+              if (irq >= 0 && irq < NR_IRQS)
-+                      vrc4171_irq = irq;
++      scsi_unregister_module(MODULE_SCSI_HA, &qs_ata_sht);
++      pci_unregister_driver(&qs_ata_pci_driver);
++}
 +
-+              if (*options != ',')
-+                      return 0;
-+              options++;
++MODULE_AUTHOR("Mark Lord");
++MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
++MODULE_VERSION(DRV_VERSION);
++
++module_init(qs_ata_init);
++module_exit(qs_ata_exit);
+diff -Nur linux-2.4.29/drivers/scsi/sata_sil.c linux-mips/drivers/scsi/sata_sil.c
+--- linux-2.4.29/drivers/scsi/sata_sil.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_sil.c 2005-03-26 11:47:33.241196096 +0100
+@@ -71,12 +71,14 @@
+       { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
++      { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
++      { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+       { }     /* terminate list */
+ };
+ /* TODO firmware versions should be added - eric */
+-struct sil_drivelist {
++static const struct sil_drivelist {
+       const char * product;
+       unsigned int quirk;
+ } sil_blacklist [] = {
+@@ -84,10 +86,12 @@
+       { "ST330013AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST340017AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST360015AS",         SIL_QUIRK_MOD15WRITE },
++      { "ST380013AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST380023AS",         SIL_QUIRK_MOD15WRITE },
+       { "ST3120023AS",        SIL_QUIRK_MOD15WRITE },
+       { "ST3160023AS",        SIL_QUIRK_MOD15WRITE },
+       { "ST3120026AS",        SIL_QUIRK_MOD15WRITE },
++      { "ST3200822AS",        SIL_QUIRK_MOD15WRITE },
+       { "ST340014ASL",        SIL_QUIRK_MOD15WRITE },
+       { "ST360014ASL",        SIL_QUIRK_MOD15WRITE },
+       { "ST380011ASL",        SIL_QUIRK_MOD15WRITE },
+@@ -136,6 +140,8 @@
+       .post_set_mode          = sil_post_set_mode,
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+@@ -333,6 +339,7 @@
+       void *mmio_base;
+       int rc;
+       unsigned int i;
++      int pci_dev_busy = 0;
+       u32 tmp, irq_mask;
+       if (!printed_version++)
+@@ -347,8 +354,10 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -430,7 +439,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_sis.c linux-mips/drivers/scsi/sata_sis.c
+--- linux-2.4.29/drivers/scsi/sata_sis.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_sis.c 2005-03-26 11:47:33.244195604 +0100
+@@ -103,6 +103,8 @@
+       .phy_reset              = sata_phy_reset,
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+@@ -201,14 +203,17 @@
+       int rc;
+       u32 genctl;
+       struct ata_port_info *ppi;
++      int pci_dev_busy = 0;
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -255,7 +260,8 @@
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_svw.c linux-mips/drivers/scsi/sata_svw.c
+--- linux-2.4.29/drivers/scsi/sata_svw.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_svw.c 2005-03-26 11:47:33.246195276 +0100
+@@ -156,7 +156,7 @@
+  *    spin_lock_irqsave(host_set lock)
+  */
+-void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
++static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+ {
+       struct ata_port *ap = qc->ap;
+       unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+@@ -186,7 +186,7 @@
+  *    spin_lock_irqsave(host_set lock)
+  */
+-void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
++static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+ {
+       struct ata_port *ap = qc->ap;
+       void *mmio = (void *) ap->ioaddr.bmdma_addr;
+@@ -302,6 +302,8 @@
+       .phy_reset              = sata_phy_reset,
+       .bmdma_setup            = k2_bmdma_setup_mmio,
+       .bmdma_start            = k2_bmdma_start_mmio,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+@@ -339,6 +341,7 @@
+       struct ata_probe_ent *probe_ent = NULL;
+       unsigned long base;
+       void *mmio_base;
++      int pci_dev_busy = 0;
+       int rc;
+       if (!printed_version++)
+@@ -360,8 +363,10 @@
+       /* Request PCI regions */
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -429,7 +434,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_sx4.c linux-mips/drivers/scsi/sata_sx4.c
+--- linux-2.4.29/drivers/scsi/sata_sx4.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_sx4.c 2005-03-26 11:47:33.249194784 +0100
+@@ -1191,8 +1191,7 @@
+                       error = 0;
+                       break;     
+               }
+-              set_current_state(TASK_UNINTERRUPTIBLE);
+-              schedule_timeout((i * 100) * HZ / 1000 + 1);
++              msleep(i*100);
+       }
+       return error;
+ }
+@@ -1225,8 +1224,7 @@
+       readl(mmio + PDC_TIME_CONTROL);
+       /* Wait 3 seconds */
+-      set_current_state(TASK_UNINTERRUPTIBLE);
+-      schedule_timeout(3 * HZ);
++      msleep(3000);
+       /* 
+          When timer is enabled, counter is decreased every internal
+@@ -1369,6 +1367,7 @@
+       void *mmio_base, *dimm_mmio = NULL;
+       struct pdc_host_priv *hpriv = NULL;
+       unsigned int board_idx = (unsigned int) ent->driver_data;
++      int pci_dev_busy = 0;
+       int rc;
+       if (!printed_version++)
+@@ -1383,8 +1382,10 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
 +      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -1469,7 +1470,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_uli.c linux-mips/drivers/scsi/sata_uli.c
+--- linux-2.4.29/drivers/scsi/sata_uli.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_uli.c 2005-03-26 11:47:33.252194291 +0100
+@@ -98,6 +98,8 @@
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+@@ -186,14 +188,17 @@
+       struct ata_port_info *ppi;
+       int rc;
+       unsigned int board_idx = (unsigned int) ent->driver_data;
++      int pci_dev_busy = 0;
+       rc = pci_enable_device(pdev);
+       if (rc)
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+       rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+       if (rc)
+@@ -256,7 +261,8 @@
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sata_via.c linux-mips/drivers/scsi/sata_via.c
+--- linux-2.4.29/drivers/scsi/sata_via.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_via.c 2005-03-26 11:47:33.268191666 +0100
+@@ -24,6 +24,11 @@
+    If you do not delete the provisions above, a recipient may use your
+    version of this file under either the OSL or the GPL.
++   ----------------------------------------------------------------------
 +
-+      if (strncmp(options, "slota:", 6) == 0) {
-+              options += 6;
-+              if (*options != '\0') {
-+                      if (strncmp(options, "noprobe", 7) == 0) {
-+                              vrc4171_sockets[CARD_SLOTA].noprobe = 1;
-+                              options += 7;
-+                      }
++   To-do list:
++   * VT6421 PATA support
 +
-+                      if (*options != ',')
-+                              return 0;
-+                      options++;
-+              } else
-+                      return 0;
+  */
+ #include <linux/kernel.h>
+@@ -38,11 +43,14 @@
+ #include <asm/io.h>
+ #define DRV_NAME      "sata_via"
+-#define DRV_VERSION   "1.0"
++#define DRV_VERSION   "1.1"
+-enum {
+-      via_sata                = 0,
++enum board_ids_enum {
++      vt6420,
++      vt6421,
++};
++enum {
+       SATA_CHAN_ENAB          = 0x40, /* SATA channel enable */
+       SATA_INT_GATE           = 0x41, /* SATA interrupt gating */
+       SATA_NATIVE_MODE        = 0x42, /* Native mode enable */
+@@ -50,10 +58,8 @@
+       PORT0                   = (1 << 1),
+       PORT1                   = (1 << 0),
+-
+-      ENAB_ALL                = PORT0 | PORT1,
+-
+-      INT_GATE_ALL            = PORT0 | PORT1,
++      ALL_PORTS               = PORT0 | PORT1,
++      N_PORTS                 = 2,
+       NATIVE_MODE_ALL         = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+@@ -66,7 +72,8 @@
+ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+ static struct pci_device_id svia_pci_tbl[] = {
+-      { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata },
++      { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
++      { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+       { }     /* terminate list */
+ };
+@@ -111,6 +118,9 @@
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
 +
-+      }
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+@@ -159,18 +169,132 @@
+       8, 4, 8, 4, 16, 256
+ };
++static const unsigned int vt6421_bar_sizes[] = {
++      16, 16, 16, 16, 32, 128
++};
 +
-+      if (strncmp(options, "slotb:", 6) == 0) {
-+              options += 6;
-+              if (*options != '\0') {
-+                      if (strncmp(options, "pccard", 6) == 0) {
-+                              vrc4171_slotb = SLOTB_IS_PCCARD;
-+                              options += 6;
-+                      } else if (strncmp(options, "cf", 2) == 0) {
-+                              vrc4171_slotb = SLOTB_IS_CF;
-+                              options += 2;
-+                      } else if (strncmp(options, "flashrom", 8) == 0) {
-+                              vrc4171_slotb = SLOTB_IS_FLASHROM;
-+                              options += 8;
-+                      } else if (strncmp(options, "none", 4) == 0) {
-+                              vrc4171_slotb = SLOTB_IS_NONE;
-+                              options += 4;
-+                      }
+ static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+ {
+       return addr + (port * 128);
+ }
++static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
++{
++      return addr + (port * 64);
++}
 +
-+                      if (*options != ',')
-+                              return 0;
-+                      options++;
++static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
++                            struct pci_dev *pdev,
++                            unsigned int port)
++{
++      unsigned long reg_addr = pci_resource_start(pdev, port);
++      unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
++      unsigned long scr_addr;
 +
-+                      if ( strncmp(options, "memnoprobe", 10) == 0)
-+                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_MEM;
-+                      if ( strncmp(options, "ionoprobe", 9) == 0)
-+                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_IO;
-+                      if ( strncmp(options, "noprobe", 7) == 0)
-+                              vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_ALL;
-+              }
-+      }
++      probe_ent->port[port].cmd_addr = reg_addr;
++      probe_ent->port[port].altstatus_addr =
++      probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
++      probe_ent->port[port].bmdma_addr = bmdma_addr;
 +
-+      return 0;
-+}
++      scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
++      probe_ent->port[port].scr_addr = scr_addr;
 +
-+__setup("vrc4171_card=", vrc4171_card_setup);
++      ata_std_ports(&probe_ent->port[port]);
++}
 +
-+static int __devinit vrc4171_card_init(void)
++static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
 +{
-+      int retval, slot;
++      struct ata_probe_ent *probe_ent;
++      struct ata_port_info *ppi = &svia_port_info;
 +
-+      vrc4171_set_multifunction_pin(vrc4171_slotb);
++      probe_ent = ata_pci_init_native_mode(pdev, &ppi);
++      if (!probe_ent)
++              return NULL;
 +
-+      if (request_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE,
-+                             "NEC VRC4171 Card Controller") == NULL)
-+              return -EBUSY;
++      probe_ent->port[0].scr_addr =
++              svia_scr_addr(pci_resource_start(pdev, 5), 0);
++      probe_ent->port[1].scr_addr =
++              svia_scr_addr(pci_resource_start(pdev, 5), 1);
 +
-+      for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
-+              if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
-+                      break;
++      return probe_ent;
++}
 +
-+              retval = vrc4171_add_socket(slot);
-+              if (retval != 0)
-+                      return retval;
-+      }
++static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
++{
++      struct ata_probe_ent *probe_ent;
++      unsigned int i;
 +
-+      retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
-+                           "NEC VRC4171 Card Controller", vrc4171_sockets);
-+      if (retval < 0) {
-+              for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
-+                      vrc4171_remove_socket(slot);
++      probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
++      if (!probe_ent)
++              return NULL;
 +
-+              return retval;
-+      }
++      memset(probe_ent, 0, sizeof(*probe_ent));
++      probe_ent->dev = pci_dev_to_dev(pdev);
++      INIT_LIST_HEAD(&probe_ent->node);
 +
-+      printk(KERN_INFO "NEC VRC4171 Card Controller, connected to IRQ %d\n", vrc4171_irq);
++      probe_ent->sht          = &svia_sht;
++      probe_ent->host_flags   = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
++                                ATA_FLAG_NO_LEGACY;
++      probe_ent->port_ops     = &svia_sata_ops;
++      probe_ent->n_ports      = N_PORTS;
++      probe_ent->irq          = pdev->irq;
++      probe_ent->irq_flags    = SA_SHIRQ;
++      probe_ent->pio_mask     = 0x1f;
++      probe_ent->mwdma_mask   = 0x07;
++      probe_ent->udma_mask    = 0x7f;
 +
-+      return 0;
++      for (i = 0; i < N_PORTS; i++)
++              vt6421_init_addrs(probe_ent, pdev, i);
++
++      return probe_ent;
 +}
 +
-+static void __devexit vrc4171_card_exit(void)
++static void svia_configure(struct pci_dev *pdev)
 +{
-+      int slot;
++      u8 tmp8;
 +
-+      for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
-+              vrc4171_remove_socket(slot);
++      pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
++      printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
++             pci_name(pdev),
++             (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
 +
-+      release_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE);
++      /* make sure SATA channels are enabled */
++      pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
++      if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
++              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
++                     pci_name(pdev), (int) tmp8);
++              tmp8 |= ALL_PORTS;
++              pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
++      }
++
++      /* make sure interrupts for each channel sent to us */
++      pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
++      if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
++              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
++                     pci_name(pdev), (int) tmp8);
++              tmp8 |= ALL_PORTS;
++              pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
++      }
++
++      /* make sure native mode is enabled */
++      pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
++      if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
++              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
++                     pci_name(pdev), (int) tmp8);
++              tmp8 |= NATIVE_MODE_ALL;
++              pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
++      }
 +}
 +
-+module_init(vrc4171_card_init);
-+module_exit(vrc4171_card_exit);
-diff -Nur linux-2.4.29/drivers/scsi/NCR53C9x.h linux-mips/drivers/scsi/NCR53C9x.h
---- linux-2.4.29/drivers/scsi/NCR53C9x.h       2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/scsi/NCR53C9x.h 2003-12-15 19:19:51.000000000 +0100
-@@ -144,12 +144,7 @@
+ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+ {
+       static int printed_version;
+       unsigned int i;
+       int rc;
+-      struct ata_port_info *ppi;
+       struct ata_probe_ent *probe_ent;
++      int board_id = (int) ent->driver_data;
++      const int *bar_sizes;
++      int pci_dev_busy = 0;
+       u8 tmp8;
+       if (!printed_version++)
+@@ -181,20 +305,28 @@
+               return rc;
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
+-      pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+-      if (tmp8 & SATA_2DEV) {
+-              printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
+-                     pci_name(pdev), (int) tmp8);
+-              rc = -EIO;
+-              goto err_out_regions;
++      if (board_id == vt6420) {
++              pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
++              if (tmp8 & SATA_2DEV) {
++                      printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
++                      pci_name(pdev), (int) tmp8);
++                      rc = -EIO;
++                      goto err_out_regions;
++              }
++
++              bar_sizes = &svia_bar_sizes[0];
++      } else {
++              bar_sizes = &vt6421_bar_sizes[0];
+       }
+       for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+               if ((pci_resource_start(pdev, i) == 0) ||
+-                  (pci_resource_len(pdev, i) < svia_bar_sizes[i])) {
++                  (pci_resource_len(pdev, i) < bar_sizes[i])) {
+                       printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
+                              pci_name(pdev), i,
+                              pci_resource_start(pdev, i),
+@@ -207,8 +339,11 @@
+       if (rc)
+               goto err_out_regions;
+-      ppi = &svia_port_info;
+-      probe_ent = ata_pci_init_native_mode(pdev, &ppi);
++      if (board_id == vt6420)
++              probe_ent = vt6420_init_probe_ent(pdev);
++      else
++              probe_ent = vt6421_init_probe_ent(pdev);
++      
+       if (!probe_ent) {
+               printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+                      pci_name(pdev));
+@@ -216,42 +351,7 @@
+               goto err_out_regions;
+       }
+-      probe_ent->port[0].scr_addr =
+-              svia_scr_addr(pci_resource_start(pdev, 5), 0);
+-      probe_ent->port[1].scr_addr =
+-              svia_scr_addr(pci_resource_start(pdev, 5), 1);
+-
+-      pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+-      printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
+-             pci_name(pdev),
+-             (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+-
+-      /* make sure SATA channels are enabled */
+-      pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+-      if ((tmp8 & ENAB_ALL) != ENAB_ALL) {
+-              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
+-                     pci_name(pdev), (int) tmp8);
+-              tmp8 |= ENAB_ALL;
+-              pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+-      }
+-
+-      /* make sure interrupts for each channel sent to us */
+-      pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+-      if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) {
+-              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
+-                     pci_name(pdev), (int) tmp8);
+-              tmp8 |= INT_GATE_ALL;
+-              pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+-      }
+-
+-      /* make sure native mode is enabled */
+-      pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+-      if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+-              printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
+-                     pci_name(pdev), (int) tmp8);
+-              tmp8 |= NATIVE_MODE_ALL;
+-              pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+-      }
++      svia_configure(pdev);
+       pci_set_master(pdev);
+@@ -262,7 +362,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
  
- #ifndef MULTIPLE_PAD_SIZES
+diff -Nur linux-2.4.29/drivers/scsi/sata_vsc.c linux-mips/drivers/scsi/sata_vsc.c
+--- linux-2.4.29/drivers/scsi/sata_vsc.c       2005-01-19 15:10:03.000000000 +0100
++++ linux-mips/drivers/scsi/sata_vsc.c 2005-03-26 11:47:33.270191338 +0100
+@@ -155,7 +155,8 @@
+  *
+  * Read the interrupt register and process for the devices that have them pending.
+  */
+-irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
++static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
++                                     struct pt_regs *regs)
+ {
+       struct ata_host_set *host_set = dev_instance;
+       unsigned int i;
+@@ -218,6 +219,8 @@
+       .phy_reset              = sata_phy_reset,
+       .bmdma_setup            = ata_bmdma_setup,
+       .bmdma_start            = ata_bmdma_start,
++      .bmdma_stop             = ata_bmdma_stop,
++      .bmdma_status           = ata_bmdma_status,
+       .qc_prep                = ata_qc_prep,
+       .qc_issue               = ata_qc_issue_prot,
+       .eng_timeout            = ata_eng_timeout,
+@@ -256,6 +259,7 @@
+       static int printed_version;
+       struct ata_probe_ent *probe_ent = NULL;
+       unsigned long base;
++      int pci_dev_busy = 0;
+       void *mmio_base;
+       int rc;
+@@ -275,13 +279,15 @@
+       }
  
--#ifdef CONFIG_CPU_HAS_WB
--#include <asm/wbflush.h>
--#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
--#else
--#define esp_write(__reg, __val) ((__reg) = (__val))
--#endif
-+#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0)
- #define esp_read(__reg) (__reg)
+       rc = pci_request_regions(pdev, DRV_NAME);
+-      if (rc)
++      if (rc) {
++              pci_dev_busy = 1;
+               goto err_out;
++      }
  
- struct ESP_regs {
+       /*
+        * Use 32 bit DMA mask, because 64 bit address support is poor.
+        */
+-      rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
++      rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (rc)
+               goto err_out_regions;
+@@ -348,7 +354,8 @@
+ err_out_regions:
+       pci_release_regions(pdev);
+ err_out:
+-      pci_disable_device(pdev);
++      if (!pci_dev_busy)
++              pci_disable_device(pdev);
+       return rc;
+ }
+diff -Nur linux-2.4.29/drivers/scsi/sd.c linux-mips/drivers/scsi/sd.c
+--- linux-2.4.29/drivers/scsi/sd.c     2003-08-25 13:44:42.000000000 +0200
++++ linux-mips/drivers/scsi/sd.c       2005-03-26 11:47:33.274190681 +0100
+@@ -1220,7 +1220,7 @@
+                       goto cleanup_gendisks_part;
+               memset(sd_gendisks[i].part, 0, (SCSI_DISKS_PER_MAJOR << 4) * sizeof(struct hd_struct));
+               sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
+-              sd_gendisks[i].nr_real = 0;
++              sd_gendisks[i].nr_real = SCSI_DISKS_PER_MAJOR;
+               sd_gendisks[i].real_devices =
+                   (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
+       }
+@@ -1333,7 +1333,6 @@
+       rscsi_disks[i].device = SDp;
+       rscsi_disks[i].has_part_table = 0;
+       sd_template.nr_dev++;
+-      SD_GENDISK(i).nr_real++;
+         devnum = i % SCSI_DISKS_PER_MAJOR;
+         SD_GENDISK(i).de_arr[devnum] = SDp->de;
+         if (SDp->removable)
+@@ -1447,7 +1446,6 @@
+                       SDp->attached--;
+                       sd_template.dev_noticed--;
+                       sd_template.nr_dev--;
+-                      SD_GENDISK(i).nr_real--;
+                       return;
+               }
+       return;
+diff -Nur linux-2.4.29/drivers/scsi/st.c linux-mips/drivers/scsi/st.c
+--- linux-2.4.29/drivers/scsi/st.c     2005-01-19 15:10:04.000000000 +0100
++++ linux-mips/drivers/scsi/st.c       2005-03-26 11:47:33.279189861 +0100
+@@ -1641,7 +1641,7 @@
+                                                       if (STps->drv_block >= 0)
+                                                               STps->drv_block += 1;
+                                                       (STp->buffer)->buffer_bytes = 0;
+-                                                      return (-EIO);
++                                                      return (-ENOMEM);
+                                               }
+                                               (STp->buffer)->buffer_bytes = bytes - transfer;
+                                       } else {
+@@ -3778,7 +3778,6 @@
+       read:           st_read,
+       write:          st_write,
+       ioctl:          st_ioctl,
+-      llseek:         no_llseek,
+       open:           st_open,
+       flush:          st_flush,
+       release:        st_release,
+diff -Nur linux-2.4.29/drivers/scsi/sym53c8xx.c linux-mips/drivers/scsi/sym53c8xx.c
+--- linux-2.4.29/drivers/scsi/sym53c8xx.c      2004-04-14 15:05:32.000000000 +0200
++++ linux-mips/drivers/scsi/sym53c8xx.c        2005-03-26 11:47:34.823936333 +0100
+@@ -13182,7 +13182,7 @@
+       ** descriptors.
+       */
+       if (chip && (chip->features & FE_DAC)) {
+-              if (pci_set_dma_mask(pdev, (u64) 0xffffffffff))
++              if (pci_set_dma_mask(pdev, (u64) 0xffffffffffULL))
+                       chip->features &= ~FE_DAC_IN_USE;
+               else
+                       chip->features |= FE_DAC_IN_USE;
 diff -Nur linux-2.4.29/drivers/sound/au1550_i2s.c linux-mips/drivers/sound/au1550_i2s.c
 --- linux-2.4.29/drivers/sound/au1550_i2s.c    2005-01-19 15:10:04.000000000 +0100
-+++ linux-mips/drivers/sound/au1550_i2s.c      2005-02-12 04:07:11.000000000 +0100
++++ linux-mips/drivers/sound/au1550_i2s.c      2005-03-26 11:47:35.065896621 +0100
 @@ -41,6 +41,7 @@
   *  675 Mass Ave, Cambridge, MA 02139, USA.
   *
@@ -18974,192 +29469,873 @@ diff -Nur linux-2.4.29/drivers/tc/zs.c linux-mips/drivers/tc/zs.c
 -              write_zsreg(info->zs_channel, 0, ERR_RES);
  }
  
- /* This sets up the serial port we're using, and turns on
-@@ -2360,11 +2347,11 @@
-  * for /dev/ttyb which is determined in setup_arch() from the
-  * boot command line flags.
+ /* This sets up the serial port we're using, and turns on
+@@ -2360,11 +2347,11 @@
+  * for /dev/ttyb which is determined in setup_arch() from the
+  * boot command line flags.
+  */
+-struct zs_hook zs_kgdbhook = {
+-      init_channel : kgdbhook_init_channel,
+-      init_info    : kgdbhook_init_info,
+-      cflags       : B38400|CS8|CLOCAL,
+-      rx_char      : kgdbhook_rx_char,
++struct dec_serial_hook zs_kgdbhook = {
++      .init_channel   = kgdbhook_init_channel,
++      .init_info      = kgdbhook_init_info,
++      .rx_char        = kgdbhook_rx_char,
++      .cflags         = B38400 | CS8 | CLOCAL,
+ }
+ void __init zs_kgdb_hook(int tty_num)
+diff -Nur linux-2.4.29/drivers/tc/zs.h linux-mips/drivers/tc/zs.h
+--- linux-2.4.29/drivers/tc/zs.h       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/tc/zs.h 2004-07-01 15:28:54.000000000 +0200
+@@ -1,14 +1,18 @@
+ /*
+- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
++ * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
+  *
+  * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
++ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+  *
+  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
++ * Copyright (C) 2004  Maciej W. Rozycki
+  */
+ #ifndef _DECSERIAL_H
+ #define _DECSERIAL_H
++#include <asm/dec/serial.h>
++
+ #define NUM_ZSREGS    16
+ struct serial_struct {
+@@ -89,63 +93,50 @@
+       unsigned char curregs[NUM_ZSREGS];
+ };
+-struct dec_serial;
+-
+-struct zs_hook {
+-      int (*init_channel)(struct dec_serial* info);
+-      void (*init_info)(struct dec_serial* info);
+-      void (*rx_char)(unsigned char ch, unsigned char stat);
+-      int  (*poll_rx_char)(struct dec_serial* info);
+-      int  (*poll_tx_char)(struct dec_serial* info,
+-                           unsigned char ch);
+-      unsigned cflags;
+-};
+-
+ struct dec_serial {
+-      struct dec_serial *zs_next;     /* For IRQ servicing chain */
+-      struct dec_zschannel *zs_channel; /* Channel registers */
+-      struct dec_zschannel *zs_chan_a;        /* A side registers */
+-      unsigned char read_reg_zero;
+-
+-      char soft_carrier;  /* Use soft carrier on this channel */
+-      char break_abort;   /* Is serial console in, so process brk/abrt */
+-      struct zs_hook *hook;  /* Hook on this channel */
+-      char is_cons;       /* Is this our console. */
+-      unsigned char tx_active; /* character is being xmitted */
+-      unsigned char tx_stopped; /* output is suspended */
+-
+-      /* We need to know the current clock divisor
+-       * to read the bps rate the chip has currently
+-       * loaded.
++      struct dec_serial       *zs_next;       /* For IRQ servicing chain.  */
++      struct dec_zschannel    *zs_channel;    /* Channel registers.  */
++      struct dec_zschannel    *zs_chan_a;     /* A side registers.  */
++      unsigned char           read_reg_zero;
++
++      struct dec_serial_hook  *hook;          /* Hook on this channel.  */
++      int                     tty_break;      /* Set on BREAK condition.  */
++      int                     is_cons;        /* Is this our console.  */
++      int                     tx_active;      /* Char is being xmitted.  */
++      int                     tx_stopped;     /* Output is suspended.  */
++
++      /*
++       * We need to know the current clock divisor
++       * to read the bps rate the chip has currently loaded.
+        */
+-      unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+-      int zs_baud;
++      int                     clk_divisor;    /* May be 1, 16, 32, or 64.  */
++      int                     zs_baud;
+-      char change_needed;
++      char                    change_needed;
+       int                     magic;
+       int                     baud_base;
+       int                     port;
+       int                     irq;
+-      int                     flags;          /* defined in tty.h */
+-      int                     type;           /* UART type */
++      int                     flags;          /* Defined in tty.h.  */
++      int                     type;           /* UART type.  */
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     xmit_fifo_size;
+       int                     custom_divisor;
+-      int                     x_char; /* xon/xoff character */
++      int                     x_char;         /* XON/XOFF character.  */
+       int                     close_delay;
+       unsigned short          closing_wait;
+       unsigned short          closing_wait2;
+       unsigned long           event;
+       unsigned long           last_active;
+       int                     line;
+-      int                     count;      /* # of fd on device */
+-      int                     blocked_open; /* # of blocked opens */
+-      long                    session; /* Session of opening process */
+-      long                    pgrp; /* pgrp of opening process */
++      int                     count;          /* # of fds on device.  */
++      int                     blocked_open;   /* # of blocked opens.  */
++      long                    session;        /* Sess of opening process.  */
++      long                    pgrp;           /* Pgrp of opening process.  */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+diff -Nur linux-2.4.29/drivers/usb/devio.c linux-mips/drivers/usb/devio.c
+--- linux-2.4.29/drivers/usb/devio.c   2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/usb/devio.c     2005-03-26 11:47:35.208873156 +0100
+@@ -1132,6 +1132,8 @@
+                       /* ifno might usefully be passed ... */
+                        retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+                       /* size = min_t(int, size, retval)? */
++                      if (retval == -ENOIOCTLCMD)
++                              retval = -ENOTTY;
+                }
+       }
+@@ -1146,24 +1148,10 @@
+       return retval;
+ }
+-static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static int usbdev_ioctl_exclusive(struct dev_state *ps, struct inode *inode,
++                                unsigned int cmd, unsigned long arg)
+ {
+-      struct dev_state *ps = (struct dev_state *)file->private_data;
+-      int ret = -ENOIOCTLCMD;
+-
+-      if (!(file->f_mode & FMODE_WRITE))
+-              return -EPERM;
+-      down_read(&ps->devsem);
+-      if (!ps->dev) {
+-              up_read(&ps->devsem);
+-              return -ENODEV;
+-      }
+-
+-      /*
+-       * grab device's exclusive_access mutex to prevent its driver from
+-       * using this device while it is being accessed by us.
+-       */
+-      down(&ps->dev->exclusive_access);
++      int ret;
+       switch (cmd) {
+       case USBDEVFS_CONTROL:
+@@ -1194,14 +1182,6 @@
+                       inode->i_mtime = CURRENT_TIME;
+               break;
+-      case USBDEVFS_GETDRIVER:
+-              ret = proc_getdriver(ps, (void *)arg);
+-              break;
+-
+-      case USBDEVFS_CONNECTINFO:
+-              ret = proc_connectinfo(ps, (void *)arg);
+-              break;
+-
+       case USBDEVFS_SETINTERFACE:
+               ret = proc_setintf(ps, (void *)arg);
+               break;
+@@ -1220,6 +1200,53 @@
+               ret = proc_unlinkurb(ps, (void *)arg);
+               break;
++      case USBDEVFS_CLAIMINTERFACE:
++              ret = proc_claiminterface(ps, (void *)arg);
++              break;
++
++      case USBDEVFS_RELEASEINTERFACE:
++              ret = proc_releaseinterface(ps, (void *)arg);
++              break;
++
++      case USBDEVFS_IOCTL:
++              ret = proc_ioctl(ps, (void *) arg);
++              break;
++
++      default:
++              ret = -ENOTTY;
++      }
++      return ret;
++}
++
++static int usbdev_ioctl(struct inode *inode, struct file *file,
++                      unsigned int cmd, unsigned long arg)
++{
++      struct dev_state *ps = file->private_data;
++      int ret;
++
++      if (!(file->f_mode & FMODE_WRITE))
++              return -EPERM;
++      down_read(&ps->devsem);
++      if (!ps->dev) {
++              up_read(&ps->devsem);
++              return -ENODEV;
++      }
++
++      /*
++       * Some ioctls don't touch the device and can be called without
++       * grabbing its exclusive_access mutex; they are handled in this
++       * switch.  Other ioctls which need exclusive_access are handled in
++       * usbdev_ioctl_exclusive().
++       */
++      switch (cmd) {
++      case USBDEVFS_GETDRIVER:
++              ret = proc_getdriver(ps, (void *)arg);
++              break;
++
++      case USBDEVFS_CONNECTINFO:
++              ret = proc_connectinfo(ps, (void *)arg);
++              break;
++
+       case USBDEVFS_REAPURB:
+               ret = proc_reapurb(ps, (void *)arg);
+               break;
+@@ -1232,19 +1259,28 @@
+               ret = proc_disconnectsignal(ps, (void *)arg);
+               break;
++      case USBDEVFS_CONTROL:
++      case USBDEVFS_BULK:
++      case USBDEVFS_RESETEP:
++      case USBDEVFS_RESET:
++      case USBDEVFS_CLEAR_HALT:
++      case USBDEVFS_SETINTERFACE:
++      case USBDEVFS_SETCONFIGURATION:
++      case USBDEVFS_SUBMITURB:
++      case USBDEVFS_DISCARDURB:
+       case USBDEVFS_CLAIMINTERFACE:
+-              ret = proc_claiminterface(ps, (void *)arg);
+-              break;
+-
+       case USBDEVFS_RELEASEINTERFACE:
+-              ret = proc_releaseinterface(ps, (void *)arg);
+-              break;
+-
+       case USBDEVFS_IOCTL:
+-              ret = proc_ioctl(ps, (void *) arg);
++              ret = -ERESTARTSYS;
++              if (down_interruptible(&ps->dev->exclusive_access) == 0) {
++                      ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
++                      up(&ps->dev->exclusive_access);
++              }
+               break;
++
++      default:
++              ret = -ENOTTY;
+       }
+-      up(&ps->dev->exclusive_access);
+       up_read(&ps->devsem);
+       if (ret >= 0)
+               inode->i_atime = CURRENT_TIME;
+diff -Nur linux-2.4.29/drivers/usb/hid-core.c linux-mips/drivers/usb/hid-core.c
+--- linux-2.4.29/drivers/usb/hid-core.c        2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/usb/hid-core.c  2005-03-26 11:47:35.374845916 +0100
+@@ -1064,18 +1064,31 @@
+ static void hid_ctrl(struct urb *urb)
+ {
+       struct hid_device *hid = urb->context;
++      unsigned long flags;
+       if (urb->status)
+               warn("ctrl urb status %d received", urb->status);
++      spin_lock_irqsave(&hid->outlock, flags);
++
+       hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+-      if (hid->outhead != hid->outtail)
+-              hid_submit_out(hid);
++      if (hid->outhead != hid->outtail) {
++              if (hid_submit_out(hid)) {
++                      clear_bit(HID_OUT_RUNNING, &hid->iofl);
++              }
++              spin_unlock_irqrestore(&hid->outlock, flags);
++              return;
++      }
++
++      clear_bit(HID_OUT_RUNNING, &hid->iofl);
++      spin_unlock_irqrestore(&hid->outlock, flags);
+ }
+ void hid_write_report(struct hid_device *hid, struct hid_report *report)
+ {
++      unsigned long flags;
++
+       if (hid->report_enum[report->type].numbered) {
+               hid->out[hid->outhead].buffer[0] = report->id;
+               hid_output_report(report, hid->out[hid->outhead].buffer + 1);
+@@ -1087,13 +1100,18 @@
+       hid->out[hid->outhead].dr.wValue = cpu_to_le16(((report->type + 1) << 8) | report->id);
++      spin_lock_irqsave(&hid->outlock, flags);
++
+       hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+       if (hid->outhead == hid->outtail)
+               hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+-      if (hid->urbout.status != -EINPROGRESS)
+-              hid_submit_out(hid);
++      if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl))
++              if (hid_submit_out(hid))
++                      clear_bit(HID_OUT_RUNNING, &hid->iofl);
++
++      spin_unlock_irqrestore(&hid->outlock, flags);
+ }
+ int hid_open(struct hid_device *hid)
+@@ -1333,6 +1351,8 @@
+               return NULL;
+       }
++      spin_lock_init(&hid->outlock);
++
+       hid->version = hdesc->bcdHID;
+       hid->country = hdesc->bCountryCode;
+       hid->dev = dev;
+diff -Nur linux-2.4.29/drivers/usb/hiddev.c linux-mips/drivers/usb/hiddev.c
+--- linux-2.4.29/drivers/usb/hiddev.c  2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/drivers/usb/hiddev.c    2005-03-26 11:47:35.743785364 +0100
+@@ -328,6 +328,7 @@
+                               }
+                               
+                               schedule();
++                              set_current_state(TASK_INTERRUPTIBLE);
+                       }
+                       set_current_state(TASK_RUNNING);
+diff -Nur linux-2.4.29/drivers/usb/hid.h linux-mips/drivers/usb/hid.h
+--- linux-2.4.29/drivers/usb/hid.h     2003-08-25 13:44:42.000000000 +0200
++++ linux-mips/drivers/usb/hid.h       2005-03-26 11:47:35.742785528 +0100
+@@ -302,6 +302,8 @@
+ #define HID_CLAIMED_INPUT     1
+ #define HID_CLAIMED_HIDDEV    2
++#define HID_OUT_RUNNING               2
++
+ struct hid_input {
+       struct list_head list;
+       struct hid_report *report;
+@@ -322,12 +324,15 @@
+       struct usb_device *dev;                                         /* USB device */
+       int ifnum;                                                      /* USB interface number */
++      unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
++
+       struct urb urb;                                                 /* USB URB structure */
+       char buffer[HID_BUFFER_SIZE];                                   /* Rx buffer */
+       struct urb urbout;                                              /* Output URB */
+       struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE];             /* Transmit buffer */
+       unsigned char outhead, outtail;                                 /* Tx buffer head & tail */
++      spinlock_t outlock;                                             /* Output fifo spinlock */
+       unsigned claimed;                                               /* Claimed by hidinput, hiddev? */      
+       unsigned quirks;                                                /* Various quirks the device can pull on us */
+diff -Nur linux-2.4.29/drivers/usb/serial/ftdi_sio.c linux-mips/drivers/usb/serial/ftdi_sio.c
+--- linux-2.4.29/drivers/usb/serial/ftdi_sio.c 2005-01-19 15:10:07.000000000 +0100
++++ linux-mips/drivers/usb/serial/ftdi_sio.c   2005-03-26 11:47:35.754783559 +0100
+@@ -737,8 +737,6 @@
+ };
+-
+-
+ static struct usb_serial_device_type ftdi_userdev_device = {
+       .owner =                THIS_MODULE,
+       .name =                 "FTDI SIO compatible",
+@@ -1240,15 +1238,6 @@
+ } /* ftdi_HE_TIRA1_startup */
+-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect 
+- *   it is called when the usb device is disconnected
+- *
+- *   usbserial:usb_serial_disconnect
+- *      calls __serial_close for each open of the port
+- *      shutdown is called then (ie ftdi_shutdown)
+- */
+-
+-
+ /* Startup for the 8U232AM chip */
+ static int ftdi_userdev_startup (struct usb_serial *serial)
+ {
+@@ -1273,6 +1262,14 @@
+ }
++/* ftdi_shutdown is called from usbserial:usb_serial_disconnect 
++ *   it is called when the usb device is disconnected
++ *
++ *   usbserial:usb_serial_disconnect
++ *      calls __serial_close for each open of the port
++ *      shutdown is called then (ie ftdi_shutdown)
++ */
++
+ static void ftdi_shutdown (struct usb_serial *serial)
+ { /* ftdi_shutdown */
+       
+@@ -1382,6 +1379,7 @@
+       struct usb_serial *serial;
+       unsigned int c_cflag = port->tty->termios->c_cflag;
+       char buf[1];
++      int err;
+       dbg("%s", __FUNCTION__);
+@@ -1412,8 +1410,9 @@
+               /* shutdown our bulk read */
+               if (port->read_urb) {
+-                      if(usb_unlink_urb (port->read_urb)<0)
+-                              err("Error unlinking urb");
++                      err = usb_unlink_urb (port->read_urb);
++                      if (err < 0 && err != -ENODEV)
++                              err("Error unlinking urb (%d)", err);
+               }
+               /* unlink the running write urbs */
+diff -Nur linux-2.4.29/drivers/usb/serial/mct_u232.c linux-mips/drivers/usb/serial/mct_u232.c
+--- linux-2.4.29/drivers/usb/serial/mct_u232.c 2005-01-19 15:10:08.000000000 +0100
++++ linux-mips/drivers/usb/serial/mct_u232.c   2005-03-26 11:47:35.755783395 +0100
+@@ -86,26 +86,14 @@
+ #include "usb-serial.h"
+ #include "mct_u232.h"
+-
+ /*
+  * Version Information
   */
--struct zs_hook zs_kgdbhook = {
--      init_channel : kgdbhook_init_channel,
--      init_info    : kgdbhook_init_info,
--      cflags       : B38400|CS8|CLOCAL,
--      rx_char      : kgdbhook_rx_char,
-+struct dec_serial_hook zs_kgdbhook = {
-+      .init_channel   = kgdbhook_init_channel,
-+      .init_info      = kgdbhook_init_info,
-+      .rx_char        = kgdbhook_rx_char,
-+      .cflags         = B38400 | CS8 | CLOCAL,
- }
+-#define DRIVER_VERSION "v1.2"
++#define DRIVER_VERSION "z2.0"         /* Linux in-kernel version */
+ #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
+ #define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
  
- void __init zs_kgdb_hook(int tty_num)
-diff -Nur linux-2.4.29/drivers/tc/zs.h linux-mips/drivers/tc/zs.h
---- linux-2.4.29/drivers/tc/zs.h       2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/tc/zs.h 2004-07-01 15:28:54.000000000 +0200
-@@ -1,14 +1,18 @@
  /*
-- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
-+ * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
-  *
-  * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
-+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
-  *
-  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
-  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-+ * Copyright (C) 2004  Maciej W. Rozycki
+- * Some not properly written applications do not handle the return code of
+- * write() correctly. This can result in character losses. A work-a-round
+- * can be compiled in with the following definition. This work-a-round
+- * should _NOT_ be part of an 'official' kernel release, of course!
+- */
+-#undef FIX_WRITE_RETURN_CODE_PROBLEM
+-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+-static int write_blocking; /* disabled by default */
+-#endif
+-
+-/*
+  * Function prototypes
   */
- #ifndef _DECSERIAL_H
- #define _DECSERIAL_H
+ static int  mct_u232_startup           (struct usb_serial *serial);
+@@ -114,13 +102,6 @@
+                                         struct file *filp);
+ static void mct_u232_close             (struct usb_serial_port *port,
+                                         struct file *filp);
+-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+-static int  mct_u232_write             (struct usb_serial_port *port,
+-                                        int from_user,
+-                                        const unsigned char *buf,
+-                                        int count);
+-static void mct_u232_write_bulk_callback (struct urb *urb);
+-#endif
+ static void mct_u232_read_int_callback   (struct urb *urb);
+ static void mct_u232_set_termios         (struct usb_serial_port *port,
+                                         struct termios * old);
+@@ -147,7 +128,7 @@
+ static struct usb_serial_device_type mct_u232_device = {
+       .owner =             THIS_MODULE,
+-      .name =              "Magic Control Technology USB-RS232",
++      .name =              "MCT U232",
+       .id_table =          id_table_combined,
+       .num_interrupt_in =  2,
+       .num_bulk_in =       0,
+@@ -155,10 +136,6 @@
+       .num_ports =         1,
+       .open =              mct_u232_open,
+       .close =             mct_u232_close,
+-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+-      .write =             mct_u232_write,
+-      .write_bulk_callback = mct_u232_write_bulk_callback,
+-#endif
+       .read_int_callback = mct_u232_read_int_callback,
+       .ioctl =             mct_u232_ioctl,
+       .set_termios =       mct_u232_set_termios,
+@@ -167,9 +144,14 @@
+       .shutdown =          mct_u232_shutdown,
+ };
  
-+#include <asm/dec/serial.h>
++struct mct_u232_interval_kludge {
++      int ecnt;                       /* Error counter */
++      int ibase;                      /* Initial interval value */
++};
+ struct mct_u232_private {
+       spinlock_t lock;
++      struct mct_u232_interval_kludge ik[2];
+       unsigned int         control_state; /* Modem Line Setting (TIOCM) */
+       unsigned char        last_lcr;      /* Line Control Register */
+       unsigned char        last_lsr;      /* Line Status Register */
+@@ -359,17 +341,13 @@
+       struct mct_u232_private *priv;
+       struct usb_serial_port *port, *rport;
+-      /* allocate the private data structure */
+       priv = kmalloc(sizeof(struct mct_u232_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+-      /* set initial values for control structures */
++      memset(priv, 0, sizeof(struct mct_u232_private));
+       spin_lock_init(&priv->lock);
+-      priv->control_state = 0;
+-      priv->last_lsr = 0;
+-      priv->last_msr = 0;
+       serial->port->private = priv;
+- 
 +
- #define NUM_ZSREGS    16
+       init_waitqueue_head(&serial->port->write_wait);
  
- struct serial_struct {
-@@ -89,63 +93,50 @@
-       unsigned char curregs[NUM_ZSREGS];
- };
+       /* Puh, that's dirty */
+@@ -383,20 +361,27 @@
+       rport->interrupt_in_urb = NULL;
+       port->read_urb->context = port;
++      priv->ik[0].ibase = port->read_urb->interval;
++      priv->ik[1].ibase = port->interrupt_in_urb->interval;
++
+       return (0);
+ } /* mct_u232_startup */
+ static void mct_u232_shutdown (struct usb_serial *serial)
+ {
++      struct mct_u232_private *priv;
+       int i;
+       
+       dbg("%s", __FUNCTION__);
+       for (i=0; i < serial->num_ports; ++i) {
+               /* My special items, the standard routines free my urbs */
+-              if (serial->port[i].private)
+-                      kfree(serial->port[i].private);
++              priv = serial->port[i].private;
++              if (priv) {
++                      serial->port[i].private = NULL;
++                      kfree(priv);
++              }
+       }
+ } /* mct_u232_shutdown */
+@@ -448,16 +433,20 @@
+       spin_unlock_irqrestore(&priv->lock, flags);
+       port->read_urb->dev = port->serial->dev;
++      port->read_urb->interval = priv->ik[0].ibase;
+       retval = usb_submit_urb(port->read_urb);
+       if (retval) {
+-              err("usb_submit_urb(read bulk) failed");
++              err("usb_submit_urb(read bulk) failed pipe 0x%x err %d",
++                  port->read_urb->pipe, retval);
+               goto exit;
+       }
+       port->interrupt_in_urb->dev = port->serial->dev;
++      port->interrupt_in_urb->interval = priv->ik[1].ibase;
+       retval = usb_submit_urb(port->interrupt_in_urb);
+       if (retval)
+-              err(" usb_submit_urb(read int) failed");
++              err(" usb_submit_urb(read int) failed pipe 0x%x err %d",
++                  port->interrupt_in_urb->pipe, retval);
+ exit:
+       return 0;
+@@ -476,109 +465,22 @@
+       }
+ } /* mct_u232_close */
  
--struct dec_serial;
 -
--struct zs_hook {
--      int (*init_channel)(struct dec_serial* info);
--      void (*init_info)(struct dec_serial* info);
--      void (*rx_char)(unsigned char ch, unsigned char stat);
--      int  (*poll_rx_char)(struct dec_serial* info);
--      int  (*poll_tx_char)(struct dec_serial* info,
--                           unsigned char ch);
--      unsigned cflags;
--};
+-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+-/* The generic routines work fine otherwise */
 -
- struct dec_serial {
--      struct dec_serial *zs_next;     /* For IRQ servicing chain */
--      struct dec_zschannel *zs_channel; /* Channel registers */
--      struct dec_zschannel *zs_chan_a;        /* A side registers */
--      unsigned char read_reg_zero;
+-static int mct_u232_write (struct usb_serial_port *port, int from_user,
+-                         const unsigned char *buf, int count)
++static void mct_u232_error_step (struct urb *urb,
++    struct mct_u232_private *priv, int n)
+ {
+-      struct usb_serial *serial = port->serial;
+-      int result, bytes_sent, size;
 -
--      char soft_carrier;  /* Use soft carrier on this channel */
--      char break_abort;   /* Is serial console in, so process brk/abrt */
--      struct zs_hook *hook;  /* Hook on this channel */
--      char is_cons;       /* Is this our console. */
--      unsigned char tx_active; /* character is being xmitted */
--      unsigned char tx_stopped; /* output is suspended */
+-      dbg("%s - port %d", __FUNCTION__, port->number);
 -
--      /* We need to know the current clock divisor
--       * to read the bps rate the chip has currently
--       * loaded.
-+      struct dec_serial       *zs_next;       /* For IRQ servicing chain.  */
-+      struct dec_zschannel    *zs_channel;    /* Channel registers.  */
-+      struct dec_zschannel    *zs_chan_a;     /* A side registers.  */
-+      unsigned char           read_reg_zero;
+-      if (count == 0) {
+-              dbg("%s - write request of 0 bytes", __FUNCTION__);
+-              return (0);
+-      }
+-
+-      /* only do something if we have a bulk out endpoint */
+-      if (!serial->num_bulk_out)
+-              return(0);;
+-      
+-      /* another write is still pending? */
+-      if (port->write_urb->status == -EINPROGRESS) {
+-              dbg("%s - already writing", __FUNCTION__);
+-              return (0);
+-      }
+-              
+-      bytes_sent = 0;
+-      while (count > 0) {
+-              size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+-              
+-              usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
+-              
+-              if (from_user) {
+-                      if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) {
+-                              return -EFAULT;
+-                      }
+-              }
+-              else {
+-                      memcpy (port->write_urb->transfer_buffer, buf, size);
+-              }
+-              
+-              /* set up our urb */
+-              FILL_BULK_URB(port->write_urb, serial->dev,
+-                            usb_sndbulkpipe(serial->dev,
+-                                            port->bulk_out_endpointAddress),
+-                            port->write_urb->transfer_buffer, size,
+-                            ((serial->type->write_bulk_callback) ?
+-                             serial->type->write_bulk_callback :
+-                             mct_u232_write_bulk_callback),
+-                            port);
+-              
+-              /* send the data out the bulk port */
+-              result = usb_submit_urb(port->write_urb);
+-              if (result) {
+-                      err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
+-                      return result;
+-              }
+-
+-              bytes_sent += size;
+-              if (write_blocking)
+-                      interruptible_sleep_on(&port->write_wait);
+-              else
+-                      break;
+-
+-              buf += size;
+-              count -= size;
+-      }
+-      
+-      return bytes_sent;
+-} /* mct_u232_write */
+-
+-static void mct_u232_write_bulk_callback (struct urb *urb)
+-{
+-      struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+-      struct usb_serial *serial = port->serial;
+-              struct tty_struct *tty = port->tty;
+-
+-      dbg("%s - port %d", __FUNCTION__, port->number);
+-      
+-      if (!serial) {
+-              dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+-              return;
+-      }
++      struct mct_u232_interval_kludge *ikp = &priv->ik[n];
+-      if (urb->status) {
+-              dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
+-                  urb->status);
+-              return;
+-      }
+-
+-      if (write_blocking) {
+-              wake_up_interruptible(&port->write_wait);
+-              tty_wakeup(tty);
++      if (ikp->ecnt >= 2) {
++              if (urb->interval)
++                      err("%s - too many errors: "
++                          "status %d pipe 0x%x interval %d",
++                          __FUNCTION__,
++                          urb->status, urb->pipe, urb->interval);
++              urb->interval = 0;
+       } else {
+-              /* from generic_write_bulk_callback */
+-              queue_task(&port->tqueue, &tq_immediate);
+-              mark_bh(IMMEDIATE_BH);
++              ++ikp->ecnt;
+       }
+-
+-      return;
+-} /* mct_u232_write_bulk_callback */
+-#endif
++}
+ static void mct_u232_read_int_callback (struct urb *urb)
+ {
+@@ -589,21 +491,37 @@
+       unsigned char *data = urb->transfer_buffer;
+       unsigned long flags;
+-        dbg("%s - port %d", __FUNCTION__, port->number);
+-
+       /* The urb might have been killed. */
+         if (urb->status) {
+-                dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
+-                  urb->status);
++              dbg("%s - nonzero status %d, pipe 0x%x flags 0x%x interval %d",
++                  __FUNCTION__,
++                  urb->status, urb->pipe, urb->transfer_flags, urb->interval);
++              /*
++               * The bad stuff happens when a device is disconnected.
++               * This can cause us to spin while trying to resubmit.
++               * Unfortunately, in kernel 2.4 error codes are wildly
++               * different between controllers, so the status is useless.
++               * Instead we just refuse to spin too much.
++               */
++              if (urb == port->read_urb)
++                      mct_u232_error_step(urb, priv, 0);
++              if (urb == port->interrupt_in_urb)
++                      mct_u232_error_step(urb, priv, 1);
+                 return;
+         }
+       if (!serial) {
+               dbg("%s - bad serial pointer, exiting", __FUNCTION__);
+               return;
+       }
+-      
 +
-+      struct dec_serial_hook  *hook;          /* Hook on this channel.  */
-+      int                     tty_break;      /* Set on BREAK condition.  */
-+      int                     is_cons;        /* Is this our console.  */
-+      int                     tx_active;      /* Char is being xmitted.  */
-+      int                     tx_stopped;     /* Output is suspended.  */
++        dbg("%s - port %d", __FUNCTION__, port->number);
+       usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
++      if (urb == port->read_urb)
++              priv->ik[0].ecnt = 0;
++      if (urb == port->interrupt_in_urb)
++              priv->ik[1].ecnt = 0;
 +
-+      /*
-+       * We need to know the current clock divisor
-+       * to read the bps rate the chip has currently loaded.
+       /*
+        * Work-a-round: handle the 'usual' bulk-in pipe here
         */
--      unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
--      int zs_baud;
-+      int                     clk_divisor;    /* May be 1, 16, 32, or 64.  */
-+      int                     zs_baud;
+@@ -660,7 +578,6 @@
+       /* INT urbs are automatically re-submitted */
+ } /* mct_u232_read_int_callback */
  
--      char change_needed;
-+      char                    change_needed;
+-
+ static void mct_u232_set_termios (struct usb_serial_port *port,
+                                 struct termios *old_termios)
+ {
+@@ -781,6 +698,21 @@
+ } /* mct_u232_break_ctl */
  
-       int                     magic;
-       int                     baud_base;
-       int                     port;
-       int                     irq;
--      int                     flags;          /* defined in tty.h */
--      int                     type;           /* UART type */
-+      int                     flags;          /* Defined in tty.h.  */
-+      int                     type;           /* UART type.  */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     ignore_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     custom_divisor;
--      int                     x_char; /* xon/xoff character */
-+      int                     x_char;         /* XON/XOFF character.  */
-       int                     close_delay;
-       unsigned short          closing_wait;
-       unsigned short          closing_wait2;
-       unsigned long           event;
-       unsigned long           last_active;
-       int                     line;
--      int                     count;      /* # of fd on device */
--      int                     blocked_open; /* # of blocked opens */
--      long                    session; /* Session of opening process */
--      long                    pgrp; /* pgrp of opening process */
-+      int                     count;          /* # of fds on device.  */
-+      int                     blocked_open;   /* # of blocked opens.  */
-+      long                    session;        /* Sess of opening process.  */
-+      long                    pgrp;           /* Pgrp of opening process.  */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-diff -Nur linux-2.4.29/drivers/video/Config.in linux-mips/drivers/video/Config.in
---- linux-2.4.29/drivers/video/Config.in       2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/video/Config.in 2005-02-12 04:07:18.000000000 +0100
-@@ -87,8 +87,8 @@
-    if [ "$CONFIG_HP300" = "y" ]; then
-       define_bool CONFIG_FB_HP300 y
-    fi
--   if [ "$ARCH" = "alpha" ]; then
--      tristate '  TGA framebuffer support' CONFIG_FB_TGA
-+   if [ "$ARCH" = "alpha" -o "$CONFIG_TC" = "y" ]; then
-+      tristate '  TGA/SFB+ framebuffer support' CONFIG_FB_TGA
-    fi
-    if [ "$CONFIG_X86" = "y" ]; then
-       bool '  VESA VGA graphics console' CONFIG_FB_VESA
-@@ -121,6 +121,17 @@
-          hex '    Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
-       fi
-    fi
-+   if [ "$CONFIG_SOC_AU1100" = "y" ]; then
-+      bool '  Au1100 LCD Driver' CONFIG_FB_AU1100
-+   fi
-+   
-+   if [ "$CONFIG_SOC_AU1200" = "y" ]; then
-+      bool '  Au1200 LCD Driver' CONFIG_FB_AU1200
-+      if [ "$CONFIG_FB_AU1200" = "y" ]; then
-+      int  '    Number of planes (1 to 4)' CONFIG_FB_AU1200_DEVS 1
-+      fi
-+   fi
-+   
-    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-       if [ "$CONFIG_PCI" != "n" ]; then
-        tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
-@@ -178,9 +189,6 @@
-            bool '    Use CRT on Pb1100 ' CONFIG_PB1500_CRT
-            bool '    Use TFT Panel on Pb1100 ' CONFIG_PB1500_TFT
-            fi
--           if [ "$CONFIG_SOC_AU1100" = "y" ]; then
--           bool '    Au1100 LCD Driver' CONFIG_FB_AU1100
--           fi
-        fi
-       fi
-    fi
-diff -Nur linux-2.4.29/drivers/video/Makefile linux-mips/drivers/video/Makefile
---- linux-2.4.29/drivers/video/Makefile        2004-02-18 14:36:31.000000000 +0100
-+++ linux-mips/drivers/video/Makefile  2005-02-12 04:07:18.000000000 +0100
-@@ -87,6 +87,7 @@
- obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
- obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
- obj-$(CONFIG_FB_AU1100)                 += au1100fb.o fbgen.o
-+obj-$(CONFIG_FB_AU1200)                 += au1200fb.o fbgen.o
- obj-$(CONFIG_FB_IT8181)                 += it8181fb.o fbgen.o
  
- subdir-$(CONFIG_STI_CONSOLE)      += sti
++static int mct_u232_tiocmget (struct usb_serial_port *port, struct file *file)
++{
++      struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
++      unsigned int control_state;
++      unsigned long flags;
++      
++      dbg("%s", __FUNCTION__);
++
++      spin_lock_irqsave(&priv->lock, flags);
++      control_state = priv->control_state;
++      spin_unlock_irqrestore(&priv->lock, flags);
++
++      return control_state;
++}
++
+ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
+                          unsigned int cmd, unsigned long arg)
+ {
+@@ -794,8 +726,8 @@
+       /* Based on code from acm.c and others */
+       switch (cmd) {
+       case TIOCMGET:
+-              return put_user(priv->control_state, (unsigned long *) arg);
+-              break;
++              mask = mct_u232_tiocmget(port, file);
++              return put_user(mask, (unsigned long *) arg);
+       case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+       case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+@@ -865,12 +797,5 @@
+ MODULE_DESCRIPTION( DRIVER_DESC );
+ MODULE_LICENSE("GPL");
+-#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+-MODULE_PARM(write_blocking, "i");
+-MODULE_PARM_DESC(write_blocking, 
+-               "The write function will block to write out all data");
+-#endif
+-
+ MODULE_PARM(debug, "i");
+ MODULE_PARM_DESC(debug, "Debug enabled or not");
+-
+diff -Nur linux-2.4.29/drivers/usb/storage/transport.c linux-mips/drivers/usb/storage/transport.c
+--- linux-2.4.29/drivers/usb/storage/transport.c       2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/usb/storage/transport.c 2005-03-26 11:47:35.757783067 +0100
+@@ -1181,6 +1181,13 @@
+       /* if the command transfered well, then we go to the data stage */
+       if (result == 0) {
++
++              /* Genesys Logic interface chips need a 100us delay between
++               * the command phase and the data phase.  Some systems need
++               * even more, probably because of clock rate inaccuracies. */
++              if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS)
++                      udelay(110);
++
+               /* send/receive data payload, if there is any */
+               if (bcb->DataTransferLength) {
+                       usb_stor_transfer(srb, us);
+diff -Nur linux-2.4.29/drivers/usb/storage/usb.c linux-mips/drivers/usb/storage/usb.c
+--- linux-2.4.29/drivers/usb/storage/usb.c     2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/drivers/usb/storage/usb.c       2005-03-26 11:47:35.758782903 +0100
+@@ -996,6 +996,15 @@
+                */
+               ss->htmplt.proc_dir = (void *)ss; 
++              /* According to the technical support people at Genesys Logic,
++               * devices using their chips have problems transferring more
++               * than 32 KB at a time.  In practice people have found that
++               * 64 KB works okay and that's what Windows does.  But we'll
++               * be conservative.
++               */
++              if (ss->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS)
++                      ss->htmplt.max_sectors = 64;
++
+               /* Just before we start our control thread, initialize
+                * the device if it needs initialization */
+               if (unusual_dev && unusual_dev->initFunction)
+diff -Nur linux-2.4.29/drivers/usb/storage/usb.h linux-mips/drivers/usb/storage/usb.h
+--- linux-2.4.29/drivers/usb/storage/usb.h     2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/drivers/usb/storage/usb.h       2005-03-26 11:47:35.759782739 +0100
+@@ -193,4 +193,7 @@
+ /* Function to fill an inquiry response. See usb.c for details */
+ extern void fill_inquiry_response(struct us_data *us,
+       unsigned char *data, unsigned int data_len);
++
++/* Vendor ID list for devices that require special handling */
++#define USB_VENDOR_ID_GENESYS         0x05e3  /* Genesys Logic */
+ #endif
 diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200fb.c
 --- linux-2.4.29/drivers/video/au1200fb.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-mips/drivers/video/au1200fb.c        2005-02-11 22:16:44.000000000 +0100
-@@ -0,0 +1,1599 @@
++++ linux-mips/drivers/video/au1200fb.c        2005-03-13 09:04:16.000000000 +0100
+@@ -0,0 +1,1564 @@
 +/*
 + * BRIEF MODULE DESCRIPTION
 + *    Au1200 LCD Driver.
@@ -19213,18 +30389,6 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +#include <video/fbcon-cfb32.h>
 +#define CMAPSIZE 16
 +
-+#ifdef CONFIG_MIPS_PB1200
-+#include <asm/pb1200.h>
-+#endif
-+
-+#ifdef CONFIG_MIPS_DB1200
-+#include <asm/db1200.h>
-+#endif
-+
-+#ifdef CONFIG_MIPS_FICMMP
-+#include <asm/ficmmp.h>
-+#endif
-+
 +#define AU1200_LCD_GET_WINENABLE      1
 +#define AU1200_LCD_SET_WINENABLE      2
 +#define AU1200_LCD_GET_WINLOCATION    3
@@ -19267,7 +30431,7 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +
 +AU1200_LCD *lcd = (AU1200_LCD *)AU1200_LCD_ADDR;
 +static int window_index = 0; /* default is zero */
-+static int panel_index = 0; /* default is zero */
++static int panel_index = -1; /* default is call board_au1200fb_panel */
 +
 +struct window_settings
 +{
@@ -19314,15 +30478,15 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
 +#endif
 +
-+static int panel_init (void);
-+static int panel_shutdown (void);
-+
++extern int board_au1200fb_panel (void);
++extern int board_au1200fb_panel_init (void);
++extern int board_au1200fb_panel_shutdown (void);
 +
 +#if defined(CONFIG_FOCUS_ENHANCEMENTS)
-+extern int focus_init_hdtv(void);
-+extern int focus_init_component(void);
-+extern int focus_init_cvsv(void);
-+extern int focus_shutdown(void);
++extern int board_au1200fb_focus_init_hdtv(void);
++extern int board_au1200fb_focus_init_component(void);
++extern int board_au1200fb_focus_init_cvsv(void);
++extern int board_au1200fb_focus_shutdown(void);
 +#endif
 +
 +/*
@@ -19502,8 +30666,8 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000004, /* 96MHz AUXPLL directly */
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ panel_init,
-+              /* device_shutdown      */ panel_shutdown,
++              /* device_init          */ board_au1200fb_panel_init,
++              /* device_shutdown      */ board_au1200fb_panel_shutdown,
 +      },
 +
 +      { /* Index 6: Toshiba 640x480 TFT */
@@ -19520,8 +30684,8 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000004, /* 96MHz AUXPLL directly */
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ panel_init,
-+              /* device_shutdown      */ panel_shutdown,
++              /* device_init          */ board_au1200fb_panel_init,
++              /* device_shutdown      */ board_au1200fb_panel_shutdown,
 +      },
 +
 +      { /* Index 7: Sharp 320x240 TFT */
@@ -19538,11 +30702,28 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000004, /* 96MHz AUXPLL directly */
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ panel_init,
-+              /* device_shutdown      */ panel_shutdown,
++              /* device_init          */ board_au1200fb_panel_init,
++              /* device_shutdown      */ board_au1200fb_panel_shutdown,
++      },
++      { /* Index 8: Toppoly TD070WGCB2 7" 854x480 TFT */
++              "Toppoly_TD070WGCB2",
++              854, 480,
++              /* mode_screen          */ LCD_SCREEN_SX_N(854) | LCD_SCREEN_SY_N(480),
++              /* mode_horztiming      */ LCD_HORZTIMING_HND2_N(44) | LCD_HORZTIMING_HND1_N(44) | LCD_HORZTIMING_HPW_N(114),
++              /* mode_verttiming      */ LCD_VERTTIMING_VND2_N(20) | LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
++              /* mode_clkcontrol      */ 0x00020001, /* /4=24Mhz */
++              /* mode_pwmdiv          */ 0x8000063f,
++              /* mode_pwmhi           */ 0x03400000,
++              /* mode_outmask         */ 0x00FCFCFC,
++              /* mode_fifoctrl        */ 0x2f2f2f2f,
++              /* mode_toyclksrc   */ 0x00000004, /* AUXPLL directly */
++              /* mode_backlight   */ 0x00000000,
++              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
++              /* device_init          */ board_au1200fb_panel_init,
++              /* device_shutdown      */ board_au1200fb_panel_shutdown,
 +      },
 +#if defined(CONFIG_FOCUS_ENHANCEMENTS)
-+      { /* Index 8: Focus FS453 TV-Out 640x480 */
++      { /* Index 9: Focus FS453 TV-Out 640x480 */
 +              "FS453_640x480 (Composite/S-Video)",
 +              640, 480,
 +              /* mode_screen          */ LCD_SCREEN_SX_N(640) | LCD_SCREEN_SY_N(480),
@@ -19556,11 +30737,11 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000000,
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ focus_init_cvsv,
-+              /* device_shutdown      */ focus_shutdown,
++              /* device_init          */ board_au1200fb_focus_init_cvsv,
++              /* device_shutdown      */ board_au1200fb_focus_shutdown,
 +      },
 +      
-+      { /* Index 9: Focus FS453 TV-Out 640x480 */
++      { /* Index 10: Focus FS453 TV-Out 640x480 */
 +              "FS453_640x480 (Component Video)",
 +              640, 480,
 +              /* mode_screen          */ LCD_SCREEN_SX_N(640) | LCD_SCREEN_SY_N(480),
@@ -19574,11 +30755,11 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000000,
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ focus_init_component,
-+              /* device_shutdown      */ focus_shutdown,
++              /* device_init          */ board_au1200fb_focus_init_component,
++              /* device_shutdown      */ board_au1200fb_focus_shutdown,
 +      },
 +      
-+      { /* Index 10: Focus FS453 TV-Out 640x480 */
++      { /* Index 11: Focus FS453 TV-Out 640x480 */
 +              "FS453_640x480 (HDTV)",
 +              720, 480,
 +              /* mode_screen          */ LCD_SCREEN_SX_N(720) | LCD_SCREEN_SY_N(480),
@@ -19592,8 +30773,8 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              /* mode_toyclksrc   */ 0x00000000,
 +              /* mode_backlight   */ 0x00000000,
 +              /* mode_auxpll          */ 8, /* 96MHz AUXPLL */
-+              /* device_init          */ focus_init_hdtv,
-+              /* device_shutdown      */ focus_shutdown,
++              /* device_init          */ board_au1200fb_focus_init_hdtv,
++              /* device_shutdown      */ board_au1200fb_focus_shutdown,
 +      },
 +#endif
 +};
@@ -19666,36 +30847,6 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +};
 +
 +
-+static int panel_init (void)
-+{
-+#if defined(CONFIG_MIPS_PB1200) || defined(CONFIG_MIPS_DB1200)
-+      /* Apply power */
-+    BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-+      bcsr->board |= (BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
-+      /*printk("panel_init(%s)\n", panel->name); */
-+#elif defined(CONFIG_MIPS_FICMMP)
-+      /*Enable data buffers*/
-+      ficmmp_config_clear(FICMMP_CONFIG_LCMDATAOUT);
-+      /*Take LCD out of reset*/
-+      ficmmp_config_set(FICMMP_CONFIG_LCMPWREN | FICMMP_CONFIG_LCMEN);
-+#endif
-+}
-+
-+static int panel_shutdown (void)
-+{
-+#if defined(CONFIG_MIPS_PB1200) || defined(CONFIG_MIPS_DB1200)
-+      /* Remove power */
-+    BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-+      bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
-+      /*printk("panel_shutdown(%s)\n", panel->name);*/
-+#elif defined(CONFIG_MIPS_FICMMP)
-+      /*Disable data buffers*/
-+      ficmmp_config_set(FICMMP_CONFIG_LCMDATAOUT);
-+      /*Put LCD in reset, remove power*/
-+      ficmmp_config_clear(FICMMP_CONFIG_LCMEN | FICMMP_CONFIG_LCMPWREN);
-+#endif
-+}
-+
 +static int
 +winbpp (unsigned int winctrl1)
 +{
@@ -20071,21 +31222,14 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +      switch (blank_mode) {
 +      case VESA_NO_BLANKING:
 +              /* printk("turn on panel\n"); */
-+              if (panel->device_init) panel->device_init();
-+        lcd->screen |= LCD_SCREEN_SEN;
-+              /* FIX!!! Need panel poweron callback */
++              au1200_setpanel(panel);
 +              break;
 +
 +      case VESA_VSYNC_SUSPEND:
 +      case VESA_HSYNC_SUSPEND:
 +      case VESA_POWERDOWN:
 +              /* printk("turn off panel\n"); */
-+              /* FIX!!! Need panel poweroff callback */
-+              if (panel->device_shutdown) panel->device_shutdown();
-+        lcd->screen &= ~LCD_SCREEN_SEN;
-+              while ((lcd->intstatus & LCD_INT_SD) == 0)
-+                      ;
-+              lcd->intstatus = LCD_INT_SD;
++              au1200_setpanel(NULL);
 +        break;
 +      default: 
 +              break;
@@ -20318,6 +31462,9 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +              if (panel->device_shutdown != NULL) panel->device_shutdown();
 +      }
 +
++      /* Check if only needing to turn off panel */
++      if (panel == NULL) return;
++
 +      panel = newpanel;
 +      
 +      printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
@@ -20325,9 +31472,11 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +      /*
 +       * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
 +       */
-+      /* FIX!!! if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT)) */
++      if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
 +      {
 +              uint32 sys_clksrc;
++              /* WARNING! This should really be a check since other peripherals can 
++                 be affected by changins sys_auxpll  */
 +              au_writel(panel->mode_auxpll, SYS_AUXPLL);
 +              sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f; 
 +              sys_clksrc |= panel->mode_toyclksrc;
@@ -20571,6 +31720,7 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +
 +int __init au1200fb_init(void)
 +{
++      int num_panels = sizeof(panels)/sizeof(struct panel_settings);
 +      struct au1200fb_info *fb_info;
 +      struct display *disp;
 +      struct au1200fb_par *par;
@@ -20580,6 +31730,12 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +    /*
 +      * Get the panel information/display mode
 +      */
++      if (panel_index < 0)
++              panel_index = board_au1200fb_panel();
++      if ((panel_index < 0) || (panel_index >= num_panels)) {
++              printk("ERROR: INVALID PANEL %d\n", panel_index);
++              return -EINVAL;
++      }
 +      panel = &panels[panel_index];
 +      win = &windows[window_index];
 +
@@ -20697,37 +31853,22 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.c linux-mips/drivers/video/au1200f
 +      for(this_opt=strtok(options, ","); this_opt;
 +          this_opt=strtok(NULL, ",")) {
 +              if (!strncmp(this_opt, "panel:", 6)) {
-+#if defined(CONFIG_MIPS_PB1200) || defined(CONFIG_MIPS_DB1200)
-+                      /* Read Pb1200 Rotary Switch S11 to obtain default panel */
-+#ifdef CONFIG_MIPS_PB1200
-+                      if (!strncmp(this_opt+6, "s11", 3))
-+#endif
-+#ifdef CONFIG_MIPS_DB1200
-+                      if (!strncmp(this_opt+6, "s7", 3))
-+#endif
-+                      {
-+                              BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-+                              int p;
-+
-+                              p = bcsr->switches;
-+                              p >>= 8;
-+                              p &= 0x0F;
-+                              if (p >= num_panels) p = 0;
-+                              panel_index = p;
++                      int i;
++                      long int li;
++                      char *endptr;
++                      this_opt += 6;
++
++                      /* Panel name can be name, "bs" for board-switch, or number/index */
++                      li = simple_strtol(this_opt, &endptr, 0);
++                      if (*endptr == '\0') {
++                              panel_index = (int)li;
++                      }
++                      else if (strcmp(this_opt, "bs") == 0) {
++                              panel_index = board_au1200fb_panel();
 +                      }
 +                      else
-+#elif defined(CONFIG_MIPS_FICMMP)
-+      au1xxx_gpio_tristate(6);
-+      
-+      if(au1xxx_gpio_read(12) == 0)
-+              panel_index = 8;
-+      else
-+              panel_index = 7;
-+#endif
-+                      /* Get the panel name, everything else if fixed */
 +                      for (i=0; i<num_panels; i++) {
-+                              if (!strncmp(this_opt+6, panels[i].name, 
-+                                                      strlen(this_opt))) {
++                              if (!strcmp(this_opt, panels[i].name)) {
 +                                      panel_index = i;
 +                                      break;
 +                              }
@@ -21051,9 +32192,51 @@ diff -Nur linux-2.4.29/drivers/video/au1200fb.h linux-mips/drivers/video/au1200f
 +
 +/********************************************************************/
 +#endif /* _AU1200LCD_H */
+diff -Nur linux-2.4.29/drivers/video/Config.in linux-mips/drivers/video/Config.in
+--- linux-2.4.29/drivers/video/Config.in       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/video/Config.in 2005-03-26 11:47:35.761782411 +0100
+@@ -87,8 +87,8 @@
+    if [ "$CONFIG_HP300" = "y" ]; then
+       define_bool CONFIG_FB_HP300 y
+    fi
+-   if [ "$ARCH" = "alpha" ]; then
+-      tristate '  TGA framebuffer support' CONFIG_FB_TGA
++   if [ "$ARCH" = "alpha" -o "$CONFIG_TC" = "y" ]; then
++      tristate '  TGA/SFB+ framebuffer support' CONFIG_FB_TGA
+    fi
+    if [ "$CONFIG_X86" = "y" ]; then
+       bool '  VESA VGA graphics console' CONFIG_FB_VESA
+@@ -121,6 +121,17 @@
+          hex '    Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
+       fi
+    fi
++   if [ "$CONFIG_SOC_AU1100" = "y" ]; then
++      bool '  Au1100 LCD Driver' CONFIG_FB_AU1100
++   fi
++   
++   if [ "$CONFIG_SOC_AU1200" = "y" ]; then
++      bool '  Au1200 LCD Driver' CONFIG_FB_AU1200
++      if [ "$CONFIG_FB_AU1200" = "y" ]; then
++      int  '    Number of planes (1 to 4)' CONFIG_FB_AU1200_DEVS 1
++      fi
++   fi
++   
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       if [ "$CONFIG_PCI" != "n" ]; then
+        tristate '  Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
+@@ -178,9 +189,6 @@
+            bool '    Use CRT on Pb1100 ' CONFIG_PB1500_CRT
+            bool '    Use TFT Panel on Pb1100 ' CONFIG_PB1500_TFT
+            fi
+-           if [ "$CONFIG_SOC_AU1100" = "y" ]; then
+-           bool '    Au1100 LCD Driver' CONFIG_FB_AU1100
+-           fi
+        fi
+       fi
+    fi
 diff -Nur linux-2.4.29/drivers/video/fbmem.c linux-mips/drivers/video/fbmem.c
 --- linux-2.4.29/drivers/video/fbmem.c 2005-01-19 15:10:09.000000000 +0100
-+++ linux-mips/drivers/video/fbmem.c   2005-02-12 04:07:19.000000000 +0100
++++ linux-mips/drivers/video/fbmem.c   2005-03-26 11:47:36.031738105 +0100
 @@ -139,6 +139,8 @@
  extern int e1356fb_setup(char*);
  extern int au1100fb_init(void);
@@ -21352,6 +32535,17 @@ diff -Nur linux-2.4.29/drivers/video/ims332.h linux-mips/drivers/video/ims332.h
 +                              IMS332_CTRL_A_BOOT_ENABLE_VTG);
 +      printk("\n");
 +}
+diff -Nur linux-2.4.29/drivers/video/Makefile linux-mips/drivers/video/Makefile
+--- linux-2.4.29/drivers/video/Makefile        2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/drivers/video/Makefile  2005-03-26 11:47:35.762782246 +0100
+@@ -87,6 +87,7 @@
+ obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
+ obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
+ obj-$(CONFIG_FB_AU1100)                 += au1100fb.o fbgen.o
++obj-$(CONFIG_FB_AU1200)                 += au1200fb.o fbgen.o
+ obj-$(CONFIG_FB_IT8181)                 += it8181fb.o fbgen.o
+ subdir-$(CONFIG_STI_CONSOLE)      += sti
 diff -Nur linux-2.4.29/drivers/video/maxinefb.h linux-mips/drivers/video/maxinefb.h
 --- linux-2.4.29/drivers/video/maxinefb.h      2003-08-25 13:44:42.000000000 +0200
 +++ linux-mips/drivers/video/maxinefb.h        1970-01-01 01:00:00.000000000 +0100
@@ -21827,24 +33021,676 @@ diff -Nur linux-2.4.29/fs/binfmt_elf.c linux-mips/fs/binfmt_elf.c
                    bprm->argc++;
                  }
                }
-+      } else {
-+              /* Executables without an interpreter also need a personality  */
-+              SET_PERSONALITY(elf_ex, ibcs2_interpreter);
++      } else {
++              /* Executables without an interpreter also need a personality  */
++              SET_PERSONALITY(elf_ex, ibcs2_interpreter);
+       }
+       /* Flush all traces of the currently running executable */
+@@ -1208,7 +1211,11 @@
+       elf.e_entry = 0;
+       elf.e_phoff = sizeof(elf);
+       elf.e_shoff = 0;
++#ifdef ELF_CORE_EFLAGS
++      elf.e_flags = ELF_CORE_EFLAGS;
++#else
+       elf.e_flags = 0;
++#endif
+       elf.e_ehsize = sizeof(elf);
+       elf.e_phentsize = sizeof(struct elf_phdr);
+       elf.e_phnum = segs+1;           /* Include notes */
+diff -Nur linux-2.4.29/fs/ext3/fsync.c linux-mips/fs/ext3/fsync.c
+--- linux-2.4.29/fs/ext3/fsync.c       2002-11-29 00:53:15.000000000 +0100
++++ linux-mips/fs/ext3/fsync.c 2005-03-26 11:47:36.070731705 +0100
+@@ -69,7 +69,7 @@
+       if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
+               ret |= fsync_inode_data_buffers(inode);
+-      ext3_force_commit(inode->i_sb);
++      ret |= ext3_force_commit(inode->i_sb);
+       return ret;
+ }
+diff -Nur linux-2.4.29/fs/ext3/super.c linux-mips/fs/ext3/super.c
+--- linux-2.4.29/fs/ext3/super.c       2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/fs/ext3/super.c 2005-03-26 11:47:36.071731541 +0100
+@@ -1608,12 +1608,13 @@
+ static int ext3_sync_fs(struct super_block *sb)
+ {
++      int err;
+       tid_t target;
+       
+       sb->s_dirt = 0;
+       target = log_start_commit(EXT3_SB(sb)->s_journal, NULL);
+-      log_wait_commit(EXT3_SB(sb)->s_journal, target);
+-      return 0;
++      err = log_wait_commit(EXT3_SB(sb)->s_journal, target);
++      return err;
+ }
+ /*
+diff -Nur linux-2.4.29/fs/file_table.c linux-mips/fs/file_table.c
+--- linux-2.4.29/fs/file_table.c       2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/fs/file_table.c 2005-03-26 11:47:36.063732854 +0100
+@@ -46,6 +46,7 @@
+               f->f_version = ++event;
+               f->f_uid = current->fsuid;
+               f->f_gid = current->fsgid;
++              f->f_maxcount = INT_MAX;
+               list_add(&f->f_list, &anon_list);
+               file_list_unlock();
+               return f;
+@@ -91,6 +92,8 @@
+       filp->f_uid    = current->fsuid;
+       filp->f_gid    = current->fsgid;
+       filp->f_op     = dentry->d_inode->i_fop;
++      filp->f_maxcount = INT_MAX;
++
+       if (filp->f_op->open)
+               return filp->f_op->open(dentry->d_inode, filp);
+       else
+diff -Nur linux-2.4.29/fs/jbd/commit.c linux-mips/fs/jbd/commit.c
+--- linux-2.4.29/fs/jbd/commit.c       2004-02-18 14:36:31.000000000 +0100
++++ linux-mips/fs/jbd/commit.c 2005-03-26 11:47:36.078730392 +0100
+@@ -92,7 +92,7 @@
+       struct buffer_head *wbuf[64];
+       int bufs;
+       int flags;
+-      int err;
++      int err = 0;
+       unsigned long blocknr;
+       char *tagp = NULL;
+       journal_header_t *header;
+@@ -299,6 +299,8 @@
+                       spin_unlock(&journal_datalist_lock);
+                       unlock_journal(journal);
+                       wait_on_buffer(bh);
++                      if (unlikely(!buffer_uptodate(bh)))
++                              err = -EIO;
+                       /* the journal_head may have been removed now */
+                       lock_journal(journal);
+                       goto write_out_data;
+@@ -326,6 +328,8 @@
+                       spin_unlock(&journal_datalist_lock);
+                       unlock_journal(journal);
+                       wait_on_buffer(bh);
++                      if (unlikely(!buffer_uptodate(bh)))
++                              err = -EIO;
+                       lock_journal(journal);
+                       spin_lock(&journal_datalist_lock);
+                       continue;       /* List may have changed */
+@@ -351,6 +355,9 @@
+       }
+       spin_unlock(&journal_datalist_lock);
++      if (err)
++              __journal_abort_hard(journal);
++
+       /*
+        * If we found any dirty or locked buffers, then we should have
+        * looped back up to the write_out_data label.  If there weren't
+@@ -541,6 +548,8 @@
+               if (buffer_locked(bh)) {
+                       unlock_journal(journal);
+                       wait_on_buffer(bh);
++                      if (unlikely(!buffer_uptodate(bh)))
++                              err = -EIO;
+                       lock_journal(journal);
+                       goto wait_for_iobuf;
+               }
+@@ -602,6 +611,8 @@
+               if (buffer_locked(bh)) {
+                       unlock_journal(journal);
+                       wait_on_buffer(bh);
++                      if (unlikely(!buffer_uptodate(bh)))
++                              err = -EIO;
+                       lock_journal(journal);
+                       goto wait_for_ctlbuf;
+               }
+@@ -650,6 +661,8 @@
+               bh->b_end_io = journal_end_buffer_io_sync;
+               submit_bh(WRITE, bh);
+               wait_on_buffer(bh);
++              if (unlikely(!buffer_uptodate(bh)))
++                      err = -EIO;
+               put_bh(bh);             /* One for getblk() */
+               journal_unlock_journal_head(descriptor);
+       }
+@@ -661,6 +674,9 @@
+ skip_commit: /* The journal should be unlocked by now. */
++      if (err)
++              __journal_abort_hard(journal);
++      
+       /* Call any callbacks that had been registered for handles in this
+        * transaction.  It is up to the callback to free any allocated
+        * memory.
+diff -Nur linux-2.4.29/fs/jbd/journal.c linux-mips/fs/jbd/journal.c
+--- linux-2.4.29/fs/jbd/journal.c      2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/fs/jbd/journal.c        2005-03-26 11:47:36.079730228 +0100
+@@ -582,8 +582,10 @@
+  * Wait for a specified commit to complete.
+  * The caller may not hold the journal lock.
+  */
+-void log_wait_commit (journal_t *journal, tid_t tid)
++int log_wait_commit (journal_t *journal, tid_t tid)
+ {
++      int err = 0;
++
+       lock_kernel();
+ #ifdef CONFIG_JBD_DEBUG
+       lock_journal(journal);
+@@ -600,6 +602,12 @@
+               sleep_on(&journal->j_wait_done_commit);
+       }
+       unlock_kernel();
++
++      if (unlikely(is_journal_aborted(journal))) {
++              printk(KERN_EMERG "journal commit I/O error\n");
++              err = -EIO;
++      }
++      return err;
+ }
+ /*
+@@ -1326,7 +1334,7 @@
+       /* Wait for the log commit to complete... */
+       if (transaction)
+-              log_wait_commit(journal, transaction->t_tid);
++              err = log_wait_commit(journal, transaction->t_tid);
+       /* ...and flush everything in the log out to disk. */
+       lock_journal(journal);
+diff -Nur linux-2.4.29/fs/jbd/transaction.c linux-mips/fs/jbd/transaction.c
+--- linux-2.4.29/fs/jbd/transaction.c  2004-08-08 01:26:05.000000000 +0200
++++ linux-mips/fs/jbd/transaction.c    2005-03-26 11:47:36.081729900 +0100
+@@ -1484,7 +1484,7 @@
+                * to wait for the commit to complete.  
+                */
+               if (handle->h_sync && !(current->flags & PF_MEMALLOC))
+-                      log_wait_commit(journal, tid);
++                      err = log_wait_commit(journal, tid);
+       }
+       kfree(handle);
+       return err;
+@@ -1509,7 +1509,7 @@
+               goto out;
+       }
+       handle->h_sync = 1;
+-      journal_stop(handle);
++      ret = journal_stop(handle);
+ out:
+       unlock_kernel();
+       return ret;
+diff -Nur linux-2.4.29/fs/jfs/jfs_defragfs.h linux-mips/fs/jfs/jfs_defragfs.h
+--- linux-2.4.29/fs/jfs/jfs_defragfs.h 2002-11-29 00:53:15.000000000 +0100
++++ linux-mips/fs/jfs/jfs_defragfs.h   1970-01-01 01:00:00.000000000 +0100
+@@ -1,51 +0,0 @@
+-/*
+- *   Copyright (c) International Business Machines Corp., 2000-2001
+- *
+- *   This program is free software;  you can redistribute it and/or modify
+- *   it under the terms of the GNU General Public License as published by
+- *   the Free Software Foundation; either version 2 of the License, or 
+- *   (at your option) any later version.
+- * 
+- *   This program is distributed in the hope that it will be useful,
+- *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
+- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+- *   the GNU General Public License for more details.
+- *
+- *   You should have received a copy of the GNU General Public License
+- *   along with this program;  if not, write to the Free Software 
+- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+- */
+-#ifndef       _H_JFS_DEFRAGFS
+-#define _H_JFS_DEFRAGFS
+-
+-/*
+- *    defragfs parameter list
+- */
+-struct defragfs {
+-      uint flag;              /* 4: */
+-      u8 dev;                 /* 1: */
+-      u8 pad[3];              /* 3: */
+-      s32 fileset;            /* 4: */
+-      u32 inostamp;           /* 4: */
+-      u32 ino;                /* 4: */
+-      u32 gen;                /* 4: */
+-      s64 xoff;               /* 8: */
+-      s64 old_xaddr;          /* 8: */
+-      s64 new_xaddr;          /* 8: */
+-      s32 xlen;               /* 4: */
+-};
+-
+-/* plist flag */
+-#define DEFRAGFS_SYNC         0x80000000
+-#define DEFRAGFS_COMMIT               0x40000000
+-#define DEFRAGFS_RELOCATE     0x10000000
+-
+-#define       INODE_TYPE              0x0000F000      /* IFREG or IFDIR */
+-
+-#define EXTENT_TYPE           0x000000ff
+-#define DTPAGE                        0x00000001
+-#define XTPAGE                        0x00000002
+-#define DATAEXT                       0x00000004
+-#define EAEXT                 0x00000008
+-
+-#endif                                /* _H_JFS_DEFRAGFS */
+diff -Nur linux-2.4.29/fs/jfs/jfs_imap.c linux-mips/fs/jfs/jfs_imap.c
+--- linux-2.4.29/fs/jfs/jfs_imap.c     2005-01-19 15:10:10.000000000 +0100
++++ linux-mips/fs/jfs/jfs_imap.c       2005-03-26 11:47:36.085729244 +0100
+@@ -486,7 +486,6 @@
+       /* read the page of fixed disk inode (AIT) in raw mode */
+       mp = read_metapage(ip, address << sbi->l2nbperpage, PSIZE, 1);
+       if (mp == NULL) {
+-              ip->i_sb = NULL;
+               ip->i_nlink = 1;        /* Don't want iput() deleting it */
+               iput(ip);
+               return (NULL);
+@@ -499,7 +498,6 @@
+       /* copy on-disk inode to in-memory inode */
+       if ((copy_from_dinode(dp, ip)) != 0) {
+               /* handle bad return by returning NULL for ip */
+-              ip->i_sb = NULL;
+               ip->i_nlink = 1;        /* Don't want iput() deleting it */
+               iput(ip);
+               /* release the page */
+diff -Nur linux-2.4.29/fs/jfs/jfs_metapage.c linux-mips/fs/jfs/jfs_metapage.c
+--- linux-2.4.29/fs/jfs/jfs_metapage.c 2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/fs/jfs/jfs_metapage.c   2005-03-26 11:47:36.086729079 +0100
+@@ -298,14 +298,14 @@
+       mp = search_hash(hash_ptr, mapping, lblock);
+       if (mp) {
+             page_found:
+-              mp->count++;
+-              lock_metapage(mp);
+-              spin_unlock(&meta_lock);
+               if (test_bit(META_stale, &mp->flag)) {
+-                      release_metapage(mp);
+-                      yield();        /* Let other waiters release it, too */
++                      spin_unlock(&meta_lock);
++                      yield();
+                       goto again;
+               }
++              mp->count++;
++              lock_metapage(mp);
++              spin_unlock(&meta_lock);
+               if (test_bit(META_discard, &mp->flag)) {
+                       if (!new) {
+                               jfs_error(inode->i_sb,
+@@ -518,7 +518,6 @@
+       }
+       if (mp->page) {
+-              /* Releasing spinlock, we have to check mp->count later */
+               set_bit(META_stale, &mp->flag);
+               spin_unlock(&meta_lock);
+               kunmap(mp->page);
+@@ -555,12 +554,6 @@
+               list_del(&mp->synclist);
+               LOGSYNC_UNLOCK(log);
+       }
+-      if (mp->count) {
+-              /* Someone else is trying to get this metpage */
+-              unlock_metapage(mp);
+-              spin_unlock(&meta_lock);
+-              return;
+-      }
+       remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
+       spin_unlock(&meta_lock);
+@@ -589,12 +582,8 @@
+               mp = search_hash(hash_ptr, mapping, lblock);
+               if (mp) {
+                       if (test_bit(META_stale, &mp->flag)) {
+-                              /* Racing with release_metapage */
+-                              mp->count++;
+-                              lock_metapage(mp);
+                               spin_unlock(&meta_lock);
+-                              /* racing release_metapage should be done now */
+-                              release_metapage(mp);
++                              yield();
+                               goto again;
+                       }
+diff -Nur linux-2.4.29/fs/jfs/jfs_unicode.c linux-mips/fs/jfs/jfs_unicode.c
+--- linux-2.4.29/fs/jfs/jfs_unicode.c  2004-04-14 15:05:40.000000000 +0200
++++ linux-mips/fs/jfs/jfs_unicode.c    2005-03-26 11:47:36.089728587 +0100
+@@ -1,5 +1,5 @@
+ /*
+- *   Copyright (c) International Business Machines Corp., 2000-2002
++ *   Copyright (C) International Business Machines Corp., 2000-2005
+  *
+  *   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
+@@ -18,7 +18,7 @@
+ #include <linux/fs.h>
+ #include <linux/slab.h>
+-#include "jfs_types.h"
++#include "jfs_incore.h"
+ #include "jfs_filsys.h"
+ #include "jfs_unicode.h"
+ #include "jfs_debug.h"
+@@ -34,17 +34,40 @@
+ {
+       int i;
+       int outlen = 0;
++      static int warn_again = 5;      /* Only warn up to 5 times total */
++      int warn = !!warn_again;        /* once per string */
+-      for (i = 0; (i < len) && from[i]; i++) {
+-              int charlen;
+-              charlen =
+-                  codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
+-                                     NLS_MAX_CHARSET_SIZE);
+-              if (charlen > 0) {
+-                      outlen += charlen;
+-              } else {
+-                      to[outlen++] = '?';
++      if (codepage) {
++              for (i = 0; (i < len) && from[i]; i++) {
++                      int charlen;
++                      charlen =
++                          codepage->uni2char(le16_to_cpu(from[i]),
++                                             &to[outlen],
++                                             NLS_MAX_CHARSET_SIZE);
++                      if (charlen > 0)
++                              outlen += charlen;
++                      else
++                              to[outlen++] = '?';
+               }
++      } else {
++              for (i = 0; (i < len) && from[i]; i++) {
++                      if (le16_to_cpu(from[i]) & 0xff00) {
++                              if (warn) {
++                                      warn--;
++                                      warn_again--;
++                                      printk(KERN_ERR
++                      "non-latin1 character 0x%x found in JFS file name\n", 
++                                             le16_to_cpu(from[i]));
++                                      printk(KERN_ERR
++                              "mount with iocharset=utf8 to access\n");
++                              }
++                              to[i] = '?';
++                      }
++                      else
++                              to[i] = (char) (le16_to_cpu(from[i]));
++              }
++              outlen = i;
++
+       }
+       to[outlen] = 0;
+       return outlen;
+@@ -56,20 +79,27 @@
+  * FUNCTION:  Convert character string to unicode string
+  *
+  */
+-static int jfs_strtoUCS(wchar_t * to, const char *from, int len,
++static int jfs_strtoUCS(wchar_t * to, const unsigned char *from, int len,
+               struct nls_table *codepage)
+ {
+       int charlen;
+       int i;
+-      for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
+-              charlen = codepage->char2uni(from, len, &to[i]);
+-              if (charlen < 1) {
+-                      jfs_err("jfs_strtoUCS: char2uni returned %d.", charlen);
+-                      jfs_err("charset = %s, char = 0x%x",
+-                              codepage->charset, (unsigned char) *from);
+-                      return charlen;
++      if (codepage) {
++              for (i = 0; len && *from; i++, from += charlen, len -= charlen)
++              {
++                      charlen = codepage->char2uni(from, len, &to[i]);
++                      if (charlen < 1) {
++                              jfs_err("jfs_strtoUCS: char2uni returned %d.",
++                                      charlen);
++                              jfs_err("charset = %s, char = 0x%x",
++                                      codepage->charset, *from);
++                              return charlen;
++                      }
+               }
++      } else {
++              for (i = 0; (i < len) && from[i]; i++)
++                      to[i] = (wchar_t) from[i];
+       }
+       to[i] = 0;
+@@ -82,9 +112,9 @@
+  * FUNCTION:  Allocate and translate to unicode string
+  *
+  */
+-int get_UCSname(struct component_name * uniName, struct dentry *dentry,
+-              struct nls_table *nls_tab)
++int get_UCSname(struct component_name * uniName, struct dentry *dentry)
+ {
++      struct nls_table *nls_tab = JFS_SBI(dentry->d_sb)->nls_tab;
+       int length = dentry->d_name.len;
+       if (length > JFS_NAME_MAX)
+diff -Nur linux-2.4.29/fs/jfs/jfs_unicode.h linux-mips/fs/jfs/jfs_unicode.h
+--- linux-2.4.29/fs/jfs/jfs_unicode.h  2002-11-29 00:53:15.000000000 +0100
++++ linux-mips/fs/jfs/jfs_unicode.h    2005-03-26 11:47:36.095727603 +0100
+@@ -1,6 +1,6 @@
+ /*
+- *   Copyright (c) International Business Machines Corp., 2000-2002
+- *   Portions Copyright (c) Christoph Hellwig, 2001-2002
++ *   Copyright (C) International Business Machines Corp., 2000-2002
++ *   Portions Copyright (C) Christoph Hellwig, 2001-2002
+  *
+  *   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
+@@ -30,8 +30,7 @@
+ extern signed char UniUpperTable[512];
+ extern UNICASERANGE UniUpperRange[];
+-extern int get_UCSname(struct component_name *, struct dentry *,
+-                     struct nls_table *);
++extern int get_UCSname(struct component_name *, struct dentry *);
+ extern int jfs_strfromUCS_le(char *, const wchar_t *, int, struct nls_table *);
+ #define free_UCSname(COMP) kfree((COMP)->name)
+diff -Nur linux-2.4.29/fs/jfs/namei.c linux-mips/fs/jfs/namei.c
+--- linux-2.4.29/fs/jfs/namei.c        2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/fs/jfs/namei.c  2005-03-26 11:47:36.096727438 +0100
+@@ -74,7 +74,7 @@
+        * search parent directory for entry/freespace
+        * (dtSearch() returns parent directory page pinned)
+        */
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out1;
+       /*
+@@ -195,7 +195,7 @@
+        * search parent directory for entry/freespace
+        * (dtSearch() returns parent directory page pinned)
+        */
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out1;
+       /*
+@@ -318,9 +318,8 @@
+               goto out;
+       }
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab))) {
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out;
+-      }
+       tid = txBegin(dip->i_sb, 0);
+@@ -437,7 +436,7 @@
+       jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out;
+       IWRITE_LOCK(ip);
+@@ -780,7 +779,7 @@
+       /*
+        * scan parent directory for entry/freespace
+        */
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(ip->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out;
+       if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE)))
+@@ -865,7 +864,7 @@
+        * (dtSearch() returns parent directory page pinned)
+        */
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out1;
+       /*
+@@ -1044,12 +1043,10 @@
+       old_ip = old_dentry->d_inode;
+       new_ip = new_dentry->d_inode;
+-      if ((rc = get_UCSname(&old_dname, old_dentry,
+-                            JFS_SBI(old_dir->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&old_dname, old_dentry)))
+               goto out1;
+-      if ((rc = get_UCSname(&new_dname, new_dentry,
+-                            JFS_SBI(old_dir->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&new_dname, new_dentry)))
+               goto out2;
+       /*
+@@ -1301,7 +1298,7 @@
+       jfs_info("jfs_mknod: %s", dentry->d_name.name);
+-      if ((rc = get_UCSname(&dname, dentry, JFS_SBI(dir->i_sb)->nls_tab)))
++      if ((rc = get_UCSname(&dname, dentry)))
+               goto out;
+       ip = ialloc(dir, mode);
+@@ -1376,8 +1373,7 @@
+       else if (strcmp(name, "..") == 0)
+               inum = PARENT(dip);
+       else {
+-              if ((rc =
+-                   get_UCSname(&key, dentry, JFS_SBI(dip->i_sb)->nls_tab)))
++              if ((rc = get_UCSname(&key, dentry)))
+                       return ERR_PTR(rc);
+               rc = dtSearch(dip, &key, &inum, &btstack, JFS_LOOKUP);
+               free_UCSname(&key);
+diff -Nur linux-2.4.29/fs/jfs/super.c linux-mips/fs/jfs/super.c
+--- linux-2.4.29/fs/jfs/super.c        2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/fs/jfs/super.c  2005-03-26 11:47:36.101726618 +0100
+@@ -1,5 +1,5 @@
+ /*
+- *   Copyright (C) International Business Machines Corp., 2000-2003
++ *   Copyright (C) International Business Machines Corp., 2000-2005
+  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
+  *
+  *   This program is free software;  you can redistribute it and/or modify
+@@ -155,8 +155,10 @@
+       rc = jfs_umount(sb);
+       if (rc)
+               jfs_err("jfs_umount failed with return code %d", rc);
+-      unload_nls(sbi->nls_tab);
+-      sbi->nls_tab = NULL;
++      if (sbi->nls_tab) {
++              unload_nls(sbi->nls_tab);
++              sbi->nls_tab = NULL;
++      }
+       kfree(sbi);
+ }
+@@ -182,7 +184,7 @@
+ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
+                        int *flag)
+ {
+-      void *nls_map = NULL;
++      void *nls_map = (void *)-1;     /* -1: no change;  NULL: none */
+       char *this_char;
+       char *value;
+       struct jfs_sb_info *sbi = JFS_SBI(sb);
+@@ -222,13 +224,12 @@
+               } else if (!strcmp(this_char, "iocharset")) {
+                       if (!value || !*value)
+                               goto needs_arg;
+-                      if (nls_map)    /* specified iocharset twice! */
++                      if (nls_map && nls_map != (void *) -1)
+                               unload_nls(nls_map);
+-                      nls_map = load_nls(value);
+-                      if (!nls_map) {
+-                              printk(KERN_ERR "JFS: charset not found\n");
+-                              goto cleanup;
+-                      }
++                      if (!strcmp(value, "none"))
++                              nls_map = NULL;
++                      else
++                              nls_map = load_nls(value);
+               } else if (!strcmp(this_char, "resize")) {
+                       if (!value || !*value) {
+                               *newLVSize = jfs_get_volume_size(sb);
+@@ -250,9 +251,9 @@
+                       goto cleanup;
+               }
        }
-       /* Flush all traces of the currently running executable */
-@@ -1208,7 +1211,11 @@
-       elf.e_entry = 0;
-       elf.e_phoff = sizeof(elf);
-       elf.e_shoff = 0;
-+#ifdef ELF_CORE_EFLAGS
-+      elf.e_flags = ELF_CORE_EFLAGS;
-+#else
-       elf.e_flags = 0;
-+#endif
-       elf.e_ehsize = sizeof(elf);
-       elf.e_phentsize = sizeof(struct elf_phdr);
-       elf.e_phnum = segs+1;           /* Include notes */
+-      if (nls_map) {
++      if (nls_map != (void *) -1) {
+               /* Discard old (if remount) */
+-              if (sbi->nls_tab)
++              if (sbi->nls_tab && sbi->nls_tab != (void *) -1)
+                       unload_nls(sbi->nls_tab);
+               sbi->nls_tab = nls_map;
+       }
+@@ -260,7 +261,7 @@
+ needs_arg:
+       printk(KERN_ERR "JFS: %s needs an argument\n", this_char);
+ cleanup:
+-      if (nls_map)
++      if (nls_map && nls_map != (void *) -1)
+               unload_nls(nls_map);
+       return 0;
+ }
+@@ -328,6 +329,8 @@
+       /* initialize the mount flag and determine the default error handler */
+       flag = JFS_ERR_REMOUNT_RO;
++      /* nls_tab will be set to NULL if no character mapping is requested */
++      sbi->nls_tab = (void *) -1;
+       if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
+               kfree(sbi);
+               return NULL;
+@@ -378,7 +381,7 @@
+       if (!sb->s_root)
+               goto out_no_root;
+-      if (!sbi->nls_tab)
++      if (sbi->nls_tab == (void *) -1)
+               sbi->nls_tab = load_nls_default();
+       /* logical blocks are represented by 40 bits in pxd_t, etc. */
+diff -Nur linux-2.4.29/fs/nfsd/vfs.c linux-mips/fs/nfsd/vfs.c
+--- linux-2.4.29/fs/nfsd/vfs.c 2004-11-17 12:54:21.000000000 +0100
++++ linux-mips/fs/nfsd/vfs.c   2005-03-26 11:47:36.103726290 +0100
+@@ -466,6 +466,8 @@
+       atomic_set(&filp->f_count, 1);
+       filp->f_dentry = dentry;
+       filp->f_vfsmnt = fhp->fh_export->ex_mnt;
++      filp->f_maxcount = INT_MAX;
++
+       if (access & MAY_WRITE) {
+               filp->f_flags = O_WRONLY|O_LARGEFILE;
+               filp->f_mode  = FMODE_WRITE;
 diff -Nur linux-2.4.29/fs/partitions/sgi.c linux-mips/fs/partitions/sgi.c
 --- linux-2.4.29/fs/partitions/sgi.c   2001-10-02 05:03:26.000000000 +0200
 +++ linux-mips/fs/partitions/sgi.c     2004-08-11 22:30:07.000000000 +0200
@@ -21914,6 +33760,48 @@ diff -Nur linux-2.4.29/fs/proc/array.c linux-mips/fs/proc/array.c
  
        return len;
  }
+diff -Nur linux-2.4.29/fs/proc/kcore.c linux-mips/fs/proc/kcore.c
+--- linux-2.4.29/fs/proc/kcore.c       2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/fs/proc/kcore.c 2005-03-26 11:47:36.107725633 +0100
+@@ -136,7 +136,10 @@
+       }
+       *elf_buflen =   sizeof(struct elfhdr) + 
+                       (*num_vma + 2)*sizeof(struct elf_phdr) + 
+-                      3 * sizeof(struct memelfnote);
++                      3 * (sizeof(struct elf_note) + 4) +
++                      sizeof(struct elf_prstatus) +
++                      sizeof(struct elf_prpsinfo) +
++                      sizeof(struct task_struct);
+       *elf_buflen = PAGE_ALIGN(*elf_buflen);
+       return (size - PAGE_OFFSET + *elf_buflen);
+ }
+@@ -279,7 +282,7 @@
+       memset(&prstatus, 0, sizeof(struct elf_prstatus));
+-      nhdr->p_filesz  = notesize(&notes[0]);
++      nhdr->p_filesz += notesize(&notes[0]);
+       bufp = storenote(&notes[0], bufp);
+       /* set up the process info */
+@@ -296,7 +299,7 @@
+       strcpy(prpsinfo.pr_fname, "vmlinux");
+       strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
+-      nhdr->p_filesz  = notesize(&notes[1]);
++      nhdr->p_filesz += notesize(&notes[1]);
+       bufp = storenote(&notes[1], bufp);
+       /* set up the task structure */
+@@ -305,7 +308,7 @@
+       notes[2].datasz = sizeof(struct task_struct);
+       notes[2].data   = current;
+-      nhdr->p_filesz  = notesize(&notes[2]);
++      nhdr->p_filesz += notesize(&notes[2]);
+       bufp = storenote(&notes[2], bufp);
+ } /* end elf_kcore_store_hdr() */
 diff -Nur linux-2.4.29/fs/proc/proc_misc.c linux-mips/fs/proc/proc_misc.c
 --- linux-2.4.29/fs/proc/proc_misc.c   2004-08-08 01:26:06.000000000 +0200
 +++ linux-mips/fs/proc/proc_misc.c     2004-08-14 20:39:01.000000000 +0200
@@ -21953,6 +33841,128 @@ diff -Nur linux-2.4.29/fs/proc/proc_misc.c linux-mips/fs/proc/proc_misc.c
                                   + kstat.per_cpu_nice[cpu_logical_map(i)] \
                                   + kstat.per_cpu_system[cpu_logical_map(i)]));
        proc_sprintf(page, &off, &len,
+diff -Nur linux-2.4.29/fs/proc/proc_tty.c linux-mips/fs/proc/proc_tty.c
+--- linux-2.4.29/fs/proc/proc_tty.c    2005-01-19 15:10:11.000000000 +0100
++++ linux-mips/fs/proc/proc_tty.c      2005-03-26 11:47:36.107725633 +0100
+@@ -129,7 +129,7 @@
+ }
+ /*
+- * Thsi function is called by register_tty_driver() to handle
++ * This function is called by tty_register_driver() to handle
+  * registering the driver's /proc handler into /proc/tty/driver/<foo>
+  */
+ void proc_tty_register_driver(struct tty_driver *driver)
+@@ -152,7 +152,7 @@
+ }
+ /*
+- * This function is called by unregister_tty_driver()
++ * This function is called by tty_unregister_driver()
+  */
+ void proc_tty_unregister_driver(struct tty_driver *driver)
+ {
+diff -Nur linux-2.4.29/fs/read_write.c linux-mips/fs/read_write.c
+--- linux-2.4.29/fs/read_write.c       2003-08-25 13:44:43.000000000 +0200
++++ linux-mips/fs/read_write.c 2005-03-26 11:47:36.064732690 +0100
+@@ -40,6 +40,28 @@
+       return -EISDIR;
+ }
++int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count)
++{
++      struct inode *inode;
++      loff_t pos;
++
++      if (unlikely(count > file->f_maxcount))
++              goto Einval;
++
++      pos = *ppos;
++
++      if (unlikely((pos < 0) || (loff_t) (pos + count) < 0))
++              goto Einval;
++
++      inode = file->f_dentry->d_inode;
++      if (inode->i_flock && MANDATORY_LOCK(inode))
++              return locks_mandatory_area(read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, inode, file, *ppos, count);
++      return 0;
++
++Einval:
++      return -EINVAL;
++}
++
+ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
+ {
+       long long retval;
+@@ -168,8 +190,8 @@
+       file = fget(fd);
+       if (file) {
+               if (file->f_mode & FMODE_READ) {
+-                      ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+-                                              file, file->f_pos, count);
++                      ret = rw_verify_area(READ, file, &file->f_pos, count);
++
+                       if (!ret) {
+                               ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+                               ret = -EINVAL;
+@@ -193,9 +215,7 @@
+       file = fget(fd);
+       if (file) {
+               if (file->f_mode & FMODE_WRITE) {
+-                      struct inode *inode = file->f_dentry->d_inode;
+-                      ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+-                              file->f_pos, count);
++                      ret = rw_verify_area(WRITE, file, &file->f_pos, count);
+                       if (!ret) {
+                               ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+                               ret = -EINVAL;
+@@ -224,7 +244,6 @@
+       ssize_t ret, i;
+       io_fn_t fn;
+       iov_fn_t fnv;
+-      struct inode *inode;
+       /*
+        * First get the "struct iovec" from user memory and
+@@ -275,12 +294,11 @@
+                       goto out;
+       }
+-      inode = file->f_dentry->d_inode;
+       /* VERIFY_WRITE actually means a read, as we write to user space */
+-      ret = locks_verify_area((type == VERIFY_WRITE
+-                               ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+-                              inode, file, file->f_pos, tot_len);
+-      if (ret) goto out;
++      ret = rw_verify_area((type == VERIFY_WRITE ? READ : WRITE),
++                              file, &file->f_pos, tot_len);
++      if (ret) 
++              goto out;
+       fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
+       if (fnv) {
+@@ -383,8 +401,8 @@
+               goto bad_file;
+       if (!(file->f_mode & FMODE_READ))
+               goto out;
+-      ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+-                              file, pos, count);
++      ret = rw_verify_area(READ, file, &pos, count);
++
+       if (ret)
+               goto out;
+       ret = -EINVAL;
+@@ -414,8 +432,8 @@
+               goto bad_file;
+       if (!(file->f_mode & FMODE_WRITE))
+               goto out;
+-      ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+-                              file, pos, count);
++      ret = rw_verify_area(WRITE, file, &pos, count);
++
+       if (ret)
+               goto out;
+       ret = -EINVAL;
 diff -Nur linux-2.4.29/include/asm-alpha/param.h linux-mips/include/asm-alpha/param.h
 --- linux-2.4.29/include/asm-alpha/param.h     2000-11-08 08:37:31.000000000 +0100
 +++ linux-mips/include/asm-alpha/param.h       2000-11-28 04:59:03.000000000 +0100
@@ -21966,6 +33976,18 @@ diff -Nur linux-2.4.29/include/asm-alpha/param.h linux-mips/include/asm-alpha/pa
  #endif
  
  #define EXEC_PAGESIZE 8192
+diff -Nur linux-2.4.29/include/asm-i386/acpi.h linux-mips/include/asm-i386/acpi.h
+--- linux-2.4.29/include/asm-i386/acpi.h       2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/include/asm-i386/acpi.h 2005-03-26 11:47:36.177714147 +0100
+@@ -121,6 +121,8 @@
+ extern int acpi_strict;
+ extern int acpi_disabled;
+ extern int acpi_ht;
++extern int acpi_skip_timer_override;
++void __init check_acpi_pci(void);
+ static inline void disable_acpi(void) 
+ { 
+       acpi_disabled = 1;
 diff -Nur linux-2.4.29/include/asm-i386/param.h linux-mips/include/asm-i386/param.h
 --- linux-2.4.29/include/asm-i386/param.h      2000-10-27 20:04:43.000000000 +0200
 +++ linux-mips/include/asm-i386/param.h        2000-11-23 03:00:55.000000000 +0100
@@ -21979,6 +34001,11 @@ diff -Nur linux-2.4.29/include/asm-i386/param.h linux-mips/include/asm-i386/para
  #endif
  
  #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.29/include/asm-i386/pci-direct.h linux-mips/include/asm-i386/pci-direct.h
+--- linux-2.4.29/include/asm-i386/pci-direct.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/include/asm-i386/pci-direct.h   2005-03-18 13:13:30.000000000 +0100
+@@ -0,0 +1 @@
++#include "asm-x86_64/pci-direct.h"
 diff -Nur linux-2.4.29/include/asm-ia64/param.h linux-mips/include/asm-ia64/param.h
 --- linux-2.4.29/include/asm-ia64/param.h      2004-04-14 15:05:40.000000000 +0200
 +++ linux-mips/include/asm-ia64/param.h        2004-04-16 05:14:20.000000000 +0200
@@ -22012,6 +34039,124 @@ diff -Nur linux-2.4.29/include/asm-m68k/param.h linux-mips/include/asm-m68k/para
  #endif
  
  #define EXEC_PAGESIZE 8192
+diff -Nur linux-2.4.29/include/asm-mips/au1000_gpio.h linux-mips/include/asm-mips/au1000_gpio.h
+--- linux-2.4.29/include/asm-mips/au1000_gpio.h        2002-11-29 00:53:15.000000000 +0100
++++ linux-mips/include/asm-mips/au1000_gpio.h  2005-01-31 12:59:48.000000000 +0100
+@@ -30,6 +30,13 @@
+  *  675 Mass Ave, Cambridge, MA 02139, USA.
+  */
++/*
++ *  Revision history
++ *    01/31/02  0.01   Initial release. Steve Longerbeam, MontaVista
++ *    10/12/03  0.1    Added Au1100/Au1500, GPIO2, and bit operations. K.C. Nishio, AMD
++ *    08/05/04  0.11   Added Au1550 and Au1200. K.C. Nishio
++ */
++
+ #ifndef __AU1000_GPIO_H
+ #define __AU1000_GPIO_H
+@@ -44,13 +51,94 @@
+ #define AU1000GPIO_TRISTATE   _IOW (AU1000GPIO_IOC_MAGIC, 4, int)
+ #define AU1000GPIO_AVAIL_MASK _IOR (AU1000GPIO_IOC_MAGIC, 5, int)
++// bit operations
++#define AU1000GPIO_BIT_READ   _IOW (AU1000GPIO_IOC_MAGIC, 6, int)
++#define AU1000GPIO_BIT_SET    _IOW (AU1000GPIO_IOC_MAGIC, 7, int)
++#define AU1000GPIO_BIT_CLEAR  _IOW (AU1000GPIO_IOC_MAGIC, 8, int)
++#define AU1000GPIO_BIT_TRISTATE       _IOW (AU1000GPIO_IOC_MAGIC, 9, int)
++#define AU1000GPIO_BIT_INIT   _IOW (AU1000GPIO_IOC_MAGIC, 10, int)
++#define AU1000GPIO_BIT_TERM   _IOW (AU1000GPIO_IOC_MAGIC, 11, int)
++
++/* set this major numer same as the CRIS GPIO driver */
++#define AU1X00_GPIO_MAJOR     (120)
++
++#define ENABLED_ZERO          (0)
++#define ENABLED_ONE           (1)
++#define ENABLED_10            (0x2)
++#define ENABLED_11            (0x3)
++#define ENABLED_111           (0x7)
++#define NOT_AVAIL             (-1)
++#define AU1X00_MAX_PRIMARY_GPIO       (32) 
++
++#define AU1000_GPIO_MINOR_MAX AU1X00_MAX_PRIMARY_GPIO
++/* Au1100, 1500, 1550 and 1200 have the secondary GPIO block */
++#define AU1XX0_GPIO_MINOR_MAX (48)
++
++#define AU1X00_GPIO_NAME      "gpio"
++
++/* GPIO pins which are not multiplexed */
++#if defined(CONFIG_SOC_AU1000)
++  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
++  #define NATIVE_GPIO2PIN     (0)
++#elif defined(CONFIG_SOC_AU1100)
++  #define NATIVE_GPIOPIN      ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) | (1 << 18) | \
++                               (1 << 17) | (1 << 16) | (1 << 7) | (1 << 1) | (1 << 0))
++  #define NATIVE_GPIO2PIN     (0)
++#elif defined(CONFIG_SOC_AU1500)
++  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
++  /* exclude the PCI reset output signal: GPIO[200], DMA_REQ2 and DMA_REQ3 */
++  #define NATIVE_GPIO2PIN     (0xfffe & ~((1 << 9) | (1 << 8))) 
++#elif defined(CONFIG_SOC_AU1550)
++  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 1) | (1 << 0))
++  /* please refere Au1550 Data Book, chapter 15 */
++  #define NATIVE_GPIO2PIN     (1 << 5) 
++#elif defined(CONFIG_SOC_AU1200)
++  #define NATIVE_GPIOPIN      ((1 << 7) | (1 << 5))
++  #define NATIVE_GPIO2PIN     (0) 
++#endif
++
++/* minor as u32 */
++#define MINOR_TO_GPIOPIN(minor)               ((minor < AU1X00_MAX_PRIMARY_GPIO) ? minor : (minor - AU1X00_MAX_PRIMARY_GPIO))
++#define IS_PRIMARY_GPIOPIN(minor)     ((minor < AU1X00_MAX_PRIMARY_GPIO) ? 1 : 0)
++
++/*
++ * pin to minor mapping.
++ * GPIO0-GPIO31, minor=0-31.
++ * GPIO200-GPIO215, minor=32-47.
++ */
++typedef struct _au1x00_gpio_bit_ctl {
++      int direction;  // The direction of this GPIO pin. 0: IN, 1: OUT.
++      int data;       // Pin output when itized (0/1), or at the term. 0/1/-1 (tristate).
++} au1x00_gpio_bit_ctl;
++
++typedef struct _au1x00_gpio_driver {
++      const char      *driver_name;
++      const char      *name;
++      int             name_base;      /* offset of printed name */
++      short           major;          /* major device number */
++      short           minor_start;    /* start of minor device number*/
++      short           num;            /* number of devices */
++} au1x00_gpio_driver;
++
+ #ifdef __KERNEL__
+-extern u32 get_au1000_avail_gpio_mask(void);
+-extern int au1000gpio_tristate(u32 data);
+-extern int au1000gpio_in(u32 *data);
+-extern int au1000gpio_set(u32 data);
+-extern int au1000gpio_clear(u32 data);
+-extern int au1000gpio_out(u32 data);
++extern u32 get_au1000_avail_gpio_mask(u32 *avail_gpio2);
++extern int au1000gpio_tristate(u32 minor, u32 data);
++extern int au1000gpio_in(u32 minor, u32 *data);
++extern int au1000gpio_set(u32 minor, u32 data);
++extern int au1000gpio_clear(u32 minor, u32 data);
++extern int au1000gpio_out(u32 minor, u32 data);
++extern int au1000gpio_bit_read(u32 minor, u32 *read_data);
++extern int au1000gpio_bit_set(u32 minor);
++extern int au1000gpio_bit_clear(u32 minor);
++extern int au1000gpio_bit_tristate(u32 minor);
++extern int check_minor_to_gpio(u32 minor);
++extern int au1000gpio_bit_init(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
++extern int au1000gpio_bit_term(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
++
++extern void gpio_register_devfs (au1x00_gpio_driver *driver, unsigned int flags, unsigned minor);
++extern void gpio_unregister_devfs (au1x00_gpio_driver *driver, unsigned minor);
++extern int gpio_register_driver(au1x00_gpio_driver *driver);
++extern int gpio_unregister_driver(au1x00_gpio_driver *driver);
+ #endif
+ #endif
 diff -Nur linux-2.4.29/include/asm-mips/au1000.h linux-mips/include/asm-mips/au1000.h
 --- linux-2.4.29/include/asm-mips/au1000.h     2005-01-19 15:10:11.000000000 +0100
 +++ linux-mips/include/asm-mips/au1000.h       2005-01-31 12:59:48.000000000 +0100
@@ -22661,145 +34806,27 @@ diff -Nur linux-2.4.29/include/asm-mips/au1000.h linux-mips/include/asm-mips/au1
 +#define outputset outputrd
 +      /* 0x010C */ u32 outputclr;
 +      /* 0x0110 */ u32 pinstaterd;
-+#define pininputen pinstaterd
-+
-+} AU1X00_SYS;
-+
-+static AU1X00_SYS* const sys  = (AU1X00_SYS *)SYS_BASE;
-+
-+#endif
- /* Processor information base on prid.
-  * Copied from PowerPC.
-  */
-+#ifndef _LANGUAGE_ASSEMBLY
- struct cpu_spec {
-       /* CPU is matched via (PRID & prid_mask) == prid_value */
-       unsigned int    prid_mask;
-@@ -1404,3 +1849,6 @@
- extern struct cpu_spec                cpu_specs[];
- extern struct cpu_spec                *cur_cpu_spec[];
- #endif
-+
-+#endif
-+
-diff -Nur linux-2.4.29/include/asm-mips/au1000_gpio.h linux-mips/include/asm-mips/au1000_gpio.h
---- linux-2.4.29/include/asm-mips/au1000_gpio.h        2002-11-29 00:53:15.000000000 +0100
-+++ linux-mips/include/asm-mips/au1000_gpio.h  2005-01-31 12:59:48.000000000 +0100
-@@ -30,6 +30,13 @@
-  *  675 Mass Ave, Cambridge, MA 02139, USA.
-  */
-+/*
-+ *  Revision history
-+ *    01/31/02  0.01   Initial release. Steve Longerbeam, MontaVista
-+ *    10/12/03  0.1    Added Au1100/Au1500, GPIO2, and bit operations. K.C. Nishio, AMD
-+ *    08/05/04  0.11   Added Au1550 and Au1200. K.C. Nishio
-+ */
-+
- #ifndef __AU1000_GPIO_H
- #define __AU1000_GPIO_H
-@@ -44,13 +51,94 @@
- #define AU1000GPIO_TRISTATE   _IOW (AU1000GPIO_IOC_MAGIC, 4, int)
- #define AU1000GPIO_AVAIL_MASK _IOR (AU1000GPIO_IOC_MAGIC, 5, int)
-+// bit operations
-+#define AU1000GPIO_BIT_READ   _IOW (AU1000GPIO_IOC_MAGIC, 6, int)
-+#define AU1000GPIO_BIT_SET    _IOW (AU1000GPIO_IOC_MAGIC, 7, int)
-+#define AU1000GPIO_BIT_CLEAR  _IOW (AU1000GPIO_IOC_MAGIC, 8, int)
-+#define AU1000GPIO_BIT_TRISTATE       _IOW (AU1000GPIO_IOC_MAGIC, 9, int)
-+#define AU1000GPIO_BIT_INIT   _IOW (AU1000GPIO_IOC_MAGIC, 10, int)
-+#define AU1000GPIO_BIT_TERM   _IOW (AU1000GPIO_IOC_MAGIC, 11, int)
-+
-+/* set this major numer same as the CRIS GPIO driver */
-+#define AU1X00_GPIO_MAJOR     (120)
-+
-+#define ENABLED_ZERO          (0)
-+#define ENABLED_ONE           (1)
-+#define ENABLED_10            (0x2)
-+#define ENABLED_11            (0x3)
-+#define ENABLED_111           (0x7)
-+#define NOT_AVAIL             (-1)
-+#define AU1X00_MAX_PRIMARY_GPIO       (32) 
++#define pininputen pinstaterd
 +
-+#define AU1000_GPIO_MINOR_MAX AU1X00_MAX_PRIMARY_GPIO
-+/* Au1100, 1500, 1550 and 1200 have the secondary GPIO block */
-+#define AU1XX0_GPIO_MINOR_MAX (48)
++} AU1X00_SYS;
 +
-+#define AU1X00_GPIO_NAME      "gpio"
++static AU1X00_SYS* const sys  = (AU1X00_SYS *)SYS_BASE;
 +
-+/* GPIO pins which are not multiplexed */
-+#if defined(CONFIG_SOC_AU1000)
-+  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
-+  #define NATIVE_GPIO2PIN     (0)
-+#elif defined(CONFIG_SOC_AU1100)
-+  #define NATIVE_GPIOPIN      ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) | (1 << 18) | \
-+                               (1 << 17) | (1 << 16) | (1 << 7) | (1 << 1) | (1 << 0))
-+  #define NATIVE_GPIO2PIN     (0)
-+#elif defined(CONFIG_SOC_AU1500)
-+  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
-+  /* exclude the PCI reset output signal: GPIO[200], DMA_REQ2 and DMA_REQ3 */
-+  #define NATIVE_GPIO2PIN     (0xfffe & ~((1 << 9) | (1 << 8))) 
-+#elif defined(CONFIG_SOC_AU1550)
-+  #define NATIVE_GPIOPIN      ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 1) | (1 << 0))
-+  /* please refere Au1550 Data Book, chapter 15 */
-+  #define NATIVE_GPIO2PIN     (1 << 5) 
-+#elif defined(CONFIG_SOC_AU1200)
-+  #define NATIVE_GPIOPIN      ((1 << 7) | (1 << 5))
-+  #define NATIVE_GPIO2PIN     (0) 
 +#endif
+ /* Processor information base on prid.
+  * Copied from PowerPC.
+  */
++#ifndef _LANGUAGE_ASSEMBLY
+ struct cpu_spec {
+       /* CPU is matched via (PRID & prid_mask) == prid_value */
+       unsigned int    prid_mask;
+@@ -1404,3 +1849,6 @@
+ extern struct cpu_spec                cpu_specs[];
+ extern struct cpu_spec                *cur_cpu_spec[];
+ #endif
 +
-+/* minor as u32 */
-+#define MINOR_TO_GPIOPIN(minor)               ((minor < AU1X00_MAX_PRIMARY_GPIO) ? minor : (minor - AU1X00_MAX_PRIMARY_GPIO))
-+#define IS_PRIMARY_GPIOPIN(minor)     ((minor < AU1X00_MAX_PRIMARY_GPIO) ? 1 : 0)
-+
-+/*
-+ * pin to minor mapping.
-+ * GPIO0-GPIO31, minor=0-31.
-+ * GPIO200-GPIO215, minor=32-47.
-+ */
-+typedef struct _au1x00_gpio_bit_ctl {
-+      int direction;  // The direction of this GPIO pin. 0: IN, 1: OUT.
-+      int data;       // Pin output when itized (0/1), or at the term. 0/1/-1 (tristate).
-+} au1x00_gpio_bit_ctl;
-+
-+typedef struct _au1x00_gpio_driver {
-+      const char      *driver_name;
-+      const char      *name;
-+      int             name_base;      /* offset of printed name */
-+      short           major;          /* major device number */
-+      short           minor_start;    /* start of minor device number*/
-+      short           num;            /* number of devices */
-+} au1x00_gpio_driver;
-+
- #ifdef __KERNEL__
--extern u32 get_au1000_avail_gpio_mask(void);
--extern int au1000gpio_tristate(u32 data);
--extern int au1000gpio_in(u32 *data);
--extern int au1000gpio_set(u32 data);
--extern int au1000gpio_clear(u32 data);
--extern int au1000gpio_out(u32 data);
-+extern u32 get_au1000_avail_gpio_mask(u32 *avail_gpio2);
-+extern int au1000gpio_tristate(u32 minor, u32 data);
-+extern int au1000gpio_in(u32 minor, u32 *data);
-+extern int au1000gpio_set(u32 minor, u32 data);
-+extern int au1000gpio_clear(u32 minor, u32 data);
-+extern int au1000gpio_out(u32 minor, u32 data);
-+extern int au1000gpio_bit_read(u32 minor, u32 *read_data);
-+extern int au1000gpio_bit_set(u32 minor);
-+extern int au1000gpio_bit_clear(u32 minor);
-+extern int au1000gpio_bit_tristate(u32 minor);
-+extern int check_minor_to_gpio(u32 minor);
-+extern int au1000gpio_bit_init(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
-+extern int au1000gpio_bit_term(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
++#endif
 +
-+extern void gpio_register_devfs (au1x00_gpio_driver *driver, unsigned int flags, unsigned minor);
-+extern void gpio_unregister_devfs (au1x00_gpio_driver *driver, unsigned minor);
-+extern int gpio_register_driver(au1x00_gpio_driver *driver);
-+extern int gpio_unregister_driver(au1x00_gpio_driver *driver);
- #endif
- #endif
 diff -Nur linux-2.4.29/include/asm-mips/au1000_pcmcia.h linux-mips/include/asm-mips/au1000_pcmcia.h
 --- linux-2.4.29/include/asm-mips/au1000_pcmcia.h      2005-01-19 15:10:11.000000000 +0100
 +++ linux-mips/include/asm-mips/au1000_pcmcia.h        2005-01-31 12:59:48.000000000 +0100
@@ -23808,7 +35835,7 @@ diff -Nur linux-2.4.29/include/asm-mips/hazards.h linux-mips/include/asm-mips/ha
  #endif /* _ASM_HAZARDS_H */
 diff -Nur linux-2.4.29/include/asm-mips/mipsregs.h linux-mips/include/asm-mips/mipsregs.h
 --- linux-2.4.29/include/asm-mips/mipsregs.h   2005-01-19 15:10:12.000000000 +0100
-+++ linux-mips/include/asm-mips/mipsregs.h     2005-02-12 04:07:58.000000000 +0100
++++ linux-mips/include/asm-mips/mipsregs.h     2005-03-26 11:47:36.210708732 +0100
 @@ -757,10 +757,18 @@
  #define read_c0_config1()     __read_32bit_c0_register($16, 1)
  #define read_c0_config2()     __read_32bit_c0_register($16, 2)
@@ -24708,7 +36735,7 @@ diff -Nur linux-2.4.29/include/asm-mips64/hazards.h linux-mips/include/asm-mips6
  #endif /* _ASM_HAZARDS_H */
 diff -Nur linux-2.4.29/include/asm-mips64/mipsregs.h linux-mips/include/asm-mips64/mipsregs.h
 --- linux-2.4.29/include/asm-mips64/mipsregs.h 2005-01-19 15:10:12.000000000 +0100
-+++ linux-mips/include/asm-mips64/mipsregs.h   2005-02-12 04:08:02.000000000 +0100
++++ linux-mips/include/asm-mips64/mipsregs.h   2005-03-26 11:47:36.406676569 +0100
 @@ -757,10 +757,18 @@
  #define read_c0_config1()     __read_32bit_c0_register($16, 1)
  #define read_c0_config2()     __read_32bit_c0_register($16, 2)
@@ -24868,6 +36895,18 @@ diff -Nur linux-2.4.29/include/asm-ppc/param.h linux-mips/include/asm-ppc/param.
  #endif
  
  #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.29/include/asm-ppc/processor.h linux-mips/include/asm-ppc/processor.h
+--- linux-2.4.29/include/asm-ppc/processor.h   2004-04-14 15:05:40.000000000 +0200
++++ linux-mips/include/asm-ppc/processor.h     2005-03-26 11:47:36.510659503 +0100
+@@ -678,7 +678,7 @@
+ #define PVR_440GP_RC2 0x40200481
+ #define PVR_440GX_RA  0x51b21850
+ #define PVR_440GX_RB  0x51b21851
+-#define PVR_440GX_RB1 0x51b21852
++#define PVR_440GX_RC  0x51b21892
+ #define       PVR_601         0x00010000
+ #define       PVR_602         0x00050000
+ #define       PVR_603         0x00030000
 diff -Nur linux-2.4.29/include/asm-s390/param.h linux-mips/include/asm-s390/param.h
 --- linux-2.4.29/include/asm-s390/param.h      2001-02-13 23:13:44.000000000 +0100
 +++ linux-mips/include/asm-s390/param.h        2001-03-09 21:34:48.000000000 +0100
@@ -24907,19 +36946,681 @@ diff -Nur linux-2.4.29/include/asm-sparc/param.h linux-mips/include/asm-sparc/pa
  #endif
  
  #define EXEC_PAGESIZE 8192    /* Thanks for sun4's we carry baggage... */
+diff -Nur linux-2.4.29/include/asm-sparc/system.h linux-mips/include/asm-sparc/system.h
+--- linux-2.4.29/include/asm-sparc/system.h    2004-02-18 14:36:32.000000000 +0100
++++ linux-mips/include/asm-sparc/system.h      2005-03-26 11:47:36.945588121 +0100
+@@ -295,11 +295,11 @@
+ #define wmb() mb()
+ #define set_mb(__var, __value)  do { __var = __value; mb(); } while(0)
+ #define set_wmb(__var, __value) set_mb(__var, __value)
+-#define smp_mb()      __asm__ __volatile__("":::"memory");
+-#define smp_rmb()     __asm__ __volatile__("":::"memory");
+-#define smp_wmb()     __asm__ __volatile__("":::"memory");
++#define smp_mb()      __asm__ __volatile__("":::"memory")
++#define smp_rmb()     __asm__ __volatile__("":::"memory")
++#define smp_wmb()     __asm__ __volatile__("":::"memory")
+-#define nop() __asm__ __volatile__ ("nop");
++#define nop() __asm__ __volatile__ ("nop")
+ /* This has special calling conventions */
+ #ifndef CONFIG_SMP
+diff -Nur linux-2.4.29/include/asm-sparc64/atomic.h linux-mips/include/asm-sparc64/atomic.h
+--- linux-2.4.29/include/asm-sparc64/atomic.h  2001-07-20 03:11:13.000000000 +0200
++++ linux-mips/include/asm-sparc64/atomic.h    2005-03-26 11:47:36.964585003 +0100
+@@ -8,31 +8,59 @@
+ #ifndef __ARCH_SPARC64_ATOMIC__
+ #define __ARCH_SPARC64_ATOMIC__
++#include <linux/config.h>
++
+ typedef struct { volatile int counter; } atomic_t;
+ #define ATOMIC_INIT(i)        { (i) }
+ #define atomic_read(v)                ((v)->counter)
+ #define atomic_set(v, i)      (((v)->counter) = i)
+-extern int __atomic_add(int, atomic_t *);
+-extern int __atomic_sub(int, atomic_t *);
++extern void atomic_add(int, atomic_t *);
++extern void atomic_sub(int, atomic_t *);
++
++extern int atomic_add_ret(int, atomic_t *);
++extern int atomic_sub_ret(int, atomic_t *);
++
++#define atomic_dec_return(v) atomic_sub_ret(1, v)
++
++#define atomic_inc_return(v) atomic_add_ret(1, v)
++
++#define atomic_sub_return(i, v) atomic_sub_ret(i, v)
++
++#define atomic_add_return(i, v) atomic_add_ret(i, v)
++
++/*
++ * atomic_inc_and_test - increment and test
++ * @v: pointer of type atomic_t
++ *
++ * Atomically increments @v by 1
++ * and returns true if the result is zero, or false for all
++ * other cases.
++ */
++#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
++
++#define atomic_sub_and_test(i, v) (atomic_sub_ret(i, v) == 0)
+-#define atomic_add(i, v) ((void)__atomic_add(i, v))
+-#define atomic_sub(i, v) ((void)__atomic_sub(i, v))
++#define atomic_dec_and_test(v) (atomic_sub_ret(1, v) == 0)
+-#define atomic_dec_return(v) __atomic_sub(1, v)
+-#define atomic_inc_return(v) __atomic_add(1, v)
++#define atomic_inc(v) atomic_add(1, v)
+-#define atomic_sub_and_test(i, v) (__atomic_sub(i, v) == 0)
+-#define atomic_dec_and_test(v) (__atomic_sub(1, v) == 0)
++#define atomic_dec(v) atomic_sub(1, v)
+-#define atomic_inc(v) ((void)__atomic_add(1, v))
+-#define atomic_dec(v) ((void)__atomic_sub(1, v))
++#define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
+ /* Atomic operations are already serializing */
++#ifdef CONFIG_SMP
++#define smp_mb__before_atomic_dec()   membar("#StoreLoad | #LoadLoad")
++#define smp_mb__after_atomic_dec()    membar("#StoreLoad | #StoreStore")
++#define smp_mb__before_atomic_inc()   membar("#StoreLoad | #LoadLoad")
++#define smp_mb__after_atomic_inc()    membar("#StoreLoad | #StoreStore")
++#else
+ #define smp_mb__before_atomic_dec()   barrier()
+ #define smp_mb__after_atomic_dec()    barrier()
+ #define smp_mb__before_atomic_inc()   barrier()
+ #define smp_mb__after_atomic_inc()    barrier()
++#endif
+ #endif /* !(__ARCH_SPARC64_ATOMIC__) */
+diff -Nur linux-2.4.29/include/asm-sparc64/bitops.h linux-mips/include/asm-sparc64/bitops.h
+--- linux-2.4.29/include/asm-sparc64/bitops.h  2001-12-21 18:42:03.000000000 +0100
++++ linux-mips/include/asm-sparc64/bitops.h    2005-03-26 11:47:37.017576306 +0100
+@@ -1,4 +1,4 @@
+-/* $Id$
++/* $Id$
+  * bitops.h: Bit string operations on the V9.
+  *
+  * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
+@@ -7,114 +7,126 @@
+ #ifndef _SPARC64_BITOPS_H
+ #define _SPARC64_BITOPS_H
++#include <linux/config.h>
++#include <linux/compiler.h>
+ #include <asm/byteorder.h>
+-extern long ___test_and_set_bit(unsigned long nr, volatile void *addr);
+-extern long ___test_and_clear_bit(unsigned long nr, volatile void *addr);
+-extern long ___test_and_change_bit(unsigned long nr, volatile void *addr);
+-
+-#define test_and_set_bit(nr,addr)     ({___test_and_set_bit(nr,addr)!=0;})
+-#define test_and_clear_bit(nr,addr)   ({___test_and_clear_bit(nr,addr)!=0;})
+-#define test_and_change_bit(nr,addr)  ({___test_and_change_bit(nr,addr)!=0;})
+-#define set_bit(nr,addr)              ((void)___test_and_set_bit(nr,addr))
+-#define clear_bit(nr,addr)            ((void)___test_and_clear_bit(nr,addr))
+-#define change_bit(nr,addr)           ((void)___test_and_change_bit(nr,addr))
++extern int test_and_set_bit(unsigned long nr, volatile void *addr);
++extern int test_and_clear_bit(unsigned long nr, volatile void *addr);
++extern int test_and_change_bit(unsigned long nr, volatile void *addr);
++extern void set_bit(unsigned long nr, volatile void *addr);
++extern void clear_bit(unsigned long nr, volatile void *addr);
++extern void change_bit(unsigned long nr, volatile void *addr);
+ /* "non-atomic" versions... */
+-#define __set_bit(X,Y)                                        \
+-do {  unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      *__m |= (1UL << (__nr & 63));                   \
+-} while (0)
+-#define __clear_bit(X,Y)                              \
+-do {  unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      *__m &= ~(1UL << (__nr & 63));                  \
+-} while (0)
+-#define __change_bit(X,Y)                             \
+-do {  unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      *__m ^= (1UL << (__nr & 63));                   \
+-} while (0)
+-#define __test_and_set_bit(X,Y)                               \
+-({    unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      long __old = *__m;                              \
+-      long __mask = (1UL << (__nr & 63));             \
+-      *__m = (__old | __mask);                        \
+-      ((__old & __mask) != 0);                        \
+-})
+-#define __test_and_clear_bit(X,Y)                     \
+-({    unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      long __old = *__m;                              \
+-      long __mask = (1UL << (__nr & 63));             \
+-      *__m = (__old & ~__mask);                       \
+-      ((__old & __mask) != 0);                        \
+-})
+-#define __test_and_change_bit(X,Y)                    \
+-({    unsigned long __nr = (X);                       \
+-      long *__m = ((long *) (Y)) + (__nr >> 6);       \
+-      long __old = *__m;                              \
+-      long __mask = (1UL << (__nr & 63));             \
+-      *__m = (__old ^ __mask);                        \
+-      ((__old & __mask) != 0);                        \
+-})
+-#define smp_mb__before_clear_bit()    do { } while(0)
+-#define smp_mb__after_clear_bit()     do { } while(0)
++static __inline__ void __set_bit(int nr, volatile void *addr)
++{
++      unsigned long *m;
++
++      m = ((unsigned long *)addr) + (nr >> 6);
++      *m |= (1UL << (nr & 63));
++}
++
++static __inline__ void __clear_bit(int nr, volatile void *addr)
++{
++      unsigned long *m;
++
++      m = ((unsigned long *)addr) + (nr >> 6);
++      *m &= ~(1UL << (nr & 63));
++}
+-extern __inline__ int test_bit(int nr, __const__ void *addr)
++static __inline__ void __change_bit(int nr, volatile void *addr)
+ {
+-      return (1UL & (((__const__ long *) addr)[nr >> 6] >> (nr & 63))) != 0UL;
++      unsigned long *m;
++
++      m = ((unsigned long *)addr) + (nr >> 6);
++      *m ^= (1UL << (nr & 63));
++}
++
++static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
++{
++      unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
++      unsigned long old = *m;
++      unsigned long mask = (1UL << (nr & 63));
++
++      *m = (old | mask);
++      return ((old & mask) != 0);
++}
++
++static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
++{
++      unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
++      unsigned long old = *m;
++      unsigned long mask = (1UL << (nr & 63));
++
++      *m = (old & ~mask);
++      return ((old & mask) != 0);
++}
++
++static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
++{
++      unsigned long *m = ((unsigned long *)addr) + (nr >> 6);
++      unsigned long old = *m;
++      unsigned long mask = (1UL << (nr & 63));
++
++      *m = (old ^ mask);
++      return ((old & mask) != 0);
++}
++
++#ifdef CONFIG_SMP
++#define smp_mb__before_clear_bit()    membar("#StoreLoad | #LoadLoad")
++#define smp_mb__after_clear_bit()     membar("#StoreLoad | #StoreStore")
++#else
++#define smp_mb__before_clear_bit()    barrier()
++#define smp_mb__after_clear_bit()     barrier()
++#endif
++
++static __inline__ int test_bit(int nr, __const__ volatile void *_addr)
++{
++      __const__ unsigned long *addr;
++
++      addr = (__const__ unsigned long *) _addr;
++
++      return (1UL & ((addr)[nr >> 6] >> (nr & 63))) != 0UL;
+ }
+ /* The easy/cheese version for now. */
+-extern __inline__ unsigned long ffz(unsigned long word)
++static __inline__ unsigned long ffz(unsigned long word)
+ {
+       unsigned long result;
+-#ifdef ULTRA_HAS_POPULATION_COUNT     /* Thanks for nothing Sun... */
+-      __asm__ __volatile__(
+-"     brz,pn  %0, 1f\n"
+-"      neg    %0, %%g1\n"
+-"     xnor    %0, %%g1, %%g2\n"
+-"     popc    %%g2, %0\n"
+-"1:   " : "=&r" (result)
+-        : "0" (word)
+-        : "g1", "g2");
+-#else
+-#if 1 /* def EASY_CHEESE_VERSION */
+       result = 0;
+       while(word & 1) {
+               result++;
+               word >>= 1;
+       }
+-#else
+-      unsigned long tmp;
++      return result;
++}
+-      result = 0;     
+-      tmp = ~word & -~word;
+-      if (!(unsigned)tmp) {
+-              tmp >>= 32;
+-              result = 32;
+-      }
+-      if (!(unsigned short)tmp) {
+-              tmp >>= 16;
+-              result += 16;
+-      }
+-      if (!(unsigned char)tmp) {
+-              tmp >>= 8;
+-              result += 8;
++/**
++ * __ffs - find first bit in word.
++ * @word: The word to search
++ *
++ * Undefined if no bit exists, so code should check against 0 first.
++ */
++static __inline__ unsigned long __ffs(unsigned long word)
++{
++      unsigned long result = 0;
++
++      while (!(word & 1UL)) {
++              result++;
++              word >>= 1;
+       }
+-      if (tmp & 0xf0) result += 4;
+-      if (tmp & 0xcc) result += 2;
+-      if (tmp & 0xaa) result ++;
+-#endif
+-#endif
+       return result;
+ }
++/*
++ * fls: find last bit set.
++ */
++
++#define fls(x) generic_fls(x)
++
+ #ifdef __KERNEL__
+ /*
+@@ -122,8 +134,12 @@
+  * the libc and compiler builtin ffs routines, therefore
+  * differs in spirit from the above ffz (man ffs).
+  */
+-
+-#define ffs(x) generic_ffs(x)
++static __inline__ int ffs(int x)
++{
++      if (!x)
++              return 0;
++      return __ffs((unsigned long)x) + 1;
++}
+ /*
+  * hweightN: returns the hamming weight (i.e. the number
+@@ -132,7 +148,15 @@
+ #ifdef ULTRA_HAS_POPULATION_COUNT
+-extern __inline__ unsigned int hweight32(unsigned int w)
++static __inline__ unsigned int hweight64(unsigned long w)
++{
++      unsigned int res;
++
++      __asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
++      return res;
++}
++
++static __inline__ unsigned int hweight32(unsigned int w)
+ {
+       unsigned int res;
+@@ -140,7 +164,7 @@
+       return res;
+ }
+-extern __inline__ unsigned int hweight16(unsigned int w)
++static __inline__ unsigned int hweight16(unsigned int w)
+ {
+       unsigned int res;
+@@ -148,7 +172,7 @@
+       return res;
+ }
+-extern __inline__ unsigned int hweight8(unsigned int w)
++static __inline__ unsigned int hweight8(unsigned int w)
+ {
+       unsigned int res;
+@@ -158,6 +182,7 @@
+ #else
++#define hweight64(x) generic_hweight64(x)
+ #define hweight32(x) generic_hweight32(x)
+ #define hweight16(x) generic_hweight16(x)
+ #define hweight8(x) generic_hweight8(x)
+@@ -170,7 +195,7 @@
+  * on Linus's ALPHA routines, which are pretty portable BTW.
+  */
+-extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
++static __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+ {
+       unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+       unsigned long result = offset & ~63UL;
+@@ -211,15 +236,12 @@
+ #define find_first_zero_bit(addr, size) \
+         find_next_zero_bit((addr), (size), 0)
+-extern long ___test_and_set_le_bit(int nr, volatile void *addr);
+-extern long ___test_and_clear_le_bit(int nr, volatile void *addr);
+-
+-#define test_and_set_le_bit(nr,addr)  ({___test_and_set_le_bit(nr,addr)!=0;})
+-#define test_and_clear_le_bit(nr,addr)        ({___test_and_clear_le_bit(nr,addr)!=0;})
+-#define set_le_bit(nr,addr)           ((void)___test_and_set_le_bit(nr,addr))
+-#define clear_le_bit(nr,addr)         ((void)___test_and_clear_le_bit(nr,addr))
++#define test_and_set_le_bit(nr,addr)  \
++      test_and_set_bit((nr) ^ 0x38, (addr))
++#define test_and_clear_le_bit(nr,addr)        \
++      test_and_clear_bit((nr) ^ 0x38, (addr))
+-extern __inline__ int test_le_bit(int nr, __const__ void * addr)
++static __inline__ int test_le_bit(int nr, __const__ void *addr)
+ {
+       int                     mask;
+       __const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
+@@ -232,7 +254,7 @@
+ #define find_first_zero_le_bit(addr, size) \
+         find_next_zero_le_bit((addr), (size), 0)
+-extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
++static __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+ {
+       unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+       unsigned long result = offset & ~63UL;
+@@ -271,18 +293,41 @@
+ #ifdef __KERNEL__
+-#define ext2_set_bit                  test_and_set_le_bit
+-#define ext2_clear_bit                        test_and_clear_le_bit
+-#define ext2_test_bit                         test_le_bit
+-#define ext2_find_first_zero_bit      find_first_zero_le_bit
+-#define ext2_find_next_zero_bit               find_next_zero_le_bit
++#define __set_le_bit(nr, addr) \
++      __set_bit((nr) ^ 0x38, (addr))
++#define __clear_le_bit(nr, addr) \
++      __clear_bit((nr) ^ 0x38, (addr))
++#define __test_and_clear_le_bit(nr, addr) \
++      __test_and_clear_bit((nr) ^ 0x38, (addr))
++#define __test_and_set_le_bit(nr, addr) \
++      __test_and_set_bit((nr) ^ 0x38, (addr))
++
++#define ext2_set_bit(nr,addr) \
++      __test_and_set_le_bit((nr),(unsigned long *)(addr))
++#define ext2_set_bit_atomic(lock,nr,addr) \
++      test_and_set_le_bit((nr),(unsigned long *)(addr))
++#define ext2_clear_bit(nr,addr)       \
++      __test_and_clear_le_bit((nr),(unsigned long *)(addr))
++#define ext2_clear_bit_atomic(lock,nr,addr) \
++      test_and_clear_le_bit((nr),(unsigned long *)(addr))
++#define ext2_test_bit(nr,addr)        \
++      test_le_bit((nr),(unsigned long *)(addr))
++#define ext2_find_first_zero_bit(addr, size) \
++      find_first_zero_le_bit((unsigned long *)(addr), (size))
++#define ext2_find_next_zero_bit(addr, size, off) \
++      find_next_zero_le_bit((unsigned long *)(addr), (size), (off))
+ /* Bitmap functions for the minix filesystem.  */
+-#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
+-#define minix_set_bit(nr,addr) set_bit(nr,addr)
+-#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
+-#define minix_test_bit(nr,addr) test_bit(nr,addr)
+-#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
++#define minix_test_and_set_bit(nr,addr)       \
++      test_and_set_bit((nr),(unsigned long *)(addr))
++#define minix_set_bit(nr,addr)        \
++      set_bit((nr),(unsigned long *)(addr))
++#define minix_test_and_clear_bit(nr,addr) \
++      test_and_clear_bit((nr),(unsigned long *)(addr))
++#define minix_test_bit(nr,addr)       \
++      test_bit((nr),(unsigned long *)(addr))
++#define minix_find_first_zero_bit(addr,size) \
++      find_first_zero_bit((unsigned long *)(addr),(size))
+ #endif /* __KERNEL__ */
 diff -Nur linux-2.4.29/include/asm-sparc64/param.h linux-mips/include/asm-sparc64/param.h
 --- linux-2.4.29/include/asm-sparc64/param.h   2000-10-30 23:34:12.000000000 +0100
 +++ linux-mips/include/asm-sparc64/param.h     2000-11-23 03:00:56.000000000 +0100
 @@ -4,6 +4,9 @@
  
- #ifndef HZ
- #define HZ 100
-+#ifdef __KERNEL__
-+#define hz_to_std(a) (a)
-+#endif
- #endif
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ #define EXEC_PAGESIZE 8192    /* Thanks for sun4's we carry baggage... */
+diff -Nur linux-2.4.29/include/asm-sparc64/system.h linux-mips/include/asm-sparc64/system.h
+--- linux-2.4.29/include/asm-sparc64/system.h  2003-06-13 16:51:38.000000000 +0200
++++ linux-mips/include/asm-sparc64/system.h    2005-03-26 11:47:37.092563999 +0100
+@@ -106,9 +106,9 @@
+ #define nop()                 __asm__ __volatile__ ("nop")
+-#define membar(type)  __asm__ __volatile__ ("membar " type : : : "memory");
++#define membar(type)  __asm__ __volatile__ ("membar " type : : : "memory")
+ #define mb()          \
+-      membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad");
++      membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad")
+ #define rmb()         membar("#LoadLoad")
+ #define wmb()         membar("#StoreStore")
+ #define set_mb(__var, __value) \
+@@ -121,9 +121,9 @@
+ #define smp_rmb()     rmb()
+ #define smp_wmb()     wmb()
+ #else
+-#define smp_mb()      __asm__ __volatile__("":::"memory");
+-#define smp_rmb()     __asm__ __volatile__("":::"memory");
+-#define smp_wmb()     __asm__ __volatile__("":::"memory");
++#define smp_mb()      __asm__ __volatile__("":::"memory")
++#define smp_rmb()     __asm__ __volatile__("":::"memory")
++#define smp_wmb()     __asm__ __volatile__("":::"memory")
+ #endif
+ #define flushi(addr)  __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
+@@ -246,6 +246,7 @@
+ extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
+ {
+       __asm__ __volatile__(
++"     membar          #StoreLoad | #LoadLoad\n"
+ "     mov             %0, %%g5\n"
+ "1:   lduw            [%2], %%g7\n"
+ "     cas             [%2], %%g7, %0\n"
+@@ -262,6 +263,7 @@
+ extern __inline__ unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
+ {
+       __asm__ __volatile__(
++"     membar          #StoreLoad | #LoadLoad\n"
+ "     mov             %0, %%g5\n"
+ "1:   ldx             [%2], %%g7\n"
+ "     casx            [%2], %%g7, %0\n"
+@@ -306,7 +308,8 @@
+ extern __inline__ unsigned long
+ __cmpxchg_u32(volatile int *m, int old, int new)
+ {
+-      __asm__ __volatile__("cas [%2], %3, %0\n\t"
++      __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
++                           "cas [%2], %3, %0\n\t"
+                            "membar #StoreLoad | #StoreStore"
+                            : "=&r" (new)
+                            : "0" (new), "r" (m), "r" (old)
+@@ -318,7 +321,8 @@
+ extern __inline__ unsigned long
+ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+ {
+-      __asm__ __volatile__("casx [%2], %3, %0\n\t"
++      __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
++                           "casx [%2], %3, %0\n\t"
+                            "membar #StoreLoad | #StoreStore"
+                            : "=&r" (new)
+                            : "0" (new), "r" (m), "r" (old)
+diff -Nur linux-2.4.29/include/asm-x86_64/acpi.h linux-mips/include/asm-x86_64/acpi.h
+--- linux-2.4.29/include/asm-x86_64/acpi.h     2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/include/asm-x86_64/acpi.h       2005-03-26 11:47:37.164552184 +0100
+@@ -118,6 +118,7 @@
+ extern int acpi_strict;
+ extern int acpi_disabled;
+ extern int acpi_ht;
++extern int acpi_skip_timer_override;
+ static inline void disable_acpi(void) 
+ { 
+       acpi_disabled = 1;
+diff -Nur linux-2.4.29/include/linux/ata.h linux-mips/include/linux/ata.h
+--- linux-2.4.29/include/linux/ata.h   2005-01-19 15:10:12.000000000 +0100
++++ linux-mips/include/linux/ata.h     2005-03-26 11:47:37.226542010 +0100
+@@ -123,6 +123,8 @@
+       ATA_CMD_PIO_WRITE_EXT   = 0x34,
+       ATA_CMD_SET_FEATURES    = 0xEF,
+       ATA_CMD_PACKET          = 0xA0,
++      ATA_CMD_VERIFY          = 0x40,
++      ATA_CMD_VERIFY_EXT      = 0x42,
+       /* SETFEATURES stuff */
+       SETFEATURES_XFER        = 0x03,
+diff -Nur linux-2.4.29/include/linux/brlock.h linux-mips/include/linux/brlock.h
+--- linux-2.4.29/include/linux/brlock.h        2002-11-29 00:53:15.000000000 +0100
++++ linux-mips/include/linux/brlock.h  2005-03-26 11:47:37.233540861 +0100
+@@ -18,16 +18,6 @@
+  * Registry idea and naming [ crutial! :-) ] by:
+  *
+  *                 David S. Miller <davem@redhat.com>
+- *
+- * David has an implementation that doesn't use atomic operations in
+- * the read branch via memory ordering tricks - i guess we need to
+- * split this up into a per-arch thing? The atomicity issue is a
+- * secondary item in profiles, at least on x86 platforms.
+- *
+- * The atomic op version overhead is indeed a big deal on
+- * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and
+- * compare-and-swap cpus (Sparc64).  So we control which
+- * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM
+  */
+ /* Register bigreader lock indices here. */
+@@ -45,17 +35,7 @@
+ #include <linux/cache.h>
+ #include <linux/spinlock.h>
+-#if defined(__i386__) || defined(__ia64__) || defined(__x86_64__)
+-#define __BRLOCK_USE_ATOMICS
+-#else
+-#undef __BRLOCK_USE_ATOMICS
+-#endif
+-
+-#ifdef __BRLOCK_USE_ATOMICS
+-typedef rwlock_t      brlock_read_lock_t;
+-#else
+ typedef unsigned int  brlock_read_lock_t;
+-#endif
+ /*
+  * align last allocated index to the next cacheline:
+@@ -65,39 +45,14 @@
+ extern brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX];
+-#ifndef __BRLOCK_USE_ATOMICS
+ struct br_wrlock {
+       spinlock_t lock;
+ } __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
+ extern struct br_wrlock __br_write_locks[__BR_IDX_MAX];
+-#endif
+ extern void __br_lock_usage_bug (void);
+-#ifdef __BRLOCK_USE_ATOMICS
+-
+-static inline void br_read_lock (enum brlock_indices idx)
+-{
+-      /*
+-       * This causes a link-time bug message if an
+-       * invalid index is used:
+-       */
+-      if (idx >= __BR_END)
+-              __br_lock_usage_bug();
+-
+-      read_lock(&__brlock_array[smp_processor_id()][idx]);
+-}
+-
+-static inline void br_read_unlock (enum brlock_indices idx)
+-{
+-      if (idx >= __BR_END)
+-              __br_lock_usage_bug();
+-
+-      read_unlock(&__brlock_array[smp_processor_id()][idx]);
+-}
+-
+-#else /* ! __BRLOCK_USE_ATOMICS */
+ static inline void br_read_lock (enum brlock_indices idx)
+ {
+       unsigned int *ctr;
+@@ -149,7 +104,6 @@
+       wmb();
+       (*ctr)--;
+ }
+-#endif /* __BRLOCK_USE_ATOMICS */
+ /* write path not inlined - it's rare and larger */
+diff -Nur linux-2.4.29/include/linux/fs.h linux-mips/include/linux/fs.h
+--- linux-2.4.29/include/linux/fs.h    2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/include/linux/fs.h      2005-03-26 11:47:37.386515755 +0100
+@@ -576,6 +576,7 @@
+       unsigned int            f_uid, f_gid;
+       int                     f_error;
++      size_t                  f_maxcount;
+       unsigned long           f_version;
+       /* needed for tty driver, and maybe others */
+@@ -1056,14 +1057,7 @@
+       return 0;
+ }
+-static inline int locks_verify_area(int read_write, struct inode *inode,
+-                                  struct file *filp, loff_t offset,
+-                                  size_t count)
+-{
+-      if (inode->i_flock && MANDATORY_LOCK(inode))
+-              return locks_mandatory_area(read_write, inode, filp, offset, count);
+-      return 0;
+-}
++extern int rw_verify_area(int, struct file *, loff_t *, size_t);
  
- #define EXEC_PAGESIZE 8192    /* Thanks for sun4's we carry baggage... */
+ static inline int locks_verify_truncate(struct inode *inode,
+                                   struct file *filp,
 diff -Nur linux-2.4.29/include/linux/i2c-algo-au1550.h linux-mips/include/linux/i2c-algo-au1550.h
 --- linux-2.4.29/include/linux/i2c-algo-au1550.h       1970-01-01 01:00:00.000000000 +0100
 +++ linux-mips/include/linux/i2c-algo-au1550.h 2004-07-07 02:38:02.000000000 +0200
@@ -24977,6 +37678,229 @@ diff -Nur linux-2.4.29/include/linux/i2c-id.h linux-mips/include/linux/i2c-id.h
  /* --- SMBus only adapters                                            */
  #define I2C_HW_SMBUS_PIIX4    0x00
  #define I2C_HW_SMBUS_ALI15X3  0x01
+diff -Nur linux-2.4.29/include/linux/jbd.h linux-mips/include/linux/jbd.h
+--- linux-2.4.29/include/linux/jbd.h   2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/include/linux/jbd.h     2005-03-26 11:47:37.416510832 +0100
+@@ -848,7 +848,7 @@
+ extern int    log_space_left (journal_t *); /* Called with journal locked */
+ extern tid_t  log_start_commit (journal_t *, transaction_t *);
+-extern void   log_wait_commit (journal_t *, tid_t);
++extern int    log_wait_commit (journal_t *, tid_t);
+ extern int    log_do_checkpoint (journal_t *, int);
+ extern void   log_wait_for_space(journal_t *, int nblocks);
+diff -Nur linux-2.4.29/include/linux/libata-compat.h linux-mips/include/linux/libata-compat.h
+--- linux-2.4.29/include/linux/libata-compat.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-mips/include/linux/libata-compat.h   2005-03-26 11:47:37.456504268 +0100
+@@ -1,8 +1,16 @@
+ #ifndef __LIBATA_COMPAT_H__
+ #define __LIBATA_COMPAT_H__
++#include <linux/types.h>
+ #include <linux/delay.h>
+ #include <linux/pci.h>
++#include <linux/slab.h>
++
++typedef u32 __le32;
++typedef u64 __le64;
++
++#define DMA_64BIT_MASK 0xffffffffffffffffULL
++#define DMA_32BIT_MASK 0x00000000ffffffffULL
+ #define MODULE_VERSION(ver_str)
+@@ -10,11 +18,6 @@
+       struct pci_dev pdev;
+ };
+-static inline void libata_msleep(unsigned long msecs)
+-{
+-      msleep(msecs);
+-}
+-
+ static inline struct pci_dev *to_pci_dev(struct device *dev)
+ {
+       return (struct pci_dev *) dev;
+@@ -47,4 +50,13 @@
+ #define dev_set_drvdata(dev,ptr) \
+       pci_set_drvdata(to_pci_dev(dev),(ptr))
++static inline void *kcalloc(size_t nmemb, size_t size, int flags)
++{
++      size_t total = nmemb * size;
++      void *mem = kmalloc(total, flags);
++      if (mem)
++              memset(mem, 0, total);
++      return mem;
++}
++
+ #endif /* __LIBATA_COMPAT_H__ */
+diff -Nur linux-2.4.29/include/linux/libata.h linux-mips/include/linux/libata.h
+--- linux-2.4.29/include/linux/libata.h        2005-01-19 15:10:12.000000000 +0100
++++ linux-mips/include/linux/libata.h  2005-03-26 11:47:37.460503612 +0100
+@@ -335,6 +335,8 @@
+       void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
+       u8   (*check_status)(struct ata_port *ap);
++      u8   (*check_altstatus)(struct ata_port *ap);
++      u8   (*check_err)(struct ata_port *ap);
+       void (*dev_select)(struct ata_port *ap, unsigned int device);
+       void (*phy_reset) (struct ata_port *ap);
+@@ -361,6 +363,9 @@
+       void (*port_stop) (struct ata_port *ap);
+       void (*host_stop) (struct ata_host_set *host_set);
++
++      void (*bmdma_stop) (struct ata_port *ap);
++      u8   (*bmdma_status) (struct ata_port *ap);
+ };
+ struct ata_port_info {
+@@ -401,6 +406,8 @@
+ extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
+ extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
+ extern u8 ata_check_status(struct ata_port *ap);
++extern u8 ata_altstatus(struct ata_port *ap);
++extern u8 ata_chk_err(struct ata_port *ap);
+ extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf);
+ extern int ata_port_start (struct ata_port *ap);
+ extern void ata_port_stop (struct ata_port *ap);
+@@ -416,6 +423,8 @@
+                             unsigned int ofs, unsigned int len);
+ extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
+ extern void ata_bmdma_start (struct ata_queued_cmd *qc);
++extern void ata_bmdma_stop(struct ata_port *ap);
++extern u8   ata_bmdma_status(struct ata_port *ap);
+ extern void ata_bmdma_irq_clear(struct ata_port *ap);
+ extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat);
+ extern void ata_eng_timeout(struct ata_port *ap);
+@@ -435,8 +444,6 @@
+ extern struct ata_probe_ent *
+ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port);
+-extern struct ata_probe_ent *
+-ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port);
+ extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits);
+ #endif /* CONFIG_PCI */
+@@ -453,26 +460,11 @@
+               (dev->class == ATA_DEV_ATAPI));
+ }
+-static inline u8 ata_chk_err(struct ata_port *ap)
+-{
+-      if (ap->flags & ATA_FLAG_MMIO) {
+-              return readb((void __iomem *) ap->ioaddr.error_addr);
+-      }
+-      return inb(ap->ioaddr.error_addr);
+-}
+-
+ static inline u8 ata_chk_status(struct ata_port *ap)
+ {
+       return ap->ops->check_status(ap);
+ }
+-static inline u8 ata_altstatus(struct ata_port *ap)
+-{
+-      if (ap->flags & ATA_FLAG_MMIO)
+-              return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+-      return inb(ap->ioaddr.altstatus_addr);
+-}
+-
+ static inline void ata_pause(struct ata_port *ap)
+ {
+       ata_altstatus(ap);
+@@ -596,46 +588,6 @@
+       return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0;
+ }
+-static inline void ata_bmdma_stop(struct ata_port *ap)
+-{
+-      if (ap->flags & ATA_FLAG_MMIO) {
+-              void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+-
+-              /* clear start/stop bit */
+-              writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+-                    mmio + ATA_DMA_CMD);
+-      } else {
+-              /* clear start/stop bit */
+-              outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+-                  ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+-      }
+-
+-      /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+-      ata_altstatus(ap);            /* dummy read */
+-}
+-
+-static inline void ata_bmdma_ack_irq(struct ata_port *ap)
+-{
+-      if (ap->flags & ATA_FLAG_MMIO) {
+-              void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
+-              writeb(readb(mmio), mmio);
+-      } else {
+-              unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+-              outb(inb(addr), addr);
+-      }
+-}
+-
+-static inline u8 ata_bmdma_status(struct ata_port *ap)
+-{
+-      u8 host_stat;
+-      if (ap->flags & ATA_FLAG_MMIO) {
+-              void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+-              host_stat = readb(mmio + ATA_DMA_STATUS);
+-      } else
+-              host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+-      return host_stat;
+-}
+-
+ static inline int ata_try_flush_cache(struct ata_device *dev)
+ {
+       return ata_id_wcache_enabled(dev->id) ||
+diff -Nur linux-2.4.29/include/linux/netfilter_ipv4/ip_conntrack.h linux-mips/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.4.29/include/linux/netfilter_ipv4/ip_conntrack.h   2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/include/linux/netfilter_ipv4/ip_conntrack.h     2005-03-26 11:47:37.735458485 +0100
+@@ -249,10 +249,9 @@
+ /* Call me when a conntrack is destroyed. */
+ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
+-extern int ip_ct_no_defrag;
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+-ip_ct_gather_frags(struct sk_buff *skb);
++ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user);
+ /* Delete all conntracks which match. */
+ extern void
+diff -Nur linux-2.4.29/include/linux/netlink.h linux-mips/include/linux/netlink.h
+--- linux-2.4.29/include/linux/netlink.h       2005-01-19 15:10:12.000000000 +0100
++++ linux-mips/include/linux/netlink.h 2005-03-26 11:47:37.463503119 +0100
+@@ -117,10 +117,9 @@
+ /*
+  *    skb should fit one page. This choice is good for headerless malloc.
+- *
+- *      FIXME: What is the best size for SLAB???? --ANK
+  */
+-#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
++#define NLMSG_GOODORDER 0
++#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
+ struct netlink_callback
+diff -Nur linux-2.4.29/include/linux/pci_ids.h linux-mips/include/linux/pci_ids.h
+--- linux-2.4.29/include/linux/pci_ids.h       2005-01-19 15:10:12.000000000 +0100
++++ linux-mips/include/linux/pci_ids.h 2005-03-26 11:47:37.534491468 +0100
+@@ -1937,7 +1937,6 @@
+ #define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5
+ #define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6
+ #define PCI_DEVICE_ID_INTEL_82801EB_7 0x24d7
+-#define PCI_DEVICE_ID_INTEL_82801DB_10        0x24ca
+ #define PCI_DEVICE_ID_INTEL_82801EB_11        0x24db
+ #define PCI_DEVICE_ID_INTEL_82801EB_13        0x24dd
+ #define PCI_DEVICE_ID_INTEL_ESB_0     0x25a0
 diff -Nur linux-2.4.29/include/linux/sched.h linux-mips/include/linux/sched.h
 --- linux-2.4.29/include/linux/sched.h 2005-01-19 15:10:12.000000000 +0100
 +++ linux-mips/include/linux/sched.h   2004-11-29 18:47:18.000000000 +0100
@@ -25004,6 +37928,30 @@ diff -Nur linux-2.4.29/include/linux/serial.h linux-mips/include/linux/serial.h
  
  #define SERIAL_IO_PORT        0
  #define SERIAL_IO_HUB6        1
+diff -Nur linux-2.4.29/include/linux/skbuff.h linux-mips/include/linux/skbuff.h
+--- linux-2.4.29/include/linux/skbuff.h        2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/include/linux/skbuff.h  2005-03-26 11:47:37.600480638 +0100
+@@ -290,15 +290,11 @@
+  
+ static inline void kfree_skb(struct sk_buff *skb)
+ {
+-      if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
+-              __kfree_skb(skb);
+-}
+-
+-/* Use this if you didn't touch the skb state [for fast switching] */
+-static inline void kfree_skb_fast(struct sk_buff *skb)
+-{
+-      if (atomic_read(&skb->users) == 1 || atomic_dec_and_test(&skb->users))
+-              kfree_skbmem(skb);      
++      if (likely(atomic_read(&skb->users) == 1))
++              smp_rmb();
++      else if (likely(!atomic_dec_and_test(&skb->users)))
++              return;
++      __kfree_skb(skb);
+ }
+ /**
 diff -Nur linux-2.4.29/include/linux/swap.h linux-mips/include/linux/swap.h
 --- linux-2.4.29/include/linux/swap.h  2005-01-19 15:10:12.000000000 +0100
 +++ linux-mips/include/linux/swap.h    2004-11-29 18:47:18.000000000 +0100
@@ -25038,6 +37986,103 @@ diff -Nur linux-2.4.29/include/linux/swap.h linux-mips/include/linux/swap.h
  /*
   * Max bad pages in the new format..
   */
+diff -Nur linux-2.4.29/include/linux/sysctl.h linux-mips/include/linux/sysctl.h
+--- linux-2.4.29/include/linux/sysctl.h        2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/include/linux/sysctl.h  2005-03-26 11:47:37.673468659 +0100
+@@ -326,6 +326,7 @@
+       NET_TCP_BIC_LOW_WINDOW=104,
+       NET_TCP_DEFAULT_WIN_SCALE=105,
+       NET_TCP_MODERATE_RCVBUF=106,
++      NET_TCP_BIC_BETA=108,
+ };
+ enum {
+diff -Nur linux-2.4.29/include/net/dst.h linux-mips/include/net/dst.h
+--- linux-2.4.29/include/net/dst.h     2003-08-25 13:44:44.000000000 +0200
++++ linux-mips/include/net/dst.h       2005-03-26 11:47:37.821444373 +0100
+@@ -104,8 +104,10 @@
+ static inline
+ void dst_release(struct dst_entry * dst)
+ {
+-      if (dst)
++      if (dst) {
++              smp_mb__before_atomic_dec();
+               atomic_dec(&dst->__refcnt);
++      }
+ }
+ extern void * dst_alloc(struct dst_ops * ops);
+diff -Nur linux-2.4.29/include/net/ip.h linux-mips/include/net/ip.h
+--- linux-2.4.29/include/net/ip.h      2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/include/net/ip.h        2005-03-26 11:47:37.822444209 +0100
+@@ -227,9 +227,19 @@
+ /*
+  *    Functions provided by ip_fragment.o
+  */
+- 
+-struct sk_buff *ip_defrag(struct sk_buff *skb);
+-extern void ipfrag_flush(void);
++
++enum ip_defrag_users
++{
++      IP_DEFRAG_LOCAL_DELIVER,
++      IP_DEFRAG_CALL_RA_CHAIN,
++      IP_DEFRAG_CONNTRACK_IN,
++      IP_DEFRAG_CONNTRACK_OUT,
++      IP_DEFRAG_NAT_OUT,
++      IP_DEFRAG_VS_OUT,
++      IP_DEFRAG_VS_FWD
++};
++
++struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
+ extern int ip_frag_nqueues;
+ extern atomic_t ip_frag_mem;
+diff -Nur linux-2.4.29/include/net/tcp.h linux-mips/include/net/tcp.h
+--- linux-2.4.29/include/net/tcp.h     2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/include/net/tcp.h       2005-03-26 11:47:37.891432886 +0100
+@@ -395,9 +395,8 @@
+ # define TCP_TW_RECYCLE_TICK (12+2-TCP_TW_RECYCLE_SLOTS_LOG)
+ #endif
+-#define BICTCP_1_OVER_BETA    8       /*
+-                                       * Fast recovery
+-                                       * multiplicative decrease factor
++#define BICTCP_BETA_SCALE    1024     /* Scale factor beta calculation
++                                       * max_cwnd = snd_cwnd * beta
+                                        */
+ #define BICTCP_MAX_INCREMENT 32               /*
+                                        * Limit on the amount of
+@@ -491,6 +490,7 @@
+ extern int sysctl_tcp_bic;
+ extern int sysctl_tcp_bic_fast_convergence;
+ extern int sysctl_tcp_bic_low_window;
++extern int sysctl_tcp_bic_beta;
+ extern int sysctl_tcp_default_win_scale;
+ extern int sysctl_tcp_moderate_rcvbuf;
+@@ -1132,15 +1132,16 @@
+       if (tcp_is_bic(tp)) {
+               if (sysctl_tcp_bic_fast_convergence &&
+                   tp->snd_cwnd < tp->bictcp.last_max_cwnd)
+-                      tp->bictcp.last_max_cwnd
+-                              = (tp->snd_cwnd * (2*BICTCP_1_OVER_BETA-1))
+-                              / (BICTCP_1_OVER_BETA/2);
++                      tp->bictcp.last_max_cwnd = (tp->snd_cwnd * 
++                                                  (BICTCP_BETA_SCALE
++                                                   + sysctl_tcp_bic_beta))
++                              / (2 * BICTCP_BETA_SCALE);
+               else
+                       tp->bictcp.last_max_cwnd = tp->snd_cwnd;
+               if (tp->snd_cwnd > sysctl_tcp_bic_low_window)
+-                      return max(tp->snd_cwnd - (tp->snd_cwnd/BICTCP_1_OVER_BETA),
+-                                 2U);
++                      return max((tp->snd_cwnd * sysctl_tcp_bic_beta)
++                                 / BICTCP_BETA_SCALE, 2U);
+       }
+       return max(tp->snd_cwnd >> 1U, 2U);
 diff -Nur linux-2.4.29/include/video/newport.h linux-mips/include/video/newport.h
 --- linux-2.4.29/include/video/newport.h       2001-04-12 21:20:31.000000000 +0200
 +++ linux-mips/include/video/newport.h 2004-09-23 15:32:29.000000000 +0200
@@ -25233,6 +38278,46 @@ diff -Nur linux-2.4.29/kernel/sys.c linux-mips/kernel/sys.c
  }
  
  /*
+diff -Nur linux-2.4.29/lib/brlock.c linux-mips/lib/brlock.c
+--- linux-2.4.29/lib/brlock.c  2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/lib/brlock.c    2005-03-26 11:47:38.065404334 +0100
+@@ -15,29 +15,6 @@
+ #include <linux/sched.h>
+ #include <linux/brlock.h>
+-#ifdef __BRLOCK_USE_ATOMICS
+-
+-brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] =
+-   { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = RW_LOCK_UNLOCKED } };
+-
+-void fastcall __br_write_lock (enum brlock_indices idx)
+-{
+-      int i;
+-
+-      for (i = 0; i < smp_num_cpus; i++)
+-              write_lock(&__brlock_array[cpu_logical_map(i)][idx]);
+-}
+-
+-void fastcall __br_write_unlock (enum brlock_indices idx)
+-{
+-      int i;
+-
+-      for (i = 0; i < smp_num_cpus; i++)
+-              write_unlock(&__brlock_array[cpu_logical_map(i)][idx]);
+-}
+-
+-#else /* ! __BRLOCK_USE_ATOMICS */
+-
+ brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] =
+    { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = 0 } };
+@@ -64,6 +41,4 @@
+       spin_unlock(&__br_write_locks[idx].lock);
+ }
+-#endif /* __BRLOCK_USE_ATOMICS */
+-
+ #endif /* CONFIG_SMP */
 diff -Nur linux-2.4.29/lib/Makefile linux-mips/lib/Makefile
 --- linux-2.4.29/lib/Makefile  2004-04-14 15:05:40.000000000 +0200
 +++ linux-mips/lib/Makefile    2004-04-16 05:14:21.000000000 +0200
@@ -25244,3 +38329,712 @@ diff -Nur linux-2.4.29/lib/Makefile linux-mips/lib/Makefile
  include $(TOPDIR)/drivers/net/Makefile.lib
  include $(TOPDIR)/drivers/usb/Makefile.lib
  include $(TOPDIR)/drivers/bluetooth/Makefile.lib
+diff -Nur linux-2.4.29/MAINTAINERS linux-mips/MAINTAINERS
+--- linux-2.4.29/MAINTAINERS   2005-01-19 15:09:24.000000000 +0100
++++ linux-mips/MAINTAINERS     2005-03-26 11:47:05.618729582 +0100
+@@ -1058,8 +1058,8 @@
+ JFS FILESYSTEM
+ P:    Dave Kleikamp
+ M:    shaggy@austin.ibm.com
+-L:    jfs-discussion@oss.software.ibm.com
+-W:    http://oss.software.ibm.com/developerworks/opensource/jfs/
++L:    jfs-discussion@lists.sourceforge.net
++W:    http://jfs.sourceforge.net/
+ S:    Supported
+ JOYSTICK DRIVER
+@@ -1532,7 +1532,7 @@
+ PPP OVER ETHERNET
+ P:    Michal Ostrowski
+-M:    mostrows@styx.uwaterloo.ca
++M:    mostrows@speakeasy.net
+ S:    Maintained
+ PRISM54 WIRELESS DRIVER
+diff -Nur linux-2.4.29/Makefile linux-mips/Makefile
+--- linux-2.4.29/Makefile      2005-01-19 15:10:14.000000000 +0100
++++ linux-mips/Makefile        2005-03-26 11:47:05.686718424 +0100
+@@ -1,11 +1,11 @@
+ VERSION = 2
+ PATCHLEVEL = 4
+-SUBLEVEL = 29
+-EXTRAVERSION =
++SUBLEVEL = 30
++EXTRAVERSION = -pre3
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++ARCH = mips
+ KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+@@ -462,10 +462,11 @@
+       $(MAKE) -C Documentation/DocBook mrproper
+ distclean: mrproper
+-      rm -f core `find . \( -not -type d \) -and \
+-              \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+-              -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+-              -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
++      find . \( -not -type d \) -and \
++              \( -name core -o -name '*.orig' -o -name '*.rej' \
++              -o -name '*~' -o -name '*.bak' -o -name '#*#' \
++              -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \
++              -o -name TAGS -o -name tags \) -print | env -i xargs rm -f
+ backup: mrproper
+       cd .. && tar cf - linux/ | gzip -9 > backup.gz
+@@ -492,7 +493,7 @@
+       $(MAKE) -C Documentation/DocBook man
+ sums:
+-      find . -type f -print | sort | xargs sum > .SUMS
++      find . -type f -print | sort | env -i xargs sum > .SUMS
+ dep-files: scripts/mkdep archdep include/linux/version.h
+       rm -f .depend .hdepend
+diff -Nur linux-2.4.29/mm/filemap.c linux-mips/mm/filemap.c
+--- linux-2.4.29/mm/filemap.c  2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/mm/filemap.c    2005-03-26 11:47:38.292367084 +0100
+@@ -1870,7 +1870,7 @@
+               goto fput_in;
+       if (!in_inode->i_mapping->a_ops->readpage)
+               goto fput_in;
+-      retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count);
++      retval = rw_verify_area(READ, in_file, &in_file->f_pos, count);
+       if (retval)
+               goto fput_in;
+@@ -1887,7 +1887,7 @@
+       if (!out_file->f_op || !out_file->f_op->write)
+               goto fput_out;
+       out_inode = out_file->f_dentry->d_inode;
+-      retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count);
++      retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
+       if (retval)
+               goto fput_out;
+@@ -2589,7 +2589,7 @@
+       long error = -EBADF;
+       struct file * file;
+       struct inode * inode;
+-      unsigned long size, rlim_rss;
++      unsigned long size;
+       /* Doesn't work if there's no mapped file. */
+       if (!vma->vm_file)
+@@ -2605,13 +2605,6 @@
+               end = vma->vm_end;
+       end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+-      /* Make sure this doesn't exceed the process's max rss. */
+-      error = -EIO;
+-      rlim_rss = current->rlim ?  current->rlim[RLIMIT_RSS].rlim_cur :
+-                              LONG_MAX; /* default: see resource.h */
+-      if ((vma->vm_mm->rss + (end - start)) > rlim_rss)
+-              return error;
+-
+       /* round to cluster boundaries if this isn't a "random" area. */
+       if (!VM_RandomReadHint(vma)) {
+               start = CLUSTER_OFFSET(start);
+@@ -3268,7 +3261,12 @@
+                       status = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA);
+       }
+       
+-      err = written ? written : status;
++      /*
++       * generic_osync_inode always returns 0 or negative value.
++       * So 'status < written' is always true, and written should
++       * be returned if status >= 0.
++       */
++      err = (status < 0) ? status : written;
+ out:
+       return err;
+diff -Nur linux-2.4.29/mm/swapfile.c linux-mips/mm/swapfile.c
+--- linux-2.4.29/mm/swapfile.c 2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/mm/swapfile.c   2005-03-26 11:47:38.293366920 +0100
+@@ -738,8 +738,10 @@
+       for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
+               p = swap_info + type;
+               if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
+-                      if (p->swap_file == nd.dentry)
+-                        break;
++                      if (p->swap_file == nd.dentry ||
++                          (S_ISBLK(nd.dentry->d_inode->i_mode) &&
++                          p->swap_device == nd.dentry->d_inode->i_rdev))
++                              break;
+               }
+               prev = type;
+       }
+diff -Nur linux-2.4.29/net/core/dev.c linux-mips/net/core/dev.c
+--- linux-2.4.29/net/core/dev.c        2004-04-14 15:05:41.000000000 +0200
++++ linux-mips/net/core/dev.c  2005-03-26 11:47:38.556323762 +0100
+@@ -2180,10 +2180,26 @@
+               case SIOCSIFNAME:
+                       if (dev->flags&IFF_UP)
+                               return -EBUSY;
+-                      if (__dev_get_by_name(ifr->ifr_newname))
+-                              return -EEXIST;
+-                      memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
+-                      dev->name[IFNAMSIZ-1] = 0;
++                      /* Check if name contains a wildcard */
++                      if (strchr(ifr->ifr_newname, '%')) {
++                              char format[IFNAMSIZ + 1];
++                              int ret;
++                              memcpy(format, ifr->ifr_newname, IFNAMSIZ);
++                              format[IFNAMSIZ-1] = 0;
++                              /* Find a free name based on format.
++                               * dev_alloc_name() replaces "%d" with at max
++                               * 2 digits, so no name overflow. - Jean II */
++                              ret = dev_alloc_name(dev, format);
++                              if (ret < 0)
++                                      return ret;
++                              /* Copy the new name back to caller. */
++                              strncpy(ifr->ifr_newname, dev->name, IFNAMSIZ);
++                      } else {
++                              if (__dev_get_by_name(ifr->ifr_newname))
++                                      return -EEXIST;
++                              memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
++                              dev->name[IFNAMSIZ-1] = 0;
++                      }
+                       notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+                       return 0;
+@@ -2316,6 +2332,7 @@
+                *      - return a value
+                */
+                
++              case SIOCSIFNAME:
+               case SIOCGMIIPHY:
+               case SIOCGMIIREG:
+                       if (!capable(CAP_NET_ADMIN))
+@@ -2351,7 +2368,6 @@
+               case SIOCDELMULTI:
+               case SIOCSIFHWBROADCAST:
+               case SIOCSIFTXQLEN:
+-              case SIOCSIFNAME:
+               case SIOCSMIIREG:
+               case SIOCBONDENSLAVE:
+               case SIOCBONDRELEASE:
+diff -Nur linux-2.4.29/net/core/dst.c linux-mips/net/core/dst.c
+--- linux-2.4.29/net/core/dst.c        2003-08-25 13:44:44.000000000 +0200
++++ linux-mips/net/core/dst.c  2005-03-26 11:47:38.557323598 +0100
+@@ -142,8 +142,13 @@
+ void dst_destroy(struct dst_entry * dst)
+ {
+-      struct neighbour *neigh = dst->neighbour;
+-      struct hh_cache *hh = dst->hh;
++      struct neighbour *neigh;
++      struct hh_cache *hh;
++
++      smp_rmb();
++
++      neigh = dst->neighbour;
++      hh = dst->hh;
+       dst->hh = NULL;
+       if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+diff -Nur linux-2.4.29/net/core/neighbour.c linux-mips/net/core/neighbour.c
+--- linux-2.4.29/net/core/neighbour.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/core/neighbour.c    2005-03-26 11:47:38.629311783 +0100
+@@ -111,7 +111,7 @@
+ unsigned long neigh_rand_reach_time(unsigned long base)
+ {
+-      return (net_random() % base) + (base>>1);
++      return (base ? (net_random() % base) + (base >> 1) : 0);
+ }
+@@ -1469,6 +1469,7 @@
+       nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ndm));
+       ndm = NLMSG_DATA(nlh);
++      nlh->nlmsg_flags = pid ? NLM_F_MULTI : 0;
+       ndm->ndm_family = n->ops->family;
+       ndm->ndm_flags = n->flags;
+       ndm->ndm_type = n->type;
+diff -Nur linux-2.4.29/net/ipv4/ipconfig.c linux-mips/net/ipv4/ipconfig.c
+--- linux-2.4.29/net/ipv4/ipconfig.c   2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/net/ipv4/ipconfig.c     2005-03-26 11:47:38.712298163 +0100
+@@ -1162,7 +1162,7 @@
+               if (*cp == ':')
+                       *cp++ = '\0';
+               addr = in_aton(name);
+-              strcpy(name, cp);
++              memmove(name, cp, strlen(cp) + 1);
+       } else
+               addr = INADDR_NONE;
+diff -Nur linux-2.4.29/net/ipv4/ip_fragment.c linux-mips/net/ipv4/ip_fragment.c
+--- linux-2.4.29/net/ipv4/ip_fragment.c        2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/net/ipv4/ip_fragment.c  2005-03-26 11:47:38.632311291 +0100
+@@ -72,6 +72,7 @@
+ struct ipq {
+       struct ipq      *next;          /* linked list pointers                 */
+       struct list_head lru_list;      /* lru list member                      */
++      u32             user;
+       u32             saddr;
+       u32             daddr;
+       u16             id;
+@@ -242,13 +243,13 @@
+ /* Memory limiting on fragments.  Evictor trashes the oldest 
+  * fragment queue until we are back under the threshold.
+  */
+-static void __ip_evictor(int threshold)
++static void ip_evictor(void)
+ {
+       struct ipq *qp;
+       struct list_head *tmp;
+       int work;
+-      work = atomic_read(&ip_frag_mem) - threshold;
++      work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
+       if (work <= 0)
+               return;
+@@ -273,11 +274,6 @@
+       }
+ }
+-static inline void ip_evictor(void)
+-{
+-      __ip_evictor(sysctl_ipfrag_low_thresh);
+-}
+-
+ /*
+  * Oops, a fragment queue timed out.  Kill it and send an ICMP reply.
+  */
+@@ -324,7 +320,8 @@
+               if(qp->id == qp_in->id          &&
+                  qp->saddr == qp_in->saddr    &&
+                  qp->daddr == qp_in->daddr    &&
+-                 qp->protocol == qp_in->protocol) {
++                 qp->protocol == qp_in->protocol &&
++                 qp->user == qp_in->user) {
+                       atomic_inc(&qp->refcnt);
+                       write_unlock(&ipfrag_lock);
+                       qp_in->last_in |= COMPLETE;
+@@ -351,7 +348,7 @@
+ }
+ /* Add an entry to the 'ipq' queue for a newly received IP datagram. */
+-static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph)
++static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user)
+ {
+       struct ipq *qp;
+@@ -363,6 +360,7 @@
+       qp->id = iph->id;
+       qp->saddr = iph->saddr;
+       qp->daddr = iph->daddr;
++      qp->user = user;
+       qp->len = 0;
+       qp->meat = 0;
+       qp->fragments = NULL;
+@@ -385,7 +383,7 @@
+ /* Find the correct entry in the "incomplete datagrams" queue for
+  * this IP datagram, and create new one, if nothing is found.
+  */
+-static inline struct ipq *ip_find(struct iphdr *iph)
++static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
+ {
+       __u16 id = iph->id;
+       __u32 saddr = iph->saddr;
+@@ -399,7 +397,8 @@
+               if(qp->id == id         &&
+                  qp->saddr == saddr   &&
+                  qp->daddr == daddr   &&
+-                 qp->protocol == protocol) {
++                 qp->protocol == protocol &&
++                 qp->user == user) {
+                       atomic_inc(&qp->refcnt);
+                       read_unlock(&ipfrag_lock);
+                       return qp;
+@@ -407,7 +406,7 @@
+       }
+       read_unlock(&ipfrag_lock);
+-      return ip_frag_create(hash, iph);
++      return ip_frag_create(hash, iph, user);
+ }
+ /* Add new segment to existing queue. */
+@@ -641,7 +640,7 @@
+ }
+ /* Process an incoming IP datagram fragment. */
+-struct sk_buff *ip_defrag(struct sk_buff *skb)
++struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
+ {
+       struct iphdr *iph = skb->nh.iph;
+       struct ipq *qp;
+@@ -656,7 +655,7 @@
+       dev = skb->dev;
+       /* Lookup (or create) queue header */
+-      if ((qp = ip_find(iph)) != NULL) {
++      if ((qp = ip_find(iph, user)) != NULL) {
+               struct sk_buff *ret = NULL;
+               spin_lock(&qp->lock);
+@@ -687,8 +686,3 @@
+       ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+       add_timer(&ipfrag_secret_timer);
+ }
+-
+-void ipfrag_flush(void)
+-{
+-      __ip_evictor(0);
+-}
+diff -Nur linux-2.4.29/net/ipv4/ip_input.c linux-mips/net/ipv4/ip_input.c
+--- linux-2.4.29/net/ipv4/ip_input.c   2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/net/ipv4/ip_input.c     2005-03-26 11:47:38.711298328 +0100
+@@ -170,7 +170,7 @@
+                   && ((sk->bound_dev_if == 0) 
+                       || (sk->bound_dev_if == skb->dev->ifindex))) {
+                       if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-                              skb = ip_defrag(skb);
++                              skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN);
+                               if (skb == NULL) {
+                                       read_unlock(&ip_ra_lock);
+                                       return 1;
+@@ -291,7 +291,7 @@
+        */
+       if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-              skb = ip_defrag(skb);
++              skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER);
+               if (!skb)
+                       return 0;
+       }
+diff -Nur linux-2.4.29/net/ipv4/ipvs/ip_vs_core.c linux-mips/net/ipv4/ipvs/ip_vs_core.c
+--- linux-2.4.29/net/ipv4/ipvs/ip_vs_core.c    2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/ipv4/ipvs/ip_vs_core.c      2005-03-26 11:47:38.913265180 +0100
+@@ -506,7 +506,7 @@
+       /* reassemble IP fragments, but will it happen in ICMP packets?? */
+       if (skb->nh.iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+-              skb = ip_defrag(skb);
++              skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
+               if (!skb)
+                       return NF_STOLEN;
+               *skb_p = skb;
+@@ -658,7 +658,7 @@
+       /* reassemble IP fragments */
+       if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+-              skb = ip_defrag(skb);
++              skb = ip_defrag(skb, IP_DEFRAG_VS_OUT);
+               if (!skb)
+                       return NF_STOLEN;
+               iph = skb->nh.iph;
+@@ -1164,7 +1164,7 @@
+               return NF_ACCEPT;
+       if (iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) {
+-              skb = ip_defrag(skb);
++              skb = ip_defrag(skb, IP_DEFRAG_VS_FWD);
+               if (!skb)
+                       return NF_STOLEN;
+               *skb_p = skb;
+diff -Nur linux-2.4.29/net/ipv4/netfilter/ip_conntrack_core.c linux-mips/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.4.29/net/ipv4/netfilter/ip_conntrack_core.c        2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/ipv4/netfilter/ip_conntrack_core.c  2005-03-26 11:47:38.949259273 +0100
+@@ -834,7 +834,10 @@
+       /* Gather fragments. */
+       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-              *pskb = ip_ct_gather_frags(*pskb);
++              *pskb = ip_ct_gather_frags(*pskb,
++                                         hooknum == NF_IP_PRE_ROUTING ?
++                                         IP_DEFRAG_CONNTRACK_IN :
++                                         IP_DEFRAG_CONNTRACK_OUT);
+               if (!*pskb)
+                       return NF_STOLEN;
+       }
+@@ -1183,29 +1186,22 @@
+       WRITE_UNLOCK(&ip_conntrack_lock);
+ }
+-int ip_ct_no_defrag;
+-
+ /* Returns new sk_buff, or NULL */
+ struct sk_buff *
+-ip_ct_gather_frags(struct sk_buff *skb)
++ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user)
+ {
+       struct sock *sk = skb->sk;
+ #ifdef CONFIG_NETFILTER_DEBUG
+       unsigned int olddebug = skb->nf_debug;
+ #endif
+-      if (unlikely(ip_ct_no_defrag)) {
+-              kfree_skb(skb);
+-              return NULL;
+-      }
+-
+       if (sk) {
+               sock_hold(sk);
+               skb_orphan(skb);
+       }
+       local_bh_disable(); 
+-      skb = ip_defrag(skb);
++      skb = ip_defrag(skb, user);
+       local_bh_enable();
+       if (!skb) {
+diff -Nur linux-2.4.29/net/ipv4/netfilter/ip_conntrack_standalone.c linux-mips/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.4.29/net/ipv4/netfilter/ip_conntrack_standalone.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/ipv4/netfilter/ip_conntrack_standalone.c    2005-03-26 11:47:38.951258945 +0100
+@@ -393,13 +393,6 @@
+  cleanup_inandlocalops:
+       nf_unregister_hook(&ip_conntrack_local_out_ops);
+  cleanup_inops:
+-      /* Frag queues may hold fragments with skb->dst == NULL */
+-      ip_ct_no_defrag = 1;
+-      local_bh_disable();
+-      br_write_lock(BR_NETPROTO_LOCK);
+-      br_write_unlock(BR_NETPROTO_LOCK);
+-      ipfrag_flush();
+-      local_bh_enable();
+       nf_unregister_hook(&ip_conntrack_in_ops);
+  cleanup_proc:
+       proc_net_remove("ip_conntrack");
+diff -Nur linux-2.4.29/net/ipv4/netfilter/ip_fw_compat.c linux-mips/net/ipv4/netfilter/ip_fw_compat.c
+--- linux-2.4.29/net/ipv4/netfilter/ip_fw_compat.c     2003-11-28 19:26:21.000000000 +0100
++++ linux-mips/net/ipv4/netfilter/ip_fw_compat.c       2005-03-26 11:47:38.979254350 +0100
+@@ -108,7 +108,7 @@
+                                         (*pskb)->nh.raw, &redirpt, pskb);
+               if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-                      *pskb = ip_ct_gather_frags(*pskb);
++                      *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_CONNTRACK_IN);
+                       if (!*pskb)
+                               return NF_STOLEN;
+diff -Nur linux-2.4.29/net/ipv4/netfilter/ip_nat_standalone.c linux-mips/net/ipv4/netfilter/ip_nat_standalone.c
+--- linux-2.4.29/net/ipv4/netfilter/ip_nat_standalone.c        2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/ipv4/netfilter/ip_nat_standalone.c  2005-03-26 11:47:38.980254186 +0100
+@@ -201,7 +201,7 @@
+          I'm starting to have nightmares about fragments.  */
+       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
+-              *pskb = ip_ct_gather_frags(*pskb);
++              *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT);
+               if (!*pskb)
+                       return NF_STOLEN;
+diff -Nur linux-2.4.29/net/ipv4/sysctl_net_ipv4.c linux-mips/net/ipv4/sysctl_net_ipv4.c
+--- linux-2.4.29/net/ipv4/sysctl_net_ipv4.c    2004-08-08 01:26:06.000000000 +0200
++++ linux-mips/net/ipv4/sysctl_net_ipv4.c      2005-03-26 11:47:38.713297999 +0100
+@@ -268,6 +268,9 @@
+       {NET_TCP_MODERATE_RCVBUF, "tcp_moderate_rcvbuf",
+        &sysctl_tcp_moderate_rcvbuf, sizeof(int), 0644, NULL,
+        &proc_dointvec},
++      {NET_TCP_BIC_BETA, "tcp_bic_beta",
++       &sysctl_tcp_bic_beta, sizeof(int), 0644, NULL,
++       &proc_dointvec},
+       {0}
+ };
+diff -Nur linux-2.4.29/net/ipv4/tcp_input.c linux-mips/net/ipv4/tcp_input.c
+--- linux-2.4.29/net/ipv4/tcp_input.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-mips/net/ipv4/tcp_input.c    2005-03-26 11:47:38.911265508 +0100
+@@ -107,6 +107,7 @@
+ int sysctl_tcp_bic;
+ int sysctl_tcp_bic_fast_convergence = 1;
+ int sysctl_tcp_bic_low_window = 14;
++int sysctl_tcp_bic_beta = 819;                /* = 819/1024 (BICTCP_BETA_SCALE) */
+ #define FLAG_DATA             0x01 /* Incoming frame contained data.          */
+ #define FLAG_WIN_UPDATE               0x02 /* Incoming ACK was a window update.       */
+@@ -3647,8 +3648,7 @@
+       while (before(start, end)) {
+               struct sk_buff *nskb;
+               int header = skb_headroom(skb);
+-              int copy = (PAGE_SIZE - sizeof(struct sk_buff) -
+-                          sizeof(struct skb_shared_info) - header - 31)&~15;
++              int copy = SKB_MAX_ORDER(header, 0);
+               /* Too big header? This can happen with IPv6. */
+               if (copy < 0)
+diff -Nur linux-2.4.29/net/netlink/af_netlink.c linux-mips/net/netlink/af_netlink.c
+--- linux-2.4.29/net/netlink/af_netlink.c      2005-01-19 15:10:14.000000000 +0100
++++ linux-mips/net/netlink/af_netlink.c        2005-03-26 11:47:39.200218085 +0100
+@@ -327,10 +327,11 @@
+       struct sock **skp;
+       struct netlink_table *table = &nl_table[sk->protocol];
+       struct nl_pid_hash *hash = &table->hash;
++      u32 pid = nlk_sk(sk)->pid;
+       netlink_table_grab();
+       hash->entries--;
+-      for (skp = hash->table; *skp; skp = &((*skp)->next)) {
++      for (skp = nl_pid_hashfn(hash, pid); *skp; skp = &((*skp)->next)) {
+               if (*skp == sk) {
+                       *skp = sk->next;
+                       __sock_put(sk);
+diff -Nur linux-2.4.29/net/netsyms.c linux-mips/net/netsyms.c
+--- linux-2.4.29/net/netsyms.c 2005-01-19 15:10:14.000000000 +0100
++++ linux-mips/net/netsyms.c   2005-03-26 11:47:38.458339844 +0100
+@@ -287,7 +287,6 @@
+ EXPORT_SYMBOL(inetdev_by_index);
+ EXPORT_SYMBOL(in_dev_finish_destroy);
+ EXPORT_SYMBOL(ip_defrag);
+-EXPORT_SYMBOL(ipfrag_flush);
+ /* Route manipulation */
+ EXPORT_SYMBOL(ip_rt_ioctl);
+diff -Nur linux-2.4.29/net/sched/cls_u32.c linux-mips/net/sched/cls_u32.c
+--- linux-2.4.29/net/sched/cls_u32.c   2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/net/sched/cls_u32.c     2005-03-26 11:47:39.202217756 +0100
+@@ -70,6 +70,7 @@
+ {
+       struct tc_u_hnode       *next;
+       u32                     handle;
++      u32                     prio;
+       struct tc_u_common      *tp_c;
+       int                     refcnt;
+       unsigned                divisor;
+@@ -271,6 +272,7 @@
+       root_ht->divisor = 0;
+       root_ht->refcnt++;
+       root_ht->handle = tp_c ? gen_new_htid(tp_c) : 0x80000000;
++      root_ht->prio = tp->prio;
+       if (tp_c == NULL) {
+               tp_c = kmalloc(sizeof(*tp_c), GFP_KERNEL);
+@@ -534,6 +536,7 @@
+               ht->refcnt = 0;
+               ht->divisor = divisor;
+               ht->handle = handle;
++              ht->prio = tp->prio;
+               ht->next = tp_c->hlist;
+               tp_c->hlist = ht;
+               *arg = (unsigned long)ht;
+@@ -606,6 +609,8 @@
+               return;
+       for (ht = tp_c->hlist; ht; ht = ht->next) {
++              if (ht->prio != tp->prio)
++                      continue;
+               if (arg->count >= arg->skip) {
+                       if (arg->fn(tp, (unsigned long)ht, arg) < 0) {
+                               arg->stop = 1;
+diff -Nur linux-2.4.29/net/sched/sch_ingress.c linux-mips/net/sched/sch_ingress.c
+--- linux-2.4.29/net/sched/sch_ingress.c       2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/net/sched/sch_ingress.c 2005-03-26 11:47:39.203217592 +0100
+@@ -14,6 +14,7 @@
+ #include <linux/netdevice.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv6.h>
+ #include <linux/netfilter.h>
+ #include <linux/smp.h>
+ #include <net/pkt_sched.h>
+@@ -241,6 +242,15 @@
+       NF_IP_PRI_FILTER + 1
+ };
++static struct nf_hook_ops ing6_ops =
++{
++      { NULL, NULL},
++      ing_hook,
++      PF_INET6,
++      NF_IP6_PRE_ROUTING,
++      NF_IP6_PRI_FILTER + 1
++};
++
+ int ingress_init(struct Qdisc *sch,struct rtattr *opt)
+ {
+       struct ingress_qdisc_data *p = PRIV(sch);
+@@ -249,8 +259,13 @@
+               if (nf_register_hook(&ing_ops) < 0) {
+                       printk("ingress qdisc registration error \n");
+                       goto error;
+-                      }
++              }
+               nf_registered++;
++              if (nf_register_hook(&ing6_ops) < 0) {
++                      printk("IPv6 ingress qdisc registration error, " \
++                          "disabling IPv6 support.\n");
++              } else
++                      nf_registered++;
+       }
+       DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
+@@ -374,8 +389,11 @@
+ void cleanup_module(void) 
+ {
+       unregister_qdisc(&ingress_qdisc_ops);
+-      if (nf_registered)
++      if (nf_registered) {
+               nf_unregister_hook(&ing_ops);
++              if (nf_registered > 1)
++                      nf_unregister_hook(&ing6_ops);
++      }
+ }
+ #endif
+ MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.29/net/sched/sch_netem.c linux-mips/net/sched/sch_netem.c
+--- linux-2.4.29/net/sched/sch_netem.c 2005-01-19 15:10:14.000000000 +0100
++++ linux-mips/net/sched/sch_netem.c   2005-03-26 11:47:39.283204465 +0100
+@@ -180,6 +180,7 @@
+       if (q->loss && q->loss >= get_crandom(&q->loss_cor)) {
+               pr_debug("netem_enqueue: random loss\n");
+               sch->stats.drops++;
++              kfree_skb(skb);
+               return 0;       /* lie about loss so TCP doesn't know */
+       }
+diff -Nur linux-2.4.29/net/unix/af_unix.c linux-mips/net/unix/af_unix.c
+--- linux-2.4.29/net/unix/af_unix.c    2004-11-17 12:54:22.000000000 +0100
++++ linux-mips/net/unix/af_unix.c      2005-03-26 11:47:39.318198721 +0100
+@@ -1686,8 +1686,13 @@
+                       }
+                       spin_lock(&sk->receive_queue.lock);
+-                      if((skb=skb_peek(&sk->receive_queue))!=NULL)
+-                              amount=skb->len;
++                      if (sk->type == SOCK_STREAM) {
++                              skb_queue_walk(&sk->receive_queue, skb)
++                                      amount += skb->len;
++                      } else {
++                              if((skb=skb_peek(&sk->receive_queue))!=NULL)
++                                      amount=skb->len;
++                      }
+                       spin_unlock(&sk->receive_queue.lock);
+                       err = put_user(amount, (int *)arg);
+                       break;
+diff -Nur linux-2.4.29/scripts/Configure linux-mips/scripts/Configure
+--- linux-2.4.29/scripts/Configure     2003-06-13 16:51:39.000000000 +0200
++++ linux-mips/scripts/Configure       2005-03-26 11:47:39.412183296 +0100
+@@ -378,15 +378,18 @@
+ function hex () {
+       old=$(eval echo "\${$2}")
+       def=${old:-$3}
+-      def=${def#*[x,X]}
+       while :; do
+         readln "$1 ($2) [$def] " "$def" "$old"
+-        ans=${ans#*[x,X]}
+-        if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
++        if expr "$ans" : '0x[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
+           define_hex "$2" "$ans"
+           break
+         else
+-          help "$2"
++          if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
++            define_hex "$2" "0x$ans"
++            break
++          else
++            help "$2"
++          fi
+         fi
+       done
+ }
index 27c5cb54c75361c50a871cf01985e3542e107bae..b1c34abe4d388b10d9884c031fb8870958a324e2 100644 (file)
@@ -1,7 +1,40 @@
-diff -Nur linux-mips-cvs/include/linux/if_bridge.h linux-ebtables/include/linux/if_bridge.h
---- linux-mips-cvs/include/linux/if_bridge.h   2000-02-24 01:13:20.000000000 +0100
-+++ linux-ebtables/include/linux/if_bridge.h   2005-02-07 05:52:50.000000000 +0100
-@@ -102,7 +102,8 @@
+--- linux-2.4.29/net/bridge/br_private.h       2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/bridge/br_private.h      2005-03-14 21:24:04.000000000 +0100
+@@ -143,8 +143,10 @@ extern void br_fdb_insert(struct net_bri
+ /* br_forward.c */
+ extern void br_deliver(struct net_bridge_port *to,
+               struct sk_buff *skb);
++extern int br_dev_queue_push_xmit(struct sk_buff *skb);
+ extern void br_forward(struct net_bridge_port *to,
+               struct sk_buff *skb);
++extern int br_forward_finish(struct sk_buff *skb);
+ extern void br_flood_deliver(struct net_bridge *br,
+                     struct sk_buff *skb,
+                     int clone);
+@@ -165,7 +167,8 @@ extern void br_get_port_ifindices(struct
+                          int *ifindices);
+ /* br_input.c */
+-extern void br_handle_frame(struct sk_buff *skb);
++extern int br_handle_frame_finish(struct sk_buff *skb);
++extern int br_handle_frame(struct sk_buff *skb);
+ /* br_ioctl.c */
+ extern int br_ioctl(struct net_bridge *br,
+@@ -175,6 +178,10 @@ extern int br_ioctl(struct net_bridge *b
+            unsigned long arg2);
+ extern int br_ioctl_deviceless_stub(unsigned long arg);
++/* br_netfilter.c */
++extern int br_netfilter_init(void);
++extern void br_netfilter_fini(void);
++
+ /* br_stp.c */
+ extern int br_is_root_bridge(struct net_bridge *br);
+ extern struct net_bridge_port *br_get_port(struct net_bridge *br,
+--- linux-2.4.29/include/linux/if_bridge.h     2001-11-22 20:47:12.000000000 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/if_bridge.h    2005-03-14 21:11:28.000000000 +0100
+@@ -102,7 +102,8 @@ struct net_bridge;
  struct net_bridge_port;
  
  extern int (*br_ioctl_hook)(unsigned long arg);
@@ -11,7398 +44,5247 @@ diff -Nur linux-mips-cvs/include/linux/if_bridge.h linux-ebtables/include/linux/
  
  #endif
  
-diff -Nur linux-mips-cvs/include/linux/netfilter.h linux-ebtables/include/linux/netfilter.h
---- linux-mips-cvs/include/linux/netfilter.h   2005-01-20 03:19:24.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter.h   2005-02-07 05:52:50.000000000 +0100
-@@ -118,17 +118,23 @@
- /* This is gross, but inline doesn't cut it for avoiding the function
-    call in fast path: gcc doesn't inline (needs value tracking?). --RR */
- #ifdef CONFIG_NETFILTER_DEBUG
--#define NF_HOOK nf_hook_slow
-+#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                   \
-+nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN)
-+#define NF_HOOK_THRESH nf_hook_slow
- #else
- #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                   \
- (list_empty(&nf_hooks[(pf)][(hook)])                                  \
-  ? (okfn)(skb)                                                                \
-- : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
-+ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), INT_MIN))
-+#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)    \
-+(list_empty(&nf_hooks[(pf)][(hook)])                                  \
-+ ? (okfn)(skb)                                                                \
-+ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn), (thresh)))
+--- linux-2.4.29/net/core/dev.c        2004-04-14 15:05:41.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/core/dev.c       2005-03-14 00:00:29.000000000 +0100
+@@ -1426,7 +1426,7 @@ static void net_tx_action(struct softirq
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+-void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
++int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
  #endif
  
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
-                struct net_device *indev, struct net_device *outdev,
--               int (*okfn)(struct sk_buff *));
-+               int (*okfn)(struct sk_buff *), int thresh);
static __inline__ int handle_bridge(struct sk_buff *skb,
+@@ -1443,7 +1443,6 @@ static __inline__ int handle_bridge(stru
+               }
+       }
  
- /* Call setsockopt() */
- int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt, 
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_802_3.h linux-ebtables/include/linux/netfilter_bridge/ebt_802_3.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_802_3.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_802_3.h  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,60 @@
-+#ifndef __LINUX_BRIDGE_EBT_802_3_H
-+#define __LINUX_BRIDGE_EBT_802_3_H
-+
-+#define EBT_802_3_SAP 0x01
-+#define EBT_802_3_TYPE 0x02
+-      br_handle_frame_hook(skb);
+       return ret;
+ }
+@@ -1503,7 +1502,12 @@ int netif_receive_skb(struct sk_buff *sk
+ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+       if (skb->dev->br_port != NULL && br_handle_frame_hook != NULL &&
+           skb->pkt_type != PACKET_LOOPBACK) {
+-              return handle_bridge(skb, pt_prev);
++              int ret;
 +
-+#define EBT_802_3_MATCH "802_3"
++              ret = handle_bridge(skb, pt_prev);
++              if (br_handle_frame_hook(skb) == 0)
++                      return ret;
++              pt_prev = NULL;
+       }
+ #endif
+--- linux-2.4.29/net/bridge/br_input.c 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/bridge/br_input.c        2005-03-14 00:00:29.000000000 +0100
+@@ -24,6 +24,9 @@ unsigned char bridge_ula[6] = { 0x01, 0x
+ static int br_pass_frame_up_finish(struct sk_buff *skb)
+ {
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug = 0;
++#endif
+       netif_rx(skb);
+       return 0;
+@@ -46,7 +49,7 @@ static void br_pass_frame_up(struct net_
+                       br_pass_frame_up_finish);
+ }
+-static int br_handle_frame_finish(struct sk_buff *skb)
++int br_handle_frame_finish(struct sk_buff *skb)
+ {
+       struct net_bridge *br;
+       unsigned char *dest;
+@@ -112,7 +115,7 @@ err_nolock:
+       return 0;
+ }
+-void br_handle_frame(struct sk_buff *skb)
++int br_handle_frame(struct sk_buff *skb)
+ {
+       struct net_bridge *br;
+       unsigned char *dest;
+@@ -146,26 +149,35 @@ void br_handle_frame(struct sk_buff *skb
+               goto handle_special_frame;
+       if (p->state == BR_STATE_FORWARDING) {
++              if (br_should_route_hook && br_should_route_hook(&skb)) {
++                      read_unlock(&br->lock);
++                      return -1;
++              }
 +
-+/*
-+ * If frame has DSAP/SSAP value 0xaa you must check the SNAP type
-+ * to discover what kind of packet we're carrying. 
-+ */
-+#define CHECK_TYPE 0xaa
++              if (!memcmp(p->br->dev.dev_addr, dest, ETH_ALEN))
++                      skb->pkt_type = PACKET_HOST;
 +
-+/*
-+ * Control field may be one or two bytes.  If the first byte has
-+ * the value 0x03 then the entire length is one byte, otherwise it is two.
-+ * One byte controls are used in Unnumbered Information frames.
-+ * Two byte controls are used in Numbered Information frames.
-+ */
-+#define IS_UI 0x03
+               NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+                       br_handle_frame_finish);
+               read_unlock(&br->lock);
+-              return;
++              return 0;
+       }
+ err:
+       read_unlock(&br->lock);
+ err_nolock:
+       kfree_skb(skb);
+-      return;
++      return 0;
+ handle_special_frame:
+       if (!dest[5]) {
+               NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,NULL,
+                       br_stp_handle_bpdu);
+               read_unlock(&br->lock);
+-              return;
++              return 0;
+       }
+       read_unlock(&br->lock);
+       kfree_skb(skb);
++      return 0;
+ }
+--- linux-2.4.29/net/bridge/br_forward.c       2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/br_forward.c      2005-03-14 00:00:29.000000000 +0100
+@@ -30,18 +30,21 @@ static inline int should_deliver(struct 
+       return 1;
+ }
+-static int __dev_queue_push_xmit(struct sk_buff *skb)
++int br_dev_queue_push_xmit(struct sk_buff *skb)
+ {
++#ifdef CONFIG_NETFILTER
++      nf_bridge_maybe_copy_header(skb);
++#endif
+       skb_push(skb, ETH_HLEN);
+       dev_queue_xmit(skb);
+       return 0;
+ }
+-static int __br_forward_finish(struct sk_buff *skb)
++int br_forward_finish(struct sk_buff *skb)
+ {
+       NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
+-                      __dev_queue_push_xmit);
++                      br_dev_queue_push_xmit);
+       return 0;
+ }
+@@ -49,8 +52,11 @@ static int __br_forward_finish(struct sk
+ static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
+ {
+       skb->dev = to->dev;
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug = 0;
++#endif
+       NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
+-                      __br_forward_finish);
++                      br_forward_finish);
+ }
+ static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb)
+@@ -62,7 +68,7 @@ static void __br_forward(struct net_brid
+       skb->ip_summed = CHECKSUM_NONE;
+       NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
+-                      __br_forward_finish);
++                      br_forward_finish);
+ }
+ /* called under bridge lock */
+--- linux-2.4.29/net/bridge/br.c       2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/bridge/br.c      2005-03-14 00:00:29.000000000 +0100
+@@ -30,6 +30,8 @@
+ #include "../atm/lec.h"
+ #endif
++int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
 +
-+#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3)
+ void br_dec_use_count()
+ {
+       MOD_DEC_USE_COUNT;
+@@ -44,6 +46,10 @@ static int __init br_init(void)
+ {
+       printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
++#ifdef CONFIG_NETFILTER
++      if (br_netfilter_init())
++              return 1;
++#endif
+       br_handle_frame_hook = br_handle_frame;
+       br_ioctl_hook = br_ioctl_deviceless_stub;
+ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+@@ -57,6 +63,9 @@ static int __init br_init(void)
+ static void __exit br_deinit(void)
+ {
++#ifdef CONFIG_NETFILTER
++      br_netfilter_fini();
++#endif
+       unregister_netdevice_notifier(&br_device_notifier);
+       rtnl_lock();
+@@ -73,7 +82,7 @@ static void __exit br_deinit(void)
+ #endif
+ }
+-EXPORT_NO_SYMBOLS;
++EXPORT_SYMBOL(br_should_route_hook);
+ module_init(br_init)
+ module_exit(br_deinit)
+--- linux-2.4.29/net/bridge/Makefile   2000-12-29 23:07:24.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/Makefile  2005-03-14 00:00:29.000000000 +0100
+@@ -7,10 +7,17 @@
+ #
+ # Note 2! The CFLAGS definition is now in the main makefile...
++export-objs := br.o
 +
-+/* ui has one byte ctrl, ni has two */
-+struct hdr_ui {
-+      uint8_t dsap;
-+      uint8_t ssap;
-+      uint8_t ctrl;
-+      uint8_t orig[3];
-+      uint16_t type;
-+};
+ O_TARGET      := bridge.o
+ obj-y         := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
+                       br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
+                       br_stp_if.o br_stp_timer.o
 +
-+struct hdr_ni {
-+      uint8_t dsap;
-+      uint8_t ssap;
-+      uint16_t ctrl;
-+      uint8_t  orig[3];
-+      uint16_t type;
-+};
++ifeq ($(CONFIG_NETFILTER),y)
++obj-y         += br_netfilter.o
++endif
 +
-+struct ebt_802_3_hdr {
-+      uint8_t  daddr[6];
-+      uint8_t  saddr[6];
-+      uint16_t len;
-+      union {
-+              struct hdr_ui ui;
-+              struct hdr_ni ni;
-+      } llc;
+ obj-m         := $(O_TARGET)
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.29/include/linux/netfilter_bridge.h      2001-06-12 04:15:27.000000000 +0200
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge.h     2005-03-14 21:24:06.000000000 +0100
+@@ -6,6 +6,10 @@
+ #include <linux/config.h>
+ #include <linux/netfilter.h>
++#if defined(__KERNEL__) && defined(CONFIG_NETFILTER)
++#include <asm/atomic.h>
++#include <linux/if_ether.h>
++#endif
+ /* Bridge Hooks */
+ /* After promisc drops, checksum checks. */
+@@ -18,7 +22,76 @@
+ #define NF_BR_LOCAL_OUT               3
+ /* Packets about to hit the wire. */
+ #define NF_BR_POST_ROUTING    4
+-#define NF_BR_NUMHOOKS                5
++/* Not really a hook, but used for the ebtables broute table */
++#define NF_BR_BROUTING                5
++#define NF_BR_NUMHOOKS                6
++
++#ifdef __KERNEL__
++
++#define BRNF_PKT_TYPE                 0x01
++#define BRNF_BRIDGED_DNAT             0x02
++#define BRNF_DONT_TAKE_PARENT         0x04
++#define BRNF_BRIDGED                  0x08
++#define BRNF_NF_BRIDGE_PREROUTING     0x10
++
++enum nf_br_hook_priorities {
++      NF_BR_PRI_FIRST = INT_MIN,
++      NF_BR_PRI_NAT_DST_BRIDGED = -300,
++      NF_BR_PRI_FILTER_BRIDGED = -200,
++      NF_BR_PRI_BRNF = 0,
++      NF_BR_PRI_NAT_DST_OTHER = 100,
++      NF_BR_PRI_FILTER_OTHER = 200,
++      NF_BR_PRI_NAT_SRC = 300,
++      NF_BR_PRI_LAST = INT_MAX,
 +};
 +
-+struct ebt_802_3_info 
++#ifdef CONFIG_NETFILTER
++static inline
++struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
 +{
-+      uint8_t  sap;
-+      uint16_t type;
-+      uint8_t  bitmask;
-+      uint8_t  invflags;
-+};
++      struct nf_bridge_info **nf_bridge = &(skb->nf_bridge);
 +
++      if ((*nf_bridge = kmalloc(sizeof(**nf_bridge), GFP_ATOMIC)) != NULL) {
++              atomic_set(&(*nf_bridge)->use, 1);
++              (*nf_bridge)->mask = 0;
++              (*nf_bridge)->physindev = (*nf_bridge)->physoutdev = NULL;
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++              (*nf_bridge)->netoutdev = NULL;
 +#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_among.h linux-ebtables/include/linux/netfilter_bridge/ebt_among.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_among.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_among.h  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,65 @@
-+#ifndef __LINUX_BRIDGE_EBT_AMONG_H
-+#define __LINUX_BRIDGE_EBT_AMONG_H
++      }
 +
-+#define EBT_AMONG_DST 0x01
-+#define EBT_AMONG_SRC 0x02
++      return *nf_bridge;
++}
 +
-+/* Grzegorz Borowiak <grzes@gnu.univ.gda.pl> 2003
-+ * 
-+ * Write-once-read-many hash table, used for checking if a given
-+ * MAC address belongs to a set or not and possibly for checking
-+ * if it is related with a given IPv4 address.
++/* Only used in br_forward.c */
++static inline
++void nf_bridge_maybe_copy_header(struct sk_buff *skb)
++{
++      if (skb->nf_bridge) {
++              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++                      memcpy(skb->data - 18, skb->nf_bridge->data, 18);
++                      skb_push(skb, 4);
++              } else
++                      memcpy(skb->data - 16, skb->nf_bridge->data, 16);
++      }
++}
++
++static inline
++void nf_bridge_save_header(struct sk_buff *skb)
++{
++        int header_size = 16;
++
++      if (skb->protocol == __constant_htons(ETH_P_8021Q))
++              header_size = 18;
++      memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
++}
++struct bridge_skb_cb {
++      union {
++              __u32 ipv4;
++      } daddr;
++};
++#endif /* CONFIG_NETFILTER */
++#endif /* __KERNEL__ */
+ #endif
+--- linux-2.4.29/include/linux/netfilter_ipv4/ip_tables.h      2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_ipv4/ip_tables.h     2005-03-14 21:24:28.000000000 +0100
+@@ -159,7 +159,7 @@ struct ipt_entry
+ #define IPT_CONTINUE 0xFFFFFFFF
+ /* For standard target */
+-#define IPT_RETURN (-NF_MAX_VERDICT - 1)
++#define IPT_RETURN (-NF_REPEAT - 1)
+ /* TCP matching stuff */
+ struct ipt_tcp
+--- linux-2.4.29/include/linux/netfilter_ipv6/ip6_tables.h     2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_ipv6/ip6_tables.h    2005-03-14 00:00:29.000000000 +0100
+@@ -167,7 +167,7 @@ struct ip6t_entry
+ #define IP6T_CONTINUE 0xFFFFFFFF
+ /* For standard target */
+-#define IP6T_RETURN (-NF_MAX_VERDICT - 1)
++#define IP6T_RETURN (-NF_REPEAT - 1)
+ /* TCP matching stuff */
+ struct ip6t_tcp
+--- linux-2.4.29/include/linux/netfilter_arp/arp_tables.h      2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_arp/arp_tables.h     2005-03-14 21:24:31.000000000 +0100
+@@ -154,7 +154,7 @@ struct arpt_entry
+ #define ARPT_CONTINUE 0xFFFFFFFF
+ /* For standard target */
+-#define ARPT_RETURN (-NF_MAX_VERDICT - 1)
++#define ARPT_RETURN (-NF_REPEAT - 1)
+ /* The argument to ARPT_SO_GET_INFO */
+ struct arpt_getinfo
+--- linux-2.4.29/net/Makefile  2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/Makefile 2005-03-14 00:00:29.000000000 +0100
+@@ -7,7 +7,8 @@
+ O_TARGET :=   network.o
+-mod-subdirs :=        ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802
++mod-subdirs :=        ipv4/netfilter ipv6/netfilter bridge/netfilter ipx irda \
++      bluetooth atm netlink sched core sctp 802
+ export-objs :=        netsyms.o
+ subdir-y :=   core ethernet
+@@ -27,6 +28,12 @@ subdir-$(CONFIG_NETFILTER)  += ipv6/netfi
+ endif
+ endif
++ifneq ($(CONFIG_BRIDGE),n)
++ifneq ($(CONFIG_BRIDGE),)
++subdir-$(CONFIG_BRIDGE)               += bridge/netfilter
++endif
++endif
++
+ subdir-$(CONFIG_KHTTPD)               += khttpd
+ subdir-$(CONFIG_PACKET)               += packet
+ subdir-$(CONFIG_NET_SCHED)    += sched
+--- linux-2.4.29/net/Config.in 2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/Config.in        2005-03-14 00:00:29.000000000 +0100
+@@ -70,6 +70,9 @@ if [ "$CONFIG_DECNET" != "n" ]; then
+    source net/decnet/Config.in
+ fi
+ dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
++if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
++   source net/bridge/netfilter/Config.in
++fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
+    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/Makefile        2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,34 @@
++#
++# Makefile for the netfilter modules on top of bridging.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now in the main makefile...
++
++O_TARGET      := netfilter.o
++
++export-objs := ebtables.o
++
++obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
++obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
++obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
++obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o
++obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
++obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o
++obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
++obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o
++obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
++obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o
++obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
++obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o
++obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o
++obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
++obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_ulog.o
++obj-$(CONFIG_BRIDGE_EBT_ARPREPLY) += ebt_arpreply.o
++obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
++obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
++obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
++obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
++include $(TOPDIR)/Rules.make
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/Config.in       2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,23 @@
++#
++# Bridge netfilter configuration
++#
++dep_tristate '  Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
++dep_tristate '    ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: ulog support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: among filter support' CONFIG_BRIDGE_EBT_AMONG $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: limit filter support' CONFIG_BRIDGE_EBT_LIMIT $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: 802.1Q VLAN filter support' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: 802.3 filter support' CONFIG_BRIDGE_EBT_802_3 $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: packet type filter support' CONFIG_BRIDGE_EBT_PKTTYPE $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: STP filter support' CONFIG_BRIDGE_EBT_STP $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: arp reply target support' CONFIG_BRIDGE_EBT_ARPREPLY $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
++dep_tristate '    ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebtable_filter.c        2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,90 @@
++/*
++ *  ebtable_filter
 + *
-+ * The hash value of an address is its last byte.
-+ * 
-+ * In real-world ethernet addresses, values of the last byte are
-+ * evenly distributed and there is no need to consider other bytes.
-+ * It would only slow the routines down.
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
 + *
-+ * For MAC address comparison speedup reasons, we introduce a trick.
-+ * MAC address is mapped onto an array of two 32-bit integers.
-+ * This pair of integers is compared with MAC addresses in the
-+ * hash table, which are stored also in form of pairs of integers
-+ * (in `cmp' array). This is quick as it requires only two elementary
-+ * number comparisons in worst case. Further, we take advantage of
-+ * fact that entropy of 3 last bytes of address is larger than entropy
-+ * of 3 first bytes. So first we compare 4 last bytes of addresses and
-+ * if they are the same we compare 2 first.
++ *  April, 2002
 + *
-+ * Yes, it is a memory overhead, but in 2003 AD, who cares?
 + */
 +
-+struct ebt_mac_wormhash_tuple
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/module.h>
++
++#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
++   (1 << NF_BR_LOCAL_OUT))
++
++static struct ebt_entries initial_chains[] =
 +{
-+      uint32_t cmp[2];
-+      uint32_t ip;
++  {0, "INPUT", 0, EBT_ACCEPT, 0},
++  {0, "FORWARD", 0, EBT_ACCEPT, 0},
++  {0, "OUTPUT", 0, EBT_ACCEPT, 0}
 +};
 +
-+struct ebt_mac_wormhash
++static struct ebt_replace initial_table =
 +{
-+      int table[257];
-+      int poolsize;
-+      struct ebt_mac_wormhash_tuple pool[0];
++  "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
 +};
 +
-+#define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \
-+              + (x)->poolsize * sizeof(struct ebt_mac_wormhash_tuple) : 0)
-+
-+struct ebt_among_info
++static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
 +{
-+      int wh_dst_ofs;
-+      int wh_src_ofs;
-+      int bitmask;
-+};
++      if (valid_hooks & ~FILTER_VALID_HOOKS)
++              return -EINVAL;
++      return 0;
++}
 +
-+#define EBT_AMONG_DST_NEG 0x1
-+#define EBT_AMONG_SRC_NEG 0x2
-+
-+#define ebt_among_wh_dst(x) ((x)->wh_dst_ofs ? \
-+      (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_dst_ofs) : NULL)
-+#define ebt_among_wh_src(x) ((x)->wh_src_ofs ? \
-+      (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_src_ofs) : NULL)
-+
-+#define EBT_AMONG_MATCH "among"
++static struct ebt_table frame_filter =
++{ 
++  {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, 
++  RW_LOCK_UNLOCKED, check, NULL
++};
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_arp.h linux-ebtables/include/linux/netfilter_bridge/ebt_arp.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_arp.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_arp.h    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,32 @@
-+#ifndef __LINUX_BRIDGE_EBT_ARP_H
-+#define __LINUX_BRIDGE_EBT_ARP_H
++static unsigned int
++ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
++   const struct net_device *out, int (*okfn)(struct sk_buff *))
++{
++      return ebt_do_table(hook, pskb, in, out, &frame_filter);
++}
 +
-+#define EBT_ARP_OPCODE 0x01
-+#define EBT_ARP_HTYPE 0x02
-+#define EBT_ARP_PTYPE 0x04
-+#define EBT_ARP_SRC_IP 0x08
-+#define EBT_ARP_DST_IP 0x10
-+#define EBT_ARP_SRC_MAC 0x20
-+#define EBT_ARP_DST_MAC 0x40
-+#define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \
-+   EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)
-+#define EBT_ARP_MATCH "arp"
++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}
++};
 +
-+struct ebt_arp_info
++static int __init init(void)
 +{
-+      uint16_t htype;
-+      uint16_t ptype;
-+      uint16_t opcode;
-+      uint32_t saddr;
-+      uint32_t smsk;
-+      uint32_t daddr;
-+      uint32_t dmsk;
-+      unsigned char smaddr[ETH_ALEN];
-+      unsigned char smmsk[ETH_ALEN];
-+      unsigned char dmaddr[ETH_ALEN];
-+      unsigned char dmmsk[ETH_ALEN];
-+      uint8_t  bitmask;
-+      uint8_t  invflags;
-+};
++      int i, j, ret;
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_arpreply.h linux-ebtables/include/linux/netfilter_bridge/ebt_arpreply.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_arpreply.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_arpreply.h       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,11 @@
-+#ifndef __LINUX_BRIDGE_EBT_ARPREPLY_H
-+#define __LINUX_BRIDGE_EBT_ARPREPLY_H
++      ret = ebt_register_table(&frame_filter);
++      if (ret < 0)
++              return ret;
++      for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
++              if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
++                      goto cleanup;
++      return ret;
++cleanup:
++      for (j = 0; j < i; j++)
++              nf_unregister_hook(&ebt_ops_filter[j]);
++      ebt_unregister_table(&frame_filter);
++      return ret;
++}
 +
-+struct ebt_arpreply_info
++static void __exit fini(void)
 +{
-+      unsigned char mac[ETH_ALEN];
-+      int target;
-+};
-+#define EBT_ARPREPLY_TARGET "arpreply"
++      int i;
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_ip.h linux-ebtables/include/linux/netfilter_bridge/ebt_ip.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_ip.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_ip.h     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,43 @@
++      for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
++              nf_unregister_hook(&ebt_ops_filter[i]);
++      ebt_unregister_table(&frame_filter);
++}
++
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebtable_nat.c   2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,96 @@
 +/*
-+ *  ebt_ip
++ *  ebtable_nat
 + *
 + *    Authors:
 + *    Bart De Schuymer <bart.de.schuymer@pandora.be>
 + *
 + *  April, 2002
 + *
-+ *  Changes:
-+ *    added ip-sport and ip-dport
-+ *    Innominate Security Technologies AG <mhopf@innominate.com>
-+ *    September, 2002
 + */
 +
-+#ifndef __LINUX_BRIDGE_EBT_IP_H
-+#define __LINUX_BRIDGE_EBT_IP_H
-+
-+#define EBT_IP_SOURCE 0x01
-+#define EBT_IP_DEST 0x02
-+#define EBT_IP_TOS 0x04
-+#define EBT_IP_PROTO 0x08
-+#define EBT_IP_SPORT 0x10
-+#define EBT_IP_DPORT 0x20
-+#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
-+ EBT_IP_SPORT | EBT_IP_DPORT )
-+#define EBT_IP_MATCH "ip"
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/module.h>
++#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
++   (1 << NF_BR_POST_ROUTING))
 +
-+// the same values are used for the invflags
-+struct ebt_ip_info
++static struct ebt_entries initial_chains[] =
 +{
-+      uint32_t saddr;
-+      uint32_t daddr;
-+      uint32_t smsk;
-+      uint32_t dmsk;
-+      uint8_t  tos;
-+      uint8_t  protocol;
-+      uint8_t  bitmask;
-+      uint8_t  invflags;
-+      uint16_t sport[2];
-+      uint16_t dport[2];
++  {0, "PREROUTING", 0, EBT_ACCEPT, 0},
++  {0, "OUTPUT", 0, EBT_ACCEPT, 0},
++  {0, "POSTROUTING", 0, EBT_ACCEPT, 0}
 +};
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_limit.h linux-ebtables/include/linux/netfilter_bridge/ebt_limit.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_limit.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_limit.h  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,23 @@
-+#ifndef __LINUX_BRIDGE_EBT_LIMIT_H
-+#define __LINUX_BRIDGE_EBT_LIMIT_H
-+
-+#define EBT_LIMIT_MATCH "limit"
-+
-+/* timings are in milliseconds. */
-+#define EBT_LIMIT_SCALE 10000
-+
-+/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
-+   seconds, or one every 59 hours. */
-+
-+struct ebt_limit_info
++static struct ebt_replace initial_table =
 +{
-+      u_int32_t avg;    /* Average secs between packets * scale */
-+      u_int32_t burst;  /* Period multiplier for upper limit. */
-+
-+      /* Used internally by the kernel */
-+      unsigned long prev;
-+      u_int32_t credit;
-+      u_int32_t credit_cap, cost;
++  "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
 +};
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_log.h linux-ebtables/include/linux/netfilter_bridge/ebt_log.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_log.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_log.h    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,17 @@
-+#ifndef __LINUX_BRIDGE_EBT_LOG_H
-+#define __LINUX_BRIDGE_EBT_LOG_H
-+
-+#define EBT_LOG_IP 0x01 // if the frame is made by ip, log the ip information
-+#define EBT_LOG_ARP 0x02
-+#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
-+#define EBT_LOG_PREFIX_SIZE 30
-+#define EBT_LOG_WATCHER "log"
-+
-+struct ebt_log_info
++static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
 +{
-+      uint8_t loglevel;
-+      uint8_t prefix[EBT_LOG_PREFIX_SIZE];
-+      uint32_t bitmask;
-+};
-+
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_mark_m.h linux-ebtables/include/linux/netfilter_bridge/ebt_mark_m.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_mark_m.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_mark_m.h 2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,15 @@
-+#ifndef __LINUX_BRIDGE_EBT_MARK_M_H
-+#define __LINUX_BRIDGE_EBT_MARK_M_H
++      if (valid_hooks & ~NAT_VALID_HOOKS)
++              return -EINVAL;
++      return 0;
++}
 +
-+#define EBT_MARK_AND 0x01
-+#define EBT_MARK_OR 0x02
-+#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR)
-+struct ebt_mark_m_info
++static struct ebt_table frame_nat =
 +{
-+      unsigned long mark, mask;
-+      uint8_t invert;
-+      uint8_t bitmask;
++  {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS,
++  RW_LOCK_UNLOCKED, check, NULL
 +};
-+#define EBT_MARK_MATCH "mark_m"
-+
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_mark_t.h linux-ebtables/include/linux/netfilter_bridge/ebt_mark_t.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_mark_t.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_mark_t.h 2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,12 @@
-+#ifndef __LINUX_BRIDGE_EBT_MARK_T_H
-+#define __LINUX_BRIDGE_EBT_MARK_T_H
 +
-+struct ebt_mark_t_info
++static unsigned int
++ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
++   , const struct net_device *out, int (*okfn)(struct sk_buff *))
 +{
-+      unsigned long mark;
-+      // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN
-+      int target;
-+};
-+#define EBT_MARK_TARGET "mark"
-+
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_nat.h linux-ebtables/include/linux/netfilter_bridge/ebt_nat.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_nat.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_nat.h    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,13 @@
-+#ifndef __LINUX_BRIDGE_EBT_NAT_H
-+#define __LINUX_BRIDGE_EBT_NAT_H
++      return ebt_do_table(hook, pskb, in, out, &frame_nat);
++}
 +
-+struct ebt_nat_info
++static unsigned int
++ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
++   , const struct net_device *out, int (*okfn)(struct sk_buff *))
 +{
-+      unsigned char mac[ETH_ALEN];
-+      // EBT_ACCEPT, EBT_DROP, EBT_CONTINUE or EBT_RETURN
-+      int target;
-+};
-+#define EBT_SNAT_TARGET "snat"
-+#define EBT_DNAT_TARGET "dnat"
-+
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_pkttype.h linux-ebtables/include/linux/netfilter_bridge/ebt_pkttype.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_pkttype.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_pkttype.h        2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,11 @@
-+#ifndef __LINUX_BRIDGE_EBT_PKTTYPE_H
-+#define __LINUX_BRIDGE_EBT_PKTTYPE_H
++      return ebt_do_table(hook, pskb, in, out, &frame_nat);
++}
 +
-+struct ebt_pkttype_info
-+{
-+      uint8_t pkt_type;
-+      uint8_t invert;
++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},
 +};
-+#define EBT_PKTTYPE_MATCH "pkttype"
-+
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_redirect.h linux-ebtables/include/linux/netfilter_bridge/ebt_redirect.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_redirect.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_redirect.h       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,11 @@
-+#ifndef __LINUX_BRIDGE_EBT_REDIRECT_H
-+#define __LINUX_BRIDGE_EBT_REDIRECT_H
 +
-+struct ebt_redirect_info
++static int __init init(void)
 +{
-+      // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN
-+      int target;
-+};
-+#define EBT_REDIRECT_TARGET "redirect"
++      int i, ret, j;
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_stp.h linux-ebtables/include/linux/netfilter_bridge/ebt_stp.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_stp.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_stp.h    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,46 @@
-+#ifndef __LINUX_BRIDGE_EBT_STP_H
-+#define __LINUX_BRIDGE_EBT_STP_H
++      ret = ebt_register_table(&frame_nat);
++      if (ret < 0)
++              return ret;
++      for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
++              if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
++                      goto cleanup;
++      return ret;
++cleanup:
++      for (j = 0; j < i; j++)
++              nf_unregister_hook(&ebt_ops_nat[j]);
++      ebt_unregister_table(&frame_nat);
++      return ret;
++}
 +
-+#define EBT_STP_TYPE          0x0001
++static void __exit fini(void)
++{
++      int i;
 +
-+#define EBT_STP_FLAGS         0x0002
-+#define EBT_STP_ROOTPRIO      0x0004
-+#define EBT_STP_ROOTADDR      0x0008
-+#define EBT_STP_ROOTCOST      0x0010
-+#define EBT_STP_SENDERPRIO    0x0020
-+#define EBT_STP_SENDERADDR    0x0040
-+#define EBT_STP_PORT          0x0080
-+#define EBT_STP_MSGAGE                0x0100
-+#define EBT_STP_MAXAGE                0x0200
-+#define EBT_STP_HELLOTIME     0x0400
-+#define EBT_STP_FWDD          0x0800
++      for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
++              nf_unregister_hook(&ebt_ops_nat[i]);
++      ebt_unregister_table(&frame_nat);
++}
 +
-+#define EBT_STP_MASK          0x0fff
-+#define EBT_STP_CONFIG_MASK   0x0ffe
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebtable_broute.c        2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,79 @@
++/*
++ *  ebtable_broute
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  April, 2002
++ *
++ *  This table lets you choose between routing and bridging for frames
++ *  entering on a bridge enslaved nic. This table is traversed before any
++ *  other ebtables table. See net/bridge/br_input.c.
++ */
 +
-+#define EBT_STP_MATCH "stp"
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/module.h>
++#include <linux/if_bridge.h>
++#include <linux/brlock.h>
 +
-+struct ebt_stp_config_info
-+{
-+      uint8_t flags;
-+      uint16_t root_priol, root_priou;
-+      char root_addr[6], root_addrmsk[6];
-+      uint32_t root_costl, root_costu;
-+      uint16_t sender_priol, sender_priou;
-+      char sender_addr[6], sender_addrmsk[6];
-+      uint16_t portl, portu;
-+      uint16_t msg_agel, msg_ageu;
-+      uint16_t max_agel, max_ageu;
-+      uint16_t hello_timel, hello_timeu;
-+      uint16_t forward_delayl, forward_delayu;
-+};
++// 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};
 +
-+struct ebt_stp_info
++static struct ebt_replace initial_table =
 +{
-+      uint8_t type;
-+      struct ebt_stp_config_info config;
-+      uint16_t bitmask;
-+      uint16_t invflags;
++  "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries),
++  { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain
 +};
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_ulog.h linux-ebtables/include/linux/netfilter_bridge/ebt_ulog.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_ulog.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_ulog.h   2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,33 @@
-+#ifndef _EBT_ULOG_H
-+#define _EBT_ULOG_H
-+
-+#define EBT_ULOG_DEFAULT_NLGROUP 0
-+#define EBT_ULOG_DEFAULT_QTHRESHOLD 1
-+#define EBT_ULOG_MAXNLGROUPS 32 /* hardcoded netlink max */
-+#define EBT_ULOG_PREFIX_LEN 32
-+#define EBT_ULOG_MAX_QLEN 50
-+#define EBT_ULOG_WATCHER "ulog"
++static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
++{
++      if (valid_hooks & ~(1 << NF_BR_BROUTING))
++              return -EINVAL;
++      return 0;
++}
 +
-+struct ebt_ulog_info {
-+      uint32_t nlgroup;
-+      unsigned int cprange;
-+      unsigned int qthreshold;
-+      char prefix[EBT_ULOG_PREFIX_LEN];
++static struct ebt_table broute_table =
++{
++  {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING,
++  RW_LOCK_UNLOCKED, check, NULL
 +};
 +
-+typedef struct ebt_ulog_packet_msg {
-+      char indev[IFNAMSIZ];
-+      char outdev[IFNAMSIZ];
-+      char physindev[IFNAMSIZ];
-+      char physoutdev[IFNAMSIZ];
-+      char prefix[EBT_ULOG_PREFIX_LEN];
-+      struct timeval stamp;
-+      unsigned long mark;
-+      unsigned int hook;
-+      size_t data_len;
-+      /* The complete packet, including Ethernet header and perhaps
-+       * the VLAN header is appended */
-+      unsigned char data[0] __attribute__ ((aligned (__alignof__(int))));
-+} ebt_ulog_packet_msg_t;
++static int ebt_broute(struct sk_buff **pskb)
++{
++      int ret;
 +
-+#endif /* _EBT_ULOG_H */
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebt_vlan.h linux-ebtables/include/linux/netfilter_bridge/ebt_vlan.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebt_vlan.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebt_vlan.h   2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,20 @@
-+#ifndef __LINUX_BRIDGE_EBT_VLAN_H
-+#define __LINUX_BRIDGE_EBT_VLAN_H
++      ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL,
++         &broute_table);
++      if (ret == NF_DROP)
++              return 1; // route it
++      return 0; // bridge it
++}
 +
-+#define EBT_VLAN_ID   0x01
-+#define EBT_VLAN_PRIO 0x02
-+#define EBT_VLAN_ENCAP        0x04
-+#define EBT_VLAN_MASK (EBT_VLAN_ID | EBT_VLAN_PRIO | EBT_VLAN_ENCAP)
-+#define EBT_VLAN_MATCH "vlan"
++static int __init init(void)
++{
++      int ret;
 +
-+struct ebt_vlan_info {
-+      uint16_t id;            /* VLAN ID {1-4095} */
-+      uint8_t prio;           /* VLAN User Priority {0-7} */
-+      uint16_t encap;         /* VLAN Encapsulated frame code {0-65535} */
-+      uint8_t bitmask;                /* Args bitmask bit 1=1 - ID arg,
-+                                 bit 2=1 User-Priority arg, bit 3=1 encap*/
-+      uint8_t invflags;               /* Inverse bitmask  bit 1=1 - inversed ID arg, 
-+                                 bit 2=1 - inversed Pirority arg */
-+};
++      ret = ebt_register_table(&broute_table);
++      if (ret < 0)
++              return ret;
++      br_write_lock_bh(BR_NETPROTO_LOCK);
++      // see br_input.c
++      br_should_route_hook = ebt_broute;
++      br_write_unlock_bh(BR_NETPROTO_LOCK);
++      return ret;
++}
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge/ebtables.h linux-ebtables/include/linux/netfilter_bridge/ebtables.h
---- linux-mips-cvs/include/linux/netfilter_bridge/ebtables.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_bridge/ebtables.h   2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,361 @@
++static void __exit fini(void)
++{
++      br_write_lock_bh(BR_NETPROTO_LOCK);
++      br_should_route_hook = NULL;
++      br_write_unlock_bh(BR_NETPROTO_LOCK);
++      ebt_unregister_table(&broute_table);
++}
++
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_among.c     2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,223 @@
 +/*
-+ *  ebtables
++ *  ebt_among
 + *
 + *    Authors:
-+ *    Bart De Schuymer                <bart.de.schuymer@pandora.be>
++ *    Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
 + *
-+ *  ebtables.c,v 2.0, September, 2002
++ *  August, 2003
 + *
-+ *  This code is stongly inspired on the iptables code which is
-+ *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
 + */
 +
-+#ifndef __LINUX_BRIDGE_EFF_H
-+#define __LINUX_BRIDGE_EFF_H
-+#include <linux/if.h>
-+#include <linux/netfilter_bridge.h>
-+#include <linux/if_ether.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_among.h>
++#include <linux/ip.h>
++#include <linux/if_arp.h>
++#include <linux/module.h>
 +
-+#define EBT_TABLE_MAXNAMELEN 32
-+#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
-+#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
++static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
++                                   const char *mac, uint32_t ip)
++{
++      /* You may be puzzled as to how this code works.
++       * Some tricks were used, refer to 
++       *      include/linux/netfilter_bridge/ebt_among.h
++       * as there you can find a solution of this mystery.
++       */
++      const struct ebt_mac_wormhash_tuple *p;
++      int start, limit, i;
++      uint32_t cmp[2] = { 0, 0 };
++      int key = (const unsigned char) mac[5];
 +
-+// verdicts >0 are "branches"
-+#define EBT_ACCEPT   -1
-+#define EBT_DROP     -2
-+#define EBT_CONTINUE -3
-+#define EBT_RETURN   -4
-+#define NUM_STANDARD_TARGETS   4
++      memcpy(((char *) cmp) + 2, mac, 6);
++      start = wh->table[key];
++      limit = wh->table[key + 1];
++      if (ip) {
++              for (i = start; i < limit; i++) {
++                      p = &wh->pool[i];
++                      if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
++                              if (p->ip == 0 || p->ip == ip) {
++                                      return 1;
++                              }
++                      }
++              }
++      } else {
++              for (i = start; i < limit; i++) {
++                      p = &wh->pool[i];
++                      if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
++                              if (p->ip == 0) {
++                                      return 1;
++                              }
++                      }
++              }
++      }
++      return 0;
++}
 +
-+struct ebt_counter
++static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
++                                          *wh)
 +{
-+      uint64_t pcnt;
-+      uint64_t bcnt;
-+};
++      int i;
 +
-+struct ebt_entries {
-+      // this field is always set to zero
-+      // See EBT_ENTRY_OR_ENTRIES.
-+      // Must be same size as ebt_entry.bitmask
-+      unsigned int distinguisher;
-+      // the chain name
-+      char name[EBT_CHAIN_MAXNAMELEN];
-+      // counter offset for this chain
-+      unsigned int counter_offset;
-+      // one standard (accept, drop, return) per hook
-+      int policy;
-+      // nr. of entries
-+      unsigned int nentries;
-+      // entry list
-+      char data[0];
-+};
++      for (i = 0; i < 256; i++) {
++              if (wh->table[i] > wh->table[i + 1])
++                      return -0x100 - i;
++              if (wh->table[i] < 0)
++                      return -0x200 - i;
++              if (wh->table[i] > wh->poolsize)
++                      return -0x300 - i;
++      }
++      if (wh->table[256] > wh->poolsize)
++              return -0xc00;
++      return 0;
++}
 +
-+// used for the bitmask of struct ebt_entry
++static int get_ip_dst(const struct sk_buff *skb, uint32_t * addr)
++{
++      if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP))
++              *addr = skb->nh.iph->daddr;
++      else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
++              uint32_t arp_len = sizeof(struct arphdr) +
++                  (2 * (((*skb).nh.arph)->ar_hln)) +
++                  (2 * (((*skb).nh.arph)->ar_pln));
 +
-+// This is a hack to make a difference between an ebt_entry struct and an
-+// ebt_entries struct when traversing the entries from start to end.
-+// Using this simplifies the code alot, while still being able to use
-+// ebt_entries.
-+// Contrary, iptables doesn't use something like ebt_entries and therefore uses
-+// different techniques for naming the policy and such. So, iptables doesn't
-+// need a hack like this.
-+#define EBT_ENTRY_OR_ENTRIES 0x01
-+// these are the normal masks
-+#define EBT_NOPROTO 0x02
-+#define EBT_802_3 0x04
-+#define EBT_SOURCEMAC 0x08
-+#define EBT_DESTMAC 0x10
-+#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
-+   | EBT_ENTRY_OR_ENTRIES)
++              /* Make sure the packet is long enough. */
++              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
++                      return -1;
++              /* IPv4 addresses are always 4 bytes. */
++              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
++                      return -1;
 +
-+#define EBT_IPROTO 0x01
-+#define EBT_IIN 0x02
-+#define EBT_IOUT 0x04
-+#define EBT_ISOURCE 0x8
-+#define EBT_IDEST 0x10
-+#define EBT_ILOGICALIN 0x20
-+#define EBT_ILOGICALOUT 0x40
-+#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
-+   | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
++              memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) +
++                     (2 * (((*skb).nh.arph)->ar_hln)) +
++                     (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
 +
-+struct ebt_entry_match
-+{
-+      union {
-+              char name[EBT_FUNCTION_MAXNAMELEN];
-+              struct ebt_match *match;
-+      } u;
-+      // size of data
-+      unsigned int match_size;
-+      unsigned char data[0];
-+};
++      }
++      return 0;
++}
 +
-+struct ebt_entry_watcher
++static int get_ip_src(const struct sk_buff *skb, uint32_t * addr)
 +{
-+      union {
-+              char name[EBT_FUNCTION_MAXNAMELEN];
-+              struct ebt_watcher *watcher;
-+      } u;
-+      // size of data
-+      unsigned int watcher_size;
-+      unsigned char data[0];
-+};
++      if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP))
++              *addr = skb->nh.iph->saddr;
++      else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
++              uint32_t arp_len = sizeof(struct arphdr) +
++                  (2 * (((*skb).nh.arph)->ar_hln)) +
++                  (2 * (((*skb).nh.arph)->ar_pln));
 +
-+struct ebt_entry_target
-+{
-+      union {
-+              char name[EBT_FUNCTION_MAXNAMELEN];
-+              struct ebt_target *target;
-+      } u;
-+      // size of data
-+      unsigned int target_size;
-+      unsigned char data[0];
-+};
++              /* Make sure the packet is long enough. */
++              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
++                      return -1;
++              /* IPv4 addresses are always 4 bytes. */
++              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
++                      return -1;
 +
-+#define EBT_STANDARD_TARGET "standard"
-+struct ebt_standard_target
-+{
-+      struct ebt_entry_target target;
-+      int verdict;
-+};
++              memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) +
++                     ((((*skb).nh.arph)->ar_hln)), sizeof(uint32_t));
 +
-+// one entry
-+struct ebt_entry {
-+      // this needs to be the first field
-+      unsigned int bitmask;
-+      unsigned int invflags;
-+      uint16_t ethproto;
-+      // the physical in-dev
-+      char in[IFNAMSIZ];
-+      // the logical in-dev
-+      char logical_in[IFNAMSIZ];
-+      // the physical out-dev
-+      char out[IFNAMSIZ];
-+      // the logical out-dev
-+      char logical_out[IFNAMSIZ];
-+      unsigned char sourcemac[ETH_ALEN];
-+      unsigned char sourcemsk[ETH_ALEN];
-+      unsigned char destmac[ETH_ALEN];
-+      unsigned char destmsk[ETH_ALEN];
-+      // sizeof ebt_entry + matches
-+      unsigned int watchers_offset;
-+      // sizeof ebt_entry + matches + watchers
-+      unsigned int target_offset;
-+      // sizeof ebt_entry + matches + watchers + target
-+      unsigned int next_offset;
-+      unsigned char elems[0];
-+};
++      }
++      return 0;
++}
 +
-+struct ebt_replace
++static int ebt_filter_among(const struct sk_buff *skb,
++                          const struct net_device *in,
++                          const struct net_device *out, const void *data,
++                          unsigned int datalen)
 +{
-+      char name[EBT_TABLE_MAXNAMELEN];
-+      unsigned int valid_hooks;
-+      // nr of rules in the table
-+      unsigned int nentries;
-+      // total size of the entries
-+      unsigned int entries_size;
-+      // start of the chains
-+      struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
-+      // nr of counters userspace expects back
-+      unsigned int num_counters;
-+      // where the kernel will put the old counters
-+      struct ebt_counter *counters;
-+      char *entries;
-+};
-+
-+// [gs]etsockopt numbers
-+#define EBT_BASE_CTL            128
++      struct ebt_among_info *info = (struct ebt_among_info *) data;
++      const char *dmac, *smac;
++      const struct ebt_mac_wormhash *wh_dst, *wh_src;
++      uint32_t dip = 0, sip = 0;
 +
-+#define EBT_SO_SET_ENTRIES      (EBT_BASE_CTL)
-+#define EBT_SO_SET_COUNTERS     (EBT_SO_SET_ENTRIES+1)
-+#define EBT_SO_SET_MAX          (EBT_SO_SET_COUNTERS+1)
++      wh_dst = ebt_among_wh_dst(info);
++      wh_src = ebt_among_wh_src(info);
 +
-+#define EBT_SO_GET_INFO         (EBT_BASE_CTL)
-+#define EBT_SO_GET_ENTRIES      (EBT_SO_GET_INFO+1)
-+#define EBT_SO_GET_INIT_INFO    (EBT_SO_GET_ENTRIES+1)
-+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
-+#define EBT_SO_GET_MAX          (EBT_SO_GET_INIT_ENTRIES+1)
++      if (wh_src) {
++              smac = skb->mac.ethernet->h_source;
++              if (get_ip_src(skb, &sip))
++                      return EBT_NOMATCH;
++              if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
++                      /* we match only if it contains */
++                      if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
++                              return EBT_NOMATCH;
++              } else {
++                      /* we match only if it DOES NOT contain */
++                      if (ebt_mac_wormhash_contains(wh_src, smac, sip))
++                              return EBT_NOMATCH;
++              }
++      }
 +
-+#ifdef __KERNEL__
++      if (wh_dst) {
++              dmac = skb->mac.ethernet->h_dest;
++              if (get_ip_dst(skb, &dip))
++                      return EBT_NOMATCH;
++              if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
++                      /* we match only if it contains */
++                      if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
++                              return EBT_NOMATCH;
++              } else {
++                      /* we match only if it DOES NOT contain */
++                      if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
++                              return EBT_NOMATCH;
++              }
++      }
 +
-+// return values for match() functions
-+#define EBT_MATCH 0
-+#define EBT_NOMATCH 1
++      return EBT_MATCH;
++}
 +
-+struct ebt_match
++static int ebt_among_check(const char *tablename, unsigned int hookmask,
++                         const struct ebt_entry *e, void *data,
++                         unsigned int datalen)
 +{
-+      struct list_head list;
-+      const char name[EBT_FUNCTION_MAXNAMELEN];
-+      // 0 == it matches
-+      int (*match)(const struct sk_buff *skb, const struct net_device *in,
-+         const struct net_device *out, const void *matchdata,
-+         unsigned int datalen);
-+      // 0 == let it in
-+      int (*check)(const char *tablename, unsigned int hookmask,
-+         const struct ebt_entry *e, void *matchdata, unsigned int datalen);
-+      void (*destroy)(void *matchdata, unsigned int datalen);
-+      struct module *me;
-+};
++      struct ebt_among_info *info = (struct ebt_among_info *) data;
++      int expected_length = sizeof(struct ebt_among_info);
++      const struct ebt_mac_wormhash *wh_dst, *wh_src;
++      int err;
 +
-+struct ebt_watcher
-+{
-+      struct list_head list;
-+      const char name[EBT_FUNCTION_MAXNAMELEN];
-+      void (*watcher)(const struct sk_buff *skb, unsigned int hooknr,
-+         const struct net_device *in, const struct net_device *out,
-+         const void *watcherdata, unsigned int datalen);
-+      // 0 == let it in
-+      int (*check)(const char *tablename, unsigned int hookmask,
-+         const struct ebt_entry *e, void *watcherdata, unsigned int datalen);
-+      void (*destroy)(void *watcherdata, unsigned int datalen);
-+      struct module *me;
-+};
++      wh_dst = ebt_among_wh_dst(info);
++      wh_src = ebt_among_wh_src(info);
++      expected_length += ebt_mac_wormhash_size(wh_dst);
++      expected_length += ebt_mac_wormhash_size(wh_src);
 +
-+struct ebt_target
-+{
-+      struct list_head list;
-+      const char name[EBT_FUNCTION_MAXNAMELEN];
-+      // returns one of the standard verdicts
-+      int (*target)(struct sk_buff **pskb, unsigned int hooknr,
-+         const struct net_device *in, const struct net_device *out,
-+         const void *targetdata, unsigned int datalen);
-+      // 0 == let it in
-+      int (*check)(const char *tablename, unsigned int hookmask,
-+         const struct ebt_entry *e, void *targetdata, unsigned int datalen);
-+      void (*destroy)(void *targetdata, unsigned int datalen);
-+      struct module *me;
-+};
++      if (datalen != EBT_ALIGN(expected_length)) {
++              printk(KERN_WARNING
++                     "ebtables: among: wrong size: %d"
++                     "against expected %d, rounded to %d\n",
++                     datalen, expected_length,
++                     EBT_ALIGN(expected_length));
++              return -EINVAL;
++      }
++      if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
++              printk(KERN_WARNING
++                     "ebtables: among: dst integrity fail: %x\n", -err);
++              return -EINVAL;
++      }
++      if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
++              printk(KERN_WARNING
++                     "ebtables: among: src integrity fail: %x\n", -err);
++              return -EINVAL;
++      }
++      return 0;
++}
 +
-+// used for jumping from and into user defined chains (udc)
-+struct ebt_chainstack
-+{
-+      struct ebt_entries *chaininfo; // pointer to chain data
-+      struct ebt_entry *e; // pointer to entry data
-+      unsigned int n; // n'th entry
++static struct ebt_match filter_among = {
++      {NULL, NULL}, 
++      EBT_AMONG_MATCH, 
++      ebt_filter_among, 
++      ebt_among_check,
++      NULL,
++      THIS_MODULE
 +};
 +
-+struct ebt_table_info
++static int __init init(void)
 +{
-+      // total size of the entries
-+      unsigned int entries_size;
-+      unsigned int nentries;
-+      // pointers to the start of the chains
-+      struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
-+      // room to maintain the stack used for jumping from and into udc
-+      struct ebt_chainstack **chainstack;
-+      char *entries;
-+      struct ebt_counter counters[0] ____cacheline_aligned;
-+};
++      return ebt_register_match(&filter_among);
++}
 +
-+struct ebt_table
++static void __exit fini(void)
 +{
-+      struct list_head list;
-+      char name[EBT_TABLE_MAXNAMELEN];
-+      struct ebt_replace *table;
-+      unsigned int valid_hooks;
-+      rwlock_t lock;
-+      // e.g. could be the table explicitly only allows certain
-+      // matches, targets, ... 0 == let it in
-+      int (*check)(const struct ebt_table_info *info,
-+         unsigned int valid_hooks);
-+      // the data used by the kernel
-+      struct ebt_table_info *private;
-+};
-+
-+#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_entry_target)-1)) & \
-+                   ~(__alignof__(struct ebt_entry_target)-1))
-+extern int ebt_register_table(struct ebt_table *table);
-+extern void ebt_unregister_table(struct ebt_table *table);
-+extern int ebt_register_match(struct ebt_match *match);
-+extern void ebt_unregister_match(struct ebt_match *match);
-+extern int ebt_register_watcher(struct ebt_watcher *watcher);
-+extern void ebt_unregister_watcher(struct ebt_watcher *watcher);
-+extern int ebt_register_target(struct ebt_target *target);
-+extern void ebt_unregister_target(struct ebt_target *target);
-+extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   struct ebt_table *table);
++      ebt_unregister_match(&filter_among);
++}
 +
-+   // Used in the kernel match() functions
-+#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg))
-+// True if the hook mask denotes that the rule is in a base chain,
-+// used in the check() functions
-+#define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS))
-+// Clear the bit in the hook mask that tells if the rule is on a base chain
-+#define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS))
-+// True if the target is not a standard target
-+#define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_limit.c     2005-03-14 00:00:29.000000000 +0100
+@@ -0,0 +1,101 @@
++/*
++ *  ebt_limit
++ *
++ *    Authors:
++ *    Tom Marshall <tommy@home.tig-grr.com>
++ *
++ *    Mostly copied from netfilter's ipt_limit.c, see that file for explanation
++ *
++ *  September, 2003
++ *
++ */
 +
-+#endif /* __KERNEL__ */
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_limit.h>
++#include <linux/module.h>
 +
-+// blatently stolen from ip_tables.h
-+// fn returns 0 to continue iteration
-+#define EBT_MATCH_ITERATE(e, fn, args...)                   \
-+({                                                          \
-+      unsigned int __i;                                   \
-+      int __ret = 0;                                      \
-+      struct ebt_entry_match *__match;                    \
-+                                                          \
-+      for (__i = sizeof(struct ebt_entry);                \
-+           __i < (e)->watchers_offset;                    \
-+           __i += __match->match_size +                   \
-+           sizeof(struct ebt_entry_match)) {              \
-+              __match = (void *)(e) + __i;                \
-+                                                          \
-+              __ret = fn(__match , ## args);              \
-+              if (__ret != 0)                             \
-+                      break;                              \
-+      }                                                   \
-+      if (__ret == 0) {                                   \
-+              if (__i != (e)->watchers_offset)            \
-+                      __ret = -EINVAL;                    \
-+      }                                                   \
-+      __ret;                                              \
-+})
++#include <linux/netdevice.h>
++#include <linux/spinlock.h>
 +
-+#define EBT_WATCHER_ITERATE(e, fn, args...)                 \
-+({                                                          \
-+      unsigned int __i;                                   \
-+      int __ret = 0;                                      \
-+      struct ebt_entry_watcher *__watcher;                \
-+                                                          \
-+      for (__i = e->watchers_offset;                      \
-+           __i < (e)->target_offset;                      \
-+           __i += __watcher->watcher_size +               \
-+           sizeof(struct ebt_entry_watcher)) {            \
-+              __watcher = (void *)(e) + __i;              \
-+                                                          \
-+              __ret = fn(__watcher , ## args);            \
-+              if (__ret != 0)                             \
-+                      break;                              \
-+      }                                                   \
-+      if (__ret == 0) {                                   \
-+              if (__i != (e)->target_offset)              \
-+                      __ret = -EINVAL;                    \
-+      }                                                   \
-+      __ret;                                              \
-+})
++static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED;
 +
-+#define EBT_ENTRY_ITERATE(entries, size, fn, args...)       \
-+({                                                          \
-+      unsigned int __i;                                   \
-+      int __ret = 0;                                      \
-+      struct ebt_entry *__entry;                          \
-+                                                          \
-+      for (__i = 0; __i < (size);) {                      \
-+              __entry = (void *)(entries) + __i;          \
-+              __ret = fn(__entry , ## args);              \
-+              if (__ret != 0)                             \
-+                      break;                              \
-+              if (__entry->bitmask != 0)                  \
-+                      __i += __entry->next_offset;        \
-+              else                                        \
-+                      __i += sizeof(struct ebt_entries);  \
-+      }                                                   \
-+      if (__ret == 0) {                                   \
-+              if (__i != (size))                          \
-+                      __ret = -EINVAL;                    \
-+      }                                                   \
-+      __ret;                                              \
-+})
++#define CREDITS_PER_JIFFY 128
 +
-+#endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_bridge.h linux-ebtables/include/linux/netfilter_bridge.h
---- linux-mips-cvs/include/linux/netfilter_bridge.h    2001-08-22 05:25:11.000000000 +0200
-+++ linux-ebtables/include/linux/netfilter_bridge.h    2005-02-07 05:52:50.000000000 +0100
-@@ -6,6 +6,10 @@
- #include <linux/config.h>
- #include <linux/netfilter.h>
-+#if defined(__KERNEL__) && defined(CONFIG_NETFILTER)
-+#include <asm/atomic.h>
-+#include <linux/if_ether.h>
-+#endif
- /* Bridge Hooks */
- /* After promisc drops, checksum checks. */
-@@ -18,7 +22,76 @@
- #define NF_BR_LOCAL_OUT               3
- /* Packets about to hit the wire. */
- #define NF_BR_POST_ROUTING    4
--#define NF_BR_NUMHOOKS                5
-+/* Not really a hook, but used for the ebtables broute table */
-+#define NF_BR_BROUTING                5
-+#define NF_BR_NUMHOOKS                6
++static int ebt_limit_match(const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, const void *data, unsigned int datalen)
++{
++      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
++      unsigned long now = jiffies;
 +
-+#ifdef __KERNEL__
++      spin_lock_bh(&limit_lock);
++      info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY;
++      if (info->credit > info->credit_cap)
++              info->credit = info->credit_cap;
 +
-+#define BRNF_PKT_TYPE                 0x01
-+#define BRNF_BRIDGED_DNAT             0x02
-+#define BRNF_DONT_TAKE_PARENT         0x04
-+#define BRNF_BRIDGED                  0x08
-+#define BRNF_NF_BRIDGE_PREROUTING     0x10
++      if (info->credit >= info->cost) {
++              /* We're not limited. */
++              info->credit -= info->cost;
++              spin_unlock_bh(&limit_lock);
++              return EBT_MATCH;
++      }
 +
-+enum nf_br_hook_priorities {
-+      NF_BR_PRI_FIRST = INT_MIN,
-+      NF_BR_PRI_NAT_DST_BRIDGED = -300,
-+      NF_BR_PRI_FILTER_BRIDGED = -200,
-+      NF_BR_PRI_BRNF = 0,
-+      NF_BR_PRI_NAT_DST_OTHER = 100,
-+      NF_BR_PRI_FILTER_OTHER = 200,
-+      NF_BR_PRI_NAT_SRC = 300,
-+      NF_BR_PRI_LAST = INT_MAX,
-+};
++      spin_unlock_bh(&limit_lock);
++      return EBT_NOMATCH;
++}
 +
-+#ifdef CONFIG_NETFILTER
-+static inline
-+struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
++/* Precision saver. */
++static u_int32_t
++user2credits(u_int32_t user)
 +{
-+      struct nf_bridge_info **nf_bridge = &(skb->nf_bridge);
++      /* If multiplying would overflow... */
++      if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
++              /* Divide first. */
++              return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
 +
-+      if ((*nf_bridge = kmalloc(sizeof(**nf_bridge), GFP_ATOMIC)) != NULL) {
-+              atomic_set(&(*nf_bridge)->use, 1);
-+              (*nf_bridge)->mask = 0;
-+              (*nf_bridge)->physindev = (*nf_bridge)->physoutdev = NULL;
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+              (*nf_bridge)->netoutdev = NULL;
-+#endif
-+      }
-+
-+      return *nf_bridge;
-+}
-+
-+/* Only used in br_forward.c */
-+static inline
-+void nf_bridge_maybe_copy_header(struct sk_buff *skb)
-+{
-+      if (skb->nf_bridge) {
-+              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+                      memcpy(skb->data - 18, skb->nf_bridge->data, 18);
-+                      skb_push(skb, 4);
-+              } else
-+                      memcpy(skb->data - 16, skb->nf_bridge->data, 16);
-+      }
++      return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
 +}
 +
-+static inline
-+void nf_bridge_save_header(struct sk_buff *skb)
++static int ebt_limit_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
 +{
-+        int header_size = 16;
-+
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q))
-+              header_size = 18;
-+      memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
-+}
-+struct bridge_skb_cb {
-+      union {
-+              __u32 ipv4;
-+      } daddr;
-+};
-+#endif /* CONFIG_NETFILTER */
-+#endif /* __KERNEL__ */
- #endif
-diff -Nur linux-mips-cvs/include/linux/netfilter_ipv4/ipt_physdev.h linux-ebtables/include/linux/netfilter_ipv4/ipt_physdev.h
---- linux-mips-cvs/include/linux/netfilter_ipv4/ipt_physdev.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_ipv4/ipt_physdev.h  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,24 @@
-+#ifndef _IPT_PHYSDEV_H
-+#define _IPT_PHYSDEV_H
-+
-+#ifdef __KERNEL__
-+#include <linux/if.h>
-+#endif
++      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
 +
-+#define IPT_PHYSDEV_OP_IN             0x01
-+#define IPT_PHYSDEV_OP_OUT            0x02
-+#define IPT_PHYSDEV_OP_BRIDGED                0x04
-+#define IPT_PHYSDEV_OP_ISIN           0x08
-+#define IPT_PHYSDEV_OP_ISOUT          0x10
-+#define IPT_PHYSDEV_OP_MASK           (0x20 - 1)
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
++              return -EINVAL;
 +
-+struct ipt_physdev_info {
-+      char physindev[IFNAMSIZ];
-+      char in_mask[IFNAMSIZ];
-+      char physoutdev[IFNAMSIZ];
-+      char out_mask[IFNAMSIZ];
-+      u_int8_t invert;
-+      u_int8_t bitmask;
-+};
++      /* Check for overflow. */
++      if (info->burst == 0
++          || user2credits(info->avg * info->burst) < user2credits(info->avg)) {
++              printk("Overflow in ebt_limit: %u/%u\n",
++                      info->avg, info->burst);
++              return -EINVAL;
++      }
 +
-+#endif /*_IPT_PHYSDEV_H*/
-diff -Nur linux-mips-cvs/include/linux/netfilter_ipv4.h linux-ebtables/include/linux/netfilter_ipv4.h
---- linux-mips-cvs/include/linux/netfilter_ipv4.h      2002-02-26 07:00:31.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_ipv4.h      2005-02-07 05:52:50.000000000 +0100
-@@ -52,8 +52,10 @@
- enum nf_ip_hook_priorities {
-       NF_IP_PRI_FIRST = INT_MIN,
-       NF_IP_PRI_CONNTRACK = -200,
-+      NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
-       NF_IP_PRI_MANGLE = -150,
-       NF_IP_PRI_NAT_DST = -100,
-+      NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
-       NF_IP_PRI_FILTER = 0,
-       NF_IP_PRI_NAT_SRC = 100,
-       NF_IP_PRI_LAST = INT_MAX,
-diff -Nur linux-mips-cvs/include/linux/netfilter_ipv6.h linux-ebtables/include/linux/netfilter_ipv6.h
---- linux-mips-cvs/include/linux/netfilter_ipv6.h      2001-01-11 05:02:45.000000000 +0100
-+++ linux-ebtables/include/linux/netfilter_ipv6.h      2005-02-07 05:52:50.000000000 +0100
-@@ -57,8 +57,10 @@
- enum nf_ip6_hook_priorities {
-       NF_IP6_PRI_FIRST = INT_MIN,
-       NF_IP6_PRI_CONNTRACK = -200,
-+      NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
-       NF_IP6_PRI_MANGLE = -150,
-       NF_IP6_PRI_NAT_DST = -100,
-+      NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
-       NF_IP6_PRI_FILTER = 0,
-       NF_IP6_PRI_NAT_SRC = 100,
-       NF_IP6_PRI_LAST = INT_MAX,
-diff -Nur linux-mips-cvs/include/linux/skbuff.h linux-ebtables/include/linux/skbuff.h
---- linux-mips-cvs/include/linux/skbuff.h      2005-01-31 12:56:47.000000000 +0100
-+++ linux-ebtables/include/linux/skbuff.h      2005-02-07 05:52:50.000000000 +0100
-@@ -92,6 +92,20 @@
- struct nf_ct_info {
-       struct nf_conntrack *master;
- };
++      /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
++      info->prev = jiffies;
++      info->credit = user2credits(info->avg * info->burst);
++      info->credit_cap = user2credits(info->avg * info->burst);
++      info->cost = user2credits(info->avg);
++      return 0;
++}
 +
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+struct nf_bridge_info {
-+      atomic_t use;
-+      struct net_device *physindev;
-+      struct net_device *physoutdev;
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+      struct net_device *netoutdev;
-+#endif
-+      unsigned int mask;
-+      unsigned long data[32 / sizeof(unsigned long)];
++static struct ebt_match ebt_limit_reg =
++{
++      {NULL, NULL}, EBT_LIMIT_MATCH, ebt_limit_match, ebt_limit_check, NULL,
++      THIS_MODULE
 +};
-+#endif
-+
- #endif
- struct sk_buff_head {
-@@ -208,6 +222,9 @@
- #ifdef CONFIG_NETFILTER_DEBUG
-         unsigned int nf_debug;
- #endif
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      struct nf_bridge_info   *nf_bridge;     /* Saved data about a bridged frame - see br_netfilter.c */
-+#endif
- #endif /*CONFIG_NETFILTER*/
- #if defined(CONFIG_HIPPI)
-@@ -1175,6 +1192,20 @@
-       skb->nf_debug = 0;
- #endif
- }
 +
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
++static int __init init(void)
 +{
-+      if (nf_bridge && atomic_dec_and_test(&nf_bridge->use))
-+              kfree(nf_bridge);
++      return ebt_register_match(&ebt_limit_reg);
 +}
-+static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge)
++
++static void __exit fini(void)
 +{
-+      if (nf_bridge)
-+              atomic_inc(&nf_bridge->use);
++      ebt_unregister_match(&ebt_limit_reg);
 +}
-+#endif
-+
- #else /* CONFIG_NETFILTER */
- static inline void nf_reset(struct sk_buff *skb) {}
- #endif /* CONFIG_NETFILTER */
-diff -Nur linux-mips-cvs/include/linux/sysctl.h linux-ebtables/include/linux/sysctl.h
---- linux-mips-cvs/include/linux/sysctl.h      2004-11-29 18:47:18.000000000 +0100
-+++ linux-ebtables/include/linux/sysctl.h      2005-02-07 05:52:50.000000000 +0100
-@@ -608,6 +608,15 @@
-       NET_DECNET_CONF_DEV_STATE = 7
- };
-+/* /proc/sys/net/bridge */
-+enum {
-+      NET_BRIDGE_NF_CALL_ARPTABLES = 1,
-+      NET_BRIDGE_NF_CALL_IPTABLES = 2,
-+      NET_BRIDGE_NF_CALL_IP6TABLES = 3,
-+      NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
-+};
 +
-+
- /* CTL_PROC names: */
- /* CTL_FS names: */
-diff -Nur linux-mips-cvs/include/linux/sysctl.h.orig linux-ebtables/include/linux/sysctl.h.orig
---- linux-mips-cvs/include/linux/sysctl.h.orig 1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/include/linux/sysctl.h.orig 2004-11-29 18:47:18.000000000 +0100
-@@ -0,0 +1,841 @@
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_arpreply.c  2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,86 @@
 +/*
-+ * sysctl.h: General linux system control interface
++ *  ebt_arpreply
++ *
++ *    Authors:
++ *    Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
++ *    Bart De Schuymer <bdschuym@pandora.be>
 + *
-+ * Begun 24 March 1995, Stephen Tweedie
++ *  August, 2003
 + *
-+ ****************************************************************
-+ ****************************************************************
-+ **
-+ **  WARNING:  
-+ **  The values in this file are exported to user space via 
-+ **  the sysctl() binary interface.  Do *NOT* change the 
-+ **  numbering of any existing values here, and do not change
-+ **  any numbers within any one set of values.  If you have
-+ **  to redefine an existing interface, use a new number for it.
-+ **  The kernel will then return ENOTDIR to any application using
-+ **  the old binary interface.
-+ **
-+ **  --sct
-+ **
-+ ****************************************************************
-+ ****************************************************************
 + */
 +
-+#ifndef _LINUX_SYSCTL_H
-+#define _LINUX_SYSCTL_H
-+
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/list.h>
-+
-+struct file;
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_arpreply.h>
++#include <linux/if_arp.h>
++#include <net/arp.h>
++#include <linux/module.h>
 +
-+#define CTL_MAXNAME 10
++static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
++      struct arphdr *ah;
++      unsigned char *sha, *arp_ptr;
++      u32 sip, tip;
 +
-+struct __sysctl_args {
-+      int *name;
-+      int nlen;
-+      void *oldval;
-+      size_t *oldlenp;
-+      void *newval;
-+      size_t newlen;
-+      unsigned long __unused[4];
-+};
++      ah = (**pskb).nh.arph;
++      if (ah->ar_op != __constant_htons(ARPOP_REQUEST) ||
++          ah->ar_hln != ETH_ALEN || ah->ar_pro != htons(ETH_P_IP) ||
++          ah->ar_pln != 4)
++              return EBT_CONTINUE;
 +
-+/* Define sysctl names first */
++      arp_ptr = (unsigned char *)(ah + 1);
 +
-+/* Top-level names: */
++      /* get source and target IP */
++      sha = arp_ptr;
++      arp_ptr += ETH_ALEN;
++      memcpy(&sip, arp_ptr, 4);
++      arp_ptr += 4 + ETH_ALEN;
++      memcpy(&tip, arp_ptr, 4);
 +
-+/* For internal pattern-matching use only: */
-+#ifdef __KERNEL__
-+#define CTL_ANY               -1      /* Matches any name */
-+#define CTL_NONE      0
-+#endif
++      arp_send(ARPOP_REPLY, ETH_P_ARP, sip, in, tip, sha, info->mac, sha);
 +
-+enum
-+{
-+      CTL_KERN=1,             /* General kernel info and control */
-+      CTL_VM=2,               /* VM management */
-+      CTL_NET=3,              /* Networking */
-+      CTL_PROC=4,             /* Process info */
-+      CTL_FS=5,               /* Filesystems */
-+      CTL_DEBUG=6,            /* Debugging */
-+      CTL_DEV=7,              /* Devices */
-+      CTL_BUS=8,              /* Busses */
-+      CTL_ABI=9,              /* Binary emulation */
-+      CTL_CPU=10              /* CPU stuff (speed scaling, etc) */
-+};
++      return info->target;
++}
 +
-+/* CTL_BUS names: */
-+enum
++static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
 +{
-+      CTL_BUS_ISA=1           /* ISA */
-+};
-+
-+/* CTL_KERN names: */
-+enum
-+{
-+      KERN_OSTYPE=1,          /* string: system version */
-+      KERN_OSRELEASE=2,       /* string: system release */
-+      KERN_OSREV=3,           /* int: system revision */
-+      KERN_VERSION=4,         /* string: compile time info */
-+      KERN_SECUREMASK=5,      /* struct: maximum rights mask */
-+      KERN_PROF=6,            /* table: profiling information */
-+      KERN_NODENAME=7,
-+      KERN_DOMAINNAME=8,
-+
-+      KERN_CAP_BSET=14,       /* int: capability bounding set */
-+      KERN_PANIC=15,          /* int: panic timeout */
-+      KERN_REALROOTDEV=16,    /* real root device to mount after initrd */
-+
-+      KERN_SPARC_REBOOT=21,   /* reboot command on Sparc */
-+      KERN_CTLALTDEL=22,      /* int: allow ctl-alt-del to reboot */
-+      KERN_PRINTK=23,         /* struct: control printk logging parameters */
-+      KERN_NAMETRANS=24,      /* Name translation */
-+      KERN_PPC_HTABRECLAIM=25, /* turn htab reclaimation on/off on PPC */
-+      KERN_PPC_ZEROPAGED=26,  /* turn idle page zeroing on/off on PPC */
-+      KERN_PPC_POWERSAVE_NAP=27, /* use nap mode for power saving */
-+      KERN_MODPROBE=28,
-+      KERN_SG_BIG_BUFF=29,
-+      KERN_ACCT=30,           /* BSD process accounting parameters */
-+      KERN_PPC_L2CR=31,       /* l2cr register on PPC */
-+
-+      KERN_RTSIGNR=32,        /* Number of rt sigs queued */
-+      KERN_RTSIGMAX=33,       /* Max queuable */
-+      
-+      KERN_SHMMAX=34,         /* long: Maximum shared memory segment */
-+      KERN_MSGMAX=35,         /* int: Maximum size of a messege */
-+      KERN_MSGMNB=36,         /* int: Maximum message queue size */
-+      KERN_MSGPOOL=37,        /* int: Maximum system message pool size */
-+      KERN_SYSRQ=38,          /* int: Sysreq enable */
-+      KERN_MAX_THREADS=39,    /* int: Maximum nr of threads in the system */
-+      KERN_RANDOM=40,         /* Random driver */
-+      KERN_SHMALL=41,         /* int: Maximum size of shared memory */
-+      KERN_MSGMNI=42,         /* int: msg queue identifiers */
-+      KERN_SEM=43,            /* struct: sysv semaphore limits */
-+      KERN_SPARC_STOP_A=44,   /* int: Sparc Stop-A enable */
-+      KERN_SHMMNI=45,         /* int: shm array identifiers */
-+      KERN_OVERFLOWUID=46,    /* int: overflow UID */
-+      KERN_OVERFLOWGID=47,    /* int: overflow GID */
-+      KERN_SHMPATH=48,        /* string: path to shm fs */
-+      KERN_HOTPLUG=49,        /* string: path to hotplug policy agent */
-+      KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */
-+      KERN_S390_USER_DEBUG_LOGGING=51,  /* int: dumps of user faults */
-+      KERN_CORE_USES_PID=52,          /* int: use core or core.%pid */
-+      KERN_TAINTED=53,        /* int: various kernel tainted flags */
-+      KERN_CADPID=54,         /* int: PID of the process to notify on CAD */
-+      KERN_CORE_PATTERN=56,   /* string: pattern for core-files */
-+      KERN_PPC_L3CR=57,       /* l3cr register on PPC */
-+      KERN_EXCEPTION_TRACE=58, /* boolean: exception trace */
-+      KERN_CORE_SETUID=59,    /* int: set to allow core dumps of setuid apps */
-+      KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */
-+};
-+
-+
-+/* CTL_VM names: */
-+enum
-+{
-+      VM_SWAPCTL=1,           /* struct: Set vm swapping control */
-+      VM_SWAPOUT=2,           /* int: Linear or sqrt() swapout for hogs */
-+      VM_FREEPG=3,            /* struct: Set free page thresholds */
-+      VM_BDFLUSH=4,           /* struct: Control buffer cache flushing */
-+      VM_OVERCOMMIT_MEMORY=5, /* Turn off the virtual memory safety limit */
-+      VM_BUFFERMEM=6,         /* struct: Set buffer memory thresholds */
-+      VM_PAGECACHE=7,         /* struct: Set cache memory thresholds */
-+      VM_PAGERDAEMON=8,       /* struct: Control kswapd behaviour */
-+      VM_PGT_CACHE=9,         /* struct: Set page table cache parameters */
-+      VM_PAGE_CLUSTER=10,     /* int: set number of pages to swap together */
-+      VM_MAX_MAP_COUNT=11,    /* int: Maximum number of active map areas */
-+      VM_MIN_READAHEAD=12,    /* Min file readahead */
-+      VM_MAX_READAHEAD=13,    /* Max file readahead */
-+      VM_VFS_SCAN_RATIO=14,   /* part of the inactive vfs lists to scan */
-+      VM_LRU_BALANCE_RATIO=15,/* balance active and inactive caches */
-+      VM_PASSES=16,           /* number of vm passes before failing */
-+      VM_PAGEBUF=17,          /* struct: Control pagebuf parameters */
-+      VM_GFP_DEBUG=18,        /* debug GFP failures */
-+      VM_CACHE_SCAN_RATIO=19, /* part of the inactive cache list to scan */
-+      VM_MAPPED_RATIO=20,     /* amount of unfreeable pages that triggers swapout */
-+      VM_LAPTOP_MODE=21,      /* kernel in laptop flush mode */
-+      VM_BLOCK_DUMP=22,       /* dump fs activity to log */
-+      VM_ANON_LRU=23,         /* immediatly insert anon pages in the vm page lru */
-+};
-+
++      struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
 +
-+/* CTL_NET names: */
-+enum
-+{
-+      NET_CORE=1,
-+      NET_ETHER=2,
-+      NET_802=3,
-+      NET_UNIX=4,
-+      NET_IPV4=5,
-+      NET_IPX=6,
-+      NET_ATALK=7,
-+      NET_NETROM=8,
-+      NET_AX25=9,
-+      NET_BRIDGE=10,
-+      NET_ROSE=11,
-+      NET_IPV6=12,
-+      NET_X25=13,
-+      NET_TR=14,
-+      NET_DECNET=15,
-+      NET_ECONET=16,
-+      NET_KHTTPD=17,
-+      NET_SCTP=18
-+};
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
++              return -EINVAL;
++      if (BASE_CHAIN && info->target == EBT_RETURN)
++              return -EINVAL;
++      if (e->ethproto != __constant_htons(ETH_P_ARP) ||
++          e->invflags & EBT_IPROTO)
++              return -EINVAL;
++      CLEAR_BASE_CHAIN_BIT;
++      if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
++              return -EINVAL;
++      return 0;
++}
 +
-+/* /proc/sys/kernel/random */
-+enum
++static struct ebt_target reply_target =
 +{
-+      RANDOM_POOLSIZE=1,
-+      RANDOM_ENTROPY_COUNT=2,
-+      RANDOM_READ_THRESH=3,
-+      RANDOM_WRITE_THRESH=4,
-+      RANDOM_BOOT_ID=5,
-+      RANDOM_UUID=6
++      .name           = EBT_ARPREPLY_TARGET,
++      .target         = ebt_target_reply,
++      .check          = ebt_target_reply_check,
++      .me             = THIS_MODULE,
 +};
 +
-+/* /proc/sys/bus/isa */
-+enum
++static int __init init(void)
 +{
-+      BUS_ISA_MEM_BASE=1,
-+      BUS_ISA_PORT_BASE=2,
-+      BUS_ISA_PORT_SHIFT=3
-+};
-+
-+/* /proc/sys/net/core */
-+enum
-+{
-+      NET_CORE_WMEM_MAX=1,
-+      NET_CORE_RMEM_MAX=2,
-+      NET_CORE_WMEM_DEFAULT=3,
-+      NET_CORE_RMEM_DEFAULT=4,
-+/* was        NET_CORE_DESTROY_DELAY */
-+      NET_CORE_MAX_BACKLOG=6,
-+      NET_CORE_FASTROUTE=7,
-+      NET_CORE_MSG_COST=8,
-+      NET_CORE_MSG_BURST=9,
-+      NET_CORE_OPTMEM_MAX=10,
-+      NET_CORE_HOT_LIST_LENGTH=11,
-+      NET_CORE_DIVERT_VERSION=12,
-+      NET_CORE_NO_CONG_THRESH=13,
-+      NET_CORE_NO_CONG=14,
-+      NET_CORE_LO_CONG=15,
-+      NET_CORE_MOD_CONG=16,
-+      NET_CORE_DEV_WEIGHT=17,
-+      NET_CORE_SOMAXCONN=18,
-+};
-+
-+/* /proc/sys/net/ethernet */
-+
-+/* /proc/sys/net/802 */
-+
-+/* /proc/sys/net/unix */
++      return ebt_register_target(&reply_target);
++}
 +
-+enum
++static void __exit fini(void)
 +{
-+      NET_UNIX_DESTROY_DELAY=1,
-+      NET_UNIX_DELETE_DELAY=2,
-+      NET_UNIX_MAX_DGRAM_QLEN=3,
-+};
++      ebt_unregister_target(&reply_target);
++}
 +
-+/* /proc/sys/net/ipv4 */
-+enum
-+{
-+      /* v2.0 compatibile variables */
-+      NET_IPV4_FORWARD=8,
-+      NET_IPV4_DYNADDR=9,
-+
-+      NET_IPV4_CONF=16,
-+      NET_IPV4_NEIGH=17,
-+      NET_IPV4_ROUTE=18,
-+      NET_IPV4_FIB_HASH=19,
-+      NET_IPV4_NETFILTER=20,
-+
-+      NET_IPV4_TCP_TIMESTAMPS=33,
-+      NET_IPV4_TCP_WINDOW_SCALING=34,
-+      NET_IPV4_TCP_SACK=35,
-+      NET_IPV4_TCP_RETRANS_COLLAPSE=36,
-+      NET_IPV4_DEFAULT_TTL=37,
-+      NET_IPV4_AUTOCONFIG=38,
-+      NET_IPV4_NO_PMTU_DISC=39,
-+      NET_IPV4_TCP_SYN_RETRIES=40,
-+      NET_IPV4_IPFRAG_HIGH_THRESH=41,
-+      NET_IPV4_IPFRAG_LOW_THRESH=42,
-+      NET_IPV4_IPFRAG_TIME=43,
-+      NET_IPV4_TCP_MAX_KA_PROBES=44,
-+      NET_IPV4_TCP_KEEPALIVE_TIME=45,
-+      NET_IPV4_TCP_KEEPALIVE_PROBES=46,
-+      NET_IPV4_TCP_RETRIES1=47,
-+      NET_IPV4_TCP_RETRIES2=48,
-+      NET_IPV4_TCP_FIN_TIMEOUT=49,
-+      NET_IPV4_IP_MASQ_DEBUG=50,
-+      NET_TCP_SYNCOOKIES=51,
-+      NET_TCP_STDURG=52,
-+      NET_TCP_RFC1337=53,
-+      NET_TCP_SYN_TAILDROP=54,
-+      NET_TCP_MAX_SYN_BACKLOG=55,
-+      NET_IPV4_LOCAL_PORT_RANGE=56,
-+      NET_IPV4_ICMP_ECHO_IGNORE_ALL=57,
-+      NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=58,
-+      NET_IPV4_ICMP_SOURCEQUENCH_RATE=59,
-+      NET_IPV4_ICMP_DESTUNREACH_RATE=60,
-+      NET_IPV4_ICMP_TIMEEXCEED_RATE=61,
-+      NET_IPV4_ICMP_PARAMPROB_RATE=62,
-+      NET_IPV4_ICMP_ECHOREPLY_RATE=63,
-+      NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
-+      NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
-+      NET_TCP_TW_RECYCLE=66,
-+      NET_IPV4_ALWAYS_DEFRAG=67,
-+      NET_IPV4_TCP_KEEPALIVE_INTVL=68,
-+      NET_IPV4_INET_PEER_THRESHOLD=69,
-+      NET_IPV4_INET_PEER_MINTTL=70,
-+      NET_IPV4_INET_PEER_MAXTTL=71,
-+      NET_IPV4_INET_PEER_GC_MINTIME=72,
-+      NET_IPV4_INET_PEER_GC_MAXTIME=73,
-+      NET_TCP_ORPHAN_RETRIES=74,
-+      NET_TCP_ABORT_ON_OVERFLOW=75,
-+      NET_TCP_SYNACK_RETRIES=76,
-+      NET_TCP_MAX_ORPHANS=77,
-+      NET_TCP_MAX_TW_BUCKETS=78,
-+      NET_TCP_FACK=79,
-+      NET_TCP_REORDERING=80,
-+      NET_TCP_ECN=81,
-+      NET_TCP_DSACK=82,
-+      NET_TCP_MEM=83,
-+      NET_TCP_WMEM=84,
-+      NET_TCP_RMEM=85,
-+      NET_TCP_APP_WIN=86,
-+      NET_TCP_ADV_WIN_SCALE=87,
-+      NET_IPV4_NONLOCAL_BIND=88,
-+      NET_IPV4_ICMP_RATELIMIT=89,
-+      NET_IPV4_ICMP_RATEMASK=90,
-+      NET_TCP_TW_REUSE=91,
-+      NET_TCP_FRTO=92,
-+      NET_TCP_LOW_LATENCY=93,
-+      NET_IPV4_IPFRAG_SECRET_INTERVAL=94,
-+      NET_TCP_WESTWOOD=95,
-+      NET_IPV4_IGMP_MAX_MSF=96,
-+      NET_TCP_NO_METRICS_SAVE=97,
-+      NET_TCP_VEGAS=98,
-+      NET_TCP_VEGAS_ALPHA=99,
-+      NET_TCP_VEGAS_BETA=100,
-+      NET_TCP_VEGAS_GAMMA=101,
-+      NET_TCP_BIC=102,
-+      NET_TCP_BIC_FAST_CONVERGENCE=103,
-+      NET_TCP_BIC_LOW_WINDOW=104,
-+      NET_TCP_DEFAULT_WIN_SCALE=105,
-+      NET_TCP_MODERATE_RCVBUF=106,
-+};
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_802_3.c     2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,74 @@
++/*
++ * 802_3
++ *
++ * Author:
++ * Chris Vitale csv@bluetail.com
++ *
++ * May 2003
++ * 
++ */
 +
-+enum {
-+      NET_IPV4_ROUTE_FLUSH=1,
-+      NET_IPV4_ROUTE_MIN_DELAY=2,
-+      NET_IPV4_ROUTE_MAX_DELAY=3,
-+      NET_IPV4_ROUTE_GC_THRESH=4,
-+      NET_IPV4_ROUTE_MAX_SIZE=5,
-+      NET_IPV4_ROUTE_GC_MIN_INTERVAL=6,
-+      NET_IPV4_ROUTE_GC_TIMEOUT=7,
-+      NET_IPV4_ROUTE_GC_INTERVAL=8,
-+      NET_IPV4_ROUTE_REDIRECT_LOAD=9,
-+      NET_IPV4_ROUTE_REDIRECT_NUMBER=10,
-+      NET_IPV4_ROUTE_REDIRECT_SILENCE=11,
-+      NET_IPV4_ROUTE_ERROR_COST=12,
-+      NET_IPV4_ROUTE_ERROR_BURST=13,
-+      NET_IPV4_ROUTE_GC_ELASTICITY=14,
-+      NET_IPV4_ROUTE_MTU_EXPIRES=15,
-+      NET_IPV4_ROUTE_MIN_PMTU=16,
-+      NET_IPV4_ROUTE_MIN_ADVMSS=17,
-+      NET_IPV4_ROUTE_SECRET_INTERVAL=18,
-+};
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_802_3.h>
++#include <linux/module.h>
 +
-+enum
++static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, const void *data, unsigned int datalen)
 +{
-+      NET_PROTO_CONF_ALL=-2,
-+      NET_PROTO_CONF_DEFAULT=-3
-+
-+      /* And device ifindices ... */
-+};
-+
-+enum
-+{
-+      NET_IPV4_CONF_FORWARDING=1,
-+      NET_IPV4_CONF_MC_FORWARDING=2,
-+      NET_IPV4_CONF_PROXY_ARP=3,
-+      NET_IPV4_CONF_ACCEPT_REDIRECTS=4,
-+      NET_IPV4_CONF_SECURE_REDIRECTS=5,
-+      NET_IPV4_CONF_SEND_REDIRECTS=6,
-+      NET_IPV4_CONF_SHARED_MEDIA=7,
-+      NET_IPV4_CONF_RP_FILTER=8,
-+      NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
-+      NET_IPV4_CONF_BOOTP_RELAY=10,
-+      NET_IPV4_CONF_LOG_MARTIANS=11,
-+      NET_IPV4_CONF_TAG=12,
-+      NET_IPV4_CONF_ARPFILTER=13,
-+      NET_IPV4_CONF_MEDIUM_ID=14,
-+      NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
-+      NET_IPV4_CONF_ARP_ANNOUNCE=18,
-+      NET_IPV4_CONF_ARP_IGNORE=19,
-+};
-+
-+/* /proc/sys/net/ipv4/netfilter */
-+enum
-+{
-+      NET_IPV4_NF_CONNTRACK_MAX=1,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
-+      NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
-+      NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10,
-+      NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
-+      NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
-+      NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
-+      NET_IPV4_NF_CONNTRACK_BUCKETS=14,
-+};
-+ 
-+/* /proc/sys/net/ipv6 */
-+enum {
-+      NET_IPV6_CONF=16,
-+      NET_IPV6_NEIGH=17,
-+      NET_IPV6_ROUTE=18,
-+      NET_IPV6_ICMP=19,
-+      NET_IPV6_BINDV6ONLY=20,
-+      NET_IPV6_MLD_MAX_MSF=25,
-+};
-+
-+enum {
-+      NET_IPV6_ROUTE_FLUSH=1,
-+      NET_IPV6_ROUTE_GC_THRESH=2,
-+      NET_IPV6_ROUTE_MAX_SIZE=3,
-+      NET_IPV6_ROUTE_GC_MIN_INTERVAL=4,
-+      NET_IPV6_ROUTE_GC_TIMEOUT=5,
-+      NET_IPV6_ROUTE_GC_INTERVAL=6,
-+      NET_IPV6_ROUTE_GC_ELASTICITY=7,
-+      NET_IPV6_ROUTE_MTU_EXPIRES=8,
-+      NET_IPV6_ROUTE_MIN_ADVMSS=9
-+};
-+
-+enum {
-+      NET_IPV6_FORWARDING=1,
-+      NET_IPV6_HOP_LIMIT=2,
-+      NET_IPV6_MTU=3,
-+      NET_IPV6_ACCEPT_RA=4,
-+      NET_IPV6_ACCEPT_REDIRECTS=5,
-+      NET_IPV6_AUTOCONF=6,
-+      NET_IPV6_DAD_TRANSMITS=7,
-+      NET_IPV6_RTR_SOLICITS=8,
-+      NET_IPV6_RTR_SOLICIT_INTERVAL=9,
-+      NET_IPV6_RTR_SOLICIT_DELAY=10
-+};
-+
-+/* /proc/sys/net/ipv6/icmp */
-+enum {
-+      NET_IPV6_ICMP_RATELIMIT=1
-+};
-+
-+/* /proc/sys/net/<protocol>/neigh/<dev> */
-+enum {
-+      NET_NEIGH_MCAST_SOLICIT=1,
-+      NET_NEIGH_UCAST_SOLICIT=2,
-+      NET_NEIGH_APP_SOLICIT=3,
-+      NET_NEIGH_RETRANS_TIME=4,
-+      NET_NEIGH_REACHABLE_TIME=5,
-+      NET_NEIGH_DELAY_PROBE_TIME=6,
-+      NET_NEIGH_GC_STALE_TIME=7,
-+      NET_NEIGH_UNRES_QLEN=8,
-+      NET_NEIGH_PROXY_QLEN=9,
-+      NET_NEIGH_ANYCAST_DELAY=10,
-+      NET_NEIGH_PROXY_DELAY=11,
-+      NET_NEIGH_LOCKTIME=12,
-+      NET_NEIGH_GC_INTERVAL=13,
-+      NET_NEIGH_GC_THRESH1=14,
-+      NET_NEIGH_GC_THRESH2=15,
-+      NET_NEIGH_GC_THRESH3=16
-+};
++      struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
++      struct ebt_802_3_hdr *hdr = (struct ebt_802_3_hdr *)skb->mac.ethernet;
++      uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
 +
-+/* /proc/sys/net/ipx */
-+enum {
-+      NET_IPX_PPROP_BROADCASTING=1,
-+      NET_IPX_FORWARDING=2
-+};
++      if (info->bitmask & EBT_802_3_SAP) {
++              if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) 
++                              return EBT_NOMATCH;
++              if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP))
++                              return EBT_NOMATCH;
++      }
 +
++      if (info->bitmask & EBT_802_3_TYPE) {
++              if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
++                      return EBT_NOMATCH;
++              if (FWINV(info->type != type, EBT_802_3_TYPE)) 
++                      return EBT_NOMATCH;
++      }
 +
-+/* /proc/sys/net/appletalk */
-+enum {
-+      NET_ATALK_AARP_EXPIRY_TIME=1,
-+      NET_ATALK_AARP_TICK_TIME=2,
-+      NET_ATALK_AARP_RETRANSMIT_LIMIT=3,
-+      NET_ATALK_AARP_RESOLVE_TIME=4
-+};
++      return EBT_MATCH;
++}
 +
++static struct ebt_match filter_802_3;
++static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
 +
-+/* /proc/sys/net/netrom */
-+enum {
-+      NET_NETROM_DEFAULT_PATH_QUALITY=1,
-+      NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER=2,
-+      NET_NETROM_NETWORK_TTL_INITIALISER=3,
-+      NET_NETROM_TRANSPORT_TIMEOUT=4,
-+      NET_NETROM_TRANSPORT_MAXIMUM_TRIES=5,
-+      NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY=6,
-+      NET_NETROM_TRANSPORT_BUSY_DELAY=7,
-+      NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8,
-+      NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9,
-+      NET_NETROM_ROUTING_CONTROL=10,
-+      NET_NETROM_LINK_FAILS_COUNT=11
-+};
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_802_3_info)))
++              return -EINVAL;
++      if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK)
++              return -EINVAL;
 +
-+/* /proc/sys/net/ax25 */
-+enum {
-+      NET_AX25_IP_DEFAULT_MODE=1,
-+      NET_AX25_DEFAULT_MODE=2,
-+      NET_AX25_BACKOFF_TYPE=3,
-+      NET_AX25_CONNECT_MODE=4,
-+      NET_AX25_STANDARD_WINDOW=5,
-+      NET_AX25_EXTENDED_WINDOW=6,
-+      NET_AX25_T1_TIMEOUT=7,
-+      NET_AX25_T2_TIMEOUT=8,
-+      NET_AX25_T3_TIMEOUT=9,
-+      NET_AX25_IDLE_TIMEOUT=10,
-+      NET_AX25_N2=11,
-+      NET_AX25_PACLEN=12,
-+      NET_AX25_PROTOCOL=13,
-+      NET_AX25_DAMA_SLAVE_TIMEOUT=14
-+};
++      return 0;
++}
 +
-+/* /proc/sys/net/rose */
-+enum {
-+      NET_ROSE_RESTART_REQUEST_TIMEOUT=1,
-+      NET_ROSE_CALL_REQUEST_TIMEOUT=2,
-+      NET_ROSE_RESET_REQUEST_TIMEOUT=3,
-+      NET_ROSE_CLEAR_REQUEST_TIMEOUT=4,
-+      NET_ROSE_ACK_HOLD_BACK_TIMEOUT=5,
-+      NET_ROSE_ROUTING_CONTROL=6,
-+      NET_ROSE_LINK_FAIL_TIMEOUT=7,
-+      NET_ROSE_MAX_VCS=8,
-+      NET_ROSE_WINDOW_SIZE=9,
-+      NET_ROSE_NO_ACTIVITY_TIMEOUT=10
++static struct ebt_match filter_802_3 =
++{
++      .name           = EBT_802_3_MATCH,
++      .match          = ebt_filter_802_3,
++      .check          = ebt_802_3_check,
++      .me             = THIS_MODULE,
 +};
 +
-+/* /proc/sys/net/x25 */
-+enum {
-+      NET_X25_RESTART_REQUEST_TIMEOUT=1,
-+      NET_X25_CALL_REQUEST_TIMEOUT=2,
-+      NET_X25_RESET_REQUEST_TIMEOUT=3,
-+      NET_X25_CLEAR_REQUEST_TIMEOUT=4,
-+      NET_X25_ACK_HOLD_BACK_TIMEOUT=5
-+};
++static int __init init(void)
++{
++      return ebt_register_match(&filter_802_3);
++}
 +
-+/* /proc/sys/net/token-ring */
-+enum
++static void __exit fini(void)
 +{
-+      NET_TR_RIF_TIMEOUT=1
-+};
++      ebt_unregister_match(&filter_802_3);
++}
 +
-+/* /proc/sys/net/decnet/ */
-+enum {
-+      NET_DECNET_NODE_TYPE = 1,
-+      NET_DECNET_NODE_ADDRESS = 2,
-+      NET_DECNET_NODE_NAME = 3,
-+      NET_DECNET_DEFAULT_DEVICE = 4,
-+      NET_DECNET_TIME_WAIT = 5,
-+      NET_DECNET_DN_COUNT = 6,
-+      NET_DECNET_DI_COUNT = 7,
-+      NET_DECNET_DR_COUNT = 8,
-+      NET_DECNET_DST_GC_INTERVAL = 9,
-+      NET_DECNET_CONF = 10,
-+      NET_DECNET_NO_FC_MAX_CWND = 11,
-+      NET_DECNET_DEBUG_LEVEL = 255
-+};
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_mark.c      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,66 @@
++/*
++ *  ebt_mark
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  July, 2002
++ *
++ */
 +
-+/* /proc/sys/net/sctp */
-+enum {
-+      NET_SCTP_RTO_INITIAL = 1,
-+      NET_SCTP_RTO_MIN     = 2,
-+      NET_SCTP_RTO_MAX     = 3,
-+      NET_SCTP_RTO_ALPHA   = 4,
-+      NET_SCTP_RTO_BETA    = 5,
-+      NET_SCTP_VALID_COOKIE_LIFE       =  6,
-+      NET_SCTP_ASSOCIATION_MAX_RETRANS =  7,
-+      NET_SCTP_PATH_MAX_RETRANS        =  8,
-+      NET_SCTP_MAX_INIT_RETRANSMITS    =  9,
-+      NET_SCTP_HB_INTERVAL             = 10,
-+      NET_SCTP_PRESERVE_ENABLE         = 11,
-+      NET_SCTP_MAX_BURST               = 12,
-+      NET_SCTP_ADDIP_ENABLE            = 13,
-+      NET_SCTP_PRSCTP_ENABLE           = 14,
-+};
-+/* /proc/sys/net/khttpd/ */
-+enum {
-+      NET_KHTTPD_DOCROOT      = 1,
-+      NET_KHTTPD_START        = 2,
-+      NET_KHTTPD_STOP         = 3,
-+      NET_KHTTPD_UNLOAD       = 4,
-+      NET_KHTTPD_CLIENTPORT   = 5,
-+      NET_KHTTPD_PERMREQ      = 6,
-+      NET_KHTTPD_PERMFORBID   = 7,
-+      NET_KHTTPD_LOGGING      = 8,
-+      NET_KHTTPD_SERVERPORT   = 9,
-+      NET_KHTTPD_DYNAMICSTRING= 10,
-+      NET_KHTTPD_SLOPPYMIME   = 11,
-+      NET_KHTTPD_THREADS      = 12,
-+      NET_KHTTPD_MAXCONNECT   = 13
-+};
++// The mark target can be used in any chain
++// I believe adding a mangle table just for marking is total overkill
++// Marking a frame doesn't really change anything in the frame anyway
 +
-+/* /proc/sys/net/decnet/conf/<dev> */
-+enum {
-+      NET_DECNET_CONF_LOOPBACK = -2,
-+      NET_DECNET_CONF_DDCMP = -3,
-+      NET_DECNET_CONF_PPP = -4,
-+      NET_DECNET_CONF_X25 = -5,
-+      NET_DECNET_CONF_GRE = -6,
-+      NET_DECNET_CONF_ETHER = -7
-+
-+      /* ... and ifindex of devices */
-+};
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_mark_t.h>
++#include <linux/module.h>
 +
-+/* /proc/sys/net/decnet/conf/<dev>/ */
-+enum {
-+      NET_DECNET_CONF_DEV_PRIORITY = 1,
-+      NET_DECNET_CONF_DEV_T1 = 2,
-+      NET_DECNET_CONF_DEV_T2 = 3,
-+      NET_DECNET_CONF_DEV_T3 = 4,
-+      NET_DECNET_CONF_DEV_FORWARDING = 5,
-+      NET_DECNET_CONF_DEV_BLKSIZE = 6,
-+      NET_DECNET_CONF_DEV_STATE = 7
-+};
++static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
 +
-+/* CTL_PROC names: */
-+
-+/* CTL_FS names: */
-+enum
-+{
-+      FS_NRINODE=1,   /* int:current number of allocated inodes */
-+      FS_STATINODE=2,
-+      FS_MAXINODE=3,  /* int:maximum number of inodes that can be allocated */
-+      FS_NRDQUOT=4,   /* int:current number of allocated dquots */
-+      /* was FS_MAXDQUOT */
-+      FS_NRFILE=6,    /* int:current number of allocated filedescriptors */
-+      FS_MAXFILE=7,   /* int:maximum number of filedescriptors that can be allocated */
-+      FS_DENTRY=8,
-+      FS_NRSUPER=9,   /* int:current number of allocated super_blocks */
-+      FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */
-+      FS_OVERFLOWUID=11,      /* int: overflow UID */
-+      FS_OVERFLOWGID=12,      /* int: overflow GID */
-+      FS_LEASES=13,   /* int: leases enabled */
-+      FS_DIR_NOTIFY=14,       /* int: directory notification enabled */
-+      FS_LEASE_TIME=15,       /* int: maximum time to wait for a lease break */
-+      FS_DQSTATS=16,  /* dir: disc quota usage statistics and settings */
-+      FS_XFS=17,      /* struct: control xfs parameters */
-+};
++      if ((*pskb)->nfmark != info->mark) {
++              (*pskb)->nfmark = info->mark;
++              (*pskb)->nfcache |= NFC_ALTERED;
++      }
++      return info->target;
++}
 +
-+/* /proc/sys/fs/quota/ */
-+enum {
-+      FS_DQ_LOOKUPS = 1,
-+      FS_DQ_DROPS = 2,
-+      FS_DQ_READS = 3,
-+      FS_DQ_WRITES = 4,
-+      FS_DQ_CACHE_HITS = 5,
-+      FS_DQ_ALLOCATED = 6,
-+      FS_DQ_FREE = 7,
-+      FS_DQ_SYNCS = 8,
-+      FS_DQ_WARNINGS = 9,
-+};
++static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
 +
-+/* CTL_DEBUG names: */
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
++              return -EINVAL;
++      if (BASE_CHAIN && info->target == EBT_RETURN)
++              return -EINVAL;
++      CLEAR_BASE_CHAIN_BIT;
++      if (INVALID_TARGET)
++              return -EINVAL;
++      return 0;
++}
 +
-+/* CTL_DEV names: */
-+enum {
-+      DEV_CDROM=1,
-+      DEV_HWMON=2,
-+      DEV_PARPORT=3,
-+      DEV_RAID=4,
-+      DEV_MAC_HID=5
++static struct ebt_target mark_target =
++{
++      {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark,
++      ebt_target_mark_check, NULL, THIS_MODULE
 +};
 +
-+/* /proc/sys/dev/cdrom */
-+enum {
-+      DEV_CDROM_INFO=1,
-+      DEV_CDROM_AUTOCLOSE=2,
-+      DEV_CDROM_AUTOEJECT=3,
-+      DEV_CDROM_DEBUG=4,
-+      DEV_CDROM_LOCK=5,
-+      DEV_CDROM_CHECK_MEDIA=6
-+};
++static int __init init(void)
++{
++      return ebt_register_target(&mark_target);
++}
 +
-+/* /proc/sys/dev/parport */
-+enum {
-+      DEV_PARPORT_DEFAULT=-3
-+};
++static void __exit fini(void)
++{
++      ebt_unregister_target(&mark_target);
++}
 +
-+/* /proc/sys/dev/raid */
-+enum {
-+      DEV_RAID_SPEED_LIMIT_MIN=1,
-+      DEV_RAID_SPEED_LIMIT_MAX=2
-+};
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_mark_m.c    2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,61 @@
++/*
++ *  ebt_mark_m
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  July, 2002
++ *
++ */
 +
-+/* /proc/sys/dev/parport/default */
-+enum {
-+      DEV_PARPORT_DEFAULT_TIMESLICE=1,
-+      DEV_PARPORT_DEFAULT_SPINTIME=2
-+};
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_mark_m.h>
++#include <linux/module.h>
 +
-+/* /proc/sys/dev/parport/parport n */
-+enum {
-+      DEV_PARPORT_SPINTIME=1,
-+      DEV_PARPORT_BASE_ADDR=2,
-+      DEV_PARPORT_IRQ=3,
-+      DEV_PARPORT_DMA=4,
-+      DEV_PARPORT_MODES=5,
-+      DEV_PARPORT_DEVICES=6,
-+      DEV_PARPORT_AUTOPROBE=16
-+};
++static int ebt_filter_mark(const struct sk_buff *skb,
++   const struct net_device *in, const struct net_device *out, const void *data,
++   unsigned int datalen)
++{
++      struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
 +
-+/* /proc/sys/dev/parport/parport n/devices/ */
-+enum {
-+      DEV_PARPORT_DEVICES_ACTIVE=-3,
-+};
++      if (info->bitmask & EBT_MARK_OR)
++              return !(!!(skb->nfmark & info->mask) ^ info->invert);
++      return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
++}
 +
-+/* /proc/sys/dev/parport/parport n/devices/device n */
-+enum {
-+      DEV_PARPORT_DEVICE_TIMESLICE=1,
-+};
++static int ebt_mark_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++        struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
 +
-+/* /proc/sys/dev/mac_hid */
-+enum {
-+      DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1,
-+      DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2,
-+      DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3,
-+      DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4,
-+      DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5,
-+      DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6
-+};
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
++              return -EINVAL;
++      if (info->bitmask & ~EBT_MARK_MASK)
++              return -EINVAL;
++      if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
++              return -EINVAL;
++      if (!info->bitmask)
++              return -EINVAL;
++      return 0;
++}
 +
-+/* /proc/sys/abi */
-+enum
++static struct ebt_match filter_mark =
 +{
-+      ABI_DEFHANDLER_COFF=1,  /* default handler for coff binaries */
-+      ABI_DEFHANDLER_ELF=2,   /* default handler for ELF binaries */
-+      ABI_DEFHANDLER_LCALL7=3,/* default handler for procs using lcall7 */
-+      ABI_DEFHANDLER_LIBCSO=4,/* default handler for an libc.so ELF interp */
-+      ABI_TRACE=5,            /* tracing flags */
-+      ABI_FAKE_UTSNAME=6,     /* fake target utsname information */
++      {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL,
++      THIS_MODULE
 +};
 +
-+#ifdef __KERNEL__
-+
-+extern asmlinkage long sys_sysctl(struct __sysctl_args *);
-+extern void sysctl_init(void);
-+
-+typedef struct ctl_table ctl_table;
-+
-+typedef int ctl_handler (ctl_table *table, int *name, int nlen,
-+                       void *oldval, size_t *oldlenp,
-+                       void *newval, size_t newlen, 
-+                       void **context);
-+
-+typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
-+                        void *buffer, size_t *lenp);
-+
-+extern int proc_dostring(ctl_table *, int, struct file *,
-+                       void *, size_t *);
-+extern int proc_dointvec(ctl_table *, int, struct file *,
-+                       void *, size_t *);
-+extern int proc_dointvec_bset(ctl_table *, int, struct file *,
-+                            void *, size_t *);
-+extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
-+                              void *, size_t *);
-+extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
-+                               void *, size_t *);
-+extern int proc_doulongvec_minmax(ctl_table *, int, struct file *,
-+                                void *, size_t *);
-+extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int,
-+                                    struct file *, void *, size_t *);
-+
-+extern int do_sysctl (int *name, int nlen,
-+                    void *oldval, size_t *oldlenp,
-+                    void *newval, size_t newlen);
-+
-+extern int do_sysctl_strategy (ctl_table *table, 
-+                             int *name, int nlen,
-+                             void *oldval, size_t *oldlenp,
-+                             void *newval, size_t newlen, void ** context);
-+
-+extern ctl_handler sysctl_string;
-+extern ctl_handler sysctl_intvec;
-+extern ctl_handler sysctl_jiffies;
++static int __init init(void)
++{
++      return ebt_register_match(&filter_mark);
++}
 +
++static void __exit fini(void)
++{
++      ebt_unregister_match(&filter_mark);
++}
 +
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_pkttype.c   2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,60 @@
 +/*
-+ * Register a set of sysctl names by calling register_sysctl_table
-+ * with an initialised array of ctl_table's.  An entry with zero
-+ * ctl_name terminates the table.  table->de will be set up by the
-+ * registration and need not be initialised in advance.
++ *  ebt_pkttype
 + *
-+ * sysctl names can be mirrored automatically under /proc/sys.  The
-+ * procname supplied controls /proc naming.
++ *    Authors:
++ *    Bart De Schuymer <bdschuym@pandora.be>
 + *
-+ * The table's mode will be honoured both for sys_sysctl(2) and
-+ * proc-fs access.
++ *  April, 2003
 + *
-+ * Leaf nodes in the sysctl tree will be represented by a single file
-+ * under /proc; non-leaf nodes will be represented by directories.  A
-+ * null procname disables /proc mirroring at this node.
-+ * 
-+ * sysctl(2) can automatically manage read and write requests through
-+ * the sysctl table.  The data and maxlen fields of the ctl_table
-+ * struct enable minimal validation of the values being written to be
-+ * performed, and the mode field allows minimal authentication.
-+ * 
-+ * More sophisticated management can be enabled by the provision of a
-+ * strategy routine with the table entry.  This will be called before
-+ * any automatic read or write of the data is performed.
-+ * 
-+ * The strategy routine may return:
-+ * <0: Error occurred (error is passed to user process)
-+ * 0:  OK - proceed with automatic read or write.
-+ * >0: OK - read or write has been done by the strategy routine, so 
-+ *     return immediately.
-+ * 
-+ * There must be a proc_handler routine for any terminal nodes
-+ * mirrored under /proc/sys (non-terminals are handled by a built-in
-+ * directory handler).  Several default handlers are available to
-+ * cover common cases.
 + */
 +
-+/* A sysctl table is an array of struct ctl_table: */
-+struct ctl_table 
-+{
-+      int ctl_name;                   /* Binary ID */
-+      const char *procname;           /* Text ID for /proc/sys, or zero */
-+      void *data;
-+      int maxlen;
-+      mode_t mode;
-+      ctl_table *child;
-+      proc_handler *proc_handler;     /* Callback for text formatting */
-+      ctl_handler *strategy;          /* Callback function for all r/w */
-+      struct proc_dir_entry *de;      /* /proc control block */
-+      void *extra1;
-+      void *extra2;
-+};
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_pkttype.h>
++#include <linux/module.h>
++
++static int ebt_filter_pkttype(const struct sk_buff *skb,
++   const struct net_device *in,
++   const struct net_device *out,
++   const void *data,
++   unsigned int datalen)
++{
++      struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++
++      return (skb->pkt_type != info->pkt_type) ^ info->invert;
++}
++
++static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
++              return -EINVAL;
++      if (info->invert != 0 && info->invert != 1)
++              return -EINVAL;
++      /* Allow any pkt_type value */
++      return 0;
++}
 +
-+/* struct ctl_table_header is used to maintain dynamic lists of
-+   ctl_table trees. */
-+struct ctl_table_header
++static struct ebt_match filter_pkttype =
 +{
-+      ctl_table *ctl_table;
-+      struct list_head ctl_entry;
++      .name           = EBT_PKTTYPE_MATCH,
++      .match          = ebt_filter_pkttype,
++      .check          = ebt_pkttype_check,
++      .me             = THIS_MODULE,
 +};
 +
-+struct ctl_table_header * register_sysctl_table(ctl_table * table, 
-+                                              int insert_at_head);
-+void unregister_sysctl_table(struct ctl_table_header * table);
++static int __init init(void)
++{
++      return ebt_register_match(&filter_pkttype);
++}
 +
-+#else /* __KERNEL__ */
++static void __exit fini(void)
++{
++      ebt_unregister_match(&filter_pkttype);
++}
 +
-+#endif /* __KERNEL__ */
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_stp.c       2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,191 @@
++/*
++ *  ebt_stp
++ *
++ *    Authors:
++ *    Bart De Schuymer <bdschuym@pandora.be>
++ *    Stephen Hemminger <shemminger@osdl.org>
++ *
++ *  June, 2003
++ */
 +
-+#endif /* _LINUX_SYSCTL_H */
-diff -Nur linux-mips-cvs/net/8021q/vlan_dev.c linux-ebtables/net/8021q/vlan_dev.c
---- linux-mips-cvs/net/8021q/vlan_dev.c        2004-11-29 18:47:19.000000000 +0100
-+++ linux-ebtables/net/8021q/vlan_dev.c        2005-02-07 05:52:50.000000000 +0100
-@@ -488,6 +488,10 @@
-       stats->tx_packets++; /* for statics only */
-       stats->tx_bytes += skb->len;
-+      skb->protocol = __constant_htons(ETH_P_8021Q);
-+      skb->mac.raw -= VLAN_HLEN;
-+      skb->nh.raw -= VLAN_HLEN;
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_stp.h>
++#include <linux/module.h>
 +
-       skb->dev = VLAN_DEV_INFO(dev)->real_dev;
-       dev_queue_xmit(skb);
-diff -Nur linux-mips-cvs/net/Config.in linux-ebtables/net/Config.in
---- linux-mips-cvs/net/Config.in       2005-01-09 20:34:04.000000000 +0100
-+++ linux-ebtables/net/Config.in       2005-02-07 05:52:50.000000000 +0100
-@@ -70,6 +70,9 @@
-    source net/decnet/Config.in
- fi
- dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
-+if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
-+   source net/bridge/netfilter/Config.in
-+fi
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
-    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-diff -Nur linux-mips-cvs/net/Config.in.orig linux-ebtables/net/Config.in.orig
---- linux-mips-cvs/net/Config.in.orig  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/Config.in.orig  2005-01-09 20:34:04.000000000 +0100
-@@ -0,0 +1,107 @@
-+#
-+# Network configuration
-+#
-+mainmenu_option next_comment
-+comment 'Networking options'
-+tristate 'Packet socket' CONFIG_PACKET
-+if [ "$CONFIG_PACKET" != "n" ]; then
-+   bool '  Packet socket: mmapped IO' CONFIG_PACKET_MMAP
-+fi
++#define BPDU_TYPE_CONFIG 0
++#define BPDU_TYPE_TCN 0x80
 +
-+tristate 'Netlink device emulation' CONFIG_NETLINK_DEV
++struct stp_header {
++      uint8_t dsap;
++      uint8_t ssap;
++      uint8_t ctrl;
++      uint8_t pid;
++      uint8_t vers;
++      uint8_t type;
++};
 +
-+bool 'Network packet filtering (replaces ipchains)' CONFIG_NETFILTER
-+if [ "$CONFIG_NETFILTER" = "y" ]; then
-+   bool '  Network packet filtering debugging' CONFIG_NETFILTER_DEBUG
-+fi
-+bool 'Socket Filtering'  CONFIG_FILTER
-+tristate 'Unix domain sockets' CONFIG_UNIX
-+bool 'TCP/IP networking' CONFIG_INET
-+if [ "$CONFIG_INET" = "y" ]; then
-+   source net/ipv4/Config.in
-+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+#   IPv6 as module will cause a CRASH if you try to unload it
-+      tristate '  The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
-+      if [ "$CONFIG_IPV6" != "n" ]; then
-+       source net/ipv6/Config.in
-+      fi
-+   fi
-+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+      source net/khttpd/Config.in
-+   fi
-+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+      source net/sctp/Config.in
-+   fi
-+fi
-+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+   tristate 'Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)' CONFIG_ATM
-+   if [ "$CONFIG_ATM" = "y" -o "$CONFIG_ATM" = "m" ]; then
-+      if [ "$CONFIG_INET" = "y" ]; then
-+       dep_tristate '  Classical IP over ATM' CONFIG_ATM_CLIP $CONFIG_ATM
-+       if [ "$CONFIG_ATM_CLIP" != "n" ]; then
-+          bool '    Do NOT send ICMP if no neighbour' CONFIG_ATM_CLIP_NO_ICMP
-+       fi
-+      fi
-+      dep_tristate '  LAN Emulation (LANE) support' CONFIG_ATM_LANE $CONFIG_ATM
-+      if [ "$CONFIG_INET" = "y" -a "$CONFIG_ATM_LANE" != "n" ]; then
-+       tristate '    Multi-Protocol Over ATM (MPOA) support' CONFIG_ATM_MPOA
-+      fi
-+      dep_tristate '  RFC1483/2684 Bridged protocols' CONFIG_ATM_BR2684 $CONFIG_ATM
-+      if [ "$CONFIG_ATM_BR2684" != "n" ]; then
-+            bool '    Per-VC IP filter kludge' CONFIG_ATM_BR2684_IPFILTER
-+      fi
-+   fi
-+fi
-+tristate '802.1Q VLAN Support' CONFIG_VLAN_8021Q
++struct stp_config_pdu {
++      uint8_t flags;
++      uint8_t root[8];
++      uint8_t root_cost[4];
++      uint8_t sender[8];
++      uint8_t port[2];
++      uint8_t msg_age[2];
++      uint8_t max_age[2];
++      uint8_t hello_time[2];
++      uint8_t forward_delay[2];
++};
 +
-+comment ' '
-+tristate 'The IPX protocol' CONFIG_IPX
-+if [ "$CONFIG_IPX" != "n" ]; then
-+   source net/ipx/Config.in
-+fi
++#define NR16(p) (p[0] << 8 | p[1])
++#define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
 +
-+tristate 'Appletalk protocol support' CONFIG_ATALK
-+if [ "$CONFIG_ATALK" != "n" ]; then
-+   source drivers/net/appletalk/Config.in
-+fi
++static int ebt_filter_config(struct ebt_stp_info *info,
++   struct stp_config_pdu *stpc)
++{
++      struct ebt_stp_config_info *c;
++      uint16_t v16;
++      uint32_t v32;
++      int verdict, i;
 +
-+tristate 'DECnet Support' CONFIG_DECNET
-+if [ "$CONFIG_DECNET" != "n" ]; then
-+   source net/decnet/Config.in
-+fi
-+dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
-+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-+   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
-+   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-+   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
-+   bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT
-+#   if [ "$CONFIG_LLC" = "y" ]; then
-+#      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
-+#   fi
-+   if [ "$CONFIG_INET" = "y" ]; then
-+      tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET
-+      if [ "$CONFIG_ECONET" != "n" ]; then
-+       bool '  AUN over UDP' CONFIG_ECONET_AUNUDP
-+       bool '  Native Econet' CONFIG_ECONET_NATIVE
-+      fi
-+   fi
-+   tristate 'WAN router' CONFIG_WAN_ROUTER
-+   bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE
-+   bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL
-+fi
++      c = &info->config;
++      if ((info->bitmask & EBT_STP_FLAGS) &&
++          FWINV(c->flags != stpc->flags, EBT_STP_FLAGS))
++              return EBT_NOMATCH;
++      if (info->bitmask & EBT_STP_ROOTPRIO) {
++              v16 = NR16(stpc->root);
++              if (FWINV(v16 < c->root_priol ||
++                  v16 > c->root_priou, EBT_STP_ROOTPRIO))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_ROOTADDR) {
++              verdict = 0;
++              for (i = 0; i < 6; i++)
++                      verdict |= (stpc->root[2+i] ^ c->root_addr[i]) &
++                                 c->root_addrmsk[i];
++              if (FWINV(verdict != 0, EBT_STP_ROOTADDR))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_ROOTCOST) {
++              v32 = NR32(stpc->root_cost);
++              if (FWINV(v32 < c->root_costl ||
++                  v32 > c->root_costu, EBT_STP_ROOTCOST))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_SENDERPRIO) {
++              v16 = NR16(stpc->sender);
++              if (FWINV(v16 < c->sender_priol ||
++                  v16 > c->sender_priou, EBT_STP_SENDERPRIO))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_SENDERADDR) {
++              verdict = 0;
++              for (i = 0; i < 6; i++)
++                      verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) &
++                                 c->sender_addrmsk[i];
++              if (FWINV(verdict != 0, EBT_STP_SENDERADDR))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_PORT) {
++              v16 = NR16(stpc->port);
++              if (FWINV(v16 < c->portl ||
++                  v16 > c->portu, EBT_STP_PORT))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_MSGAGE) {
++              v16 = NR16(stpc->msg_age);
++              if (FWINV(v16 < c->msg_agel ||
++                  v16 > c->msg_ageu, EBT_STP_MSGAGE))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_MAXAGE) {
++              v16 = NR16(stpc->max_age);
++              if (FWINV(v16 < c->max_agel ||
++                  v16 > c->max_ageu, EBT_STP_MAXAGE))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_HELLOTIME) {
++              v16 = NR16(stpc->hello_time);
++              if (FWINV(v16 < c->hello_timel ||
++                  v16 > c->hello_timeu, EBT_STP_HELLOTIME))
++                      return EBT_NOMATCH;
++      }
++      if (info->bitmask & EBT_STP_FWDD) {
++              v16 = NR16(stpc->forward_delay);
++              if (FWINV(v16 < c->forward_delayl ||
++                  v16 > c->forward_delayu, EBT_STP_FWDD))
++                      return EBT_NOMATCH;
++      }
++      return EBT_MATCH;
++}
 +
-+mainmenu_option next_comment
-+comment 'QoS and/or fair queueing'
-+bool 'QoS and/or fair queueing' CONFIG_NET_SCHED
-+if [ "$CONFIG_NET_SCHED" = "y" ]; then
-+   source net/sched/Config.in
-+fi
-+#bool 'Network code profiler' CONFIG_NET_PROFILE
-+endmenu
-+
-+mainmenu_option next_comment
-+comment 'Network testing'
-+dep_tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN $CONFIG_PROC_FS
-+endmenu
-+
-+endmenu
-diff -Nur linux-mips-cvs/net/Makefile linux-ebtables/net/Makefile
---- linux-mips-cvs/net/Makefile        2004-08-14 20:39:04.000000000 +0200
-+++ linux-ebtables/net/Makefile        2005-02-07 05:52:50.000000000 +0100
-@@ -7,7 +7,8 @@
- O_TARGET :=   network.o
--mod-subdirs :=        ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core sctp 802
-+mod-subdirs :=        ipv4/netfilter ipv6/netfilter bridge/netfilter ipx irda \
-+      bluetooth atm netlink sched core sctp 802
- export-objs :=        netsyms.o
- subdir-y :=   core ethernet
-@@ -27,6 +28,12 @@
- endif
- endif
-+ifneq ($(CONFIG_BRIDGE),n)
-+ifneq ($(CONFIG_BRIDGE),)
-+subdir-$(CONFIG_BRIDGE)               += bridge/netfilter
-+endif
-+endif
++static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, const void *data, unsigned int datalen)
++{
++      struct ebt_stp_info *info = (struct ebt_stp_info *)data;
++      struct stp_header stph;
++      uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
++      if (skb_copy_bits(skb, 0, &stph, sizeof(stph)))
++              return EBT_NOMATCH;
 +
- subdir-$(CONFIG_KHTTPD)               += khttpd
- subdir-$(CONFIG_PACKET)               += packet
- subdir-$(CONFIG_NET_SCHED)    += sched
-diff -Nur linux-mips-cvs/net/bridge/Makefile linux-ebtables/net/bridge/Makefile
---- linux-mips-cvs/net/bridge/Makefile 2001-01-10 18:18:10.000000000 +0100
-+++ linux-ebtables/net/bridge/Makefile 2005-02-07 05:52:50.000000000 +0100
-@@ -7,10 +7,17 @@
- #
- # Note 2! The CFLAGS definition is now in the main makefile...
-+export-objs := br.o
++      /* The stp code only considers these */
++      if (memcmp(&stph, header, sizeof(header)))
++              return EBT_NOMATCH;
 +
- O_TARGET      := bridge.o
- obj-y         := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
-                       br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
-                       br_stp_if.o br_stp_timer.o
++      if (info->bitmask & EBT_STP_TYPE
++          && FWINV(info->type != stph.type, EBT_STP_TYPE))
++              return EBT_NOMATCH;
 +
-+ifeq ($(CONFIG_NETFILTER),y)
-+obj-y         += br_netfilter.o
-+endif
++      if (stph.type == BPDU_TYPE_CONFIG &&
++          info->bitmask & EBT_STP_CONFIG_MASK) {
++              struct stp_config_pdu stpc;
 +
- obj-m         := $(O_TARGET)
- include $(TOPDIR)/Rules.make
-diff -Nur linux-mips-cvs/net/bridge/br.c linux-ebtables/net/bridge/br.c
---- linux-mips-cvs/net/bridge/br.c     2004-08-14 20:39:04.000000000 +0200
-+++ linux-ebtables/net/bridge/br.c     2005-02-07 05:52:50.000000000 +0100
-@@ -30,6 +30,8 @@
- #include "../atm/lec.h"
- #endif
-+int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
++              if (skb_copy_bits(skb, sizeof(stph), &stpc, sizeof(stpc)))
++                  return EBT_NOMATCH;
++              return ebt_filter_config(info, &stpc);
++      }
++      return EBT_MATCH;
++}
 +
- void br_dec_use_count()
- {
-       MOD_DEC_USE_COUNT;
-@@ -44,6 +46,10 @@
- {
-       printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n");
-+#ifdef CONFIG_NETFILTER
-+      if (br_netfilter_init())
-+              return 1;
-+#endif
-       br_handle_frame_hook = br_handle_frame;
-       br_ioctl_hook = br_ioctl_deviceless_stub;
- #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
-@@ -57,6 +63,9 @@
- static void __exit br_deinit(void)
- {
-+#ifdef CONFIG_NETFILTER
-+      br_netfilter_fini();
-+#endif
-       unregister_netdevice_notifier(&br_device_notifier);
-       rtnl_lock();
-@@ -73,7 +82,7 @@
- #endif
- }
--EXPORT_NO_SYMBOLS;
-+EXPORT_SYMBOL(br_should_route_hook);
- module_init(br_init)
- module_exit(br_deinit)
-diff -Nur linux-mips-cvs/net/bridge/br_forward.c linux-ebtables/net/bridge/br_forward.c
---- linux-mips-cvs/net/bridge/br_forward.c     2003-11-17 02:07:47.000000000 +0100
-+++ linux-ebtables/net/bridge/br_forward.c     2005-02-07 05:52:50.000000000 +0100
-@@ -30,18 +30,21 @@
-       return 1;
- }
--static int __dev_queue_push_xmit(struct sk_buff *skb)
-+int br_dev_queue_push_xmit(struct sk_buff *skb)
- {
-+#ifdef CONFIG_NETFILTER
-+      nf_bridge_maybe_copy_header(skb);
-+#endif
-       skb_push(skb, ETH_HLEN);
-       dev_queue_xmit(skb);
-       return 0;
- }
--static int __br_forward_finish(struct sk_buff *skb)
-+int br_forward_finish(struct sk_buff *skb)
- {
-       NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
--                      __dev_queue_push_xmit);
-+                      br_dev_queue_push_xmit);
-       return 0;
- }
-@@ -49,8 +52,11 @@
- static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
- {
-       skb->dev = to->dev;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug = 0;
-+#endif
-       NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
--                      __br_forward_finish);
-+                      br_forward_finish);
- }
- static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb)
-@@ -62,7 +68,7 @@
-       skb->ip_summed = CHECKSUM_NONE;
-       NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
--                      __br_forward_finish);
-+                      br_forward_finish);
- }
- /* called under bridge lock */
-diff -Nur linux-mips-cvs/net/bridge/br_input.c linux-ebtables/net/bridge/br_input.c
---- linux-mips-cvs/net/bridge/br_input.c       2003-08-13 19:19:30.000000000 +0200
-+++ linux-ebtables/net/bridge/br_input.c       2005-02-07 05:52:50.000000000 +0100
-@@ -24,6 +24,9 @@
- static int br_pass_frame_up_finish(struct sk_buff *skb)
- {
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug = 0;
-+#endif
-       netif_rx(skb);
-       return 0;
-@@ -46,7 +49,7 @@
-                       br_pass_frame_up_finish);
- }
--static int br_handle_frame_finish(struct sk_buff *skb)
-+int br_handle_frame_finish(struct sk_buff *skb)
- {
-       struct net_bridge *br;
-       unsigned char *dest;
-@@ -112,7 +115,7 @@
-       return 0;
- }
--void br_handle_frame(struct sk_buff *skb)
-+int br_handle_frame(struct sk_buff *skb)
- {
-       struct net_bridge *br;
-       unsigned char *dest;
-@@ -146,26 +149,35 @@
-               goto handle_special_frame;
-       if (p->state == BR_STATE_FORWARDING) {
-+              if (br_should_route_hook && br_should_route_hook(&skb)) {
-+                      read_unlock(&br->lock);
-+                      return -1;
-+              }
++static int ebt_stp_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_stp_info *info = (struct ebt_stp_info *)data;
++      int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
++      uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
++      uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 +
-+              if (!memcmp(p->br->dev.dev_addr, dest, ETH_ALEN))
-+                      skb->pkt_type = PACKET_HOST;
++      if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
++          !(info->bitmask & EBT_STP_MASK))
++              return -EINVAL;
++      if (datalen != len)
++              return -EINVAL;
++      /* Make sure the match only receives stp frames */
++      if (memcmp(e->destmac, bridge_ula, ETH_ALEN) ||
++          memcmp(e->destmsk, msk, ETH_ALEN) || !(e->bitmask & EBT_DESTMAC))
++              return -EINVAL;
 +
-               NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
-                       br_handle_frame_finish);
-               read_unlock(&br->lock);
--              return;
-+              return 0;
-       }
- err:
-       read_unlock(&br->lock);
- err_nolock:
-       kfree_skb(skb);
--      return;
-+      return 0;
- handle_special_frame:
-       if (!dest[5]) {
-               NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,NULL,
-                       br_stp_handle_bpdu);
-               read_unlock(&br->lock);
--              return;
-+              return 0;
-       }
-       read_unlock(&br->lock);
-       kfree_skb(skb);
 +      return 0;
- }
-diff -Nur linux-mips-cvs/net/bridge/br_netfilter.c linux-ebtables/net/bridge/br_netfilter.c
---- linux-mips-cvs/net/bridge/br_netfilter.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/br_netfilter.c   2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,1103 @@
++}
++
++static struct ebt_match filter_stp =
++{
++      .name           = EBT_STP_MATCH,
++      .match          = ebt_filter_stp,
++      .check          = ebt_stp_check,
++      .me             = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++      return ebt_register_match(&filter_stp);
++}
++
++static void __exit fini(void)
++{
++      ebt_unregister_match(&filter_stp);
++}
++
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_redirect.c  2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,71 @@
 +/*
-+ *    Handle firewalling
-+ *    Linux ethernet bridge
++ *  ebt_redirect
 + *
 + *    Authors:
-+ *    Lennert Buytenhek               <buytenh@gnu.org>
-+ *    Bart De Schuymer (maintainer)   <bdschuym@pandora.be>
-+ *
-+ *    Changes:
-+ *    Apr 29 2003: physdev module support (bdschuym)
-+ *    Jun 19 2003: let arptables see bridged ARP traffic (bdschuym)
-+ *    Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
-+ *                 (bdschuym)
-+ *    Aug 28 2004: add IPv6 filtering (bdschuym)
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
 + *
-+ *    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.
++ *  April, 2002
 + *
-+ *    Lennert dedicates this file to Kerstin Wurdinger.
 + */
 +
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_redirect.h>
 +#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/ip.h>
-+#include <linux/netdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/if_ether.h>
-+#include <linux/if_vlan.h>
-+#include <linux/netfilter_bridge.h>
-+#include <linux/netfilter_ipv4.h>
-+#include <linux/netfilter_ipv6.h>
-+#include <linux/in_route.h>
-+#include <net/ip.h>
-+#include <net/ipv6.h>
-+#include <asm/uaccess.h>
-+#include <asm/checksum.h>
-+#include "br_private.h"
-+#ifdef CONFIG_SYSCTL
-+#include <linux/sysctl.h>
-+#endif
++#include <net/sock.h>
++#include "../br_private.h"
 +
-+#define skb_origaddr(skb)      (((struct bridge_skb_cb *) \
-+                               (skb->nf_bridge->data))->daddr.ipv4)
-+#define store_orig_dstaddr(skb)        (skb_origaddr(skb) = (skb)->nh.iph->daddr)
-+#define dnat_took_place(skb)   (skb_origaddr(skb) != (skb)->nh.iph->daddr)
++static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
 +
-+#define has_bridge_parent(device)     ((device)->br_port != NULL)
-+#define bridge_parent(device)         (&((device)->br_port->br->dev))
++      if (hooknr != NF_BR_BROUTING)
++              memcpy((**pskb).mac.ethernet->h_dest,
++                 in->br_port->br->dev.dev_addr, ETH_ALEN);
++      else {
++              memcpy((**pskb).mac.ethernet->h_dest,
++                 in->dev_addr, ETH_ALEN);
++              (*pskb)->pkt_type = PACKET_HOST;
++      }
++      return info->target;
++}
 +
-+#ifdef CONFIG_SYSCTL
-+static struct ctl_table_header *brnf_sysctl_header;
-+static int brnf_call_iptables = 1;
-+static int brnf_call_ip6tables = 1;
-+static int brnf_call_arptables = 1;
-+static int brnf_filter_vlan_tagged = 1;
-+#else
-+#define brnf_filter_vlan_tagged 1
-+#endif
++static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
 +
-+#define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
-+      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP) &&  \
-+      brnf_filter_vlan_tagged)
-+#define IS_VLAN_IPV6 (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
-+      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IPV6) &&  \
-+      brnf_filter_vlan_tagged)
-+/*
-+#define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) &&   \
-+      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \
-+      brnf_filter_vlan_tagged)
-+*/
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
++              return -EINVAL;
++      if (BASE_CHAIN && info->target == EBT_RETURN)
++              return -EINVAL;
++      CLEAR_BASE_CHAIN_BIT;
++      if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
++           (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
++              return -EINVAL;
++      if (INVALID_TARGET)
++              return -EINVAL;
++      return 0;
++}
 +
-+/* We need these fake structures to make netfilter happy --
-+ * lots of places assume that skb->dst != NULL, which isn't
-+ * all that unreasonable.
-+ *
-+ * Currently, we fill in the PMTU entry because netfilter
-+ * refragmentation needs it, and the rt_flags entry because
-+ * ipt_REJECT needs it.  Future netfilter modules might
-+ * require us to fill additional fields.
-+ */
-+static struct net_device __fake_net_device = {
-+      .hard_header_len        = ETH_HLEN
++static struct ebt_target redirect_target =
++{
++      {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect,
++      ebt_target_redirect_check, NULL, THIS_MODULE
 +};
 +
-+static struct rtable __fake_rtable = {
-+      u: {
-+              dst: {
-+                      __refcnt:               ATOMIC_INIT(1),
-+                      dev:                    &__fake_net_device,
-+                      pmtu:                   1500
-+              }
-+      },
++static int __init init(void)
++{
++      return ebt_register_target(&redirect_target);
++}
 +
-+      rt_flags:       0
-+};
++static void __exit fini(void)
++{
++      ebt_unregister_target(&redirect_target);
++}
 +
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_arp.c       2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,149 @@
++/*
++ *  ebt_arp
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *    Tim Gardner <timg@tpi.com>
++ *
++ *  April, 2002
++ *
++ */
 +
-+/* PF_BRIDGE/PRE_ROUTING *********************************************/
-+/* Undo the changes made for ip6tables PREROUTING and continue the
-+ * bridge PRE_ROUTING hook. */
-+static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_arp.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/module.h>
++
++static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, const void *data, unsigned int datalen)
 +{
-+      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
++      struct ebt_arp_info *info = (struct ebt_arp_info *)data;
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
-+#endif
++      if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
++         ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE))
++              return EBT_NOMATCH;
++      if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
++         ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE))
++              return EBT_NOMATCH;
++      if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
++         ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE))
++              return EBT_NOMATCH;
 +
-+      if (nf_bridge->mask & BRNF_PKT_TYPE) {
-+              skb->pkt_type = PACKET_OTHERHOST;
-+              nf_bridge->mask ^= BRNF_PKT_TYPE;
++      if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP))
++      {
++              uint32_t arp_len = sizeof(struct arphdr) +
++                 (2 * (((*skb).nh.arph)->ar_hln)) +
++                 (2 * (((*skb).nh.arph)->ar_pln));
++              uint32_t dst;
++              uint32_t src;
++
++              // Make sure the packet is long enough.
++              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
++                      return EBT_NOMATCH;
++              // IPv4 addresses are always 4 bytes.
++              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
++                      return EBT_NOMATCH;
++
++              if (info->bitmask & EBT_ARP_SRC_IP) {
++                      memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) +
++                         ((*skb).nh.arph)->ar_hln, sizeof(uint32_t));
++                      if (FWINV(info->saddr != (src & info->smsk),
++                         EBT_ARP_SRC_IP))
++                              return EBT_NOMATCH;
++              }
++
++              if (info->bitmask & EBT_ARP_DST_IP) {
++                      memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) +
++                         (2*(((*skb).nh.arph)->ar_hln)) +
++                         (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
++                      if (FWINV(info->daddr != (dst & info->dmsk),
++                         EBT_ARP_DST_IP))
++                              return EBT_NOMATCH;
++              }
 +      }
-+      nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 +
-+      skb->dst = (struct dst_entry *)&__fake_rtable;
-+      dst_hold(skb->dst);
++      if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC))
++      {
++              uint32_t arp_len = sizeof(struct arphdr) +
++                 (2 * (((*skb).nh.arph)->ar_hln)) +
++                 (2 * (((*skb).nh.arph)->ar_pln));
++              unsigned char dst[ETH_ALEN];
++              unsigned char src[ETH_ALEN];
 +
-+      skb->dev = nf_bridge->physindev;
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_push(skb, VLAN_HLEN);
-+              skb->nh.raw -= VLAN_HLEN;
++              // Make sure the packet is long enough.
++              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
++                      return EBT_NOMATCH;
++              // MAC addresses are 6 bytes.
++              if (((*skb).nh.arph)->ar_hln != ETH_ALEN)
++                      return EBT_NOMATCH;
++              if (info->bitmask & EBT_ARP_SRC_MAC) {
++                      uint8_t verdict, i;
++
++                      memcpy(&src, ((*skb).nh.raw) +
++                                      sizeof(struct arphdr),
++                                      ETH_ALEN);
++                      verdict = 0;
++                      for (i = 0; i < 6; i++)
++                              verdict |= (src[i] ^ info->smaddr[i]) &
++                                     info->smmsk[i];  
++                      if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
++                              return EBT_NOMATCH;
++              }
++
++              if (info->bitmask & EBT_ARP_DST_MAC) { 
++                      uint8_t verdict, i;
++
++                      memcpy(&dst, ((*skb).nh.raw) +
++                                      sizeof(struct arphdr) +
++                                      (((*skb).nh.arph)->ar_hln) +
++                                      (((*skb).nh.arph)->ar_pln),
++                                      ETH_ALEN);
++                      verdict = 0;
++                      for (i = 0; i < 6; i++)
++                              verdict |= (dst[i] ^ info->dmaddr[i]) &
++                                      info->dmmsk[i];
++                      if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
++                              return EBT_NOMATCH;
++              }
 +      }
-+      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
-+                     br_handle_frame_finish, 1);
 +
++      return EBT_MATCH;
++}
++
++static int ebt_arp_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_arp_info *info = (struct ebt_arp_info *)data;
++
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
++              return -EINVAL;
++      if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
++         e->ethproto != __constant_htons(ETH_P_RARP)) ||
++         e->invflags & EBT_IPROTO)
++              return -EINVAL;
++      if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
++              return -EINVAL;
 +      return 0;
 +}
 +
-+static void __br_dnat_complain(void)
++static struct ebt_match filter_arp =
 +{
-+      static unsigned long last_complaint;
++      {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL,
++      THIS_MODULE
++};
 +
-+      if (jiffies - last_complaint >= 5 * HZ) {
-+              printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
-+                      "forwarding to be enabled\n");
-+              last_complaint = jiffies;
-+      }
++static int __init init(void)
++{
++      return ebt_register_match(&filter_arp);
 +}
 +
++static void __exit fini(void)
++{
++      ebt_unregister_match(&filter_arp);
++}
 +
-+/* This requires some explaining. If DNAT has taken place,
-+ * we will need to fix up the destination Ethernet address,
-+ * and this is a tricky process.
-+ *
-+ * There are two cases to consider:
-+ * 1. The packet was DNAT'ed to a device in the same bridge
-+ *    port group as it was received on. We can still bridge
-+ *    the packet.
-+ * 2. The packet was DNAT'ed to a different device, either
-+ *    a non-bridged device or another bridge port group.
-+ *    The packet will need to be routed.
-+ *
-+ * The correct way of distinguishing between these two cases is to
-+ * call ip_route_input() and to look at skb->dst->dev, which is
-+ * changed to the destination device if ip_route_input() succeeds.
-+ *
-+ * Let us first consider the case that ip_route_input() succeeds:
-+ *
-+ * If skb->dst->dev equals the logical bridge device the packet
-+ * came in on, we can consider this bridging. We then call
-+ * skb->dst->output() which will make the packet enter br_nf_local_out()
-+ * not much later. In that function it is assured that the iptables
-+ * FORWARD chain is traversed for the packet.
-+ *
-+ * Otherwise, the packet is considered to be routed and we just
-+ * change the destination MAC address so that the packet will
-+ * later be passed up to the IP stack to be routed.
-+ *
-+ * Let us now consider the case that ip_route_input() fails:
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_ip.c        2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,121 @@
++/*
++ *  ebt_ip
 + *
-+ * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
-+ * will fail, while __ip_route_output_key() will return success. The source
-+ * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
-+ * thinks we're handling a locally generated packet and won't care
-+ * if IP forwarding is allowed. We send a warning message to the users's
-+ * log telling her to put IP forwarding on.
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
 + *
-+ * ip_route_input() will also fail if there is no route available.
-+ * In that case we just drop the packet.
++ *  April, 2002
 + *
-+ * --Lennert, 20020411
-+ * --Bart, 20020416 (updated)
-+ * --Bart, 20021007 (updated)
-+ */
++ *  Changes:
++ *    added ip-sport and ip-dport
++ *    Innominate Security Technologies AG <mhopf@innominate.com>
++ *    September, 2002
++ */
 +
-+static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
-+{
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD);
-+#endif
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_ip.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/module.h>
 +
-+      if (skb->pkt_type == PACKET_OTHERHOST) {
-+              skb->pkt_type = PACKET_HOST;
-+              skb->nf_bridge->mask |= BRNF_PKT_TYPE;
-+      }
-+      skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
++struct tcpudphdr {
++      uint16_t src;
++      uint16_t dst;
++};
 +
-+      skb->dev = bridge_parent(skb->dev);
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_pull(skb, VLAN_HLEN);
-+              skb->nh.raw += VLAN_HLEN;
-+      }
-+      skb->dst->output(skb);
-+      return 0;
-+}
++union h_u {
++      unsigned char *raw;
++      struct tcpudphdr *tuh;
++};
 +
-+static int br_nf_pre_routing_finish(struct sk_buff *skb)
++static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, const void *data,
++   unsigned int datalen)
 +{
-+      struct net_device *dev = skb->dev;
-+      struct iphdr *iph = skb->nh.iph;
-+      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
-+
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
-+#endif
-+
-+      if (nf_bridge->mask & BRNF_PKT_TYPE) {
-+              skb->pkt_type = PACKET_OTHERHOST;
-+              nf_bridge->mask ^= BRNF_PKT_TYPE;
-+      }
-+      nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
-+
-+      if (dnat_took_place(skb)) {
-+              if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
-+                  dev)) {
-+                      struct rtable *rt;
++      struct ebt_ip_info *info = (struct ebt_ip_info *)data;
 +
-+                      if (!ip_route_output(&rt, iph->daddr, 0, iph->tos, 0)) {
-+                              /* Bridged-and-DNAT'ed traffic doesn't
-+                               * require ip_forwarding.
-+                               */
-+                              if (((struct dst_entry *)rt)->dev == dev) {
-+                                      skb->dst = (struct dst_entry *)rt;
-+                                      goto bridged_dnat;
-+                              }
-+                              __br_dnat_complain();
-+                              dst_release((struct dst_entry *)rt);
++      if (info->bitmask & EBT_IP_TOS &&
++         FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS))
++              return EBT_NOMATCH;
++      if (info->bitmask & EBT_IP_PROTO) {
++              if (FWINV(info->protocol != ((*skb).nh.iph)->protocol,
++                        EBT_IP_PROTO))
++                      return EBT_NOMATCH;
++              if ( info->protocol == IPPROTO_TCP ||
++                   info->protocol == IPPROTO_UDP )
++              {
++                      union h_u h;
++                      h.raw = skb->data + skb->nh.iph->ihl*4;
++                      if (info->bitmask & EBT_IP_DPORT) {
++                              uint16_t port = ntohs(h.tuh->dst);
++                              if (FWINV(port < info->dport[0] ||
++                                        port > info->dport[1],
++                                        EBT_IP_DPORT))
++                              return EBT_NOMATCH;
 +                      }
-+                      kfree_skb(skb);
-+                      return 0;
-+              } else {
-+                      if (skb->dst->dev == dev) {
-+bridged_dnat:
-+                              /* Tell br_nf_local_out this is a
-+                               * bridged frame
-+                               */
-+                              nf_bridge->mask |= BRNF_BRIDGED_DNAT;
-+                              skb->dev = nf_bridge->physindev;
-+                              if (skb->protocol ==
-+                                  __constant_htons(ETH_P_8021Q)) {
-+                                      skb_push(skb, VLAN_HLEN);
-+                                      skb->nh.raw -= VLAN_HLEN;
-+                              }
-+                              NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
-+                                             skb, skb->dev, NULL,
-+                                             br_nf_pre_routing_finish_bridge,
-+                                             1);
-+                              return 0;
++                      if (info->bitmask & EBT_IP_SPORT) {
++                              uint16_t port = ntohs(h.tuh->src);
++                              if (FWINV(port < info->sport[0] ||
++                                        port > info->sport[1],
++                                        EBT_IP_SPORT))
++                              return EBT_NOMATCH;
 +                      }
-+                      memcpy(skb->mac.ethernet->h_dest, dev->dev_addr,
-+                             ETH_ALEN);
-+                      skb->pkt_type = PACKET_HOST;
 +              }
-+      } else {
-+              skb->dst = (struct dst_entry *)&__fake_rtable;
-+              dst_hold(skb->dst);
 +      }
++      if (info->bitmask & EBT_IP_SOURCE &&
++         FWINV((((*skb).nh.iph)->saddr & info->smsk) !=
++         info->saddr, EBT_IP_SOURCE))
++              return EBT_NOMATCH;
++      if ((info->bitmask & EBT_IP_DEST) &&
++         FWINV((((*skb).nh.iph)->daddr & info->dmsk) !=
++         info->daddr, EBT_IP_DEST))
++              return EBT_NOMATCH;
++      return EBT_MATCH;
++}
 +
-+      skb->dev = nf_bridge->physindev;
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_push(skb, VLAN_HLEN);
-+              skb->nh.raw -= VLAN_HLEN;
-+      }
-+      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
-+                     br_handle_frame_finish, 1);
++static int ebt_ip_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_ip_info *info = (struct ebt_ip_info *)data;
 +
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
++              return -EINVAL;
++      if (e->ethproto != __constant_htons(ETH_P_IP) ||
++         e->invflags & EBT_IPROTO)
++              return -EINVAL;
++      if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
++              return -EINVAL;
++      if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
++              if (!info->bitmask & EBT_IPROTO)
++                      return -EINVAL;
++              if (info->protocol != IPPROTO_TCP &&
++                  info->protocol != IPPROTO_UDP)
++                       return -EINVAL;
++      }
++      if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
++              return -EINVAL;
++      if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
++              return -EINVAL;
 +      return 0;
 +}
 +
-+/* Some common code for IPv4/IPv6 */
-+static void setup_pre_routing(struct sk_buff *skb)
++static struct ebt_match filter_ip =
 +{
-+      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
-+
-+      if (skb->pkt_type == PACKET_OTHERHOST) {
-+              skb->pkt_type = PACKET_HOST;
-+              nf_bridge->mask |= BRNF_PKT_TYPE;
-+      }
++      {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL,
++      THIS_MODULE
++};
 +
-+      nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
-+      nf_bridge->physindev = skb->dev;
-+      skb->dev = bridge_parent(skb->dev);
++static int __init init(void)
++{
++      return ebt_register_match(&filter_ip);
 +}
 +
-+/* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
-+static int check_hbh_len(struct sk_buff *skb)
++static void __exit fini(void)
 +{
-+      unsigned char *raw = (u8*)(skb->nh.ipv6h+1);
-+      u32 pkt_len;
-+      int off = raw - skb->nh.raw;
-+      int len = (raw[1]+1)<<3;
-+
-+      if ((raw + len) - skb->data > skb_headlen(skb))
-+              goto bad;
++      ebt_unregister_match(&filter_ip);
++}
 +
-+      off += 2;
-+      len -= 2;
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_vlan.c      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,259 @@
++/*
++ * Description: EBTables 802.1Q match extension kernelspace module.
++ * Authors: Nick Fedchik <nick@fedchik.org.ua>
++ *          Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *    
++ * 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
++ */
 +
-+      while (len > 0) {
-+              int optlen = raw[off+1]+2;
++#include <linux/if_ether.h>
++#include <linux/if_vlan.h>
++#include <linux/module.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_vlan.h>
 +
-+              switch (skb->nh.raw[off]) {
-+              case IPV6_TLV_PAD0:
-+                      optlen = 1;
-+                      break;
++static unsigned char debug;
++#define MODULE_VERSION "0.6"
 +
-+              case IPV6_TLV_PADN:
-+                      break;
++MODULE_PARM(debug, "0-1b");
++MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
++MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
++MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
++                 MODULE_VERSION);
++MODULE_LICENSE("GPL");
 +
-+              case IPV6_TLV_JUMBO:
-+                      if (skb->nh.raw[off+1] != 4 || (off&3) != 2)
-+                              goto bad;
 +
-+                      pkt_len = ntohl(*(u32*)(skb->nh.raw+off+2));
++#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
++#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
++#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
++#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
++#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1;
 +
-+                      if (pkt_len > skb->len - sizeof(struct ipv6hdr))
-+                              goto bad;
-+                      if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
-+                              if (__pskb_trim(skb,
-+                                  pkt_len + sizeof(struct ipv6hdr)))
-+                                      goto bad;
-+                              if (skb->ip_summed == CHECKSUM_HW)
-+                                      skb->ip_summed = CHECKSUM_NONE;
-+                      }
-+                      break;
-+              default:
-+                      if (optlen > len)
-+                              goto bad;
-+                      break;
-+              }
-+              off += optlen;
-+              len -= optlen;
-+      }
-+      if (len == 0)
-+              return 0;
-+bad:
-+      return -1;
++/*
++ * Function description: ebt_filter_vlan() is main engine for 
++ * checking passed 802.1Q frame according to 
++ * the passed extension parameters (in the *data buffer)
++ * ebt_filter_vlan() is called after successfull check the rule params
++ * by ebt_check_vlan() function.
++ * Parameters:
++ * const struct sk_buff *skb - pointer to passed ethernet frame buffer
++ * const void *data - pointer to passed extension parameters
++ * unsigned int datalen - length of passed *data buffer
++ * const struct net_device *in  -
++ * const struct net_device *out -
++ * const struct ebt_counter *c -
++ * Returned values:
++ * 0 - ok (all rule params matched)
++ * 1 - miss (rule params not acceptable to the parsed frame)
++ */
++static int
++ebt_filter_vlan(const struct sk_buff *skb,
++              const struct net_device *in,
++              const struct net_device *out,
++              const void *data, unsigned int datalen)
++{
++      struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;     /* userspace data */
++      struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw;        /* Passed tagged frame */
++
++      unsigned short TCI;     /* Whole TCI, given from parsed frame */
++      unsigned short id;      /* VLAN ID, given from frame TCI */
++      unsigned char prio;     /* user_priority, given from frame TCI */
++      unsigned short encap;   /* VLAN encapsulated Type/Length field, given from orig frame */
++
++      /*
++       * Tag Control Information (TCI) consists of the following elements:
++       * - User_priority. The user_priority field is three bits in length, 
++       * interpreted as a binary number. 
++       * - Canonical Format Indicator (CFI). The Canonical Format Indicator 
++       * (CFI) is a single bit flag value. Currently ignored.
++       * - VLAN Identifier (VID). The VID is encoded as 
++       * an unsigned binary number. 
++       */
++      TCI = ntohs(frame->h_vlan_TCI);
++      id = TCI & VLAN_VID_MASK;
++      prio = (TCI >> 13) & 0x7;
++      encap = frame->h_vlan_encapsulated_proto;
 +
++      /*
++       * Checking VLAN Identifier (VID)
++       */
++      if (GET_BITMASK(EBT_VLAN_ID)) { /* Is VLAN ID parsed? */
++              EXIT_ON_MISMATCH(id, EBT_VLAN_ID);
++      }
++      /*
++       * Checking user_priority
++       */
++      if (GET_BITMASK(EBT_VLAN_PRIO)) {       /* Is VLAN user_priority parsed? */
++              EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO);
++      }
++      /*
++       * Checking Encapsulated Proto (Length/Type) field
++       */
++      if (GET_BITMASK(EBT_VLAN_ENCAP)) {      /* Is VLAN Encap parsed? */
++              EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
++      }
++      /*
++       * All possible extension parameters was parsed.
++       * If rule never returned by missmatch, then all ok.
++       */
++      return 0;
 +}
 +
-+/* Replicate the checks that IPv6 does on packet reception and pass the packet
-+ * to ip6tables, which doesn't support NAT, so things are fairly simple. */
-+static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
-+   struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, int (*okfn)(struct sk_buff *))
++/*
++ * Function description: ebt_vlan_check() is called when userspace 
++ * delivers the table entry to the kernel, 
++ * and to check that userspace doesn't give a bad table.
++ * Parameters:
++ * const char *tablename - table name string
++ * unsigned int hooknr - hook number
++ * const struct ebt_entry *e - ebtables entry basic set
++ * const void *data - pointer to passed extension parameters
++ * unsigned int datalen - length of passed *data buffer
++ * Returned values:
++ * 0 - ok (all delivered rule params are correct)
++ * 1 - miss (rule params is out of range, invalid, incompatible, etc.)
++ */
++static int
++ebt_check_vlan(const char *tablename,
++             unsigned int hooknr,
++             const struct ebt_entry *e, void *data, unsigned int datalen)
 +{
-+      struct ipv6hdr *hdr;
-+      u32 pkt_len;
-+      struct nf_bridge_info *nf_bridge;
-+
-+      if (skb->len < sizeof(struct ipv6hdr))
-+              goto inhdr_error;
++      struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
 +
-+      if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
-+              goto inhdr_error;
++      /*
++       * Parameters buffer overflow check 
++       */
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
++              DEBUG_MSG
++                  ("passed size %d is not eq to ebt_vlan_info (%d)\n",
++                   datalen, sizeof(struct ebt_vlan_info));
++              return -EINVAL;
++      }
 +
-+      hdr = skb->nh.ipv6h;
++      /*
++       * Is it 802.1Q frame checked?
++       */
++      if (e->ethproto != __constant_htons(ETH_P_8021Q)) {
++              DEBUG_MSG
++                  ("passed entry proto %2.4X is not 802.1Q (8100)\n",
++                   (unsigned short) ntohs(e->ethproto));
++              return -EINVAL;
++      }
 +
-+      if (hdr->version != 6)
-+              goto inhdr_error;
++      /*
++       * Check for bitmask range 
++       * True if even one bit is out of mask
++       */
++      if (info->bitmask & ~EBT_VLAN_MASK) {
++              DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
++                        info->bitmask, EBT_VLAN_MASK);
++              return -EINVAL;
++      }
 +
-+      pkt_len = ntohs(hdr->payload_len);
++      /*
++       * Check for inversion flags range 
++       */
++      if (info->invflags & ~EBT_VLAN_MASK) {
++              DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
++                        info->invflags, EBT_VLAN_MASK);
++              return -EINVAL;
++      }
 +
-+      if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
-+              if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
-+                      goto inhdr_error;
-+              if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
-+                      if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
-+                              goto inhdr_error;
-+                      if (skb->ip_summed == CHECKSUM_HW)
-+                              skb->ip_summed = CHECKSUM_NONE;
++      /*
++       * Reserved VLAN ID (VID) values
++       * -----------------------------
++       * 0 - The null VLAN ID. 
++       * 1 - The default Port VID (PVID)
++       * 0x0FFF - Reserved for implementation use. 
++       * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096.
++       */
++      if (GET_BITMASK(EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */
++              if (!!info->id) {       /* if id!=0 => check vid range */
++                      if (info->id > VLAN_GROUP_ARRAY_LEN) {
++                              DEBUG_MSG
++                                  ("id %d is out of range (1-4096)\n",
++                                   info->id);
++                              return -EINVAL;
++                      }
++                      /*
++                       * Note: This is valid VLAN-tagged frame point.
++                       * Any value of user_priority are acceptable, 
++                       * but should be ignored according to 802.1Q Std.
++                       * So we just drop the prio flag. 
++                       */
++                      info->bitmask &= ~EBT_VLAN_PRIO;
 +              }
++              /*
++               * Else, id=0 (null VLAN ID)  => user_priority range (any?)
++               */
 +      }
-+      if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb))
-+              goto inhdr_error;
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_IP6_PRE_ROUTING);
-+#endif
-+      if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
-+              return NF_DROP;
-+      setup_pre_routing(skb);
++      if (GET_BITMASK(EBT_VLAN_PRIO)) {
++              if ((unsigned char) info->prio > 7) {
++                      DEBUG_MSG
++                          ("prio %d is out of range (0-7)\n",
++                           info->prio);
++                      return -EINVAL;
++              }
++      }
++      /*
++       * Check for encapsulated proto range - it is possible to be 
++       * any value for u_short range.
++       * if_ether.h:  ETH_ZLEN        60   -  Min. octets in frame sans FCS
++       */
++      if (GET_BITMASK(EBT_VLAN_ENCAP)) {
++              if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
++                      DEBUG_MSG
++                          ("encap frame length %d is less than minimal\n",
++                           ntohs(info->encap));
++                      return -EINVAL;
++              }
++      }
 +
-+      NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
-+              br_nf_pre_routing_finish_ipv6);
++      return 0;
++}
 +
-+      return NF_STOLEN;
++static struct ebt_match filter_vlan = {
++      {NULL, NULL},
++      EBT_VLAN_MATCH,
++      ebt_filter_vlan,
++      ebt_check_vlan,
++      NULL,
++      THIS_MODULE
++};
 +
-+inhdr_error:
-+      return NF_DROP;
++/*
++ * Module initialization function.
++ */
++static int __init init(void)
++{
++      DEBUG_MSG("ebtables 802.1Q extension module v"
++                MODULE_VERSION "\n");
++      DEBUG_MSG("module debug=%d\n", !!debug);
++      return ebt_register_match(&filter_vlan);
 +}
 +
-+/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
-+ * Replicate the checks that IPv4 does on packet reception.
-+ * Set skb->dev to the bridge device (i.e. parent of the
-+ * receiving device) to make netfilter happy, the REDIRECT
-+ * target in particular.  Save the original destination IP
-+ * address to be able to detect DNAT afterwards.
++/*
++ * Module "finalization" function
 + */
-+static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
++static void __exit fini(void)
 +{
-+      struct iphdr *iph;
-+      __u32 len;
-+      struct sk_buff *skb = *pskb;
-+      struct nf_bridge_info *nf_bridge;
-+      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)
-+                                 ((*pskb)->mac.ethernet);
-+ 
-+      if (skb->protocol == __constant_htons(ETH_P_IPV6) || IS_VLAN_IPV6) {
-+#ifdef CONFIG_SYSCTL
-+              if (!brnf_call_ip6tables)
-+                      return NF_ACCEPT;
-+#endif
-+              if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
-+                      goto out;
-+
-+              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+                      skb_pull(skb, VLAN_HLEN);
-+                      (skb)->nh.raw += VLAN_HLEN;
-+              }
-+              return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
-+      }
-+
-+#ifdef CONFIG_SYSCTL
-+      if (!brnf_call_iptables)
-+              return NF_ACCEPT;
-+#endif
-+
-+      if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
-+              return NF_ACCEPT;
-+      if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
-+              goto out;
-+ 
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_pull(skb, VLAN_HLEN);
-+              (skb)->nh.raw += VLAN_HLEN;
-+      }
-+
-+      if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-+              goto inhdr_error;
++      ebt_unregister_match(&filter_vlan);
++}
 +
-+      iph = skb->nh.iph;
-+      if (iph->ihl < 5 || iph->version != 4)
-+              goto inhdr_error;
++module_init(init);
++module_exit(fini);
 +
-+      if (!pskb_may_pull(skb, 4*iph->ihl))
-+              goto inhdr_error;
++EXPORT_NO_SYMBOLS;
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_log.c       2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,153 @@
++/*
++ *  ebt_log
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  April, 2002
++ *
++ */
 +
-+      iph = skb->nh.iph;
-+      if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0)
-+              goto inhdr_error;
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_log.h>
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/if_arp.h>
++#include <linux/spinlock.h>
 +
-+      len = ntohs(iph->tot_len);
-+      if (skb->len < len || len < 4*iph->ihl)
-+              goto inhdr_error;
++static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED;
 +
-+      if (skb->len > len) {
-+              __pskb_trim(skb, len);
-+              if (skb->ip_summed == CHECKSUM_HW)
-+                      skb->ip_summed = CHECKSUM_NONE;
-+      }
++static int ebt_log_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_log_info *info = (struct ebt_log_info *)data;
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING);
-+#endif
-+      if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
-+              return NF_DROP;
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
++              return -EINVAL;
++      if (info->bitmask & ~EBT_LOG_MASK)
++              return -EINVAL;
++      if (info->loglevel >= 8)
++              return -EINVAL;
++      info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
++      return 0;
++}
 +
-+      setup_pre_routing(skb);
-+      store_orig_dstaddr(skb);
++struct tcpudphdr
++{
++      uint16_t src;
++      uint16_t dst;
++};
 +
-+      NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
-+              br_nf_pre_routing_finish);
++struct arppayload
++{
++      unsigned char mac_src[ETH_ALEN];
++      unsigned char ip_src[4];
++      unsigned char mac_dst[ETH_ALEN];
++      unsigned char ip_dst[4];
++};
 +
-+      return NF_STOLEN;
++static void print_MAC(unsigned char *p)
++{
++      int i;
 +
-+inhdr_error:
-+//    IP_INC_STATS_BH(IpInHdrErrors);
-+out:
-+      return NF_DROP;
++      for (i = 0; i < ETH_ALEN; i++, p++)
++              printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
 +}
 +
-+
-+/* PF_BRIDGE/LOCAL_IN ************************************************/
-+/* The packet is locally destined, which requires a real
-+ * dst_entry, so detach the fake one.  On the way up, the
-+ * packet would pass through PRE_ROUTING again (which already
-+ * took place when the packet entered the bridge), but we
-+ * register an IPv4 PRE_ROUTING 'sabotage' hook that will
-+ * prevent this from happening.
-+ */
-+static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
++#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
++static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
 +   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
++   const void *data, unsigned int datalen)
 +{
-+      struct sk_buff *skb = *pskb;
++      struct ebt_log_info *info = (struct ebt_log_info *)data;
++      char level_string[4] = "< >";
++      level_string[1] = '0' + info->loglevel;
 +
-+      if (skb->dst == (struct dst_entry *)&__fake_rtable) {
-+              dst_release(skb->dst);
-+              skb->dst = NULL;
-+      }
++      spin_lock_bh(&ebt_log_lock);
++      printk(level_string);
++      printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
++         out ? out->name : "");
 +
-+      return NF_ACCEPT;
-+}
++      printk("MAC source = ");
++      print_MAC((skb->mac.ethernet)->h_source);
++      printk("MAC dest = ");
++      print_MAC((skb->mac.ethernet)->h_dest);
 +
-+/* PF_BRIDGE/FORWARD *************************************************/
-+static int br_nf_forward_finish(struct sk_buff *skb)
-+{
-+      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
-+      struct net_device *in;
-+/*    struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);*/
++      printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_BR_FORWARD);
-+#endif
++      if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
++         htons(ETH_P_IP)){
++              struct iphdr *iph = skb->nh.iph;
++              printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
++                 NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++              printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol);
++              if (iph->protocol == IPPROTO_TCP ||
++                  iph->protocol == IPPROTO_UDP) {
++                      struct tcpudphdr *ports = (struct tcpudphdr *)(skb->data + iph->ihl*4);
 +
-+/*    if (skb->protocol != __constant_htons(ETH_P_ARP) && !IS_VLAN_ARP) {*/
-+              in = nf_bridge->physindev;
-+              if (nf_bridge->mask & BRNF_PKT_TYPE) {
-+                      skb->pkt_type = PACKET_OTHERHOST;
-+                      nf_bridge->mask ^= BRNF_PKT_TYPE;
++                      if (skb->data + iph->ihl*4 > skb->tail) {
++                              printk(" INCOMPLETE TCP/UDP header");
++                              goto out;
++                      }
++                      printk(" SPT=%u DPT=%u", ntohs(ports->src),
++                         ntohs(ports->dst));
 +              }
-+/*    } else {
-+              in = *((struct net_device **)(skb->cb));
-+      }*/
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_push(skb, VLAN_HLEN);
-+              skb->nh.raw -= VLAN_HLEN;
++              goto out;
 +      }
-+      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
-+                      skb->dev, br_forward_finish, 1);
-+      return 0;
-+}
-+
-+/* This is the 'purely bridged' case.  For IP, we pass the packet to
-+ * netfilter with indev and outdev set to the bridge device,
-+ * but we are still able to filter on the 'real' indev/outdev
-+ * because of the ipt_physdev.c module. For ARP, indev and outdev are the
-+ * bridge ports.
-+ */
-+static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
-+{
-+      struct sk_buff *skb = *pskb;
-+      struct nf_bridge_info *nf_bridge;
-+      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
-+      int pf;
 +
-+      if (!skb->nf_bridge)
-+              return NF_ACCEPT;
++      if ((info->bitmask & EBT_LOG_ARP) &&
++          ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
++          (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
++              struct arphdr * arph = skb->nh.arph;
++              printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
++                 ntohs(arph->ar_hrd), ntohs(arph->ar_pro),
++                 ntohs(arph->ar_op));
++              /* If it's for Ethernet and the lengths are OK,
++               * then log the ARP payload */
++              if (arph->ar_hrd == __constant_htons(1) &&
++                  arph->ar_hln == ETH_ALEN &&
++                  arph->ar_pln == sizeof(uint32_t)) {
++                      struct arppayload *arpp = (struct arppayload *)(skb->data + sizeof(*arph));
 +
-+      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
-+              pf = PF_INET;
-+      else
-+              pf = PF_INET6;
++                      if (skb->data + sizeof(*arph) > skb->tail) {
++                              printk(" INCOMPLETE ARP header");
++                              goto out;
++                      }
 +
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_pull(*pskb, VLAN_HLEN);
-+              (*pskb)->nh.raw += VLAN_HLEN;
-+      }
++                      printk(" ARP MAC SRC=");
++                      print_MAC(arpp->mac_src);
++                      printk(" ARP IP SRC=%u.%u.%u.%u",
++                             myNIPQUAD(arpp->ip_src));
++                      printk(" ARP MAC DST=");
++                      print_MAC(arpp->mac_dst);
++                      printk(" ARP IP DST=%u.%u.%u.%u",
++                             myNIPQUAD(arpp->ip_dst));
++              }
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_BR_FORWARD);
-+#endif
-+      nf_bridge = skb->nf_bridge;
-+      if (skb->pkt_type == PACKET_OTHERHOST) {
-+              skb->pkt_type = PACKET_HOST;
-+              nf_bridge->mask |= BRNF_PKT_TYPE;
 +      }
-+
-+      /* The physdev module checks on this */
-+      nf_bridge->mask |= BRNF_BRIDGED;
-+      nf_bridge->physoutdev = skb->dev;
-+
-+      NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in),
-+              bridge_parent(out), br_nf_forward_finish);
-+
-+      return NF_STOLEN;
++out:
++      printk("\n");
++      spin_unlock_bh(&ebt_log_lock);
 +}
 +
-+/*
-+static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
++static struct ebt_watcher log =
 +{
-+      struct sk_buff *skb = *pskb;
-+      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
-+      struct net_device **d = (struct net_device **)(skb->cb);
-+
-+      if (!brnf_call_arptables)
-+              return NF_ACCEPT;
-+
-+      if (skb->protocol != __constant_htons(ETH_P_ARP)) {
-+              if (!IS_VLAN_ARP)
-+                      return NF_ACCEPT;
-+              skb_pull(*pskb, VLAN_HLEN);
-+              (*pskb)->nh.raw += VLAN_HLEN;
-+      }
-+
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug ^= (1 << NF_BR_FORWARD);
-+#endif
-+
-+      if (skb->nh.arph->ar_pln != 4) {
-+              if (IS_VLAN_ARP) {
-+                      skb_push(*pskb, VLAN_HLEN);
-+                      (*pskb)->nh.raw -= VLAN_HLEN;
-+              }
-+              return NF_ACCEPT;
-+      }
-+      *d = (struct net_device *)in;
-+      NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in,
-+              (struct net_device *)out, br_nf_forward_finish);
++      {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL,
++      THIS_MODULE
++};
 +
-+      return NF_STOLEN;
++static int __init init(void)
++{
++      return ebt_register_watcher(&log);
 +}
-+*/
 +
-+/* PF_BRIDGE/LOCAL_OUT ***********************************************/
-+static int br_nf_local_out_finish(struct sk_buff *skb)
++static void __exit fini(void)
 +{
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT);
-+#endif
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_push(skb, VLAN_HLEN);
-+              skb->nh.raw -= VLAN_HLEN;
-+      }
-+
-+      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
-+                      br_forward_finish, NF_BR_PRI_FIRST + 1);
-+
-+      return 0;
++      ebt_unregister_watcher(&log);
 +}
 +
-+
-+/* This function sees both locally originated IP packets and forwarded
-+ * IP packets (in both cases the destination device is a bridge
-+ * device). It also sees bridged-and-DNAT'ed packets.
-+ * To be able to filter on the physical bridge devices (with the ipt_physdev.c
-+ * module), we steal packets destined to a bridge device away from the
-+ * PF_INET/FORWARD and PF_INET/OUTPUT hook functions, and give them back later,
-+ * when we have determined the real output device. This is done in here.
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_ulog.c      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,281 @@
++/*
++ * netfilter module for userspace bridged Ethernet frames logging daemons
++ *
++ *    Authors:
++ *    Bart De Schuymer <bdschuym@pandora.be>
++ *
++ *  November, 2004
++ *
++ * Based on ipt_ULOG.c, which is
++ * (C) 2000-2002 by Harald Welte <laforge@netfilter.org>
++ *
++ * This module accepts two parameters: 
++ * 
++ * nlbufsiz:
++ *   The parameter specifies how big the buffer for each netlink multicast
++ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
++ * get accumulated in the kernel until they are sent to userspace. It is
++ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
++ * because atomically allocating 128kB inside the network rx softirq is not
++ * reliable. Please also keep in mind that this buffer size is allocated for
++ * each nlgroup you are using, so the total kernel memory usage increases
++ * by that factor.
++ *
++ * flushtimeout:
++ *   Specify, after how many hundredths of a second the queue should be
++ *   flushed even if it is not full yet.
 + *
-+ * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
-+ * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
-+ * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
-+ * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
-+ * will be executed.
-+ * Otherwise, if nf_bridge->physindev is NULL, the bridge-nf code never touched
-+ * this packet before, and so the packet was locally originated. We fake
-+ * the PF_INET/LOCAL_OUT hook.
-+ * Finally, if nf_bridge->physindev isn't NULL, then the packet was IP routed,
-+ * so we fake the PF_INET/FORWARD hook. ipv4_sabotage_out() makes sure
-+ * even routed packets that didn't arrive on a bridge interface have their
-+ * nf_bridge->physindev set.
 + */
 +
-+static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
-+{
-+      struct net_device *realindev, *realoutdev;
-+      struct sk_buff *skb = *pskb;
-+      struct nf_bridge_info *nf_bridge;
-+      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
-+      int pf;
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/spinlock.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/netlink.h>
++#include <linux/netdevice.h>
++#include <linux/module.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_ulog.h>
++#include <net/sock.h>
++#include "../br_private.h"
 +
-+      if (!skb->nf_bridge)
-+              return NF_ACCEPT;
++#define PRINTR(format, args...)       do { if (net_ratelimit()) \
++                                              printk(format , ## args); } while (0)
 +
-+      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
-+              pf = PF_INET;
-+      else
-+              pf = PF_INET6;
-+ 
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      /* Sometimes we get packets with NULL ->dst here (for example,
-+       * running a dhcp client daemon triggers this). This should now
-+       * be fixed, but let's keep the check around. */
-+      if (skb->dst == NULL) {
-+              printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
-+              return NF_ACCEPT;
-+      }
-+#endif
++static unsigned int nlbufsiz = 4096;
++MODULE_PARM(nlbufsiz, "i");
++MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
++                           "(defaults to 4096)");
 +
-+      nf_bridge = skb->nf_bridge;
-+      nf_bridge->physoutdev = skb->dev;
-+      realindev = nf_bridge->physindev;
++static unsigned int flushtimeout = 10;
++MODULE_PARM(flushtimeout, "i");
++MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second) "
++                               "(defaults to 10)");
 +
-+      /* Bridged, take PF_BRIDGE/FORWARD.
-+       * (see big note in front of br_nf_pre_routing_finish)
-+       */
-+      if (nf_bridge->mask & BRNF_BRIDGED_DNAT) {
-+              if (nf_bridge->mask & BRNF_PKT_TYPE) {
-+                      skb->pkt_type = PACKET_OTHERHOST;
-+                      nf_bridge->mask ^= BRNF_PKT_TYPE;
-+              }
-+              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+                      skb_push(skb, VLAN_HLEN);
-+                      skb->nh.raw -= VLAN_HLEN;
-+              }
++typedef struct {
++      unsigned int qlen;              /* number of nlmsgs' in the skb */
++      struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
++      struct sk_buff *skb;            /* the pre-allocated skb */
++      struct timer_list timer;        /* the timer function */
++      spinlock_t lock;                /* the per-queue lock */
++} ebt_ulog_buff_t;
 +
-+              NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
-+                      skb->dev, br_forward_finish);
-+              goto out;
-+      }
-+      realoutdev = bridge_parent(skb->dev);
++static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS];
++static struct sock *ebtlognl;
 +
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+      /* iptables should match -o br0.x */
-+      if (nf_bridge->netoutdev)
-+              realoutdev = nf_bridge->netoutdev;
-+#endif
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_pull(skb, VLAN_HLEN);
-+              (*pskb)->nh.raw += VLAN_HLEN;
-+      }
-+      /* IP forwarded traffic has a physindev, locally
-+       * generated traffic hasn't.
-+       */
-+      if (realindev != NULL) {
-+              if (((nf_bridge->mask & BRNF_DONT_TAKE_PARENT) == 0) &&
-+                  has_bridge_parent(realindev))
-+                      realindev = bridge_parent(realindev);
-+              NF_HOOK_THRESH(pf, NF_IP_FORWARD, skb, realindev,
-+                             realoutdev, okfn,
-+                             NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1);
-+      } else {
-+#ifdef CONFIG_NETFILTER_DEBUG
-+              skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT);
-+#endif
++/* send one ulog_buff_t to userspace */
++static void ulog_send(unsigned int nlgroup)
++{
++      ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup];
 +
-+              NF_HOOK_THRESH(pf, NF_IP_LOCAL_OUT, skb, realindev,
-+                             realoutdev, okfn,
-+                             NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1);
-+      }
++      if (timer_pending(&ub->timer))
++              del_timer(&ub->timer);
 +
-+out:
-+      return NF_STOLEN;
++      /* last nlmsg needs NLMSG_DONE */
++      if (ub->qlen > 1)
++              ub->lastnlh->nlmsg_type = NLMSG_DONE;
++
++      NETLINK_CB(ub->skb).dst_groups = 1 << nlgroup;
++      netlink_broadcast(ebtlognl, ub->skb, 0, 1 << nlgroup, GFP_ATOMIC);
++
++      ub->qlen = 0;
++      ub->skb = NULL;
 +}
 +
++/* timer function to flush queue in flushtimeout time */
++static void ulog_timer(unsigned long data)
++{
++      spin_lock_bh(&ulog_buffers[data].lock);
++      if (ulog_buffers[data].skb)
++              ulog_send(data);
++      spin_unlock_bh(&ulog_buffers[data].lock);
++}
 +
-+/* PF_BRIDGE/POST_ROUTING ********************************************/
-+static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
++static struct sk_buff *ulog_alloc_skb(unsigned int size)
 +{
-+      struct sk_buff *skb = *pskb;
-+      struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
-+      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
-+      struct net_device *realoutdev = bridge_parent(skb->dev);
-+      int pf;
++      struct sk_buff *skb;
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      /* Be very paranoid. This probably won't happen anymore, but let's
-+       * keep the check just to be sure... */
-+      if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
-+              printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
-+                               "bad mac.raw pointer.");
-+              goto print_error;
++      skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
++      if (!skb) {
++              PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
++                     "of size %ub!\n", nlbufsiz);
++              if (size < nlbufsiz) {
++                      /* try to allocate only as much as we need for
++                       * current packet */
++                      skb = alloc_skb(size, GFP_ATOMIC);
++                      if (!skb)
++                              PRINTR(KERN_ERR "ebt_ulog: can't even allocate "
++                                     "buffer of size %ub\n", size);
++              }
 +      }
-+#endif
 +
-+      if (!nf_bridge)
-+              return NF_ACCEPT;
++      return skb;
++}
 +
-+      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
-+              pf = PF_INET;
++static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      ebt_ulog_packet_msg_t *pm;
++      size_t size, copy_len;
++      struct nlmsghdr *nlh;
++      struct ebt_ulog_info *loginfo = (struct ebt_ulog_info *)data;
++      unsigned int group = loginfo->nlgroup;
++      ebt_ulog_buff_t *ub = &ulog_buffers[group];
++      spinlock_t *lock = &ub->lock;
++
++      if ((loginfo->cprange == 0) ||
++          (loginfo->cprange > skb->len + ETH_HLEN))
++              copy_len = skb->len + ETH_HLEN;
 +      else
-+              pf = PF_INET6;
++              copy_len = loginfo->cprange;
 +
-+      /* Sometimes we get packets with NULL ->dst here (for example,
-+       * running a dhcp client daemon triggers this).
-+       */
-+      if (skb->dst == NULL)
-+              return NF_ACCEPT;
++      size = NLMSG_SPACE(sizeof(*pm) + copy_len);
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+      /* Sometimes we get packets with NULL ->dst here (for example,
-+       * running a dhcp client daemon triggers this). This should now
-+       * be fixed, but let's keep the check around.
-+       */
-+      if (skb->dst == NULL) {
-+              printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
-+              goto print_error;
-+      }
++      spin_lock_bh(lock);
 +
-+      skb->nf_debug ^= (1 << NF_IP_POST_ROUTING);
-+#endif
++      if (!ub->skb) {
++              if (!(ub->skb = ulog_alloc_skb(size)))
++                      goto alloc_failure;
++      } else if (size > skb_tailroom(ub->skb)) {
++              ulog_send(group);
 +
-+      /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
-+       * about the value of skb->pkt_type.
-+       */
-+      if (skb->pkt_type == PACKET_OTHERHOST) {
-+              skb->pkt_type = PACKET_HOST;
-+              nf_bridge->mask |= BRNF_PKT_TYPE;
++              if (!(ub->skb = ulog_alloc_skb(size)))
++                      goto alloc_failure;
 +      }
 +
-+      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
-+              skb_pull(skb, VLAN_HLEN);
-+              skb->nh.raw += VLAN_HLEN;
-+      }
++      nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0,
++                      size - NLMSG_ALIGN(sizeof(*nlh)));
++      ub->qlen++;
 +
-+      nf_bridge_save_header(skb);
++      pm = NLMSG_DATA(nlh);
 +
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+      if (nf_bridge->netoutdev)
-+              realoutdev = nf_bridge->netoutdev;
-+#endif
-+      NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL,
-+              realoutdev, br_dev_queue_push_xmit);
++      /* Fill in the ulog data */
++      do_gettimeofday(&pm->stamp);
++      if (ub->qlen == 1)
++              ub->skb->stamp = pm->stamp;
++      pm->data_len = copy_len;
++      pm->mark = skb->nfmark;
++      pm->hook = hooknr;
++      if (loginfo->prefix != NULL)
++              strcpy(pm->prefix, loginfo->prefix);
++      else
++              *(pm->prefix) = '\0';
 +
-+      return NF_STOLEN;
++      if (in) {
++              strcpy(pm->physindev, in->name);
++              strcpy(pm->indev, in->br_port->br->dev.name);
++      } else
++              pm->indev[0] = pm->physindev[0] = '\0';
 +
-+#ifdef CONFIG_NETFILTER_DEBUG
-+print_error:
-+      if (skb->dev != NULL) {
-+              printk("[%s]", skb->dev->name);
-+              if (has_bridge_parent(skb->dev))
-+                      printk("[%s]", bridge_parent(skb->dev)->name);
-+      }
-+      printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
-+                                            skb->data);
-+      return NF_ACCEPT;
-+#endif
-+}
++      if (out) {
++              strcpy(pm->physoutdev, out->name);
++              strcpy(pm->outdev, out->br_port->br->dev.name);
++      } else
++              pm->outdev[0] = pm->physoutdev[0] = '\0';
 +
++      if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0)
++              BUG();
 +
-+/* IPv4/SABOTAGE *****************************************************/
++      if (ub->qlen > 1)
++              ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
 +
-+/* Don't hand locally destined packets to PF_INET/PRE_ROUTING
-+ * for the second time.
-+ */
-+static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
-+{
-+      if ((*pskb)->nf_bridge &&
-+          !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
-+              okfn(*pskb);
-+              return NF_STOLEN;
++      ub->lastnlh = nlh;
++
++      if (ub->qlen >= loginfo->qthreshold)
++              ulog_send(group);
++      else if (!timer_pending(&ub->timer)) {
++              ub->timer.expires = jiffies + flushtimeout * HZ / 100;
++              add_timer(&ub->timer);
 +      }
 +
-+      return NF_ACCEPT;
++unlock:
++      spin_unlock_bh(lock);
++
++      return;
++
++nlmsg_failure:
++      PRINTR(KERN_ERR "ebt_ULOG: error during NLMSG_PUT.\n");
++      goto unlock;
++alloc_failure:
++      goto unlock;
 +}
 +
-+/* Postpone execution of PF_INET/FORWARD, PF_INET/LOCAL_OUT
-+ * and PF_INET/POST_ROUTING until we have done the forwarding
-+ * decision in the bridge code and have determined skb->physoutdev.
-+ */
-+static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   int (*okfn)(struct sk_buff *))
++static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
 +{
-+      struct sk_buff *skb = *pskb;
++      struct ebt_ulog_info *loginfo = (struct ebt_ulog_info *)data;
 +
-+      if ((out->hard_start_xmit == br_dev_xmit &&
-+          okfn != br_nf_forward_finish &&
-+          okfn != br_nf_local_out_finish &&
-+          okfn != br_dev_queue_push_xmit)
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+          || ((out->priv_flags & IFF_802_1Q_VLAN) &&
-+          VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
-+#endif
-+          ) {
-+              struct nf_bridge_info *nf_bridge;
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
++          loginfo->nlgroup > 31)
++              return -EINVAL;
 +
-+              if (!skb->nf_bridge) {
-+#ifdef CONFIG_SYSCTL
-+                      /* This code is executed while in the IP(v6) stack,
-+                         the version should be 4 or 6. We can't use
-+                         skb->protocol because that isn't set on
-+                         PF_INET(6)/LOCAL_OUT. */
-+                      struct iphdr *ip = skb->nh.iph;
++      loginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0';
 +
-+                      if (ip->version == 4 && !brnf_call_iptables)
-+                              return NF_ACCEPT;
-+                      else if (ip->version == 6 && !brnf_call_ip6tables)
-+                              return NF_ACCEPT;
-+#endif
-+                      if (hook == NF_IP_POST_ROUTING)
-+                              return NF_ACCEPT;
-+                      if (!nf_bridge_alloc(skb))
-+                              return NF_DROP;
-+              }
++      if (loginfo->qthreshold > EBT_ULOG_MAX_QLEN)
++              loginfo->qthreshold = EBT_ULOG_MAX_QLEN;
 +
-+              nf_bridge = skb->nf_bridge;
++      return 0;
++}
 +
-+              /* This frame will arrive on PF_BRIDGE/LOCAL_OUT and we
-+               * will need the indev then. For a brouter, the real indev
-+               * can be a bridge port, so we make sure br_nf_local_out()
-+               * doesn't use the bridge parent of the indev by using
-+               * the BRNF_DONT_TAKE_PARENT mask.
-+               */
-+              if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
-+                      nf_bridge->mask &= BRNF_DONT_TAKE_PARENT;
-+                      nf_bridge->physindev = (struct net_device *)in;
-+              }
-+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
-+              /* the iptables outdev is br0.x, not br0 */
-+              if (out->priv_flags & IFF_802_1Q_VLAN)
-+                      nf_bridge->netoutdev = (struct net_device *)out;
-+#endif
-+              okfn(skb);
-+              return NF_STOLEN;
++static struct ebt_watcher ulog = {
++      {NULL, NULL}, EBT_ULOG_WATCHER, ebt_ulog, ebt_ulog_check, NULL,
++      THIS_MODULE
++};
++
++static int __init init(void)
++{
++      int i, ret = 0;
++
++      if (nlbufsiz >= 128*1024) {
++              printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
++                     " please try a smaller nlbufsiz parameter.\n");
++              return -EINVAL;
 +      }
 +
-+      return NF_ACCEPT;
++      /* initialize ulog_buffers */
++      for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
++              init_timer(&ulog_buffers[i].timer);
++              ulog_buffers[i].timer.function = ulog_timer;
++              ulog_buffers[i].timer.data = i;
++              ulog_buffers[i].lock = SPIN_LOCK_UNLOCKED;
++      }
++
++      ebtlognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
++      if (!ebtlognl)
++              ret = -ENOMEM;
++      else if ((ret = ebt_register_watcher(&ulog)))
++              sock_release(ebtlognl->socket);
++
++      return ret;
 +}
 +
-+/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
-+ * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
-+ * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
-+ * ip_refrag() can return NF_STOLEN.
-+ */
-+static struct nf_hook_ops br_nf_ops[] = {
-+      { .hook = br_nf_pre_routing, 
-+        .pf = PF_BRIDGE, 
-+        .hooknum = NF_BR_PRE_ROUTING, 
-+        .priority = NF_BR_PRI_BRNF, },
-+      { .hook = br_nf_local_in,
-+        .pf = PF_BRIDGE,
-+        .hooknum = NF_BR_LOCAL_IN,
-+        .priority = NF_BR_PRI_BRNF, },
-+      { .hook = br_nf_forward_ip,
-+        .pf = PF_BRIDGE,
-+        .hooknum = NF_BR_FORWARD,
-+        .priority = NF_BR_PRI_BRNF /*- 1*/, },
-+/*    { .hook = br_nf_forward_arp,
-+        .pf = PF_BRIDGE,
-+        .hooknum = NF_BR_FORWARD,
-+        .priority = NF_BR_PRI_BRNF, },*/
-+      { .hook = br_nf_local_out,
-+        .pf = PF_BRIDGE,
-+        .hooknum = NF_BR_LOCAL_OUT,
-+        .priority = NF_BR_PRI_FIRST, },
-+      { .hook = br_nf_post_routing,
-+        .pf = PF_BRIDGE,
-+        .hooknum = NF_BR_POST_ROUTING,
-+        .priority = NF_BR_PRI_LAST, },
-+      { .hook = ip_sabotage_in,
-+        .pf = PF_INET,
-+        .hooknum = NF_IP_PRE_ROUTING,
-+        .priority = NF_IP_PRI_FIRST, },
-+      { .hook = ip_sabotage_in,
-+        .pf = PF_INET6,
-+        .hooknum = NF_IP6_PRE_ROUTING,
-+        .priority = NF_IP6_PRI_FIRST, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET,
-+        .hooknum = NF_IP_FORWARD,
-+        .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET6,
-+        .hooknum = NF_IP6_FORWARD,
-+        .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET,
-+        .hooknum = NF_IP_LOCAL_OUT,
-+        .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET6,
-+        .hooknum = NF_IP6_LOCAL_OUT,
-+        .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET,
-+        .hooknum = NF_IP_POST_ROUTING,
-+        .priority = NF_IP_PRI_FIRST, },
-+      { .hook = ip_sabotage_out,
-+        .pf = PF_INET6,
-+        .hooknum = NF_IP6_POST_ROUTING,
-+        .priority = NF_IP6_PRI_FIRST, },
-+};
-+
-+#ifdef CONFIG_SYSCTL
-+static
-+int brnf_sysctl_call_tables(ctl_table *ctl, int write, struct file * filp,
-+                      void *buffer, size_t *lenp)
++static void __exit fini(void)
 +{
-+      int ret;
++      ebt_ulog_buff_t *ub;
++      int i;
 +
-+      ret = proc_dointvec(ctl, write, filp, buffer, lenp);
++      ebt_unregister_watcher(&ulog);
++      for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
++              ub = &ulog_buffers[i];
++              if (timer_pending(&ub->timer))
++                      del_timer(&ub->timer);
++              spin_lock_bh(&ub->lock);
++              if (ub->skb) {
++                      kfree_skb(ub->skb);
++                      ub->skb = NULL;
++              }
++              spin_unlock_bh(&ub->lock);
++      }
++      sock_release(ebtlognl->socket);
++}
 +
-+      if (write && *(int *)(ctl->data))
-+              *(int *)(ctl->data) = 1;
-+      return ret;
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
++MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
++                   " frames");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_snat.c      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,64 @@
++/*
++ *  ebt_snat
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  June, 2002
++ *
++ */
++
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_nat.h>
++#include <linux/module.h>
++
++static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_nat_info *info = (struct ebt_nat_info *) data;
++
++      memcpy(((**pskb).mac.ethernet)->h_source, info->mac,
++         ETH_ALEN * sizeof(unsigned char));
++      return info->target;
 +}
 +
-+static ctl_table brnf_table[] = {
-+      {
-+              .ctl_name       = NET_BRIDGE_NF_CALL_ARPTABLES,
-+              .procname       = "bridge-nf-call-arptables",
-+              .data           = &brnf_call_arptables,
-+              .maxlen         = sizeof(int),
-+              .mode           = 0644,
-+              .proc_handler   = &brnf_sysctl_call_tables,
-+      },
-+      {
-+              .ctl_name       = NET_BRIDGE_NF_CALL_IPTABLES,
-+              .procname       = "bridge-nf-call-iptables",
-+              .data           = &brnf_call_iptables,
-+              .maxlen         = sizeof(int),
-+              .mode           = 0644,
-+              .proc_handler   = &brnf_sysctl_call_tables,
-+      },
-+      {
-+              .ctl_name       = NET_BRIDGE_NF_CALL_IP6TABLES,
-+              .procname       = "bridge-nf-call-ip6tables",
-+              .data           = &brnf_call_ip6tables,
-+              .maxlen         = sizeof(int),
-+              .mode           = 0644,
-+              .proc_handler   = &brnf_sysctl_call_tables,
-+      },
-+      {
-+              .ctl_name       = NET_BRIDGE_NF_FILTER_VLAN_TAGGED,
-+              .procname       = "bridge-nf-filter-vlan-tagged",
-+              .data           = &brnf_filter_vlan_tagged,
-+              .maxlen         = sizeof(int),
-+              .mode           = 0644,
-+              .proc_handler   = &brnf_sysctl_call_tables,
-+      },
-+      { .ctl_name = 0 }
-+};
++static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_nat_info *info = (struct ebt_nat_info *) data;
 +
-+static ctl_table brnf_bridge_table[] = {
-+      {
-+              .ctl_name       = NET_BRIDGE,
-+              .procname       = "bridge",
-+              .mode           = 0555,
-+              .child          = brnf_table,
-+      },
-+      { .ctl_name = 0 }
-+};
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
++              return -EINVAL;
++      if (BASE_CHAIN && info->target == EBT_RETURN)
++              return -EINVAL;
++      CLEAR_BASE_CHAIN_BIT;
++      if (strcmp(tablename, "nat"))
++              return -EINVAL;
++      if (hookmask & ~(1 << NF_BR_POST_ROUTING))
++              return -EINVAL;
++      if (INVALID_TARGET)
++              return -EINVAL;
++      return 0;
++}
 +
-+static ctl_table brnf_net_table[] = {
-+      {
-+              .ctl_name       = CTL_NET,
-+              .procname       = "net",
-+              .mode           = 0555,
-+              .child          = brnf_bridge_table,
-+      },
-+      { .ctl_name = 0 }
++static struct ebt_target snat =
++{
++      {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check,
++      NULL, THIS_MODULE
 +};
-+#endif
 +
-+int br_netfilter_init(void)
++static int __init init(void)
 +{
-+      int i;
++      return ebt_register_target(&snat);
++}
 +
-+      for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
-+              int ret;
++static void __exit fini(void)
++{
++      ebt_unregister_target(&snat);
++}
 +
-+              if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
-+                      continue;
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebt_dnat.c      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,65 @@
++/*
++ *  ebt_dnat
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  June, 2002
++ *
++ */
 +
-+              while (i--)
-+                      nf_unregister_hook(&br_nf_ops[i]);
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/netfilter_bridge/ebt_nat.h>
++#include <linux/module.h>
++#include <net/sock.h>
 +
-+              return ret;
-+      }
++static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
++   const struct net_device *in, const struct net_device *out,
++   const void *data, unsigned int datalen)
++{
++      struct ebt_nat_info *info = (struct ebt_nat_info *)data;
 +
-+#ifdef CONFIG_SYSCTL
-+      brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0);
-+      if (brnf_sysctl_header == NULL) {
-+              printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n");
-+              for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++)
-+                      nf_unregister_hook(&br_nf_ops[i]);
-+              return -EFAULT;
-+      }
-+#endif
++      memcpy(((**pskb).mac.ethernet)->h_dest, info->mac,
++         ETH_ALEN * sizeof(unsigned char));
++      return info->target;
++}
 +
-+      printk(KERN_NOTICE "Bridge firewalling registered\n");
++static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
++   const struct ebt_entry *e, void *data, unsigned int datalen)
++{
++      struct ebt_nat_info *info = (struct ebt_nat_info *)data;
 +
++      if (BASE_CHAIN && info->target == EBT_RETURN)
++              return -EINVAL;
++      CLEAR_BASE_CHAIN_BIT;
++      if ( (strcmp(tablename, "nat") ||
++         (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
++         (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
++              return -EINVAL;
++      if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
++              return -EINVAL;
++      if (INVALID_TARGET)
++              return -EINVAL;
 +      return 0;
 +}
 +
-+void br_netfilter_fini(void)
++static struct ebt_target dnat =
 +{
-+      int i;
-+
-+      for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
-+              nf_unregister_hook(&br_nf_ops[i]);
-+#ifdef CONFIG_SYSCTL
-+      unregister_sysctl_table(brnf_sysctl_header);
-+#endif
++      {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check,
++      NULL, THIS_MODULE
++};
 +
++static int __init init(void)
++{
++      return ebt_register_target(&dnat);
 +}
-diff -Nur linux-mips-cvs/net/bridge/br_private.h linux-ebtables/net/bridge/br_private.h
---- linux-mips-cvs/net/bridge/br_private.h     2004-08-14 20:39:04.000000000 +0200
-+++ linux-ebtables/net/bridge/br_private.h     2005-02-07 05:52:50.000000000 +0100
-@@ -143,8 +143,10 @@
- /* br_forward.c */
- extern void br_deliver(struct net_bridge_port *to,
-               struct sk_buff *skb);
-+extern int br_dev_queue_push_xmit(struct sk_buff *skb);
- extern void br_forward(struct net_bridge_port *to,
-               struct sk_buff *skb);
-+extern int br_forward_finish(struct sk_buff *skb);
- extern void br_flood_deliver(struct net_bridge *br,
-                     struct sk_buff *skb,
-                     int clone);
-@@ -165,7 +167,8 @@
-                          int *ifindices);
- /* br_input.c */
--extern void br_handle_frame(struct sk_buff *skb);
-+extern int br_handle_frame_finish(struct sk_buff *skb);
-+extern int br_handle_frame(struct sk_buff *skb);
- /* br_ioctl.c */
- extern int br_ioctl(struct net_bridge *br,
-@@ -175,6 +178,10 @@
-            unsigned long arg2);
- extern int br_ioctl_deviceless_stub(unsigned long arg);
-+/* br_netfilter.c */
-+extern int br_netfilter_init(void);
-+extern void br_netfilter_fini(void);
-+
- /* br_stp.c */
- extern int br_is_root_bridge(struct net_bridge *br);
- extern struct net_bridge_port *br_get_port(struct net_bridge *br,
-diff -Nur linux-mips-cvs/net/bridge/netfilter/Config.in linux-ebtables/net/bridge/netfilter/Config.in
---- linux-mips-cvs/net/bridge/netfilter/Config.in      1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/Config.in      2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,23 @@
-+#
-+# Bridge netfilter configuration
-+#
-+dep_tristate '  Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
-+dep_tristate '    ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: ulog support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: among filter support' CONFIG_BRIDGE_EBT_AMONG $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: limit filter support' CONFIG_BRIDGE_EBT_LIMIT $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: 802.1Q VLAN filter support' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: 802.3 filter support' CONFIG_BRIDGE_EBT_802_3 $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: packet type filter support' CONFIG_BRIDGE_EBT_PKTTYPE $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: STP filter support' CONFIG_BRIDGE_EBT_STP $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: arp reply target support' CONFIG_BRIDGE_EBT_ARPREPLY $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
-+dep_tristate '    ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
-diff -Nur linux-mips-cvs/net/bridge/netfilter/Makefile linux-ebtables/net/bridge/netfilter/Makefile
---- linux-mips-cvs/net/bridge/netfilter/Makefile       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/Makefile       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,34 @@
-+#
-+# Makefile for the netfilter modules on top of bridging.
-+#
-+# Note! Dependencies are done automagically by 'make dep', which also
-+# removes any old dependencies. DON'T put your own dependencies here
-+# unless it's something special (ie not a .c file).
-+#
-+# Note 2! The CFLAGS definition is now in the main makefile...
-+
-+O_TARGET      := netfilter.o
 +
-+export-objs := ebtables.o
++static void __exit fini(void)
++{
++      ebt_unregister_target(&dnat);
++}
 +
-+obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
-+obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
-+obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
-+obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o
-+obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
-+obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o
-+obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
-+obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o
-+obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
-+obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o
-+obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
-+obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o
-+obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o
-+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
-+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_ulog.o
-+obj-$(CONFIG_BRIDGE_EBT_ARPREPLY) += ebt_arpreply.o
-+obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
-+obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
-+obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
-+obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
-+include $(TOPDIR)/Rules.make
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_802_3.c linux-ebtables/net/bridge/netfilter/ebt_802_3.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_802_3.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_802_3.c    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,74 @@
++module_init(init);
++module_exit(fini);
++EXPORT_NO_SYMBOLS;
++MODULE_LICENSE("GPL");
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/netfilter/ebtables.c      2005-03-14 21:04:05.155913576 +0100
+@@ -0,0 +1,1497 @@
 +/*
-+ * 802_3
++ *  ebtables
 + *
-+ * Author:
-+ * Chris Vitale csv@bluetail.com
++ *  Author:
++ *  Bart De Schuymer          <bart.de.schuymer@pandora.be>
 + *
-+ * May 2003
-+ * 
++ *  ebtables.c,v 2.0, July, 2002
++ *
++ *  This code is stongly inspired on the iptables code which is
++ *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
++ *
++ *  This program is free software; you can redistribute it and/or
++ *  modify it under the terms of the GNU General Public License
++ *  as published by the Free Software Foundation; either version
++ *  2 of the License, or (at your option) any later version.
 + */
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_802_3.h>
++// used for print_string
++#include <linux/sched.h>
++#include <linux/tty.h>
++
++#include <linux/kmod.h>
 +#include <linux/module.h>
++#include <linux/vmalloc.h>
++#include <linux/netfilter_bridge/ebtables.h>
++#include <linux/spinlock.h>
++#include <asm/uaccess.h>
++#include <linux/smp.h>
++#include <net/sock.h>
++// needed for logical [in,out]-dev filtering
++#include "../br_private.h"
 +
-+static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, const void *data, unsigned int datalen)
++// list_named_find
++#define ASSERT_READ_LOCK(x)
++#define ASSERT_WRITE_LOCK(x)
++#include <linux/netfilter_ipv4/listhelp.h>
++
++#if 0 // use this for remote debugging
++// Copyright (C) 1998 by Ori Pomerantz
++// Print the string to the appropriate tty, the one
++// the current task uses
++static void print_string(char *str)
 +{
-+      struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
-+      struct ebt_802_3_hdr *hdr = (struct ebt_802_3_hdr *)skb->mac.ethernet;
-+      uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
++      struct tty_struct *my_tty;
 +
-+      if (info->bitmask & EBT_802_3_SAP) {
-+              if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) 
-+                              return EBT_NOMATCH;
-+              if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP))
-+                              return EBT_NOMATCH;
++      /* The tty for the current task */
++      my_tty = current->tty;
++      if (my_tty != NULL) {
++              (*(my_tty->driver).write)(my_tty, 0, str, strlen(str));
++              (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2);
 +      }
++}
 +
-+      if (info->bitmask & EBT_802_3_TYPE) {
-+              if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
-+                      return EBT_NOMATCH;
-+              if (FWINV(info->type != type, EBT_802_3_TYPE)) 
-+                      return EBT_NOMATCH;
-+      }
++#define BUGPRINT(args) print_string(args);
++#else
++#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
++                                         "report to author: "format, ## args)
++// #define BUGPRINT(format, args...)
++#endif
++#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
++                                         ": out of memory: "format, ## args)
++// #define MEMPRINT(format, args...)
 +
-+      return EBT_MATCH;
-+}
 +
-+static struct ebt_match filter_802_3;
-+static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_802_3_info)))
-+              return -EINVAL;
-+      if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK)
-+              return -EINVAL;
++// Each cpu has its own set of counters, so there is no need for write_lock in
++// the softirq
++// For reading or updating the counters, the user context needs to
++// get a write_lock
++
++// The size of each set of counters is altered to get cache alignment
++#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
++#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
++#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
++   COUNTER_OFFSET(n) * cpu))
++
++
++
++static DECLARE_MUTEX(ebt_mutex);
++static LIST_HEAD(ebt_tables);
++static LIST_HEAD(ebt_targets);
++static LIST_HEAD(ebt_matches);
++static LIST_HEAD(ebt_watchers);
++
++static struct ebt_target ebt_standard_target =
++{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
 +
++static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
++   const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
++   const struct net_device *out)
++{
++      w->u.watcher->watcher(skb, hooknr, in, out, w->data,
++         w->watcher_size);
++      // watchers don't give a verdict
 +      return 0;
 +}
 +
-+static struct ebt_match filter_802_3 =
++static inline int ebt_do_match (struct ebt_entry_match *m,
++   const struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out)
 +{
-+      .name           = EBT_802_3_MATCH,
-+      .match          = ebt_filter_802_3,
-+      .check          = ebt_802_3_check,
-+      .me             = THIS_MODULE,
-+};
++      return m->u.match->match(skb, in, out, m->data,
++         m->match_size);
++}
 +
-+static int __init init(void)
++static inline int ebt_dev_check(char *entry, const struct net_device *device)
 +{
-+      return ebt_register_match(&filter_802_3);
++      int i = 0;
++      char *devname = device->name;
++
++      if (*entry == '\0')
++              return 0;
++      if (!device)
++              return 1;
++      /* 1 is the wildcard token */
++      while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
++              i++;
++      return (devname[i] != entry[i] && entry[i] != 1);
 +}
 +
-+static void __exit fini(void)
++#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
++// process standard matches
++static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
++   const struct net_device *in, const struct net_device *out)
 +{
-+      ebt_unregister_match(&filter_802_3);
-+}
++      int verdict, i;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_among.c linux-ebtables/net/bridge/netfilter/ebt_among.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_among.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_among.c    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,223 @@
-+/*
-+ *  ebt_among
-+ *
-+ *    Authors:
-+ *    Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
-+ *
-+ *  August, 2003
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_among.h>
-+#include <linux/ip.h>
-+#include <linux/if_arp.h>
-+#include <linux/module.h>
++      if (e->bitmask & EBT_802_3) {
++              if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
++                      return 1;
++      } else if (!(e->bitmask & EBT_NOPROTO) &&
++         FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
++              return 1;
 +
-+static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
-+                                   const char *mac, uint32_t ip)
-+{
-+      /* You may be puzzled as to how this code works.
-+       * Some tricks were used, refer to 
-+       *      include/linux/netfilter_bridge/ebt_among.h
-+       * as there you can find a solution of this mystery.
-+       */
-+      const struct ebt_mac_wormhash_tuple *p;
-+      int start, limit, i;
-+      uint32_t cmp[2] = { 0, 0 };
-+      int key = (const unsigned char) mac[5];
++      if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
++              return 1;
++      if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
++              return 1;
++      if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
++         e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN))
++              return 1;
++      if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
++         e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT))
++              return 1;
 +
-+      memcpy(((char *) cmp) + 2, mac, 6);
-+      start = wh->table[key];
-+      limit = wh->table[key + 1];
-+      if (ip) {
-+              for (i = start; i < limit; i++) {
-+                      p = &wh->pool[i];
-+                      if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
-+                              if (p->ip == 0 || p->ip == ip) {
-+                                      return 1;
-+                              }
-+                      }
-+              }
-+      } else {
-+              for (i = start; i < limit; i++) {
-+                      p = &wh->pool[i];
-+                      if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
-+                              if (p->ip == 0) {
-+                                      return 1;
-+                              }
-+                      }
-+              }
++      if (e->bitmask & EBT_SOURCEMAC) {
++              verdict = 0;
++              for (i = 0; i < 6; i++)
++                      verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
++                         e->sourcemsk[i];
++              if (FWINV2(verdict != 0, EBT_ISOURCE) )
++                      return 1;
++      }
++      if (e->bitmask & EBT_DESTMAC) {
++              verdict = 0;
++              for (i = 0; i < 6; i++)
++                      verdict |= (h->h_dest[i] ^ e->destmac[i]) &
++                         e->destmsk[i];
++              if (FWINV2(verdict != 0, EBT_IDEST) )
++                      return 1;
 +      }
 +      return 0;
 +}
 +
-+static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
-+                                          *wh)
++// Do some firewalling
++unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   struct ebt_table *table)
 +{
-+      int i;
++      int i, nentries;
++      struct ebt_entry *point;
++      struct ebt_counter *counter_base, *cb_base;
++      struct ebt_entry_target *t;
++      int verdict, sp = 0;
++      struct ebt_chainstack *cs;
++      struct ebt_entries *chaininfo;
++      char *base;
++      struct ebt_table_info *private;
 +
-+      for (i = 0; i < 256; i++) {
-+              if (wh->table[i] > wh->table[i + 1])
-+                      return -0x100 - i;
-+              if (wh->table[i] < 0)
-+                      return -0x200 - i;
-+              if (wh->table[i] > wh->poolsize)
-+                      return -0x300 - i;
-+      }
-+      if (wh->table[256] > wh->poolsize)
-+              return -0xc00;
-+      return 0;
-+}
++      read_lock_bh(&table->lock);
++      private = table->private;
++      cb_base = COUNTER_BASE(private->counters, private->nentries,
++         cpu_number_map(smp_processor_id()));
++      if (private->chainstack)
++              cs = private->chainstack[cpu_number_map(smp_processor_id())];
++      else
++              cs = NULL;
++      chaininfo = private->hook_entry[hook];
++      nentries = private->hook_entry[hook]->nentries;
++      point = (struct ebt_entry *)(private->hook_entry[hook]->data);
++      counter_base = cb_base + private->hook_entry[hook]->counter_offset;
++      // base for chain jumps
++      base = private->entries;
++      i = 0;
++      while (i < nentries) {
++              if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out))
++                      goto letscontinue;
 +
-+static int get_ip_dst(const struct sk_buff *skb, uint32_t * addr)
-+{
-+      if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP))
-+              *addr = skb->nh.iph->daddr;
-+      else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
-+              uint32_t arp_len = sizeof(struct arphdr) +
-+                  (2 * (((*skb).nh.arph)->ar_hln)) +
-+                  (2 * (((*skb).nh.arph)->ar_pln));
++              if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
++                      goto letscontinue;
 +
-+              /* Make sure the packet is long enough. */
-+              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
-+                      return -1;
-+              /* IPv4 addresses are always 4 bytes. */
-+              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
-+                      return -1;
++              // increase counter
++              (*(counter_base + i)).pcnt++;
++              (*(counter_base + i)).bcnt+=(**pskb).len;
 +
-+              memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) +
-+                     (2 * (((*skb).nh.arph)->ar_hln)) +
-+                     (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
++              // these should only watch: not modify, nor tell us
++              // what to do with the packet
++              EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,
++                 out);
++
++              t = (struct ebt_entry_target *)
++                 (((char *)point) + point->target_offset);
++              // standard target
++              if (!t->u.target->target)
++                      verdict = ((struct ebt_standard_target *)t)->verdict;
++              else
++                      verdict = t->u.target->target(pskb, hook,
++                         in, out, t->data, t->target_size);
++              if (verdict == EBT_ACCEPT) {
++                      read_unlock_bh(&table->lock);
++                      return NF_ACCEPT;
++              }
++              if (verdict == EBT_DROP) {
++                      read_unlock_bh(&table->lock);
++                      return NF_DROP;
++              }
++              if (verdict == EBT_RETURN) {
++letsreturn:
++#ifdef CONFIG_NETFILTER_DEBUG
++                      if (sp == 0) {
++                              BUGPRINT("RETURN on base chain");
++                              // act like this is EBT_CONTINUE
++                              goto letscontinue;
++                      }
++#endif
++                      sp--;
++                      // put all the local variables right
++                      i = cs[sp].n;
++                      chaininfo = cs[sp].chaininfo;
++                      nentries = chaininfo->nentries;
++                      point = cs[sp].e;
++                      counter_base = cb_base +
++                         chaininfo->counter_offset;
++                      continue;
++              }
++              if (verdict == EBT_CONTINUE)
++                      goto letscontinue;
++#ifdef CONFIG_NETFILTER_DEBUG
++              if (verdict < 0) {
++                      BUGPRINT("bogus standard verdict\n");
++                      read_unlock_bh(&table->lock);
++                      return NF_DROP;
++              }
++#endif
++              // jump to a udc
++              cs[sp].n = i + 1;
++              cs[sp].chaininfo = chaininfo;
++              cs[sp].e = (struct ebt_entry *)
++                 (((char *)point) + point->next_offset);
++              i = 0;
++              chaininfo = (struct ebt_entries *) (base + verdict);
++#ifdef CONFIG_NETFILTER_DEBUG
++              if (chaininfo->distinguisher) {
++                      BUGPRINT("jump to non-chain\n");
++                      read_unlock_bh(&table->lock);
++                      return NF_DROP;
++              }
++#endif
++              nentries = chaininfo->nentries;
++              point = (struct ebt_entry *)chaininfo->data;
++              counter_base = cb_base + chaininfo->counter_offset;
++              sp++;
++              continue;
++letscontinue:
++              point = (struct ebt_entry *)
++                 (((char *)point) + point->next_offset);
++              i++;
++      }
 +
++      // I actually like this :)
++      if (chaininfo->policy == EBT_RETURN)
++              goto letsreturn;
++      if (chaininfo->policy == EBT_ACCEPT) {
++              read_unlock_bh(&table->lock);
++              return NF_ACCEPT;
 +      }
-+      return 0;
++      read_unlock_bh(&table->lock);
++      return NF_DROP;
 +}
 +
-+static int get_ip_src(const struct sk_buff *skb, uint32_t * addr)
++// If it succeeds, returns element and locks mutex
++static inline void *
++find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
++   struct semaphore *mutex)
 +{
-+      if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP))
-+              *addr = skb->nh.iph->saddr;
-+      else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
-+              uint32_t arp_len = sizeof(struct arphdr) +
-+                  (2 * (((*skb).nh.arph)->ar_hln)) +
-+                  (2 * (((*skb).nh.arph)->ar_pln));
-+
-+              /* Make sure the packet is long enough. */
-+              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
-+                      return -1;
-+              /* IPv4 addresses are always 4 bytes. */
-+              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
-+                      return -1;
++      void *ret;
 +
-+              memcpy(addr, ((*skb).nh.raw) + sizeof(struct arphdr) +
-+                     ((((*skb).nh.arph)->ar_hln)), sizeof(uint32_t));
++      *error = down_interruptible(mutex);
++      if (*error != 0)
++              return NULL;
 +
++      ret = list_named_find(head, name);
++      if (!ret) {
++              *error = -ENOENT;
++              up(mutex);
 +      }
-+      return 0;
++      return ret;
 +}
 +
-+static int ebt_filter_among(const struct sk_buff *skb,
-+                          const struct net_device *in,
-+                          const struct net_device *out, const void *data,
-+                          unsigned int datalen)
++#ifndef CONFIG_KMOD
++#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
++#else
++static void *
++find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
++   int *error, struct semaphore *mutex)
 +{
-+      struct ebt_among_info *info = (struct ebt_among_info *) data;
-+      const char *dmac, *smac;
-+      const struct ebt_mac_wormhash *wh_dst, *wh_src;
-+      uint32_t dip = 0, sip = 0;
-+
-+      wh_dst = ebt_among_wh_dst(info);
-+      wh_src = ebt_among_wh_src(info);
++      void *ret;
 +
-+      if (wh_src) {
-+              smac = skb->mac.ethernet->h_source;
-+              if (get_ip_src(skb, &sip))
-+                      return EBT_NOMATCH;
-+              if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
-+                      /* we match only if it contains */
-+                      if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
-+                              return EBT_NOMATCH;
-+              } else {
-+                      /* we match only if it DOES NOT contain */
-+                      if (ebt_mac_wormhash_contains(wh_src, smac, sip))
-+                              return EBT_NOMATCH;
-+              }
++      ret = find_inlist_lock_noload(head, name, error, mutex);
++      if (!ret) {
++              char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
++              strcpy(modulename, prefix);
++              strcat(modulename, name);
++              request_module(modulename);
++              ret = find_inlist_lock_noload(head, name, error, mutex);
 +      }
++      return ret;
++}
++#endif
 +
-+      if (wh_dst) {
-+              dmac = skb->mac.ethernet->h_dest;
-+              if (get_ip_dst(skb, &dip))
-+                      return EBT_NOMATCH;
-+              if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
-+                      /* we match only if it contains */
-+                      if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
-+                              return EBT_NOMATCH;
-+              } else {
-+                      /* we match only if it DOES NOT contain */
-+                      if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
-+                              return EBT_NOMATCH;
-+              }
-+      }
++static inline struct ebt_table *
++find_table_lock(const char *name, int *error, struct semaphore *mutex)
++{
++      return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
++}
 +
-+      return EBT_MATCH;
++static inline struct ebt_match *
++find_match_lock(const char *name, int *error, struct semaphore *mutex)
++{
++      return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
 +}
 +
-+static int ebt_among_check(const char *tablename, unsigned int hookmask,
-+                         const struct ebt_entry *e, void *data,
-+                         unsigned int datalen)
++static inline struct ebt_watcher *
++find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
 +{
-+      struct ebt_among_info *info = (struct ebt_among_info *) data;
-+      int expected_length = sizeof(struct ebt_among_info);
-+      const struct ebt_mac_wormhash *wh_dst, *wh_src;
-+      int err;
++      return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
++}
 +
-+      wh_dst = ebt_among_wh_dst(info);
-+      wh_src = ebt_among_wh_src(info);
-+      expected_length += ebt_mac_wormhash_size(wh_dst);
-+      expected_length += ebt_mac_wormhash_size(wh_src);
++static inline struct ebt_target *
++find_target_lock(const char *name, int *error, struct semaphore *mutex)
++{
++      return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
++}
 +
-+      if (datalen != EBT_ALIGN(expected_length)) {
-+              printk(KERN_WARNING
-+                     "ebtables: among: wrong size: %d"
-+                     "against expected %d, rounded to %d\n",
-+                     datalen, expected_length,
-+                     EBT_ALIGN(expected_length));
-+              return -EINVAL;
-+      }
-+      if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
-+              printk(KERN_WARNING
-+                     "ebtables: among: dst integrity fail: %x\n", -err);
++static inline int
++ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
++   const char *name, unsigned int hookmask, unsigned int *cnt)
++{
++      struct ebt_match *match;
++      int ret;
++
++      if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
++         ((char *)e) + e->watchers_offset)
 +              return -EINVAL;
-+      }
-+      if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
-+              printk(KERN_WARNING
-+                     "ebtables: among: src integrity fail: %x\n", -err);
++      match = find_match_lock(m->u.name, &ret, &ebt_mutex);
++      if (!match)
++              return ret;
++      m->u.match = match;
++      if (match->me)
++              __MOD_INC_USE_COUNT(match->me);
++      up(&ebt_mutex);
++      if (match->check &&
++         match->check(name, hookmask, e, m->data, m->match_size) != 0) {
++              BUGPRINT("match->check failed\n");
++              if (match->me)
++                      __MOD_DEC_USE_COUNT(match->me);
 +              return -EINVAL;
 +      }
++      (*cnt)++;
 +      return 0;
 +}
 +
-+static struct ebt_match filter_among = {
-+      {NULL, NULL}, 
-+      EBT_AMONG_MATCH, 
-+      ebt_filter_among, 
-+      ebt_among_check,
-+      NULL,
-+      THIS_MODULE
-+};
-+
-+static int __init init(void)
++static inline int
++ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
++   const char *name, unsigned int hookmask, unsigned int *cnt)
 +{
-+      return ebt_register_match(&filter_among);
-+}
++      struct ebt_watcher *watcher;
++      int ret;
 +
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&filter_among);
++      if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
++         ((char *)e) + e->target_offset)
++              return -EINVAL;
++      watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
++      if (!watcher)
++              return ret;
++      w->u.watcher = watcher;
++      if (watcher->me)
++              __MOD_INC_USE_COUNT(watcher->me);
++      up(&ebt_mutex);
++      if (watcher->check &&
++         watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
++              BUGPRINT("watcher->check failed\n");
++              if (watcher->me)
++                      __MOD_DEC_USE_COUNT(watcher->me);
++              return -EINVAL;
++      }
++      (*cnt)++;
++      return 0;
 +}
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_arp.c linux-ebtables/net/bridge/netfilter/ebt_arp.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_arp.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_arp.c      2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,149 @@
-+/*
-+ *  ebt_arp
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *    Tim Gardner <timg@tpi.com>
-+ *
-+ *  April, 2002
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_arp.h>
-+#include <linux/if_arp.h>
-+#include <linux/if_ether.h>
-+#include <linux/module.h>
-+
-+static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, const void *data, unsigned int datalen)
++// this one is very careful, as it is the first function
++// to parse the userspace data
++static inline int
++ebt_check_entry_size_and_hooks(struct ebt_entry *e,
++   struct ebt_table_info *newinfo, char *base, char *limit,
++   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
++   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
 +{
-+      struct ebt_arp_info *info = (struct ebt_arp_info *)data;
-+
-+      if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
-+         ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE))
-+              return EBT_NOMATCH;
-+      if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
-+         ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE))
-+              return EBT_NOMATCH;
-+      if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
-+         ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE))
-+              return EBT_NOMATCH;
-+
-+      if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP))
-+      {
-+              uint32_t arp_len = sizeof(struct arphdr) +
-+                 (2 * (((*skb).nh.arph)->ar_hln)) +
-+                 (2 * (((*skb).nh.arph)->ar_pln));
-+              uint32_t dst;
-+              uint32_t src;
-+
-+              // Make sure the packet is long enough.
-+              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
-+                      return EBT_NOMATCH;
-+              // IPv4 addresses are always 4 bytes.
-+              if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
-+                      return EBT_NOMATCH;
++      int i;
 +
-+              if (info->bitmask & EBT_ARP_SRC_IP) {
-+                      memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) +
-+                         ((*skb).nh.arph)->ar_hln, sizeof(uint32_t));
-+                      if (FWINV(info->saddr != (src & info->smsk),
-+                         EBT_ARP_SRC_IP))
-+                              return EBT_NOMATCH;
++      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
++              if ((valid_hooks & (1 << i)) == 0)
++                      continue;
++              if ( (char *)hook_entries[i] - base ==
++                 (char *)e - newinfo->entries)
++                      break;
++      }
++      // beginning of a new chain
++      // if i == NF_BR_NUMHOOKS it must be a user defined chain
++      if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
++              if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
++                      // we make userspace set this right,
++                      // so there is no misunderstanding
++                      BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
++                               "in distinguisher\n");
++                      return -EINVAL;
 +              }
-+
-+              if (info->bitmask & EBT_ARP_DST_IP) {
-+                      memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) +
-+                         (2*(((*skb).nh.arph)->ar_hln)) +
-+                         (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
-+                      if (FWINV(info->daddr != (dst & info->dmsk),
-+                         EBT_ARP_DST_IP))
-+                              return EBT_NOMATCH;
++              // this checks if the previous chain has as many entries
++              // as it said it has
++              if (*n != *cnt) {
++                      BUGPRINT("nentries does not equal the nr of entries "
++                               "in the chain\n");
++                      return -EINVAL;
 +              }
-+      }
-+
-+      if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC))
-+      {
-+              uint32_t arp_len = sizeof(struct arphdr) +
-+                 (2 * (((*skb).nh.arph)->ar_hln)) +
-+                 (2 * (((*skb).nh.arph)->ar_pln));
-+              unsigned char dst[ETH_ALEN];
-+              unsigned char src[ETH_ALEN];
-+
-+              // Make sure the packet is long enough.
-+              if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
-+                      return EBT_NOMATCH;
-+              // MAC addresses are 6 bytes.
-+              if (((*skb).nh.arph)->ar_hln != ETH_ALEN)
-+                      return EBT_NOMATCH;
-+              if (info->bitmask & EBT_ARP_SRC_MAC) {
-+                      uint8_t verdict, i;
-+
-+                      memcpy(&src, ((*skb).nh.raw) +
-+                                      sizeof(struct arphdr),
-+                                      ETH_ALEN);
-+                      verdict = 0;
-+                      for (i = 0; i < 6; i++)
-+                              verdict |= (src[i] ^ info->smaddr[i]) &
-+                                     info->smmsk[i];  
-+                      if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
-+                              return EBT_NOMATCH;
++              // before we look at the struct, be sure it is not too big
++              if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
++                 > limit) {
++                      BUGPRINT("entries_size too small\n");
++                      return -EINVAL;
 +              }
-+
-+              if (info->bitmask & EBT_ARP_DST_MAC) { 
-+                      uint8_t verdict, i;
-+
-+                      memcpy(&dst, ((*skb).nh.raw) +
-+                                      sizeof(struct arphdr) +
-+                                      (((*skb).nh.arph)->ar_hln) +
-+                                      (((*skb).nh.arph)->ar_pln),
-+                                      ETH_ALEN);
-+                      verdict = 0;
-+                      for (i = 0; i < 6; i++)
-+                              verdict |= (dst[i] ^ info->dmaddr[i]) &
-+                                      info->dmmsk[i];
-+                      if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
-+                              return EBT_NOMATCH;
++              if (((struct ebt_entries *)e)->policy != EBT_DROP &&
++                 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
++                      // only RETURN from udc
++                      if (i != NF_BR_NUMHOOKS ||
++                         ((struct ebt_entries *)e)->policy != EBT_RETURN) {
++                              BUGPRINT("bad policy\n");
++                              return -EINVAL;
++                      }
++              }
++              if (i == NF_BR_NUMHOOKS) // it's a user defined chain
++                      (*udc_cnt)++;
++              else
++                      newinfo->hook_entry[i] = (struct ebt_entries *)e;
++              if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
++                      BUGPRINT("counter_offset != totalcnt");
++                      return -EINVAL;
 +              }
++              *n = ((struct ebt_entries *)e)->nentries;
++              *cnt = 0;
++              return 0;
 +      }
-+
-+      return EBT_MATCH;
-+}
-+
-+static int ebt_arp_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_arp_info *info = (struct ebt_arp_info *)data;
-+
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
-+              return -EINVAL;
-+      if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
-+         e->ethproto != __constant_htons(ETH_P_RARP)) ||
-+         e->invflags & EBT_IPROTO)
++      // a plain old entry, heh
++      if (sizeof(struct ebt_entry) > e->watchers_offset ||
++         e->watchers_offset > e->target_offset ||
++         e->target_offset >= e->next_offset) {
++              BUGPRINT("entry offsets not in right order\n");
 +              return -EINVAL;
-+      if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
++      }
++      // this is not checked anywhere else
++      if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
++              BUGPRINT("target size too small\n");
 +              return -EINVAL;
++      }
++
++      (*cnt)++;
++      (*totalcnt)++;
 +      return 0;
 +}
 +
-+static struct ebt_match filter_arp =
++struct ebt_cl_stack
 +{
-+      {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL,
-+      THIS_MODULE
++      struct ebt_chainstack cs;
++      int from;
++      unsigned int hookmask;
 +};
 +
-+static int __init init(void)
++// we need these positions to check that the jumps to a different part of the
++// entries is a jump to the beginning of a new chain.
++static inline int
++ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
++   struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks,
++   struct ebt_cl_stack *udc)
 +{
-+      return ebt_register_match(&filter_arp);
-+}
++      int i;
 +
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&filter_arp);
-+}
++      // we're only interested in chain starts
++      if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
++              return 0;
++      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
++              if ((valid_hooks & (1 << i)) == 0)
++                      continue;
++              if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
++                      break;
++      }
++      // only care about udc
++      if (i != NF_BR_NUMHOOKS)
++              return 0;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_arpreply.c linux-ebtables/net/bridge/netfilter/ebt_arpreply.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_arpreply.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_arpreply.c 2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,86 @@
-+/*
-+ *  ebt_arpreply
-+ *
-+ *    Authors:
-+ *    Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
-+ *    Bart De Schuymer <bdschuym@pandora.be>
-+ *
-+ *  August, 2003
-+ *
-+ */
++      udc[*n].cs.chaininfo = (struct ebt_entries *)e;
++      // these initialisations are depended on later in check_chainloops()
++      udc[*n].cs.n = 0;
++      udc[*n].hookmask = 0;
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_arpreply.h>
-+#include <linux/if_arp.h>
-+#include <net/arp.h>
-+#include <linux/module.h>
++      (*n)++;
++      return 0;
++}
 +
-+static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
++static inline int
++ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
 +{
-+      struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
-+      struct arphdr *ah;
-+      unsigned char *sha, *arp_ptr;
-+      u32 sip, tip;
-+
-+      ah = (**pskb).nh.arph;
-+      if (ah->ar_op != __constant_htons(ARPOP_REQUEST) ||
-+          ah->ar_hln != ETH_ALEN || ah->ar_pro != htons(ETH_P_IP) ||
-+          ah->ar_pln != 4)
-+              return EBT_CONTINUE;
-+
-+      arp_ptr = (unsigned char *)(ah + 1);
-+
-+      /* get source and target IP */
-+      sha = arp_ptr;
-+      arp_ptr += ETH_ALEN;
-+      memcpy(&sip, arp_ptr, 4);
-+      arp_ptr += 4 + ETH_ALEN;
-+      memcpy(&tip, arp_ptr, 4);
-+
-+      arp_send(ARPOP_REPLY, ETH_P_ARP, sip, in, tip, sha, info->mac, sha);
++      if (i && (*i)-- == 0)
++              return 1;
++      if (m->u.match->destroy)
++              m->u.match->destroy(m->data, m->match_size);
++      if (m->u.match->me)
++              __MOD_DEC_USE_COUNT(m->u.match->me);
 +
-+      return info->target;
++      return 0;
 +}
 +
-+static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
++static inline int
++ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
 +{
-+      struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
++      if (i && (*i)-- == 0)
++              return 1;
++      if (w->u.watcher->destroy)
++              w->u.watcher->destroy(w->data, w->watcher_size);
++      if (w->u.watcher->me)
++              __MOD_DEC_USE_COUNT(w->u.watcher->me);
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
-+              return -EINVAL;
-+      if (BASE_CHAIN && info->target == EBT_RETURN)
-+              return -EINVAL;
-+      if (e->ethproto != __constant_htons(ETH_P_ARP) ||
-+          e->invflags & EBT_IPROTO)
-+              return -EINVAL;
-+      CLEAR_BASE_CHAIN_BIT;
-+      if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
-+              return -EINVAL;
 +      return 0;
 +}
 +
-+static struct ebt_target reply_target =
++static inline int
++ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
 +{
-+      .name           = EBT_ARPREPLY_TARGET,
-+      .target         = ebt_target_reply,
-+      .check          = ebt_target_reply_check,
-+      .me             = THIS_MODULE,
-+};
++      struct ebt_entry_target *t;
 +
-+static int __init init(void)
-+{
-+      return ebt_register_target(&reply_target);
++      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
++              return 0;
++      // we're done
++      if (cnt && (*cnt)-- == 0)
++              return 1;
++      EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
++      EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
++      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
++      if (t->u.target->destroy)
++              t->u.target->destroy(t->data, t->target_size);
++      if (t->u.target->me)
++              __MOD_DEC_USE_COUNT(t->u.target->me);
++
++      return 0;
 +}
 +
-+static void __exit fini(void)
++static inline int
++ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
++   const char *name, unsigned int *cnt, unsigned int valid_hooks,
++   struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
 +{
-+      ebt_unregister_target(&reply_target);
-+}
++      struct ebt_entry_target *t;
++      struct ebt_target *target;
++      unsigned int i, j, hook = 0, hookmask = 0;
++      int ret;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_dnat.c linux-ebtables/net/bridge/netfilter/ebt_dnat.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_dnat.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_dnat.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,65 @@
-+/*
-+ *  ebt_dnat
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  June, 2002
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_nat.h>
-+#include <linux/module.h>
-+#include <net/sock.h>
-+
-+static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
-+{
-+      struct ebt_nat_info *info = (struct ebt_nat_info *)data;
-+
-+      memcpy(((**pskb).mac.ethernet)->h_dest, info->mac,
-+         ETH_ALEN * sizeof(unsigned char));
-+      return info->target;
-+}
-+
-+static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_nat_info *info = (struct ebt_nat_info *)data;
++      // Don't mess with the struct ebt_entries
++      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
++              return 0;
 +
-+      if (BASE_CHAIN && info->target == EBT_RETURN)
-+              return -EINVAL;
-+      CLEAR_BASE_CHAIN_BIT;
-+      if ( (strcmp(tablename, "nat") ||
-+         (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
-+         (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
++      if (e->bitmask & ~EBT_F_MASK) {
++              BUGPRINT("Unknown flag for bitmask\n");
 +              return -EINVAL;
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
++      }
++      if (e->invflags & ~EBT_INV_MASK) {
++              BUGPRINT("Unknown flag for inv bitmask\n");
 +              return -EINVAL;
-+      if (INVALID_TARGET)
++      }
++      if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
++              BUGPRINT("NOPROTO & 802_3 not allowed\n");
 +              return -EINVAL;
++      }
++      // what hook do we belong to?
++      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
++              if ((valid_hooks & (1 << i)) == 0)
++                      continue;
++              if ((char *)newinfo->hook_entry[i] < (char *)e)
++                      hook = i;
++              else
++                      break;
++      }
++      // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
++      // a base chain
++      if (i < NF_BR_NUMHOOKS)
++              hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
++      else {
++              for (i = 0; i < udc_cnt; i++)
++                      if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
++                              break;
++              if (i == 0)
++                      hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
++              else
++                      hookmask = cl_s[i - 1].hookmask;
++      }
++      i = 0;
++      ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
++      if (ret != 0)
++              goto cleanup_matches;
++      j = 0;
++      ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
++      if (ret != 0)
++              goto cleanup_watchers;
++      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
++      target = find_target_lock(t->u.name, &ret, &ebt_mutex);
++      if (!target)
++              goto cleanup_watchers;
++      if (target->me)
++              __MOD_INC_USE_COUNT(target->me);
++      up(&ebt_mutex);
++
++      t->u.target = target;
++      if (t->u.target == &ebt_standard_target) {
++              if (e->target_offset + sizeof(struct ebt_standard_target) >
++                 e->next_offset) {
++                      BUGPRINT("Standard target size too big\n");
++                      ret = -EFAULT;
++                      goto cleanup_watchers;
++              }
++              if (((struct ebt_standard_target *)t)->verdict <
++                 -NUM_STANDARD_TARGETS) {
++                      BUGPRINT("Invalid standard target\n");
++                      ret = -EFAULT;
++                      goto cleanup_watchers;
++              }
++      } else if ((e->target_offset + t->target_size +
++         sizeof(struct ebt_entry_target) > e->next_offset) ||
++         (t->u.target->check &&
++         t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
++              if (t->u.target->me)
++                      __MOD_DEC_USE_COUNT(t->u.target->me);
++              ret = -EFAULT;
++              goto cleanup_watchers;
++      }
++      (*cnt)++;
 +      return 0;
++cleanup_watchers:
++      EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
++cleanup_matches:
++      EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
++      return ret;
 +}
 +
-+static struct ebt_target dnat =
++// checks for loops and sets the hook mask for udc
++// the hook mask for udc tells us from which base chains the udc can be
++// accessed. This mask is a parameter to the check() functions of the extensions
++static int check_chainloops(struct ebt_entries *chain,
++   struct ebt_cl_stack *cl_s, unsigned int udc_cnt, 
++   unsigned int hooknr, char *base)
 +{
-+      {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check,
-+      NULL, THIS_MODULE
-+};
++      int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
++      struct ebt_entry *e = (struct ebt_entry *)chain->data;
++      struct ebt_entry_target *t;
 +
-+static int __init init(void)
-+{
-+      return ebt_register_target(&dnat);
++      while (pos < nentries || chain_nr != -1) {
++              // end of udc, go back one 'recursion' step
++              if (pos == nentries) {
++                      // put back values of the time when this chain was called
++                      e = cl_s[chain_nr].cs.e;
++                      if (cl_s[chain_nr].from != -1)
++                              nentries =
++                              cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
++                      else
++                              nentries = chain->nentries;
++                      pos = cl_s[chain_nr].cs.n;
++                      // make sure we won't see a loop that isn't one
++                      cl_s[chain_nr].cs.n = 0;
++                      chain_nr = cl_s[chain_nr].from;
++                      if (pos == nentries)
++                              continue;
++              }
++              t = (struct ebt_entry_target *)
++                 (((char *)e) + e->target_offset);
++              if (strcmp(t->u.name, EBT_STANDARD_TARGET))
++                      goto letscontinue;
++              if (e->target_offset + sizeof(struct ebt_standard_target) >
++                 e->next_offset) {
++                      BUGPRINT("Standard target size too big\n");
++                      return -1;
++              }
++              verdict = ((struct ebt_standard_target *)t)->verdict;
++              if (verdict >= 0) { // jump to another chain
++                      struct ebt_entries *hlp2 =
++                         (struct ebt_entries *)(base + verdict);
++                      for (i = 0; i < udc_cnt; i++)
++                              if (hlp2 == cl_s[i].cs.chaininfo)
++                                      break;
++                      // bad destination or loop
++                      if (i == udc_cnt) {
++                              BUGPRINT("bad destination\n");
++                              return -1;
++                      }
++                      if (cl_s[i].cs.n) {
++                              BUGPRINT("loop\n");
++                              return -1;
++                      }
++                      // this can't be 0, so the above test is correct
++                      cl_s[i].cs.n = pos + 1;
++                      pos = 0;
++                      cl_s[i].cs.e = ((void *)e + e->next_offset);
++                      e = (struct ebt_entry *)(hlp2->data);
++                      nentries = hlp2->nentries;
++                      cl_s[i].from = chain_nr;
++                      chain_nr = i;
++                      // this udc is accessible from the base chain for hooknr
++                      cl_s[i].hookmask |= (1 << hooknr);
++                      continue;
++              }
++letscontinue:
++              e = (void *)e + e->next_offset;
++              pos++;
++      }
++      return 0;
 +}
 +
-+static void __exit fini(void)
++// do the parsing of the table/chains/entries/matches/watchers/targets, heh
++static int translate_table(struct ebt_replace *repl,
++   struct ebt_table_info *newinfo)
 +{
-+      ebt_unregister_target(&dnat);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_ip.c linux-ebtables/net/bridge/netfilter/ebt_ip.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_ip.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_ip.c       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,121 @@
-+/*
-+ *  ebt_ip
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  April, 2002
-+ *
-+ *  Changes:
-+ *    added ip-sport and ip-dport
-+ *    Innominate Security Technologies AG <mhopf@innominate.com>
-+ *    September, 2002
-+ */
++      unsigned int i, j, k, udc_cnt;
++      int ret;
++      struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_ip.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/module.h>
++      i = 0;
++      while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
++              i++;
++      if (i == NF_BR_NUMHOOKS) {
++              BUGPRINT("No valid hooks specified\n");
++              return -EINVAL;
++      }
++      if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
++              BUGPRINT("Chains don't start at beginning\n");
++              return -EINVAL;
++      }
++      // make sure chains are ordered after each other in same order
++      // as their corresponding hooks
++      for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
++              if (!(repl->valid_hooks & (1 << j)))
++                      continue;
++              if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
++                      BUGPRINT("Hook order must be followed\n");
++                      return -EINVAL;
++              }
++              i = j;
++      }
 +
-+struct tcpudphdr {
-+      uint16_t src;
-+      uint16_t dst;
-+};
++      for (i = 0; i < NF_BR_NUMHOOKS; i++)
++              newinfo->hook_entry[i] = NULL;
 +
-+union h_u {
-+      unsigned char *raw;
-+      struct tcpudphdr *tuh;
-+};
++      newinfo->entries_size = repl->entries_size;
++      newinfo->nentries = repl->nentries;
 +
-+static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, const void *data,
-+   unsigned int datalen)
-+{
-+      struct ebt_ip_info *info = (struct ebt_ip_info *)data;
-+
-+      if (info->bitmask & EBT_IP_TOS &&
-+         FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS))
-+              return EBT_NOMATCH;
-+      if (info->bitmask & EBT_IP_PROTO) {
-+              if (FWINV(info->protocol != ((*skb).nh.iph)->protocol,
-+                        EBT_IP_PROTO))
-+                      return EBT_NOMATCH;
-+              if ( info->protocol == IPPROTO_TCP ||
-+                   info->protocol == IPPROTO_UDP )
-+              {
-+                      union h_u h;
-+                      h.raw = skb->data + skb->nh.iph->ihl*4;
-+                      if (info->bitmask & EBT_IP_DPORT) {
-+                              uint16_t port = ntohs(h.tuh->dst);
-+                              if (FWINV(port < info->dport[0] ||
-+                                        port > info->dport[1],
-+                                        EBT_IP_DPORT))
-+                              return EBT_NOMATCH;
-+                      }
-+                      if (info->bitmask & EBT_IP_SPORT) {
-+                              uint16_t port = ntohs(h.tuh->src);
-+                              if (FWINV(port < info->sport[0] ||
-+                                        port > info->sport[1],
-+                                        EBT_IP_SPORT))
-+                              return EBT_NOMATCH;
-+                      }
-+              }
-+      }
-+      if (info->bitmask & EBT_IP_SOURCE &&
-+         FWINV((((*skb).nh.iph)->saddr & info->smsk) !=
-+         info->saddr, EBT_IP_SOURCE))
-+              return EBT_NOMATCH;
-+      if ((info->bitmask & EBT_IP_DEST) &&
-+         FWINV((((*skb).nh.iph)->daddr & info->dmsk) !=
-+         info->daddr, EBT_IP_DEST))
-+              return EBT_NOMATCH;
-+      return EBT_MATCH;
-+}
++      // do some early checkings and initialize some things
++      i = 0; // holds the expected nr. of entries for the chain
++      j = 0; // holds the up to now counted entries for the chain
++      k = 0; // holds the total nr. of entries, should equal
++             // newinfo->nentries afterwards
++      udc_cnt = 0; // will hold the nr. of user defined chains (udc)
++      ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
++         ebt_check_entry_size_and_hooks, newinfo, repl->entries,
++         repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
++         &udc_cnt, repl->valid_hooks);
 +
-+static int ebt_ip_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_ip_info *info = (struct ebt_ip_info *)data;
++      if (ret != 0)
++              return ret;
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
-+              return -EINVAL;
-+      if (e->ethproto != __constant_htons(ETH_P_IP) ||
-+         e->invflags & EBT_IPROTO)
-+              return -EINVAL;
-+      if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
++      if (i != j) {
++              BUGPRINT("nentries does not equal the nr of entries in the "
++                       "(last) chain\n");
 +              return -EINVAL;
-+      if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) {
-+              if (!info->bitmask & EBT_IPROTO)
-+                      return -EINVAL;
-+              if (info->protocol != IPPROTO_TCP &&
-+                  info->protocol != IPPROTO_UDP)
-+                       return -EINVAL;
 +      }
-+      if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1])
-+              return -EINVAL;
-+      if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
++      if (k != newinfo->nentries) {
++              BUGPRINT("Total nentries is wrong\n");
 +              return -EINVAL;
-+      return 0;
-+}
-+
-+static struct ebt_match filter_ip =
-+{
-+      {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL,
-+      THIS_MODULE
-+};
-+
-+static int __init init(void)
-+{
-+      return ebt_register_match(&filter_ip);
-+}
-+
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&filter_ip);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_limit.c linux-ebtables/net/bridge/netfilter/ebt_limit.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_limit.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_limit.c    2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,101 @@
-+/*
-+ *  ebt_limit
-+ *
-+ *    Authors:
-+ *    Tom Marshall <tommy@home.tig-grr.com>
-+ *
-+ *    Mostly copied from netfilter's ipt_limit.c, see that file for explanation
-+ *
-+ *  September, 2003
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_limit.h>
-+#include <linux/module.h>
++      }
 +
-+#include <linux/netdevice.h>
-+#include <linux/spinlock.h>
++      // check if all valid hooks have a chain
++      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
++              if (newinfo->hook_entry[i] == NULL &&
++                 (repl->valid_hooks & (1 << i))) {
++                      BUGPRINT("Valid hook without chain\n");
++                      return -EINVAL;
++              }
++      }
 +
-+static spinlock_t limit_lock = SPIN_LOCK_UNLOCKED;
++      // Get the location of the udc, put them in an array
++      // While we're at it, allocate the chainstack
++      if (udc_cnt) {
++              // this will get free'd in do_replace()/ebt_register_table()
++              // if an error occurs
++              newinfo->chainstack = (struct ebt_chainstack **)
++                 vmalloc(smp_num_cpus * sizeof(struct ebt_chainstack));
++              if (!newinfo->chainstack)
++                      return -ENOMEM;
++              for (i = 0; i < smp_num_cpus; i++) {
++                      newinfo->chainstack[i] =
++                         vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
++                      if (!newinfo->chainstack[i]) {
++                              while (i)
++                                      vfree(newinfo->chainstack[--i]);
++                              vfree(newinfo->chainstack);
++                              newinfo->chainstack = NULL;
++                              return -ENOMEM;
++                      }
++              }
 +
-+#define CREDITS_PER_JIFFY 128
++              cl_s = (struct ebt_cl_stack *)
++                 vmalloc(udc_cnt * sizeof(struct ebt_cl_stack));
++              if (!cl_s)
++                      return -ENOMEM;
++              i = 0; // the i'th udc
++              EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
++                 ebt_get_udc_positions, newinfo, repl->hook_entry, &i,
++                 repl->valid_hooks, cl_s);
++              // sanity check
++              if (i != udc_cnt) {
++                      BUGPRINT("i != udc_cnt\n");
++                      vfree(cl_s);
++                      return -EFAULT;
++              }
++      }
 +
-+static int ebt_limit_match(const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, const void *data, unsigned int datalen)
-+{
-+      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
-+      unsigned long now = jiffies;
++      // Check for loops
++      for (i = 0; i < NF_BR_NUMHOOKS; i++)
++              if (repl->valid_hooks & (1 << i))
++                      if (check_chainloops(newinfo->hook_entry[i],
++                         cl_s, udc_cnt, i, newinfo->entries)) {
++                              if (cl_s)
++                                      vfree(cl_s);
++                              return -EINVAL;
++                      }
 +
-+      spin_lock_bh(&limit_lock);
-+      info->credit += (now - xchg(&info->prev, now)) * CREDITS_PER_JIFFY;
-+      if (info->credit > info->credit_cap)
-+              info->credit = info->credit_cap;
++      // we now know the following (along with E=mc):
++      // - the nr of entries in each chain is right
++      // - the size of the allocated space is right
++      // - all valid hooks have a corresponding chain
++      // - there are no loops
++      // - wrong data can still be on the level of a single entry
++      // - could be there are jumps to places that are not the
++      //   beginning of a chain. This can only occur in chains that
++      //   are not accessible from any base chains, so we don't care.
 +
-+      if (info->credit >= info->cost) {
-+              /* We're not limited. */
-+              info->credit -= info->cost;
-+              spin_unlock_bh(&limit_lock);
-+              return EBT_MATCH;
++      // used to know what we need to clean up if something goes wrong
++      i = 0;
++      ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
++         ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks,
++         cl_s, udc_cnt);
++      if (ret != 0) {
++              EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
++                 ebt_cleanup_entry, &i);
 +      }
-+
-+      spin_unlock_bh(&limit_lock);
-+      return EBT_NOMATCH;
++      if (cl_s)
++              vfree(cl_s);
++      return ret;
 +}
 +
-+/* Precision saver. */
-+static u_int32_t
-+user2credits(u_int32_t user)
++// called under write_lock
++static void get_counters(struct ebt_counter *oldcounters,
++   struct ebt_counter *counters, unsigned int nentries)
 +{
-+      /* If multiplying would overflow... */
-+      if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
-+              /* Divide first. */
-+              return (user / EBT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
++      int i, cpu;
++      struct ebt_counter *counter_base;
 +
-+      return (user * HZ * CREDITS_PER_JIFFY) / EBT_LIMIT_SCALE;
++      // counters of cpu 0
++      memcpy(counters, oldcounters,
++         sizeof(struct ebt_counter) * nentries);
++      // add other counters to those of cpu 0
++      for (cpu = 1; cpu < smp_num_cpus; cpu++) {
++              counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
++              for (i = 0; i < nentries; i++) {
++                      counters[i].pcnt += counter_base[i].pcnt;
++                      counters[i].bcnt += counter_base[i].bcnt;
++              }
++      }
 +}
 +
-+static int ebt_limit_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
++// replace the table
++static int do_replace(void *user, unsigned int len)
 +{
-+      struct ebt_limit_info *info = (struct ebt_limit_info *)data;
++      int ret, i, countersize;
++      struct ebt_table_info *newinfo;
++      struct ebt_replace tmp;
++      struct ebt_table *t;
++      struct ebt_counter *counterstmp = NULL;
++      // used to be able to unlock earlier
++      struct ebt_table_info *table;
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info)))
-+              return -EINVAL;
++      if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
++              return -EFAULT;
 +
-+      /* Check for overflow. */
-+      if (info->burst == 0
-+          || user2credits(info->avg * info->burst) < user2credits(info->avg)) {
-+              printk("Overflow in ebt_limit: %u/%u\n",
-+                      info->avg, info->burst);
++      if (len != sizeof(tmp) + tmp.entries_size) {
++              BUGPRINT("Wrong len argument\n");
 +              return -EINVAL;
 +      }
 +
-+      /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */
-+      info->prev = jiffies;
-+      info->credit = user2credits(info->avg * info->burst);
-+      info->credit_cap = user2credits(info->avg * info->burst);
-+      info->cost = user2credits(info->avg);
-+      return 0;
-+}
++      if (tmp.entries_size == 0) {
++              BUGPRINT("Entries_size never zero\n");
++              return -EINVAL;
++      }
++      countersize = COUNTER_OFFSET(tmp.nentries) * smp_num_cpus;
++      newinfo = (struct ebt_table_info *)
++         vmalloc(sizeof(struct ebt_table_info) + countersize);
++      if (!newinfo)
++              return -ENOMEM;
 +
-+static struct ebt_match ebt_limit_reg =
-+{
-+      {NULL, NULL}, EBT_LIMIT_MATCH, ebt_limit_match, ebt_limit_check, NULL,
-+      THIS_MODULE
-+};
++      if (countersize)
++              memset(newinfo->counters, 0, countersize);
 +
-+static int __init init(void)
-+{
-+      return ebt_register_match(&ebt_limit_reg);
-+}
++      newinfo->entries = (char *)vmalloc(tmp.entries_size);
++      if (!newinfo->entries) {
++              ret = -ENOMEM;
++              goto free_newinfo;
++      }
++      if (copy_from_user(
++         newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
++              BUGPRINT("Couldn't copy entries from userspace\n");
++              ret = -EFAULT;
++              goto free_entries;
++      }
 +
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&ebt_limit_reg);
-+}
++      // the user wants counters back
++      // the check on the size is done later, when we have the lock
++      if (tmp.num_counters) {
++              counterstmp = (struct ebt_counter *)
++                 vmalloc(tmp.num_counters * sizeof(struct ebt_counter));
++              if (!counterstmp) {
++                      ret = -ENOMEM;
++                      goto free_entries;
++              }
++      }
++      else
++              counterstmp = NULL;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_log.c linux-ebtables/net/bridge/netfilter/ebt_log.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_log.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_log.c      2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,153 @@
-+/*
-+ *  ebt_log
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  April, 2002
-+ *
-+ */
++      // this can get initialized by translate_table()
++      newinfo->chainstack = NULL;
++      ret = translate_table(&tmp, newinfo);
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_log.h>
-+#include <linux/module.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/if_arp.h>
-+#include <linux/spinlock.h>
++      if (ret != 0)
++              goto free_counterstmp;
 +
-+static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED;
++      t = find_table_lock(tmp.name, &ret, &ebt_mutex);
++      if (!t)
++              goto free_iterate;
 +
-+static int ebt_log_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
++      // the table doesn't like it
++      if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
++              goto free_unlock;
++
++      if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
++              BUGPRINT("Wrong nr. of counters requested\n");
++              ret = -EINVAL;
++              goto free_unlock;
++      }
++
++      // we have the mutex lock, so no danger in reading this pointer
++      table = t->private;
++      // we need an atomic snapshot of the counters
++      write_lock_bh(&t->lock);
++      if (tmp.num_counters)
++              get_counters(t->private->counters, counterstmp,
++                 t->private->nentries);
++
++      t->private = newinfo;
++      write_unlock_bh(&t->lock);
++      up(&ebt_mutex);
++      // So, a user can change the chains while having messed up her counter
++      // allocation. Only reason why this is done is because this way the lock
++      // is held only once, while this doesn't bring the kernel into a
++      // dangerous state.
++      if (tmp.num_counters &&
++         copy_to_user(tmp.counters, counterstmp,
++         tmp.num_counters * sizeof(struct ebt_counter))) {
++              BUGPRINT("Couldn't copy counters to userspace\n");
++              ret = -EFAULT;
++      }
++      else
++              ret = 0;
++
++      // decrease module count and free resources
++      EBT_ENTRY_ITERATE(table->entries, table->entries_size,
++         ebt_cleanup_entry, NULL);
++
++      vfree(table->entries);
++      if (table->chainstack) {
++              for (i = 0; i < smp_num_cpus; i++)
++                      vfree(table->chainstack[i]);
++              vfree(table->chainstack);
++      }
++      vfree(table);
++
++      if (counterstmp)
++              vfree(counterstmp);
++      return ret;
++
++free_unlock:
++      up(&ebt_mutex);
++free_iterate:
++      EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
++         ebt_cleanup_entry, NULL);
++free_counterstmp:
++      if (counterstmp)
++              vfree(counterstmp);
++      // can be initialized in translate_table()
++      if (newinfo->chainstack) {
++              for (i = 0; i < smp_num_cpus; i++)
++                      vfree(newinfo->chainstack[i]);
++              vfree(newinfo->chainstack);
++      }
++free_entries:
++      if (newinfo->entries)
++              vfree(newinfo->entries);
++free_newinfo:
++      if (newinfo)
++              vfree(newinfo);
++      return ret;
++}
++
++int ebt_register_target(struct ebt_target *target)
 +{
-+      struct ebt_log_info *info = (struct ebt_log_info *)data;
++      int ret;
++
++      ret = down_interruptible(&ebt_mutex);
++      if (ret != 0)
++              return ret;
++      if (!list_named_insert(&ebt_targets, target)) {
++              up(&ebt_mutex);
++              return -EEXIST;
++      }
++      up(&ebt_mutex);
++      MOD_INC_USE_COUNT;
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
-+              return -EINVAL;
-+      if (info->bitmask & ~EBT_LOG_MASK)
-+              return -EINVAL;
-+      if (info->loglevel >= 8)
-+              return -EINVAL;
-+      info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
 +      return 0;
 +}
 +
-+struct tcpudphdr
++void ebt_unregister_target(struct ebt_target *target)
 +{
-+      uint16_t src;
-+      uint16_t dst;
-+};
++      down(&ebt_mutex);
++      LIST_DELETE(&ebt_targets, target);
++      up(&ebt_mutex);
++      MOD_DEC_USE_COUNT;
++}
 +
-+struct arppayload
++int ebt_register_match(struct ebt_match *match)
 +{
-+      unsigned char mac_src[ETH_ALEN];
-+      unsigned char ip_src[4];
-+      unsigned char mac_dst[ETH_ALEN];
-+      unsigned char ip_dst[4];
-+};
++      int ret;
 +
-+static void print_MAC(unsigned char *p)
-+{
-+      int i;
++      ret = down_interruptible(&ebt_mutex);
++      if (ret != 0)
++              return ret;
++      if (!list_named_insert(&ebt_matches, match)) {
++              up(&ebt_mutex);
++              return -EEXIST;
++      }
++      up(&ebt_mutex);
++      MOD_INC_USE_COUNT;
 +
-+      for (i = 0; i < ETH_ALEN; i++, p++)
-+              printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
++      return 0;
 +}
 +
-+#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
-+static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
++void ebt_unregister_match(struct ebt_match *match)
 +{
-+      struct ebt_log_info *info = (struct ebt_log_info *)data;
-+      char level_string[4] = "< >";
-+      level_string[1] = '0' + info->loglevel;
++      down(&ebt_mutex);
++      LIST_DELETE(&ebt_matches, match);
++      up(&ebt_mutex);
++      MOD_DEC_USE_COUNT;
++}
 +
-+      spin_lock_bh(&ebt_log_lock);
-+      printk(level_string);
-+      printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
-+         out ? out->name : "");
++int ebt_register_watcher(struct ebt_watcher *watcher)
++{
++      int ret;
 +
-+      printk("MAC source = ");
-+      print_MAC((skb->mac.ethernet)->h_source);
-+      printk("MAC dest = ");
-+      print_MAC((skb->mac.ethernet)->h_dest);
++      ret = down_interruptible(&ebt_mutex);
++      if (ret != 0)
++              return ret;
++      if (!list_named_insert(&ebt_watchers, watcher)) {
++              up(&ebt_mutex);
++              return -EEXIST;
++      }
++      up(&ebt_mutex);
++      MOD_INC_USE_COUNT;
 +
-+      printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
++      return 0;
++}
 +
-+      if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
-+         htons(ETH_P_IP)){
-+              struct iphdr *iph = skb->nh.iph;
-+              printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
-+                 NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
-+              printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol);
-+              if (iph->protocol == IPPROTO_TCP ||
-+                  iph->protocol == IPPROTO_UDP) {
-+                      struct tcpudphdr *ports = (struct tcpudphdr *)(skb->data + iph->ihl*4);
++void ebt_unregister_watcher(struct ebt_watcher *watcher)
++{
++      down(&ebt_mutex);
++      LIST_DELETE(&ebt_watchers, watcher);
++      up(&ebt_mutex);
++      MOD_DEC_USE_COUNT;
++}
 +
-+                      if (skb->data + iph->ihl*4 > skb->tail) {
-+                              printk(" INCOMPLETE TCP/UDP header");
-+                              goto out;
-+                      }
-+                      printk(" SPT=%u DPT=%u", ntohs(ports->src),
-+                         ntohs(ports->dst));
-+              }
-+              goto out;
++int ebt_register_table(struct ebt_table *table)
++{
++      struct ebt_table_info *newinfo;
++      int ret, i, countersize;
++
++      if (!table || !table->table ||!table->table->entries ||
++          table->table->entries_size == 0 ||
++          table->table->counters || table->private) {
++              BUGPRINT("Bad table data for ebt_register_table!!!\n");
++              return -EINVAL;
 +      }
 +
-+      if ((info->bitmask & EBT_LOG_ARP) &&
-+          ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
-+          (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
-+              struct arphdr * arph = skb->nh.arph;
-+              printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
-+                 ntohs(arph->ar_hrd), ntohs(arph->ar_pro),
-+                 ntohs(arph->ar_op));
-+              /* If it's for Ethernet and the lengths are OK,
-+               * then log the ARP payload */
-+              if (arph->ar_hrd == __constant_htons(1) &&
-+                  arph->ar_hln == ETH_ALEN &&
-+                  arph->ar_pln == sizeof(uint32_t)) {
-+                      struct arppayload *arpp = (struct arppayload *)(skb->data + sizeof(*arph));
++      countersize = COUNTER_OFFSET(table->table->nentries) * smp_num_cpus;
++      newinfo = (struct ebt_table_info *)
++         vmalloc(sizeof(struct ebt_table_info) + countersize);
++      ret = -ENOMEM;
++      if (!newinfo)
++              return -ENOMEM;
 +
-+                      if (skb->data + sizeof(*arph) > skb->tail) {
-+                              printk(" INCOMPLETE ARP header");
-+                              goto out;
-+                      }
++      newinfo->entries = (char *)vmalloc(table->table->entries_size);
++      if (!(newinfo->entries))
++              goto free_newinfo;
 +
-+                      printk(" ARP MAC SRC=");
-+                      print_MAC(arpp->mac_src);
-+                      printk(" ARP IP SRC=%u.%u.%u.%u",
-+                             myNIPQUAD(arpp->ip_src));
-+                      printk(" ARP MAC DST=");
-+                      print_MAC(arpp->mac_dst);
-+                      printk(" ARP IP DST=%u.%u.%u.%u",
-+                             myNIPQUAD(arpp->ip_dst));
-+              }
++      memcpy(newinfo->entries, table->table->entries,
++         table->table->entries_size);
++
++      if (countersize)
++              memset(newinfo->counters, 0, countersize);
 +
++      // fill in newinfo and parse the entries
++      newinfo->chainstack = NULL;
++      ret = translate_table(table->table, newinfo);
++      if (ret != 0) {
++              BUGPRINT("Translate_table failed\n");
++              goto free_chainstack;
 +      }
-+out:
-+      printk("\n");
-+      spin_unlock_bh(&ebt_log_lock);
++
++      if (table->check && table->check(newinfo, table->valid_hooks)) {
++              BUGPRINT("The table doesn't like its own initial data, lol\n");
++              return -EINVAL;
++      }
++
++      table->private = newinfo;
++      table->lock = RW_LOCK_UNLOCKED;
++      ret = down_interruptible(&ebt_mutex);
++      if (ret != 0)
++              goto free_chainstack;
++
++      if (list_named_find(&ebt_tables, table->name)) {
++              ret = -EEXIST;
++              BUGPRINT("Table name already exists\n");
++              goto free_unlock;
++      }
++
++      list_prepend(&ebt_tables, table);
++      up(&ebt_mutex);
++      MOD_INC_USE_COUNT;
++      return 0;
++free_unlock:
++      up(&ebt_mutex);
++free_chainstack:
++      if (newinfo->chainstack) {
++              for (i = 0; i < smp_num_cpus; i++)
++                      vfree(newinfo->chainstack[i]);
++              vfree(newinfo->chainstack);
++      }
++      vfree(newinfo->entries);
++free_newinfo:
++      vfree(newinfo);
++      return ret;
 +}
 +
-+static struct ebt_watcher log =
++void ebt_unregister_table(struct ebt_table *table)
 +{
-+      {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL,
-+      THIS_MODULE
-+};
++      int i;
 +
-+static int __init init(void)
-+{
-+      return ebt_register_watcher(&log);
++      if (!table) {
++              BUGPRINT("Request to unregister NULL table!!!\n");
++              return;
++      }
++      down(&ebt_mutex);
++      LIST_DELETE(&ebt_tables, table);
++      up(&ebt_mutex);
++      EBT_ENTRY_ITERATE(table->private->entries,
++         table->private->entries_size, ebt_cleanup_entry, NULL);
++      if (table->private->entries)
++              vfree(table->private->entries);
++      if (table->private->chainstack) {
++              for (i = 0; i < smp_num_cpus; i++)
++                      vfree(table->private->chainstack[i]);
++              vfree(table->private->chainstack);
++      }
++      vfree(table->private);
++      MOD_DEC_USE_COUNT;
 +}
 +
-+static void __exit fini(void)
++// userspace just supplied us with counters
++static int update_counters(void *user, unsigned int len)
 +{
-+      ebt_unregister_watcher(&log);
-+}
++      int i, ret;
++      struct ebt_counter *tmp;
++      struct ebt_replace hlp;
++      struct ebt_table *t;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_mark.c linux-ebtables/net/bridge/netfilter/ebt_mark.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_mark.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_mark.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,66 @@
-+/*
-+ *  ebt_mark
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  July, 2002
-+ *
-+ */
++      if (copy_from_user(&hlp, user, sizeof(hlp)))
++              return -EFAULT;
 +
-+// The mark target can be used in any chain
-+// I believe adding a mangle table just for marking is total overkill
-+// Marking a frame doesn't really change anything in the frame anyway
++      if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
++              return -EINVAL;
++      if (hlp.num_counters == 0)
++              return -EINVAL;
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_mark_t.h>
-+#include <linux/module.h>
++      if ( !(tmp = (struct ebt_counter *)
++         vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){
++              MEMPRINT("Update_counters && nomemory\n");
++              return -ENOMEM;
++      }
 +
-+static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
-+{
-+      struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++      t = find_table_lock(hlp.name, &ret, &ebt_mutex);
++      if (!t)
++              goto free_tmp;
 +
-+      if ((*pskb)->nfmark != info->mark) {
-+              (*pskb)->nfmark = info->mark;
-+              (*pskb)->nfcache |= NFC_ALTERED;
++      if (hlp.num_counters != t->private->nentries) {
++              BUGPRINT("Wrong nr of counters\n");
++              ret = -EINVAL;
++              goto unlock_mutex;
 +      }
-+      return info->target;
-+}
 +
-+static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
++      if ( copy_from_user(tmp, hlp.counters,
++         hlp.num_counters * sizeof(struct ebt_counter)) ) {
++              BUGPRINT("Updata_counters && !cfu\n");
++              ret = -EFAULT;
++              goto unlock_mutex;
++      }
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
-+              return -EINVAL;
-+      if (BASE_CHAIN && info->target == EBT_RETURN)
-+              return -EINVAL;
-+      CLEAR_BASE_CHAIN_BIT;
-+      if (INVALID_TARGET)
-+              return -EINVAL;
-+      return 0;
++      // we want an atomic add of the counters
++      write_lock_bh(&t->lock);
++
++      // we add to the counters of the first cpu
++      for (i = 0; i < hlp.num_counters; i++) {
++              t->private->counters[i].pcnt += tmp[i].pcnt;
++              t->private->counters[i].bcnt += tmp[i].bcnt;
++      }
++
++      write_unlock_bh(&t->lock);
++      ret = 0;
++unlock_mutex:
++      up(&ebt_mutex);
++free_tmp:
++      vfree(tmp);
++      return ret;
 +}
 +
-+static struct ebt_target mark_target =
++static inline int ebt_make_matchname(struct ebt_entry_match *m,
++   char *base, char *ubase)
 +{
-+      {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark,
-+      ebt_target_mark_check, NULL, THIS_MODULE
-+};
++      char *hlp = ubase - base + (char *)m;
++      if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
++              return -EFAULT;
++      return 0;
++}
 +
-+static int __init init(void)
++static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
++   char *base, char *ubase)
 +{
-+      return ebt_register_target(&mark_target);
++      char *hlp = ubase - base + (char *)w;
++      if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
++              return -EFAULT;
++      return 0;
 +}
 +
-+static void __exit fini(void)
++static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
 +{
-+      ebt_unregister_target(&mark_target);
-+}
++      int ret;
++      char *hlp;
++      struct ebt_entry_target *t;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_mark_m.c linux-ebtables/net/bridge/netfilter/ebt_mark_m.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_mark_m.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_mark_m.c   2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,61 @@
-+/*
-+ *  ebt_mark_m
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  July, 2002
-+ *
-+ */
++      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
++              return 0;
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_mark_m.h>
-+#include <linux/module.h>
++      hlp = ubase - base + (char *)e + e->target_offset;
++      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
++      
++      ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
++      if (ret != 0)
++              return ret;
++      ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
++      if (ret != 0)
++              return ret;
++      if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
++              return -EFAULT;
++      return 0;
++}
 +
-+static int ebt_filter_mark(const struct sk_buff *skb,
-+   const struct net_device *in, const struct net_device *out, const void *data,
-+   unsigned int datalen)
++// called with ebt_mutex down
++static int copy_everything_to_user(struct ebt_table *t, void *user,
++   int *len, int cmd)
 +{
-+      struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++      struct ebt_replace tmp;
++      struct ebt_counter *counterstmp, *oldcounters;
++      unsigned int entries_size, nentries;
++      char *entries;
 +
-+      if (info->bitmask & EBT_MARK_OR)
-+              return !(!!(skb->nfmark & info->mask) ^ info->invert);
-+      return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
-+}
++      if (cmd == EBT_SO_GET_ENTRIES) {
++              entries_size = t->private->entries_size;
++              nentries = t->private->nentries;
++              entries = t->private->entries;
++              oldcounters = t->private->counters;
++      } else {
++              entries_size = t->table->entries_size;
++              nentries = t->table->nentries;
++              entries = t->table->entries;
++              oldcounters = t->table->counters;
++      }
 +
-+static int ebt_mark_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+        struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
++      if (copy_from_user(&tmp, user, sizeof(tmp))) {
++              BUGPRINT("Cfu didn't work\n");
++              return -EFAULT;
++      }
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
-+              return -EINVAL;
-+      if (info->bitmask & ~EBT_MARK_MASK)
++      if (*len != sizeof(struct ebt_replace) + entries_size +
++         (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
++              BUGPRINT("Wrong size\n");
 +              return -EINVAL;
-+      if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
++      }
++
++      if (tmp.nentries != nentries) {
++              BUGPRINT("Nentries wrong\n");
 +              return -EINVAL;
-+      if (!info->bitmask)
++      }
++
++      if (tmp.entries_size != entries_size) {
++              BUGPRINT("Wrong size\n");
 +              return -EINVAL;
-+      return 0;
++      }
++
++      // userspace might not need the counters
++      if (tmp.num_counters) {
++              if (tmp.num_counters != nentries) {
++                      BUGPRINT("Num_counters wrong\n");
++                      return -EINVAL;
++              }
++              counterstmp = (struct ebt_counter *)
++                 vmalloc(nentries * sizeof(struct ebt_counter));
++              if (!counterstmp) {
++                      MEMPRINT("Couldn't copy counters, out of memory\n");
++                      return -ENOMEM;
++              }
++              write_lock_bh(&t->lock);
++              get_counters(oldcounters, counterstmp, nentries);
++              write_unlock_bh(&t->lock);
++
++              if (copy_to_user(tmp.counters, counterstmp,
++                 nentries * sizeof(struct ebt_counter))) {
++                      BUGPRINT("Couldn't copy counters to userspace\n");
++                      vfree(counterstmp);
++                      return -EFAULT;
++              }
++              vfree(counterstmp);
++      }
++
++      if (copy_to_user(tmp.entries, entries, entries_size)) {
++              BUGPRINT("Couldn't copy entries to userspace\n");
++              return -EFAULT;
++      }
++      // set the match/watcher/target names right
++      return EBT_ENTRY_ITERATE(entries, entries_size,
++         ebt_make_names, entries, tmp.entries);
 +}
 +
-+static struct ebt_match filter_mark =
++static int do_ebt_set_ctl(struct sock *sk,
++      int cmd, void *user, unsigned int len)
 +{
-+      {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL,
-+      THIS_MODULE
-+};
++      int ret;
 +
-+static int __init init(void)
-+{
-+      return ebt_register_match(&filter_mark);
++      switch(cmd) {
++      case EBT_SO_SET_ENTRIES:
++              ret = do_replace(user, len);
++              break;
++      case EBT_SO_SET_COUNTERS:
++              ret = update_counters(user, len);
++              break;
++      default:
++              ret = -EINVAL;
++  }
++      return ret;
 +}
 +
-+static void __exit fini(void)
++static int do_ebt_get_ctl(struct sock *sk, int cmd, void *user, int *len)
 +{
-+      ebt_unregister_match(&filter_mark);
-+}
++      int ret;
++      struct ebt_replace tmp;
++      struct ebt_table *t;
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_pkttype.c linux-ebtables/net/bridge/netfilter/ebt_pkttype.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_pkttype.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_pkttype.c  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,60 @@
-+/*
-+ *  ebt_pkttype
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bdschuym@pandora.be>
-+ *
-+ *  April, 2003
-+ *
-+ */
++      if (copy_from_user(&tmp, user, sizeof(tmp)))
++              return -EFAULT;
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_pkttype.h>
-+#include <linux/module.h>
++      t = find_table_lock(tmp.name, &ret, &ebt_mutex);
++      if (!t)
++              return ret;
 +
-+static int ebt_filter_pkttype(const struct sk_buff *skb,
-+   const struct net_device *in,
-+   const struct net_device *out,
-+   const void *data,
-+   unsigned int datalen)
-+{
-+      struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++      switch(cmd) {
++      case EBT_SO_GET_INFO:
++      case EBT_SO_GET_INIT_INFO:
++              if (*len != sizeof(struct ebt_replace)){
++                      ret = -EINVAL;
++                      up(&ebt_mutex);
++                      break;
++              }
++              if (cmd == EBT_SO_GET_INFO) {
++                      tmp.nentries = t->private->nentries;
++                      tmp.entries_size = t->private->entries_size;
++                      tmp.valid_hooks = t->valid_hooks;
++              } else {
++                      tmp.nentries = t->table->nentries;
++                      tmp.entries_size = t->table->entries_size;
++                      tmp.valid_hooks = t->table->valid_hooks;
++              }
++              up(&ebt_mutex);
++              if (copy_to_user(user, &tmp, *len) != 0){
++                      BUGPRINT("c2u Didn't work\n");
++                      ret = -EFAULT;
++                      break;
++              }
++              ret = 0;
++              break;
 +
-+      return (skb->pkt_type != info->pkt_type) ^ info->invert;
-+}
++      case EBT_SO_GET_ENTRIES:
++      case EBT_SO_GET_INIT_ENTRIES:
++              ret = copy_everything_to_user(t, user, len, cmd);
++              up(&ebt_mutex);
++              break;
 +
-+static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
++      default:
++              up(&ebt_mutex);
++              ret = -EINVAL;
++      }
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
-+              return -EINVAL;
-+      if (info->invert != 0 && info->invert != 1)
-+              return -EINVAL;
-+      /* Allow any pkt_type value */
-+      return 0;
++      return ret;
 +}
 +
-+static struct ebt_match filter_pkttype =
-+{
-+      .name           = EBT_PKTTYPE_MATCH,
-+      .match          = ebt_filter_pkttype,
-+      .check          = ebt_pkttype_check,
-+      .me             = THIS_MODULE,
++static struct nf_sockopt_ops ebt_sockopts =
++{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl,
++    EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL
 +};
 +
 +static int __init init(void)
 +{
-+      return ebt_register_match(&filter_pkttype);
++      int ret;
++
++      down(&ebt_mutex);
++      list_named_insert(&ebt_targets, &ebt_standard_target);
++      up(&ebt_mutex);
++      if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
++              return ret;
++
++      printk(KERN_NOTICE "Ebtables v2.0 registered\n");
++      return 0;
 +}
 +
 +static void __exit fini(void)
 +{
-+      ebt_unregister_match(&filter_pkttype);
++      nf_unregister_sockopt(&ebt_sockopts);
++      printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
 +}
 +
++EXPORT_SYMBOL(ebt_register_table);
++EXPORT_SYMBOL(ebt_unregister_table);
++EXPORT_SYMBOL(ebt_register_match);
++EXPORT_SYMBOL(ebt_unregister_match);
++EXPORT_SYMBOL(ebt_register_watcher);
++EXPORT_SYMBOL(ebt_unregister_watcher);
++EXPORT_SYMBOL(ebt_register_target);
++EXPORT_SYMBOL(ebt_unregister_target);
++EXPORT_SYMBOL(ebt_do_table);
 +module_init(init);
 +module_exit(fini);
-+EXPORT_NO_SYMBOLS;
 +MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_redirect.c linux-ebtables/net/bridge/netfilter/ebt_redirect.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_redirect.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_redirect.c 2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,71 @@
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebtables.h    2005-03-14 21:24:12.000000000 +0100
+@@ -0,0 +1,361 @@
 +/*
-+ *  ebt_redirect
++ *  ebtables
 + *
 + *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *    Bart De Schuymer                <bart.de.schuymer@pandora.be>
 + *
-+ *  April, 2002
++ *  ebtables.c,v 2.0, September, 2002
 + *
++ *  This code is stongly inspired on the iptables code which is
++ *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
 + */
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_redirect.h>
-+#include <linux/module.h>
-+#include <net/sock.h>
-+#include "../br_private.h"
++#ifndef __LINUX_BRIDGE_EFF_H
++#define __LINUX_BRIDGE_EFF_H
++#include <linux/if.h>
++#include <linux/netfilter_bridge.h>
++#include <linux/if_ether.h>
 +
-+static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
-+{
-+      struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
++#define EBT_TABLE_MAXNAMELEN 32
++#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
++#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
 +
-+      if (hooknr != NF_BR_BROUTING)
-+              memcpy((**pskb).mac.ethernet->h_dest,
-+                 in->br_port->br->dev.dev_addr, ETH_ALEN);
-+      else {
-+              memcpy((**pskb).mac.ethernet->h_dest,
-+                 in->dev_addr, ETH_ALEN);
-+              (*pskb)->pkt_type = PACKET_HOST;
-+      }
-+      return info->target;
-+}
++// verdicts >0 are "branches"
++#define EBT_ACCEPT   -1
++#define EBT_DROP     -2
++#define EBT_CONTINUE -3
++#define EBT_RETURN   -4
++#define NUM_STANDARD_TARGETS   4
 +
-+static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
++struct ebt_counter
 +{
-+      struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
++      uint64_t pcnt;
++      uint64_t bcnt;
++};
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
-+              return -EINVAL;
-+      if (BASE_CHAIN && info->target == EBT_RETURN)
-+              return -EINVAL;
-+      CLEAR_BASE_CHAIN_BIT;
-+      if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
-+           (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
-+              return -EINVAL;
-+      if (INVALID_TARGET)
-+              return -EINVAL;
-+      return 0;
-+}
++struct ebt_entries {
++      // this field is always set to zero
++      // See EBT_ENTRY_OR_ENTRIES.
++      // Must be same size as ebt_entry.bitmask
++      unsigned int distinguisher;
++      // the chain name
++      char name[EBT_CHAIN_MAXNAMELEN];
++      // counter offset for this chain
++      unsigned int counter_offset;
++      // one standard (accept, drop, return) per hook
++      int policy;
++      // nr. of entries
++      unsigned int nentries;
++      // entry list
++      char data[0];
++};
 +
-+static struct ebt_target redirect_target =
++// used for the bitmask of struct ebt_entry
++
++// This is a hack to make a difference between an ebt_entry struct and an
++// ebt_entries struct when traversing the entries from start to end.
++// Using this simplifies the code alot, while still being able to use
++// ebt_entries.
++// Contrary, iptables doesn't use something like ebt_entries and therefore uses
++// different techniques for naming the policy and such. So, iptables doesn't
++// need a hack like this.
++#define EBT_ENTRY_OR_ENTRIES 0x01
++// these are the normal masks
++#define EBT_NOPROTO 0x02
++#define EBT_802_3 0x04
++#define EBT_SOURCEMAC 0x08
++#define EBT_DESTMAC 0x10
++#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
++   | EBT_ENTRY_OR_ENTRIES)
++
++#define EBT_IPROTO 0x01
++#define EBT_IIN 0x02
++#define EBT_IOUT 0x04
++#define EBT_ISOURCE 0x8
++#define EBT_IDEST 0x10
++#define EBT_ILOGICALIN 0x20
++#define EBT_ILOGICALOUT 0x40
++#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
++   | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
++
++struct ebt_entry_match
 +{
-+      {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect,
-+      ebt_target_redirect_check, NULL, THIS_MODULE
++      union {
++              char name[EBT_FUNCTION_MAXNAMELEN];
++              struct ebt_match *match;
++      } u;
++      // size of data
++      unsigned int match_size;
++      unsigned char data[0];
 +};
 +
-+static int __init init(void)
++struct ebt_entry_watcher
 +{
-+      return ebt_register_target(&redirect_target);
-+}
++      union {
++              char name[EBT_FUNCTION_MAXNAMELEN];
++              struct ebt_watcher *watcher;
++      } u;
++      // size of data
++      unsigned int watcher_size;
++      unsigned char data[0];
++};
 +
-+static void __exit fini(void)
++struct ebt_entry_target
 +{
-+      ebt_unregister_target(&redirect_target);
-+}
++      union {
++              char name[EBT_FUNCTION_MAXNAMELEN];
++              struct ebt_target *target;
++      } u;
++      // size of data
++      unsigned int target_size;
++      unsigned char data[0];
++};
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_snat.c linux-ebtables/net/bridge/netfilter/ebt_snat.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_snat.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_snat.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,64 @@
-+/*
-+ *  ebt_snat
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  June, 2002
-+ *
-+ */
++#define EBT_STANDARD_TARGET "standard"
++struct ebt_standard_target
++{
++      struct ebt_entry_target target;
++      int verdict;
++};
 +
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_nat.h>
-+#include <linux/module.h>
++// one entry
++struct ebt_entry {
++      // this needs to be the first field
++      unsigned int bitmask;
++      unsigned int invflags;
++      uint16_t ethproto;
++      // the physical in-dev
++      char in[IFNAMSIZ];
++      // the logical in-dev
++      char logical_in[IFNAMSIZ];
++      // the physical out-dev
++      char out[IFNAMSIZ];
++      // the logical out-dev
++      char logical_out[IFNAMSIZ];
++      unsigned char sourcemac[ETH_ALEN];
++      unsigned char sourcemsk[ETH_ALEN];
++      unsigned char destmac[ETH_ALEN];
++      unsigned char destmsk[ETH_ALEN];
++      // sizeof ebt_entry + matches
++      unsigned int watchers_offset;
++      // sizeof ebt_entry + matches + watchers
++      unsigned int target_offset;
++      // sizeof ebt_entry + matches + watchers + target
++      unsigned int next_offset;
++      unsigned char elems[0];
++};
 +
-+static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
++struct ebt_replace
 +{
-+      struct ebt_nat_info *info = (struct ebt_nat_info *) data;
++      char name[EBT_TABLE_MAXNAMELEN];
++      unsigned int valid_hooks;
++      // nr of rules in the table
++      unsigned int nentries;
++      // total size of the entries
++      unsigned int entries_size;
++      // start of the chains
++      struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
++      // nr of counters userspace expects back
++      unsigned int num_counters;
++      // where the kernel will put the old counters
++      struct ebt_counter *counters;
++      char *entries;
++};
 +
-+      memcpy(((**pskb).mac.ethernet)->h_source, info->mac,
-+         ETH_ALEN * sizeof(unsigned char));
-+      return info->target;
-+}
++// [gs]etsockopt numbers
++#define EBT_BASE_CTL            128
 +
-+static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_nat_info *info = (struct ebt_nat_info *) data;
++#define EBT_SO_SET_ENTRIES      (EBT_BASE_CTL)
++#define EBT_SO_SET_COUNTERS     (EBT_SO_SET_ENTRIES+1)
++#define EBT_SO_SET_MAX          (EBT_SO_SET_COUNTERS+1)
 +
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
-+              return -EINVAL;
-+      if (BASE_CHAIN && info->target == EBT_RETURN)
-+              return -EINVAL;
-+      CLEAR_BASE_CHAIN_BIT;
-+      if (strcmp(tablename, "nat"))
-+              return -EINVAL;
-+      if (hookmask & ~(1 << NF_BR_POST_ROUTING))
-+              return -EINVAL;
-+      if (INVALID_TARGET)
-+              return -EINVAL;
-+      return 0;
-+}
++#define EBT_SO_GET_INFO         (EBT_BASE_CTL)
++#define EBT_SO_GET_ENTRIES      (EBT_SO_GET_INFO+1)
++#define EBT_SO_GET_INIT_INFO    (EBT_SO_GET_ENTRIES+1)
++#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
++#define EBT_SO_GET_MAX          (EBT_SO_GET_INIT_ENTRIES+1)
 +
-+static struct ebt_target snat =
-+{
-+      {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check,
-+      NULL, THIS_MODULE
-+};
++#ifdef __KERNEL__
 +
-+static int __init init(void)
-+{
-+      return ebt_register_target(&snat);
-+}
++// return values for match() functions
++#define EBT_MATCH 0
++#define EBT_NOMATCH 1
 +
-+static void __exit fini(void)
++struct ebt_match
 +{
-+      ebt_unregister_target(&snat);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_stp.c linux-ebtables/net/bridge/netfilter/ebt_stp.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_stp.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_stp.c      2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,191 @@
-+/*
-+ *  ebt_stp
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bdschuym@pandora.be>
-+ *    Stephen Hemminger <shemminger@osdl.org>
-+ *
-+ *  June, 2003
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_stp.h>
-+#include <linux/module.h>
-+
-+#define BPDU_TYPE_CONFIG 0
-+#define BPDU_TYPE_TCN 0x80
-+
-+struct stp_header {
-+      uint8_t dsap;
-+      uint8_t ssap;
-+      uint8_t ctrl;
-+      uint8_t pid;
-+      uint8_t vers;
-+      uint8_t type;
-+};
-+
-+struct stp_config_pdu {
-+      uint8_t flags;
-+      uint8_t root[8];
-+      uint8_t root_cost[4];
-+      uint8_t sender[8];
-+      uint8_t port[2];
-+      uint8_t msg_age[2];
-+      uint8_t max_age[2];
-+      uint8_t hello_time[2];
-+      uint8_t forward_delay[2];
++      struct list_head list;
++      const char name[EBT_FUNCTION_MAXNAMELEN];
++      // 0 == it matches
++      int (*match)(const struct sk_buff *skb, const struct net_device *in,
++         const struct net_device *out, const void *matchdata,
++         unsigned int datalen);
++      // 0 == let it in
++      int (*check)(const char *tablename, unsigned int hookmask,
++         const struct ebt_entry *e, void *matchdata, unsigned int datalen);
++      void (*destroy)(void *matchdata, unsigned int datalen);
++      struct module *me;
 +};
 +
-+#define NR16(p) (p[0] << 8 | p[1])
-+#define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
-+
-+static int ebt_filter_config(struct ebt_stp_info *info,
-+   struct stp_config_pdu *stpc)
++struct ebt_watcher
 +{
-+      struct ebt_stp_config_info *c;
-+      uint16_t v16;
-+      uint32_t v32;
-+      int verdict, i;
-+
-+      c = &info->config;
-+      if ((info->bitmask & EBT_STP_FLAGS) &&
-+          FWINV(c->flags != stpc->flags, EBT_STP_FLAGS))
-+              return EBT_NOMATCH;
-+      if (info->bitmask & EBT_STP_ROOTPRIO) {
-+              v16 = NR16(stpc->root);
-+              if (FWINV(v16 < c->root_priol ||
-+                  v16 > c->root_priou, EBT_STP_ROOTPRIO))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_ROOTADDR) {
-+              verdict = 0;
-+              for (i = 0; i < 6; i++)
-+                      verdict |= (stpc->root[2+i] ^ c->root_addr[i]) &
-+                                 c->root_addrmsk[i];
-+              if (FWINV(verdict != 0, EBT_STP_ROOTADDR))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_ROOTCOST) {
-+              v32 = NR32(stpc->root_cost);
-+              if (FWINV(v32 < c->root_costl ||
-+                  v32 > c->root_costu, EBT_STP_ROOTCOST))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_SENDERPRIO) {
-+              v16 = NR16(stpc->sender);
-+              if (FWINV(v16 < c->sender_priol ||
-+                  v16 > c->sender_priou, EBT_STP_SENDERPRIO))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_SENDERADDR) {
-+              verdict = 0;
-+              for (i = 0; i < 6; i++)
-+                      verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) &
-+                                 c->sender_addrmsk[i];
-+              if (FWINV(verdict != 0, EBT_STP_SENDERADDR))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_PORT) {
-+              v16 = NR16(stpc->port);
-+              if (FWINV(v16 < c->portl ||
-+                  v16 > c->portu, EBT_STP_PORT))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_MSGAGE) {
-+              v16 = NR16(stpc->msg_age);
-+              if (FWINV(v16 < c->msg_agel ||
-+                  v16 > c->msg_ageu, EBT_STP_MSGAGE))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_MAXAGE) {
-+              v16 = NR16(stpc->max_age);
-+              if (FWINV(v16 < c->max_agel ||
-+                  v16 > c->max_ageu, EBT_STP_MAXAGE))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_HELLOTIME) {
-+              v16 = NR16(stpc->hello_time);
-+              if (FWINV(v16 < c->hello_timel ||
-+                  v16 > c->hello_timeu, EBT_STP_HELLOTIME))
-+                      return EBT_NOMATCH;
-+      }
-+      if (info->bitmask & EBT_STP_FWDD) {
-+              v16 = NR16(stpc->forward_delay);
-+              if (FWINV(v16 < c->forward_delayl ||
-+                  v16 > c->forward_delayu, EBT_STP_FWDD))
-+                      return EBT_NOMATCH;
-+      }
-+      return EBT_MATCH;
-+}
++      struct list_head list;
++      const char name[EBT_FUNCTION_MAXNAMELEN];
++      void (*watcher)(const struct sk_buff *skb, unsigned int hooknr,
++         const struct net_device *in, const struct net_device *out,
++         const void *watcherdata, unsigned int datalen);
++      // 0 == let it in
++      int (*check)(const char *tablename, unsigned int hookmask,
++         const struct ebt_entry *e, void *watcherdata, unsigned int datalen);
++      void (*destroy)(void *watcherdata, unsigned int datalen);
++      struct module *me;
++};
 +
-+static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out, const void *data, unsigned int datalen)
++struct ebt_target
 +{
-+      struct ebt_stp_info *info = (struct ebt_stp_info *)data;
-+      struct stp_header stph;
-+      uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
-+      if (skb_copy_bits(skb, 0, &stph, sizeof(stph)))
-+              return EBT_NOMATCH;
-+
-+      /* The stp code only considers these */
-+      if (memcmp(&stph, header, sizeof(header)))
-+              return EBT_NOMATCH;
-+
-+      if (info->bitmask & EBT_STP_TYPE
-+          && FWINV(info->type != stph.type, EBT_STP_TYPE))
-+              return EBT_NOMATCH;
-+
-+      if (stph.type == BPDU_TYPE_CONFIG &&
-+          info->bitmask & EBT_STP_CONFIG_MASK) {
-+              struct stp_config_pdu stpc;
-+
-+              if (skb_copy_bits(skb, sizeof(stph), &stpc, sizeof(stpc)))
-+                  return EBT_NOMATCH;
-+              return ebt_filter_config(info, &stpc);
-+      }
-+      return EBT_MATCH;
-+}
++      struct list_head list;
++      const char name[EBT_FUNCTION_MAXNAMELEN];
++      // returns one of the standard verdicts
++      int (*target)(struct sk_buff **pskb, unsigned int hooknr,
++         const struct net_device *in, const struct net_device *out,
++         const void *targetdata, unsigned int datalen);
++      // 0 == let it in
++      int (*check)(const char *tablename, unsigned int hookmask,
++         const struct ebt_entry *e, void *targetdata, unsigned int datalen);
++      void (*destroy)(void *targetdata, unsigned int datalen);
++      struct module *me;
++};
 +
-+static int ebt_stp_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
++// used for jumping from and into user defined chains (udc)
++struct ebt_chainstack
 +{
-+      struct ebt_stp_info *info = (struct ebt_stp_info *)data;
-+      int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
-+      uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
-+      uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-+
-+      if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
-+          !(info->bitmask & EBT_STP_MASK))
-+              return -EINVAL;
-+      if (datalen != len)
-+              return -EINVAL;
-+      /* Make sure the match only receives stp frames */
-+      if (memcmp(e->destmac, bridge_ula, ETH_ALEN) ||
-+          memcmp(e->destmsk, msk, ETH_ALEN) || !(e->bitmask & EBT_DESTMAC))
-+              return -EINVAL;
-+
-+      return 0;
-+}
++      struct ebt_entries *chaininfo; // pointer to chain data
++      struct ebt_entry *e; // pointer to entry data
++      unsigned int n; // n'th entry
++};
 +
-+static struct ebt_match filter_stp =
++struct ebt_table_info
 +{
-+      .name           = EBT_STP_MATCH,
-+      .match          = ebt_filter_stp,
-+      .check          = ebt_stp_check,
-+      .me             = THIS_MODULE,
++      // total size of the entries
++      unsigned int entries_size;
++      unsigned int nentries;
++      // pointers to the start of the chains
++      struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
++      // room to maintain the stack used for jumping from and into udc
++      struct ebt_chainstack **chainstack;
++      char *entries;
++      struct ebt_counter counters[0] ____cacheline_aligned;
 +};
 +
-+static int __init init(void)
++struct ebt_table
 +{
-+      return ebt_register_match(&filter_stp);
-+}
++      struct list_head list;
++      char name[EBT_TABLE_MAXNAMELEN];
++      struct ebt_replace *table;
++      unsigned int valid_hooks;
++      rwlock_t lock;
++      // e.g. could be the table explicitly only allows certain
++      // matches, targets, ... 0 == let it in
++      int (*check)(const struct ebt_table_info *info,
++         unsigned int valid_hooks);
++      // the data used by the kernel
++      struct ebt_table_info *private;
++};
 +
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&filter_stp);
-+}
++#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_entry_target)-1)) & \
++                   ~(__alignof__(struct ebt_entry_target)-1))
++extern int ebt_register_table(struct ebt_table *table);
++extern void ebt_unregister_table(struct ebt_table *table);
++extern int ebt_register_match(struct ebt_match *match);
++extern void ebt_unregister_match(struct ebt_match *match);
++extern int ebt_register_watcher(struct ebt_watcher *watcher);
++extern void ebt_unregister_watcher(struct ebt_watcher *watcher);
++extern int ebt_register_target(struct ebt_target *target);
++extern void ebt_unregister_target(struct ebt_target *target);
++extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   struct ebt_table *table);
 +
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_ulog.c linux-ebtables/net/bridge/netfilter/ebt_ulog.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_ulog.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_ulog.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,281 @@
-+/*
-+ * netfilter module for userspace bridged Ethernet frames logging daemons
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bdschuym@pandora.be>
-+ *
-+ *  November, 2004
-+ *
-+ * Based on ipt_ULOG.c, which is
-+ * (C) 2000-2002 by Harald Welte <laforge@netfilter.org>
-+ *
-+ * This module accepts two parameters: 
-+ * 
-+ * nlbufsiz:
-+ *   The parameter specifies how big the buffer for each netlink multicast
-+ * group is. e.g. If you say nlbufsiz=8192, up to eight kb of packets will
-+ * get accumulated in the kernel until they are sent to userspace. It is
-+ * NOT possible to allocate more than 128kB, and it is strongly discouraged,
-+ * because atomically allocating 128kB inside the network rx softirq is not
-+ * reliable. Please also keep in mind that this buffer size is allocated for
-+ * each nlgroup you are using, so the total kernel memory usage increases
-+ * by that factor.
-+ *
-+ * flushtimeout:
-+ *   Specify, after how many hundredths of a second the queue should be
-+ *   flushed even if it is not full yet.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/config.h>
-+#include <linux/spinlock.h>
-+#include <linux/socket.h>
-+#include <linux/skbuff.h>
-+#include <linux/kernel.h>
-+#include <linux/timer.h>
-+#include <linux/netlink.h>
-+#include <linux/netdevice.h>
-+#include <linux/module.h>
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_ulog.h>
-+#include <net/sock.h>
-+#include "../br_private.h"
-+
-+#define PRINTR(format, args...)       do { if (net_ratelimit()) \
-+                                              printk(format , ## args); } while (0)
-+
-+static unsigned int nlbufsiz = 4096;
-+MODULE_PARM(nlbufsiz, "i");
-+MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
-+                           "(defaults to 4096)");
-+
-+static unsigned int flushtimeout = 10;
-+MODULE_PARM(flushtimeout, "i");
-+MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second) "
-+                               "(defaults to 10)");
-+
-+typedef struct {
-+      unsigned int qlen;              /* number of nlmsgs' in the skb */
-+      struct nlmsghdr *lastnlh;       /* netlink header of last msg in skb */
-+      struct sk_buff *skb;            /* the pre-allocated skb */
-+      struct timer_list timer;        /* the timer function */
-+      spinlock_t lock;                /* the per-queue lock */
-+} ebt_ulog_buff_t;
-+
-+static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS];
-+static struct sock *ebtlognl;
-+
-+/* send one ulog_buff_t to userspace */
-+static void ulog_send(unsigned int nlgroup)
-+{
-+      ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup];
-+
-+      if (timer_pending(&ub->timer))
-+              del_timer(&ub->timer);
-+
-+      /* last nlmsg needs NLMSG_DONE */
-+      if (ub->qlen > 1)
-+              ub->lastnlh->nlmsg_type = NLMSG_DONE;
-+
-+      NETLINK_CB(ub->skb).dst_groups = 1 << nlgroup;
-+      netlink_broadcast(ebtlognl, ub->skb, 0, 1 << nlgroup, GFP_ATOMIC);
-+
-+      ub->qlen = 0;
-+      ub->skb = NULL;
-+}
-+
-+/* timer function to flush queue in flushtimeout time */
-+static void ulog_timer(unsigned long data)
-+{
-+      spin_lock_bh(&ulog_buffers[data].lock);
-+      if (ulog_buffers[data].skb)
-+              ulog_send(data);
-+      spin_unlock_bh(&ulog_buffers[data].lock);
-+}
-+
-+static struct sk_buff *ulog_alloc_skb(unsigned int size)
-+{
-+      struct sk_buff *skb;
-+
-+      skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
-+      if (!skb) {
-+              PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
-+                     "of size %ub!\n", nlbufsiz);
-+              if (size < nlbufsiz) {
-+                      /* try to allocate only as much as we need for
-+                       * current packet */
-+                      skb = alloc_skb(size, GFP_ATOMIC);
-+                      if (!skb)
-+                              PRINTR(KERN_ERR "ebt_ulog: can't even allocate "
-+                                     "buffer of size %ub\n", size);
-+              }
-+      }
-+
-+      return skb;
-+}
-+
-+static void ebt_ulog(const struct sk_buff *skb, unsigned int hooknr,
-+   const struct net_device *in, const struct net_device *out,
-+   const void *data, unsigned int datalen)
-+{
-+      ebt_ulog_packet_msg_t *pm;
-+      size_t size, copy_len;
-+      struct nlmsghdr *nlh;
-+      struct ebt_ulog_info *loginfo = (struct ebt_ulog_info *)data;
-+      unsigned int group = loginfo->nlgroup;
-+      ebt_ulog_buff_t *ub = &ulog_buffers[group];
-+      spinlock_t *lock = &ub->lock;
-+
-+      if ((loginfo->cprange == 0) ||
-+          (loginfo->cprange > skb->len + ETH_HLEN))
-+              copy_len = skb->len + ETH_HLEN;
-+      else
-+              copy_len = loginfo->cprange;
-+
-+      size = NLMSG_SPACE(sizeof(*pm) + copy_len);
-+
-+      spin_lock_bh(lock);
-+
-+      if (!ub->skb) {
-+              if (!(ub->skb = ulog_alloc_skb(size)))
-+                      goto alloc_failure;
-+      } else if (size > skb_tailroom(ub->skb)) {
-+              ulog_send(group);
-+
-+              if (!(ub->skb = ulog_alloc_skb(size)))
-+                      goto alloc_failure;
-+      }
-+
-+      nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, 0,
-+                      size - NLMSG_ALIGN(sizeof(*nlh)));
-+      ub->qlen++;
-+
-+      pm = NLMSG_DATA(nlh);
-+
-+      /* Fill in the ulog data */
-+      do_gettimeofday(&pm->stamp);
-+      if (ub->qlen == 1)
-+              ub->skb->stamp = pm->stamp;
-+      pm->data_len = copy_len;
-+      pm->mark = skb->nfmark;
-+      pm->hook = hooknr;
-+      if (loginfo->prefix != NULL)
-+              strcpy(pm->prefix, loginfo->prefix);
-+      else
-+              *(pm->prefix) = '\0';
-+
-+      if (in) {
-+              strcpy(pm->physindev, in->name);
-+              strcpy(pm->indev, in->br_port->br->dev.name);
-+      } else
-+              pm->indev[0] = pm->physindev[0] = '\0';
-+
-+      if (out) {
-+              strcpy(pm->physoutdev, out->name);
-+              strcpy(pm->outdev, out->br_port->br->dev.name);
-+      } else
-+              pm->outdev[0] = pm->physoutdev[0] = '\0';
-+
-+      if (skb_copy_bits(skb, -ETH_HLEN, pm->data, copy_len) < 0)
-+              BUG();
-+
-+      if (ub->qlen > 1)
-+              ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
-+
-+      ub->lastnlh = nlh;
-+
-+      if (ub->qlen >= loginfo->qthreshold)
-+              ulog_send(group);
-+      else if (!timer_pending(&ub->timer)) {
-+              ub->timer.expires = jiffies + flushtimeout * HZ / 100;
-+              add_timer(&ub->timer);
-+      }
-+
-+unlock:
-+      spin_unlock_bh(lock);
-+
-+      return;
-+
-+nlmsg_failure:
-+      PRINTR(KERN_ERR "ebt_ULOG: error during NLMSG_PUT.\n");
-+      goto unlock;
-+alloc_failure:
-+      goto unlock;
-+}
-+
-+static int ebt_ulog_check(const char *tablename, unsigned int hookmask,
-+   const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_ulog_info *loginfo = (struct ebt_ulog_info *)data;
-+
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) ||
-+          loginfo->nlgroup > 31)
-+              return -EINVAL;
-+
-+      loginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0';
-+
-+      if (loginfo->qthreshold > EBT_ULOG_MAX_QLEN)
-+              loginfo->qthreshold = EBT_ULOG_MAX_QLEN;
-+
-+      return 0;
-+}
-+
-+static struct ebt_watcher ulog = {
-+      {NULL, NULL}, EBT_ULOG_WATCHER, ebt_ulog, ebt_ulog_check, NULL,
-+      THIS_MODULE
-+};
-+
-+static int __init init(void)
-+{
-+      int i, ret = 0;
-+
-+      if (nlbufsiz >= 128*1024) {
-+              printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
-+                     " please try a smaller nlbufsiz parameter.\n");
-+              return -EINVAL;
-+      }
-+
-+      /* initialize ulog_buffers */
-+      for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
-+              init_timer(&ulog_buffers[i].timer);
-+              ulog_buffers[i].timer.function = ulog_timer;
-+              ulog_buffers[i].timer.data = i;
-+              ulog_buffers[i].lock = SPIN_LOCK_UNLOCKED;
-+      }
-+
-+      ebtlognl = netlink_kernel_create(NETLINK_NFLOG, NULL);
-+      if (!ebtlognl)
-+              ret = -ENOMEM;
-+      else if ((ret = ebt_register_watcher(&ulog)))
-+              sock_release(ebtlognl->socket);
-+
-+      return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+      ebt_ulog_buff_t *ub;
-+      int i;
-+
-+      ebt_unregister_watcher(&ulog);
-+      for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) {
-+              ub = &ulog_buffers[i];
-+              if (timer_pending(&ub->timer))
-+                      del_timer(&ub->timer);
-+              spin_lock_bh(&ub->lock);
-+              if (ub->skb) {
-+                      kfree_skb(ub->skb);
-+                      ub->skb = NULL;
-+              }
-+              spin_unlock_bh(&ub->lock);
-+      }
-+      sock_release(ebtlognl->socket);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
-+MODULE_DESCRIPTION("ebtables userspace logging module for bridged Ethernet"
-+                   " frames");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebt_vlan.c linux-ebtables/net/bridge/netfilter/ebt_vlan.c
---- linux-mips-cvs/net/bridge/netfilter/ebt_vlan.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebt_vlan.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,259 @@
-+/*
-+ * Description: EBTables 802.1Q match extension kernelspace module.
-+ * Authors: Nick Fedchik <nick@fedchik.org.ua>
-+ *          Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *    
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ * 
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *  
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ */
-+
-+#include <linux/if_ether.h>
-+#include <linux/if_vlan.h>
-+#include <linux/module.h>
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/netfilter_bridge/ebt_vlan.h>
-+
-+static unsigned char debug;
-+#define MODULE_VERSION "0.6"
-+
-+MODULE_PARM(debug, "0-1b");
-+MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
-+MODULE_AUTHOR("Nick Fedchik <nick@fedchik.org.ua>");
-+MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
-+                 MODULE_VERSION);
-+MODULE_LICENSE("GPL");
-+
-+
-+#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
-+#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
-+#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
-+#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
-+#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1;
-+
-+/*
-+ * Function description: ebt_filter_vlan() is main engine for 
-+ * checking passed 802.1Q frame according to 
-+ * the passed extension parameters (in the *data buffer)
-+ * ebt_filter_vlan() is called after successfull check the rule params
-+ * by ebt_check_vlan() function.
-+ * Parameters:
-+ * const struct sk_buff *skb - pointer to passed ethernet frame buffer
-+ * const void *data - pointer to passed extension parameters
-+ * unsigned int datalen - length of passed *data buffer
-+ * const struct net_device *in  -
-+ * const struct net_device *out -
-+ * const struct ebt_counter *c -
-+ * Returned values:
-+ * 0 - ok (all rule params matched)
-+ * 1 - miss (rule params not acceptable to the parsed frame)
-+ */
-+static int
-+ebt_filter_vlan(const struct sk_buff *skb,
-+              const struct net_device *in,
-+              const struct net_device *out,
-+              const void *data, unsigned int datalen)
-+{
-+      struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;     /* userspace data */
-+      struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw;        /* Passed tagged frame */
-+
-+      unsigned short TCI;     /* Whole TCI, given from parsed frame */
-+      unsigned short id;      /* VLAN ID, given from frame TCI */
-+      unsigned char prio;     /* user_priority, given from frame TCI */
-+      unsigned short encap;   /* VLAN encapsulated Type/Length field, given from orig frame */
-+
-+      /*
-+       * Tag Control Information (TCI) consists of the following elements:
-+       * - User_priority. The user_priority field is three bits in length, 
-+       * interpreted as a binary number. 
-+       * - Canonical Format Indicator (CFI). The Canonical Format Indicator 
-+       * (CFI) is a single bit flag value. Currently ignored.
-+       * - VLAN Identifier (VID). The VID is encoded as 
-+       * an unsigned binary number. 
-+       */
-+      TCI = ntohs(frame->h_vlan_TCI);
-+      id = TCI & VLAN_VID_MASK;
-+      prio = (TCI >> 13) & 0x7;
-+      encap = frame->h_vlan_encapsulated_proto;
-+
-+      /*
-+       * Checking VLAN Identifier (VID)
-+       */
-+      if (GET_BITMASK(EBT_VLAN_ID)) { /* Is VLAN ID parsed? */
-+              EXIT_ON_MISMATCH(id, EBT_VLAN_ID);
-+      }
-+      /*
-+       * Checking user_priority
-+       */
-+      if (GET_BITMASK(EBT_VLAN_PRIO)) {       /* Is VLAN user_priority parsed? */
-+              EXIT_ON_MISMATCH(prio, EBT_VLAN_PRIO);
-+      }
-+      /*
-+       * Checking Encapsulated Proto (Length/Type) field
-+       */
-+      if (GET_BITMASK(EBT_VLAN_ENCAP)) {      /* Is VLAN Encap parsed? */
-+              EXIT_ON_MISMATCH(encap, EBT_VLAN_ENCAP);
-+      }
-+      /*
-+       * All possible extension parameters was parsed.
-+       * If rule never returned by missmatch, then all ok.
-+       */
-+      return 0;
-+}
-+
-+/*
-+ * Function description: ebt_vlan_check() is called when userspace 
-+ * delivers the table entry to the kernel, 
-+ * and to check that userspace doesn't give a bad table.
-+ * Parameters:
-+ * const char *tablename - table name string
-+ * unsigned int hooknr - hook number
-+ * const struct ebt_entry *e - ebtables entry basic set
-+ * const void *data - pointer to passed extension parameters
-+ * unsigned int datalen - length of passed *data buffer
-+ * Returned values:
-+ * 0 - ok (all delivered rule params are correct)
-+ * 1 - miss (rule params is out of range, invalid, incompatible, etc.)
-+ */
-+static int
-+ebt_check_vlan(const char *tablename,
-+             unsigned int hooknr,
-+             const struct ebt_entry *e, void *data, unsigned int datalen)
-+{
-+      struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
-+
-+      /*
-+       * Parameters buffer overflow check 
-+       */
-+      if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
-+              DEBUG_MSG
-+                  ("passed size %d is not eq to ebt_vlan_info (%d)\n",
-+                   datalen, sizeof(struct ebt_vlan_info));
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Is it 802.1Q frame checked?
-+       */
-+      if (e->ethproto != __constant_htons(ETH_P_8021Q)) {
-+              DEBUG_MSG
-+                  ("passed entry proto %2.4X is not 802.1Q (8100)\n",
-+                   (unsigned short) ntohs(e->ethproto));
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Check for bitmask range 
-+       * True if even one bit is out of mask
-+       */
-+      if (info->bitmask & ~EBT_VLAN_MASK) {
-+              DEBUG_MSG("bitmask %2X is out of mask (%2X)\n",
-+                        info->bitmask, EBT_VLAN_MASK);
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Check for inversion flags range 
-+       */
-+      if (info->invflags & ~EBT_VLAN_MASK) {
-+              DEBUG_MSG("inversion flags %2X is out of mask (%2X)\n",
-+                        info->invflags, EBT_VLAN_MASK);
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Reserved VLAN ID (VID) values
-+       * -----------------------------
-+       * 0 - The null VLAN ID. 
-+       * 1 - The default Port VID (PVID)
-+       * 0x0FFF - Reserved for implementation use. 
-+       * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096.
-+       */
-+      if (GET_BITMASK(EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */
-+              if (!!info->id) {       /* if id!=0 => check vid range */
-+                      if (info->id > VLAN_GROUP_ARRAY_LEN) {
-+                              DEBUG_MSG
-+                                  ("id %d is out of range (1-4096)\n",
-+                                   info->id);
-+                              return -EINVAL;
-+                      }
-+                      /*
-+                       * Note: This is valid VLAN-tagged frame point.
-+                       * Any value of user_priority are acceptable, 
-+                       * but should be ignored according to 802.1Q Std.
-+                       * So we just drop the prio flag. 
-+                       */
-+                      info->bitmask &= ~EBT_VLAN_PRIO;
-+              }
-+              /*
-+               * Else, id=0 (null VLAN ID)  => user_priority range (any?)
-+               */
-+      }
-+
-+      if (GET_BITMASK(EBT_VLAN_PRIO)) {
-+              if ((unsigned char) info->prio > 7) {
-+                      DEBUG_MSG
-+                          ("prio %d is out of range (0-7)\n",
-+                           info->prio);
-+                      return -EINVAL;
-+              }
-+      }
-+      /*
-+       * Check for encapsulated proto range - it is possible to be 
-+       * any value for u_short range.
-+       * if_ether.h:  ETH_ZLEN        60   -  Min. octets in frame sans FCS
-+       */
-+      if (GET_BITMASK(EBT_VLAN_ENCAP)) {
-+              if ((unsigned short) ntohs(info->encap) < ETH_ZLEN) {
-+                      DEBUG_MSG
-+                          ("encap frame length %d is less than minimal\n",
-+                           ntohs(info->encap));
-+                      return -EINVAL;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+static struct ebt_match filter_vlan = {
-+      {NULL, NULL},
-+      EBT_VLAN_MATCH,
-+      ebt_filter_vlan,
-+      ebt_check_vlan,
-+      NULL,
-+      THIS_MODULE
-+};
-+
-+/*
-+ * Module initialization function.
-+ */
-+static int __init init(void)
-+{
-+      DEBUG_MSG("ebtables 802.1Q extension module v"
-+                MODULE_VERSION "\n");
-+      DEBUG_MSG("module debug=%d\n", !!debug);
-+      return ebt_register_match(&filter_vlan);
-+}
-+
-+/*
-+ * Module "finalization" function
-+ */
-+static void __exit fini(void)
-+{
-+      ebt_unregister_match(&filter_vlan);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+EXPORT_NO_SYMBOLS;
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebtable_broute.c linux-ebtables/net/bridge/netfilter/ebtable_broute.c
---- linux-mips-cvs/net/bridge/netfilter/ebtable_broute.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebtable_broute.c       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,79 @@
-+/*
-+ *  ebtable_broute
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  April, 2002
-+ *
-+ *  This table lets you choose between routing and bridging for frames
-+ *  entering on a bridge enslaved nic. This table is traversed before any
-+ *  other ebtables table. See net/bridge/br_input.c.
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/module.h>
-+#include <linux/if_bridge.h>
-+#include <linux/brlock.h>
-+
-+// 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_replace initial_table =
-+{
-+  "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries),
-+  { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain
-+};
-+
-+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-+{
-+      if (valid_hooks & ~(1 << NF_BR_BROUTING))
-+              return -EINVAL;
-+      return 0;
-+}
-+
-+static struct ebt_table broute_table =
-+{
-+  {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING,
-+  RW_LOCK_UNLOCKED, check, NULL
-+};
-+
-+static int ebt_broute(struct sk_buff **pskb)
-+{
-+      int ret;
-+
-+      ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL,
-+         &broute_table);
-+      if (ret == NF_DROP)
-+              return 1; // route it
-+      return 0; // bridge it
-+}
-+
-+static int __init init(void)
-+{
-+      int ret;
-+
-+      ret = ebt_register_table(&broute_table);
-+      if (ret < 0)
-+              return ret;
-+      br_write_lock_bh(BR_NETPROTO_LOCK);
-+      // see br_input.c
-+      br_should_route_hook = ebt_broute;
-+      br_write_unlock_bh(BR_NETPROTO_LOCK);
-+      return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+      br_write_lock_bh(BR_NETPROTO_LOCK);
-+      br_should_route_hook = NULL;
-+      br_write_unlock_bh(BR_NETPROTO_LOCK);
-+      ebt_unregister_table(&broute_table);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebtable_filter.c linux-ebtables/net/bridge/netfilter/ebtable_filter.c
---- linux-mips-cvs/net/bridge/netfilter/ebtable_filter.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebtable_filter.c       2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,90 @@
-+/*
-+ *  ebtable_filter
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  April, 2002
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/module.h>
-+
-+#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
-+   (1 << NF_BR_LOCAL_OUT))
-+
-+static struct ebt_entries initial_chains[] =
-+{
-+  {0, "INPUT", 0, EBT_ACCEPT, 0},
-+  {0, "FORWARD", 0, EBT_ACCEPT, 0},
-+  {0, "OUTPUT", 0, EBT_ACCEPT, 0}
-+};
-+
-+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
-+};
-+
-+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-+{
-+      if (valid_hooks & ~FILTER_VALID_HOOKS)
-+              return -EINVAL;
-+      return 0;
-+}
-+
-+static struct ebt_table frame_filter =
-+{ 
-+  {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, 
-+  RW_LOCK_UNLOCKED, check, NULL
-+};
-+
-+static unsigned int
-+ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
-+   const struct net_device *out, int (*okfn)(struct sk_buff *))
-+{
-+      return ebt_do_table(hook, pskb, in, out, &frame_filter);
-+}
-+
-+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}
-+};
-+
-+static int __init init(void)
-+{
-+      int i, j, ret;
-+
-+      ret = ebt_register_table(&frame_filter);
-+      if (ret < 0)
-+              return ret;
-+      for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
-+              if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
-+                      goto cleanup;
-+      return ret;
-+cleanup:
-+      for (j = 0; j < i; j++)
-+              nf_unregister_hook(&ebt_ops_filter[j]);
-+      ebt_unregister_table(&frame_filter);
-+      return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+      int i;
-+
-+      for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
-+              nf_unregister_hook(&ebt_ops_filter[i]);
-+      ebt_unregister_table(&frame_filter);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebtable_nat.c linux-ebtables/net/bridge/netfilter/ebtable_nat.c
---- linux-mips-cvs/net/bridge/netfilter/ebtable_nat.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebtable_nat.c  2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,96 @@
-+/*
-+ *  ebtable_nat
-+ *
-+ *    Authors:
-+ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
-+ *
-+ *  April, 2002
-+ *
-+ */
-+
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/module.h>
-+#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
-+   (1 << NF_BR_POST_ROUTING))
-+
-+static struct ebt_entries initial_chains[] =
-+{
-+  {0, "PREROUTING", 0, EBT_ACCEPT, 0},
-+  {0, "OUTPUT", 0, EBT_ACCEPT, 0},
-+  {0, "POSTROUTING", 0, EBT_ACCEPT, 0}
-+};
-+
-+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
-+};
-+
-+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
-+{
-+      if (valid_hooks & ~NAT_VALID_HOOKS)
-+              return -EINVAL;
-+      return 0;
-+}
-+
-+static struct ebt_table frame_nat =
-+{
-+  {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS,
-+  RW_LOCK_UNLOCKED, check, NULL
-+};
-+
-+static unsigned int
-+ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
-+   , const struct net_device *out, int (*okfn)(struct sk_buff *))
-+{
-+      return ebt_do_table(hook, pskb, in, out, &frame_nat);
-+}
-+
-+static unsigned int
-+ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
-+   , const struct net_device *out, int (*okfn)(struct sk_buff *))
-+{
-+      return ebt_do_table(hook, pskb, in, out, &frame_nat);
-+}
-+
-+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},
-+};
-+
-+static int __init init(void)
-+{
-+      int i, ret, j;
-+
-+      ret = ebt_register_table(&frame_nat);
-+      if (ret < 0)
-+              return ret;
-+      for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
-+              if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
-+                      goto cleanup;
-+      return ret;
-+cleanup:
-+      for (j = 0; j < i; j++)
-+              nf_unregister_hook(&ebt_ops_nat[j]);
-+      ebt_unregister_table(&frame_nat);
-+      return ret;
-+}
-+
-+static void __exit fini(void)
-+{
-+      int i;
-+
-+      for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
-+              nf_unregister_hook(&ebt_ops_nat[i]);
-+      ebt_unregister_table(&frame_nat);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+EXPORT_NO_SYMBOLS;
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/bridge/netfilter/ebtables.c linux-ebtables/net/bridge/netfilter/ebtables.c
---- linux-mips-cvs/net/bridge/netfilter/ebtables.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/bridge/netfilter/ebtables.c     2005-02-07 05:52:50.000000000 +0100
-@@ -0,0 +1,1496 @@
-+/*
-+ *  ebtables
-+ *
-+ *  Author:
-+ *  Bart De Schuymer          <bart.de.schuymer@pandora.be>
-+ *
-+ *  ebtables.c,v 2.0, July, 2002
-+ *
-+ *  This code is stongly inspired on the iptables code which is
-+ *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
-+ *
-+ *  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.
-+ */
-+
-+// used for print_string
-+#include <linux/sched.h>
-+#include <linux/tty.h>
-+
-+#include <linux/kmod.h>
-+#include <linux/module.h>
-+#include <linux/vmalloc.h>
-+#include <linux/netfilter_bridge/ebtables.h>
-+#include <linux/spinlock.h>
-+#include <asm/uaccess.h>
-+#include <linux/smp.h>
-+#include <net/sock.h>
-+// needed for logical [in,out]-dev filtering
-+#include "../br_private.h"
-+
-+// list_named_find
-+#define ASSERT_READ_LOCK(x)
-+#define ASSERT_WRITE_LOCK(x)
-+#include <linux/netfilter_ipv4/listhelp.h>
-+
-+#if 0 // use this for remote debugging
-+// Copyright (C) 1998 by Ori Pomerantz
-+// Print the string to the appropriate tty, the one
-+// the current task uses
-+static void print_string(char *str)
-+{
-+      struct tty_struct *my_tty;
-+
-+      /* The tty for the current task */
-+      my_tty = current->tty;
-+      if (my_tty != NULL) {
-+              (*(my_tty->driver).write)(my_tty, 0, str, strlen(str));
-+              (*(my_tty->driver).write)(my_tty, 0, "\015\012", 2);
-+      }
-+}
-+
-+#define BUGPRINT(args) print_string(args);
-+#else
-+#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
-+                                         "report to author: "format, ## args)
-+// #define BUGPRINT(format, args...)
-+#endif
-+#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
-+                                         ": out of memory: "format, ## args)
-+// #define MEMPRINT(format, args...)
-+
-+
-+
-+// Each cpu has its own set of counters, so there is no need for write_lock in
-+// the softirq
-+// For reading or updating the counters, the user context needs to
-+// get a write_lock
-+
-+// The size of each set of counters is altered to get cache alignment
-+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
-+#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
-+#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
-+   COUNTER_OFFSET(n) * cpu))
-+
-+
-+
-+static DECLARE_MUTEX(ebt_mutex);
-+static LIST_HEAD(ebt_tables);
-+static LIST_HEAD(ebt_targets);
-+static LIST_HEAD(ebt_matches);
-+static LIST_HEAD(ebt_watchers);
-+
-+static struct ebt_target ebt_standard_target =
-+{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
-+
-+static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
-+   const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,
-+   const struct net_device *out)
-+{
-+      w->u.watcher->watcher(skb, hooknr, in, out, w->data,
-+         w->watcher_size);
-+      // watchers don't give a verdict
-+      return 0;
-+}
-+
-+static inline int ebt_do_match (struct ebt_entry_match *m,
-+   const struct sk_buff *skb, const struct net_device *in,
-+   const struct net_device *out)
-+{
-+      return m->u.match->match(skb, in, out, m->data,
-+         m->match_size);
-+}
-+
-+static inline int ebt_dev_check(char *entry, const struct net_device *device)
-+{
-+      int i = 0;
-+      char *devname = device->name;
-+
-+      if (*entry == '\0')
-+              return 0;
-+      if (!device)
-+              return 1;
-+      /* 1 is the wildcard token */
-+      while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])
-+              i++;
-+      return (devname[i] != entry[i] && entry[i] != 1);
-+}
-+
-+#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
-+// process standard matches
-+static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
-+   const struct net_device *in, const struct net_device *out)
-+{
-+      int verdict, i;
-+
-+      if (e->bitmask & EBT_802_3) {
-+              if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
-+                      return 1;
-+      } else if (!(e->bitmask & EBT_NOPROTO) &&
-+         FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
-+              return 1;
-+
-+      if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
-+              return 1;
-+      if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
-+              return 1;
-+      if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
-+         e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN))
-+              return 1;
-+      if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
-+         e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT))
-+              return 1;
-+
-+      if (e->bitmask & EBT_SOURCEMAC) {
-+              verdict = 0;
-+              for (i = 0; i < 6; i++)
-+                      verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
-+                         e->sourcemsk[i];
-+              if (FWINV2(verdict != 0, EBT_ISOURCE) )
-+                      return 1;
-+      }
-+      if (e->bitmask & EBT_DESTMAC) {
-+              verdict = 0;
-+              for (i = 0; i < 6; i++)
-+                      verdict |= (h->h_dest[i] ^ e->destmac[i]) &
-+                         e->destmsk[i];
-+              if (FWINV2(verdict != 0, EBT_IDEST) )
-+                      return 1;
-+      }
-+      return 0;
-+}
-+
-+// Do some firewalling
-+unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
-+   const struct net_device *in, const struct net_device *out,
-+   struct ebt_table *table)
-+{
-+      int i, nentries;
-+      struct ebt_entry *point;
-+      struct ebt_counter *counter_base, *cb_base;
-+      struct ebt_entry_target *t;
-+      int verdict, sp = 0;
-+      struct ebt_chainstack *cs;
-+      struct ebt_entries *chaininfo;
-+      char *base;
-+      struct ebt_table_info *private = table->private;
-+
-+      read_lock_bh(&table->lock);
-+      cb_base = COUNTER_BASE(private->counters, private->nentries,
-+         cpu_number_map(smp_processor_id()));
-+      if (private->chainstack)
-+              cs = private->chainstack[cpu_number_map(smp_processor_id())];
-+      else
-+              cs = NULL;
-+      chaininfo = private->hook_entry[hook];
-+      nentries = private->hook_entry[hook]->nentries;
-+      point = (struct ebt_entry *)(private->hook_entry[hook]->data);
-+      counter_base = cb_base + private->hook_entry[hook]->counter_offset;
-+      // base for chain jumps
-+      base = private->entries;
-+      i = 0;
-+      while (i < nentries) {
-+              if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out))
-+                      goto letscontinue;
-+
-+              if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
-+                      goto letscontinue;
-+
-+              // increase counter
-+              (*(counter_base + i)).pcnt++;
-+              (*(counter_base + i)).bcnt+=(**pskb).len;
-+
-+              // these should only watch: not modify, nor tell us
-+              // what to do with the packet
-+              EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,
-+                 out);
-+
-+              t = (struct ebt_entry_target *)
-+                 (((char *)point) + point->target_offset);
-+              // standard target
-+              if (!t->u.target->target)
-+                      verdict = ((struct ebt_standard_target *)t)->verdict;
-+              else
-+                      verdict = t->u.target->target(pskb, hook,
-+                         in, out, t->data, t->target_size);
-+              if (verdict == EBT_ACCEPT) {
-+                      read_unlock_bh(&table->lock);
-+                      return NF_ACCEPT;
-+              }
-+              if (verdict == EBT_DROP) {
-+                      read_unlock_bh(&table->lock);
-+                      return NF_DROP;
-+              }
-+              if (verdict == EBT_RETURN) {
-+letsreturn:
-+#ifdef CONFIG_NETFILTER_DEBUG
-+                      if (sp == 0) {
-+                              BUGPRINT("RETURN on base chain");
-+                              // act like this is EBT_CONTINUE
-+                              goto letscontinue;
-+                      }
-+#endif
-+                      sp--;
-+                      // put all the local variables right
-+                      i = cs[sp].n;
-+                      chaininfo = cs[sp].chaininfo;
-+                      nentries = chaininfo->nentries;
-+                      point = cs[sp].e;
-+                      counter_base = cb_base +
-+                         chaininfo->counter_offset;
-+                      continue;
-+              }
-+              if (verdict == EBT_CONTINUE)
-+                      goto letscontinue;
-+#ifdef CONFIG_NETFILTER_DEBUG
-+              if (verdict < 0) {
-+                      BUGPRINT("bogus standard verdict\n");
-+                      read_unlock_bh(&table->lock);
-+                      return NF_DROP;
-+              }
-+#endif
-+              // jump to a udc
-+              cs[sp].n = i + 1;
-+              cs[sp].chaininfo = chaininfo;
-+              cs[sp].e = (struct ebt_entry *)
-+                 (((char *)point) + point->next_offset);
-+              i = 0;
-+              chaininfo = (struct ebt_entries *) (base + verdict);
-+#ifdef CONFIG_NETFILTER_DEBUG
-+              if (chaininfo->distinguisher) {
-+                      BUGPRINT("jump to non-chain\n");
-+                      read_unlock_bh(&table->lock);
-+                      return NF_DROP;
-+              }
-+#endif
-+              nentries = chaininfo->nentries;
-+              point = (struct ebt_entry *)chaininfo->data;
-+              counter_base = cb_base + chaininfo->counter_offset;
-+              sp++;
-+              continue;
-+letscontinue:
-+              point = (struct ebt_entry *)
-+                 (((char *)point) + point->next_offset);
-+              i++;
-+      }
-+
-+      // I actually like this :)
-+      if (chaininfo->policy == EBT_RETURN)
-+              goto letsreturn;
-+      if (chaininfo->policy == EBT_ACCEPT) {
-+              read_unlock_bh(&table->lock);
-+              return NF_ACCEPT;
-+      }
-+      read_unlock_bh(&table->lock);
-+      return NF_DROP;
-+}
-+
-+// If it succeeds, returns element and locks mutex
-+static inline void *
-+find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
-+   struct semaphore *mutex)
-+{
-+      void *ret;
-+
-+      *error = down_interruptible(mutex);
-+      if (*error != 0)
-+              return NULL;
-+
-+      ret = list_named_find(head, name);
-+      if (!ret) {
-+              *error = -ENOENT;
-+              up(mutex);
-+      }
-+      return ret;
-+}
-+
-+#ifndef CONFIG_KMOD
-+#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
-+#else
-+static void *
-+find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
-+   int *error, struct semaphore *mutex)
-+{
-+      void *ret;
-+
-+      ret = find_inlist_lock_noload(head, name, error, mutex);
-+      if (!ret) {
-+              char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
-+              strcpy(modulename, prefix);
-+              strcat(modulename, name);
-+              request_module(modulename);
-+              ret = find_inlist_lock_noload(head, name, error, mutex);
-+      }
-+      return ret;
-+}
-+#endif
-+
-+static inline struct ebt_table *
-+find_table_lock(const char *name, int *error, struct semaphore *mutex)
-+{
-+      return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
-+}
-+
-+static inline struct ebt_match *
-+find_match_lock(const char *name, int *error, struct semaphore *mutex)
-+{
-+      return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
-+}
-+
-+static inline struct ebt_watcher *
-+find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
-+{
-+      return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
-+}
-+
-+static inline struct ebt_target *
-+find_target_lock(const char *name, int *error, struct semaphore *mutex)
-+{
-+      return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
-+}
-+
-+static inline int
-+ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
-+   const char *name, unsigned int hookmask, unsigned int *cnt)
-+{
-+      struct ebt_match *match;
-+      int ret;
-+
-+      if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
-+         ((char *)e) + e->watchers_offset)
-+              return -EINVAL;
-+      match = find_match_lock(m->u.name, &ret, &ebt_mutex);
-+      if (!match)
-+              return ret;
-+      m->u.match = match;
-+      if (match->me)
-+              __MOD_INC_USE_COUNT(match->me);
-+      up(&ebt_mutex);
-+      if (match->check &&
-+         match->check(name, hookmask, e, m->data, m->match_size) != 0) {
-+              BUGPRINT("match->check failed\n");
-+              if (match->me)
-+                      __MOD_DEC_USE_COUNT(match->me);
-+              return -EINVAL;
-+      }
-+      (*cnt)++;
-+      return 0;
-+}
-+
-+static inline int
-+ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
-+   const char *name, unsigned int hookmask, unsigned int *cnt)
-+{
-+      struct ebt_watcher *watcher;
-+      int ret;
-+
-+      if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
-+         ((char *)e) + e->target_offset)
-+              return -EINVAL;
-+      watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
-+      if (!watcher)
-+              return ret;
-+      w->u.watcher = watcher;
-+      if (watcher->me)
-+              __MOD_INC_USE_COUNT(watcher->me);
-+      up(&ebt_mutex);
-+      if (watcher->check &&
-+         watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
-+              BUGPRINT("watcher->check failed\n");
-+              if (watcher->me)
-+                      __MOD_DEC_USE_COUNT(watcher->me);
-+              return -EINVAL;
-+      }
-+      (*cnt)++;
-+      return 0;
-+}
-+
-+// this one is very careful, as it is the first function
-+// to parse the userspace data
-+static inline int
-+ebt_check_entry_size_and_hooks(struct ebt_entry *e,
-+   struct ebt_table_info *newinfo, char *base, char *limit,
-+   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
-+   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
-+{
-+      int i;
-+
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-+              if ((valid_hooks & (1 << i)) == 0)
-+                      continue;
-+              if ( (char *)hook_entries[i] - base ==
-+                 (char *)e - newinfo->entries)
-+                      break;
-+      }
-+      // beginning of a new chain
-+      // if i == NF_BR_NUMHOOKS it must be a user defined chain
-+      if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
-+              if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
-+                      // we make userspace set this right,
-+                      // so there is no misunderstanding
-+                      BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
-+                               "in distinguisher\n");
-+                      return -EINVAL;
-+              }
-+              // this checks if the previous chain has as many entries
-+              // as it said it has
-+              if (*n != *cnt) {
-+                      BUGPRINT("nentries does not equal the nr of entries "
-+                               "in the chain\n");
-+                      return -EINVAL;
-+              }
-+              // before we look at the struct, be sure it is not too big
-+              if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
-+                 > limit) {
-+                      BUGPRINT("entries_size too small\n");
-+                      return -EINVAL;
-+              }
-+              if (((struct ebt_entries *)e)->policy != EBT_DROP &&
-+                 ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
-+                      // only RETURN from udc
-+                      if (i != NF_BR_NUMHOOKS ||
-+                         ((struct ebt_entries *)e)->policy != EBT_RETURN) {
-+                              BUGPRINT("bad policy\n");
-+                              return -EINVAL;
-+                      }
-+              }
-+              if (i == NF_BR_NUMHOOKS) // it's a user defined chain
-+                      (*udc_cnt)++;
-+              else
-+                      newinfo->hook_entry[i] = (struct ebt_entries *)e;
-+              if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
-+                      BUGPRINT("counter_offset != totalcnt");
-+                      return -EINVAL;
-+              }
-+              *n = ((struct ebt_entries *)e)->nentries;
-+              *cnt = 0;
-+              return 0;
-+      }
-+      // a plain old entry, heh
-+      if (sizeof(struct ebt_entry) > e->watchers_offset ||
-+         e->watchers_offset > e->target_offset ||
-+         e->target_offset >= e->next_offset) {
-+              BUGPRINT("entry offsets not in right order\n");
-+              return -EINVAL;
-+      }
-+      // this is not checked anywhere else
-+      if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
-+              BUGPRINT("target size too small\n");
-+              return -EINVAL;
-+      }
-+
-+      (*cnt)++;
-+      (*totalcnt)++;
-+      return 0;
-+}
-+
-+struct ebt_cl_stack
-+{
-+      struct ebt_chainstack cs;
-+      int from;
-+      unsigned int hookmask;
-+};
-+
-+// we need these positions to check that the jumps to a different part of the
-+// entries is a jump to the beginning of a new chain.
-+static inline int
-+ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
-+   struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks,
-+   struct ebt_cl_stack *udc)
-+{
-+      int i;
-+
-+      // we're only interested in chain starts
-+      if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
-+              return 0;
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-+              if ((valid_hooks & (1 << i)) == 0)
-+                      continue;
-+              if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
-+                      break;
-+      }
-+      // only care about udc
-+      if (i != NF_BR_NUMHOOKS)
-+              return 0;
-+
-+      udc[*n].cs.chaininfo = (struct ebt_entries *)e;
-+      // these initialisations are depended on later in check_chainloops()
-+      udc[*n].cs.n = 0;
-+      udc[*n].hookmask = 0;
-+
-+      (*n)++;
-+      return 0;
-+}
-+
-+static inline int
-+ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
-+{
-+      if (i && (*i)-- == 0)
-+              return 1;
-+      if (m->u.match->destroy)
-+              m->u.match->destroy(m->data, m->match_size);
-+      if (m->u.match->me)
-+              __MOD_DEC_USE_COUNT(m->u.match->me);
-+
-+      return 0;
-+}
-+
-+static inline int
-+ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
-+{
-+      if (i && (*i)-- == 0)
-+              return 1;
-+      if (w->u.watcher->destroy)
-+              w->u.watcher->destroy(w->data, w->watcher_size);
-+      if (w->u.watcher->me)
-+              __MOD_DEC_USE_COUNT(w->u.watcher->me);
-+
-+      return 0;
-+}
-+
-+static inline int
-+ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
-+{
-+      struct ebt_entry_target *t;
-+
-+      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
-+              return 0;
-+      // we're done
-+      if (cnt && (*cnt)-- == 0)
-+              return 1;
-+      EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
-+      EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
-+      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-+      if (t->u.target->destroy)
-+              t->u.target->destroy(t->data, t->target_size);
-+      if (t->u.target->me)
-+              __MOD_DEC_USE_COUNT(t->u.target->me);
-+
-+      return 0;
-+}
-+
-+static inline int
-+ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
-+   const char *name, unsigned int *cnt, unsigned int valid_hooks,
-+   struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
-+{
-+      struct ebt_entry_target *t;
-+      struct ebt_target *target;
-+      unsigned int i, j, hook = 0, hookmask = 0;
-+      int ret;
-+
-+      // Don't mess with the struct ebt_entries
-+      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
-+              return 0;
-+
-+      if (e->bitmask & ~EBT_F_MASK) {
-+              BUGPRINT("Unknown flag for bitmask\n");
-+              return -EINVAL;
-+      }
-+      if (e->invflags & ~EBT_INV_MASK) {
-+              BUGPRINT("Unknown flag for inv bitmask\n");
-+              return -EINVAL;
-+      }
-+      if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
-+              BUGPRINT("NOPROTO & 802_3 not allowed\n");
-+              return -EINVAL;
-+      }
-+      // what hook do we belong to?
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-+              if ((valid_hooks & (1 << i)) == 0)
-+                      continue;
-+              if ((char *)newinfo->hook_entry[i] < (char *)e)
-+                      hook = i;
-+              else
-+                      break;
-+      }
-+      // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
-+      // a base chain
-+      if (i < NF_BR_NUMHOOKS)
-+              hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
-+      else {
-+              for (i = 0; i < udc_cnt; i++)
-+                      if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
-+                              break;
-+              if (i == 0)
-+                      hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
-+              else
-+                      hookmask = cl_s[i - 1].hookmask;
-+      }
-+      i = 0;
-+      ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
-+      if (ret != 0)
-+              goto cleanup_matches;
-+      j = 0;
-+      ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
-+      if (ret != 0)
-+              goto cleanup_watchers;
-+      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-+      target = find_target_lock(t->u.name, &ret, &ebt_mutex);
-+      if (!target)
-+              goto cleanup_watchers;
-+      if (target->me)
-+              __MOD_INC_USE_COUNT(target->me);
-+      up(&ebt_mutex);
-+
-+      t->u.target = target;
-+      if (t->u.target == &ebt_standard_target) {
-+              if (e->target_offset + sizeof(struct ebt_standard_target) >
-+                 e->next_offset) {
-+                      BUGPRINT("Standard target size too big\n");
-+                      ret = -EFAULT;
-+                      goto cleanup_watchers;
-+              }
-+              if (((struct ebt_standard_target *)t)->verdict <
-+                 -NUM_STANDARD_TARGETS) {
-+                      BUGPRINT("Invalid standard target\n");
-+                      ret = -EFAULT;
-+                      goto cleanup_watchers;
-+              }
-+      } else if ((e->target_offset + t->target_size +
-+         sizeof(struct ebt_entry_target) > e->next_offset) ||
-+         (t->u.target->check &&
-+         t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
-+              if (t->u.target->me)
-+                      __MOD_DEC_USE_COUNT(t->u.target->me);
-+              ret = -EFAULT;
-+              goto cleanup_watchers;
-+      }
-+      (*cnt)++;
-+      return 0;
-+cleanup_watchers:
-+      EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
-+cleanup_matches:
-+      EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
-+      return ret;
-+}
-+
-+// checks for loops and sets the hook mask for udc
-+// the hook mask for udc tells us from which base chains the udc can be
-+// accessed. This mask is a parameter to the check() functions of the extensions
-+static int check_chainloops(struct ebt_entries *chain,
-+   struct ebt_cl_stack *cl_s, unsigned int udc_cnt, 
-+   unsigned int hooknr, char *base)
-+{
-+      int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
-+      struct ebt_entry *e = (struct ebt_entry *)chain->data;
-+      struct ebt_entry_target *t;
-+
-+      while (pos < nentries || chain_nr != -1) {
-+              // end of udc, go back one 'recursion' step
-+              if (pos == nentries) {
-+                      // put back values of the time when this chain was called
-+                      e = cl_s[chain_nr].cs.e;
-+                      if (cl_s[chain_nr].from != -1)
-+                              nentries =
-+                              cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
-+                      else
-+                              nentries = chain->nentries;
-+                      pos = cl_s[chain_nr].cs.n;
-+                      // make sure we won't see a loop that isn't one
-+                      cl_s[chain_nr].cs.n = 0;
-+                      chain_nr = cl_s[chain_nr].from;
-+                      if (pos == nentries)
-+                              continue;
-+              }
-+              t = (struct ebt_entry_target *)
-+                 (((char *)e) + e->target_offset);
-+              if (strcmp(t->u.name, EBT_STANDARD_TARGET))
-+                      goto letscontinue;
-+              if (e->target_offset + sizeof(struct ebt_standard_target) >
-+                 e->next_offset) {
-+                      BUGPRINT("Standard target size too big\n");
-+                      return -1;
-+              }
-+              verdict = ((struct ebt_standard_target *)t)->verdict;
-+              if (verdict >= 0) { // jump to another chain
-+                      struct ebt_entries *hlp2 =
-+                         (struct ebt_entries *)(base + verdict);
-+                      for (i = 0; i < udc_cnt; i++)
-+                              if (hlp2 == cl_s[i].cs.chaininfo)
-+                                      break;
-+                      // bad destination or loop
-+                      if (i == udc_cnt) {
-+                              BUGPRINT("bad destination\n");
-+                              return -1;
-+                      }
-+                      if (cl_s[i].cs.n) {
-+                              BUGPRINT("loop\n");
-+                              return -1;
-+                      }
-+                      // this can't be 0, so the above test is correct
-+                      cl_s[i].cs.n = pos + 1;
-+                      pos = 0;
-+                      cl_s[i].cs.e = ((void *)e + e->next_offset);
-+                      e = (struct ebt_entry *)(hlp2->data);
-+                      nentries = hlp2->nentries;
-+                      cl_s[i].from = chain_nr;
-+                      chain_nr = i;
-+                      // this udc is accessible from the base chain for hooknr
-+                      cl_s[i].hookmask |= (1 << hooknr);
-+                      continue;
-+              }
-+letscontinue:
-+              e = (void *)e + e->next_offset;
-+              pos++;
-+      }
-+      return 0;
-+}
-+
-+// do the parsing of the table/chains/entries/matches/watchers/targets, heh
-+static int translate_table(struct ebt_replace *repl,
-+   struct ebt_table_info *newinfo)
-+{
-+      unsigned int i, j, k, udc_cnt;
-+      int ret;
-+      struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops
-+
-+      i = 0;
-+      while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
-+              i++;
-+      if (i == NF_BR_NUMHOOKS) {
-+              BUGPRINT("No valid hooks specified\n");
-+              return -EINVAL;
-+      }
-+      if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
-+              BUGPRINT("Chains don't start at beginning\n");
-+              return -EINVAL;
-+      }
-+      // make sure chains are ordered after each other in same order
-+      // as their corresponding hooks
-+      for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
-+              if (!(repl->valid_hooks & (1 << j)))
-+                      continue;
-+              if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
-+                      BUGPRINT("Hook order must be followed\n");
-+                      return -EINVAL;
-+              }
-+              i = j;
-+      }
-+
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++)
-+              newinfo->hook_entry[i] = NULL;
-+
-+      newinfo->entries_size = repl->entries_size;
-+      newinfo->nentries = repl->nentries;
-+
-+      // do some early checkings and initialize some things
-+      i = 0; // holds the expected nr. of entries for the chain
-+      j = 0; // holds the up to now counted entries for the chain
-+      k = 0; // holds the total nr. of entries, should equal
-+             // newinfo->nentries afterwards
-+      udc_cnt = 0; // will hold the nr. of user defined chains (udc)
-+      ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-+         ebt_check_entry_size_and_hooks, newinfo, repl->entries,
-+         repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
-+         &udc_cnt, repl->valid_hooks);
-+
-+      if (ret != 0)
-+              return ret;
-+
-+      if (i != j) {
-+              BUGPRINT("nentries does not equal the nr of entries in the "
-+                       "(last) chain\n");
-+              return -EINVAL;
-+      }
-+      if (k != newinfo->nentries) {
-+              BUGPRINT("Total nentries is wrong\n");
-+              return -EINVAL;
-+      }
-+
-+      // check if all valid hooks have a chain
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++) {
-+              if (newinfo->hook_entry[i] == NULL &&
-+                 (repl->valid_hooks & (1 << i))) {
-+                      BUGPRINT("Valid hook without chain\n");
-+                      return -EINVAL;
-+              }
-+      }
-+
-+      // Get the location of the udc, put them in an array
-+      // While we're at it, allocate the chainstack
-+      if (udc_cnt) {
-+              // this will get free'd in do_replace()/ebt_register_table()
-+              // if an error occurs
-+              newinfo->chainstack = (struct ebt_chainstack **)
-+                 vmalloc(smp_num_cpus * sizeof(struct ebt_chainstack));
-+              if (!newinfo->chainstack)
-+                      return -ENOMEM;
-+              for (i = 0; i < smp_num_cpus; i++) {
-+                      newinfo->chainstack[i] =
-+                         vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
-+                      if (!newinfo->chainstack[i]) {
-+                              while (i)
-+                                      vfree(newinfo->chainstack[--i]);
-+                              vfree(newinfo->chainstack);
-+                              newinfo->chainstack = NULL;
-+                              return -ENOMEM;
-+                      }
-+              }
-+
-+              cl_s = (struct ebt_cl_stack *)
-+                 vmalloc(udc_cnt * sizeof(struct ebt_cl_stack));
-+              if (!cl_s)
-+                      return -ENOMEM;
-+              i = 0; // the i'th udc
-+              EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-+                 ebt_get_udc_positions, newinfo, repl->hook_entry, &i,
-+                 repl->valid_hooks, cl_s);
-+              // sanity check
-+              if (i != udc_cnt) {
-+                      BUGPRINT("i != udc_cnt\n");
-+                      vfree(cl_s);
-+                      return -EFAULT;
-+              }
-+      }
-+
-+      // Check for loops
-+      for (i = 0; i < NF_BR_NUMHOOKS; i++)
-+              if (repl->valid_hooks & (1 << i))
-+                      if (check_chainloops(newinfo->hook_entry[i],
-+                         cl_s, udc_cnt, i, newinfo->entries)) {
-+                              if (cl_s)
-+                                      vfree(cl_s);
-+                              return -EINVAL;
-+                      }
-+
-+      // we now know the following (along with E=mc²):
-+      // - the nr of entries in each chain is right
-+      // - the size of the allocated space is right
-+      // - all valid hooks have a corresponding chain
-+      // - there are no loops
-+      // - wrong data can still be on the level of a single entry
-+      // - could be there are jumps to places that are not the
-+      //   beginning of a chain. This can only occur in chains that
-+      //   are not accessible from any base chains, so we don't care.
-+
-+      // used to know what we need to clean up if something goes wrong
-+      i = 0;
-+      ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-+         ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks,
-+         cl_s, udc_cnt);
-+      if (ret != 0) {
-+              EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-+                 ebt_cleanup_entry, &i);
-+      }
-+      if (cl_s)
-+              vfree(cl_s);
-+      return ret;
-+}
-+
-+// called under write_lock
-+static void get_counters(struct ebt_counter *oldcounters,
-+   struct ebt_counter *counters, unsigned int nentries)
-+{
-+      int i, cpu;
-+      struct ebt_counter *counter_base;
-+
-+      // counters of cpu 0
-+      memcpy(counters, oldcounters,
-+         sizeof(struct ebt_counter) * nentries);
-+      // add other counters to those of cpu 0
-+      for (cpu = 1; cpu < smp_num_cpus; cpu++) {
-+              counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
-+              for (i = 0; i < nentries; i++) {
-+                      counters[i].pcnt += counter_base[i].pcnt;
-+                      counters[i].bcnt += counter_base[i].bcnt;
-+              }
-+      }
-+}
-+
-+// replace the table
-+static int do_replace(void *user, unsigned int len)
-+{
-+      int ret, i, countersize;
-+      struct ebt_table_info *newinfo;
-+      struct ebt_replace tmp;
-+      struct ebt_table *t;
-+      struct ebt_counter *counterstmp = NULL;
-+      // used to be able to unlock earlier
-+      struct ebt_table_info *table;
-+
-+      if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
-+              return -EFAULT;
-+
-+      if (len != sizeof(tmp) + tmp.entries_size) {
-+              BUGPRINT("Wrong len argument\n");
-+              return -EINVAL;
-+      }
-+
-+      if (tmp.entries_size == 0) {
-+              BUGPRINT("Entries_size never zero\n");
-+              return -EINVAL;
-+      }
-+      countersize = COUNTER_OFFSET(tmp.nentries) * smp_num_cpus;
-+      newinfo = (struct ebt_table_info *)
-+         vmalloc(sizeof(struct ebt_table_info) + countersize);
-+      if (!newinfo)
-+              return -ENOMEM;
-+
-+      if (countersize)
-+              memset(newinfo->counters, 0, countersize);
-+
-+      newinfo->entries = (char *)vmalloc(tmp.entries_size);
-+      if (!newinfo->entries) {
-+              ret = -ENOMEM;
-+              goto free_newinfo;
-+      }
-+      if (copy_from_user(
-+         newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
-+              BUGPRINT("Couldn't copy entries from userspace\n");
-+              ret = -EFAULT;
-+              goto free_entries;
-+      }
-+
-+      // the user wants counters back
-+      // the check on the size is done later, when we have the lock
-+      if (tmp.num_counters) {
-+              counterstmp = (struct ebt_counter *)
-+                 vmalloc(tmp.num_counters * sizeof(struct ebt_counter));
-+              if (!counterstmp) {
-+                      ret = -ENOMEM;
-+                      goto free_entries;
-+              }
-+      }
-+      else
-+              counterstmp = NULL;
-+
-+      // this can get initialized by translate_table()
-+      newinfo->chainstack = NULL;
-+      ret = translate_table(&tmp, newinfo);
-+
-+      if (ret != 0)
-+              goto free_counterstmp;
-+
-+      t = find_table_lock(tmp.name, &ret, &ebt_mutex);
-+      if (!t)
-+              goto free_iterate;
-+
-+      // the table doesn't like it
-+      if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
-+              goto free_unlock;
-+
-+      if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
-+              BUGPRINT("Wrong nr. of counters requested\n");
-+              ret = -EINVAL;
-+              goto free_unlock;
-+      }
-+
-+      // we have the mutex lock, so no danger in reading this pointer
-+      table = t->private;
-+      // we need an atomic snapshot of the counters
-+      write_lock_bh(&t->lock);
-+      if (tmp.num_counters)
-+              get_counters(t->private->counters, counterstmp,
-+                 t->private->nentries);
-+
-+      t->private = newinfo;
-+      write_unlock_bh(&t->lock);
-+      up(&ebt_mutex);
-+      // So, a user can change the chains while having messed up her counter
-+      // allocation. Only reason why this is done is because this way the lock
-+      // is held only once, while this doesn't bring the kernel into a
-+      // dangerous state.
-+      if (tmp.num_counters &&
-+         copy_to_user(tmp.counters, counterstmp,
-+         tmp.num_counters * sizeof(struct ebt_counter))) {
-+              BUGPRINT("Couldn't copy counters to userspace\n");
-+              ret = -EFAULT;
-+      }
-+      else
-+              ret = 0;
-+
-+      // decrease module count and free resources
-+      EBT_ENTRY_ITERATE(table->entries, table->entries_size,
-+         ebt_cleanup_entry, NULL);
-+
-+      vfree(table->entries);
-+      if (table->chainstack) {
-+              for (i = 0; i < smp_num_cpus; i++)
-+                      vfree(table->chainstack[i]);
-+              vfree(table->chainstack);
-+      }
-+      vfree(table);
-+
-+      if (counterstmp)
-+              vfree(counterstmp);
-+      return ret;
-+
-+free_unlock:
-+      up(&ebt_mutex);
-+free_iterate:
-+      EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
-+         ebt_cleanup_entry, NULL);
-+free_counterstmp:
-+      if (counterstmp)
-+              vfree(counterstmp);
-+      // can be initialized in translate_table()
-+      if (newinfo->chainstack) {
-+              for (i = 0; i < smp_num_cpus; i++)
-+                      vfree(newinfo->chainstack[i]);
-+              vfree(newinfo->chainstack);
-+      }
-+free_entries:
-+      if (newinfo->entries)
-+              vfree(newinfo->entries);
-+free_newinfo:
-+      if (newinfo)
-+              vfree(newinfo);
-+      return ret;
-+}
-+
-+int ebt_register_target(struct ebt_target *target)
-+{
-+      int ret;
++   // Used in the kernel match() functions
++#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg))
++// True if the hook mask denotes that the rule is in a base chain,
++// used in the check() functions
++#define BASE_CHAIN (hookmask & (1 << NF_BR_NUMHOOKS))
++// Clear the bit in the hook mask that tells if the rule is on a base chain
++#define CLEAR_BASE_CHAIN_BIT (hookmask &= ~(1 << NF_BR_NUMHOOKS))
++// True if the target is not a standard target
++#define INVALID_TARGET (info->target < -NUM_STANDARD_TARGETS || info->target >= 0)
 +
-+      ret = down_interruptible(&ebt_mutex);
-+      if (ret != 0)
-+              return ret;
-+      if (!list_named_insert(&ebt_targets, target)) {
-+              up(&ebt_mutex);
-+              return -EEXIST;
-+      }
-+      up(&ebt_mutex);
-+      MOD_INC_USE_COUNT;
++#endif /* __KERNEL__ */
 +
-+      return 0;
-+}
++// blatently stolen from ip_tables.h
++// fn returns 0 to continue iteration
++#define EBT_MATCH_ITERATE(e, fn, args...)                   \
++({                                                          \
++      unsigned int __i;                                   \
++      int __ret = 0;                                      \
++      struct ebt_entry_match *__match;                    \
++                                                          \
++      for (__i = sizeof(struct ebt_entry);                \
++           __i < (e)->watchers_offset;                    \
++           __i += __match->match_size +                   \
++           sizeof(struct ebt_entry_match)) {              \
++              __match = (void *)(e) + __i;                \
++                                                          \
++              __ret = fn(__match , ## args);              \
++              if (__ret != 0)                             \
++                      break;                              \
++      }                                                   \
++      if (__ret == 0) {                                   \
++              if (__i != (e)->watchers_offset)            \
++                      __ret = -EINVAL;                    \
++      }                                                   \
++      __ret;                                              \
++})
 +
-+void ebt_unregister_target(struct ebt_target *target)
-+{
-+      down(&ebt_mutex);
-+      LIST_DELETE(&ebt_targets, target);
-+      up(&ebt_mutex);
-+      MOD_DEC_USE_COUNT;
-+}
++#define EBT_WATCHER_ITERATE(e, fn, args...)                 \
++({                                                          \
++      unsigned int __i;                                   \
++      int __ret = 0;                                      \
++      struct ebt_entry_watcher *__watcher;                \
++                                                          \
++      for (__i = e->watchers_offset;                      \
++           __i < (e)->target_offset;                      \
++           __i += __watcher->watcher_size +               \
++           sizeof(struct ebt_entry_watcher)) {            \
++              __watcher = (void *)(e) + __i;              \
++                                                          \
++              __ret = fn(__watcher , ## args);            \
++              if (__ret != 0)                             \
++                      break;                              \
++      }                                                   \
++      if (__ret == 0) {                                   \
++              if (__i != (e)->target_offset)              \
++                      __ret = -EINVAL;                    \
++      }                                                   \
++      __ret;                                              \
++})
 +
-+int ebt_register_match(struct ebt_match *match)
-+{
-+      int ret;
++#define EBT_ENTRY_ITERATE(entries, size, fn, args...)       \
++({                                                          \
++      unsigned int __i;                                   \
++      int __ret = 0;                                      \
++      struct ebt_entry *__entry;                          \
++                                                          \
++      for (__i = 0; __i < (size);) {                      \
++              __entry = (void *)(entries) + __i;          \
++              __ret = fn(__entry , ## args);              \
++              if (__ret != 0)                             \
++                      break;                              \
++              if (__entry->bitmask != 0)                  \
++                      __i += __entry->next_offset;        \
++              else                                        \
++                      __i += sizeof(struct ebt_entries);  \
++      }                                                   \
++      if (__ret == 0) {                                   \
++              if (__i != (size))                          \
++                      __ret = -EINVAL;                    \
++      }                                                   \
++      __ret;                                              \
++})
 +
-+      ret = down_interruptible(&ebt_mutex);
-+      if (ret != 0)
-+              return ret;
-+      if (!list_named_insert(&ebt_matches, match)) {
-+              up(&ebt_mutex);
-+              return -EEXIST;
-+      }
-+      up(&ebt_mutex);
-+      MOD_INC_USE_COUNT;
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_among.h   2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,65 @@
++#ifndef __LINUX_BRIDGE_EBT_AMONG_H
++#define __LINUX_BRIDGE_EBT_AMONG_H
 +
-+      return 0;
-+}
++#define EBT_AMONG_DST 0x01
++#define EBT_AMONG_SRC 0x02
 +
-+void ebt_unregister_match(struct ebt_match *match)
-+{
-+      down(&ebt_mutex);
-+      LIST_DELETE(&ebt_matches, match);
-+      up(&ebt_mutex);
-+      MOD_DEC_USE_COUNT;
-+}
++/* Grzegorz Borowiak <grzes@gnu.univ.gda.pl> 2003
++ * 
++ * Write-once-read-many hash table, used for checking if a given
++ * MAC address belongs to a set or not and possibly for checking
++ * if it is related with a given IPv4 address.
++ *
++ * The hash value of an address is its last byte.
++ * 
++ * In real-world ethernet addresses, values of the last byte are
++ * evenly distributed and there is no need to consider other bytes.
++ * It would only slow the routines down.
++ *
++ * For MAC address comparison speedup reasons, we introduce a trick.
++ * MAC address is mapped onto an array of two 32-bit integers.
++ * This pair of integers is compared with MAC addresses in the
++ * hash table, which are stored also in form of pairs of integers
++ * (in `cmp' array). This is quick as it requires only two elementary
++ * number comparisons in worst case. Further, we take advantage of
++ * fact that entropy of 3 last bytes of address is larger than entropy
++ * of 3 first bytes. So first we compare 4 last bytes of addresses and
++ * if they are the same we compare 2 first.
++ *
++ * Yes, it is a memory overhead, but in 2003 AD, who cares?
++ */
 +
-+int ebt_register_watcher(struct ebt_watcher *watcher)
++struct ebt_mac_wormhash_tuple
 +{
-+      int ret;
-+
-+      ret = down_interruptible(&ebt_mutex);
-+      if (ret != 0)
-+              return ret;
-+      if (!list_named_insert(&ebt_watchers, watcher)) {
-+              up(&ebt_mutex);
-+              return -EEXIST;
-+      }
-+      up(&ebt_mutex);
-+      MOD_INC_USE_COUNT;
-+
-+      return 0;
-+}
++      uint32_t cmp[2];
++      uint32_t ip;
++};
 +
-+void ebt_unregister_watcher(struct ebt_watcher *watcher)
++struct ebt_mac_wormhash
 +{
-+      down(&ebt_mutex);
-+      LIST_DELETE(&ebt_watchers, watcher);
-+      up(&ebt_mutex);
-+      MOD_DEC_USE_COUNT;
-+}
++      int table[257];
++      int poolsize;
++      struct ebt_mac_wormhash_tuple pool[0];
++};
 +
-+int ebt_register_table(struct ebt_table *table)
++#define ebt_mac_wormhash_size(x) ((x) ? sizeof(struct ebt_mac_wormhash) \
++              + (x)->poolsize * sizeof(struct ebt_mac_wormhash_tuple) : 0)
++
++struct ebt_among_info
 +{
-+      struct ebt_table_info *newinfo;
-+      int ret, i, countersize;
++      int wh_dst_ofs;
++      int wh_src_ofs;
++      int bitmask;
++};
 +
-+      if (!table || !table->table ||!table->table->entries ||
-+          table->table->entries_size == 0 ||
-+          table->table->counters || table->private) {
-+              BUGPRINT("Bad table data for ebt_register_table!!!\n");
-+              return -EINVAL;
-+      }
++#define EBT_AMONG_DST_NEG 0x1
++#define EBT_AMONG_SRC_NEG 0x2
 +
-+      countersize = COUNTER_OFFSET(table->table->nentries) * smp_num_cpus;
-+      newinfo = (struct ebt_table_info *)
-+         vmalloc(sizeof(struct ebt_table_info) + countersize);
-+      ret = -ENOMEM;
-+      if (!newinfo)
-+              return -ENOMEM;
++#define ebt_among_wh_dst(x) ((x)->wh_dst_ofs ? \
++      (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_dst_ofs) : NULL)
++#define ebt_among_wh_src(x) ((x)->wh_src_ofs ? \
++      (struct ebt_mac_wormhash*)((char*)(x) + (x)->wh_src_ofs) : NULL)
 +
-+      newinfo->entries = (char *)vmalloc(table->table->entries_size);
-+      if (!(newinfo->entries))
-+              goto free_newinfo;
++#define EBT_AMONG_MATCH "among"
 +
-+      memcpy(newinfo->entries, table->table->entries,
-+         table->table->entries_size);
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_limit.h   2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,23 @@
++#ifndef __LINUX_BRIDGE_EBT_LIMIT_H
++#define __LINUX_BRIDGE_EBT_LIMIT_H
 +
-+      if (countersize)
-+              memset(newinfo->counters, 0, countersize);
++#define EBT_LIMIT_MATCH "limit"
 +
-+      // fill in newinfo and parse the entries
-+      newinfo->chainstack = NULL;
-+      ret = translate_table(table->table, newinfo);
-+      if (ret != 0) {
-+              BUGPRINT("Translate_table failed\n");
-+              goto free_chainstack;
-+      }
++/* timings are in milliseconds. */
++#define EBT_LIMIT_SCALE 10000
 +
-+      if (table->check && table->check(newinfo, table->valid_hooks)) {
-+              BUGPRINT("The table doesn't like its own initial data, lol\n");
-+              return -EINVAL;
-+      }
++/* 1/10,000 sec period => max of 10,000/sec.  Min rate is then 429490
++   seconds, or one every 59 hours. */
 +
-+      table->private = newinfo;
-+      table->lock = RW_LOCK_UNLOCKED;
-+      ret = down_interruptible(&ebt_mutex);
-+      if (ret != 0)
-+              goto free_chainstack;
++struct ebt_limit_info
++{
++      u_int32_t avg;    /* Average secs between packets * scale */
++      u_int32_t burst;  /* Period multiplier for upper limit. */
 +
-+      if (list_named_find(&ebt_tables, table->name)) {
-+              ret = -EEXIST;
-+              BUGPRINT("Table name already exists\n");
-+              goto free_unlock;
-+      }
++      /* Used internally by the kernel */
++      unsigned long prev;
++      u_int32_t credit;
++      u_int32_t credit_cap, cost;
++};
 +
-+      list_prepend(&ebt_tables, table);
-+      up(&ebt_mutex);
-+      MOD_INC_USE_COUNT;
-+      return 0;
-+free_unlock:
-+      up(&ebt_mutex);
-+free_chainstack:
-+      if (newinfo->chainstack) {
-+              for (i = 0; i < smp_num_cpus; i++)
-+                      vfree(newinfo->chainstack[i]);
-+              vfree(newinfo->chainstack);
-+      }
-+      vfree(newinfo->entries);
-+free_newinfo:
-+      vfree(newinfo);
-+      return ret;
-+}
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_arpreply.h        2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef __LINUX_BRIDGE_EBT_ARPREPLY_H
++#define __LINUX_BRIDGE_EBT_ARPREPLY_H
 +
-+void ebt_unregister_table(struct ebt_table *table)
++struct ebt_arpreply_info
 +{
-+      int i;
++      unsigned char mac[ETH_ALEN];
++      int target;
++};
++#define EBT_ARPREPLY_TARGET "arpreply"
 +
-+      if (!table) {
-+              BUGPRINT("Request to unregister NULL table!!!\n");
-+              return;
-+      }
-+      down(&ebt_mutex);
-+      LIST_DELETE(&ebt_tables, table);
-+      up(&ebt_mutex);
-+      EBT_ENTRY_ITERATE(table->private->entries,
-+         table->private->entries_size, ebt_cleanup_entry, NULL);
-+      if (table->private->entries)
-+              vfree(table->private->entries);
-+      if (table->private->chainstack) {
-+              for (i = 0; i < smp_num_cpus; i++)
-+                      vfree(table->private->chainstack[i]);
-+              vfree(table->private->chainstack);
-+      }
-+      vfree(table->private);
-+      MOD_DEC_USE_COUNT;
-+}
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_802_3.h   2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,60 @@
++#ifndef __LINUX_BRIDGE_EBT_802_3_H
++#define __LINUX_BRIDGE_EBT_802_3_H
 +
-+// userspace just supplied us with counters
-+static int update_counters(void *user, unsigned int len)
-+{
-+      int i, ret;
-+      struct ebt_counter *tmp;
-+      struct ebt_replace hlp;
-+      struct ebt_table *t;
++#define EBT_802_3_SAP 0x01
++#define EBT_802_3_TYPE 0x02
 +
-+      if (copy_from_user(&hlp, user, sizeof(hlp)))
-+              return -EFAULT;
++#define EBT_802_3_MATCH "802_3"
 +
-+      if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
-+              return -EINVAL;
-+      if (hlp.num_counters == 0)
-+              return -EINVAL;
++/*
++ * If frame has DSAP/SSAP value 0xaa you must check the SNAP type
++ * to discover what kind of packet we're carrying. 
++ */
++#define CHECK_TYPE 0xaa
 +
-+      if ( !(tmp = (struct ebt_counter *)
-+         vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){
-+              MEMPRINT("Update_counters && nomemory\n");
-+              return -ENOMEM;
-+      }
++/*
++ * Control field may be one or two bytes.  If the first byte has
++ * the value 0x03 then the entire length is one byte, otherwise it is two.
++ * One byte controls are used in Unnumbered Information frames.
++ * Two byte controls are used in Numbered Information frames.
++ */
++#define IS_UI 0x03
 +
-+      t = find_table_lock(hlp.name, &ret, &ebt_mutex);
-+      if (!t)
-+              goto free_tmp;
++#define EBT_802_3_MASK (EBT_802_3_SAP | EBT_802_3_TYPE | EBT_802_3)
 +
-+      if (hlp.num_counters != t->private->nentries) {
-+              BUGPRINT("Wrong nr of counters\n");
-+              ret = -EINVAL;
-+              goto unlock_mutex;
-+      }
++/* ui has one byte ctrl, ni has two */
++struct hdr_ui {
++      uint8_t dsap;
++      uint8_t ssap;
++      uint8_t ctrl;
++      uint8_t orig[3];
++      uint16_t type;
++};
 +
-+      if ( copy_from_user(tmp, hlp.counters,
-+         hlp.num_counters * sizeof(struct ebt_counter)) ) {
-+              BUGPRINT("Updata_counters && !cfu\n");
-+              ret = -EFAULT;
-+              goto unlock_mutex;
-+      }
++struct hdr_ni {
++      uint8_t dsap;
++      uint8_t ssap;
++      uint16_t ctrl;
++      uint8_t  orig[3];
++      uint16_t type;
++};
 +
-+      // we want an atomic add of the counters
-+      write_lock_bh(&t->lock);
++struct ebt_802_3_hdr {
++      uint8_t  daddr[6];
++      uint8_t  saddr[6];
++      uint16_t len;
++      union {
++              struct hdr_ui ui;
++              struct hdr_ni ni;
++      } llc;
++};
 +
-+      // we add to the counters of the first cpu
-+      for (i = 0; i < hlp.num_counters; i++) {
-+              t->private->counters[i].pcnt += tmp[i].pcnt;
-+              t->private->counters[i].bcnt += tmp[i].bcnt;
-+      }
++struct ebt_802_3_info 
++{
++      uint8_t  sap;
++      uint16_t type;
++      uint8_t  bitmask;
++      uint8_t  invflags;
++};
 +
-+      write_unlock_bh(&t->lock);
-+      ret = 0;
-+unlock_mutex:
-+      up(&ebt_mutex);
-+free_tmp:
-+      vfree(tmp);
-+      return ret;
-+}
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_arp.h     2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,32 @@
++#ifndef __LINUX_BRIDGE_EBT_ARP_H
++#define __LINUX_BRIDGE_EBT_ARP_H
 +
-+static inline int ebt_make_matchname(struct ebt_entry_match *m,
-+   char *base, char *ubase)
-+{
-+      char *hlp = ubase - base + (char *)m;
-+      if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
-+              return -EFAULT;
-+      return 0;
-+}
++#define EBT_ARP_OPCODE 0x01
++#define EBT_ARP_HTYPE 0x02
++#define EBT_ARP_PTYPE 0x04
++#define EBT_ARP_SRC_IP 0x08
++#define EBT_ARP_DST_IP 0x10
++#define EBT_ARP_SRC_MAC 0x20
++#define EBT_ARP_DST_MAC 0x40
++#define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \
++   EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)
++#define EBT_ARP_MATCH "arp"
 +
-+static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
-+   char *base, char *ubase)
++struct ebt_arp_info
 +{
-+      char *hlp = ubase - base + (char *)w;
-+      if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
-+              return -EFAULT;
-+      return 0;
-+}
++      uint16_t htype;
++      uint16_t ptype;
++      uint16_t opcode;
++      uint32_t saddr;
++      uint32_t smsk;
++      uint32_t daddr;
++      uint32_t dmsk;
++      unsigned char smaddr[ETH_ALEN];
++      unsigned char smmsk[ETH_ALEN];
++      unsigned char dmaddr[ETH_ALEN];
++      unsigned char dmmsk[ETH_ALEN];
++      uint8_t  bitmask;
++      uint8_t  invflags;
++};
 +
-+static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
-+{
-+      int ret;
-+      char *hlp;
-+      struct ebt_entry_target *t;
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_ip.h      2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,43 @@
++/*
++ *  ebt_ip
++ *
++ *    Authors:
++ *    Bart De Schuymer <bart.de.schuymer@pandora.be>
++ *
++ *  April, 2002
++ *
++ *  Changes:
++ *    added ip-sport and ip-dport
++ *    Innominate Security Technologies AG <mhopf@innominate.com>
++ *    September, 2002
++ */
 +
-+      if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
-+              return 0;
++#ifndef __LINUX_BRIDGE_EBT_IP_H
++#define __LINUX_BRIDGE_EBT_IP_H
 +
-+      hlp = ubase - base + (char *)e + e->target_offset;
-+      t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
-+      
-+      ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
-+      if (ret != 0)
-+              return ret;
-+      ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
-+      if (ret != 0)
-+              return ret;
-+      if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
-+              return -EFAULT;
-+      return 0;
-+}
++#define EBT_IP_SOURCE 0x01
++#define EBT_IP_DEST 0x02
++#define EBT_IP_TOS 0x04
++#define EBT_IP_PROTO 0x08
++#define EBT_IP_SPORT 0x10
++#define EBT_IP_DPORT 0x20
++#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
++ EBT_IP_SPORT | EBT_IP_DPORT )
++#define EBT_IP_MATCH "ip"
 +
-+// called with ebt_mutex down
-+static int copy_everything_to_user(struct ebt_table *t, void *user,
-+   int *len, int cmd)
++// the same values are used for the invflags
++struct ebt_ip_info
 +{
-+      struct ebt_replace tmp;
-+      struct ebt_counter *counterstmp, *oldcounters;
-+      unsigned int entries_size, nentries;
-+      char *entries;
++      uint32_t saddr;
++      uint32_t daddr;
++      uint32_t smsk;
++      uint32_t dmsk;
++      uint8_t  tos;
++      uint8_t  protocol;
++      uint8_t  bitmask;
++      uint8_t  invflags;
++      uint16_t sport[2];
++      uint16_t dport[2];
++};
 +
-+      if (cmd == EBT_SO_GET_ENTRIES) {
-+              entries_size = t->private->entries_size;
-+              nentries = t->private->nentries;
-+              entries = t->private->entries;
-+              oldcounters = t->private->counters;
-+      } else {
-+              entries_size = t->table->entries_size;
-+              nentries = t->table->nentries;
-+              entries = t->table->entries;
-+              oldcounters = t->table->counters;
-+      }
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_pkttype.h 2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef __LINUX_BRIDGE_EBT_PKTTYPE_H
++#define __LINUX_BRIDGE_EBT_PKTTYPE_H
 +
-+      if (copy_from_user(&tmp, user, sizeof(tmp))) {
-+              BUGPRINT("Cfu didn't work\n");
-+              return -EFAULT;
-+      }
++struct ebt_pkttype_info
++{
++      uint8_t pkt_type;
++      uint8_t invert;
++};
++#define EBT_PKTTYPE_MATCH "pkttype"
 +
-+      if (*len != sizeof(struct ebt_replace) + entries_size +
-+         (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
-+              BUGPRINT("Wrong size\n");
-+              return -EINVAL;
-+      }
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_stp.h     2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,46 @@
++#ifndef __LINUX_BRIDGE_EBT_STP_H
++#define __LINUX_BRIDGE_EBT_STP_H
 +
-+      if (tmp.nentries != nentries) {
-+              BUGPRINT("Nentries wrong\n");
-+              return -EINVAL;
-+      }
++#define EBT_STP_TYPE          0x0001
 +
-+      if (tmp.entries_size != entries_size) {
-+              BUGPRINT("Wrong size\n");
-+              return -EINVAL;
-+      }
++#define EBT_STP_FLAGS         0x0002
++#define EBT_STP_ROOTPRIO      0x0004
++#define EBT_STP_ROOTADDR      0x0008
++#define EBT_STP_ROOTCOST      0x0010
++#define EBT_STP_SENDERPRIO    0x0020
++#define EBT_STP_SENDERADDR    0x0040
++#define EBT_STP_PORT          0x0080
++#define EBT_STP_MSGAGE                0x0100
++#define EBT_STP_MAXAGE                0x0200
++#define EBT_STP_HELLOTIME     0x0400
++#define EBT_STP_FWDD          0x0800
 +
-+      // userspace might not need the counters
-+      if (tmp.num_counters) {
-+              if (tmp.num_counters != nentries) {
-+                      BUGPRINT("Num_counters wrong\n");
-+                      return -EINVAL;
-+              }
-+              counterstmp = (struct ebt_counter *)
-+                 vmalloc(nentries * sizeof(struct ebt_counter));
-+              if (!counterstmp) {
-+                      MEMPRINT("Couldn't copy counters, out of memory\n");
-+                      return -ENOMEM;
-+              }
-+              write_lock_bh(&t->lock);
-+              get_counters(oldcounters, counterstmp, nentries);
-+              write_unlock_bh(&t->lock);
++#define EBT_STP_MASK          0x0fff
++#define EBT_STP_CONFIG_MASK   0x0ffe
 +
-+              if (copy_to_user(tmp.counters, counterstmp,
-+                 nentries * sizeof(struct ebt_counter))) {
-+                      BUGPRINT("Couldn't copy counters to userspace\n");
-+                      vfree(counterstmp);
-+                      return -EFAULT;
-+              }
-+              vfree(counterstmp);
-+      }
++#define EBT_STP_MATCH "stp"
 +
-+      if (copy_to_user(tmp.entries, entries, entries_size)) {
-+              BUGPRINT("Couldn't copy entries to userspace\n");
-+              return -EFAULT;
-+      }
-+      // set the match/watcher/target names right
-+      return EBT_ENTRY_ITERATE(entries, entries_size,
-+         ebt_make_names, entries, tmp.entries);
-+}
++struct ebt_stp_config_info
++{
++      uint8_t flags;
++      uint16_t root_priol, root_priou;
++      char root_addr[6], root_addrmsk[6];
++      uint32_t root_costl, root_costu;
++      uint16_t sender_priol, sender_priou;
++      char sender_addr[6], sender_addrmsk[6];
++      uint16_t portl, portu;
++      uint16_t msg_agel, msg_ageu;
++      uint16_t max_agel, max_ageu;
++      uint16_t hello_timel, hello_timeu;
++      uint16_t forward_delayl, forward_delayu;
++};
 +
-+static int do_ebt_set_ctl(struct sock *sk,
-+      int cmd, void *user, unsigned int len)
++struct ebt_stp_info
 +{
-+      int ret;
++      uint8_t type;
++      struct ebt_stp_config_info config;
++      uint16_t bitmask;
++      uint16_t invflags;
++};
 +
-+      switch(cmd) {
-+      case EBT_SO_SET_ENTRIES:
-+              ret = do_replace(user, len);
-+              break;
-+      case EBT_SO_SET_COUNTERS:
-+              ret = update_counters(user, len);
-+              break;
-+      default:
-+              ret = -EINVAL;
-+  }
-+      return ret;
-+}
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_vlan.h    2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef __LINUX_BRIDGE_EBT_VLAN_H
++#define __LINUX_BRIDGE_EBT_VLAN_H
++
++#define EBT_VLAN_ID   0x01
++#define EBT_VLAN_PRIO 0x02
++#define EBT_VLAN_ENCAP        0x04
++#define EBT_VLAN_MASK (EBT_VLAN_ID | EBT_VLAN_PRIO | EBT_VLAN_ENCAP)
++#define EBT_VLAN_MATCH "vlan"
++
++struct ebt_vlan_info {
++      uint16_t id;            /* VLAN ID {1-4095} */
++      uint8_t prio;           /* VLAN User Priority {0-7} */
++      uint16_t encap;         /* VLAN Encapsulated frame code {0-65535} */
++      uint8_t bitmask;                /* Args bitmask bit 1=1 - ID arg,
++                                 bit 2=1 User-Priority arg, bit 3=1 encap*/
++      uint8_t invflags;               /* Inverse bitmask  bit 1=1 - inversed ID arg, 
++                                 bit 2=1 - inversed Pirority arg */
++};
++
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_log.h     2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,17 @@
++#ifndef __LINUX_BRIDGE_EBT_LOG_H
++#define __LINUX_BRIDGE_EBT_LOG_H
 +
-+static int do_ebt_get_ctl(struct sock *sk, int cmd, void *user, int *len)
-+{
-+      int ret;
-+      struct ebt_replace tmp;
-+      struct ebt_table *t;
++#define EBT_LOG_IP 0x01 // if the frame is made by ip, log the ip information
++#define EBT_LOG_ARP 0x02
++#define EBT_LOG_MASK (EBT_LOG_IP | EBT_LOG_ARP)
++#define EBT_LOG_PREFIX_SIZE 30
++#define EBT_LOG_WATCHER "log"
 +
-+      if (copy_from_user(&tmp, user, sizeof(tmp)))
-+              return -EFAULT;
++struct ebt_log_info
++{
++      uint8_t loglevel;
++      uint8_t prefix[EBT_LOG_PREFIX_SIZE];
++      uint32_t bitmask;
++};
 +
-+      t = find_table_lock(tmp.name, &ret, &ebt_mutex);
-+      if (!t)
-+              return ret;
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_ulog.h    2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,33 @@
++#ifndef _EBT_ULOG_H
++#define _EBT_ULOG_H
 +
-+      switch(cmd) {
-+      case EBT_SO_GET_INFO:
-+      case EBT_SO_GET_INIT_INFO:
-+              if (*len != sizeof(struct ebt_replace)){
-+                      ret = -EINVAL;
-+                      up(&ebt_mutex);
-+                      break;
-+              }
-+              if (cmd == EBT_SO_GET_INFO) {
-+                      tmp.nentries = t->private->nentries;
-+                      tmp.entries_size = t->private->entries_size;
-+                      tmp.valid_hooks = t->valid_hooks;
-+              } else {
-+                      tmp.nentries = t->table->nentries;
-+                      tmp.entries_size = t->table->entries_size;
-+                      tmp.valid_hooks = t->table->valid_hooks;
-+              }
-+              up(&ebt_mutex);
-+              if (copy_to_user(user, &tmp, *len) != 0){
-+                      BUGPRINT("c2u Didn't work\n");
-+                      ret = -EFAULT;
-+                      break;
-+              }
-+              ret = 0;
-+              break;
++#define EBT_ULOG_DEFAULT_NLGROUP 0
++#define EBT_ULOG_DEFAULT_QTHRESHOLD 1
++#define EBT_ULOG_MAXNLGROUPS 32 /* hardcoded netlink max */
++#define EBT_ULOG_PREFIX_LEN 32
++#define EBT_ULOG_MAX_QLEN 50
++#define EBT_ULOG_WATCHER "ulog"
 +
-+      case EBT_SO_GET_ENTRIES:
-+      case EBT_SO_GET_INIT_ENTRIES:
-+              ret = copy_everything_to_user(t, user, len, cmd);
-+              up(&ebt_mutex);
-+              break;
++struct ebt_ulog_info {
++      uint32_t nlgroup;
++      unsigned int cprange;
++      unsigned int qthreshold;
++      char prefix[EBT_ULOG_PREFIX_LEN];
++};
 +
-+      default:
-+              up(&ebt_mutex);
-+              ret = -EINVAL;
-+      }
++typedef struct ebt_ulog_packet_msg {
++      char indev[IFNAMSIZ];
++      char outdev[IFNAMSIZ];
++      char physindev[IFNAMSIZ];
++      char physoutdev[IFNAMSIZ];
++      char prefix[EBT_ULOG_PREFIX_LEN];
++      struct timeval stamp;
++      unsigned long mark;
++      unsigned int hook;
++      size_t data_len;
++      /* The complete packet, including Ethernet header and perhaps
++       * the VLAN header is appended */
++      unsigned char data[0] __attribute__ ((aligned (__alignof__(int))));
++} ebt_ulog_packet_msg_t;
 +
-+      return ret;
-+}
++#endif /* _EBT_ULOG_H */
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_nat.h     2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,13 @@
++#ifndef __LINUX_BRIDGE_EBT_NAT_H
++#define __LINUX_BRIDGE_EBT_NAT_H
 +
-+static struct nf_sockopt_ops ebt_sockopts =
-+{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl,
-+    EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL
++struct ebt_nat_info
++{
++      unsigned char mac[ETH_ALEN];
++      // EBT_ACCEPT, EBT_DROP, EBT_CONTINUE or EBT_RETURN
++      int target;
 +};
++#define EBT_SNAT_TARGET "snat"
++#define EBT_DNAT_TARGET "dnat"
 +
-+static int __init init(void)
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_redirect.h        2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef __LINUX_BRIDGE_EBT_REDIRECT_H
++#define __LINUX_BRIDGE_EBT_REDIRECT_H
++
++struct ebt_redirect_info
 +{
-+      int ret;
++      // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN
++      int target;
++};
++#define EBT_REDIRECT_TARGET "redirect"
 +
-+      down(&ebt_mutex);
-+      list_named_insert(&ebt_targets, &ebt_standard_target);
-+      up(&ebt_mutex);
-+      if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
-+              return ret;
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_mark_m.h  2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,15 @@
++#ifndef __LINUX_BRIDGE_EBT_MARK_M_H
++#define __LINUX_BRIDGE_EBT_MARK_M_H
 +
-+      printk(KERN_NOTICE "Ebtables v2.0 registered\n");
-+      return 0;
-+}
++#define EBT_MARK_AND 0x01
++#define EBT_MARK_OR 0x02
++#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR)
++struct ebt_mark_m_info
++{
++      unsigned long mark, mask;
++      uint8_t invert;
++      uint8_t bitmask;
++};
++#define EBT_MARK_MATCH "mark_m"
 +
-+static void __exit fini(void)
++#endif
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_bridge/ebt_mark_t.h  2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,12 @@
++#ifndef __LINUX_BRIDGE_EBT_MARK_T_H
++#define __LINUX_BRIDGE_EBT_MARK_T_H
++
++struct ebt_mark_t_info
 +{
-+      nf_unregister_sockopt(&ebt_sockopts);
-+      printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
-+}
++      unsigned long mark;
++      // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN
++      int target;
++};
++#define EBT_MARK_TARGET "mark"
 +
-+EXPORT_SYMBOL(ebt_register_table);
-+EXPORT_SYMBOL(ebt_unregister_table);
-+EXPORT_SYMBOL(ebt_register_match);
-+EXPORT_SYMBOL(ebt_unregister_match);
-+EXPORT_SYMBOL(ebt_register_watcher);
-+EXPORT_SYMBOL(ebt_unregister_watcher);
-+EXPORT_SYMBOL(ebt_register_target);
-+EXPORT_SYMBOL(ebt_unregister_target);
-+EXPORT_SYMBOL(ebt_do_table);
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/core/dev.c linux-ebtables/net/core/dev.c
---- linux-mips-cvs/net/core/dev.c      2004-04-16 05:14:21.000000000 +0200
-+++ linux-ebtables/net/core/dev.c      2005-02-07 05:52:50.000000000 +0100
-@@ -1426,7 +1426,7 @@
++#endif
+--- linux-2.4.29/include/linux/netfilter.h     2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter.h    2005-03-14 21:11:36.000000000 +0100
+@@ -17,7 +17,8 @@
+ #define NF_STOLEN 2
+ #define NF_QUEUE 3
+ #define NF_REPEAT 4
+-#define NF_MAX_VERDICT NF_REPEAT
++#define NF_STOP 5
++#define NF_MAX_VERDICT NF_STOP
  
- #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
--void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
-+int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
+ /* Generic cache responses from hook functions.
+    <= 0x2000 is used for protocol-flags. */
+@@ -118,17 +119,34 @@ extern struct list_head nf_hooks[NPROTO]
+ /* This is gross, but inline doesn't cut it for avoiding the function
+    call in fast path: gcc doesn't inline (needs value tracking?). --RR */
+ #ifdef CONFIG_NETFILTER_DEBUG
+-#define NF_HOOK nf_hook_slow
++#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                           \
++({int __ret;                                                                  \
++if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
++       __ret = (okfn)(skb);                                                   \
++__ret;})
++#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)            \
++({int __ret;                                                                  \
++if ((__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
++       __ret = (okfn)(skb);                                                   \
++__ret;})
+ #else
+-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                   \
+-(list_empty(&nf_hooks[(pf)][(hook)])                                  \
+- ? (okfn)(skb)                                                                \
+- : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
++#define NF_HOOK(pf, hook, skb, indev, outdev, okfn)                           \
++({int __ret;                                                                  \
++if (list_empty(&nf_hooks[pf][hook]) ||                                        \
++    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, INT_MIN)) == 1) \
++       __ret = (okfn)(skb);                                                   \
++__ret;})
++#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)            \
++({int __ret;                                                                  \
++if (list_empty(&nf_hooks[pf][hook]) ||                                        \
++    (__ret=nf_hook_slow(pf, hook, &(skb), indev, outdev, okfn, thresh)) == 1)  \
++       __ret = (okfn)(skb);                                                   \
++__ret;})
  #endif
  
- static __inline__ int handle_bridge(struct sk_buff *skb,
-@@ -1443,7 +1443,6 @@
-               }
-       }
--      br_handle_frame_hook(skb);
-       return ret;
- }
+-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
++int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+                struct net_device *indev, struct net_device *outdev,
+-               int (*okfn)(struct sk_buff *));
++               int (*okfn)(struct sk_buff *), int thresh);
  
-@@ -1503,7 +1502,12 @@
- #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-       if (skb->dev->br_port != NULL && br_handle_frame_hook != NULL &&
-           skb->pkt_type != PACKET_LOOPBACK) {
--              return handle_bridge(skb, pt_prev);
-+              int ret;
+ /* Call setsockopt() */
+ int nf_setsockopt(struct sock *sk, int pf, int optval, char *opt, 
+--- linux-2.4.29/include/linux/netfilter_ipv4.h        2002-02-25 20:38:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_ipv4.h       2005-03-14 21:11:36.000000000 +0100
+@@ -52,8 +52,10 @@
+ enum nf_ip_hook_priorities {
+       NF_IP_PRI_FIRST = INT_MIN,
+       NF_IP_PRI_CONNTRACK = -200,
++      NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
+       NF_IP_PRI_MANGLE = -150,
+       NF_IP_PRI_NAT_DST = -100,
++      NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
+       NF_IP_PRI_FILTER = 0,
+       NF_IP_PRI_NAT_SRC = 100,
+       NF_IP_PRI_LAST = INT_MAX,
+--- linux-2.4.29/include/linux/netfilter_ipv6.h        2001-01-02 01:17:54.000000000 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_ipv6.h       2005-03-14 21:24:11.000000000 +0100
+@@ -57,8 +57,10 @@
+ enum nf_ip6_hook_priorities {
+       NF_IP6_PRI_FIRST = INT_MIN,
+       NF_IP6_PRI_CONNTRACK = -200,
++      NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
+       NF_IP6_PRI_MANGLE = -150,
+       NF_IP6_PRI_NAT_DST = -100,
++      NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT = -50,
+       NF_IP6_PRI_FILTER = 0,
+       NF_IP6_PRI_NAT_SRC = 100,
+       NF_IP6_PRI_LAST = INT_MAX,
+--- linux-2.4.29/include/linux/skbuff.h        2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.29-ebt-brnf/include/linux/skbuff.h       2005-03-14 21:07:31.000000000 +0100
+@@ -92,6 +92,20 @@ struct nf_conntrack {
+ struct nf_ct_info {
+       struct nf_conntrack *master;
+ };
 +
-+              ret = handle_bridge(skb, pt_prev);
-+              if (br_handle_frame_hook(skb) == 0)
-+                      return ret;
-+              pt_prev = NULL;
-       }
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++struct nf_bridge_info {
++      atomic_t use;
++      struct net_device *physindev;
++      struct net_device *physoutdev;
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++      struct net_device *netoutdev;
++#endif
++      unsigned int mask;
++      unsigned long data[32 / sizeof(unsigned long)];
++};
++#endif
++
+ #endif
+ struct sk_buff_head {
+@@ -208,6 +222,9 @@ struct sk_buff {
+ #ifdef CONFIG_NETFILTER_DEBUG
+         unsigned int nf_debug;
  #endif
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      struct nf_bridge_info   *nf_bridge;     /* Saved data about a bridged frame - see br_netfilter.c */
++#endif
+ #endif /*CONFIG_NETFILTER*/
  
-diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.c
---- linux-mips-cvs/net/core/netfilter.c        2005-01-20 03:19:25.000000000 +0100
-+++ linux-ebtables/net/core/netfilter.c        2005-02-07 05:52:50.000000000 +0100
-@@ -342,10 +342,15 @@
+ #if defined(CONFIG_HIPPI)
+@@ -1175,6 +1192,20 @@ nf_reset(struct sk_buff *skb)
+       skb->nf_debug = 0;
+ #endif
+ }
++
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
++{
++      if (nf_bridge && atomic_dec_and_test(&nf_bridge->use))
++              kfree(nf_bridge);
++}
++static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge)
++{
++      if (nf_bridge)
++              atomic_inc(&nf_bridge->use);
++}
++#endif
++
+ #else /* CONFIG_NETFILTER */
+ static inline void nf_reset(struct sk_buff *skb) {}
+ #endif /* CONFIG_NETFILTER */
+--- linux-2.4.29/net/core/netfilter.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/core/netfilter.c 2005-03-14 21:21:41.825275416 +0100
+@@ -342,32 +342,29 @@ static unsigned int nf_iterate(struct li
                               const struct net_device *indev,
                               const struct net_device *outdev,
                               struct list_head **i,
@@ -7410,16 +5292,48 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
 +                             int (*okfn)(struct sk_buff *),
 +                             int hook_thresh)
  {
++      unsigned int verdict;
++
        for (*i = (*i)->next; *i != head; *i = (*i)->next) {
                struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
-+
+-              switch (elem->hook(hook, skb, indev, outdev, okfn)) {
+-              case NF_QUEUE:
+-                      return NF_QUEUE;
+-
+-              case NF_STOLEN:
+-                      return NF_STOLEN;
+-
+-              case NF_DROP:
+-                      return NF_DROP;
+-              case NF_REPEAT:
+-                      *i = (*i)->prev;
+-                      break;
 +              if (hook_thresh > elem->priority)
 +                      continue;
-+
-               switch (elem->hook(hook, skb, indev, outdev, okfn)) {
-               case NF_QUEUE:
-                       return NF_QUEUE;
-@@ -413,6 +418,10 @@
++              verdict = elem->hook(hook, skb, indev, outdev, okfn);
++              if (verdict != NF_ACCEPT) {
+ #ifdef CONFIG_NETFILTER_DEBUG
+-              case NF_ACCEPT:
+-                      break;
+-
+-              default:
+-                      NFDEBUG("Evil return from %p(%u).\n", 
+-                              elem->hook, hook);
++                      if (unlikely(verdict > NF_MAX_VERDICT)) {
++                              NFDEBUG("Evil return from %p(%u).\n",
++                                      elem->hook, hook);
++                              continue;
++                      }
+ #endif
++                      if (verdict != NF_REPEAT)
++                              return verdict;
++                      *i = (*i)->prev;
+               }
+       }
+       return NF_ACCEPT;
+@@ -413,6 +410,10 @@ static void nf_queue(struct sk_buff *skb
  {
        int status;
        struct nf_info *info;
@@ -7430,7 +5344,7 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
  
        if (!queue_handler[pf].outfn) {
                kfree_skb(skb);
-@@ -435,11 +444,24 @@
+@@ -435,36 +436,52 @@ static void nf_queue(struct sk_buff *skb
        if (indev) dev_hold(indev);
        if (outdev) dev_hold(outdev);
  
@@ -7455,8 +5369,13 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
                kfree(info);
                kfree_skb(skb);
                return;
-@@ -449,7 +471,8 @@
- int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
+       }
+ }
+-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
++/* Returns 1 if okfn() needs to be executed by the caller,
++ * -EPERM for NF_DROP, 0 otherwise. */
++int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
                 struct net_device *indev,
                 struct net_device *outdev,
 -               int (*okfn)(struct sk_buff *))
@@ -7465,16 +5384,70 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
  {
        struct list_head *elem;
        unsigned int verdict;
-@@ -481,7 +504,7 @@
+       int ret = 0;
+       /* This stopgap cannot be removed until all the hooks are audited. */
+-      if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
+-              kfree_skb(skb);
++      if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0) {
++              kfree_skb(*pskb);
+               return -ENOMEM;
+       }
+-      if (skb->ip_summed == CHECKSUM_HW) {
++      if ((*pskb)->ip_summed == CHECKSUM_HW) {
+               if (outdev == NULL) {
+-                      skb->ip_summed = CHECKSUM_NONE;
++                      (*pskb)->ip_summed = CHECKSUM_NONE;
+               } else {
+-                      skb_checksum_help(skb);
++                      skb_checksum_help(*pskb);
+               }
+       }
+@@ -472,30 +489,24 @@ int nf_hook_slow(int pf, unsigned int ho
+       br_read_lock_bh(BR_NETPROTO_LOCK);
+ #ifdef CONFIG_NETFILTER_DEBUG
+-      if (skb->nf_debug & (1 << hook)) {
++      if (unlikely((*pskb)->nf_debug & (1 << hook))) {
+               printk("nf_hook: hook %i already set.\n", hook);
+-              nf_dump_skb(pf, skb);
++              nf_dump_skb(pf, *pskb);
+       }
+-      skb->nf_debug |= (1 << hook);
++      (*pskb)->nf_debug |= (1 << hook);
+ #endif
  
        elem = &nf_hooks[pf][hook];
-       verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
+-      verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
 -                           outdev, &elem, okfn);
+-      if (verdict == NF_QUEUE) {
+-              NFDEBUG("nf_hook: Verdict = QUEUE.\n");
+-              nf_queue(skb, elem, pf, hook, indev, outdev, okfn);
+-      }
+-
+-      switch (verdict) {
+-      case NF_ACCEPT:
+-              ret = okfn(skb);
+-              break;
+-
+-      case NF_DROP:
+-              kfree_skb(skb);
++      verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
 +                           outdev, &elem, okfn, hook_thresh);
-       if (verdict == NF_QUEUE) {
-               NFDEBUG("nf_hook: Verdict = QUEUE.\n");
-               nf_queue(skb, elem, pf, hook, indev, outdev, okfn);
-@@ -510,6 +533,14 @@
++      if (verdict == NF_ACCEPT || verdict == NF_STOP)
++              ret = 1;
++      else if (verdict == NF_DROP) {
++              kfree_skb(*pskb);
+               ret = -EPERM;
+-              break;
++      } else if (verdict == NF_QUEUE) {
++              NFDEBUG("nf_hook: Verdict = QUEUE.\n");
++              nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn);
+       }
+       br_read_unlock_bh(BR_NETPROTO_LOCK);
+@@ -510,6 +521,14 @@ void nf_reinject(struct sk_buff *skb, st
  
        /* We don't have BR_NETPROTO_LOCK here */
        br_read_lock_bh(BR_NETPROTO_LOCK);
@@ -7489,7 +5462,7 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
        for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) {
                if (i == &nf_hooks[info->pf][info->hook]) {
                        /* The module which sent it to userspace is gone. */
-@@ -530,7 +561,7 @@
+@@ -530,7 +549,7 @@ void nf_reinject(struct sk_buff *skb, st
                verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
                                     &skb, info->hook, 
                                     info->indev, info->outdev, &elem,
@@ -7498,10 +5471,9 @@ diff -Nur linux-mips-cvs/net/core/netfilter.c linux-ebtables/net/core/netfilter.
        }
  
        switch (verdict) {
-diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
---- linux-mips-cvs/net/core/skbuff.c   2003-08-13 19:19:30.000000000 +0200
-+++ linux-ebtables/net/core/skbuff.c   2005-02-07 05:52:50.000000000 +0100
-@@ -246,6 +246,9 @@
+--- linux-2.4.29/net/core/skbuff.c     2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/core/skbuff.c    2005-03-14 00:00:30.000000000 +0100
+@@ -246,6 +246,9 @@ static inline void skb_headerinit(void *
  #ifdef CONFIG_NETFILTER_DEBUG
        skb->nf_debug = 0;
  #endif
@@ -7511,7 +5483,7 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  #endif
  #ifdef CONFIG_NET_SCHED
        skb->tc_index = 0;
-@@ -326,6 +329,9 @@
+@@ -326,6 +329,9 @@ void __kfree_skb(struct sk_buff *skb)
        }
  #ifdef CONFIG_NETFILTER
        nf_conntrack_put(skb->nfct);
@@ -7521,7 +5493,7 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  #endif
        skb_headerinit(skb, NULL, 0);  /* clean state */
        kfree_skbmem(skb);
-@@ -393,6 +399,9 @@
+@@ -393,6 +399,9 @@ struct sk_buff *skb_clone(struct sk_buff
  #ifdef CONFIG_NETFILTER_DEBUG
        C(nf_debug);
  #endif
@@ -7531,7 +5503,7 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  #endif /*CONFIG_NETFILTER*/
  #if defined(CONFIG_HIPPI)
        C(private);
-@@ -405,6 +414,9 @@
+@@ -405,6 +414,9 @@ struct sk_buff *skb_clone(struct sk_buff
        skb->cloned = 1;
  #ifdef CONFIG_NETFILTER
        nf_conntrack_get(skb->nfct);
@@ -7541,7 +5513,7 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  #endif
        return n;
  }
-@@ -440,6 +452,10 @@
+@@ -440,6 +452,10 @@ static void copy_skb_header(struct sk_bu
  #ifdef CONFIG_NETFILTER_DEBUG
        new->nf_debug=old->nf_debug;
  #endif
@@ -7552,7 +5524,7 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  #endif
  #ifdef CONFIG_NET_SCHED
        new->tc_index = old->tc_index;
-@@ -726,9 +742,9 @@
+@@ -726,9 +742,9 @@ struct sk_buff *skb_copy_expand(const st
        /* Set the tail pointer and length */
        skb_put(n,skb->len);
  
@@ -7565,10 +5537,106 @@ diff -Nur linux-mips-cvs/net/core/skbuff.c linux-ebtables/net/core/skbuff.c
  
        copy_skb_header(n, skb);
        return n;
-diff -Nur linux-mips-cvs/net/ipv4/ip_output.c linux-ebtables/net/ipv4/ip_output.c
---- linux-mips-cvs/net/ipv4/ip_output.c        2005-01-20 03:19:25.000000000 +0100
-+++ linux-ebtables/net/ipv4/ip_output.c        2005-02-07 05:52:50.000000000 +0100
-@@ -890,6 +890,10 @@
+--- linux-2.4.29/net/ipv4/netfilter/ip_tables.c        2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/ip_tables.c       2005-03-14 00:00:30.000000000 +0100
+@@ -118,12 +118,19 @@ static LIST_HEAD(ipt_tables);
+ static inline int
+ ip_packet_match(const struct iphdr *ip,
+               const char *indev,
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++              const char *physindev,
++#endif
+               const char *outdev,
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++              const char *physoutdev,
++#endif
+               const struct ipt_ip *ipinfo,
+               int isfrag)
+ {
+       size_t i;
+       unsigned long ret;
++      unsigned long ret2 = 1;
+ #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
+@@ -153,7 +160,15 @@ ip_packet_match(const struct iphdr *ip,
+                       & ((const unsigned long *)ipinfo->iniface_mask)[i];
+       }
+-      if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
++              ret2 |= (((const unsigned long *)physindev)[i]
++                      ^ ((const unsigned long *)ipinfo->iniface)[i])
++                      & ((const unsigned long *)ipinfo->iniface_mask)[i];
++      }
++#endif
++
++      if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_IN)) {
+               dprintf("VIA in mismatch (%s vs %s).%s\n",
+                       indev, ipinfo->iniface,
+                       ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
+@@ -166,7 +181,15 @@ ip_packet_match(const struct iphdr *ip,
+                       & ((const unsigned long *)ipinfo->outiface_mask)[i];
+       }
+-      if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
++              ret2 |= (((const unsigned long *)physoutdev)[i]
++                      ^ ((const unsigned long *)ipinfo->outiface)[i])
++                      & ((const unsigned long *)ipinfo->outiface_mask)[i];
++      }
++#endif
++
++      if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_OUT)) {
+               dprintf("VIA out mismatch (%s vs %s).%s\n",
+                       outdev, ipinfo->outiface,
+                       ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
+@@ -265,6 +288,9 @@ ipt_do_table(struct sk_buff **pskb,
+       /* Initializing verdict to NF_DROP keeps gcc happy. */
+       unsigned int verdict = NF_DROP;
+       const char *indev, *outdev;
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      const char *physindev, *physoutdev;
++#endif
+       void *table_base;
+       struct ipt_entry *e, *back;
+@@ -274,6 +300,13 @@ ipt_do_table(struct sk_buff **pskb,
+       datalen = (*pskb)->len - ip->ihl * 4;
+       indev = in ? in->name : nulldevname;
+       outdev = out ? out->name : nulldevname;
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      physindev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physindev) ?
++              (*pskb)->nf_bridge->physindev->name : nulldevname;
++      physoutdev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physoutdev) ?
++              (*pskb)->nf_bridge->physoutdev->name : nulldevname;
++#endif
++
+       /* We handle fragments by dealing with the first fragment as
+        * if it was a normal packet.  All other fragments are treated
+        * normally, except that they will NEVER match rules that ask
+@@ -309,7 +342,15 @@ ipt_do_table(struct sk_buff **pskb,
+               IP_NF_ASSERT(e);
+               IP_NF_ASSERT(back);
+               (*pskb)->nfcache |= e->nfcache;
+-              if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
++              if (ip_packet_match(ip, indev,
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++                  physindev,
++#endif
++                  outdev,
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++                  physoutdev,
++#endif
++                  &e->ip, offset)) {
+                       struct ipt_entry_target *t;
+                       if (IPT_MATCH_ITERATE(e, do_match,
+--- linux-2.4.29/net/ipv4/ip_output.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/ip_output.c 2005-03-14 00:00:30.000000000 +0100
+@@ -890,6 +890,10 @@ int ip_fragment(struct sk_buff *skb, int
                /* Connection association is same as pre-frag packet */
                skb2->nfct = skb->nfct;
                nf_conntrack_get(skb2->nfct);
@@ -7579,1652 +5647,1156 @@ diff -Nur linux-mips-cvs/net/ipv4/ip_output.c linux-ebtables/net/ipv4/ip_output.
  #ifdef CONFIG_NETFILTER_DEBUG
                skb2->nf_debug = skb->nf_debug;
  #endif
-diff -Nur linux-mips-cvs/net/ipv4/ip_output.c.orig linux-ebtables/net/ipv4/ip_output.c.orig
---- linux-mips-cvs/net/ipv4/ip_output.c.orig   1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/ipv4/ip_output.c.orig   2005-01-20 03:19:25.000000000 +0100
-@@ -0,0 +1,1036 @@
+--- linux-2.4.29/net/ipv4/netfilter/ipt_LOG.c  2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/ipt_LOG.c 2005-03-14 00:00:30.000000000 +0100
+@@ -316,6 +316,18 @@ ipt_log_target(struct sk_buff **pskb,
+              loginfo->prefix,
+              in ? in->name : "",
+              out ? out->name : "");
++#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
++      if ((*pskb)->nf_bridge) {
++              struct net_device *physindev = (*pskb)->nf_bridge->physindev;
++              struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
++
++              if (physindev && in != physindev)
++                      printk("PHYSIN=%s ", physindev->name);
++              if (physoutdev && out != physoutdev)
++                      printk("PHYSOUT=%s ", physoutdev->name);
++      }
++#endif
++
+       if (in && !out) {
+               /* MAC logging for input chain only. */
+               printk("MAC=");
+--- linux-2.4.29/net/ipv4/netfilter/Makefile   2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/Makefile  2005-03-14 00:00:30.000000000 +0100
+@@ -87,6 +87,8 @@ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += i
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
++obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
++
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+ obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
+--- linux-2.4.29/net/ipv4/netfilter/Config.in  2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/Config.in 2005-03-14 00:00:30.000000000 +0100
+@@ -44,6 +44,9 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; 
+     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
+     dep_tristate '  Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES
+   fi
++  if [ "$CONFIG_BRIDGE" != "n" ]; then
++    dep_tristate '  Physdev match support' CONFIG_IP_NF_MATCH_PHYSDEV $CONFIG_IP_NF_IPTABLES
++  fi
+ # The targets
+   dep_tristate '  Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES 
+   if [ "$CONFIG_IP_NF_FILTER" != "n" ]; then
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/bridge/br_netfilter.c    2005-03-14 00:00:30.000000000 +0100
+@@ -0,0 +1,1101 @@
 +/*
-+ * INET               An implementation of the TCP/IP protocol suite for the LINUX
-+ *            operating system.  INET is implemented using the  BSD Socket
-+ *            interface as the means of communication with the user level.
-+ *
-+ *            The Internet Protocol (IP) output module.
++ *    Handle firewalling
++ *    Linux ethernet bridge
 + *
-+ * Version:   $Id$
++ *    Authors:
++ *    Lennert Buytenhek               <buytenh@gnu.org>
++ *    Bart De Schuymer (maintainer)   <bdschuym@pandora.be>
 + *
-+ * Authors:   Ross Biro, <bir7@leland.Stanford.Edu>
-+ *            Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
-+ *            Donald Becker, <becker@super.org>
-+ *            Alan Cox, <Alan.Cox@linux.org>
-+ *            Richard Underwood
-+ *            Stefan Becker, <stefanb@yello.ping.de>
-+ *            Jorge Cwik, <jorge@laser.satlink.net>
-+ *            Arnt Gulbrandsen, <agulbra@nvg.unit.no>
++ *    Changes:
++ *    Apr 29 2003: physdev module support (bdschuym)
++ *    Jun 19 2003: let arptables see bridged ARP traffic (bdschuym)
++ *    Oct 06 2003: filter encapsulated IP/ARP VLAN traffic on untagged bridge
++ *                 (bdschuym)
++ *    Aug 28 2004: add IPv6 filtering (bdschuym)
 + *
-+ *    See ip_input.c for original log
++ *    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.
 + *
-+ *    Fixes:
-+ *            Alan Cox        :       Missing nonblock feature in ip_build_xmit.
-+ *            Mike Kilburn    :       htons() missing in ip_build_xmit.
-+ *            Bradford Johnson:       Fix faulty handling of some frames when 
-+ *                                    no route is found.
-+ *            Alexander Demenshin:    Missing sk/skb free in ip_queue_xmit
-+ *                                    (in case if packet not accepted by
-+ *                                    output firewall rules)
-+ *            Mike McLagan    :       Routing by source
-+ *            Alexey Kuznetsov:       use new route cache
-+ *            Andi Kleen:             Fix broken PMTU recovery and remove
-+ *                                    some redundant tests.
-+ *    Vitaly E. Lavrov        :       Transparent proxy revived after year coma.
-+ *            Andi Kleen      :       Replace ip_reply with ip_send_reply.
-+ *            Andi Kleen      :       Split fast and slow ip_build_xmit path 
-+ *                                    for decreased register pressure on x86 
-+ *                                    and more readibility. 
-+ *            Marc Boucher    :       When call_out_firewall returns FW_QUEUE,
-+ *                                    silently drop skb instead of failing with -EPERM.
-+ *            Detlev Wengorz  :       Copy protocol for fragments.
++ *    Lennert dedicates this file to Kerstin Wurdinger.
 + */
 +
-+#include <asm/uaccess.h>
-+#include <asm/system.h>
-+#include <linux/types.h>
++#include <linux/module.h>
 +#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/config.h>
-+
-+#include <linux/socket.h>
-+#include <linux/sockios.h>
-+#include <linux/in.h>
-+#include <linux/inet.h>
++#include <linux/ip.h>
 +#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/proc_fs.h>
-+#include <linux/stat.h>
-+#include <linux/init.h>
-+
-+#include <net/snmp.h>
-+#include <net/ip.h>
-+#include <net/protocol.h>
-+#include <net/route.h>
-+#include <net/tcp.h>
-+#include <net/udp.h>
 +#include <linux/skbuff.h>
-+#include <net/sock.h>
-+#include <net/arp.h>
-+#include <net/icmp.h>
-+#include <net/raw.h>
-+#include <net/checksum.h>
-+#include <net/inetpeer.h>
-+#include <linux/igmp.h>
++#include <linux/if_ether.h>
++#include <linux/if_vlan.h>
++#include <linux/netfilter_bridge.h>
 +#include <linux/netfilter_ipv4.h>
-+#include <linux/mroute.h>
-+#include <linux/netlink.h>
++#include <linux/netfilter_ipv6.h>
++#include <linux/in_route.h>
++#include <net/ip.h>
++#include <net/ipv6.h>
++#include <asm/uaccess.h>
++#include <asm/checksum.h>
++#include "br_private.h"
++#ifdef CONFIG_SYSCTL
++#include <linux/sysctl.h>
++#endif
++
++#define skb_origaddr(skb)      (((struct bridge_skb_cb *) \
++                               (skb->nf_bridge->data))->daddr.ipv4)
++#define store_orig_dstaddr(skb)        (skb_origaddr(skb) = (skb)->nh.iph->daddr)
++#define dnat_took_place(skb)   (skb_origaddr(skb) != (skb)->nh.iph->daddr)
++
++#define has_bridge_parent(device)     ((device)->br_port != NULL)
++#define bridge_parent(device)         (&((device)->br_port->br->dev))
 +
++#ifdef CONFIG_SYSCTL
++static struct ctl_table_header *brnf_sysctl_header;
++static int brnf_call_iptables = 1;
++static int brnf_call_ip6tables = 1;
++static int brnf_call_arptables = 1;
++static int brnf_filter_vlan_tagged = 1;
++#else
++#define brnf_filter_vlan_tagged 1
++#endif
++
++#define IS_VLAN_IP (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
++      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP) &&  \
++      brnf_filter_vlan_tagged)
++#define IS_VLAN_IPV6 (skb->protocol == __constant_htons(ETH_P_8021Q) &&    \
++      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_IPV6) &&  \
++      brnf_filter_vlan_tagged)
 +/*
-+ *      Shall we try to damage output packets if routing dev changes?
++#define IS_VLAN_ARP (skb->protocol == __constant_htons(ETH_P_8021Q) &&   \
++      hdr->h_vlan_encapsulated_proto == __constant_htons(ETH_P_ARP) && \
++      brnf_filter_vlan_tagged)
++*/
++
++/* We need these fake structures to make netfilter happy --
++ * lots of places assume that skb->dst != NULL, which isn't
++ * all that unreasonable.
++ *
++ * Currently, we fill in the PMTU entry because netfilter
++ * refragmentation needs it, and the rt_flags entry because
++ * ipt_REJECT needs it.  Future netfilter modules might
++ * require us to fill additional fields.
 + */
++static struct net_device __fake_net_device = {
++      .hard_header_len        = ETH_HLEN
++};
 +
-+int sysctl_ip_dynaddr = 0;
-+int sysctl_ip_default_ttl = IPDEFTTL;
++static struct rtable __fake_rtable = {
++      u: {
++              dst: {
++                      __refcnt:               ATOMIC_INIT(1),
++                      dev:                    &__fake_net_device,
++                      pmtu:                   1500
++              }
++      },
 +
-+/* Generate a checksum for an outgoing IP datagram. */
-+__inline__ void ip_send_check(struct iphdr *iph)
-+{
-+      iph->check = 0;
-+      iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+}
++      rt_flags:       0
++};
 +
-+/* dev_loopback_xmit for use with netfilter. */
-+static int ip_dev_loopback_xmit(struct sk_buff *newskb)
++
++/* PF_BRIDGE/PRE_ROUTING *********************************************/
++/* Undo the changes made for ip6tables PREROUTING and continue the
++ * bridge PRE_ROUTING hook. */
++static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
 +{
-+      newskb->mac.raw = newskb->data;
-+      __skb_pull(newskb, newskb->nh.raw - newskb->data);
-+      newskb->pkt_type = PACKET_LOOPBACK;
-+      newskb->ip_summed = CHECKSUM_UNNECESSARY;
-+      BUG_TRAP(newskb->dst);
++      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 +
 +#ifdef CONFIG_NETFILTER_DEBUG
-+      nf_debug_ip_loopback_xmit(newskb);
++      skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
 +#endif
-+      netif_rx(newskb);
++
++      if (nf_bridge->mask & BRNF_PKT_TYPE) {
++              skb->pkt_type = PACKET_OTHERHOST;
++              nf_bridge->mask ^= BRNF_PKT_TYPE;
++      }
++      nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
++
++      skb->dst = (struct dst_entry *)&__fake_rtable;
++      dst_hold(skb->dst);
++
++      skb->dev = nf_bridge->physindev;
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_push(skb, VLAN_HLEN);
++              skb->nh.raw -= VLAN_HLEN;
++      }
++      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
++                     br_handle_frame_finish, 1);
++
 +      return 0;
 +}
 +
-+/* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
-+   changes route */
-+static inline int
-+output_maybe_reroute(struct sk_buff *skb)
++static void __br_dnat_complain(void)
 +{
-+      return skb->dst->output(skb);
++      static unsigned long last_complaint;
++
++      if (jiffies - last_complaint >= 5 * HZ) {
++              printk(KERN_WARNING "Performing cross-bridge DNAT requires IP "
++                      "forwarding to be enabled\n");
++              last_complaint = jiffies;
++      }
 +}
 +
-+/* 
-+ *            Add an ip header to a skbuff and send it out.
-+ */
-+int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
-+                        u32 saddr, u32 daddr, struct ip_options *opt)
-+{
-+      struct rtable *rt = (struct rtable *)skb->dst;
-+      struct iphdr *iph;
 +
-+      /* Build the IP header. */
-+      if (opt)
-+              iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr) + opt->optlen);
-+      else
-+              iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr));
++/* This requires some explaining. If DNAT has taken place,
++ * we will need to fix up the destination Ethernet address,
++ * and this is a tricky process.
++ *
++ * There are two cases to consider:
++ * 1. The packet was DNAT'ed to a device in the same bridge
++ *    port group as it was received on. We can still bridge
++ *    the packet.
++ * 2. The packet was DNAT'ed to a different device, either
++ *    a non-bridged device or another bridge port group.
++ *    The packet will need to be routed.
++ *
++ * The correct way of distinguishing between these two cases is to
++ * call ip_route_input() and to look at skb->dst->dev, which is
++ * changed to the destination device if ip_route_input() succeeds.
++ *
++ * Let us first consider the case that ip_route_input() succeeds:
++ *
++ * If skb->dst->dev equals the logical bridge device the packet
++ * came in on, we can consider this bridging. We then call
++ * skb->dst->output() which will make the packet enter br_nf_local_out()
++ * not much later. In that function it is assured that the iptables
++ * FORWARD chain is traversed for the packet.
++ *
++ * Otherwise, the packet is considered to be routed and we just
++ * change the destination MAC address so that the packet will
++ * later be passed up to the IP stack to be routed.
++ *
++ * Let us now consider the case that ip_route_input() fails:
++ *
++ * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
++ * will fail, while __ip_route_output_key() will return success. The source
++ * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
++ * thinks we're handling a locally generated packet and won't care
++ * if IP forwarding is allowed. We send a warning message to the users's
++ * log telling her to put IP forwarding on.
++ *
++ * ip_route_input() will also fail if there is no route available.
++ * In that case we just drop the packet.
++ *
++ * --Lennert, 20020411
++ * --Bart, 20020416 (updated)
++ * --Bart, 20021007 (updated)
++ */
 +
-+      iph->version  = 4;
-+      iph->ihl      = 5;
-+      iph->tos      = sk->protinfo.af_inet.tos;
-+      if (ip_dont_fragment(sk, &rt->u.dst))
-+              iph->frag_off = htons(IP_DF);
-+      else
-+              iph->frag_off = 0;
-+      iph->ttl      = sk->protinfo.af_inet.ttl;
-+      iph->daddr    = rt->rt_dst;
-+      iph->saddr    = rt->rt_src;
-+      iph->protocol = sk->protocol;
-+      iph->tot_len  = htons(skb->len);
-+      ip_select_ident(iph, &rt->u.dst, sk);
-+      skb->nh.iph   = iph;
++static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
++{
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug |= (1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_FORWARD);
++#endif
 +
-+      if (opt && opt->optlen) {
-+              iph->ihl += opt->optlen>>2;
-+              ip_options_build(skb, opt, daddr, rt, 0);
++      if (skb->pkt_type == PACKET_OTHERHOST) {
++              skb->pkt_type = PACKET_HOST;
++              skb->nf_bridge->mask |= BRNF_PKT_TYPE;
 +      }
-+      ip_send_check(iph);
++      skb->nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 +
-+      /* Send it out. */
-+      return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-+                     output_maybe_reroute);
++      skb->dev = bridge_parent(skb->dev);
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_pull(skb, VLAN_HLEN);
++              skb->nh.raw += VLAN_HLEN;
++      }
++      skb->dst->output(skb);
++      return 0;
 +}
 +
-+static inline int ip_finish_output2(struct sk_buff *skb)
++static int br_nf_pre_routing_finish(struct sk_buff *skb)
 +{
-+      struct dst_entry *dst = skb->dst;
-+      struct hh_cache *hh = dst->hh;
++      struct net_device *dev = skb->dev;
++      struct iphdr *iph = skb->nh.iph;
++      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 +
 +#ifdef CONFIG_NETFILTER_DEBUG
-+      nf_debug_ip_finish_output2(skb);
-+#endif /*CONFIG_NETFILTER_DEBUG*/
++      skb->nf_debug ^= (1 << NF_BR_PRE_ROUTING);
++#endif
++
++      if (nf_bridge->mask & BRNF_PKT_TYPE) {
++              skb->pkt_type = PACKET_OTHERHOST;
++              nf_bridge->mask ^= BRNF_PKT_TYPE;
++      }
++      nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
++
++      if (dnat_took_place(skb)) {
++              if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
++                  dev)) {
++                      struct rtable *rt;
 +
-+      if (hh) {
-+              int hh_alen;
++                      if (!ip_route_output(&rt, iph->daddr, 0, iph->tos, 0)) {
++                              /* Bridged-and-DNAT'ed traffic doesn't
++                               * require ip_forwarding.
++                               */
++                              if (((struct dst_entry *)rt)->dev == dev) {
++                                      skb->dst = (struct dst_entry *)rt;
++                                      goto bridged_dnat;
++                              }
++                              __br_dnat_complain();
++                              dst_release((struct dst_entry *)rt);
++                      }
++                      kfree_skb(skb);
++                      return 0;
++              } else {
++                      if (skb->dst->dev == dev) {
++bridged_dnat:
++                              /* Tell br_nf_local_out this is a
++                               * bridged frame
++                               */
++                              nf_bridge->mask |= BRNF_BRIDGED_DNAT;
++                              skb->dev = nf_bridge->physindev;
++                              if (skb->protocol ==
++                                  __constant_htons(ETH_P_8021Q)) {
++                                      skb_push(skb, VLAN_HLEN);
++                                      skb->nh.raw -= VLAN_HLEN;
++                              }
++                              NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
++                                             skb, skb->dev, NULL,
++                                             br_nf_pre_routing_finish_bridge,
++                                             1);
++                              return 0;
++                      }
++                      memcpy(skb->mac.ethernet->h_dest, dev->dev_addr,
++                             ETH_ALEN);
++                      skb->pkt_type = PACKET_HOST;
++              }
++      } else {
++              skb->dst = (struct dst_entry *)&__fake_rtable;
++              dst_hold(skb->dst);
++      }
 +
-+              read_lock_bh(&hh->hh_lock);
-+              hh_alen = HH_DATA_ALIGN(hh->hh_len);
-+              memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
-+              read_unlock_bh(&hh->hh_lock);
-+              skb_push(skb, hh->hh_len);
-+              return hh->hh_output(skb);
-+      } else if (dst->neighbour)
-+              return dst->neighbour->output(skb);
++      skb->dev = nf_bridge->physindev;
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_push(skb, VLAN_HLEN);
++              skb->nh.raw -= VLAN_HLEN;
++      }
++      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
++                     br_handle_frame_finish, 1);
 +
-+      if (net_ratelimit())
-+              printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
-+      kfree_skb(skb);
-+      return -EINVAL;
++      return 0;
 +}
 +
-+static __inline__ int __ip_finish_output(struct sk_buff *skb)
++/* Some common code for IPv4/IPv6 */
++static void setup_pre_routing(struct sk_buff *skb)
 +{
-+      struct net_device *dev = skb->dst->dev;
++      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
 +
-+      skb->dev = dev;
-+      skb->protocol = htons(ETH_P_IP);
++      if (skb->pkt_type == PACKET_OTHERHOST) {
++              skb->pkt_type = PACKET_HOST;
++              nf_bridge->mask |= BRNF_PKT_TYPE;
++      }
 +
-+      return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
-+                     ip_finish_output2);
++      nf_bridge->mask |= BRNF_NF_BRIDGE_PREROUTING;
++      nf_bridge->physindev = skb->dev;
++      skb->dev = bridge_parent(skb->dev);
 +}
 +
-+int ip_finish_output(struct sk_buff *skb)
++/* We only check the length. A bridge shouldn't do any hop-by-hop stuff anyway */
++static int check_hbh_len(struct sk_buff *skb)
 +{
-+      return __ip_finish_output(skb);
-+}
++      unsigned char *raw = (u8*)(skb->nh.ipv6h+1);
++      u32 pkt_len;
++      int off = raw - skb->nh.raw;
++      int len = (raw[1]+1)<<3;
 +
-+int ip_mc_output(struct sk_buff *skb)
-+{
-+      struct sock *sk = skb->sk;
-+      struct rtable *rt = (struct rtable*)skb->dst;
-+      struct net_device *dev = rt->u.dst.dev;
++      if ((raw + len) - skb->data > skb_headlen(skb))
++              goto bad;
 +
-+      /*
-+       *      If the indicated interface is up and running, send the packet.
-+       */
-+      IP_INC_STATS(IpOutRequests);
-+#ifdef CONFIG_IP_ROUTE_NAT
-+      if (rt->rt_flags & RTCF_NAT)
-+              ip_do_nat(skb);
-+#endif
++      off += 2;
++      len -= 2;
 +
-+      skb->dev = dev;
-+      skb->protocol = htons(ETH_P_IP);
++      while (len > 0) {
++              int optlen = raw[off+1]+2;
 +
-+      /*
-+       *      Multicasts are looped back for other local users
-+       */
++              switch (skb->nh.raw[off]) {
++              case IPV6_TLV_PAD0:
++                      optlen = 1;
++                      break;
 +
-+      if (rt->rt_flags&RTCF_MULTICAST) {
-+              if ((!sk || sk->protinfo.af_inet.mc_loop)
-+#ifdef CONFIG_IP_MROUTE
-+              /* Small optimization: do not loopback not local frames,
-+                 which returned after forwarding; they will be  dropped
-+                 by ip_mr_input in any case.
-+                 Note, that local frames are looped back to be delivered
-+                 to local recipients.
++              case IPV6_TLV_PADN:
++                      break;
 +
-+                 This check is duplicated in ip_mr_input at the moment.
-+               */
-+                  && ((rt->rt_flags&RTCF_LOCAL) || !(IPCB(skb)->flags&IPSKB_FORWARDED))
-+#endif
-+              ) {
-+                      struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
-+                      if (newskb)
-+                              NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
-+                                      newskb->dev, 
-+                                      ip_dev_loopback_xmit);
-+              }
++              case IPV6_TLV_JUMBO:
++                      if (skb->nh.raw[off+1] != 4 || (off&3) != 2)
++                              goto bad;
 +
-+              /* Multicasts with ttl 0 must not go beyond the host */
++                      pkt_len = ntohl(*(u32*)(skb->nh.raw+off+2));
 +
-+              if (skb->nh.iph->ttl == 0) {
-+                      kfree_skb(skb);
-+                      return 0;
++                      if (pkt_len > skb->len - sizeof(struct ipv6hdr))
++                              goto bad;
++                      if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
++                              if (__pskb_trim(skb,
++                                  pkt_len + sizeof(struct ipv6hdr)))
++                                      goto bad;
++                              if (skb->ip_summed == CHECKSUM_HW)
++                                      skb->ip_summed = CHECKSUM_NONE;
++                      }
++                      break;
++              default:
++                      if (optlen > len)
++                              goto bad;
++                      break;
 +              }
++              off += optlen;
++              len -= optlen;
 +      }
++      if (len == 0)
++              return 0;
++bad:
++      return -1;
 +
-+      if (rt->rt_flags&RTCF_BROADCAST) {
-+              struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
-+              if (newskb)
-+                      NF_HOOK(PF_INET, NF_IP_POST_ROUTING, newskb, NULL,
-+                              newskb->dev, ip_dev_loopback_xmit);
-+      }
-+
-+      return __ip_finish_output(skb);
 +}
 +
-+int ip_output(struct sk_buff *skb)
++/* Replicate the checks that IPv6 does on packet reception and pass the packet
++ * to ip6tables, which doesn't support NAT, so things are fairly simple. */
++static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
++   struct sk_buff *skb, const struct net_device *in,
++   const struct net_device *out, int (*okfn)(struct sk_buff *))
 +{
-+#ifdef CONFIG_IP_ROUTE_NAT
-+      struct rtable *rt = (struct rtable*)skb->dst;
-+#endif
-+
-+      IP_INC_STATS(IpOutRequests);
++      struct ipv6hdr *hdr;
++      u32 pkt_len;
++      struct nf_bridge_info *nf_bridge;
 +
-+#ifdef CONFIG_IP_ROUTE_NAT
-+      if (rt->rt_flags&RTCF_NAT)
-+              ip_do_nat(skb);
-+#endif
++      if (skb->len < sizeof(struct ipv6hdr))
++              goto inhdr_error;
 +
-+      return __ip_finish_output(skb);
-+}
++      if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
++              goto inhdr_error;
 +
-+/* Queues a packet to be sent, and starts the transmitter if necessary.  
-+ * This routine also needs to put in the total length and compute the 
-+ * checksum.  We use to do this in two stages, ip_build_header() then
-+ * this, but that scheme created a mess when routes disappeared etc.
-+ * So we do it all here, and the TCP send engine has been changed to
-+ * match. (No more unroutable FIN disasters, etc. wheee...)  This will
-+ * most likely make other reliable transport layers above IP easier
-+ * to implement under Linux.
-+ */
-+static inline int ip_queue_xmit2(struct sk_buff *skb)
-+{
-+      struct sock *sk = skb->sk;
-+      struct rtable *rt = (struct rtable *)skb->dst;
-+      struct net_device *dev;
-+      struct iphdr *iph = skb->nh.iph;
++      hdr = skb->nh.ipv6h;
 +
-+      dev = rt->u.dst.dev;
++      if (hdr->version != 6)
++              goto inhdr_error;
 +
-+      /* This can happen when the transport layer has segments queued
-+       * with a cached route, and by the time we get here things are
-+       * re-routed to a device with a different MTU than the original
-+       * device.  Sick, but we must cover it.
-+       */
-+      if (skb_headroom(skb) < dev->hard_header_len && dev->hard_header) {
-+              struct sk_buff *skb2;
++      pkt_len = ntohs(hdr->payload_len);
 +
-+              skb2 = skb_realloc_headroom(skb, (dev->hard_header_len + 15) & ~15);
-+              kfree_skb(skb);
-+              if (skb2 == NULL)
-+                      return -ENOMEM;
-+              if (sk)
-+                      skb_set_owner_w(skb2, sk);
-+              skb = skb2;
-+              iph = skb->nh.iph;
++      if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) {
++              if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
++                      goto inhdr_error;
++              if (pkt_len + sizeof(struct ipv6hdr) < skb->len) {
++                      if (__pskb_trim(skb, pkt_len + sizeof(struct ipv6hdr)))
++                              goto inhdr_error;
++                      if (skb->ip_summed == CHECKSUM_HW)
++                              skb->ip_summed = CHECKSUM_NONE;
++              }
 +      }
++      if (hdr->nexthdr == NEXTHDR_HOP && check_hbh_len(skb))
++              goto inhdr_error;
 +
-+      if (skb->len > rt->u.dst.pmtu)
-+              goto fragment;
-+
-+      ip_select_ident(iph, &rt->u.dst, sk);
-+
-+      /* Add an IP checksum. */
-+      ip_send_check(iph);
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug ^= (1 << NF_IP6_PRE_ROUTING);
++#endif
++      if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
++              return NF_DROP;
++      setup_pre_routing(skb);
 +
-+      skb->priority = sk->priority;
-+      return skb->dst->output(skb);
++      NF_HOOK(PF_INET6, NF_IP6_PRE_ROUTING, skb, skb->dev, NULL,
++              br_nf_pre_routing_finish_ipv6);
 +
-+fragment:
-+      if (ip_dont_fragment(sk, &rt->u.dst)) {
-+              /* Reject packet ONLY if TCP might fragment
-+               * it itself, if were careful enough.
-+               */
-+              NETDEBUG(printk(KERN_DEBUG "sending pkt_too_big (len[%u] pmtu[%u]) to self\n",
-+                              skb->len, rt->u.dst.pmtu));
++      return NF_STOLEN;
 +
-+              icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-+                        htonl(rt->u.dst.pmtu));
-+              kfree_skb(skb);
-+              return -EMSGSIZE;
-+      }
-+      ip_select_ident(iph, &rt->u.dst, sk);
-+      if (skb->ip_summed == CHECKSUM_HW &&
-+          (skb = skb_checksum_help(skb)) == NULL)
-+              return -ENOMEM;
-+      return ip_fragment(skb, skb->dst->output);
++inhdr_error:
++      return NF_DROP;
 +}
 +
-+int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
++/* Direct IPv6 traffic to br_nf_pre_routing_ipv6.
++ * Replicate the checks that IPv4 does on packet reception.
++ * Set skb->dev to the bridge device (i.e. parent of the
++ * receiving device) to make netfilter happy, the REDIRECT
++ * target in particular.  Save the original destination IP
++ * address to be able to detect DNAT afterwards.
++ */
++static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
 +{
-+      struct sock *sk = skb->sk;
-+      struct ip_options *opt = sk->protinfo.af_inet.opt;
-+      struct rtable *rt;
 +      struct iphdr *iph;
++      __u32 len;
++      struct sk_buff *skb = *pskb;
++      struct nf_bridge_info *nf_bridge;
++      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)
++                                 ((*pskb)->mac.ethernet);
++ 
++      if (skb->protocol == __constant_htons(ETH_P_IPV6) || IS_VLAN_IPV6) {
++#ifdef CONFIG_SYSCTL
++              if (!brnf_call_ip6tables)
++                      return NF_ACCEPT;
++#endif
++              if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
++                      goto out;
 +
-+      /* Skip all of this if the packet is already routed,
-+       * f.e. by something like SCTP.
-+       */
-+      rt = (struct rtable *) skb->dst;
-+      if (rt != NULL)
-+              goto packet_routed;
-+
-+      /* Make sure we can route this packet. */
-+      rt = (struct rtable *)__sk_dst_check(sk, 0);
-+      if (rt == NULL) {
-+              u32 daddr;
-+
-+              /* Use correct destination address if we have options. */
-+              daddr = sk->daddr;
-+              if(opt && opt->srr)
-+                      daddr = opt->faddr;
-+
-+              /* If this fails, retransmit mechanism of transport layer will
-+               * keep trying until route appears or the connection times itself
-+               * out.
-+               */
-+              if (ip_route_output(&rt, daddr, sk->saddr,
-+                                  RT_CONN_FLAGS(sk),
-+                                  sk->bound_dev_if))
-+                      goto no_route;
-+              __sk_dst_set(sk, &rt->u.dst);
-+              sk->route_caps = rt->u.dst.dev->features;
-+      }
-+      skb->dst = dst_clone(&rt->u.dst);
-+
-+packet_routed:
-+      if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
-+              goto no_route;
-+
-+      /* OK, we know where to send it, allocate and build IP header. */
-+      iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
-+      *((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (sk->protinfo.af_inet.tos & 0xff));
-+      iph->tot_len = htons(skb->len);
-+      if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
-+              iph->frag_off = htons(IP_DF);
-+      else
-+              iph->frag_off = 0;
-+      iph->ttl      = sk->protinfo.af_inet.ttl;
-+      iph->protocol = sk->protocol;
-+      iph->saddr    = rt->rt_src;
-+      iph->daddr    = rt->rt_dst;
-+      skb->nh.iph   = iph;
-+      /* Transport layer set skb->h.foo itself. */
-+
-+      if(opt && opt->optlen) {
-+              iph->ihl += opt->optlen >> 2;
-+              ip_options_build(skb, opt, sk->daddr, rt, 0);
++              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++                      skb_pull(skb, VLAN_HLEN);
++                      (skb)->nh.raw += VLAN_HLEN;
++              }
++              return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
 +      }
 +
-+      return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-+                     ip_queue_xmit2);
-+
-+no_route:
-+      IP_INC_STATS(IpOutNoRoutes);
-+      kfree_skb(skb);
-+      return -EHOSTUNREACH;
-+}
-+
-+/*
-+ *    Build and send a packet, with as little as one copy
-+ *
-+ *    Doesn't care much about ip options... option length can be
-+ *    different for fragment at 0 and other fragments.
-+ *
-+ *    Note that the fragment at the highest offset is sent first,
-+ *    so the getfrag routine can fill in the TCP/UDP checksum header
-+ *    field in the last fragment it sends... actually it also helps
-+ *    the reassemblers, they can put most packets in at the head of
-+ *    the fragment queue, and they know the total size in advance. This
-+ *    last feature will measurably improve the Linux fragment handler one
-+ *    day.
-+ *
-+ *    The callback has five args, an arbitrary pointer (copy of frag),
-+ *    the source IP address (may depend on the routing table), the 
-+ *    destination address (char *), the offset to copy from, and the
-+ *    length to be copied.
-+ */
-+
-+static int ip_build_xmit_slow(struct sock *sk,
-+                int getfrag (const void *,
-+                             char *,
-+                             unsigned int,    
-+                             unsigned int,
-+                             struct sk_buff *),
-+                const void *frag,
-+                unsigned length,
-+                struct ipcm_cookie *ipc,
-+                struct rtable *rt,
-+                int flags)
-+{
-+      unsigned int fraglen, maxfraglen, fragheaderlen;
-+      int err;
-+      int offset, mf;
-+      int mtu;
-+      u16 id;
++#ifdef CONFIG_SYSCTL
++      if (!brnf_call_iptables)
++              return NF_ACCEPT;
++#endif
 +
-+      int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
-+      int nfrags=0;
-+      struct ip_options *opt = ipc->opt;
-+      int df = 0;
++      if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
++              return NF_ACCEPT;
++      if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
++              goto out;
++ 
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_pull(skb, VLAN_HLEN);
++              (skb)->nh.raw += VLAN_HLEN;
++      }
 +
-+      mtu = rt->u.dst.pmtu;
-+      if (ip_dont_fragment(sk, &rt->u.dst))
-+              df = htons(IP_DF);
++      if (!pskb_may_pull(skb, sizeof(struct iphdr)))
++              goto inhdr_error;
 +
-+      length -= sizeof(struct iphdr);
++      iph = skb->nh.iph;
++      if (iph->ihl < 5 || iph->version != 4)
++              goto inhdr_error;
 +
-+      if (opt) {
-+              fragheaderlen = sizeof(struct iphdr) + opt->optlen;
-+              maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
-+      } else {
-+              fragheaderlen = sizeof(struct iphdr);
++      if (!pskb_may_pull(skb, 4*iph->ihl))
++              goto inhdr_error;
 +
-+              /*
-+               *      Fragheaderlen is the size of 'overhead' on each buffer. Now work
-+               *      out the size of the frames to send.
-+               */
++      iph = skb->nh.iph;
++      if (ip_fast_csum((__u8 *)iph, iph->ihl) != 0)
++              goto inhdr_error;
 +
-+              maxfraglen = ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
-+      }
++      len = ntohs(iph->tot_len);
++      if (skb->len < len || len < 4*iph->ihl)
++              goto inhdr_error;
 +
-+      if (length + fragheaderlen > 0xFFFF) {
-+              ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
-+              return -EMSGSIZE;
++      if (skb->len > len) {
++              __pskb_trim(skb, len);
++              if (skb->ip_summed == CHECKSUM_HW)
++                      skb->ip_summed = CHECKSUM_NONE;
 +      }
 +
-+      /*
-+       *      Start at the end of the frame by handling the remainder.
-+       */
-+
-+      offset = length - (length % (maxfraglen - fragheaderlen));
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug ^= (1 << NF_IP_PRE_ROUTING);
++#endif
++      if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
++              return NF_DROP;
 +
-+      /*
-+       *      Amount of memory to allocate for final fragment.
-+       */
++      setup_pre_routing(skb);
++      store_orig_dstaddr(skb);
 +
-+      fraglen = length - offset + fragheaderlen;
++      NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL,
++              br_nf_pre_routing_finish);
 +
-+      if (length-offset==0) {
-+              fraglen = maxfraglen;
-+              offset -= maxfraglen-fragheaderlen;
-+      }
++      return NF_STOLEN;
 +
-+      /*
-+       *      The last fragment will not have MF (more fragments) set.
-+       */
++inhdr_error:
++//    IP_INC_STATS_BH(IpInHdrErrors);
++out:
++      return NF_DROP;
++}
 +
-+      mf = 0;
 +
-+      /*
-+       *      Don't fragment packets for path mtu discovery.
-+       */
++/* PF_BRIDGE/LOCAL_IN ************************************************/
++/* The packet is locally destined, which requires a real
++ * dst_entry, so detach the fake one.  On the way up, the
++ * packet would pass through PRE_ROUTING again (which already
++ * took place when the packet entered the bridge), but we
++ * register an IPv4 PRE_ROUTING 'sabotage' hook that will
++ * prevent this from happening.
++ */
++static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
++{
++      struct sk_buff *skb = *pskb;
 +
-+      if (offset > 0 && sk->protinfo.af_inet.pmtudisc==IP_PMTUDISC_DO) { 
-+              ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
-+              return -EMSGSIZE;
++      if (skb->dst == (struct dst_entry *)&__fake_rtable) {
++              dst_release(skb->dst);
++              skb->dst = NULL;
 +      }
-+      if (flags&MSG_PROBE)
-+              goto out;
 +
-+      /*
-+       *      Begin outputting the bytes.
-+       */
++      return NF_ACCEPT;
++}
 +
-+      id = sk->protinfo.af_inet.id++;
++/* PF_BRIDGE/FORWARD *************************************************/
++static int br_nf_forward_finish(struct sk_buff *skb)
++{
++      struct nf_bridge_info *nf_bridge = skb->nf_bridge;
++      struct net_device *in;
++/*    struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);*/
 +
-+      do {
-+              char *data;
-+              struct sk_buff * skb;
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug ^= (1 << NF_BR_FORWARD);
++#endif
 +
-+              /*
-+               *      Get the memory we require with some space left for alignment.
-+               */
-+              if (!(flags & MSG_DONTWAIT) || nfrags == 0) {
-+                      skb = sock_alloc_send_skb(sk, fraglen + hh_len + 15,
-+                                                (flags & MSG_DONTWAIT), &err);
-+              } else {
-+                      /* On a non-blocking write, we check for send buffer
-+                       * usage on the first fragment only.
-+                       */
-+                      skb = sock_wmalloc(sk, fraglen + hh_len + 15, 1,
-+                                         sk->allocation);
-+                      if (!skb)
-+                              err = -ENOBUFS;
++/*    if (skb->protocol != __constant_htons(ETH_P_ARP) && !IS_VLAN_ARP) {*/
++              in = nf_bridge->physindev;
++              if (nf_bridge->mask & BRNF_PKT_TYPE) {
++                      skb->pkt_type = PACKET_OTHERHOST;
++                      nf_bridge->mask ^= BRNF_PKT_TYPE;
 +              }
-+              if (skb == NULL)
-+                      goto error;
-+
-+              /*
-+               *      Fill in the control structures
-+               */
-+
-+              skb->priority = sk->priority;
-+              skb->dst = dst_clone(&rt->u.dst);
-+              skb_reserve(skb, hh_len);
-+
-+              /*
-+               *      Find where to start putting bytes.
-+               */
-+
-+              data = skb_put(skb, fraglen);
-+              skb->nh.iph = (struct iphdr *)data;
-+
-+              /*
-+               *      Only write IP header onto non-raw packets 
-+               */
-+
-+              {
-+                      struct iphdr *iph = (struct iphdr *)data;
-+
-+                      iph->version = 4;
-+                      iph->ihl = 5;
-+                      if (opt) {
-+                              iph->ihl += opt->optlen>>2;
-+                              ip_options_build(skb, opt,
-+                                               ipc->addr, rt, offset);
-+                      }
-+                      iph->tos = sk->protinfo.af_inet.tos;
-+                      iph->tot_len = htons(fraglen - fragheaderlen + iph->ihl*4);
-+                      iph->frag_off = htons(offset>>3)|mf|df;
-+                      iph->id = id;
-+                      if (!mf) {
-+                              if (offset || !df) {
-+                                      /* Select an unpredictable ident only
-+                                       * for packets without DF or having
-+                                       * been fragmented.
-+                                       */
-+                                      __ip_select_ident(iph, &rt->u.dst);
-+                                      id = iph->id;
-+                              }
++/*    } else {
++              in = *((struct net_device **)(skb->cb));
++      }*/
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_push(skb, VLAN_HLEN);
++              skb->nh.raw -= VLAN_HLEN;
++      }
++      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
++                      skb->dev, br_forward_finish, 1);
++      return 0;
++}
 +
-+                              /*
-+                               *      Any further fragments will have MF set.
-+                               */
-+                              mf = htons(IP_MF);
-+                      }
-+                      if (rt->rt_type == RTN_MULTICAST)
-+                              iph->ttl = sk->protinfo.af_inet.mc_ttl;
-+                      else
-+                              iph->ttl = sk->protinfo.af_inet.ttl;
-+                      iph->protocol = sk->protocol;
-+                      iph->check = 0;
-+                      iph->saddr = rt->rt_src;
-+                      iph->daddr = rt->rt_dst;
-+                      iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+                      data += iph->ihl*4;
-+              }
++/* This is the 'purely bridged' case.  For IP, we pass the packet to
++ * netfilter with indev and outdev set to the bridge device,
++ * but we are still able to filter on the 'real' indev/outdev
++ * because of the ipt_physdev.c module. For ARP, indev and outdev are the
++ * bridge ports.
++ */
++static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
++{
++      struct sk_buff *skb = *pskb;
++      struct nf_bridge_info *nf_bridge;
++      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
++      int pf;
 +
-+              /*
-+               *      User data callback
-+               */
++      if (!skb->nf_bridge)
++              return NF_ACCEPT;
 +
-+              if (getfrag(frag, data, offset, fraglen-fragheaderlen, skb)) {
-+                      err = -EFAULT;
-+                      kfree_skb(skb);
-+                      goto error;
-+              }
++      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
++              pf = PF_INET;
++      else
++              pf = PF_INET6;
 +
-+              offset -= (maxfraglen-fragheaderlen);
-+              fraglen = maxfraglen;
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_pull(*pskb, VLAN_HLEN);
++              (*pskb)->nh.raw += VLAN_HLEN;
++      }
 +
-+              nfrags++;
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug ^= (1 << NF_BR_FORWARD);
++#endif
++      nf_bridge = skb->nf_bridge;
++      if (skb->pkt_type == PACKET_OTHERHOST) {
++              skb->pkt_type = PACKET_HOST;
++              nf_bridge->mask |= BRNF_PKT_TYPE;
++      }
 +
-+              err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, 
-+                            skb->dst->dev, output_maybe_reroute);
-+              if (err) {
-+                      if (err > 0)
-+                              err = sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0;
-+                      if (err)
-+                              goto error;
-+              }
-+      } while (offset >= 0);
++      /* The physdev module checks on this */
++      nf_bridge->mask |= BRNF_BRIDGED;
++      nf_bridge->physoutdev = skb->dev;
 +
-+      if (nfrags>1)
-+              ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates += nfrags;
-+out:
-+      return 0;
++      NF_HOOK(pf, NF_IP_FORWARD, skb, bridge_parent(in),
++              bridge_parent(out), br_nf_forward_finish);
 +
-+error:
-+      IP_INC_STATS(IpOutDiscards);
-+      if (nfrags>1)
-+              ip_statistics[smp_processor_id()*2 + !in_softirq()].IpFragCreates += nfrags;
-+      return err; 
++      return NF_STOLEN;
 +}
 +
 +/*
-+ *    Fast path for unfragmented packets.
-+ */
-+int ip_build_xmit(struct sock *sk, 
-+                int getfrag (const void *,
-+                             char *,
-+                             unsigned int,    
-+                             unsigned int,
-+                             struct sk_buff *),
-+                const void *frag,
-+                unsigned length,
-+                struct ipcm_cookie *ipc,
-+                struct rtable *rt,
-+                int flags)
++static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
 +{
-+      int err;
-+      struct sk_buff *skb;
-+      int df;
-+      struct iphdr *iph;
++      struct sk_buff *skb = *pskb;
++      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
++      struct net_device **d = (struct net_device **)(skb->cb);
 +
-+      /*
-+       *      Try the simple case first. This leaves fragmented frames, and by
-+       *      choice RAW frames within 20 bytes of maximum size(rare) to the long path
-+       */
++      if (!brnf_call_arptables)
++              return NF_ACCEPT;
++
++      if (skb->protocol != __constant_htons(ETH_P_ARP)) {
++              if (!IS_VLAN_ARP)
++                      return NF_ACCEPT;
++              skb_pull(*pskb, VLAN_HLEN);
++              (*pskb)->nh.raw += VLAN_HLEN;
++      }
 +
-+      if (!sk->protinfo.af_inet.hdrincl) {
-+              length += sizeof(struct iphdr);
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug ^= (1 << NF_BR_FORWARD);
++#endif
 +
-+              /*
-+               *      Check for slow path.
-+               */
-+              if (length > rt->u.dst.pmtu || ipc->opt != NULL)  
-+                      return ip_build_xmit_slow(sk,getfrag,frag,length,ipc,rt,flags); 
-+      } else {
-+              if (length > rt->u.dst.dev->mtu) {
-+                      ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, rt->u.dst.dev->mtu);
-+                      return -EMSGSIZE;
++      if (skb->nh.arph->ar_pln != 4) {
++              if (IS_VLAN_ARP) {
++                      skb_push(*pskb, VLAN_HLEN);
++                      (*pskb)->nh.raw -= VLAN_HLEN;
 +              }
++              return NF_ACCEPT;
 +      }
-+      if (flags&MSG_PROBE)
-+              goto out;
++      *d = (struct net_device *)in;
++      NF_HOOK(NF_ARP, NF_ARP_FORWARD, skb, (struct net_device *)in,
++              (struct net_device *)out, br_nf_forward_finish);
 +
-+      /*
-+       *      Do path mtu discovery if needed.
-+       */
-+      df = 0;
-+      if (ip_dont_fragment(sk, &rt->u.dst))
-+              df = htons(IP_DF);
++      return NF_STOLEN;
++}
++*/
 +
-+      /* 
-+       *      Fast path for unfragmented frames without options. 
-+       */ 
-+      {
-+      int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
-+
-+      skb = sock_alloc_send_skb(sk, length+hh_len+15,
-+                                flags&MSG_DONTWAIT, &err);
-+      if(skb==NULL)
-+              goto error; 
-+      skb_reserve(skb, hh_len);
-+      }
-+
-+      skb->priority = sk->priority;
-+      skb->dst = dst_clone(&rt->u.dst);
-+
-+      skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length);
-+
-+      if(!sk->protinfo.af_inet.hdrincl) {
-+              iph->version=4;
-+              iph->ihl=5;
-+              iph->tos=sk->protinfo.af_inet.tos;
-+              iph->tot_len = htons(length);
-+              iph->frag_off = df;
-+              iph->ttl=sk->protinfo.af_inet.mc_ttl;
-+              ip_select_ident(iph, &rt->u.dst, sk);
-+              if (rt->rt_type != RTN_MULTICAST)
-+                      iph->ttl=sk->protinfo.af_inet.ttl;
-+              iph->protocol=sk->protocol;
-+              iph->saddr=rt->rt_src;
-+              iph->daddr=rt->rt_dst;
-+              iph->check=0;
-+              iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+              err = getfrag(frag, ((char *)iph)+iph->ihl*4,0, length-iph->ihl*4, skb);
++/* PF_BRIDGE/LOCAL_OUT ***********************************************/
++static int br_nf_local_out_finish(struct sk_buff *skb)
++{
++#ifdef CONFIG_NETFILTER_DEBUG
++      skb->nf_debug &= ~(1 << NF_BR_LOCAL_OUT);
++#endif
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_push(skb, VLAN_HLEN);
++              skb->nh.raw -= VLAN_HLEN;
 +      }
-+      else
-+              err = getfrag(frag, (void *)iph, 0, length, skb);
 +
-+      if (err)
-+              goto error_fault;
++      NF_HOOK_THRESH(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
++                      br_forward_finish, NF_BR_PRI_FIRST + 1);
 +
-+      err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-+                    output_maybe_reroute);
-+      if (err > 0)
-+              err = sk->protinfo.af_inet.recverr ? net_xmit_errno(err) : 0;
-+      if (err)
-+              goto error;
-+out:
 +      return 0;
-+
-+error_fault:
-+      err = -EFAULT;
-+      kfree_skb(skb);
-+error:
-+      IP_INC_STATS(IpOutDiscards);
-+      return err; 
 +}
 +
-+/*
-+ *    This IP datagram is too large to be sent in one piece.  Break it up into
-+ *    smaller pieces (each of size equal to IP header plus
-+ *    a block of the data of the original IP data part) that will yet fit in a
-+ *    single device frame, and queue such a frame for sending.
++
++/* This function sees both locally originated IP packets and forwarded
++ * IP packets (in both cases the destination device is a bridge
++ * device). It also sees bridged-and-DNAT'ed packets.
++ * To be able to filter on the physical bridge devices (with the ipt_physdev.c
++ * module), we steal packets destined to a bridge device away from the
++ * PF_INET/FORWARD and PF_INET/OUTPUT hook functions, and give them back later,
++ * when we have determined the real output device. This is done in here.
 + *
-+ *    Yes this is inefficient, feel free to submit a quicker one.
++ * If (nf_bridge->mask & BRNF_BRIDGED_DNAT) then the packet is bridged
++ * and we fake the PF_BRIDGE/FORWARD hook. The function br_nf_forward()
++ * will then fake the PF_INET/FORWARD hook. br_nf_local_out() has priority
++ * NF_BR_PRI_FIRST, so no relevant PF_BRIDGE/INPUT functions have been nor
++ * will be executed.
++ * Otherwise, if nf_bridge->physindev is NULL, the bridge-nf code never touched
++ * this packet before, and so the packet was locally originated. We fake
++ * the PF_INET/LOCAL_OUT hook.
++ * Finally, if nf_bridge->physindev isn't NULL, then the packet was IP routed,
++ * so we fake the PF_INET/FORWARD hook. ipv4_sabotage_out() makes sure
++ * even routed packets that didn't arrive on a bridge interface have their
++ * nf_bridge->physindev set.
 + */
 +
-+int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
++static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
 +{
-+      struct iphdr *iph;
-+      int raw = 0;
-+      int ptr;
-+      struct net_device *dev;
-+      struct sk_buff *skb2;
-+      unsigned int mtu, hlen, left, len; 
-+      int offset;
-+      int not_last_frag;
-+      struct rtable *rt = (struct rtable*)skb->dst;
-+      int err = 0;
-+
-+      dev = rt->u.dst.dev;
-+
-+      /*
-+       *      Point into the IP datagram header.
-+       */
-+
-+      iph = skb->nh.iph;
-+
-+      /*
-+       *      Setup starting values.
-+       */
++      struct net_device *realindev, *realoutdev;
++      struct sk_buff *skb = *pskb;
++      struct nf_bridge_info *nf_bridge;
++      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
++      int pf;
 +
-+      hlen = iph->ihl * 4;
-+      left = skb->len - hlen;         /* Space per frame */
-+      mtu = rt->u.dst.pmtu - hlen;    /* Size of data space */
-+      ptr = raw + hlen;               /* Where to start from */
++      if (!skb->nf_bridge)
++              return NF_ACCEPT;
 +
-+      /*
-+       *      Fragment the datagram.
-+       */
++      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
++              pf = PF_INET;
++      else
++              pf = PF_INET6;
++ 
++#ifdef CONFIG_NETFILTER_DEBUG
++      /* Sometimes we get packets with NULL ->dst here (for example,
++       * running a dhcp client daemon triggers this). This should now
++       * be fixed, but let's keep the check around. */
++      if (skb->dst == NULL) {
++              printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
++              return NF_ACCEPT;
++      }
++#endif
 +
-+      offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3;
-+      not_last_frag = iph->frag_off & htons(IP_MF);
++      nf_bridge = skb->nf_bridge;
++      nf_bridge->physoutdev = skb->dev;
++      realindev = nf_bridge->physindev;
 +
-+      /*
-+       *      Keep copying data until we run out.
++      /* Bridged, take PF_BRIDGE/FORWARD.
++       * (see big note in front of br_nf_pre_routing_finish)
 +       */
-+
-+      while(left > 0) {
-+              len = left;
-+              /* IF: it doesn't fit, use 'mtu' - the data space left */
-+              if (len > mtu)
-+                      len = mtu;
-+              /* IF: we are not sending upto and including the packet end
-+                 then align the next start on an eight byte boundary */
-+              if (len < left) {
-+                      len &= ~7;
++      if (nf_bridge->mask & BRNF_BRIDGED_DNAT) {
++              if (nf_bridge->mask & BRNF_PKT_TYPE) {
++                      skb->pkt_type = PACKET_OTHERHOST;
++                      nf_bridge->mask ^= BRNF_PKT_TYPE;
 +              }
-+              /*
-+               *      Allocate buffer.
-+               */
-+
-+              if ((skb2 = alloc_skb(len+hlen+dev->hard_header_len+15,GFP_ATOMIC)) == NULL) {
-+                      NETDEBUG(printk(KERN_INFO "IP: frag: no memory for new fragment!\n"));
-+                      err = -ENOMEM;
-+                      goto fail;
++              if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++                      skb_push(skb, VLAN_HLEN);
++                      skb->nh.raw -= VLAN_HLEN;
 +              }
 +
-+              /*
-+               *      Set up data on packet
-+               */
-+
-+              skb2->pkt_type = skb->pkt_type;
-+              skb2->priority = skb->priority;
-+              skb_reserve(skb2, (dev->hard_header_len+15)&~15);
-+              skb_put(skb2, len + hlen);
-+              skb2->nh.raw = skb2->data;
-+              skb2->h.raw = skb2->data + hlen;
-+              skb2->protocol = skb->protocol;
-+              skb2->security = skb->security;
-+
-+              /*
-+               *      Charge the memory for the fragment to any owner
-+               *      it might possess
-+               */
-+
-+              if (skb->sk)
-+                      skb_set_owner_w(skb2, skb->sk);
-+              skb2->dst = dst_clone(skb->dst);
-+              skb2->dev = skb->dev;
-+
-+              /*
-+               *      Copy the packet header into the new buffer.
-+               */
++              NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev,
++                      skb->dev, br_forward_finish);
++              goto out;
++      }
++      realoutdev = bridge_parent(skb->dev);
 +
-+              memcpy(skb2->nh.raw, skb->data, hlen);
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++      /* iptables should match -o br0.x */
++      if (nf_bridge->netoutdev)
++              realoutdev = nf_bridge->netoutdev;
++#endif
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_pull(skb, VLAN_HLEN);
++              (*pskb)->nh.raw += VLAN_HLEN;
++      }
++      /* IP forwarded traffic has a physindev, locally
++       * generated traffic hasn't.
++       */
++      if (realindev != NULL) {
++              if (((nf_bridge->mask & BRNF_DONT_TAKE_PARENT) == 0) &&
++                  has_bridge_parent(realindev))
++                      realindev = bridge_parent(realindev);
++              NF_HOOK_THRESH(pf, NF_IP_FORWARD, skb, realindev,
++                             realoutdev, okfn,
++                             NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD + 1);
++      } else {
++#ifdef CONFIG_NETFILTER_DEBUG
++              skb->nf_debug ^= (1 << NF_IP_LOCAL_OUT);
++#endif
 +
-+              /*
-+               *      Copy a block of the IP datagram.
-+               */
-+              if (skb_copy_bits(skb, ptr, skb2->h.raw, len))
-+                      BUG();
-+              left -= len;
++              NF_HOOK_THRESH(pf, NF_IP_LOCAL_OUT, skb, realindev,
++                             realoutdev, okfn,
++                             NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT + 1);
++      }
 +
-+              /*
-+               *      Fill in the new header fields.
-+               */
-+              iph = skb2->nh.iph;
-+              iph->frag_off = htons((offset >> 3));
-+
-+              /* ANK: dirty, but effective trick. Upgrade options only if
-+               * the segment to be fragmented was THE FIRST (otherwise,
-+               * options are already fixed) and make it ONCE
-+               * on the initial skb, so that all the following fragments
-+               * will inherit fixed options.
-+               */
-+              if (offset == 0)
-+                      ip_options_fragment(skb);
++out:
++      return NF_STOLEN;
++}
 +
-+              /* Copy the flags to each fragment. */
-+              IPCB(skb2)->flags = IPCB(skb)->flags;
 +
-+              /*
-+               *      Added AC : If we are fragmenting a fragment that's not the
-+               *                 last fragment then keep MF on each bit
-+               */
-+              if (left > 0 || not_last_frag)
-+                      iph->frag_off |= htons(IP_MF);
-+              ptr += len;
-+              offset += len;
++/* PF_BRIDGE/POST_ROUTING ********************************************/
++static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
++{
++      struct sk_buff *skb = *pskb;
++      struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
++      struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
++      struct net_device *realoutdev = bridge_parent(skb->dev);
++      int pf;
 +
-+#ifdef CONFIG_NET_SCHED
-+              skb2->tc_index = skb->tc_index;
-+#endif
-+#ifdef CONFIG_NETFILTER
-+              skb2->nfmark = skb->nfmark;
-+              skb2->nfcache = skb->nfcache;
-+              /* Connection association is same as pre-frag packet */
-+              skb2->nfct = skb->nfct;
-+              nf_conntrack_get(skb2->nfct);
 +#ifdef CONFIG_NETFILTER_DEBUG
-+              skb2->nf_debug = skb->nf_debug;
-+#endif
++      /* Be very paranoid. This probably won't happen anymore, but let's
++       * keep the check just to be sure... */
++      if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
++              printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
++                               "bad mac.raw pointer.");
++              goto print_error;
++      }
 +#endif
 +
-+              /*
-+               *      Put this fragment into the sending queue.
-+               */
++      if (!nf_bridge)
++              return NF_ACCEPT;
++
++      if (skb->protocol == __constant_htons(ETH_P_IP) || IS_VLAN_IP)
++              pf = PF_INET;
++      else
++              pf = PF_INET6;
 +
-+              IP_INC_STATS(IpFragCreates);
++      /* Sometimes we get packets with NULL ->dst here (for example,
++       * running a dhcp client daemon triggers this).
++       */
++      if (skb->dst == NULL)
++              return NF_ACCEPT;
 +
-+              iph->tot_len = htons(len + hlen);
++#ifdef CONFIG_NETFILTER_DEBUG
++      /* Sometimes we get packets with NULL ->dst here (for example,
++       * running a dhcp client daemon triggers this). This should now
++       * be fixed, but let's keep the check around.
++       */
++      if (skb->dst == NULL) {
++              printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
++              goto print_error;
++      }
 +
-+              ip_send_check(iph);
++      skb->nf_debug ^= (1 << NF_IP_POST_ROUTING);
++#endif
 +
-+              err = output(skb2);
-+              if (err)
-+                      goto fail;
++      /* We assume any code from br_dev_queue_push_xmit onwards doesn't care
++       * about the value of skb->pkt_type.
++       */
++      if (skb->pkt_type == PACKET_OTHERHOST) {
++              skb->pkt_type = PACKET_HOST;
++              nf_bridge->mask |= BRNF_PKT_TYPE;
 +      }
-+      kfree_skb(skb);
-+      IP_INC_STATS(IpFragOKs);
-+      return err;
 +
-+fail:
-+      kfree_skb(skb); 
-+      IP_INC_STATS(IpFragFails);
-+      return err;
-+}
++      if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
++              skb_pull(skb, VLAN_HLEN);
++              skb->nh.raw += VLAN_HLEN;
++      }
 +
-+/*
-+ *    Fetch data from kernel space and fill in checksum if needed.
-+ */
-+static int ip_reply_glue_bits(const void *dptr, char *to, unsigned int offset, 
-+                            unsigned int fraglen, struct sk_buff *skb)
-+{
-+        struct ip_reply_arg *dp = (struct ip_reply_arg*)dptr;
-+      u16 *pktp = (u16 *)to;
-+      struct iovec *iov; 
-+      int len; 
-+      int hdrflag = 1; 
-+
-+      iov = &dp->iov[0]; 
-+      if (offset >= iov->iov_len) { 
-+              offset -= iov->iov_len;
-+              iov++; 
-+              hdrflag = 0; 
-+      }
-+      len = iov->iov_len - offset;
-+      if (fraglen > len) { /* overlapping. */ 
-+              dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, len,
-+                                           dp->csum);
-+              offset = 0;
-+              fraglen -= len; 
-+              to += len; 
-+              iov++;
-+      }
-+
-+      dp->csum = csum_partial_copy_nocheck(iov->iov_base+offset, to, fraglen, 
-+                                           dp->csum); 
-+
-+      if (hdrflag && dp->csumoffset)
-+              *(pktp + dp->csumoffset) = csum_fold(dp->csum); /* fill in checksum */
-+      return 0;              
-+}
-+
-+/* 
-+ *    Generic function to send a packet as reply to another packet.
-+ *    Used to send TCP resets so far. ICMP should use this function too.
-+ *
-+ *    Should run single threaded per socket because it uses the sock 
-+ *            structure to pass arguments.
-+ */
-+void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
-+                 unsigned int len)
-+{
-+      struct {
-+              struct ip_options       opt;
-+              char                    data[40];
-+      } replyopts;
-+      struct ipcm_cookie ipc;
-+      u32 daddr;
-+      struct rtable *rt = (struct rtable*)skb->dst;
-+
-+      if (ip_options_echo(&replyopts.opt, skb))
-+              return;
++      nf_bridge_save_header(skb);
 +
-+      daddr = ipc.addr = rt->rt_src;
-+      ipc.opt = NULL;
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++      if (nf_bridge->netoutdev)
++              realoutdev = nf_bridge->netoutdev;
++#endif
++      NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL,
++              realoutdev, br_dev_queue_push_xmit);
 +
-+      if (replyopts.opt.optlen) {
-+              ipc.opt = &replyopts.opt;
++      return NF_STOLEN;
 +
-+              if (ipc.opt->srr)
-+                      daddr = replyopts.opt.faddr;
++#ifdef CONFIG_NETFILTER_DEBUG
++print_error:
++      if (skb->dev != NULL) {
++              printk("[%s]", skb->dev->name);
++              if (has_bridge_parent(skb->dev))
++                      printk("[%s]", bridge_parent(skb->dev)->name);
 +      }
++      printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
++                                            skb->data);
++      return NF_ACCEPT;
++#endif
++}
 +
-+      if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
-+              return;
 +
-+      /* And let IP do all the hard work.
++/* IPv4/SABOTAGE *****************************************************/
 +
-+         This chunk is not reenterable, hence spinlock.
-+         Note that it uses the fact, that this function is called
-+         with locally disabled BH and that sk cannot be already spinlocked.
-+       */
-+      bh_lock_sock(sk);
-+      sk->protinfo.af_inet.tos = skb->nh.iph->tos;
-+      sk->priority = skb->priority;
-+      sk->protocol = skb->nh.iph->protocol;
-+      ip_build_xmit(sk, ip_reply_glue_bits, arg, len, &ipc, rt, MSG_DONTWAIT);
-+      bh_unlock_sock(sk);
++/* Don't hand locally destined packets to PF_INET/PRE_ROUTING
++ * for the second time.
++ */
++static unsigned int ip_sabotage_in(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
++{
++      if ((*pskb)->nf_bridge &&
++          !((*pskb)->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)) {
++              return NF_STOP;
++      }
 +
-+      ip_rt_put(rt);
++      return NF_ACCEPT;
 +}
 +
-+/*
-+ *    IP protocol layer initialiser
-+ */
-+
-+static struct packet_type ip_packet_type =
-+{
-+      __constant_htons(ETH_P_IP),
-+      NULL,   /* All devices */
-+      ip_rcv,
-+      (void*)1,
-+      NULL,
-+};
-+
-+/*
-+ *    IP registers the packet type and then calls the subprotocol initialisers
++/* Postpone execution of PF_INET/FORWARD, PF_INET/LOCAL_OUT
++ * and PF_INET/POST_ROUTING until we have done the forwarding
++ * decision in the bridge code and have determined skb->physoutdev.
 + */
-+
-+void __init ip_init(void)
++static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
++   const struct net_device *in, const struct net_device *out,
++   int (*okfn)(struct sk_buff *))
 +{
-+      dev_add_pack(&ip_packet_type);
-+
-+      ip_rt_init();
-+      inet_initpeers();
++      struct sk_buff *skb = *pskb;
 +
-+#ifdef CONFIG_IP_MULTICAST
-+      proc_net_create("igmp", 0, ip_mc_procinfo);
++      if ((out->hard_start_xmit == br_dev_xmit &&
++          okfn != br_nf_forward_finish &&
++          okfn != br_nf_local_out_finish &&
++          okfn != br_dev_queue_push_xmit)
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++          || ((out->priv_flags & IFF_802_1Q_VLAN) &&
++          VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)
 +#endif
-+      proc_net_create("mcfilter", 0, ip_mcf_procinfo);
-+}
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/Config.in linux-ebtables/net/ipv4/netfilter/Config.in
---- linux-mips-cvs/net/ipv4/netfilter/Config.in        2005-01-20 03:19:25.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/Config.in        2005-02-07 05:52:50.000000000 +0100
-@@ -44,6 +44,9 @@
-     dep_tristate '  Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
-     dep_tristate '  Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES
-   fi
-+  if [ "$CONFIG_BRIDGE" != "n" ]; then
-+    dep_tristate '  Physdev match support' CONFIG_IP_NF_MATCH_PHYSDEV $CONFIG_IP_NF_IPTABLES
-+  fi
- # The targets
-   dep_tristate '  Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES 
-   if [ "$CONFIG_IP_NF_FILTER" != "n" ]; then
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/Makefile linux-ebtables/net/ipv4/netfilter/Makefile
---- linux-mips-cvs/net/ipv4/netfilter/Makefile 2003-08-13 19:19:30.000000000 +0200
-+++ linux-ebtables/net/ipv4/netfilter/Makefile 2005-02-07 05:52:50.000000000 +0100
-@@ -87,6 +87,8 @@
- obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
- obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
-+obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o
++          ) {
++              struct nf_bridge_info *nf_bridge;
 +
- # targets
- obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
- obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/ip_tables.c linux-ebtables/net/ipv4/netfilter/ip_tables.c
---- linux-mips-cvs/net/ipv4/netfilter/ip_tables.c      2005-01-20 03:19:25.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/ip_tables.c      2005-02-07 05:52:50.000000000 +0100
-@@ -118,12 +118,19 @@
- static inline int
- ip_packet_match(const struct iphdr *ip,
-               const char *indev,
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+              const char *physindev,
-+#endif
-               const char *outdev,
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+              const char *physoutdev,
-+#endif
-               const struct ipt_ip *ipinfo,
-               int isfrag)
- {
-       size_t i;
-       unsigned long ret;
-+      unsigned long ret2 = 1;
- #define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))
-@@ -153,7 +160,15 @@
-                       & ((const unsigned long *)ipinfo->iniface_mask)[i];
-       }
--      if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
-+              ret2 |= (((const unsigned long *)physindev)[i]
-+                      ^ ((const unsigned long *)ipinfo->iniface)[i])
-+                      & ((const unsigned long *)ipinfo->iniface_mask)[i];
-+      }
-+#endif
++              if (!skb->nf_bridge) {
++#ifdef CONFIG_SYSCTL
++                      /* This code is executed while in the IP(v6) stack,
++                         the version should be 4 or 6. We can't use
++                         skb->protocol because that isn't set on
++                         PF_INET(6)/LOCAL_OUT. */
++                      struct iphdr *ip = skb->nh.iph;
 +
-+      if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_IN)) {
-               dprintf("VIA in mismatch (%s vs %s).%s\n",
-                       indev, ipinfo->iniface,
-                       ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
-@@ -166,7 +181,15 @@
-                       & ((const unsigned long *)ipinfo->outiface_mask)[i];
-       }
--      if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      for (i = 0, ret2 = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
-+              ret2 |= (((const unsigned long *)physoutdev)[i]
-+                      ^ ((const unsigned long *)ipinfo->outiface)[i])
-+                      & ((const unsigned long *)ipinfo->outiface_mask)[i];
-+      }
++                      if (ip->version == 4 && !brnf_call_iptables)
++                              return NF_ACCEPT;
++                      else if (ip->version == 6 && !brnf_call_ip6tables)
++                              return NF_ACCEPT;
 +#endif
++                      if (hook == NF_IP_POST_ROUTING)
++                              return NF_ACCEPT;
++                      if (!nf_bridge_alloc(skb))
++                              return NF_DROP;
++              }
 +
-+      if (FWINV(ret != 0 && ret2 != 0, IPT_INV_VIA_OUT)) {
-               dprintf("VIA out mismatch (%s vs %s).%s\n",
-                       outdev, ipinfo->outiface,
-                       ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
-@@ -265,6 +288,9 @@
-       /* Initializing verdict to NF_DROP keeps gcc happy. */
-       unsigned int verdict = NF_DROP;
-       const char *indev, *outdev;
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      const char *physindev, *physoutdev;
-+#endif
-       void *table_base;
-       struct ipt_entry *e, *back;
-@@ -274,6 +300,13 @@
-       datalen = (*pskb)->len - ip->ihl * 4;
-       indev = in ? in->name : nulldevname;
-       outdev = out ? out->name : nulldevname;
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      physindev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physindev) ?
-+              (*pskb)->nf_bridge->physindev->name : nulldevname;
-+      physoutdev = ((*pskb)->nf_bridge && (*pskb)->nf_bridge->physoutdev) ?
-+              (*pskb)->nf_bridge->physoutdev->name : nulldevname;
-+#endif
++              nf_bridge = skb->nf_bridge;
 +
-       /* We handle fragments by dealing with the first fragment as
-        * if it was a normal packet.  All other fragments are treated
-        * normally, except that they will NEVER match rules that ask
-@@ -309,7 +342,15 @@
-               IP_NF_ASSERT(e);
-               IP_NF_ASSERT(back);
-               (*pskb)->nfcache |= e->nfcache;
--              if (ip_packet_match(ip, indev, outdev, &e->ip, offset)) {
-+              if (ip_packet_match(ip, indev,
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+                  physindev,
-+#endif
-+                  outdev,
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+                  physoutdev,
++              /* This frame will arrive on PF_BRIDGE/LOCAL_OUT and we
++               * will need the indev then. For a brouter, the real indev
++               * can be a bridge port, so we make sure br_nf_local_out()
++               * doesn't use the bridge parent of the indev by using
++               * the BRNF_DONT_TAKE_PARENT mask.
++               */
++              if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
++                      nf_bridge->mask &= BRNF_DONT_TAKE_PARENT;
++                      nf_bridge->physindev = (struct net_device *)in;
++              }
++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
++              /* the iptables outdev is br0.x, not br0 */
++              if (out->priv_flags & IFF_802_1Q_VLAN)
++                      nf_bridge->netoutdev = (struct net_device *)out;
 +#endif
-+                  &e->ip, offset)) {
-                       struct ipt_entry_target *t;
-                       if (IPT_MATCH_ITERATE(e, do_match,
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/ipt_LOG.c linux-ebtables/net/ipv4/netfilter/ipt_LOG.c
---- linux-mips-cvs/net/ipv4/netfilter/ipt_LOG.c        2003-11-17 02:07:48.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/ipt_LOG.c        2005-02-07 05:52:50.000000000 +0100
-@@ -316,6 +316,18 @@
-              loginfo->prefix,
-              in ? in->name : "",
-              out ? out->name : "");
-+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-+      if ((*pskb)->nf_bridge) {
-+              struct net_device *physindev = (*pskb)->nf_bridge->physindev;
-+              struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev;
-+
-+              if (physindev && in != physindev)
-+                      printk("PHYSIN=%s ", physindev->name);
-+              if (physoutdev && out != physoutdev)
-+                      printk("PHYSOUT=%s ", physoutdev->name);
++              return NF_STOP;
 +      }
-+#endif
 +
-       if (in && !out) {
-               /* MAC logging for input chain only. */
-               printk("MAC=");
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/ipt_REJECT.c linux-ebtables/net/ipv4/netfilter/ipt_REJECT.c
---- linux-mips-cvs/net/ipv4/netfilter/ipt_REJECT.c     2005-01-20 03:19:25.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/ipt_REJECT.c     2005-02-07 05:52:50.000000000 +0100
-@@ -15,6 +15,9 @@
- #include <net/route.h>
- #include <linux/netfilter_ipv4/ip_tables.h>
- #include <linux/netfilter_ipv4/ipt_REJECT.h>
-+#ifdef CONFIG_BRIDGE_NETFILTER
-+#include <linux/netfilter_bridge.h>
-+#endif
- #if 0
- #define DEBUGP printk
-@@ -29,7 +32,13 @@
-       struct rt_key key = {};
-       struct rtable *rt;
--      if (hook != NF_IP_FORWARD) {
-+      /* We don't require ip forwarding to be enabled to be able to
-+       * send a RST reply for bridged traffic. */
-+      if (hook != NF_IP_FORWARD
-+#ifdef CONFIG_BRIDGE_NETFILTER
-+          || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
-+#endif
-+         ) {
-               key.dst = iph->saddr;
-               if (hook == NF_IP_LOCAL_IN)
-                       key.src = iph->daddr;
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/ipt_REJECT.c.orig linux-ebtables/net/ipv4/netfilter/ipt_REJECT.c.orig
---- linux-mips-cvs/net/ipv4/netfilter/ipt_REJECT.c.orig        1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/ipt_REJECT.c.orig        2005-01-20 03:19:25.000000000 +0100
-@@ -0,0 +1,426 @@
-+/*
-+ * This is a module which is used for rejecting packets.
-+ * Added support for customized reject packets (Jozsef Kadlecsik).
-+ * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/skbuff.h>
-+#include <linux/ip.h>
-+#include <linux/udp.h>
-+#include <linux/icmp.h>
-+#include <net/icmp.h>
-+#include <net/ip.h>
-+#include <net/tcp.h>
-+#include <net/route.h>
-+#include <linux/netfilter_ipv4/ip_tables.h>
-+#include <linux/netfilter_ipv4/ipt_REJECT.h>
++      return NF_ACCEPT;
++}
 +
-+#if 0
-+#define DEBUGP printk
-+#else
-+#define DEBUGP(format, args...)
-+#endif
++/* For br_nf_local_out we need (prio = NF_BR_PRI_FIRST), to insure that innocent
++ * PF_BRIDGE/NF_BR_LOCAL_OUT functions don't get bridged traffic as input.
++ * For br_nf_post_routing, we need (prio = NF_BR_PRI_LAST), because
++ * ip_refrag() can return NF_STOLEN.
++ */
++static struct nf_hook_ops br_nf_ops[] = {
++      { .hook = br_nf_pre_routing, 
++        .pf = PF_BRIDGE, 
++        .hooknum = NF_BR_PRE_ROUTING, 
++        .priority = NF_BR_PRI_BRNF, },
++      { .hook = br_nf_local_in,
++        .pf = PF_BRIDGE,
++        .hooknum = NF_BR_LOCAL_IN,
++        .priority = NF_BR_PRI_BRNF, },
++      { .hook = br_nf_forward_ip,
++        .pf = PF_BRIDGE,
++        .hooknum = NF_BR_FORWARD,
++        .priority = NF_BR_PRI_BRNF /*- 1*/, },
++/*    { .hook = br_nf_forward_arp,
++        .pf = PF_BRIDGE,
++        .hooknum = NF_BR_FORWARD,
++        .priority = NF_BR_PRI_BRNF, },*/
++      { .hook = br_nf_local_out,
++        .pf = PF_BRIDGE,
++        .hooknum = NF_BR_LOCAL_OUT,
++        .priority = NF_BR_PRI_FIRST, },
++      { .hook = br_nf_post_routing,
++        .pf = PF_BRIDGE,
++        .hooknum = NF_BR_POST_ROUTING,
++        .priority = NF_BR_PRI_LAST, },
++      { .hook = ip_sabotage_in,
++        .pf = PF_INET,
++        .hooknum = NF_IP_PRE_ROUTING,
++        .priority = NF_IP_PRI_FIRST, },
++      { .hook = ip_sabotage_in,
++        .pf = PF_INET6,
++        .hooknum = NF_IP6_PRE_ROUTING,
++        .priority = NF_IP6_PRI_FIRST, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET,
++        .hooknum = NF_IP_FORWARD,
++        .priority = NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET6,
++        .hooknum = NF_IP6_FORWARD,
++        .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET,
++        .hooknum = NF_IP_LOCAL_OUT,
++        .priority = NF_IP_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET6,
++        .hooknum = NF_IP6_LOCAL_OUT,
++        .priority = NF_IP6_PRI_BRIDGE_SABOTAGE_LOCAL_OUT, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET,
++        .hooknum = NF_IP_POST_ROUTING,
++        .priority = NF_IP_PRI_FIRST, },
++      { .hook = ip_sabotage_out,
++        .pf = PF_INET6,
++        .hooknum = NF_IP6_POST_ROUTING,
++        .priority = NF_IP6_PRI_FIRST, },
++};
 +
-+static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
++#ifdef CONFIG_SYSCTL
++static
++int brnf_sysctl_call_tables(ctl_table *ctl, int write, struct file * filp,
++                      void *buffer, size_t *lenp)
 +{
-+      struct iphdr *iph = skb->nh.iph;
-+      struct dst_entry *odst;
-+      struct rt_key key = {};
-+      struct rtable *rt;
-+
-+      if (hook != NF_IP_FORWARD) {
-+              key.dst = iph->saddr;
-+              if (hook == NF_IP_LOCAL_IN)
-+                      key.src = iph->daddr;
-+              key.tos = RT_TOS(iph->tos);
-+
-+              if (ip_route_output_key(&rt, &key) != 0)
-+                      return NULL;
-+      } else {
-+              /* non-local src, find valid iif to satisfy
-+               * rp-filter when calling ip_route_input. */
-+              key.dst = iph->daddr;
-+              if (ip_route_output_key(&rt, &key) != 0)
-+                      return NULL;
-+
-+              odst = skb->dst;
-+              if (ip_route_input(skb, iph->saddr, iph->daddr,
-+                                 RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
-+                      dst_release(&rt->u.dst);
-+                      return NULL;
-+              }
-+              dst_release(&rt->u.dst);
-+              rt = (struct rtable *)skb->dst;
-+              skb->dst = odst;
-+      }
++      int ret;
 +
-+      if (rt->u.dst.error) {
-+              dst_release(&rt->u.dst);
-+              rt = NULL;
-+      }
++      ret = proc_dointvec(ctl, write, filp, buffer, lenp);
 +
-+      return rt;
++      if (write && *(int *)(ctl->data))
++              *(int *)(ctl->data) = 1;
++      return ret;
 +}
 +
-+/* Send RST reply */
-+static void send_reset(struct sk_buff *oldskb, int hook)
-+{
-+      struct sk_buff *nskb;
-+      struct tcphdr *otcph, *tcph;
-+      struct rtable *rt;
-+      unsigned int otcplen;
-+      u_int16_t tmp_port;
-+      u_int32_t tmp_addr;
-+      int needs_ack;
-+      int hh_len;
-+
-+      /* IP header checks: fragment, too short. */
-+      if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
-+          || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
-+              return;
-+
-+      otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
-+      otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
-+
-+      /* No RST for RST. */
-+      if (otcph->rst)
-+              return;
-+
-+      /* Check checksum. */
-+      if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
-+                       oldskb->nh.iph->daddr,
-+                       csum_partial((char *)otcph, otcplen, 0)) != 0)
-+              return;
-+
-+      if ((rt = route_reverse(oldskb, hook)) == NULL)
-+              return;
-+
-+      hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
-+
-+
-+      /* Copy skb (even if skb is about to be dropped, we can't just
-+           clone it because there may be other things, such as tcpdump,
-+           interested in it). We also need to expand headroom in case
-+         hh_len of incoming interface < hh_len of outgoing interface */
-+      nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
-+                             GFP_ATOMIC);
-+      if (!nskb) {
-+              dst_release(&rt->u.dst);
-+              return;
-+      }
-+
-+      dst_release(nskb->dst);
-+      nskb->dst = &rt->u.dst;
-+
-+      /* This packet will not be the same as the other: clear nf fields */
-+      nf_reset(nskb);
-+      nskb->nfcache = 0;
-+      nskb->nfmark = 0;
-+
-+      tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
-+
-+      /* Swap source and dest */
-+      tmp_addr = nskb->nh.iph->saddr;
-+      nskb->nh.iph->saddr = nskb->nh.iph->daddr;
-+      nskb->nh.iph->daddr = tmp_addr;
-+      tmp_port = tcph->source;
-+      tcph->source = tcph->dest;
-+      tcph->dest = tmp_port;
-+
-+      /* Truncate to length (no data) */
-+      tcph->doff = sizeof(struct tcphdr)/4;
-+      skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
-+      nskb->nh.iph->tot_len = htons(nskb->len);
++static ctl_table brnf_table[] = {
++      {
++              .ctl_name       = NET_BRIDGE_NF_CALL_ARPTABLES,
++              .procname       = "bridge-nf-call-arptables",
++              .data           = &brnf_call_arptables,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = &brnf_sysctl_call_tables,
++      },
++      {
++              .ctl_name       = NET_BRIDGE_NF_CALL_IPTABLES,
++              .procname       = "bridge-nf-call-iptables",
++              .data           = &brnf_call_iptables,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = &brnf_sysctl_call_tables,
++      },
++      {
++              .ctl_name       = NET_BRIDGE_NF_CALL_IP6TABLES,
++              .procname       = "bridge-nf-call-ip6tables",
++              .data           = &brnf_call_ip6tables,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = &brnf_sysctl_call_tables,
++      },
++      {
++              .ctl_name       = NET_BRIDGE_NF_FILTER_VLAN_TAGGED,
++              .procname       = "bridge-nf-filter-vlan-tagged",
++              .data           = &brnf_filter_vlan_tagged,
++              .maxlen         = sizeof(int),
++              .mode           = 0644,
++              .proc_handler   = &brnf_sysctl_call_tables,
++      },
++      { .ctl_name = 0 }
++};
 +
-+      if (tcph->ack) {
-+              needs_ack = 0;
-+              tcph->seq = otcph->ack_seq;
-+              tcph->ack_seq = 0;
-+      } else {
-+              needs_ack = 1;
-+              tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
-+                                    + otcplen - (otcph->doff<<2));
-+              tcph->seq = 0;
-+      }
-+
-+      /* Reset flags */
-+      ((u_int8_t *)tcph)[13] = 0;
-+      tcph->rst = 1;
-+      tcph->ack = needs_ack;
-+
-+      tcph->window = 0;
-+      tcph->urg_ptr = 0;
-+
-+      /* Adjust TCP checksum */
-+      tcph->check = 0;
-+      tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
-+                                 nskb->nh.iph->saddr,
-+                                 nskb->nh.iph->daddr,
-+                                 csum_partial((char *)tcph,
-+                                              sizeof(struct tcphdr), 0));
-+
-+      /* Adjust IP TTL, DF */
-+      nskb->nh.iph->ttl = MAXTTL;
-+      /* Set DF, id = 0 */
-+      nskb->nh.iph->frag_off = htons(IP_DF);
-+      nskb->nh.iph->id = 0;
-+
-+      /* Adjust IP checksum */
-+      nskb->nh.iph->check = 0;
-+      nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
-+                                         nskb->nh.iph->ihl);
-+
-+      /* "Never happens" */
-+      if (nskb->len > nskb->dst->pmtu)
-+              goto free_nskb;
-+
-+      nf_ct_attach(nskb, oldskb);
-+
-+      NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-+              ip_finish_output);
-+      return;
++static ctl_table brnf_bridge_table[] = {
++      {
++              .ctl_name       = NET_BRIDGE,
++              .procname       = "bridge",
++              .mode           = 0555,
++              .child          = brnf_table,
++      },
++      { .ctl_name = 0 }
++};
 +
-+ free_nskb:
-+      kfree_skb(nskb);
-+}
++static ctl_table brnf_net_table[] = {
++      {
++              .ctl_name       = CTL_NET,
++              .procname       = "net",
++              .mode           = 0555,
++              .child          = brnf_bridge_table,
++      },
++      { .ctl_name = 0 }
++};
++#endif
 +
-+static void send_unreach(struct sk_buff *skb_in, int code)
++int br_netfilter_init(void)
 +{
-+      struct iphdr *iph;
-+      struct udphdr *udph;
-+      struct icmphdr *icmph;
-+      struct sk_buff *nskb;
-+      u32 saddr;
-+      u8 tos;
-+      int hh_len, length;
-+      struct rtable *rt = (struct rtable*)skb_in->dst;
-+      unsigned char *data;
-+
-+      if (!rt)
-+              return;
-+
-+      /* FIXME: Use sysctl number. --RR */
-+      if (!xrlim_allow(&rt->u.dst, 1*HZ))
-+              return;
-+
-+      iph = skb_in->nh.iph;
-+
-+      /* No replies to physical multicast/broadcast */
-+      if (skb_in->pkt_type!=PACKET_HOST)
-+              return;
-+
-+      /* Now check at the protocol level */
-+      if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
-+              return;
-+
-+      /* Only reply to fragment 0. */
-+      if (iph->frag_off&htons(IP_OFFSET))
-+              return;
-+
-+      /* if UDP checksum is set, verify it's correct */
-+      if (iph->protocol == IPPROTO_UDP
-+          && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
-+              int datalen = skb_in->len - (iph->ihl<<2);
-+              udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
-+              if (udph->check
-+                  && csum_tcpudp_magic(iph->saddr, iph->daddr,
-+                                       datalen, IPPROTO_UDP,
-+                                       csum_partial((char *)udph, datalen,
-+                                                    0)) != 0)
-+                      return;
-+      }
-+                  
-+      /* If we send an ICMP error to an ICMP error a mess would result.. */
-+      if (iph->protocol == IPPROTO_ICMP
-+          && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
-+              icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
-+              /* Between echo-reply (0) and timestamp (13),
-+                 everything except echo-request (8) is an error.
-+                 Also, anything greater than NR_ICMP_TYPES is
-+                 unknown, and hence should be treated as an error... */
-+              if ((icmph->type < ICMP_TIMESTAMP
-+                   && icmph->type != ICMP_ECHOREPLY
-+                   && icmph->type != ICMP_ECHO)
-+                  || icmph->type > NR_ICMP_TYPES)
-+                      return;
-+      }
-+
-+      saddr = iph->daddr;
-+      if (!(rt->rt_flags & RTCF_LOCAL))
-+              saddr = 0;
-+
-+      tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
-+
-+      if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
-+              return;
-+
-+      /* RFC says return as much as we can without exceeding 576 bytes. */
-+      length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
-+
-+      if (length > rt->u.dst.pmtu)
-+              length = rt->u.dst.pmtu;
-+      if (length > 576)
-+              length = 576;
-+
-+      hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
-+
-+      nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC);
-+      if (!nskb) {
-+              ip_rt_put(rt);
-+              return;
-+      }
-+
-+      nskb->priority = 0;
-+      nskb->dst = &rt->u.dst;
-+      skb_reserve(nskb, hh_len);
-+
-+      /* Set up IP header */
-+      iph = nskb->nh.iph
-+              = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
-+      iph->version=4;
-+      iph->ihl=5;
-+      iph->tos=tos;
-+      iph->tot_len = htons(length);
-+
-+      /* PMTU discovery never applies to ICMP packets. */
-+      iph->frag_off = 0;
-+
-+      iph->ttl = MAXTTL;
-+      ip_select_ident(iph, &rt->u.dst, NULL);
-+      iph->protocol=IPPROTO_ICMP;
-+      iph->saddr=rt->rt_src;
-+      iph->daddr=rt->rt_dst;
-+      iph->check=0;
-+      iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-+
-+      /* Set up ICMP header. */
-+      icmph = nskb->h.icmph
-+              = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
-+      icmph->type = ICMP_DEST_UNREACH;
-+      icmph->code = code;     
-+      icmph->un.gateway = 0;
-+      icmph->checksum = 0;
-+      
-+      /* Copy as much of original packet as will fit */
-+      data = skb_put(nskb,
-+                     length - sizeof(struct iphdr) - sizeof(struct icmphdr));
-+      /* FIXME: won't work with nonlinear skbs --RR */
-+      memcpy(data, skb_in->nh.iph,
-+             length - sizeof(struct iphdr) - sizeof(struct icmphdr));
-+      icmph->checksum = ip_compute_csum((unsigned char *)icmph,
-+                                        length - sizeof(struct iphdr));
-+
-+      nf_ct_attach(nskb, skb_in);
-+
-+      NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-+              ip_finish_output);
-+}     
-+
-+static unsigned int reject(struct sk_buff **pskb,
-+                         unsigned int hooknum,
-+                         const struct net_device *in,
-+                         const struct net_device *out,
-+                         const void *targinfo,
-+                         void *userinfo)
-+{
-+      const struct ipt_reject_info *reject = targinfo;
-+
-+      /* Our naive response construction doesn't deal with IP
-+           options, and probably shouldn't try. */
-+      if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr))
-+              return NF_DROP;
-+
-+      /* WARNING: This code causes reentry within iptables.
-+         This means that the iptables jump stack is now crap.  We
-+         must return an absolute verdict. --RR */
-+      switch (reject->with) {
-+      case IPT_ICMP_NET_UNREACHABLE:
-+              send_unreach(*pskb, ICMP_NET_UNREACH);
-+              break;
-+      case IPT_ICMP_HOST_UNREACHABLE:
-+              send_unreach(*pskb, ICMP_HOST_UNREACH);
-+              break;
-+      case IPT_ICMP_PROT_UNREACHABLE:
-+              send_unreach(*pskb, ICMP_PROT_UNREACH);
-+              break;
-+      case IPT_ICMP_PORT_UNREACHABLE:
-+              send_unreach(*pskb, ICMP_PORT_UNREACH);
-+              break;
-+      case IPT_ICMP_NET_PROHIBITED:
-+              send_unreach(*pskb, ICMP_NET_ANO);
-+              break;
-+      case IPT_ICMP_HOST_PROHIBITED:
-+              send_unreach(*pskb, ICMP_HOST_ANO);
-+              break;
-+      case IPT_ICMP_ADMIN_PROHIBITED:
-+              send_unreach(*pskb, ICMP_PKT_FILTERED);
-+              break;
-+      case IPT_TCP_RESET:
-+              send_reset(*pskb, hooknum);
-+      case IPT_ICMP_ECHOREPLY:
-+              /* Doesn't happen. */
-+              break;
-+      }
++      int i;
 +
-+      return NF_DROP;
-+}
++      for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
++              int ret;
 +
-+static int check(const char *tablename,
-+               const struct ipt_entry *e,
-+               void *targinfo,
-+               unsigned int targinfosize,
-+               unsigned int hook_mask)
-+{
-+      const struct ipt_reject_info *rejinfo = targinfo;
++              if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
++                      continue;
 +
-+      if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
-+              DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
-+              return 0;
-+      }
++              while (i--)
++                      nf_unregister_hook(&br_nf_ops[i]);
 +
-+      /* Only allow these for packet filtering. */
-+      if (strcmp(tablename, "filter") != 0) {
-+              DEBUGP("REJECT: bad table `%s'.\n", tablename);
-+              return 0;
-+      }
-+      if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
-+                         | (1 << NF_IP_FORWARD)
-+                         | (1 << NF_IP_LOCAL_OUT))) != 0) {
-+              DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
-+              return 0;
++              return ret;
 +      }
 +
-+      if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
-+              printk("REJECT: ECHOREPLY no longer supported.\n");
-+              return 0;
-+      } else if (rejinfo->with == IPT_TCP_RESET) {
-+              /* Must specify that it's a TCP packet */
-+              if (e->ip.proto != IPPROTO_TCP
-+                  || (e->ip.invflags & IPT_INV_PROTO)) {
-+                      DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
-+                      return 0;
-+              }
++#ifdef CONFIG_SYSCTL
++      brnf_sysctl_header = register_sysctl_table(brnf_net_table, 0);
++      if (brnf_sysctl_header == NULL) {
++              printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n");
++              for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++)
++                      nf_unregister_hook(&br_nf_ops[i]);
++              return -EFAULT;
 +      }
++#endif
 +
-+      return 1;
-+}
-+
-+static struct ipt_target ipt_reject_reg
-+= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
++      printk(KERN_NOTICE "Bridge firewalling registered\n");
 +
-+static int __init init(void)
-+{
-+      if (ipt_register_target(&ipt_reject_reg))
-+              return -EINVAL;
 +      return 0;
 +}
 +
-+static void __exit fini(void)
++void br_netfilter_fini(void)
 +{
-+      ipt_unregister_target(&ipt_reject_reg);
-+}
++      int i;
 +
-+module_init(init);
-+module_exit(fini);
-+MODULE_LICENSE("GPL");
-diff -Nur linux-mips-cvs/net/ipv4/netfilter/ipt_physdev.c linux-ebtables/net/ipv4/netfilter/ipt_physdev.c
---- linux-mips-cvs/net/ipv4/netfilter/ipt_physdev.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-ebtables/net/ipv4/netfilter/ipt_physdev.c    2005-02-07 05:52:50.000000000 +0100
++      for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
++              nf_unregister_hook(&br_nf_ops[i]);
++#ifdef CONFIG_SYSCTL
++      unregister_sysctl_table(brnf_sysctl_header);
++#endif
++
++}
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/ipt_physdev.c     2005-03-14 00:00:30.000000000 +0100
 @@ -0,0 +1,127 @@
 +/* Kernel module to match the bridge port in and
 + * out device for IP packets coming into contact with a bridge. */
@@ -9353,3 +6925,88 @@ diff -Nur linux-mips-cvs/net/ipv4/netfilter/ipt_physdev.c linux-ebtables/net/ipv
 +module_exit(fini);
 +MODULE_LICENSE("GPL");
 +EXPORT_NO_SYMBOLS;
+--- /dev/null  2005-03-14 20:10:29.001600248 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/netfilter_ipv4/ipt_physdev.h   2005-03-14 21:24:30.000000000 +0100
+@@ -0,0 +1,24 @@
++#ifndef _IPT_PHYSDEV_H
++#define _IPT_PHYSDEV_H
++
++#ifdef __KERNEL__
++#include <linux/if.h>
++#endif
++
++#define IPT_PHYSDEV_OP_IN             0x01
++#define IPT_PHYSDEV_OP_OUT            0x02
++#define IPT_PHYSDEV_OP_BRIDGED                0x04
++#define IPT_PHYSDEV_OP_ISIN           0x08
++#define IPT_PHYSDEV_OP_ISOUT          0x10
++#define IPT_PHYSDEV_OP_MASK           (0x20 - 1)
++
++struct ipt_physdev_info {
++      char physindev[IFNAMSIZ];
++      char in_mask[IFNAMSIZ];
++      char physoutdev[IFNAMSIZ];
++      char out_mask[IFNAMSIZ];
++      u_int8_t invert;
++      u_int8_t bitmask;
++};
++
++#endif /*_IPT_PHYSDEV_H*/
+--- linux-2.4.29/net/8021q/vlan_dev.c  2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/8021q/vlan_dev.c 2005-03-14 00:00:30.000000000 +0100
+@@ -488,6 +488,10 @@ int vlan_dev_hard_start_xmit(struct sk_b
+       stats->tx_packets++; /* for statics only */
+       stats->tx_bytes += skb->len;
++      skb->protocol = __constant_htons(ETH_P_8021Q);
++      skb->mac.raw -= VLAN_HLEN;
++      skb->nh.raw -= VLAN_HLEN;
++
+       skb->dev = VLAN_DEV_INFO(dev)->real_dev;
+       dev_queue_xmit(skb);
+--- linux-2.4.29/include/linux/sysctl.h        2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/include/linux/sysctl.h       2005-03-14 21:07:18.000000000 +0100
+@@ -608,6 +608,15 @@ enum {
+       NET_DECNET_CONF_DEV_STATE = 7
+ };
++/* /proc/sys/net/bridge */
++enum {
++      NET_BRIDGE_NF_CALL_ARPTABLES = 1,
++      NET_BRIDGE_NF_CALL_IPTABLES = 2,
++      NET_BRIDGE_NF_CALL_IP6TABLES = 3,
++      NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4,
++};
++
++
+ /* CTL_PROC names: */
+ /* CTL_FS names: */
+--- linux-2.4.29/net/ipv4/netfilter/ipt_REJECT.c       2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-ebt-brnf/net/ipv4/netfilter/ipt_REJECT.c      2005-03-14 00:00:30.000000000 +0100
+@@ -15,6 +15,9 @@
+ #include <net/route.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+ #include <linux/netfilter_ipv4/ipt_REJECT.h>
++#ifdef CONFIG_BRIDGE_NETFILTER
++#include <linux/netfilter_bridge.h>
++#endif
+ #if 0
+ #define DEBUGP printk
+@@ -29,7 +32,13 @@ static inline struct rtable *route_rever
+       struct rt_key key = {};
+       struct rtable *rt;
+-      if (hook != NF_IP_FORWARD) {
++      /* We don't require ip forwarding to be enabled to be able to
++       * send a RST reply for bridged traffic. */
++      if (hook != NF_IP_FORWARD
++#ifdef CONFIG_BRIDGE_NETFILTER
++          || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
++#endif
++         ) {
+               key.dst = iph->saddr;
+               if (hook == NF_IP_LOCAL_IN)
+                       key.src = iph->daddr;