## Automatically generated incremental diff
## From:   linux-2.4.5-pre1
## To:     linux-2.4.5-pre2
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.5-pre1/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.4.5-pre1/Documentation/Configure.help	Fri Apr 20 16:23:12 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:41:47 2001
@@ -5635,7 +5635,7 @@
   Default: 253
 
 Initial Bus Reset Settle Delay
-CONFIG_AIC7XXX_RESET_DELAY
+CONFIG_AIC7XXX_RESET_DELAY_MS
   The number of milliseconds to delay after an initial bus reset.
   The bus settle delay following all error recovery actions is
   dictated by the SCSI layer and is not affected by this value.
diff -urN linux-2.4.5-pre1/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile
--- linux-2.4.5-pre1/Documentation/DocBook/Makefile	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/DocBook/Makefile	Mon Dec  3 22:41:47 2001
@@ -95,6 +95,7 @@
 		$(TOPDIR)/kernel/pm.c \
 		$(TOPDIR)/kernel/ksyms.c \
 		$(TOPDIR)/kernel/kmod.c \
+		$(TOPDIR)/kernel/module.c \
 		$(TOPDIR)/kernel/printk.c \
 		$(TOPDIR)/kernel/sched.c \
 		$(TOPDIR)/kernel/sysctl.c \
diff -urN linux-2.4.5-pre1/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl
--- linux-2.4.5-pre1/Documentation/DocBook/kernel-api.tmpl	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/DocBook/kernel-api.tmpl	Mon Dec  3 22:41:47 2001
@@ -140,8 +140,13 @@
   </chapter>
 
   <chapter id="modload">
-     <title>Module Loading</title>
+     <title>Module Support</title>
+     <sect1><title>Module Loading</title>
 !Ekernel/kmod.c
+     </sect1>
+     <sect1><title>Inter Module support</title>
+!Ekernel/module.c
+     </sect1>
   </chapter>
 
   <chapter id="hardware">
diff -urN linux-2.4.5-pre1/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt
--- linux-2.4.5-pre1/Documentation/networking/8139too.txt	Thu Apr 19 09:32:48 2001
+++ linux/Documentation/networking/8139too.txt	Mon Dec  3 22:41:47 2001
@@ -185,6 +185,13 @@
 Change History
 --------------
 
+Version 0.9.17 - May 7, 2001
+
+* Fix chipset wakeup bug which prevent media connection for 8139B
+* Print out "media is unconnected..." instead of 
+  "partner ability 0000"
+
+
 Version 0.9.16 - April 14, 2001
 
 * Complete MMIO audit, disable read-after-every-write
diff -urN linux-2.4.5-pre1/Makefile linux/Makefile
--- linux-2.4.5-pre1/Makefile	Mon Dec  3 22:41:06 2001
+++ linux/Makefile	Mon Dec  3 22:41:47 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 5
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -144,7 +144,6 @@
 DRIVERS-$(CONFIG_ATM) += drivers/atm/atm.o
 DRIVERS-$(CONFIG_IDE) += drivers/ide/idedriver.o
 DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
-DRIVERS-$(CONFIG_SCSI_AIC7XXX) += drivers/scsi/aic7xxx/aic7xxx_drv.o
 DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
 
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
diff -urN linux-2.4.5-pre1/arch/alpha/defconfig linux/arch/alpha/defconfig
--- linux-2.4.5-pre1/arch/alpha/defconfig	Sun Mar  4 14:30:18 2001
+++ linux/arch/alpha/defconfig	Mon Dec  3 22:41:47 2001
@@ -286,7 +286,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY=5000
+CONFIG_AIC7XXX_RESET_DELAY_MS=5000
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
 # CONFIG_SCSI_AM53C974 is not set
diff -urN linux-2.4.5-pre1/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.4.5-pre1/arch/i386/defconfig	Mon Dec  3 22:41:06 2001
+++ linux/arch/i386/defconfig	Mon Dec  3 22:41:47 2001
@@ -441,7 +441,6 @@
 # CONFIG_PCMCIA_XIRTULIP is not set
 CONFIG_NET_PCMCIA_RADIO=y
 CONFIG_PCMCIA_RAYCS=y
-# CONFIG_PCMCIA_HERMES is not set
 # CONFIG_PCMCIA_NETWAVE is not set
 # CONFIG_PCMCIA_WAVELAN is not set
 # CONFIG_AIRONET4500_CS is not set
diff -urN linux-2.4.5-pre1/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- linux-2.4.5-pre1/arch/i386/kernel/pci-irq.c	Mon Dec  3 22:41:06 2001
+++ linux/arch/i386/kernel/pci-irq.c	Mon Dec  3 22:41:47 2001
@@ -411,6 +411,7 @@
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   pirq_piix_get, pirq_piix_set },
 	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_0, pirq_piix_get, pirq_piix_set },
+	{ "PIIX", PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_0, pirq_piix_get, pirq_piix_set },
 
 	{ "ALI", PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, pirq_ali_get, pirq_ali_set },
 
diff -urN linux-2.4.5-pre1/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.4.5-pre1/arch/i386/kernel/setup.c	Fri Apr 27 14:10:32 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec  3 22:41:47 2001
@@ -127,6 +127,9 @@
 unsigned int BIOS_revision;
 unsigned int mca_pentium_flag;
 
+/* For PCI or other memory-mapped resources */
+unsigned long pci_mem_start = 0x10000000;
+
 /*
  * Setup options
  */
@@ -1008,6 +1011,9 @@
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
 		request_resource(&ioport_resource, standard_io_resources+i);
+
+	/* Tell the PCI layer not to allocate too close to the RAM area.. */
+	pci_mem_start = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
diff -urN linux-2.4.5-pre1/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- linux-2.4.5-pre1/arch/i386/kernel/traps.c	Mon Mar 19 18:23:40 2001
+++ linux/arch/i386/kernel/traps.c	Mon Dec  3 22:41:47 2001
@@ -973,7 +973,7 @@
 	set_trap_gate(11,&segment_not_present);
 	set_trap_gate(12,&stack_segment);
 	set_trap_gate(13,&general_protection);
-	set_trap_gate(14,&page_fault);
+	set_intr_gate(14,&page_fault);
 	set_trap_gate(15,&spurious_interrupt_bug);
 	set_trap_gate(16,&coprocessor_error);
 	set_trap_gate(17,&alignment_check);
diff -urN linux-2.4.5-pre1/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- linux-2.4.5-pre1/arch/i386/mm/fault.c	Mon Dec  3 22:41:06 2001
+++ linux/arch/i386/mm/fault.c	Mon Dec  3 22:41:47 2001
@@ -117,6 +117,10 @@
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
+	/* It's safe to allow irq's after cr2 has been saved */
+	if (regs->eflags & X86_EFLAGS_IF)
+		local_irq_enable();
+
 	tsk = current;
 
 	/*
@@ -127,8 +131,12 @@
 	 * be in an interrupt or a critical region, and should
 	 * only copy the information from the master page table,
 	 * nothing more.
+	 *
+	 * This verifies that the fault happens in kernel space
+	 * (error_code & 4) == 0, and that the fault was not a
+	 * protection error (error_code & 1) == 0.
 	 */
-	if (address >= TASK_SIZE)
+	if (address >= TASK_SIZE && !(error_code & 5))
 		goto vmalloc_fault;
 
 	mm = tsk->mm;
@@ -224,7 +232,6 @@
 bad_area:
 	up_read(&mm->mmap_sem);
 
-bad_area_nosemaphore:
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
 		tsk->thread.cr2 = address;
@@ -329,24 +336,25 @@
 		int offset = __pgd_offset(address);
 		pgd_t *pgd, *pgd_k;
 		pmd_t *pmd, *pmd_k;
+		pte_t *pte_k;
 
 		asm("movl %%cr3,%0":"=r" (pgd));
 		pgd = offset + (pgd_t *)__va(pgd);
 		pgd_k = init_mm.pgd + offset;
 
-		if (!pgd_present(*pgd)) {
-			if (!pgd_present(*pgd_k))
-				goto bad_area_nosemaphore;
-			set_pgd(pgd, *pgd_k);
-			return;
-		}
-
+		if (!pgd_present(*pgd_k))
+			goto no_context;
+		set_pgd(pgd, *pgd_k);
+		
 		pmd = pmd_offset(pgd, address);
 		pmd_k = pmd_offset(pgd_k, address);
-
-		if (pmd_present(*pmd) || !pmd_present(*pmd_k))
-			goto bad_area_nosemaphore;
+		if (!pmd_present(*pmd_k))
+			goto no_context;
 		set_pmd(pmd, *pmd_k);
+
+		pte_k = pte_offset(pmd_k, address);
+		if (!pte_present(*pte_k))
+			goto no_context;
 		return;
 	}
 }
diff -urN linux-2.4.5-pre1/arch/ppc/defconfig linux/arch/ppc/defconfig
--- linux-2.4.5-pre1/arch/ppc/defconfig	Sun Mar  4 14:30:18 2001
+++ linux/arch/ppc/defconfig	Mon Dec  3 22:41:47 2001
@@ -297,7 +297,7 @@
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY=15000
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
diff -urN linux-2.4.5-pre1/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- linux-2.4.5-pre1/arch/sparc/kernel/head.S	Thu Apr 26 22:17:26 2001
+++ linux/arch/sparc/kernel/head.S	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.103 2000/05/09 17:40:13 davem Exp $
+/* $Id: head.S,v 1.104 2001/04/27 07:02:41 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.5-pre1/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- linux-2.4.5-pre1/arch/sparc/kernel/irq.c	Thu Apr 26 22:17:26 2001
+++ linux/arch/sparc/kernel/irq.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.111 2001/04/14 21:13:46 davem Exp $
+/*  $Id: irq.c,v 1.112 2001/04/27 07:02:42 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
diff -urN linux-2.4.5-pre1/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- linux-2.4.5-pre1/arch/sparc/kernel/sys_sunos.c	Thu Apr 26 22:17:26 2001
+++ linux/arch/sparc/kernel/sys_sunos.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.133 2001/03/24 09:36:10 davem Exp $
+/* $Id: sys_sunos.c,v 1.134 2001/04/27 07:02:42 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.5-pre1/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c
--- linux-2.4.5-pre1/arch/sparc/prom/console.c	Thu Apr 26 22:17:26 2001
+++ linux/arch/sparc/prom/console.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.23 2000/08/26 02:38:03 anton Exp $
+/* $Id: console.c,v 1.24 2001/04/27 07:02:42 davem Exp $
  * console.c: Routines that deal with sending and receiving IO
  *            to/from the current console device using the PROM.
  *
diff -urN linux-2.4.5-pre1/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- linux-2.4.5-pre1/arch/sparc64/defconfig	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/defconfig	Mon Dec  3 22:41:47 2001
@@ -311,7 +311,7 @@
 CONFIG_SCSI_QLOGICPTI=m
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
-CONFIG_AIC7XXX_RESET_DELAY=5000
+CONFIG_AIC7XXX_RESET_DELAY_MS=5000
 CONFIG_SCSI_AIC7XXX_OLD=m
 CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_OLD_CMDS_PER_DEVICE=8
@@ -573,6 +573,7 @@
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
 CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
 CONFIG_USB_ACM=m
 CONFIG_USB_PRINTER=m
 
diff -urN linux-2.4.5-pre1/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- linux-2.4.5-pre1/arch/sparc64/kernel/pci.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/kernel/pci.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.24 2001/03/28 10:56:34 davem Exp $
+/* $Id: pci.c,v 1.25 2001/05/02 00:27:27 davem Exp $
  * pci.c: UltraSparc PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com)
@@ -77,13 +77,13 @@
 volatile int pci_poke_faulted;
 
 /* Probe for all PCI controllers in the system. */
-extern void sabre_init(int);
-extern void psycho_init(int);
-extern void schizo_init(int);
+extern void sabre_init(int, char *);
+extern void psycho_init(int, char *);
+extern void schizo_init(int, char *);
 
 static struct {
 	char *model_name;
-	void (*init)(int);
+	void (*init)(int, char *);
 } pci_controller_table[] = {
 	{ "SUNW,sabre", sabre_init },
 	{ "pci108e,a000", sabre_init },
@@ -104,7 +104,7 @@
 		if (!strncmp(model_name,
 			     pci_controller_table[i].model_name,
 			     namelen)) {
-			pci_controller_table[i].init(node);
+			pci_controller_table[i].init(node, model_name);
 			return;
 		}
 	}
diff -urN linux-2.4.5-pre1/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- linux-2.4.5-pre1/arch/sparc64/kernel/pci_psycho.c	Thu Apr 19 08:38:49 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.22 2001/04/17 01:19:23 davem Exp $
+/* $Id: pci_psycho.c,v 1.23 2001/05/02 00:27:27 davem Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -1521,7 +1521,7 @@
 
 #define PSYCHO_CONFIGSPACE	0x001000000UL
 
-void __init psycho_init(int node)
+void __init psycho_init(int node, char *model_name)
 {
 	struct linux_prom64_registers pr_regs[3];
 	struct pci_controller_info *p;
diff -urN linux-2.4.5-pre1/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- linux-2.4.5-pre1/arch/sparc64/kernel/pci_sabre.c	Thu Apr 26 22:17:25 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.27 2001/04/24 05:14:12 davem Exp $
+/* $Id: pci_sabre.c,v 1.29 2001/05/02 00:32:56 davem Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -215,7 +215,7 @@
 	 ((unsigned long)(DEVFN) << 8)  |	\
 	 ((unsigned long)(REG)))
 
-static int apb_present;
+static int hummingbird_p;
 
 static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
 				     unsigned char bus,
@@ -231,7 +231,7 @@
 
 static int sabre_out_of_range(unsigned char devfn)
 {
-	if (!apb_present)
+	if (hummingbird_p)
 		return 0;
 
 	return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
@@ -243,7 +243,7 @@
 				unsigned char bus,
 				unsigned char devfn)
 {
-	if (!apb_present)
+	if (hummingbird_p)
 		return 0;
 
 	return ((pbm->parent == 0) ||
@@ -1461,12 +1461,10 @@
 			prom_printf("Cannot register Hummingbird's MEM space.\n");
 			prom_halt();
 		}
-	} else {
-		apb_present = 1;
 	}
 }
 
-void __init sabre_init(int pnode)
+void __init sabre_init(int pnode, char *model_name)
 {
 	struct linux_prom64_registers pr_regs[2];
 	struct pci_controller_info *p;
@@ -1477,6 +1475,18 @@
 	u32 vdma[2];
 	u32 upa_portid, dma_mask;
 	int bus;
+
+	hummingbird_p = 0;
+	if (!strcmp(model_name, "pci108e,a001"))
+		hummingbird_p = 1;
+	else if (!strcmp(model_name, "SUNW,sabre")) {
+		char compat[64];
+
+		if (prom_getproperty(pnode, "compatible",
+				     compat, sizeof(compat)) > 0 &&
+		    !strcmp(compat, "pci108e,a001"))
+			hummingbird_p = 1;
+	}
 
 	p = kmalloc(sizeof(*p), GFP_ATOMIC);
 	if (!p) {
diff -urN linux-2.4.5-pre1/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- linux-2.4.5-pre1/arch/sparc64/kernel/pci_schizo.c	Thu Apr 19 08:38:49 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.14 2001/04/17 01:19:23 davem Exp $
+/* $Id: pci_schizo.c,v 1.15 2001/05/02 00:27:27 davem Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -1709,7 +1709,7 @@
 	schizo_write(pbm_b_base + 0x2000UL, tmp);
 }
 
-void __init schizo_init(int node)
+void __init schizo_init(int node, char *model_name)
 {
 	struct linux_prom64_registers pr_regs[3];
 	struct pci_controller_info *p;
diff -urN linux-2.4.5-pre1/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- linux-2.4.5-pre1/arch/sparc64/kernel/sys_sunos32.c	Thu Apr 26 22:17:26 2001
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.59 2001/03/24 09:36:11 davem Exp $
+/* $Id: sys_sunos32.c,v 1.60 2001/04/27 07:02:42 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
diff -urN linux-2.4.5-pre1/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.4.5-pre1/drivers/cdrom/cdrom.c	Thu Mar 29 11:56:07 2001
+++ linux/drivers/cdrom/cdrom.c	Mon Dec  3 22:41:47 2001
@@ -2626,7 +2626,8 @@
 
 static void cdrom_sysctl_unregister(void)
 {
-	unregister_sysctl_table(cdrom_sysctl_header);
+	if (cdrom_sysctl_header)
+		unregister_sysctl_table(cdrom_sysctl_header);
 }
 
 #endif /* CONFIG_SYSCTL */
diff -urN linux-2.4.5-pre1/drivers/char/mxser.c linux/drivers/char/mxser.c
--- linux-2.4.5-pre1/drivers/char/mxser.c	Fri Mar  2 11:12:07 2001
+++ linux/drivers/char/mxser.c	Mon Dec  3 22:41:47 2001
@@ -27,10 +27,11 @@
  *
  *      Copyright (C) 1999,2000  Moxa Technologies Co., LTD.
  *
- *      for             : LINUX 2.0.X, 2.2.X
- *      date            : 1999/07/22
- *      version         : 1.1 
+ *      for             : LINUX 2.0.X, 2.2.X, 2.4.X
+ *      date            : 2001/05/01
+ *      version         : 1.2 
  *      
+ *    Fixes for C104H/PCI by Tim Hockin <thockin@sun.com>
  */
 
 #include <linux/config.h>
@@ -61,7 +62,7 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 
-#define		MXSER_VERSION			"1.1kern"
+#define		MXSER_VERSION			"1.2"
 
 #define		MXSERMAJOR	 	174
 #define		MXSERCUMAJOR		175
@@ -120,7 +121,7 @@
 #define CI104J_ASIC_ID  5
 
 enum {
-	MXSER_BOARD_C168_ISA = 1,
+	MXSER_BOARD_C168_ISA = 0,
 	MXSER_BOARD_C104_ISA,
 	MXSER_BOARD_CI104J,
 	MXSER_BOARD_C168_PCI,
@@ -434,7 +435,7 @@
 			     "mxser", info);
 	if (retval) {
 		restore_flags(flags);
-		printk("Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
+		printk("Board %d: %s", board, mxser_brdname[hwconf->board_type]);
 		printk("  Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
 		return (retval);
 	}
@@ -455,7 +456,7 @@
 	unsigned int ioaddress;
 
 	hwconf->board_type = board_type;
-	hwconf->ports = mxser_numports[board_type - 1];
+	hwconf->ports = mxser_numports[board_type];
 	ioaddress = pci_resource_start (pdev, 2);
 	for (i = 0; i < hwconf->ports; i++)
 		hwconf->ioaddr[i] = ioaddress + 8 * i;
@@ -544,7 +545,7 @@
 
 		if (retval != 0)
 			printk("Found MOXA %s board (CAP=0x%x)\n",
-			       mxser_brdname[hwconf.board_type - 1],
+			       mxser_brdname[hwconf.board_type],
 			       ioaddr[b]);
 
 		if (retval <= 0) {
@@ -579,7 +580,7 @@
 
 		if (retval != 0)
 			printk("Found MOXA %s board (CAP=0x%x)\n",
-			       mxser_brdname[hwconf.board_type - 1],
+			       mxser_brdname[hwconf.board_type],
 			       ioaddr[b]);
 
 		if (retval <= 0) {
@@ -612,21 +613,15 @@
 
 		n = sizeof(mxser_pcibrds) / sizeof(mxser_pciinfo);
 		index = 0;
-		b = 0;
-		while (b < n) {
+		for (b = 0; b < n; b++) {
 			pdev = pci_find_device(mxser_pcibrds[b].vendor_id,
 					       mxser_pcibrds[b].device_id, pdev);
-			if (!pdev)
-			{
-				b++;
-				continue;
-			}
-			if (pci_enable_device(pdev))
+			if (!pdev || pci_enable_device(pdev))
 				continue;
 			hwconf.pdev = pdev;
 			printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
-				mxser_brdname[mxser_pcibrds[b].board_type - 1],
-				pdev->bus->number, PCI_SLOT(pdev->devfn >> 3));
+				mxser_brdname[mxser_pcibrds[b].board_type],
+				pdev->bus->number, PCI_SLOT(pdev->devfn));
 			if (m >= MXSER_BOARDS) {
 				printk("Too many Smartio family boards found (maximum %d),board not configured\n", MXSER_BOARDS);
 			} else {
@@ -1352,7 +1347,7 @@
 		return;
 	if (port == 0)
 		return;
-	max = mxser_numports[mxsercfg[i].board_type - 1];
+	max = mxser_numports[mxsercfg[i].board_type];
 
 	while (1) {
 		irqbits = inb(port->vector) & port->vectormask;
diff -urN linux-2.4.5-pre1/drivers/net/8139too.c linux/drivers/net/8139too.c
--- linux-2.4.5-pre1/drivers/net/8139too.c	Thu Apr 19 09:32:48 2001
+++ linux/drivers/net/8139too.c	Mon Dec  3 22:41:47 2001
@@ -149,7 +149,7 @@
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.16"
+#define RTL8139_VERSION "0.9.17"
 #define MODNAME "8139too"
 #define RTL8139_DRIVER_NAME   MODNAME " Fast Ethernet driver " RTL8139_VERSION
 #define PFX MODNAME ": "
@@ -728,7 +728,7 @@
 	struct rtl8139_private *tp;
 	u8 tmp8;
 	int rc;
-	unsigned int i, have_pci_pm = 1;
+	unsigned int i;
 	u32 pio_start, pio_end, pio_flags, pio_len;
 	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
 	u32 tmp;
@@ -770,10 +770,6 @@
 	DPRINTK("PIO region size == 0x%02X\n", pio_len);
 	DPRINTK("MMIO region size == 0x%02lX\n", mmio_len);
 
-	/* ugly hueristic, but it's a chicken-and-egg problem */
-	if (pio_len < RTL8139B_IO_SIZE)
-		have_pci_pm = 0;
-	
 #ifdef USE_IO_OPS
 	/* make sure PCI base addr 0 is PIO */
 	if (!(pio_flags & IORESOURCE_IO)) {
@@ -824,30 +820,7 @@
 #endif /* USE_IO_OPS */
 
 	/* Bring old chips out of low-power mode. */
-	if (have_pci_pm) {
-		u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
-		if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
-		    (tmp8 & LWAKE))
-			new_tmp8 &= ~LWAKE;
-		new_tmp8 |= Cfg1_PM_Enable;
-		if (new_tmp8 != tmp8) {
-			RTL_W8 (Cfg9346, Cfg9346_Unlock);
-			RTL_W8 (Config1, tmp8);
-			RTL_W8 (Cfg9346, Cfg9346_Lock);
-		}
-		if (rtl_chip_info[tp->chipset].flags & HasLWake) {
-			tmp8 = RTL_R8 (Config4);
-			if (tmp8 & LWPTN)
-				RTL_W8 (Config4, tmp8 & ~LWPTN);
-		}
-	} else {
-		RTL_W8 (HltClk, 'R');
-		tmp8 = RTL_R8 (Config1);
-		tmp8 &= ~(SLEEP | PWRDN);
-		RTL_W8 (Config1, tmp8);
-	}
-
-	rtl8139_chip_reset (ioaddr);
+	RTL_W8 (HltClk, 'R');
 
 	/* check for missing/broken hardware */
 	if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
@@ -877,6 +850,32 @@
 		tp->chipset,
 		rtl_chip_info[tp->chipset].name);
 
+	if (tp->chipset >= CH_8139B) {
+		u8 new_tmp8 = tmp8 = RTL_R8 (Config1);
+		DPRINTK("PCI PM wakeup\n");
+		if ((rtl_chip_info[tp->chipset].flags & HasLWake) &&
+		    (tmp8 & LWAKE))
+			new_tmp8 &= ~LWAKE;
+		new_tmp8 |= Cfg1_PM_Enable;
+		if (new_tmp8 != tmp8) {
+			RTL_W8 (Cfg9346, Cfg9346_Unlock);
+			RTL_W8 (Config1, tmp8);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
+		}
+		if (rtl_chip_info[tp->chipset].flags & HasLWake) {
+			tmp8 = RTL_R8 (Config4);
+			if (tmp8 & LWPTN)
+				RTL_W8 (Config4, tmp8 & ~LWPTN);
+		}
+	} else {
+		DPRINTK("Old chip wakeup\n");
+		tmp8 = RTL_R8 (Config1);
+		tmp8 &= ~(SLEEP | PWRDN);
+		RTL_W8 (Config1, tmp8);
+	}
+
+	rtl8139_chip_reset (ioaddr);
+
 	DPRINTK ("EXIT, returning 0\n");
 	*dev_out = dev;
 	return 0;
@@ -1358,11 +1357,16 @@
 		else if ((mii_reg5 & 0x0100) == 0x0100
 				 || (mii_reg5 & 0x00C0) == 0x0040)
 			tp->full_duplex = 1;
-		printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+		if (mii_reg5) {
+			printk(KERN_INFO"%s: Setting %s%s-duplex based on"
 			   " auto-negotiated partner ability %4.4x.\n", dev->name,
 			   mii_reg5 == 0 ? "" :
 			   (mii_reg5 & 0x0180) ? "100mbps " : "10mbps ",
 			   tp->full_duplex ? "full" : "half", mii_reg5);
+		} else {
+			printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+			       dev->name);
+		}
 	}
 
 	if (tp->chipset >= CH_8139B) {
@@ -1542,11 +1546,18 @@
 		    || (mii_reg5 & 0x01C0) == 0x0040;
 		if (tp->full_duplex != duplex) {
 			tp->full_duplex = duplex;
-			printk (KERN_INFO
-				"%s: Setting %s-duplex based on MII #%d link"
-				" partner ability of %4.4x.\n", dev->name,
-				tp->full_duplex ? "full" : "half",
-				tp->phys[0], mii_reg5);
+
+			if (mii_reg5) {
+				printk (KERN_INFO
+					"%s: Setting %s-duplex based on MII #%d link"
+					" partner ability of %4.4x.\n",
+					dev->name,
+					tp->full_duplex ? "full" : "half",
+					tp->phys[0], mii_reg5);
+			} else {
+				printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",
+				       dev->name);
+			}
 #if 0
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
diff -urN linux-2.4.5-pre1/drivers/net/Config.in linux/drivers/net/Config.in
--- linux-2.4.5-pre1/drivers/net/Config.in	Sun Apr 22 15:43:21 2001
+++ linux/drivers/net/Config.in	Mon Dec  3 22:41:47 2001
@@ -261,6 +261,9 @@
       dep_bool '     Aironet 4500/4800 I365 broken support (EXPERIMENTAL)' CONFIG_AIRONET4500_I365 $CONFIG_EXPERIMENTAL
    fi
    dep_tristate '   Aironet 4500/4800 PROC interface ' CONFIG_AIRONET4500_PROC $CONFIG_AIRONET4500 m
+
+# New directory for Wireless LAN devices - cards above will move there
+   source drivers/net/wireless/Config.in
 fi
 
 endmenu
diff -urN linux-2.4.5-pre1/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-2.4.5-pre1/drivers/net/Makefile	Thu Apr 19 22:46:05 2001
+++ linux/drivers/net/Makefile	Mon Dec  3 22:41:47 2001
@@ -8,7 +8,7 @@
 obj-n           :=
 obj-            :=
 
-mod-subdirs     := appletalk arcnet fc irda tokenring pcmcia wan
+mod-subdirs     := appletalk arcnet fc irda tokenring pcmcia wireless wan
 
 O_TARGET := net.o
 
@@ -30,6 +30,7 @@
 endif
 
 subdir-$(CONFIG_NET_PCMCIA) += pcmcia
+subdir-$(CONFIG_NET_RADIO) += wireless
 subdir-$(CONFIG_TULIP) += tulip
 subdir-$(CONFIG_IRDA) += irda
 subdir-$(CONFIG_TR) += tokenring
diff -urN linux-2.4.5-pre1/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h
--- linux-2.4.5-pre1/drivers/net/acenic_firmware.h	Tue Mar  6 19:28:33 2001
+++ linux/drivers/net/acenic_firmware.h	Mon Dec  3 22:41:47 2001
@@ -17,7 +17,7 @@
 #define tigonFwSbssLen 0x38
 #define tigonFwBssAddr 0x00015dd0
 #define tigonFwBssLen 0x2080
-#ifndef CONFIG_ACENIC_OMIT_TIGON_I
+#ifdef CONFIG_ACENIC_OMIT_TIGON_I
 #define tigonFwText 0
 #define tigonFwData 0
 #define tigonFwRodata 0
diff -urN linux-2.4.5-pre1/drivers/net/dmfe.c linux/drivers/net/dmfe.c
--- linux-2.4.5-pre1/drivers/net/dmfe.c	Wed Apr 25 16:14:08 2001
+++ linux/drivers/net/dmfe.c	Mon Dec  3 22:41:47 2001
@@ -1306,7 +1306,7 @@
 	rxptr = db->rx_insert_ptr;
 
 	while (db->rx_avail_cnt < RX_DESC_CNT) {
-		if ((skb = alloc_skb(RX_ALLOC_SIZE, GFP_ATOMIC)) == NULL)
+		if ((skb = dev_alloc_skb(RX_ALLOC_SIZE)) == NULL)
 			break;
 		rxptr->rx_skb_ptr = (u32) skb;
 		rxptr->rdes2 = virt_to_bus(skb->tail);
diff -urN linux-2.4.5-pre1/drivers/net/eql.c linux/drivers/net/eql.c
--- linux-2.4.5-pre1/drivers/net/eql.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/eql.c	Mon Dec  3 22:41:47 2001
@@ -422,6 +422,8 @@
 				slave_t *s = eql_new_slave ();
 				equalizer_t *eql = 
 					(equalizer_t *) master_dev->priv;
+				if (!s)
+					return -ENOMEM;
 				s->dev = slave_dev;
 				s->priority = srq.priority;
 				s->priority_bps = srq.priority;
diff -urN linux-2.4.5-pre1/drivers/net/pcmcia/Config.in linux/drivers/net/pcmcia/Config.in
--- linux-2.4.5-pre1/drivers/net/pcmcia/Config.in	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/Config.in	Mon Dec  3 22:41:47 2001
@@ -26,7 +26,6 @@
    bool '  Pcmcia Wireless LAN' CONFIG_NET_PCMCIA_RADIO
    if [ "$CONFIG_NET_PCMCIA_RADIO" = "y" ]; then
       dep_tristate '    Aviator/Raytheon 2.4MHz wireless support' CONFIG_PCMCIA_RAYCS $CONFIG_PCMCIA
-      dep_tristate '    Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA
       dep_tristate '    Xircom Netwave AirSurfer wireless support' CONFIG_PCMCIA_NETWAVE $CONFIG_PCMCIA
       dep_tristate '    AT&T/Lucent Wavelan wireless support' CONFIG_PCMCIA_WAVELAN $CONFIG_PCMCIA
       dep_tristate '    Aironet 4500/4800 PCMCIA support' CONFIG_AIRONET4500_CS $CONFIG_AIRONET4500 $CONFIG_PCMCIA
diff -urN linux-2.4.5-pre1/drivers/net/pcmcia/Makefile linux/drivers/net/pcmcia/Makefile
--- linux-2.4.5-pre1/drivers/net/pcmcia/Makefile	Sun Mar 25 18:24:31 2001
+++ linux/drivers/net/pcmcia/Makefile	Mon Dec  3 22:41:47 2001
@@ -12,7 +12,7 @@
 obj-		:=
 
 # Things that need to export symbols
-export-objs	:= ray_cs.o hermes.o
+export-objs	:= ray_cs.o
 
 # 16-bit client drivers
 obj-$(CONFIG_PCMCIA_3C589)	+= 3c589_cs.o
@@ -25,7 +25,6 @@
 obj-$(CONFIG_ARCNET_COM20020_CS)+= com20020_cs.o
 
 # 16-bit wireless client drivers
-obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o hermes.o
 obj-$(CONFIG_PCMCIA_RAYCS)	+= ray_cs.o
 obj-$(CONFIG_PCMCIA_NETWAVE)	+= netwave_cs.o
 obj-$(CONFIG_PCMCIA_WAVELAN)	+= wavelan_cs.o
diff -urN linux-2.4.5-pre1/drivers/net/pcmcia/hermes.c linux/drivers/net/pcmcia/hermes.c
--- linux-2.4.5-pre1/drivers/net/pcmcia/hermes.c	Wed Apr 25 14:45:48 2001
+++ linux/drivers/net/pcmcia/hermes.c	Wed Dec 31 16:00:00 1969
@@ -1,502 +0,0 @@
-/* hermes.c
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism I & II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver.
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
- * 
- * This file distributed under the GPL, version 2.
- */
-
-static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>";
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/threads.h>
-#include <linux/smp.h>
-#include <asm/io.h>
-#include <linux/ptrace.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/errno.h>
-
-#include "hermes.h"
-
-#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
-#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
-#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */
-#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
-#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
-#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */
-
-#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
-#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
-
-/*
- * Debugging helpers
- */
-
-#undef HERMES_DEBUG
-#ifdef HERMES_DEBUG
-
-#include <stdarg.h>
-
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \
-			printk(#stuff);} while (0)
-
-#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff)
-
-#else /* ! HERMES_DEBUG */
-
-#define DEBUG(lvl, stuff...) do { } while (0)
-
-#endif /* ! HERMES_DEBUG */
-
-/*
- * Prototypes
- */
-
-static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0);
-
-/*
- * Internal inline functions
- */
-
-/*
- * Internal functions
- */
-
-/* Issue a command to the chip. Waiting for it to complete is the caller's
-   problem.
-
-   Returns -EBUSY if the command register is busy, 0 on success.
-
-   Callable from any context.
-*/
-static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0)
-{
-	uint16_t reg;
-/*  	unsigned long k = CMD_BUSY_TIMEOUT; */
-
-	/* First check that the command register is not busy */
-	reg = hermes_read_regn(hw, CMD);
-	if (reg & HERMES_CMD_BUSY) {
-		return -EBUSY;
-	}
-
-	hermes_write_regn(hw, PARAM2, 0);
-	hermes_write_regn(hw, PARAM1, 0);
-	hermes_write_regn(hw, PARAM0, param0);
-	hermes_write_regn(hw, CMD, cmd);
-	
-	return 0;
-}
-
-/*
- * Function definitions
- */
-
-void hermes_struct_init(hermes_t *hw, ushort io)
-{
-	hw->iobase = io;
-	hw->inten = 0x0;
-}
-
-int hermes_reset(hermes_t *hw)
-{
-	uint16_t status, reg;
-	int err = 0;
-	int k;
-
-	/* We don't want to be interrupted while resetting the chipset */
-	hw->inten = 0x0;
-	hermes_write_regn(hw, INTEN, 0);
-	hermes_write_regn(hw, EVACK, 0xffff);
-
-	/* Because we hope we can reset the card even if it gets into
-	   a stupid state, we actually wait to see if the command
-	   register will unbusy itself */
-	k = CMD_BUSY_TIMEOUT;
-	reg = hermes_read_regn(hw, CMD);
-	while (k && (reg & HERMES_CMD_BUSY)) {
-		if (reg == 0xffff) /* Special case - the card has probably been removed,
-				      so don't wait for the timeout */
-			return -ENODEV;
-
-		k--;
-		udelay(1);
-		reg = hermes_read_regn(hw, CMD);
-	}
-	
-	/* No need to explicitly handle the timeout - hermes_issue_cmd() will
-	   probably return -EBUSY */
-
-	/* We don't use hermes_docmd_wait here, because the reset wipes
-	   the magic constant in SWSUPPORT0 away, and it gets confused */
-	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
-	if (err)
-		return err;
-
-	reg = hermes_read_regn(hw, EVSTAT);
-	k = CMD_INIT_TIMEOUT;
-	while ( (! (reg & HERMES_EV_CMD)) && k) {
-		k--;
-		udelay(10);
-		reg = hermes_read_regn(hw, EVSTAT);
-	}
-
-	DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k);
-
-	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
-
-	if (! hermes_present(hw)) {
-		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
-		       hw->iobase);
-		err = -ENODEV;
-		goto out;
-	}
-		
-	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n",
-		       hw->iobase, reg);
-		err = -ETIMEDOUT;
-		goto out;
-	}
-
-	status = hermes_read_regn(hw, STATUS);
-
-	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
-	err = status & HERMES_STATUS_RESULT;
-
- out:
-	return err;
-}
-
-/* Issue a command to the chip, and (busy!) wait for it to
- * complete.
- *
- * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
- *
- * Callable from any context, but locking is your problem. */
-int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp)
-{
-	int err;
-	int k;
-	uint16_t reg;
-
-	err = hermes_issue_cmd(hw, cmd, parm0);
-	if (err) {
-		if (! hermes_present(hw)) {
-			printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n",
-			       hw->iobase);
-			err = -ENODEV;
-		} else 
-			printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n",
-			       hw->iobase);
-		goto out;
-	}
-
-	reg = hermes_read_regn(hw, EVSTAT);
-	k = CMD_COMPL_TIMEOUT;
-	while ( (! (reg & HERMES_EV_CMD)) && k) {
-		k--;
-		udelay(10);
-		reg = hermes_read_regn(hw, EVSTAT);
-	}
-
-	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n",
-		       hw->iobase);
-		err = -ENODEV;
-		goto out;
-	}
-		
-	if (! (reg & HERMES_EV_CMD)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n",
-		       hw->iobase);
-		err = -ETIMEDOUT;
-		goto out;
-	}
-
-	resp->status = hermes_read_regn(hw, STATUS);
-	resp->resp0 = hermes_read_regn(hw, RESP0);
-	resp->resp1 = hermes_read_regn(hw, RESP1);
-	resp->resp2 = hermes_read_regn(hw, RESP2);
-
-	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
-	err = resp->status & HERMES_STATUS_RESULT;
-
- out:
-	return err;
-}
-
-int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid)
-{
-	int err = 0;
-	hermes_response_t resp;
-	int k;
-	uint16_t reg;
-	
-	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
-		return -EINVAL;
-
-	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp);
-	if (err) {
-		printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n",
-		       hw->iobase, err);
-		return err;
-	}
-
-	reg = hermes_read_regn(hw, EVSTAT);
-	k = ALLOC_COMPL_TIMEOUT;
-	while ( (! (reg & HERMES_EV_ALLOC)) && k) {
-		k--;
-		udelay(10);
-		reg = hermes_read_regn(hw, EVSTAT);
-	}
-	
-	if (! hermes_present(hw)) {
-		printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n",
-		       hw->iobase);
-		return -ENODEV;
-	}
-		
-	if (! (reg & HERMES_EV_ALLOC)) {
-		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n",
-		       hw->iobase);
-		return -ETIMEDOUT;
-	}
-
-	*fid = hermes_read_regn(hw, ALLOCFID);
-	hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
-	
-	return 0;
-}
-
-/* Set up a BAP to read a particular chunk of data from card's internal buffer.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
- * from firmware
- *
- * Callable from any context */
-static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
-{
-	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
-	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
-	int k;
-	int l = BAP_ERROR_RETRY;
-	uint16_t reg;
-
-	/* Paranoia.. */
-	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
-		return -EINVAL;
-
-	k = BAP_BUSY_TIMEOUT;
-	reg = hermes_read_reg(hw, oreg);
-
-	if (reg & HERMES_OFFSET_BUSY)
-		return -EBUSY;
-
-	/* Now we actually set up the transfer */
- retry:
-	hermes_write_reg(hw, sreg, id);
-	hermes_write_reg(hw, oreg, offset);
-
-	/* Wait for the BAP to be ready */
-	k = BAP_BUSY_TIMEOUT;
-	reg = hermes_read_reg(hw, oreg);
-	while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
-		k--;
-		udelay(1);
-		reg = hermes_read_reg(hw, oreg);
-	}
-
-	if (reg & HERMES_OFFSET_BUSY)
-		return -ETIMEDOUT;
-
-	/* For some reason, seeking the BAP seems to randomly fail somewhere
-	   (firmware bug?). We retry a few times before giving up. */
-	if (reg & HERMES_OFFSET_ERR) {
-		if (l--) {
-			udelay(1);
-			goto retry;
-		} else
-			return -EIO;
-	}
-
-	return 0;
-}
-
-/* Read a block of data from the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem.  len
- * must be even.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
- */
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
-		     uint16_t id, uint16_t offset)
-{
-	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-	int err = 0;
-
-	if (len % 2)
-		return -EINVAL;
-
-	err = hermes_bap_seek(hw, bap, id, offset);
-	if (err)
-		goto out;
-
-	/* Actually do the transfer */
-	hermes_read_data(hw, dreg, buf, len/2);
-
- out:
-	return err;
-}
-
-/* Write a block of data to the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem. len
- * must be even.
- *
- * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
- */
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
-		      uint16_t id, uint16_t offset)
-{
-	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-	int err = 0;
-
-	if (len % 2)
-		return -EINVAL;
-
-	err = hermes_bap_seek(hw, bap, id, offset);
-	if (err)
-		goto out;
-	
-	/* Actually do the transfer */
-	hermes_write_data(hw, dreg, buf, len/2);
-
- out:	
-	return err;
-}
-
-/* Read a Length-Type-Value record from the card.
- *
- * If length is NULL, we ignore the length read from the card, and
- * read the entire buffer regardless. This is useful because some of
- * the configuration records appear to have incorrect lengths in
- * practice.
- *
- * Callable from user or bh context.  */
-int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
-		    uint16_t *length, void *buf)
-{
-	int err = 0;
-	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-	uint16_t rlength, rtype;
-	hermes_response_t resp;
-	int count;
-
-	if (buflen % 2)
-		return -EINVAL;
-
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp);
-	if (err)
-		goto out;
-
-	err = hermes_bap_seek(hw, bap, rid, 0);
-	if (err)
-		goto out;
-
-	rlength = hermes_read_reg(hw, dreg);
-	rtype = hermes_read_reg(hw, dreg);
-
-	if (length)
-		*length = rlength;
-
-	if (rtype != rid)
-		printk(KERN_WARNING "hermes_read_ltv(): rid  (0x%04x) does "
-		       "not match type (0x%04x)\n", rid, rtype);
-	if (HERMES_RECLEN_TO_BYTES(rlength) > buflen)
-		printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. "
-		       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
-		       HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength);
-	
-	/* For now we always read the whole buffer, the
-	   lengths in the records seem to be wrong, frequently */
-	count = buflen / 2;
-
-#if 0
-	if (length)
-		count = (MIN(buflen, rlength) + 1) / 2;
-	else {
-		count = buflen / 2;
-		if (rlength != buflen)
-			printk(KERN_WARNING "hermes_read_ltv(): Incorrect \
-record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid);
-	}
-#endif
-	hermes_read_data(hw, dreg, buf, count);
-
- out:
-	return err;
-}
-
-int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, 
-		     uint16_t length, const void *value)
-{
-	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
-	int err = 0;
-	hermes_response_t resp;
-	int count;
-	
-	DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n",
-	      bap, rid, length, * ((uint16_t *)value));
-
-	err = hermes_bap_seek(hw, bap, rid, 0);
-	if (err)
-		goto out;
-
-	hermes_write_reg(hw, dreg, length);
-	hermes_write_reg(hw, dreg, rid);
-
-	count = length - 1;
-
-	hermes_write_data(hw, dreg, value, count);
-
-	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
-				rid, &resp);
-
- out:
-	return err;
-}
-
-EXPORT_SYMBOL(hermes_struct_init);
-EXPORT_SYMBOL(hermes_reset);
-EXPORT_SYMBOL(hermes_docmd_wait);
-EXPORT_SYMBOL(hermes_allocate);
-
-EXPORT_SYMBOL(hermes_bap_pread);
-EXPORT_SYMBOL(hermes_bap_pwrite);
-EXPORT_SYMBOL(hermes_read_ltv);
-EXPORT_SYMBOL(hermes_write_ltv);
-
-static int __init init_hermes(void)
-{
-	printk(KERN_INFO "%s\n", version);
-
-	return 0;
-}
-
-module_init(init_hermes);
diff -urN linux-2.4.5-pre1/drivers/net/pcmcia/hermes.h linux/drivers/net/pcmcia/hermes.h
--- linux-2.4.5-pre1/drivers/net/pcmcia/hermes.h	Wed Apr 25 14:45:48 2001
+++ linux/drivers/net/pcmcia/hermes.h	Wed Dec 31 16:00:00 1969
@@ -1,402 +0,0 @@
-/* hermes.h
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism I & II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver.
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
- *
- * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * This file distributed under the GPL, version 2.
- */
-
-#ifndef _HERMES_H
-#define _HERMES_H
-
-/* Notes on locking:
- *
- * As a module of low level hardware access routines, there is no
- * locking. Users of this module should ensure that they serialize
- * access to the hermes_t structure, and to the hardware
-*/
-
-#include <linux/delay.h>
-#include <linux/if_ether.h>
-
-/*
- * Limits and constants
- */
-#define		HERMES_ALLOC_LEN_MIN		(4)
-#define		HERMES_ALLOC_LEN_MAX		(2400)
-#define		HERMES_LTV_LEN_MAX		(34)
-#define		HERMES_BAP_DATALEN_MAX		(4096)
-#define		HERMES_BAP_OFFSET_MAX		(4096)
-#define		HERMES_PORTID_MAX		(7)
-#define		HERMES_NUMPORTS_MAX		(HERMES_PORTID_MAX+1)
-#define		HERMES_PDR_LEN_MAX		(260)	/* in bytes, from EK */
-#define		HERMES_PDA_RECS_MAX		(200)	/* a guess */
-#define		HERMES_PDA_LEN_MAX		(1024)	/* in bytes, from EK */
-#define		HERMES_SCANRESULT_MAX		(35)
-#define		HERMES_CHINFORESULT_MAX		(8)
-#define		HERMES_FRAME_LEN_MAX		(2304)
-#define		HERMES_MAX_MULTICAST		(16)
-#define		HERMES_MAGIC			(0x7d1f)
-
-/*
- * Hermes register offsets
- */
-#define		HERMES_CMD			(0x00)
-#define		HERMES_PARAM0			(0x02)
-#define		HERMES_PARAM1			(0x04)
-#define		HERMES_PARAM2			(0x06)
-#define		HERMES_STATUS			(0x08)
-#define		HERMES_RESP0			(0x0A)
-#define		HERMES_RESP1			(0x0C)
-#define		HERMES_RESP2			(0x0E)
-#define		HERMES_INFOFID			(0x10)
-#define		HERMES_RXFID			(0x20)
-#define		HERMES_ALLOCFID			(0x22)
-#define		HERMES_TXCOMPLFID		(0x24)
-#define		HERMES_SELECT0			(0x18)
-#define		HERMES_OFFSET0			(0x1C)
-#define		HERMES_DATA0			(0x36)
-#define		HERMES_SELECT1			(0x1A)
-#define		HERMES_OFFSET1			(0x1E)
-#define		HERMES_DATA1			(0x38)
-#define		HERMES_EVSTAT			(0x30)
-#define		HERMES_INTEN			(0x32)
-#define		HERMES_EVACK			(0x34)
-#define		HERMES_CONTROL			(0x14)
-#define		HERMES_SWSUPPORT0		(0x28)
-#define		HERMES_SWSUPPORT1		(0x2A)
-#define		HERMES_SWSUPPORT2		(0x2C)
-#define		HERMES_AUXPAGE			(0x3A)
-#define		HERMES_AUXOFFSET		(0x3C)
-#define		HERMES_AUXDATA			(0x3E)
-
-/*
- * CMD register bitmasks
- */
-#define		HERMES_CMD_BUSY			(0x8000)
-#define		HERMES_CMD_AINFO		(0x7f00)
-#define		HERMES_CMD_MACPORT		(0x0700)
-#define		HERMES_CMD_RECL			(0x0100)
-#define		HERMES_CMD_WRITE		(0x0100)
-#define		HERMES_CMD_PROGMODE		(0x0300)
-#define		HERMES_CMD_CMDCODE		(0x003f)
-
-/*
- * STATUS register bitmasks
- */
-#define		HERMES_STATUS_RESULT		(0x7f00)
-#define		HERMES_STATUS_CMDCODE		(0x003f)
-
-/*
- * OFFSET refister bitmasks
- */
-#define		HERMES_OFFSET_BUSY		(0x8000)
-#define		HERMES_OFFSET_ERR		(0x4000)
-#define		HERMES_OFFSET_DATAOFF		(0x0ffe)
-
-/*
- * Event register bitmasks (INTEN, EVSTAT, EVACK)
- */
-#define		HERMES_EV_TICK			(0x8000)
-#define		HERMES_EV_WTERR			(0x4000)
-#define		HERMES_EV_INFDROP		(0x2000)
-#define		HERMES_EV_INFO			(0x0080)
-#define		HERMES_EV_DTIM			(0x0020)
-#define		HERMES_EV_CMD			(0x0010)
-#define		HERMES_EV_ALLOC			(0x0008)
-#define		HERMES_EV_TXEXC			(0x0004)
-#define		HERMES_EV_TX			(0x0002)
-#define		HERMES_EV_RX			(0x0001)
-
-/*
- * Command codes
- */
-/*--- Controller Commands --------------------------*/
-#define		HERMES_CMD_INIT			(0x0000)
-#define		HERMES_CMD_ENABLE		(0x0001)
-#define		HERMES_CMD_DISABLE		(0x0002)
-#define		HERMES_CMD_DIAG			(0x0003)
-
-/*--- Buffer Mgmt Commands --------------------------*/
-#define		HERMES_CMD_ALLOC		(0x000A)
-#define		HERMES_CMD_TX			(0x000B)
-#define		HERMES_CMD_CLRPRST		(0x0012)
-
-/*--- Regulate Commands --------------------------*/
-#define		HERMES_CMD_NOTIFY		(0x0010)
-#define		HERMES_CMD_INQ			(0x0011)
-
-/*--- Configure Commands --------------------------*/
-#define		HERMES_CMD_ACCESS		(0x0021)
-#define		HERMES_CMD_DOWNLD		(0x0022)
-
-/*--- Debugging Commands -----------------------------*/
-#define 	HERMES_CMD_MONITOR		(0x0038)
-#define		HERMES_MONITOR_ENABLE		(0x000b)
-#define		HERMES_MONITOR_DISABLE		(0x000f)
-
-/*
- * Configuration RIDs
- */
-
-#define		HERMES_RID_CNF_PORTTYPE		(0xfc00)
-#define		HERMES_RID_CNF_MACADDR		(0xfc01)
-#define		HERMES_RID_CNF_DESIRED_SSID	(0xfc02)
-#define		HERMES_RID_CNF_CHANNEL		(0xfc03)
-#define		HERMES_RID_CNF_OWN_SSID		(0xfc04)
-#define		HERMES_RID_CNF_SYSTEM_SCALE	(0xfc06)
-#define		HERMES_RID_CNF_MAX_DATA_LEN	(0xfc07)
-#define		HERMES_RID_CNF_PM_ENABLE	(0xfc09)
-#define		HERMES_RID_CNF_PM_MCAST_RX	(0xfc0b)
-#define		HERMES_RID_CNF_PM_PERIOD	(0xfc0c)
-#define		HERMES_RID_CNF_PM_HOLDOVER	(0xfc0d)
-#define		HERMES_RID_CNF_NICKNAME		(0xfc0e)
-#define		HERMES_RID_CNF_WEP_ON		(0xfc20)
-#define		HERMES_RID_CNF_MWO_ROBUST	(0xfc25)
-#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
-#define		HERMES_RID_CNF_MULTICAST_LIST	(0xfc80)
-#define		HERMES_RID_CNF_CREATEIBSS	(0xfc81)
-#define		HERMES_RID_CNF_FRAG_THRESH	(0xfc82)
-#define		HERMES_RID_CNF_RTS_THRESH	(0xfc83)
-#define		HERMES_RID_CNF_TX_RATE_CTRL	(0xfc84)
-#define		HERMES_RID_CNF_PROMISCUOUS	(0xfc85)
-#define		HERMES_RID_CNF_KEYS		(0xfcb0)
-#define		HERMES_RID_CNF_TX_KEY		(0xfcb1)
-#define		HERMES_RID_CNF_TICKTIME		(0xfce0)
-
-#define		HERMES_RID_CNF_PRISM2_TX_KEY	(0xfc23)
-#define		HERMES_RID_CNF_PRISM2_KEY0	(0xfc24)
-#define		HERMES_RID_CNF_PRISM2_KEY1	(0xfc25)
-#define		HERMES_RID_CNF_PRISM2_KEY2	(0xfc26)
-#define		HERMES_RID_CNF_PRISM2_KEY3	(0xfc27)
-#define		HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID	(0xfc21)
-#define		HERMES_RID_CNF_SYMBOL_AUTH_TYPE		(0xfc2A)
-#define		HERMES_RID_CNF_SYMBOL_BASIC_RATES	(0xfc8A)
-#define		HERMES_RID_CNF_SYMBOL_PREAMBLE		(0xfc8C)
-
-/*
- * Information RIDs
- */
-#define		HERMES_RID_CHANNEL_LIST		(0xfd10)
-#define		HERMES_RID_STAIDENTITY		(0xfd20)
-#define		HERMES_RID_CURRENT_SSID		(0xfd41)
-#define		HERMES_RID_CURRENT_BSSID	(0xfd42)
-#define		HERMES_RID_COMMSQUALITY		(0xfd43)
-#define 	HERMES_RID_CURRENT_TX_RATE	(0xfd44)
-#define 	HERMES_RID_SHORT_RETRY_LIMIT	(0xfd48)
-#define 	HERMES_RID_LONG_RETRY_LIMIT	(0xfd49)
-#define 	HERMES_RID_MAX_TX_LIFETIME	(0xfd4A)
-#define		HERMES_RID_WEP_AVAIL		(0xfd4f)
-#define		HERMES_RID_CURRENT_CHANNEL	(0xfdc1)
-#define		HERMES_RID_DATARATES		(0xfdc6)
-#define		HERMES_RID_SYMBOL_PRIMARY_VER	(0xfd03)
-#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd21)
-#define		HERMES_RID_SYMBOL_KEY_LENGTH	(0xfc2B)
-
-/*
- * Frame structures and constants
- */
-
-typedef struct hermes_frame_desc {
-	/* Hermes - i.e. little-endian byte-order */
-	uint16_t status; /* 0x0 */
-	uint16_t res1, res2; /* 0x2, 0x4 */
-	uint16_t q_info; /* 0x6 */
-	uint16_t res3, res4; /* 0x8, 0xA */
-	uint16_t tx_ctl; /* 0xC */
-} __attribute__ ((packed)) hermes_frame_desc_t;
-
-#define		HERMES_RXSTAT_ERR		(0x0003)
-#define		HERMES_RXSTAT_MACPORT		(0x0700)
-#define		HERMES_RXSTAT_MSGTYPE		(0xE000)
-
-#define		HERMES_RXSTAT_BADCRC		(0x0001)
-#define		HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
-
-/* RFC-1042 encoded frame */
-#define		HERMES_RXSTAT_1042		(0x2000)
-/* Bridge-tunnel encoded frame */
-#define		HERMES_RXSTAT_TUNNEL		(0x4000)
-/* Wavelan-II Management Protocol frame */
-#define		HERMES_RXSTAT_WMP		(0x6000)
-
-#ifdef __KERNEL__
-
-/* Basic control structure */
-typedef struct hermes {
-	uint iobase;
-
-	uint16_t inten; /* Which interrupts should be enabled? */
-} hermes_t;
-
-typedef struct hermes_response {
-	uint16_t status, resp0, resp1, resp2;
-} hermes_response_t;
-
-/* Firmware information structure */
-typedef struct hermes_identity {
-	uint16_t id, vendor, major, minor;
-} __attribute__ ((packed)) hermes_identity_t;
-
-/* "ID" structure - used for ESSID and station nickname */
-typedef struct hermes_id {
-	uint16_t len;
-	uint16_t val[16];
-} __attribute__ ((packed)) hermes_id_t;
-
-typedef struct hermes_commsqual {
-	uint16_t qual, signal, noise;
-} __attribute__ ((packed)) hermes_commsqual_t;
-
-typedef struct hermes_multicast {
-	uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed)) hermes_multicast_t;
-
-/* Register access convenience macros */
-#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off)))
-#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off)))
-
-#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
-#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count)))
-#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count)))
-
-/* Function prototypes */
-void hermes_struct_init(hermes_t *hw, ushort io);
-int hermes_reset(hermes_t *hw);
-int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp);
-int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid);
-
-
-int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
-		       uint16_t id, uint16_t offset);
-int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
-			uint16_t id, uint16_t offset);
-int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
-		    uint16_t *length, void *buf);
-int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid,
-		      uint16_t length, const void *value);
-
-/* Inline functions */
-
-static inline int hermes_present(hermes_t *hw)
-{
-	return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
-}
-
-static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events)
-{
-	hw->inten |= events;
-	hermes_write_regn(hw, INTEN, hw->inten);
-}
-
-static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events)
-{
-	hw->inten = events;
-	hermes_write_regn(hw, INTEN, events);
-}
-
-static inline int hermes_enable_port(hermes_t *hw, int port)
-{
-	hermes_response_t resp;
-
-	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
-				 0, &resp);
-}
-
-static inline int hermes_disable_port(hermes_t *hw, int port)
-{
-	hermes_response_t resp;
-
-	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 
-				 0, &resp);
-}
-
-#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 )
-#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
-
-#define HERMES_READ_RECORD(hw, bap, rid, buf) \
-	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
-	(hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
-
-static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word)
-{
-	uint16_t rec;
-	int err;
-
-	err = HERMES_READ_RECORD(hw, bap, rid, &rec);
-	*word = le16_to_cpu(rec);
-	return err;
-}
-
-static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word)
-{
-	uint16_t rec = cpu_to_le16(word);
-	return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
-}
-
-static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf)
-{
-	int err;
-
-	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf);
-	if (err)
-		return err;
-
-	le16_to_cpus(&buf->id);
-	le16_to_cpus(&buf->vendor);
-	le16_to_cpus(&buf->major);
-	le16_to_cpus(&buf->minor);
-	
-	return 0;
-}
-
-static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf)
-{
-	int err;
-
-	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf);
-	if (err)
-		return err;
-
-	le16_to_cpus(&buf->qual);
-	le16_to_cpus(&buf->signal);
-	le16_to_cpus(&buf->noise);
-	
-	return 0;
-}
-
-#else /* ! __KERNEL__ */
-
-/* These are provided for the benefit of userspace drivers and testing programs
-   which use ioperm() or iopl() */
-
-#define hermes_read_reg(base, off) (inw((base) + (off)))
-#define hermes_write_reg(base, off, val) (outw((val), (base) + (off)))
-
-#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name))
-#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val)))
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count)))
-#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count)))
-
-#endif /* ! __KERNEL__ */
-
-#endif  /* _HERMES_H */
diff -urN linux-2.4.5-pre1/drivers/net/pcmcia/orinoco_cs.c linux/drivers/net/pcmcia/orinoco_cs.c
--- linux-2.4.5-pre1/drivers/net/pcmcia/orinoco_cs.c	Wed Apr 25 14:45:48 2001
+++ linux/drivers/net/pcmcia/orinoco_cs.c	Wed Dec 31 16:00:00 1969
@@ -1,4327 +0,0 @@
-/* orinoco_cs.c 0.04	- (formerly known as dldwd_cs.c)
- *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
- * It should also be usable on various Prism II based cards such as the
- * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
- * cards such as the 3Com AirConnect and Ericsson WLAN.
- *
- * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
- *	With some help from :
- * Copyright (C) 2001 Jean Tourrilhes, HP Labs <jt@hpl.hp.com>
- *
- * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
- *
- * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy@fasta.fh-dortmund.de>
- *      http://www.fasta.fh-dortmund.de/users/andy/wvlan/
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David
- * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
- * Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License version 2 (the "GPL"), 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 MPL, 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 MPL or the GPL.
- */
-
-/* Notes on locking:
- *
- * The basic principle of operation is that everything except the
- * interrupt handler is serialized through a single spinlock in the
- * dldwd_priv_t structure, using dldwd_lock() and
- * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()).
- *
- * The kernel's IRQ handling stuff ensures that the interrupt handler
- * does not re-enter itself. The interrupt handler is written such
- * that everything it does is safe without a lock: chiefly this means
- * that the Rx path uses one of the Hermes chipset's BAPs while
- * everything else uses the other.
- *
- * For the moment access to the device statistics from the interrupt
- * handler is unsafe - we just put up with any resulting errors in the
- * statisics. FIXME: This should probably be changed to store the
- * stats in atomic types.
- *
- * EXCEPT that we don't want the irq handler running when we actually
- * reset or shut down the card, because strange things might happen
- * (probably the worst would be one packet of garbage, but you can't
- * be too careful). For this we use __dldwd_stop_irqs() which will set
- * a flag to disable the interrupt handler, and wait for any
- * outstanding instances of the handler to complete. THIS WILL LOSE
- * INTERRUPTS! so it shouldn't be used except for resets, when we
- * don't care about that.*/
-
-/*
- * Tentative changelog...
- *
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- *	o Allow to use regular ethX device name instead of dldwdX
- *	o Warning on IBSS with ESSID=any for firmware 6.06
- *	o Put proper range.throughput values (optimistic)
- *	o IWSPY support (IOCTL and stat gather in Rx path)
- *	o Allow setting frequency in Ad-Hoc mode
- *	o Disable WEP setting if !has_wep to work on old firmware
- *	o Fix txpower range
- *	o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- *	o Start adding Symbol support - need to check all that
- *	o Fix Prism2/Symbol WEP to accept 128 bits keys
- *	o Add Symbol WEP (add authentication type)
- *	o Add Prism2/Symbol rate
- *	o Add PM timeout (holdover duration)
- *	o Enable "iwconfig eth0 key off" and friends (toggle flags)
- *	o Enable "iwconfig eth0 power unicast/all" (toggle flags)
- *	o Try with an intel card. It report firmware 1.01, behave like
- *	  an antiquated firmware, however on windows it says 2.00. Yuck !
- *	o Workaround firmware bug in allocate buffer (Intel 1.01)
- *	o Finish external renaming to orinoco...
- *	o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- *	o Update to Wireless 11 -> add retry limit/lifetime support
- *	o Tested with a D-Link DWL 650 card, fill in firmware support
- *	o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
- *	o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-(
- *	  It work on D-Link *only* after a tcpdump. Weird...
- *	  And still doesn't work on Intel card. Grrrr...
- *	o Update the mode after a setport3
- *	o Add preamble setting for Symbol cards (not yet enabled)
- *	o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- *      o Removed the 'eth' parameter - always use ethXX as the
- *        interface name instead of dldwdXX.  The other was racy
- *        anyway.
- *	o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- *	o Tim Hurley <timster@seiki.bliztech.com> reported a D-Link card
- *	  with vendor 02 and firmware 0.08. Added in the capabilities...
- *	o Tested Lucent firmware 7.28, everything works...
- *
- * TODO - Jean II
- *	o inline functions (lot's of candidate, need to reorder code)
- *	o Separate Pcmcia specific code to help Airport/Mini PCI driver
- *	o Test PrismII/Symbol cards & firmware versions
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/proc_fs.h>
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-
-#include <pcmcia/version.h>
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-#include <pcmcia/bus_ops.h>
-
-#include "hermes.h"
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-static char *version = "orinoco_cs.c 0.04 (David Gibson <hermes@gibson.dropbear.id.au>)";
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-#define DEBUGMORE(n, args...) do { if (pc_debug>(n)) printk(args); } while (0)
-#else
-#define DEBUG(n, args...) do { } while (0)
-#define DEBUGMORE(n, args...) do { } while (0)
-#endif
-
-#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname);
-#define TRACE_EXIT(devname)  DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname);
-
-#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
-#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
-
-#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
-
-
-#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10)
-#error "orinoco_cs requires Wireless extensions v10 or later."
-#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */
-#define WIRELESS_SPY		// enable iwspy support
-
-/*====================================================================*/
-
-/* Parameters that can be set with 'insmod' */
-
-/* The old way: bit map of interrupts to choose from */
-/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
-static uint irq_mask = 0xdeb8;
-/* Newer, simpler way of listing specific interrupts */
-static int irq_list[4] = { -1 };
-/* Do a Pcmcia soft reset (may help some cards) */
-static int reset_cor = 0;
-
-MODULE_PARM(irq_mask, "i");
-MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(reset_cor, "i");
-
-/*====================================================================*/
-
-#define DLDWD_MIN_MTU		256
-#define DLDWD_MAX_MTU		(HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD)
-
-#define LTV_BUF_SIZE		128
-#define USER_BAP		0
-#define IRQ_BAP			1
-#define DLDWD_MACPORT		0
-#define IRQ_LOOP_MAX		10
-#define TX_NICBUF_SIZE		2048
-#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Intel firmware */
-#define MAX_KEYS		4
-#define MAX_KEY_SIZE		14
-#define LARGE_KEY_SIZE		13
-#define SMALL_KEY_SIZE		5
-#define MAX_FRAME_SIZE		2304
-
-const long channel_frequency[] = {
-	2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-
-#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
-
-/* This tables gives the actual meanings of the bitrate IDs returned by the firmware.
-   It gives the rate in halfMb/s, negative indicates auto mode */
-const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0};
-
-#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0]))
-typedef struct dldwd_key {
-	uint16_t len;
-	char data[MAX_KEY_SIZE];
-} __attribute__ ((packed)) dldwd_key_t;
-
-typedef dldwd_key_t dldwd_keys_t[MAX_KEYS];
-
-typedef struct dldwd_priv {
-	dev_link_t link;
-	dev_node_t node;
-	int instance;
-
-	spinlock_t lock;
-	long state;
-#define DLDWD_STATE_INIRQ 0
-#define DLDWD_STATE_DOIRQ 1
-
-	/* Net device stuff */
-	struct net_device ndev;
-	struct net_device_stats stats;
-	struct iw_statistics wstats;
-
-
-	/* Hardware control variables */
-	hermes_t hw;
-	uint16_t txfid;
-
-	/* Capabilities of the hardware/firmware */
-	hermes_identity_t firmware_info;
-	int firmware_type;
-#define FIRMWARE_TYPE_LUCENT 1
-#define FIRMWARE_TYPE_PRISM2 2
-#define FIRMWARE_TYPE_SYMBOL 3
-	int has_ibss, has_port3, prefer_port3, has_ibss_any;
-	int has_wep, has_big_wep;
-	int has_mwo;
-	int has_pm;
-	int has_retry;
-	int has_preamble;
-	int broken_reset, broken_allocate;
-	uint16_t channel_mask;
-
-	/* Current configuration */
-	uint32_t iw_mode;
-	int port_type, allow_ibss;
-	uint16_t wep_on, wep_restrict, tx_key;
-	dldwd_keys_t keys;
- 	char nick[IW_ESSID_MAX_SIZE+1];
-	char desired_essid[IW_ESSID_MAX_SIZE+1];
-	uint16_t frag_thresh, mwo_robust;
-	uint16_t channel;
-	uint16_t ap_density, rts_thresh;
-	uint16_t tx_rate_ctrl;
-	uint16_t pm_on, pm_mcast, pm_period, pm_timeout;
-	uint16_t retry_short, retry_long, retry_time;
-	uint16_t preamble;
-
-	int promiscuous, allmulti, mc_count;
-
-#ifdef WIRELESS_SPY
-	int			spy_number;
-	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
-	struct iw_quality	spy_stat[IW_MAX_SPY];
-#endif
-
-	/* /proc based debugging stuff */
-	struct proc_dir_entry *dir_dev;
-	struct proc_dir_entry *dir_regs;
-	struct proc_dir_entry *dir_recs;
-} dldwd_priv_t;
-
-struct p80211_hdr {
-	uint16_t frame_ctl;
-	uint16_t duration_id;
-	uint8_t addr1[ETH_ALEN];
-	uint8_t addr2[ETH_ALEN];
-	uint8_t addr3[ETH_ALEN];
-	uint16_t seq_ctl;
-	uint8_t addr4[ETH_ALEN];
-	uint16_t data_len;
-} __attribute__ ((packed));
-
-/* Frame control field constants */
-#define DLDWD_FCTL_VERS			0x0002
-#define DLDWD_FCTL_FTYPE		0x000c
-#define DLDWD_FCTL_STYPE		0x00f0
-#define DLDWD_FCTL_TODS			0x0100
-#define DLDWD_FCTL_FROMDS		0x0200
-#define DLDWD_FCTL_MOREFRAGS		0x0400
-#define DLDWD_FCTL_RETRY		0x0800
-#define DLDWD_FCTL_PM			0x1000
-#define DLDWD_FCTL_MOREDATA		0x2000
-#define DLDWD_FCTL_WEP			0x4000
-#define DLDWD_FCTL_ORDER		0x8000
-
-#define DLDWD_FTYPE_MGMT		0x0000
-#define DLDWD_FTYPE_CTL			0x0004
-#define DLDWD_FTYPE_DATA		0x0008
-
-struct p8022_hdr {
-	uint8_t dsap;
-	uint8_t ssap;
-	uint8_t ctrl;
-	uint8_t oui[3];
-} __attribute__ ((packed));
-
-struct dldwd_frame_hdr {
-	hermes_frame_desc_t desc;
-	struct p80211_hdr p80211;
-	struct ethhdr p8023;
-	struct p8022_hdr p8022;
-	uint16_t ethertype;
-} __attribute__ ((packed));
-
-#define P8023_OFFSET		(sizeof(hermes_frame_desc_t) + \
-				sizeof(struct p80211_hdr))
-#define ENCAPS_OVERHEAD		(sizeof(struct p8022_hdr) + 2)
-
-/*
- * Function prototypes
- */
-
-/* PCMCIA gumpf */
-
-static void dldwd_config(dev_link_t * link);
-static void dldwd_release(u_long arg);
-static int dldwd_event(event_t event, int priority,
-		       event_callback_args_t * args);
-
-static dev_link_t *dldwd_attach(void);
-static void dldwd_detach(dev_link_t *);
-
-/* Hardware control routines */
-
-static int __dldwd_hw_reset(dldwd_priv_t *priv);
-static void dldwd_shutdown(dldwd_priv_t *dev);
-static int dldwd_reset(dldwd_priv_t *dev);
-static int __dldwd_hw_setup_wep(dldwd_priv_t *priv);
-static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]);
-static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);
-static long dldwd_hw_get_freq(dldwd_priv_t *priv);
-static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
-				    int32_t *rates, int max);
-
-/* Interrupt handling routines */
-void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
-static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw);
-static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw);
-
-/* struct net_device methods */
-static int dldwd_init(struct net_device *dev);
-static int dldwd_open(struct net_device *dev);
-static int dldwd_stop(struct net_device *dev);
-
-static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev);
-static void dldwd_tx_timeout(struct net_device *dev);
-
-static struct net_device_stats *dldwd_get_stats(struct net_device *dev);
-static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev);
-static void dldwd_stat_gather(struct net_device *dev,
-			      struct sk_buff *skb,
-			      struct dldwd_frame_hdr *hdr);
-
-static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
-static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
-static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
-static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
-static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
-static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
-static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
-static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
-static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
-static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
-static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
-static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
-static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
-static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-
-static int dldwd_change_mtu(struct net_device *dev, int new_mtu);
-static void __dldwd_set_multicast_list(struct net_device *dev);
-
-/* /proc debugging stuff */
-static int dldwd_proc_init(void);
-static void dldwd_proc_cleanup(void);
-static int dldwd_proc_dev_init(dldwd_priv_t *dev);
-static void dldwd_proc_dev_cleanup(dldwd_priv_t *dev);
-
-/*
- * Inline functions
- */
-static inline void
-dldwd_lock(dldwd_priv_t *priv)
-{
-	spin_lock_bh(&priv->lock);
-}
-
-static inline void
-dldwd_unlock(dldwd_priv_t *priv)
-{
-	spin_unlock_bh(&priv->lock);
-}
-
-static inline int
-dldwd_irqs_allowed(dldwd_priv_t *priv)
-{
-	return test_bit(DLDWD_STATE_DOIRQ, &priv->state);
-}
-
-static inline void
-__dldwd_stop_irqs(dldwd_priv_t *priv)
-{
-	hermes_t *hw = &priv->hw;
-
-	hermes_set_irqmask(hw, 0);
-	clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
-	while (test_bit(DLDWD_STATE_INIRQ, &priv->state))
-		;
-}
-
-static inline void
-__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask)
-{
-	hermes_t *hw = &priv->hw;
-
-	TRACE_ENTER(priv->ndev.name);
-
-	__cli();
-	set_bit(DLDWD_STATE_DOIRQ, &priv->state);
-	hermes_set_irqmask(hw, irqmask);
-	__sti();
-
-	TRACE_EXIT(priv->ndev.name);
-}
-
-static inline void
-set_port_type(dldwd_priv_t *priv)
-{
-	switch (priv->iw_mode) {
-	case IW_MODE_INFRA:
-		priv->port_type = 1;
-		priv->allow_ibss = 0;
-		break;
-	case IW_MODE_ADHOC:
-		if (priv->prefer_port3) {
-			priv->port_type = 3;
-			priv->allow_ibss = 0;
-		} else {
-			priv->port_type = 1;
-			priv->allow_ibss = 1;
-		}
-		break;
-	default:
-		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
-		       priv->ndev.name);
-	}
-}
-
-static inline void
-dldwd_set_multicast_list(struct net_device *dev)
-{
-	dldwd_priv_t *priv = dev->priv;
-
-	dldwd_lock(priv);
-	__dldwd_set_multicast_list(dev);
-	dldwd_unlock(priv);
-}
-
-/*
- * Hardware control routines
- */
-
-static int
-__dldwd_hw_reset(dldwd_priv_t *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err;
-
-	if (! priv->broken_reset)
-		return hermes_reset(hw);
-	else {
-		hw->inten = 0;
-		hermes_write_regn(hw, INTEN, 0);
-		err = hermes_disable_port(hw, 0);
-		hermes_write_regn(hw, EVACK, 0xffff);
-		return err;
-	}
-}
-
-static void
-dldwd_shutdown(dldwd_priv_t *priv)
-{
-/* 	hermes_t *hw = &priv->hw; */
-	int err = 0;
-
-	TRACE_ENTER(priv->ndev.name);
-
-	dldwd_lock(priv);
-	__dldwd_stop_irqs(priv);
-
-	err = __dldwd_hw_reset(priv);
-	if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
-		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err);
-
-	dldwd_unlock(priv);
-
-	TRACE_EXIT(priv->ndev.name);
-}
-
-static int
-dldwd_reset(dldwd_priv_t *priv)
-{
-	struct net_device *dev = &priv->ndev;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	hermes_id_t idbuf;
-	int frame_size;
-
-	TRACE_ENTER(priv->ndev.name);
-
-	dldwd_lock(priv);
-
-	__dldwd_stop_irqs(priv);
-
-	err = __dldwd_hw_reset(priv);
-	if (err)
-		goto out;
-
-	frame_size = TX_NICBUF_SIZE;
-	/* This stupid bug is present in Intel firmware 1.10, and
-	 * may be fixed in later firmwares - Jean II */
-	if(priv->broken_allocate)
-		frame_size = TX_NICBUF_SIZE_BUG;
-	err = hermes_allocate(hw, frame_size, &priv->txfid);
-	if (err)
-		goto out;
-
-	/* Now set up all the parameters on the card */
-	
-	/* Set up the link mode */
-	
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type);
-	if (err)
-		goto out;
-	if (priv->has_ibss) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS,
-					   priv->allow_ibss);
-		if (err)
-			goto out;
-		if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss)
-		   && (!priv->has_ibss_any)) {
-			printk(KERN_WARNING "%s: This firmware requires an \
-ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
-			/* With wvlan_cs, in this case, we would crash.
-			 * hopefully, this driver will behave better...
-			 * Jean II */
-		}
-	}
-
-	/* Set up encryption */
-	if (priv->has_wep) {
-		err = __dldwd_hw_setup_wep(priv);
-		if (err)
-			goto out;
-	}
-
-	/* Set the desired ESSID */
-	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
-	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ?
-			       HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
-			       &idbuf);
-	if (err)
-		goto out;
-
-	/* Set the station name */
-	idbuf.len = cpu_to_le16(strlen(priv->nick));
-	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
-	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
-			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
-			       &idbuf);
-	if (err)
-		goto out;
-
-	/* Set the channel/frequency */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel);
-	if (err)
-		goto out;
-
-	/* Set AP density */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density);
-	if (err)
-		goto out;
-
-	/* Set RTS threshold */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh);
-	if (err)
-		goto out;
-
-	/* Set fragmentation threshold or MWO robustness */
-	if (priv->has_mwo)
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust);
-	else
-		err = hermes_write_wordrec(hw, USER_BAP,
-					   HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh);
-	if (err)
-		goto out;
-
-	/* Set bitrate */
-	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL,
-				   priv->tx_rate_ctrl);
-	if (err)
-		goto out;
-
-	/* Set power management */
-	if (priv->has_pm) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE,
-					   priv->pm_on);
-		if (err)
-			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX,
-					   priv->pm_mcast);
-		if (err)
-			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
-					   priv->pm_period);
-		if (err)
-			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
-					   priv->pm_timeout);
-		if (err)
-			goto out;
-	}
-
-	/* Set retry settings - will fail on lot's of firmwares */
-	if (priv->has_retry) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT,
-					   priv->retry_short);
-		if (err) {
-			printk(KERN_WARNING "%s: Can't set retry limit!\n", dev->name);
-			goto out;
-		}
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT,
-					   priv->retry_long);
-		if (err)
-			goto out;
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME,
-					   priv->retry_time);
-		if (err)
-			goto out;
-	}
-
-	/* Set preamble - only for Symbol so far... */
-	if (priv->has_preamble) {
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE,
-					   priv->preamble);
-		if (err) {
-			printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
-			goto out;
-		}
-	}
-
-	/* Set promiscuity / multicast*/
-	priv->promiscuous = 0;
-	priv->allmulti = 0;
-	priv->mc_count = 0;
-	__dldwd_set_multicast_list(dev);
-	
-	err = hermes_enable_port(hw, DLDWD_MACPORT);
-	if (err)
-		goto out;
-	
-	__dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
-			   HERMES_EV_TX | HERMES_EV_TXEXC |
-			   HERMES_EV_WTERR | HERMES_EV_INFO |
-			   HERMES_EV_INFDROP);
-
- out:
-	dldwd_unlock(priv);
-
-	TRACE_EXIT(priv->ndev.name);
-
-	return err;
-}
-
-static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int	extra_wep_flag = 0;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */
-		if (priv->wep_on) {
-			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key);
-			if (err)
-				return err;
-			
-			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys);
-			if (err)
-				return err;
-		}
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on);
-		if (err)
-			return err;
-		break;
-
-	case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
-		if (priv->wep_on) {
-			char keybuf[LARGE_KEY_SIZE+1];
-			int keylen;
-			int i;
-			
-			/* Write all 4 keys */
-			for(i = 0; i < MAX_KEYS; i++) {
-				keylen = priv->keys[i].len;
-				keybuf[keylen] = '\0';
-				memcpy(keybuf, priv->keys[i].data, keylen);
-				err = hermes_write_ltv(hw, USER_BAP,
-						       HERMES_RID_CNF_PRISM2_KEY0 + i,
-						       HERMES_BYTES_TO_RECLEN(keylen + 1),
-						       &keybuf);
-				if (err)
-					return err;
-			}
-
-			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
-						   priv->tx_key);
-			if (err)
-				return err;
-
-			/* Authentication is where Prism2 and Symbol
-			 * firmware differ... */
-			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
-				/* Symbol cards : set the authentication :
-				 * 0 -> no encryption, 1 -> open,
-				 * 2 -> shared key, 3 -> shared key 128bit */
-				if(priv->wep_restrict) {
-					if(priv->keys[priv->tx_key].len >
-					   SMALL_KEY_SIZE)
-						extra_wep_flag = 3;
-					else
-						extra_wep_flag = 2;
-				} else
-					extra_wep_flag = 1;
-				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict);
-				if (err)
-					return err;
-			} else {
-				/* Prism2 card : we need to modify master
-				 * WEP setting */
-				if(priv->wep_restrict)
-					extra_wep_flag = 2;
-				else
-					extra_wep_flag = 0;
-			}
-		}
-		
-		/* Master WEP setting : on/off */
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag));
-		if (err)
-			return err;	
-		break;
-
-	default:
-		if (priv->wep_on) {
-			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
-			       priv->ndev.name);
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
-static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN])
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-
-	dldwd_lock(priv);
-
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID,
-			      ETH_ALEN, NULL, buf);
-
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active,
-			      char buf[IW_ESSID_MAX_SIZE+1])
-{
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	hermes_id_t essidbuf;
-	char *p = (char *)(&essidbuf.val);
-	int len;
-
-	TRACE_ENTER(priv->ndev.name);
-
-	dldwd_lock(priv);
-
-	if (strlen(priv->desired_essid) > 0) {
-		/* We read the desired SSID from the hardware rather
-		   than from priv->desired_essid, just in case the
-		   firmware is allowed to change it on us. I'm not
-		   sure about this */
-		/* My guess is that the OWN_SSID should always be whatever
-		 * we set to the card, whereas CURRENT_SSID is the one that
-		 * may change... - Jean II */
-		uint16_t rid;
-
-		*active = 1;
-
-		rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID :
-			HERMES_RID_CNF_DESIRED_SSID;
-		
-		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
-				      NULL, &essidbuf);
-		if (err)
-			goto fail_unlock;
-	} else {
-		*active = 0;
-
-		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID,
-				      sizeof(essidbuf), NULL, &essidbuf);
-		if (err)
-			goto fail_unlock;
-	}
-
-	len = le16_to_cpu(essidbuf.len);
-
-	memset(buf, 0, sizeof(buf));
-	memcpy(buf, p, len);
-	buf[len] = '\0';
-
- fail_unlock:
-	dldwd_unlock(priv);
-
-	TRACE_EXIT(priv->ndev.name);
-
-	return err;       
-}
-
-static long dldwd_hw_get_freq(dldwd_priv_t *priv)
-{
-	
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t channel;
-	long freq = 0;
-
-	dldwd_lock(priv);
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel);
-	if (err)
-		goto out;
-
-	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
-		struct net_device *dev = &priv->ndev;
-
-		printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
-		err = -EBUSY;
-		goto out;
-
-	}
-	freq = channel_frequency[channel-1] * 100000;
-
- out:
-	dldwd_unlock(priv);
-
-	if (err > 0)
-		err = -EBUSY;
-	return err ? err : freq;
-}
-
-static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
-				    int32_t *rates, int max)
-{
-	hermes_t *hw = &priv->hw;
-	hermes_id_t list;
-	unsigned char *p = (unsigned char *)&list.val;
-	int err = 0;
-	int num;
-	int i;
-
-	dldwd_lock(priv);
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list),
-			      NULL, &list);
-	dldwd_unlock(priv);
-
-	if (err)
-		return err;
-	
-	num = le16_to_cpu(list.len);
-	*numrates = num;
-	num = MIN(num, max);
-
-	for (i = 0; i < num; i++) {
-		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
-	}
-
-	return 0;
-}
-
-#ifndef PCMCIA_DEBUG
-static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {}
-#else
-static void show_rx_frame(struct dldwd_frame_hdr *frame)
-{
-	printk(KERN_DEBUG "RX descriptor:\n");
-	printk(KERN_DEBUG "  status      = 0x%04x\n", frame->desc.status);
-	printk(KERN_DEBUG "  res1        = 0x%04x\n", frame->desc.res1);
-	printk(KERN_DEBUG "  res2        = 0x%04x\n", frame->desc.res2);
-	printk(KERN_DEBUG "  q_info      = 0x%04x\n", frame->desc.q_info);
-	printk(KERN_DEBUG "  res3        = 0x%04x\n", frame->desc.res3);
-	printk(KERN_DEBUG "  res4        = 0x%04x\n", frame->desc.res4);
-	printk(KERN_DEBUG "  tx_ctl      = 0x%04x\n", frame->desc.tx_ctl);
-
-	printk(KERN_DEBUG "IEEE 802.11 header:\n");
-	printk(KERN_DEBUG "  frame_ctl   = 0x%04x\n",
-	       frame->p80211.frame_ctl);
-	printk(KERN_DEBUG "  duration_id = 0x%04x\n",
-	       frame->p80211.duration_id);
-	printk(KERN_DEBUG "  addr1       = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p80211.addr1[0], frame->p80211.addr1[1],
-	       frame->p80211.addr1[2], frame->p80211.addr1[3],
-	       frame->p80211.addr1[4], frame->p80211.addr1[5]);
-	printk(KERN_DEBUG "  addr2       = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p80211.addr2[0], frame->p80211.addr2[1],
-	       frame->p80211.addr2[2], frame->p80211.addr2[3],
-	       frame->p80211.addr2[4], frame->p80211.addr2[5]);
-	printk(KERN_DEBUG "  addr3       = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p80211.addr3[0], frame->p80211.addr3[1],
-	       frame->p80211.addr3[2], frame->p80211.addr3[3],
-	       frame->p80211.addr3[4], frame->p80211.addr3[5]);
-	printk(KERN_DEBUG "  seq_ctl     = 0x%04x\n",
-	       frame->p80211.seq_ctl);
-	printk(KERN_DEBUG "  addr4       = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p80211.addr4[0], frame->p80211.addr4[1],
-	       frame->p80211.addr4[2], frame->p80211.addr4[3],
-	       frame->p80211.addr4[4], frame->p80211.addr4[5]);
-	printk(KERN_DEBUG "  data_len    = 0x%04x\n",
-	       frame->p80211.data_len);
-
-	printk(KERN_DEBUG "IEEE 802.3 header:\n");
-	printk(KERN_DEBUG "  dest        = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p8023.h_dest[0], frame->p8023.h_dest[1],
-	       frame->p8023.h_dest[2], frame->p8023.h_dest[3],
-	       frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
-	printk(KERN_DEBUG "  src         = %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       frame->p8023.h_source[0], frame->p8023.h_source[1],
-	       frame->p8023.h_source[2], frame->p8023.h_source[3],
-	       frame->p8023.h_source[4], frame->p8023.h_source[5]);
-	printk(KERN_DEBUG "  len         = 0x%04x\n", frame->p8023.h_proto);
-
-	printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
-	printk(KERN_DEBUG "  DSAP        = 0x%02x\n", frame->p8022.dsap);
-	printk(KERN_DEBUG "  SSAP        = 0x%02x\n", frame->p8022.ssap);
-	printk(KERN_DEBUG "  ctrl        = 0x%02x\n", frame->p8022.ctrl);
-	printk(KERN_DEBUG "  OUI         = %02x:%02x:%02x\n",
-	       frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
-	printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
-}
-#endif
-
-/*
- * Interrupt handler
- */
-void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *) dev_id;
-	hermes_t *hw = &priv->hw;
-	struct net_device *dev = &priv->ndev;
-	int count = IRQ_LOOP_MAX;
-	uint16_t evstat, events;
-	static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */
-
-	if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state))
-		BUG();
-
-	if (! dldwd_irqs_allowed(priv)) {
-		clear_bit(DLDWD_STATE_INIRQ, &priv->state);
-		return;
-	}
-
-	DEBUG(3, "%s: dldwd_interrupt()  irq %d\n", priv->ndev.name, irq);
-
-	while (1) {
-		if (jiffies != old_time)
-			timecount = 0;
-		if ( (++timecount > 50) || (! count--) ) {
-			printk(KERN_CRIT "%s: IRQ handler is looping too \
-much! Shutting down.\n",
-			       dev->name);
-			/* Perform an emergency shutdown */
-			clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
-			hermes_set_irqmask(hw, 0);
-			break;
-		}
-
-		evstat = hermes_read_regn(hw, EVSTAT);
-		DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n",
-		      count, evstat, hw->inten);
-
-		events = evstat & hw->inten;
-
-		if (! events) {
-			if (netif_queue_stopped(dev)) {
-				/* There seems to be a firmware bug which
-				   sometimes causes the card to give an
-				   interrupt with no event set, when there
-				   sould be a Tx completed event. */
-				DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n",
-				      dev->name, (int)hermes_read_regn(hw, ALLOCFID));
-				events = HERMES_EV_TX | HERMES_EV_ALLOC;
-			} else /* Nothing's happening, we're done */
-				break;
-		}
-
-		/* Check the card hasn't been removed */
-		if (! hermes_present(hw)) {
-			DEBUG(0, "dldwd_interrupt(): card removed\n");
-			break;
-		}
-
-		if (events & HERMES_EV_TICK)
-			__dldwd_ev_tick(priv, hw);
-		if (events & HERMES_EV_WTERR)
-			__dldwd_ev_wterr(priv, hw);
-		if (events & HERMES_EV_INFDROP)
-			__dldwd_ev_infdrop(priv, hw);
-		if (events & HERMES_EV_INFO)
-			__dldwd_ev_info(priv, hw);
-		if (events & HERMES_EV_RX)
-			__dldwd_ev_rx(priv, hw);
-		if (events & HERMES_EV_TXEXC)
-			__dldwd_ev_txexc(priv, hw);
-		if (events & HERMES_EV_TX)
-			__dldwd_ev_tx(priv, hw);
-		if (events & HERMES_EV_ALLOC)
-			__dldwd_ev_alloc(priv, hw);
-		
-		hermes_write_regn(hw, EVACK, events);
-	}
-
-	clear_bit(DLDWD_STATE_INIRQ, &priv->state);
-}
-
-static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw)
-{
-	printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name);
-}
-
-static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw)
-{
-	/* This seems to happen a fair bit under load, but ignoring it
-	   seems to work fine...*/
-	DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n",
-	      priv->ndev.name);
-}
-
-static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw)
-{
-	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name);
-}
-
-static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw)
-{
-	DEBUG(3, "%s: Information frame received.\n", priv->ndev.name);
-	/* We don't actually do anything about it - we assume the MAC
-	   controller can deal with it */
-}
-
-static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
-{
-	struct net_device *dev = &priv->ndev;
-	struct net_device_stats *stats = &priv->stats;
-	struct iw_statistics *wstats = &priv->wstats;
-	struct sk_buff *skb = NULL;
-	uint16_t rxfid, status;
-	int length, data_len, data_off;
-	char *p;
-	struct dldwd_frame_hdr hdr;
-	struct ethhdr *eh;
-	int err;
-
-	rxfid = hermes_read_regn(hw, RXFID);
-	DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid);
-
-	/* We read in the entire frame header here. This isn't really
-	   necessary, since we ignore most of it, but it's
-	   conceptually simpler. We can tune this later if
-	   necessary. */
-	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0);
-	if (err) {
-		printk(KERN_ERR "%s: error %d reading frame header. "
-		       "Frame dropped.\n", dev->name, err);
-		stats->rx_errors++;
-		goto drop;
-	}
-
-	status = le16_to_cpu(hdr.desc.status);
-	
-	if (status & HERMES_RXSTAT_ERR) {
-		if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) {
-			stats->rx_crc_errors++;
-			printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n",
-			       dev->name);
-			show_rx_frame(&hdr);
-		} else if ((status & HERMES_RXSTAT_ERR)
-			   == HERMES_RXSTAT_UNDECRYPTABLE) {
-			wstats->discard.code++;
-			printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n",
-			       dev->name);
-		} else {
-			wstats->discard.misc++;
-			printk("%s: Unknown Rx error (0x%x). Frame dropped.\n",
-			       dev->name, status & HERMES_RXSTAT_ERR);
-		}
-		stats->rx_errors++;
-		goto drop;
-	}
-
-	length = le16_to_cpu(hdr.p80211.data_len);
-	/* Yes, you heard right, that's le16. 802.2 and 802.3 are
-	   big-endian, but 802.11 is little-endian believe it or
-	   not. */
-	/* Correct. 802.3 is big-endian byte order and little endian bit
-	 * order, whereas 802.11 is little endian for both byte and bit
-	 * order. That's specified in the 802.11 spec. - Jean II */
-	
-	/* Sanity check */
-	if (length > MAX_FRAME_SIZE) {
-		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
-		       dev->name, length);
-		stats->rx_length_errors++;
-		stats->rx_errors++;
-		goto drop;
-	}
-
-	/* We need space for the packet data itself, plus an ethernet
-	   header, plus 2 bytes so we can align the IP header on a
-	   32bit boundary, plus 1 byte so we can read in odd length
-	   packets from the card, which has an IO granularity of 16
-	   bits */  
-	skb = dev_alloc_skb(length+ETH_HLEN+2+1);
-	if (!skb) {
-		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
-		       dev->name);
-		stats->rx_dropped++;
-		goto drop;
-	}
-
-	skb_reserve(skb, 2); /* This way the IP header is aligned */
-
-	/* Handle decapsulation */
-	switch (status & HERMES_RXSTAT_MSGTYPE) {
-		/* These both indicate a SNAP within 802.2 LLC within
-		   802.3 within 802.11 frame which we'll need to
-		   de-encapsulate. IEEE and ISO OSI have a lot to
-		   answer for.  */
-	case HERMES_RXSTAT_1042:
-	case HERMES_RXSTAT_TUNNEL:
-		data_len = length - ENCAPS_OVERHEAD;
-		data_off = sizeof(hdr);
-
-		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
-
-		memcpy(eh, &hdr.p8023, sizeof(hdr.p8023));
-		eh->h_proto = hdr.ethertype;
-
-		break;
-
-		/* Otherwise, we just throw the whole thing in, and hope
-		   the protocol layer can deal with it as 802.3 */
-	default:
-		data_len = length;
-		data_off = P8023_OFFSET;
-		break;
-	}
-
-	p = skb_put(skb, data_len);
-	if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
-			     rxfid, data_off) != 0) {
-		printk(KERN_WARNING "%s: Error reading packet data\n",
-		       dev->name);
-		stats->rx_errors++;
-		goto drop;
-	}
-
-	dev->last_rx = jiffies;
-	skb->dev = dev;
-	skb->protocol = eth_type_trans(skb, dev);
-	skb->ip_summed = CHECKSUM_NONE;
-	
-	/* Process the wireless stats if needed */
-	dldwd_stat_gather(dev, skb, &hdr);
-
-	/* Pass the packet to the networking stack */
-	netif_rx(skb);
-	stats->rx_packets++;
-	stats->rx_bytes += length;
-
-	return;
-
- drop:	
-	if (skb)
-		dev_kfree_skb_irq(skb);
-	return;
-}
-
-static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw)
-{
-	struct net_device *dev = &priv->ndev;
-	struct net_device_stats *stats = &priv->stats;
-
-	printk(KERN_WARNING "%s: Tx error!\n", dev->name);
-
-	netif_wake_queue(dev);
-	stats->tx_errors++;
-}
-
-static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw)
-{
-	struct net_device *dev = &priv->ndev;
-	struct net_device_stats *stats = &priv->stats;
-
-	DEBUG(3, "%s: Transmit completed\n", dev->name);
-
-	stats->tx_packets++;
-	netif_wake_queue(dev);
-}
-
-static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw)
-{
-	uint16_t allocfid;
-
-	allocfid = hermes_read_regn(hw, ALLOCFID);
-	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid);
-
-	/* For some reason we don't seem to get transmit completed events properly */
-	if (allocfid == priv->txfid)
-		__dldwd_ev_tx(priv, hw);
-
-/* 	hermes_write_regn(hw, ALLOCFID, 0); */
-}
-
-/*
- * struct net_device methods
- */
-
-static int dldwd_init(struct net_device *dev)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	hermes_id_t nickbuf;
-	uint16_t reclen;
-	int len;
-	char *vendor_str;
-	uint32_t firmver;
-
-	TRACE_ENTER("dldwd");
-	
-	dldwd_lock(priv);
-
-	err = hermes_reset(hw);
-	if (err != 0) {
-		printk(KERN_ERR "%s: failed to reset hardware\n", dev->name);
-		goto out;
-	}
-	
-	/* Get the firmware version */
-	err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info);
-	if (err) {
-		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
-		       dev->name, err);
-		memset(&priv->firmware_info, 0, sizeof(priv->firmware_info));
-	}
-
-	firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor;
-	DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver);
-
-	/* Determine capabilities from the firmware version */
-
-	switch (priv->firmware_info.vendor) {
-	case 0x1:
-		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
-		 * ELSA, Melco, HP, IBM, Dell 1150 cards */
-		vendor_str = "Lucent";
-		/* Lucent MAC : 00:60:1D:* & 00:02:2D:* */
-
-		priv->firmware_type = FIRMWARE_TYPE_LUCENT;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;		/* Still works in 7.28 */
-		priv->has_ibss = (firmver >= 0x60006);
-		priv->has_ibss_any = (firmver >= 0x60010);
-		priv->has_wep = (firmver >= 0x40020);
-		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
-					  Gold cards from the others? */
-		priv->has_mwo = (firmver >= 0x60000);
-		priv->has_pm = (firmver >= 0x40020);
-		priv->has_retry = 0;
-		priv->has_preamble = 0;
-		/* Tested with Lucent firmware :
-		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
-		 * Tested CableTron firmware : 4.32 => Anton */
-		break;
-	case 0x2:
-		vendor_str = "Generic Prism II";
-		/* Some D-Link cards report vendor 0x02... */
-
-		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
-		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-		priv->has_wep = (firmver >= 0x00007); /* FIXME */
-		priv->has_big_wep = 0;
-		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x00007); /* FIXME */
-		priv->has_retry = 0;
-		priv->has_preamble = 0;
-
-		/* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */
-
-		/* Special case for Symbol cards */
-		if(firmver == 0x10001) {
-			/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
-			vendor_str = "Symbol";
-			/* Intel MAC : 00:02:B3:* */
-			/* 3Com MAC : 00:50:DA:* */
-
-			/* FIXME : probably need to use SYMBOL_***ARY_VER
-			 * to get proper firmware version */
-			priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
-			priv->broken_reset = 0;
-			priv->broken_allocate = 1;
-			priv->has_port3 = 1;
-			priv->has_ibss = 1; /* FIXME */
-			priv->has_wep = 1; /* FIXME */
-			priv->has_big_wep = 1;	/* RID_SYMBOL_KEY_LENGTH */
-			priv->has_mwo = 0;
-			priv->has_pm = 1; /* FIXME */
-			priv->has_retry = 0;
-			priv->has_preamble = 0; /* FIXME */
-			/* Tested with Intel firmware : v15 => Jean II */
-		}
-		break;
-	case 0x3:
-		vendor_str = "Samsung";
-		/* To check - Should cover Samsung & Compaq */
-
-		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
-		priv->has_ibss = 0; /* FIXME: available in later firmwares */
-		priv->has_wep = (firmver >= 0x20000); /* FIXME */
-		priv->has_big_wep = 0; /* FIXME */
-		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x20000); /* FIXME */
-		priv->has_retry = 0;
-		priv->has_preamble = 0;
-		break;
-	case 0x6:
-		/* D-Link DWL 650, ... */
-		vendor_str = "LinkSys/D-Link";
-		/* D-Link MAC : 00:40:05:* */
-
-		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 1;
-		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
-		priv->has_wep = (firmver >= 0x00007); /* FIXME */
-		priv->has_big_wep = 0;
-		priv->has_mwo = 0;
-		priv->has_pm = (firmver >= 0x00007); /* FIXME */
-		priv->has_retry = 0;
-		priv->has_preamble = 0;
-		/* Tested with D-Link firmware 0.07 => Jean II */
-		/* Note : with 0.07, IBSS to a Lucent card seem flaky */
-		break;
-	default:
-		vendor_str = "UNKNOWN";
-
-		priv->firmware_type = 0;
-		priv->broken_reset = 0;
-		priv->broken_allocate = 0;
-		priv->has_port3 = 0;
-		priv->has_ibss = 0;
-		priv->has_wep = 0;
-		priv->has_big_wep = 0;
-		priv->has_mwo = 0;
-		priv->has_pm = 0;
-		priv->has_retry = 0;
-		priv->has_preamble = 0;
-	}
-
-	printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
-	       dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
-	       vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
-	
-	if (priv->has_port3)
-		printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name);
-	if (priv->has_ibss)
-		printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n",
-		       dev->name);
-	if (priv->has_wep) {
-		printk(KERN_INFO "%s: WEP supported, ", dev->name);
-		if (priv->has_big_wep)
-			printk("\"128\"-bit key.\n");
-		else
-			printk("40-bit key.\n");
-	}
-
-	/* Get the MAC address */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR,
-			      ETH_ALEN, NULL, dev->dev_addr);
-	if (err) {
-		printk(KERN_WARNING "%s: failed to read MAC address!\n",
-		       dev->name);
-		goto out;
-	}
-
-	printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
-	       dev->name, dev->dev_addr[0], dev->dev_addr[1],
-	       dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
-	       dev->dev_addr[5]);
-
-	/* Get the station name */
-	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
-			      sizeof(nickbuf), &reclen, &nickbuf);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read station name!n",
-		       dev->name);
-		goto out;
-	}
-	if ( nickbuf.len )
-		len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
-	else
-		len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen);
-	memcpy(priv->nick, &nickbuf.val, len);
-	priv->nick[len] = '\0';
-
-	printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
-	/* Get allowed channels */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read channel list!\n",
-		       dev->name);
-		goto out;
-	}
-
-	/* Get initial AP density */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read AP density!\n", dev->name);
-		goto out;
-	}
-
-	/* Get initial RTS threshold */
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name);
-		goto out;
-	}
-
-	/* Get initial fragmentation settings */
-	if (priv->has_mwo)
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST,
-					  &priv->mwo_robust);
-	else
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH,
-					  &priv->frag_thresh);
-	if (err) {
-		printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name);
-		goto out;
-	}
-
-	/* Set initial bitrate control*/
-	priv->tx_rate_ctrl = 3;
-
-	/* Power management setup */
-	if (priv->has_pm) {
-		priv->pm_on = 0;
-		priv->pm_mcast = 1;
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
-					  &priv->pm_period);
-		if (err) {
-			printk(KERN_ERR "%s: failed to read power management period!\n",
-			       dev->name);
-			goto out;
-		}
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
-					  &priv->pm_timeout);
-		if (err) {
-			printk(KERN_ERR "%s: failed to read power management timeout!\n",
-			       dev->name);
-			goto out;
-		}
-	}
-
-	/* Retry setup */
-	if (priv->has_retry) {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &priv->retry_short);
-		if (err)
-			goto out;
-
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &priv->retry_long);
-		if (err)
-			goto out;
-
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &priv->retry_time);
-		if (err)
-			goto out;
-	}
-		
-	/* Preamble setup */
-	if (priv->has_preamble) {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble);
-		if (err)
-			goto out;
-	}
-		
-	/* Set up the default configuration */
-	priv->iw_mode = IW_MODE_INFRA;
-	/* By default use IEEE/IBSS ad-hoc mode if we have it */
-	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
-	set_port_type(priv);
-
-	priv->promiscuous = 0;
-	priv->allmulti = 0;
-	priv->wep_on = 0;
-	priv->tx_key = 0;
-
-	printk(KERN_INFO "%s: ready\n", dev->name);
-
- out:
-	dldwd_unlock(priv);
-
-	TRACE_EXIT("dldwd");
-
-	return err;
-}
-
-static int dldwd_open(struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	dev_link_t *link = &priv->link;
-	int err = 0;
-	
-	TRACE_ENTER(dev->name);
-
-	link->open++;
-	MOD_INC_USE_COUNT;
-	netif_device_attach(dev);
-	
-	err = dldwd_reset(priv);
-	if (err)
-		dldwd_stop(dev);
-	else
-		netif_start_queue(dev);
-
-	TRACE_EXIT(dev->name);
-
-	return err;
-}
-
-static int dldwd_stop(struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	dev_link_t *link = &priv->link;
-
-	TRACE_ENTER(dev->name);
-
-	netif_stop_queue(dev);
-
-	dldwd_shutdown(priv);
-	
-	link->open--;
-
-	if (link->state & DEV_STALE_CONFIG)
-		mod_timer(&link->release, jiffies + HZ/20);
-	
-	MOD_DEC_USE_COUNT;
-
-	TRACE_EXIT(dev->name);
-	
-	return 0;
-}
-
-static struct net_device_stats *dldwd_get_stats(struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	
-	return &priv->stats;
-}
-
-static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	hermes_t *hw = &priv->hw;
-	struct iw_statistics *wstats = &priv->wstats;
-	int err = 0;
-	hermes_commsqual_t cq;
-
-	dldwd_lock(priv);
-
-	if (priv->port_type == 3) {
-		memset(&wstats->qual, 0, sizeof(wstats->qual));
-#ifdef WIRELESS_SPY
-		/* If a spy address is defined, we report stats of the
-		 * first spy address - Jean II */
-		if (priv->spy_number > 0) {
-			wstats->qual.qual = priv->spy_stat[0].qual;
-			wstats->qual.level = priv->spy_stat[0].level;
-			wstats->qual.noise = priv->spy_stat[0].noise;
-			wstats->qual.updated = priv->spy_stat[0].updated;
-		}
-#endif /* WIRELESS_SPY */
-	} else {
-		err = hermes_read_commsqual(hw, USER_BAP, &cq);
-		
-		DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
-		      cq.qual, cq.signal, cq.noise);
-
-		/* Why are we using MIN/MAX ? We don't really care
-		 * if the value goes above max, because we export the
-		 * raw dBm values anyway. The normalisation should be done
-		 * in user space - Jean II */
-		wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0);
-		wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95;
-		wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95;
-		wstats->qual.updated = 7;
-	}
-
-	dldwd_unlock(priv);
-
-	if (err)
-		return NULL;
-		
-	return wstats;
-}
-
-#ifdef WIRELESS_SPY
-static inline void dldwd_spy_gather(struct net_device *dev,
-				    u_char *mac,
-				    hermes_commsqual_t *cq)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	int i;
-
-	/* Gather wireless spy statistics: for each packet, compare the
-	 * source address with out list, and if match, get the stats... */
-	for (i = 0; i < priv->spy_number; i++)
-		if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
-			priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0);
-			priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95;
-			priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95;
-			priv->spy_stat[i].updated = 7;
-		}
-}
-#endif /* WIRELESS_SPY */
-
-static void dldwd_stat_gather(struct net_device *dev,
-			      struct sk_buff *skb,
-			      struct dldwd_frame_hdr *hdr)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	hermes_commsqual_t cq;
-
-	/* Using spy support with lots of Rx packets, like in an
-	 * infrastructure (AP), will really slow down everything, because
-	 * the MAC address must be compared to each entry of the spy list.
-	 * If the user really asks for it (set some address in the
-	 * spy list), we do it, but he will pay the price.
-	 * Note that to get here, you need both WIRELESS_SPY
-	 * compiled in AND some addresses in the list !!!
-	 */
-#ifdef WIRELESS_EXT
-	/* Note : gcc will optimise the whole section away if
-	 * WIRELESS_SPY is not defined... - Jean II */
-	if (
-#ifdef WIRELESS_SPY
-		(priv->spy_number > 0) ||
-#endif
-		0 )
-	{
-		u_char *stats = (u_char *) &(hdr->desc.q_info);
-		/* This code may look strange. Everywhere we are using 16 bit
-		 * ints except here. I've verified that these are are the
-		 * correct values. Please check on PPC - Jean II */
-		cq.signal = stats[1];	/* High order byte */
-		cq.noise = stats[0];	/* Low order byte */
-		cq.qual = stats[0] - stats[1];	/* Better than nothing */
-
-		DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name,
-		      cq.qual, cq.signal, cq.noise);
-
-#ifdef WIRELESS_SPY
-		dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq);  
-#endif
-	}
-#endif /* WIRELESS_EXT */
-}
-
-struct p8022_hdr encaps_hdr = {
-	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
-};
-
-static int dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	struct net_device_stats *stats = &priv->stats;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t txfid = priv->txfid;
-	char *p;
-	struct ethhdr *eh;
-	int len, data_len, data_off;
-	struct dldwd_frame_hdr hdr;
-	hermes_response_t resp;
-
-	if (! netif_running(dev)) {
-		printk(KERN_ERR "%s: Tx on stopped device!\n",
-		       dev->name);
-		return 1;
-
-	}
-	
-	if (netif_queue_stopped(dev)) {
-		printk(KERN_ERR "%s: Tx while transmitter busy!\n", 
-		       dev->name);
-		return 1;
-	}
-	
-	dldwd_lock(priv);
-
-	/* Length of the packet body */
-	len = MAX(skb->len - ETH_HLEN, ETH_ZLEN);
-
-	eh = (struct ethhdr *)skb->data;
-
-	/* Build the IEEE 802.11 header */
-	memset(&hdr, 0, sizeof(hdr));
-	memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN);
-	memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN);
-	hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA;
-
-	/* Encapsulate Ethernet-II frames */
-	if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
-		data_len = len;
-		data_off = sizeof(hdr);
-		p = skb->data + ETH_HLEN;
-
-		/* 802.11 header */
-		hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD);
-
-		/* 802.3 header */
-		memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN);
-		memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN);
-		hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD);
-		
-		/* 802.2 header */
-		memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr));
-
-		hdr.ethertype = eh->h_proto;
-		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
-					 txfid, 0);
-		if (err) {
-			printk(KERN_ERR
-			       "%s: Error %d writing packet header to BAP\n",
-			       dev->name, err);
-			stats->tx_errors++;
-			goto fail;
-		}
-	} else { /* IEEE 802.3 frame */
-		data_len = len + ETH_HLEN;
-		data_off = P8023_OFFSET;
-		p = skb->data;
-		
-		/* 802.11 header */
-		hdr.p80211.data_len = cpu_to_le16(len);
-		err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET,
-					txfid, 0);
-		if (err) {
-			printk(KERN_ERR
-			       "%s: Error %d writing packet header to BAP\n",
-			       dev->name, err);
-			stats->tx_errors++;
-			goto fail;
-		}
-	}
-
-	/* Round up for odd length packets */
-	err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d writing packet data to BAP\n",
-		       dev->name, err);
-		stats->tx_errors++;
-		goto fail;
-	}
-	
-
-	/* Finally, we actually initiate the send */
-	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp);
-	if (err) {
-		printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
-		stats->tx_errors++;
-		goto fail;
-	}
-
-	dev->trans_start = jiffies;
-	stats->tx_bytes += data_off + data_len;
-
-	netif_stop_queue(dev);
-
-	dldwd_unlock(priv);
-
-	dev_kfree_skb(skb);
-
-	return 0;
- fail:
-
-	dldwd_unlock(priv);
-	return err;
-}
-
-static void dldwd_tx_timeout(struct net_device *dev)
-{
-	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
-	struct net_device_stats *stats = &priv->stats;
-	int err = 0;
-
-	printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name);
-
-	stats->tx_errors++;
-
-	err = dldwd_reset(priv);
-	if (err)
-		printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
-		       dev->name, err);
-	else {
-		dev->trans_start = jiffies;
-		netif_wake_queue(dev);
-	}
-}
-
-static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int err = 0;
-	int ptype;
-	struct iw_range range;
-	int numrates;
-	int i, k;
-
-	TRACE_ENTER(dev->name);
-
-	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
-	if (err)
-		return err;
-
-	rrq->length = sizeof(range);
-
-	dldwd_lock(priv);
-	ptype = priv->port_type;
-	dldwd_unlock(priv);
-
-	memset(&range, 0, sizeof(range));
-
-	/* Much of this shamelessly taken from wvlan_cs.c. No idea
-	 * what it all means -dgibson */
-#if WIRELESS_EXT > 10
-	range.we_version_compiled = WIRELESS_EXT;
-	range.we_version_source = 11;
-#endif /* WIRELESS_EXT > 10 */
-
-	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
-
-	/* Set available channels/frequencies */
-	range.num_channels = NUM_CHANNELS;
-	k = 0;
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		if (priv->channel_mask & (1 << i)) {
-			range.freq[k].i = i + 1;
-			range.freq[k].m = channel_frequency[i] * 100000;
-			range.freq[k].e = 1;
-			k++;
-		}
-		
-		if (k >= IW_MAX_FREQUENCIES)
-			break;
-	}
-	range.num_frequency = k;
-
-	range.sensitivity = 3;
-
-	if ((ptype == 3) && (priv->spy_number == 0)){
-		/* Quality stats meaningless in ad-hoc mode */
-		range.max_qual.qual = 0;
-		range.max_qual.level = 0;
-		range.max_qual.noise = 0;
-	} else {
-		range.max_qual.qual = 0x8b - 0x2f;
-		range.max_qual.level = 0x2f - 0x95 - 1;
-		range.max_qual.noise = 0x2f - 0x95 - 1;
-	}
-
-	err = dldwd_hw_get_bitratelist(priv, &numrates,
-				       range.bitrate, IW_MAX_BITRATES);
-	if (err)
-		return err;
-	range.num_bitrates = numrates;
-	
-	/* Set an indication of the max TCP throughput in bit/s that we can
-	 * expect using this interface. May be use for QoS stuff...
-	 * Jean II */
-	if(numrates > 2)
-		range.throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
-	else
-		range.throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
-
-	range.min_rts = 0;
-	range.max_rts = 2347;
-	range.min_frag = 256;
-	range.max_frag = 2346;
-
-	dldwd_lock(priv);
-	if (priv->has_wep) {
-		range.max_encoding_tokens = MAX_KEYS;
-
-		range.encoding_size[0] = SMALL_KEY_SIZE;
-		range.num_encoding_sizes = 1;
-
-		if (priv->has_big_wep) {
-			range.encoding_size[1] = LARGE_KEY_SIZE;
-			range.num_encoding_sizes = 2;
-		}
-	} else {
-		range.num_encoding_sizes = 0;
-		range.max_encoding_tokens = 0;
-	}
-	dldwd_unlock(priv);
-		
-	range.min_pmp = 0;
-	range.max_pmp = 65535000;
-	range.min_pmt = 0;
-	range.max_pmt = 65535 * 1000;	/* ??? */
-	range.pmp_flags = IW_POWER_PERIOD;
-	range.pmt_flags = IW_POWER_TIMEOUT;
-	range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
-	range.num_txpower = 1;
-	range.txpower[0] = 15; /* 15dBm */
-	range.txpower_capa = IW_TXPOW_DBM;
-
-#if WIRELESS_EXT > 10
-	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
-	range.retry_flags = IW_RETRY_LIMIT;
-	range.r_time_flags = IW_RETRY_LIFETIME;
-	range.min_retry = 0;
-	range.max_retry = 65535;	/* ??? */
-	range.min_r_time = 0;
-	range.max_r_time = 65535 * 1000;	/* ??? */
-#endif /* WIRELESS_EXT > 10 */
-
-	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
-		return -EFAULT;
-
-	TRACE_EXIT(dev->name);
-
-	return 0;
-}
-
-static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	int setindex = priv->tx_key;
-	int enable = priv->wep_on;
-	int restricted = priv->wep_restrict;
-	uint16_t xlen = 0;
-	int err = 0;
-	char keybuf[MAX_KEY_SIZE];
-
-	if (erq->pointer) {
-		/* We actually have a key to set */
-		
-		if (copy_from_user(keybuf, erq->pointer, erq->length))
-			return -EFAULT;
-	}
-	
-	dldwd_lock(priv);
-	
-	if (erq->pointer) {
-		if (erq->length > MAX_KEY_SIZE) {
-			err = -E2BIG;
-			goto out;
-		}
-		
-		if ( (erq->length > LARGE_KEY_SIZE)
-		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
-			err = -EINVAL;
-			goto out;
-		}
-		
-		if ((index < 0) || (index >= MAX_KEYS))
-			index = priv->tx_key;
-		
-		if (erq->length > SMALL_KEY_SIZE) {
-			xlen = LARGE_KEY_SIZE;
-		} else if (erq->length > 0) {
-			xlen = SMALL_KEY_SIZE;
-		} else
-			xlen = 0;
-		
-		/* Switch on WEP if off */
-		if ((!enable) && (xlen > 0)) {
-			setindex = index;
-			enable = 1;
-		}
-	} else {
-		/* Important note : if the user do "iwconfig eth0 enc off",
-		 * we will arrive there with an index of -1. This is valid
-		 * but need to be taken care off... Jean II */
-		if ((index < 0) || (index >= MAX_KEYS)) {
-			if((index != -1) || (erq->flags == 0)) {
-				err = -EINVAL;
-				goto out;
-			}
-		} else {
-			/* Set the index : Check that the key is valid */
-			if(priv->keys[index].len == 0) {
-				err = -EINVAL;
-				goto out;
-			}
-			setindex = index;
-		}
-	}
-	
-	if (erq->flags & IW_ENCODE_DISABLED)
-		enable = 0;
-	/* Only for Prism2 & Symbol cards (so far) - Jean II */
-	if (erq->flags & IW_ENCODE_OPEN)
-		restricted = 0;
-	if (erq->flags & IW_ENCODE_RESTRICTED)
-		restricted = 1;
-
-	if (erq->pointer) {
-		priv->keys[index].len = cpu_to_le16(xlen);
-		memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data));
-		memcpy(priv->keys[index].data, keybuf, erq->length);
-	}
-	priv->tx_key = setindex;
-	priv->wep_on = enable;
-	priv->wep_restrict = restricted;
-	
- out:
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
-	uint16_t xlen = 0;
-	char keybuf[MAX_KEY_SIZE];
-
-	
-	dldwd_lock(priv);
-
-	if ((index < 0) || (index >= MAX_KEYS))
-		index = priv->tx_key;
-
-	erq->flags = 0;
-	if (! priv->wep_on)
-		erq->flags |= IW_ENCODE_DISABLED;
-	erq->flags |= index + 1;
-	
-	/* Only for symbol cards - Jean II */
-	if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) {
-		if(priv->wep_restrict)
-			erq->flags |= IW_ENCODE_RESTRICTED;
-		else
-			erq->flags |= IW_ENCODE_OPEN;
-	}
-
-	xlen = le16_to_cpu(priv->keys[index].len);
-
-	erq->length = xlen;
-
-	if (erq->pointer) {
-		memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE);
-	}
-	
-	dldwd_unlock(priv);
-
-	if (erq->pointer) {
-		if (copy_to_user(erq->pointer, keybuf, xlen))
-			return -EFAULT;
-	}
-
-	return 0;
-}
-
-static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-
-	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
-	 * anyway... - Jean II */
-
-	memset(&essidbuf, 0, sizeof(essidbuf));
-
-	if (erq->flags) { 
-		if (erq->length > IW_ESSID_MAX_SIZE)
-			return -E2BIG;
-		
-		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
-			return -EFAULT;
-
-		essidbuf[erq->length] = '\0';
-	}
-
-	dldwd_lock(priv);
-
-	memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1);
-
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-	int active;
-	int err = 0;
-
-	TRACE_ENTER(dev->name);
-
-	err = dldwd_hw_get_essid(priv, &active, essidbuf);
-	if (err)
-		return err;
-
-	erq->flags = 1;
-	erq->length = strlen(essidbuf) + 1;
-	if (erq->pointer)
-		if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
-			return -EFAULT;
-
-	TRACE_EXIT(dev->name);
-	
-	return 0;
-}
-
-static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
-
-	if (nrq->length > IW_ESSID_MAX_SIZE)
-		return -E2BIG;
-
-	memset(nickbuf, 0, sizeof(nickbuf));
-
-	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
-		return -EFAULT;
-
-	nickbuf[nrq->length] = '\0';
-	
-	dldwd_lock(priv);
-
-	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
-
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	char nickbuf[IW_ESSID_MAX_SIZE+1];
-
-	dldwd_lock(priv);
-	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
-	dldwd_unlock(priv);
-
-	nrq->length = strlen(nickbuf)+1;
-
-	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int chan = -1;
-
-	/* We can only use this in Ad-Hoc demo mode to set the operating
-	 * frequency, or in IBSS mode to set the frequency where the IBSS
-	 * will be created - Jean II */
-	if (priv->iw_mode != IW_MODE_ADHOC)
-		return -EOPNOTSUPP;
-
-	if ( (frq->e == 0) && (frq->m <= 1000) ) {
-		/* Setting by channel number */
-		chan = frq->m;
-	} else {
-		/* Setting by frequency - search the table */
-		int mult = 1;
-		int i;
-
-		for (i = 0; i < (6 - frq->e); i++)
-			mult *= 10;
-
-		for (i = 0; i < NUM_CHANNELS; i++)
-			if (frq->m == (channel_frequency[i] * mult))
-				chan = i+1;
-	}
-
-	if ( (chan < 1) || (chan > NUM_CHANNELS) ||
-	     ! (priv->channel_mask & (1 << (chan-1)) ) )
-		return -EINVAL;
-
-	dldwd_lock(priv);
-	priv->channel = chan;
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	uint16_t val;
-	int err;
-
-	dldwd_lock(priv);
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val);
-	dldwd_unlock(priv);
-
-	if (err)
-		return err;
-
-	srq->value = val;
-	srq->fixed = 0; /* auto */
-
-	return 0;
-}
-
-static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int val = srq->value;
-
-	if ((val < 1) || (val > 3))
-		return -EINVAL;
-	
-	dldwd_lock(priv);
-	priv->ap_density = val;
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int val = rrq->value;
-
-	if (rrq->disabled)
-		val = 2347;
-
-	if ( (val < 0) || (val > 2347) )
-		return -EINVAL;
-
-	dldwd_lock(priv);
-	priv->rts_thresh = val;
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int err = 0;
-
-	dldwd_lock(priv);
-
-	if (priv->has_mwo) {
-		if (frq->disabled)
-			priv->mwo_robust = 0;
-		else {
-			if (frq->fixed)
-				printk(KERN_WARNING "%s: Fixed fragmentation not \
-supported on this firmware. Using MWO robust instead.\n", dev->name);
-			priv->mwo_robust = 1;
-		}
-	} else {
-		if (frq->disabled)
-			priv->frag_thresh = 2346;
-		else {
-			if ( (frq->value < 256) || (frq->value > 2346) )
-				err = -EINVAL;
-			else
-				priv->frag_thresh = frq->value & ~0x1; /* must be even */
-		}
-	}
-
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t val;
-
-	dldwd_lock(priv);
-	
-	if (priv->has_mwo) {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val);
-		if (err)
-			val = 0;
-
-		frq->value = val ? 2347 : 0;
-		frq->disabled = ! val;
-		frq->fixed = 0;
-	} else {
-		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val);
-		if (err)
-			val = 0;
-
-		frq->value = val;
-		frq->disabled = (val >= 2346);
-		frq->fixed = 1;
-	}
-
-	dldwd_unlock(priv);
-	
-	return err;
-}
-
-static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int err = 0;
-	int rate_ctrl = -1;
-	int fixed, upto;
-	int brate;
-	int i;
-
-	dldwd_lock(priv);
-
-	/* Normalise value */
-	brate = rrq->value / 500000;
-
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
-		if (! rrq->fixed) {
-			if (brate > 0)
-				brate = -brate;
-			else
-				brate = -22;
-		}
-	
-		for (i = 0; i < NUM_RATES; i++)
-			if (rate_list[i] == brate) {
-				rate_ctrl = i;
-				break;
-			}
-	
-		if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) )
-			err = -EINVAL;
-		else
-			priv->tx_rate_ctrl = rate_ctrl;
-		break;
-	case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-		switch(brate) {
-		case 0:
-			fixed = 0x0;
-			upto = 0x15;
-			break;
-		case 2:
-			fixed = 0x1;
-			upto = 0x1;
-			break;
-		case 4:
-			fixed = 0x2;
-			upto = 0x3;
-			break;
-		case 11:
-			fixed = 0x4;
-			upto = 0x7;
-			break;
-		case 22:
-			fixed = 0x8;
-			upto = 0x15;
-			break;
-		default:
-			fixed = 0x0;
-			upto = 0x0;
-		}
-		if (rrq->fixed)
-			rate_ctrl = fixed;
-		else
-			rate_ctrl = upto;
-		if (rate_ctrl == 0)
-			err = -EINVAL;
-		else
-			priv->tx_rate_ctrl = rate_ctrl;
-		break;
-	}
-
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t val;
-	int brate = 0;
-
-	dldwd_lock(priv);
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val);
-	if (err)
-		goto out;
-	
-	switch (priv->firmware_type) {
-	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
-		brate = rate_list[val];
-	
-		if (brate < 0) {
-			rrq->fixed = 0;
-
-			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
-			if (err)
-				goto out;
-
-			if (val == 6)
-				brate = 11;
-			else
-				brate = 2*val;
-		} else
-			rrq->fixed = 1;
-		break;
-	case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
-	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
-		/* Check if auto or fixed (crude approximation) */
-		if((val & 0x1) && (val > 1)) {
-			rrq->fixed = 0;
-
-			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
-			if (err)
-				goto out;
-		} else
-			rrq->fixed = 1;
-
-		if(val >= 8)
-			brate = 22;
-		else if(val >= 4)
-			brate = 11;
-		else if(val >= 2)
-			brate = 4;
-		else
-			brate = 2;
-		break;
-	}
-
-	rrq->value = brate * 500000;
-	rrq->disabled = 0;
-
- out:
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int err = 0;
-
-
-	dldwd_lock(priv);
-
-	if (prq->disabled) {
-		priv->pm_on = 0;
-	} else {
-		switch (prq->flags & IW_POWER_MODE) {
-		case IW_POWER_UNICAST_R:
-			priv->pm_mcast = 0;
-			priv->pm_on = 1;
-			break;
-		case IW_POWER_ALL_R:
-			priv->pm_mcast = 1;
-			priv->pm_on = 1;
-			break;
-		case IW_POWER_ON:
-			/* No flags : but we may have a value - Jean II */
-			break;
-		default:
-			err = -EINVAL;
-		}
-		if (err)
-			goto out;
-		
-		if (prq->flags & IW_POWER_TIMEOUT) {
-			priv->pm_on = 1;
-			priv->pm_timeout = prq->value / 1000;
-		}
-		if (prq->flags & IW_POWER_PERIOD) {
-			priv->pm_on = 1;
-			priv->pm_period = prq->value / 1000;
-		}
-		/* It's valid to not have a value if we are just toggling
-		 * the flags... Jean II */
-		if(!priv->pm_on) {
-			err = -EINVAL;
-			goto out;
-		}			
-	}
-
- out:
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t enable, period, timeout, mcast;
-
-	dldwd_lock(priv);
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast);
-	if (err)
-		goto out;
-
-	prq->disabled = !enable;
-	/* Note : by default, display the period */
-	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
-		prq->flags = IW_POWER_TIMEOUT;
-		prq->value = timeout * 1000;
-	} else {
-		prq->flags = IW_POWER_PERIOD;
-		prq->value = period * 1000;
-	}
-	if (mcast)
-		prq->flags |= IW_POWER_ALL_R;
-	else
-		prq->flags |= IW_POWER_UNICAST_R;
-
- out:
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-#if WIRELESS_EXT > 10
-static int dldwd_ioctl_setretry(struct net_device *dev, struct iw_param *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int err = 0;
-
-
-	dldwd_lock(priv);
-
-	if ((rrq->disabled) || (!priv->has_retry)){
-		err = -EOPNOTSUPP;
-		goto out;
-	} else {
-		if (rrq->flags & IW_RETRY_LIMIT) {
-			if (rrq->flags & IW_RETRY_MAX)
-				priv->retry_long = rrq->value;
-			else if (rrq->flags & IW_RETRY_MIN)
-				priv->retry_short = rrq->value;
-			else {
-				/* No modifier : set both */
-				priv->retry_long = rrq->value;
-				priv->retry_short = rrq->value;
-			}
-		}
-		if (rrq->flags & IW_RETRY_LIFETIME) {
-			priv->retry_time = rrq->value / 1000;
-		}
-		if ((rrq->flags & IW_RETRY_TYPE) == 0) {
-			err = -EINVAL;
-			goto out;
-		}			
-	}
-
- out:
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	uint16_t short_limit, long_limit, lifetime;
-
-	dldwd_lock(priv);
-	
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit);
-	if (err)
-		goto out;
-
-	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime);
-	if (err)
-		goto out;
-
-	rrq->disabled = 0;		/* Can't be disabled */
-
-	/* Note : by default, display the retry number */
-	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
-		rrq->flags = IW_RETRY_LIFETIME;
-		rrq->value = lifetime * 1000;	/* ??? */
-	} else {
-		/* By default, display the min number */
-		if ((rrq->flags & IW_RETRY_MAX)) {
-			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
-			rrq->value = long_limit;
-		} else {
-			rrq->flags = IW_RETRY_LIMIT;
-			rrq->value = short_limit;
-			if(short_limit != long_limit)
-				rrq->flags |= IW_RETRY_MIN;
-		}
-	}
-
- out:
-	dldwd_unlock(priv);
-
-	return err;
-}
-#endif /* WIRELESS_EXT > 10 */
-
-static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int val = *( (int *) wrq->u.name );
-	int err = 0;
-
-	dldwd_lock(priv);
-	switch (val) {
-	case 0: /* Try to do IEEE ad-hoc mode */
-		if (! priv->has_ibss) {
-			err = -EINVAL;
-			break;
-		}
-		priv->prefer_port3 = 0;
-			
-		break;
-
-	case 1: /* Try to do Lucent proprietary ad-hoc mode */
-		if (! priv->has_port3) {
-			err = -EINVAL;
-			break;
-		}
-		priv->prefer_port3 = 1;
-		break;
-
-	default:
-		err = -EINVAL;
-	}
-
-	if (! err)
-		/* Actually update the mode we are using */
-		set_port_type(priv);
-
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	int *val = (int *)wrq->u.name;
-
-	dldwd_lock(priv);
-	*val = priv->prefer_port3;
-	dldwd_unlock(priv);
-
-	return 0;
-}
-
-/* Spy is used for link quality/strength measurements in Ad-Hoc mode
- * Jean II */
-static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	struct sockaddr address[IW_MAX_SPY];
-	int number = srq->length;
-	int i;
-	int err = 0;
-
-	/* Check the number of addresses */
-	if (number > IW_MAX_SPY)
-		return -E2BIG;
-
-	/* Get the data in the driver */
-	if (srq->pointer) {
-		if (copy_from_user(address, srq->pointer,
-				   sizeof(struct sockaddr) * number))
-			return -EFAULT;
-	}
-
-	/* Make sure nobody mess with the structure while we do */
-	dldwd_lock(priv);
-
-	/* dldwd_lock() doesn't disable interrupts, so make sure the
-	 * interrupt rx path don't get confused while we copy */
-	priv->spy_number = 0;
-
-	if (number > 0) {
-		/* Extract the addresses */
-		for (i = 0; i < number; i++)
-			memcpy(priv->spy_address[i], address[i].sa_data,
-			       ETH_ALEN);
-		/* Reset stats */
-		memset(priv->spy_stat, 0,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-		/* Set number of addresses */
-		priv->spy_number = number;
-	}
-
-	/* Time to show what we have done... */
-	DEBUG(0, "%s: New spy list:\n", dev->name);
-	for (i = 0; i < number; i++) {
-		DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n",
-		      dev->name, i+1,
-		      priv->spy_address[i][0], priv->spy_address[i][1],
-		      priv->spy_address[i][2], priv->spy_address[i][3],
-		      priv->spy_address[i][4], priv->spy_address[i][5]);
-	}
-
-	/* Now, let the others play */
-	dldwd_unlock(priv);
-
-	return err;
-}
-
-static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
-{
-	dldwd_priv_t *priv = dev->priv;
-	struct sockaddr address[IW_MAX_SPY];
-	struct iw_quality spy_stat[IW_MAX_SPY];
-	int number;
-	int i;
-
-	dldwd_lock(priv);
-
-	number = priv->spy_number;
-	if ((number > 0) && (srq->pointer)) {
-		/* Create address struct */
-		for (i = 0; i < number; i++) {
-			memcpy(address[i].sa_data, priv->spy_address[i],
-			       ETH_ALEN);
-			address[i].sa_family = AF_UNIX;
-		}
-		/* Copy stats */
-		/* In theory, we should disable irqs while copying the stats
-		 * because the rx path migh update it in the middle...
-		 * Bah, who care ? - Jean II */
-		memcpy(&spy_stat, priv->spy_stat,
-		       sizeof(struct iw_quality) * IW_MAX_SPY);
-		for (i=0; i < number; i++)
-			priv->spy_stat[i].updated = 0;
-	}
-
-	dldwd_unlock(priv);
-
-	/* Push stuff to user space */
-	srq->length = number;
-	if(copy_to_user(srq->pointer, address,
-			 sizeof(struct sockaddr) * number))
-		return -EFAULT;
-	if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
-			&spy_stat, sizeof(struct iw_quality) * number))
-		return -EFAULT;
-
-	return 0;
-}
-
-static int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	dldwd_priv_t *priv = dev->priv;
-	struct iwreq *wrq = (struct iwreq *)rq;
-	int err = 0;
-	int changed = 0;
-
-	TRACE_ENTER(dev->name);
-
-	switch (cmd) {
-	case SIOCGIWNAME:
-		DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
-		strcpy(wrq->u.name, "IEEE 802.11-DS");
-		break;
-		
-	case SIOCGIWAP:
-		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
-		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
-		err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
-		break;
-
-	case SIOCGIWRANGE:
-		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
-		err = dldwd_ioctl_getiwrange(dev, &wrq->u.data);
-		break;
-
-	case SIOCSIWMODE:
-		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
-		dldwd_lock(priv);
-		switch (wrq->u.mode) {
-		case IW_MODE_ADHOC:
-			if (! (priv->has_ibss || priv->has_port3) )
-				err = -EINVAL;
-			else {
-				priv->iw_mode = IW_MODE_ADHOC;
-				changed = 1;
-			}
-			break;
-
-		case IW_MODE_INFRA:
-			priv->iw_mode = IW_MODE_INFRA;
-			changed = 1;
-			break;
-
-		default:
-			err = -EINVAL;
-			break;
-		}
-		set_port_type(priv);
-		dldwd_unlock(priv);
-		break;
-
-	case SIOCGIWMODE:
-		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
-		dldwd_lock(priv);
-		wrq->u.mode = priv->iw_mode;
-		dldwd_unlock(priv);
-		break;
-
-	case SIOCSIWENCODE:
-		DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
-
-		err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWENCODE:
-		DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
-		if (! priv->has_wep) {
-			err = -EOPNOTSUPP;
-			break;
-		}
-
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding);
-		break;
-
-	case SIOCSIWESSID:
-		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
-		err = dldwd_ioctl_setessid(dev, &wrq->u.essid);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWESSID:
-		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
-		err = dldwd_ioctl_getessid(dev, &wrq->u.essid);
-		break;
-
-	case SIOCSIWNICKN:
-		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
-		err = dldwd_ioctl_setnick(dev, &wrq->u.data);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWNICKN:
-		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
-		err = dldwd_ioctl_getnick(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWFREQ:
-		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
-		wrq->u.freq.m = dldwd_hw_get_freq(priv);
-		wrq->u.freq.e = 1;
-		break;
-
-	case SIOCSIWFREQ:
-		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
-		err = dldwd_ioctl_setfreq(dev, &wrq->u.freq);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWSENS:
-		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
-		err = dldwd_ioctl_getsens(dev, &wrq->u.sens);
-		break;
-
-	case SIOCSIWSENS:
-		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
-		err = dldwd_ioctl_setsens(dev, &wrq->u.sens);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWRTS:
-		DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
-		wrq->u.rts.value = priv->rts_thresh;
-		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
-		wrq->u.rts.fixed = 1;
-		break;
-
-	case SIOCSIWRTS:
-		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
-		err = dldwd_ioctl_setrts(dev, &wrq->u.rts);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCSIWFRAG:
-		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
-		err = dldwd_ioctl_setfrag(dev, &wrq->u.frag);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWFRAG:
-		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
-		err = dldwd_ioctl_getfrag(dev, &wrq->u.frag);
-		break;
-
-	case SIOCSIWRATE:
-		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
-		err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWRATE:
-		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
-		err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate);
-		break;
-
-	case SIOCSIWPOWER:
-		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
-		err = dldwd_ioctl_setpower(dev, &wrq->u.power);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWPOWER:
-		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
-		err = dldwd_ioctl_getpower(dev, &wrq->u.power);
-		break;
-
-	case SIOCGIWTXPOW:
-		DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
-		/* The card only supports one tx power, so this is easy */
-		wrq->u.txpower.value = 15; /* dBm */
-		wrq->u.txpower.fixed = 1;
-		wrq->u.txpower.disabled = 0;
-		wrq->u.txpower.flags = IW_TXPOW_DBM;
-		break;
-
-#if WIRELESS_EXT > 10
-	case SIOCSIWRETRY:
-		DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name);
-		err = dldwd_ioctl_setretry(dev, &wrq->u.retry);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCGIWRETRY:
-		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
-		err = dldwd_ioctl_getretry(dev, &wrq->u.retry);
-		break;
-#endif /* WIRELESS_EXT > 10 */
-
-	case SIOCSIWSPY:
-		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
-
-		err = dldwd_ioctl_setspy(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWSPY:
-		DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
-
-		err = dldwd_ioctl_getspy(dev, &wrq->u.data);
-		break;
-
-	case SIOCGIWPRIV:
-		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
-		if (wrq->u.data.pointer) {
-			struct iw_priv_args privtab[] = {
-				{ SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" },
-				{ SIOCDEVPRIVATE + 0x2,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_port3" },
-				{ SIOCDEVPRIVATE + 0x3, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_port3" },
-				{ SIOCDEVPRIVATE + 0x4,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  0, "set_preamble" },
-				{ SIOCDEVPRIVATE + 0x5, 0,
-				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
-				  "get_preamble" }
-			};
-
-			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
-			if (err)
-				break;
-			
-			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
-			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
-				err = -EFAULT;
-		}
-		break;
-	       
-	case SIOCDEVPRIVATE + 0x0: /* force_reset */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-		
-		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-		dldwd_reset(priv);
-		break;
-
-	case SIOCDEVPRIVATE + 0x2: /* set_port3 */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		err = dldwd_ioctl_setport3(dev, wrq);
-		if (! err)
-			changed = 1;
-		break;
-
-	case SIOCDEVPRIVATE + 0x3: /* get_port3 */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n",
-		      dev->name);
-		err = dldwd_ioctl_getport3(dev, wrq);
-		break;
-
-	case SIOCDEVPRIVATE + 0x4: /* set_preamble */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n",
-		      dev->name);
-		if (! capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		/* 802.11b has recently defined some short preamble.
-		 * Basically, the Phy header has been reduced in size.
-		 * This increase performance, especially at high rates
-		 * (the preamble is transmitted at 1Mb/s), unfortunately
-		 * this give compatibility troubles... - Jean II */
-		if(priv->has_preamble) {
-			int val = *( (int *) wrq->u.name );
-
-			dldwd_lock(priv);
-			if(val)
-				priv->preamble = 1;
-			else
-				priv->preamble = 0;
-			dldwd_unlock(priv);
-			changed = 1;
-		} else
-			err = -EOPNOTSUPP;
-		break;
-
-	case SIOCDEVPRIVATE + 0x5: /* get_preamble */
-		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n",
-		      dev->name);
-		if(priv->has_preamble) {
-			int *val = (int *)wrq->u.name;
-
-			dldwd_lock(priv);
-			*val = priv->preamble;
-			dldwd_unlock(priv);
-		} else
-			err = -EOPNOTSUPP;
-		break;
-
-	default:
-		err = -EOPNOTSUPP;
-	}
-	
-	if (! err && changed && netif_running(dev)) {
-		err = dldwd_reset(priv);
-		if (err)
-			dldwd_stop(dev);
-	}		
-
-	TRACE_EXIT(dev->name);
-		
-	return err;
-}
-
-static int dldwd_change_mtu(struct net_device *dev, int new_mtu)
-{
-	TRACE_ENTER(dev->name);
-
-	if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) )
-		return -EINVAL;
-
-	dev->mtu = new_mtu;
-
-	TRACE_EXIT(dev->name);
-
-	return 0;
-}
-
-static void __dldwd_set_multicast_list(struct net_device *dev)
-{
-	dldwd_priv_t *priv = dev->priv;
-	hermes_t *hw = &priv->hw;
-	int err = 0;
-	int promisc, allmulti, mc_count;
-
-	TRACE_ENTER(dev->name);
-
-	DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n",
-	      dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count);
-
-	/* The Hermes doesn't seem to have an allmulti mode, so we go
-	 * into promiscuous mode and let the upper levels deal. */
-	if ( (dev->flags & IFF_PROMISC) ) {
-		promisc = 1;
-		allmulti = 0;
-		mc_count = 0;
-	} else if ( (dev->flags & IFF_ALLMULTI) ||
-		    (dev->mc_count > HERMES_MAX_MULTICAST) ) {
-		promisc = 0;
-		allmulti = 1;
-		mc_count = HERMES_MAX_MULTICAST;
-	} else {
-		promisc = 0;
-		allmulti = 0;
-		mc_count = dev->mc_count;
-	}
-
-	DEBUG(3, "promisc=%d mc_count=%d\n",
-	      promisc, mc_count);
-
-	if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */
-		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS,
-					   promisc);
-		if (err) {
-			printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n",
-			       dev->name, err, promisc);
-		} else 
-			priv->promiscuous = promisc;
-	}
-
-	if (allmulti) {
-		/* FIXME: This method of doing allmulticast reception
-		   comes from the NetBSD driver. Haven't actually
-		   tested whether it works or not. */
-		hermes_multicast_t mclist;
-
-		memset(&mclist, 0, sizeof(mclist));
-		err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist);
-		if (err)
-			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-			       dev->name, err);
-		else
-			priv->allmulti = 1;
-		       
-	} else if (mc_count || (! mc_count && priv->mc_count) ) {
-		struct dev_mc_list *p = dev->mc_list;
-		hermes_multicast_t mclist;
-		int i;
-
-		for (i = 0; i < mc_count; i++) {
-			/* First some paranoid checks */
-			if (! p) {
-				printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n",
-				       dev->name);
-				break;
-			}
-			if (p->dmi_addrlen != ETH_ALEN) {
-
-				printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n",
-				       dev->name, p->dmi_addrlen);
-				break;
-			}
-
-			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
-			p = p->next;
-		}
-
-		/* More paranoia */
-		if (p)
-			printk(KERN_ERR "%s: Multicast list longer than mc_count.\n",
-			       dev->name);
-
-		priv->mc_count = i;			
-
-		DEBUG(3, "priv->mc_count = %d\n", priv->mc_count);
-
-		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST,
-				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
-				       &mclist);
-		if (err)
-			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
-			       dev->name, err);
-		else
-			priv->allmulti = 0;
-	}
-
-	/* Since we can set the promiscuous flag when it wasn't asked
-	   for, make sure the net_device knows about it. */
-	if (priv->promiscuous)
-		dev->flags |= IFF_PROMISC;
-	else
-		dev->flags &= ~IFF_PROMISC;
-
-	if (priv->allmulti)
-		dev->flags |= IFF_ALLMULTI;
-	else
-		dev->flags &= ~IFF_ALLMULTI;
-
-	TRACE_EXIT(dev->name);
-}
-
-/*
- * procfs stuff
- */
-
-static struct proc_dir_entry *dir_base = NULL;
-
-/*
- * This function updates the total amount of data printed so far. It then
- * determines if the amount of data printed into a buffer  has reached the
- * offset requested. If it hasn't, then the buffer is shifted over so that
- * the next bit of data can be printed over the old bit. If the total
- * amount printed so far exceeds the total amount requested, then this
- * function returns 1, otherwise 0.
- */
-static int 
-
-shift_buffer(char *buffer, int requested_offset, int requested_len,
-	     int *total, int *slop, char **buf)
-{
-	int printed;
-	
-	printed = *buf - buffer;
-	if (*total + printed <= requested_offset) {
-		*total += printed;
-		*buf = buffer;
-	}
-	else {
-		if (*total < requested_offset) {
-			*slop = requested_offset - *total;
-		}
-		*total = requested_offset + printed - *slop;
-	}
-	if (*total > requested_offset + requested_len) {
-		return 1;
-	}
-	else {
-		return 0;
-	}
-}
-
-/*
- * This function calculates the actual start of the requested data
- * in the buffer. It also calculates actual length of data returned,
- * which could be less that the amount of data requested.
- */
-#define PROC_BUFFER_SIZE 4096
-#define PROC_SAFE_SIZE 3072
-
-static int
-calc_start_len(char *buffer, char **start, int requested_offset,
-	       int requested_len, int total, char *buf)
-{
-	int return_len, buffer_len;
-	
-	buffer_len = buf - buffer;
-	if (buffer_len >= PROC_BUFFER_SIZE - 1) {
-		printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
-	}
-	
-	/*
-	 * There may be bytes before and after the
-	 * chunk that was actually requested.
-	 */
-	return_len = total - requested_offset;
-	if (return_len < 0) {
-		return_len = 0;
-	}
-	*start = buf - return_len;
-	if (return_len > requested_len) {
-		return_len = requested_len;
-	}
-	return return_len;
-}
-
-static int
-dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset,
-			   int requested_len, int *eof, void *data)
-{
-	dldwd_priv_t *dev = (dldwd_priv_t *)data;
-	hermes_t *hw = &dev->hw;
-	char *buf;
-	int total = 0, slop = 0;
-
-	buf = page;
-
-#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name))
-
-	DHERMESREG(CMD);
-	DHERMESREG(PARAM0);
-	DHERMESREG(PARAM1);
-	DHERMESREG(PARAM2);
-	DHERMESREG(STATUS);
-	DHERMESREG(RESP0);
-	DHERMESREG(RESP1);
-	DHERMESREG(RESP2);
-	DHERMESREG(INFOFID);
-	DHERMESREG(RXFID);
-	DHERMESREG(ALLOCFID);
-	DHERMESREG(TXCOMPLFID);
-	DHERMESREG(SELECT0);
-	DHERMESREG(OFFSET0);
-	DHERMESREG(SELECT1);
-	DHERMESREG(OFFSET1);
-	DHERMESREG(EVSTAT);
-	DHERMESREG(INTEN);
-	DHERMESREG(EVACK);
-	DHERMESREG(CONTROL);
-	DHERMESREG(SWSUPPORT0);
-	DHERMESREG(SWSUPPORT1);
-	DHERMESREG(SWSUPPORT2);
-	DHERMESREG(AUXPAGE);
-	DHERMESREG(AUXOFFSET);
-	DHERMESREG(AUXDATA);
-#undef DHERMESREG
-
-	shift_buffer(page, requested_offset, requested_len, &total,
-		     &slop, &buf);
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-struct {
-	uint16_t rid;
-	char *name;
-	int minlen, maxlen;
-	int displaytype;
-#define DISPLAY_WORDS	0
-#define DISPLAY_BYTES	1
-#define DISPLAY_STRING	2
-} record_table[] = {
-#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type }
-	RTCNFENTRY(PORTTYPE, DISPLAY_WORDS),
-	RTCNFENTRY(MACADDR, DISPLAY_BYTES),
-	RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING),
-	RTCNFENTRY(CHANNEL, DISPLAY_WORDS),
-	RTCNFENTRY(OWN_SSID, DISPLAY_STRING),
-	RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS),
-	RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS),
-	RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS),
-	RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS),
-	RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS),
-	RTCNFENTRY(NICKNAME, DISPLAY_STRING),
-	RTCNFENTRY(WEP_ON, DISPLAY_WORDS),
-	RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS),
-	RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES),
-	RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS),
-	RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS),
-	RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS),
-	RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS),
-	RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS),
-	RTCNFENTRY(KEYS, DISPLAY_BYTES),
-	RTCNFENTRY(TX_KEY, DISPLAY_WORDS),
-	RTCNFENTRY(TICKTIME, DISPLAY_WORDS),
-	RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS),
-	RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES),
-	RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES),
-	RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES),
-	RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES),
-	RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS),
-#undef RTCNFENTRY
-#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type }
-	RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS),
-	RTINFENTRY(STAIDENTITY, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_SSID, DISPLAY_STRING),
-	RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES),
-	RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS),
-	RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS),
-	RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS),
-	RTINFENTRY(DATARATES, DISPLAY_BYTES),
-#undef RTINFENTRY
-};
-#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
-
-static int
-dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
-			   int requested_len, int *eof, void *data)
-{
-	dldwd_priv_t *dev = (dldwd_priv_t *)data;
-	hermes_t *hw = &dev->hw;
-	char *buf;
-	int total = 0, slop = 0;
-	int i;
-	uint16_t length;
-	int err;
-
-	buf = page;
-
-	/* print out all the config RIDs */
-	for (i = 0; i < NUM_RIDS; i++) {
-		uint16_t rid = record_table[i].rid;
-		int minlen = record_table[i].minlen;
-		int maxlen = record_table[i].maxlen;
-		int len;
-		uint8_t *val8;
-		uint16_t *val16;
-		int j;
-
-		val8 = kmalloc(maxlen + 2, GFP_KERNEL);
-		if (! val8)
-			return -ENOMEM;
-
-		err = hermes_read_ltv(hw, USER_BAP, rid, maxlen,
-				      &length, val8);
-		if (err) {
-			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
-			continue;
-		}
-		val16 = (uint16_t *)val8;
-
-		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
-			       rid, length, (length-1)*2);
-		len = MIN( MAX(minlen, (length-1)*2), maxlen);
-
-		switch (record_table[i].displaytype) {
-		case DISPLAY_WORDS:
-			for (j = 0; j < len / 2; j++) {
-				buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
-			}
-			buf--;
-			break;
-
-		case DISPLAY_BYTES:
-		default:
-			for (j = 0; j < len; j++) {
-				buf += sprintf(buf, "%02X:", val8[j]);
-			}
-			buf--;
-			break;
-
-		case DISPLAY_STRING:
-			len = MIN(len, le16_to_cpu(val16[0])+2);
-			val8[len] = '\0';
-			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
-			break;
-		}
-
-		buf += sprintf(buf, "\n");
-
-		kfree(val8);
-
-		if (shift_buffer(page, requested_offset, requested_len,
-				 &total, &slop, &buf))
-			break;
-
-		if ( (buf - page) > PROC_SAFE_SIZE )
-			break;
-	}
-
-	return calc_start_len(page, start, requested_offset, requested_len,
-			      total, buf);
-}
-
-/* initialise the /proc subsystem for the hermes driver, creating the
- * separate entries */
-static int
-dldwd_proc_init(void)
-{
-	int err = 0;
-
-	TRACE_ENTER("dldwd");
-
-	/* create the directory for it to sit in */
-	dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
-	if (dir_base == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
-		dldwd_proc_cleanup();
-		err = -ENOMEM;
-	}
-
-	TRACE_EXIT("dldwd");
-
-	return err;
-}
-
-static int
-dldwd_proc_dev_init(dldwd_priv_t *dev)
-{
-	dev->dir_dev = NULL;
-	/* create the directory for it to sit in */
-	dev->dir_dev = create_proc_entry(dev->node.dev_name, S_IFDIR | S_IRUGO | S_IXUGO,
-					 dir_base);
-	if (dev->dir_dev == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n",  dev->node.dev_name);
-		goto fail;
-	}
-
-	dev->dir_regs = NULL;
-	dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO,
-					       dev->dir_dev, dldwd_proc_get_hermes_regs, dev);
-	if (dev->dir_regs == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n",  dev->node.dev_name);
-		goto fail;
-	}
-
-	dev->dir_recs = NULL;
-	dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
-					       dev->dir_dev, dldwd_proc_get_hermes_recs, dev);
-	if (dev->dir_recs == NULL) {
-		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n",  dev->node.dev_name);
-		goto fail;
-	}
-
-	return 0;
- fail:
-	dldwd_proc_dev_cleanup(dev);
-	return -ENOMEM;
-}
-
-static void
-dldwd_proc_dev_cleanup(dldwd_priv_t *priv)
-{
-	if (priv->dir_regs) {
-		remove_proc_entry("regs", priv->dir_dev);
-		priv->dir_regs = NULL;
-	}		
-	if (priv->dir_recs) {
-		remove_proc_entry("recs", priv->dir_dev);
-		priv->dir_recs = NULL;
-	}		
-	if (priv->dir_dev) {
-		remove_proc_entry(priv->node.dev_name, dir_base);
-		priv->dir_dev = NULL;
-	}
-}
-
-static void
-dldwd_proc_cleanup(void)
-{
-	TRACE_ENTER("dldwd");
-
-	if (dir_base) {
-		remove_proc_entry("hermes", &proc_root);
-		dir_base = NULL;
-	}
-	
-	TRACE_EXIT("dldwd");
-}
-
-/*====================================================================*/
-
-/*
- * From here on in, it's all PCMCIA junk, taken almost directly from
- * dummy_cs.c
- */
-
-/*
-   The dev_info variable is the "key" that is used to match up this
-   device driver with appropriate cards, through the card configuration
-   database.
-*/
-
-static dev_info_t dev_info = "orinoco_cs";
-
-/*
-   A linked list of "instances" of the dummy device.  Each actual
-   PCMCIA card corresponds to one device instance, and is described
-   by one dev_link_t structure (defined in ds.h).
-
-   You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of dev_link_t pointers, where minor
-   device numbers are used to derive the corresponding array index.
-*/
-
-static dev_link_t *dev_list = NULL;
-static int num_instances = 0;
-
-/*====================================================================*/
-
-static void cs_error(client_handle_t handle, int func, int ret)
-{
-	error_info_t err = { func, ret };
-	CardServices(ReportError, handle, &err);
-}
-
-/*======================================================================
-  dldwd_attach() creates an "instance" of the driver, allocating
-  local data structures for one device.  The device is registered
-  with Card Services.
-  
-  The dev_link structure is initialized, but we don't actually
-  configure the card at this point -- we wait until we receive a
-  card insertion event.
-  ======================================================================*/
-
-static dev_link_t *dldwd_attach(void)
-{
-	dldwd_priv_t *priv;
-	dev_link_t *link;
-	struct net_device *ndev;
-	client_reg_t client_reg;
-	int ret, i;
-
-	TRACE_ENTER("dldwd");
-
-	/* Allocate space for private device-specific data */
-	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-	if (! priv) {
-		link = NULL;
-		goto out;
-	}
-
-	memset(priv, 0, sizeof(*priv));
-	priv->instance = num_instances++; /* FIXME: Racy? */
-	spin_lock_init(&priv->lock);
-
-	link = &priv->link;
-	ndev = &priv->ndev;
-	link->priv = ndev->priv = priv;
-
-	/* Initialize the dev_link_t structure */
-	link->release.function = &dldwd_release;
-	link->release.data = (u_long) link;
-
-	/* Interrupt setup */
-	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-	if (irq_list[0] == -1)
-		link->irq.IRQInfo2 = irq_mask;
-	else
-		for (i = 0; i < 4; i++)
-			link->irq.IRQInfo2 |= 1 << irq_list[i];
-	link->irq.Handler = NULL;
-
-	/*
-	   General socket configuration defaults can go here.  In this
-	   client, we assume very little, and rely on the CIS for almost
-	   everything.  In most clients, many details (i.e., number, sizes,
-	   and attributes of IO windows) are fixed by the nature of the
-	   device, and can be hard-wired here.
-	 */
-	link->conf.Attributes = 0;
-	link->conf.IntType = INT_MEMORY_AND_IO;
-
-	/* Set up the net_device */
-	ether_setup(ndev);
-	ndev->init = dldwd_init;
-	ndev->open = dldwd_open;
-	ndev->stop = dldwd_stop;
-	ndev->hard_start_xmit = dldwd_xmit;
-	ndev->tx_timeout = dldwd_tx_timeout;
-	ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */
-
-	ndev->get_stats = dldwd_get_stats;
-	ndev->get_wireless_stats = dldwd_get_wireless_stats;
-
-	ndev->do_ioctl = dldwd_ioctl;
-	
-	ndev->change_mtu = dldwd_change_mtu;
-	ndev->set_multicast_list = dldwd_set_multicast_list;
-
-	netif_stop_queue(ndev);
-
-	/* Register with Card Services */
-	link->next = dev_list;
-	dev_list = link;
-	client_reg.dev_info = &dev_info;
-	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-	client_reg.EventMask =
-	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-	client_reg.event_handler = &dldwd_event;
-	client_reg.Version = 0x0210;
-	client_reg.event_callback_args.client_data = link;
-	ret = CardServices(RegisterClient, &link->handle, &client_reg);
-	if (ret != CS_SUCCESS) {
-		cs_error(link->handle, RegisterClient, ret);
-		dldwd_detach(link);
-		link = NULL;
-		goto out;
-	}
-
- out:
-	TRACE_EXIT("dldwd");
-	return link;
-}				/* dldwd_attach */
-
-/*======================================================================
-  This deletes a driver "instance".  The device is de-registered
-  with Card Services.  If it has been released, all local data
-  structures are freed.  Otherwise, the structures will be freed
-  when the device is released.
-  ======================================================================*/
-
-static void dldwd_detach(dev_link_t * link)
-{
-	dev_link_t **linkp;
-	dldwd_priv_t *priv = link->priv;
-
-	TRACE_ENTER("dldwd");
-
-	/* Locate device structure */
-	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
-		if (*linkp == link)
-			break;
-	if (*linkp == NULL)
-		goto out;
-
-	/*
-	   If the device is currently configured and active, we won't
-	   actually delete it yet.  Instead, it is marked so that when
-	   the release() function is called, that will trigger a proper
-	   detach().
-	 */
-	if (link->state & DEV_CONFIG) {
-#ifdef PCMCIA_DEBUG
-		printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
-		       "still locked\n", link->dev->dev_name);
-#endif
-		link->state |= DEV_STALE_LINK;
-		goto out;
-	}
-
-	/* Break the link with Card Services */
-	if (link->handle)
-		CardServices(DeregisterClient, link->handle);
-
-	/* Unlink device structure, and free it */
-	*linkp = link->next;
-	DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev);
-	if (link->dev) {
-		DEBUG(0, "orinoco_cs: About to unregister net device %p\n",
-		      &priv->ndev);
-		unregister_netdev(&priv->ndev);
-	}
-	kfree(priv);
-
-	num_instances--; /* FIXME: Racy? */
-
- out:
-	TRACE_EXIT("dldwd");
-}				/* dldwd_detach */
-
-/*
- * Do a soft reset of the Pcmcia card using the Configuration Option Register
- * Can't do any harm, and actually may do some good on some cards...
- */
-static int dldwd_cor_reset(dev_link_t *link)
-{
-	conf_reg_t reg;
-	u_long default_cor; 
-
-	/* Save original COR value */
-	reg.Function = 0;
-	reg.Action = CS_READ;
-	reg.Offset = CISREG_COR;
-	reg.Value = 0;
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-	default_cor = reg.Value;
-
-	DEBUG(2, "dldwd : dldwd_cor_reset() : cor=0x%lX\n", default_cor);
-
-	/* Soft-Reset card */
-	reg.Action = CS_WRITE;
-	reg.Offset = CISREG_COR;
-	reg.Value = (default_cor | COR_SOFT_RESET);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has acknowledged our reset */
-	mdelay(1);
-
-	/* Restore original COR configuration index */
-	reg.Value = (default_cor & COR_CONFIG_MASK);
-	CardServices(AccessConfigurationRegister, link->handle, &reg);
-
-	/* Wait until the card has finished restarting */
-	mdelay(1);
-
-	return(0);
-}
-
-/*======================================================================
-  dldwd_config() is scheduled to run after a CARD_INSERTION event
-  is received, to configure the PCMCIA socket, and to make the
-  device available to the system.
-  ======================================================================*/
-
-#define CS_CHECK(fn, args...) \
-while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
-
-#define CFG_CHECK(fn, args...) \
-if (CardServices(fn, args) != 0) goto next_entry
-
-static void dldwd_config(dev_link_t * link)
-{
-	client_handle_t handle = link->handle;
-	dldwd_priv_t *priv = link->priv;
-	hermes_t *hw = &priv->hw;
-	struct net_device *ndev = &priv->ndev;
-	tuple_t tuple;
-	cisparse_t parse;
-	int last_fn, last_ret;
-	u_char buf[64];
-	config_info_t conf;
-	cistpl_cftable_entry_t dflt = { 0 };
-	cisinfo_t info;
-
-	TRACE_ENTER("dldwd");
-
-	CS_CHECK(ValidateCIS, handle, &info);
-
-	/*
-	   This reads the card's CONFIG tuple to find its configuration
-	   registers.
-	 */
-	tuple.DesiredTuple = CISTPL_CONFIG;
-	tuple.Attributes = 0;
-	tuple.TupleData = buf;
-	tuple.TupleDataMax = sizeof(buf);
-	tuple.TupleOffset = 0;
-	CS_CHECK(GetFirstTuple, handle, &tuple);
-	CS_CHECK(GetTupleData, handle, &tuple);
-	CS_CHECK(ParseTuple, handle, &tuple, &parse);
-	link->conf.ConfigBase = parse.config.base;
-	link->conf.Present = parse.config.rmask[0];
-
-	/* Configure card */
-	link->state |= DEV_CONFIG;
-
-	/* Look up the current Vcc */
-	CS_CHECK(GetConfigurationInfo, handle, &conf);
-	link->conf.Vcc = conf.Vcc;
-
-	DEBUG(0, "dldwd_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
-	      link->conf.ConfigBase, link->conf.Vcc);
-
-	/*
-	   In this loop, we scan the CIS for configuration table entries,
-	   each of which describes a valid card configuration, including
-	   voltage, IO window, memory window, and interrupt settings.
-
-	   We make no assumptions about the card to be configured: we use
-	   just the information available in the CIS.  In an ideal world,
-	   this would work for any PCMCIA card, but it requires a complete
-	   and accurate CIS.  In practice, a driver usually "knows" most of
-	   these things without consulting the CIS, and most client drivers
-	   will only use the CIS to fill in implementation-defined details.
-	 */
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	CS_CHECK(GetFirstTuple, handle, &tuple);
-	while (1) {
-		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
-		CFG_CHECK(GetTupleData, handle, &tuple);
-		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
-
-		DEBUG(0, "dldwd_config: index = 0x%x, flags = 0x%x\n",
-		      cfg->index, cfg->flags);
-
-		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
-			dflt = *cfg;
-		if (cfg->index == 0)
-			goto next_entry;
-		link->conf.ConfigIndex = cfg->index;
-
-		/* Does this card need audio output? */
-		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-			link->conf.Attributes |= CONF_ENABLE_SPKR;
-			link->conf.Status = CCSR_AUDIO_ENA;
-		}
-
-		/* Use power settings for Vcc and Vpp if present */
-		/*  Note that the CIS values need to be rescaled */
-		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc !=
-			    cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-				goto next_entry;
-			}
-		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
-			if (conf.Vcc !=
-			    dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
-				DEBUG(2, "dldwd_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
-				goto next_entry;
-			}
-		}
-
-		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
-			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
-			link->conf.Vpp1 = link->conf.Vpp2 =
-			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
-		
-		DEBUG(0, "dldwd_config: We seem to have configured Vcc and Vpp\n");
-
-		/* Do we need to allocate an interrupt? */
-		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
-			link->conf.Attributes |= CONF_ENABLE_IRQ;
-
-		/* IO window settings */
-		link->io.NumPorts1 = link->io.NumPorts2 = 0;
-		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
-			cistpl_io_t *io =
-			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
-			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
-			if (!(io->flags & CISTPL_IO_8BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_16;
-			if (!(io->flags & CISTPL_IO_16BIT))
-				link->io.Attributes1 =
-				    IO_DATA_PATH_WIDTH_8;
-			link->io.IOAddrLines =
-			    io->flags & CISTPL_IO_LINES_MASK;
-			link->io.BasePort1 = io->win[0].base;
-			link->io.NumPorts1 = io->win[0].len;
-			if (io->nwin > 1) {
-				link->io.Attributes2 =
-				    link->io.Attributes1;
-				link->io.BasePort2 = io->win[1].base;
-				link->io.NumPorts2 = io->win[1].len;
-			}
-
-			/* This reserves IO space but doesn't actually enable it */
-			CFG_CHECK(RequestIO, link->handle, &link->io);
-		}
-
-
-		/* If we got this far, we're cool! */
-
-		break;
-		
-	next_entry:
-		if (link->io.NumPorts1)
-			CardServices(ReleaseIO, link->handle, &link->io);
-		CS_CHECK(GetNextTuple, handle, &tuple);
-	}
-
-	/*
-	   Allocate an interrupt line.  Note that this does not assign a
-	   handler to the interrupt, unless the 'Handler' member of the
-	   irq structure is initialized.
-	 */
-	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-		int i;
-
-		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
-		link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
-		if (irq_list[0] == -1)
-			link->irq.IRQInfo2 = irq_mask;
-		else
-			for (i=0; i<4; i++)
-				link->irq.IRQInfo2 |= 1 << irq_list[i];
-		
-  		link->irq.Handler = dldwd_interrupt; 
-  		link->irq.Instance = priv; 
-		
-		CS_CHECK(RequestIRQ, link->handle, &link->irq);
-	}
-
-	/* We initialize the hermes structure before completing PCMCIA
-	   configuration just in case the interrupt handler gets
-	   called. */
-	hermes_struct_init(hw, link->io.BasePort1);
-
-	/*
-	   This actually configures the PCMCIA socket -- setting up
-	   the I/O windows and the interrupt mapping, and putting the
-	   card and host interface into "Memory and IO" mode.
-	 */
-	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
-
-	ndev->base_addr = link->io.BasePort1;
-	ndev->irq = link->irq.AssignedIRQ;
-
-	/* Do a Pcmcia soft reset of the card (optional) */
-	if(reset_cor)
-		dldwd_cor_reset(link);
-
-	/* register_netdev will give us an ethX name */
-	ndev->name[0] = '\0';
-	/* Tell the stack we exist */
-	if (register_netdev(ndev) != 0) {
-		printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
-		goto failed;
-	}
-	strcpy(priv->node.dev_name, ndev->name);
-	
-	/* Finally, report what we've done */
-	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
-	       priv->node.dev_name, link->conf.ConfigIndex,
-	       link->conf.Vcc / 10, link->conf.Vcc % 10);
-	if (link->conf.Vpp1)
-		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
-		       link->conf.Vpp1 % 10);
-	if (link->conf.Attributes & CONF_ENABLE_IRQ)
-		printk(", irq %d", link->irq.AssignedIRQ);
-	if (link->io.NumPorts1)
-		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
-		       link->io.BasePort1 + link->io.NumPorts1 - 1);
-	if (link->io.NumPorts2)
-		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
-		       link->io.BasePort2 + link->io.NumPorts2 - 1);
-	printk("\n");
-	
-	/* And give us the proc nodes for debugging */
-	if (dldwd_proc_dev_init(priv) != 0) {
-		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
-		       priv->node.dev_name);
-		goto failed;
-	}
-	
-	/*
-	   At this point, the dev_node_t structure(s) need to be
-	   initialized and arranged in a linked list at link->dev.
-	 */
-	priv->node.major = priv->node.minor = 0;
-	link->dev = &priv->node;
-	link->state &= ~DEV_CONFIG_PENDING;
-
-	TRACE_EXIT("dldwd");
-
-	return;
-
- cs_failed:
-	cs_error(link->handle, last_fn, last_ret);
- failed:
-	dldwd_release((u_long) link);
-
-	TRACE_EXIT("dldwd");
-}				/* dldwd_config */
-
-/*======================================================================
-  After a card is removed, dldwd_release() will unregister the
-  device, and release the PCMCIA configuration.  If the device is
-  still open, this will be postponed until it is closed.
-  ======================================================================*/
-
-static void dldwd_release(u_long arg)
-{
-	dev_link_t *link = (dev_link_t *) arg;
-	dldwd_priv_t *priv = link->priv;
-
-	TRACE_ENTER(link->dev->dev_name);
-
-	/*
-	   If the device is currently in use, we won't release until it
-	   is actually closed, because until then, we can't be sure that
-	   no one will try to access the device or its data structures.
-	 */
-	if (link->open) {
-		DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
-		      link->dev->dev_name);
-		link->state |= DEV_STALE_CONFIG;
-		return;
-	}
-
-	/*
-	   In a normal driver, additional code may be needed to release
-	   other kernel data structures associated with this device. 
-	 */
-
-	dldwd_proc_dev_cleanup(priv);
-
-	/* Don't bother checking to see if these succeed or not */
-	CardServices(ReleaseConfiguration, link->handle);
-	if (link->io.NumPorts1)
-		CardServices(ReleaseIO, link->handle, &link->io);
-	if (link->irq.AssignedIRQ)
-		CardServices(ReleaseIRQ, link->handle, &link->irq);
-	link->state &= ~DEV_CONFIG;
-
-	TRACE_EXIT(link->dev->dev_name);
-}				/* dldwd_release */
-
-/*======================================================================
-  The card status event handler.  Mostly, this schedules other
-  stuff to run after an event is received.
-
-  When a CARD_REMOVAL event is received, we immediately set a
-  private flag to block future accesses to this device.  All the
-  functions that actually access the device should check this flag
-  to make sure the card is still present.
-  ======================================================================*/
-
-static int dldwd_event(event_t event, int priority,
-		       event_callback_args_t * args)
-{
-	dev_link_t *link = args->client_data;
-	dldwd_priv_t *priv = (dldwd_priv_t *)link->priv;
-	struct net_device *dev = &priv->ndev;
-
-	TRACE_ENTER("dldwd");
-
-	switch (event) {
-	case CS_EVENT_CARD_REMOVAL:
-		dldwd_shutdown(priv);
-		link->state &= ~DEV_PRESENT;
-		if (link->state & DEV_CONFIG) {
-			netif_stop_queue(dev);
-			netif_device_detach(dev);
-			mod_timer(&link->release, jiffies + HZ / 20);
-		}
-		break;
-	case CS_EVENT_CARD_INSERTION:
-		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-		dldwd_config(link);
-		break;
-	case CS_EVENT_PM_SUSPEND:
-
-		link->state |= DEV_SUSPEND;
-		/* Fall through... */
-	case CS_EVENT_RESET_PHYSICAL:
-		dldwd_shutdown(priv);
-		/* Mark the device as stopped, to block IO until later */
-
-		if (link->state & DEV_CONFIG) {
-			if (link->open) {
-				netif_stop_queue(dev);
-				netif_device_detach(dev);
-			}
-			CardServices(ReleaseConfiguration, link->handle);
-		}
-		break;
-	case CS_EVENT_PM_RESUME:
-		link->state &= ~DEV_SUSPEND;
-		/* Fall through... */
-	case CS_EVENT_CARD_RESET:
-		if (link->state & DEV_CONFIG) {
-			CardServices(RequestConfiguration, link->handle,
-				     &link->conf);
-
-			if (link->open) {
-				if (dldwd_reset(priv) == 0) {
-					netif_device_attach(dev);
-					netif_start_queue(dev);
-				} else {
-					printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n",
-					       dev->name);
-					dldwd_stop(dev);
-				}
-			}
-		}
-		/*
-		   In a normal driver, additional code may go here to restore
-		   the device state and restart IO. 
-		 */
-		break;
-	}
-
-	TRACE_EXIT("dldwd");
-
-	return 0;
-}				/* dldwd_event */
-
-static int __init init_dldwd_cs(void)
-{
-	servinfo_t serv;
-	int err;
-	
-	TRACE_ENTER("dldwd");
-
-	printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n");
-
-	DEBUG(0, "%s\n", version);
-	CardServices(GetCardServicesInfo, &serv);
-	if (serv.Revision != CS_RELEASE_CODE) {
-		printk(KERN_NOTICE "orinoco_cs: Card Services release "
-		       "does not match!\n");
-		return -1;
-	}
-	register_pccard_driver(&dev_info, &dldwd_attach, &dldwd_detach);
-
-	
-	err = dldwd_proc_init();
-
-	TRACE_EXIT("dldwd");
-	return err;
-}
-
-static void __exit exit_dldwd_cs(void)
-{
-	TRACE_ENTER("dldwd");
-
-	dldwd_proc_cleanup();
-
-	unregister_pccard_driver(&dev_info);
-
-	if (dev_list)
-		DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
-	while (dev_list != NULL) {
-		del_timer(&dev_list->release);
-		if (dev_list->state & DEV_CONFIG)
-			dldwd_release((u_long) dev_list);
-		dldwd_detach(dev_list);
-	}
-
-	TRACE_EXIT("dldwd");
-}
-
-module_init(init_dldwd_cs);
-module_exit(exit_dldwd_cs);
diff -urN linux-2.4.5-pre1/drivers/net/wireless/Config.in linux/drivers/net/wireless/Config.in
--- linux-2.4.5-pre1/drivers/net/wireless/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/Config.in	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,22 @@
+#
+# Wireless LAN device configuration
+#
+
+###tristate '  Hermes chipset support' CONFIG_NET_ORINOCO
+###dep_tristate '    PCMCIA Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_NET_ORINOCO $CONFIG_PCMCIA
+
+if [ "$CONFIG_ALL_PPC" = "y" ]; then
+   tristate '  Apple Airport support (built-in)' CONFIG_APPLE_AIRPORT
+fi
+
+# If Pcmcia is compiled in, offer Pcmcia cards...
+if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+   comment 'Wireless Pcmcia cards support' 
+
+   dep_tristate '  Hermes support (Orinoco/WavelanIEEE/PrismII/Symbol 802.11b cards)' CONFIG_PCMCIA_HERMES $CONFIG_PCMCIA
+
+# If one of the Pcmcia cards above is enabled, activate Pcmcia network support
+   if [ "$CONFIG_PCMCIA_HERMES" = "y" ]; then
+      define_bool CONFIG_PCMCIA_NETCARD y
+   fi
+fi
diff -urN linux-2.4.5-pre1/drivers/net/wireless/Makefile linux/drivers/net/wireless/Makefile
--- linux-2.4.5-pre1/drivers/net/wireless/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/Makefile	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,27 @@
+#
+# drivers/net/wireless/Makefile
+#
+# Makefile for the Linux Wireless network device drivers.
+#
+
+O_TARGET := orinoco_drvs.o
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+# Things that need to export symbols
+export-objs	:= orinoco.o hermes.o
+
+# ISA Bus cards
+
+# PCI bus cards
+
+# Other cards
+obj-$(CONFIG_APPLE_AIRPORT)	+= airport.o orinoco.o hermes.o
+
+# 16-bit Pcmcia wireless client drivers
+obj-$(CONFIG_PCMCIA_HERMES)	+= orinoco_cs.o orinoco.o hermes.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.4.5-pre1/drivers/net/wireless/README linux/drivers/net/wireless/README
--- linux-2.4.5-pre1/drivers/net/wireless/README	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/README	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,25 @@
+	README
+	------
+
+	This directory is mostly for Wireless LAN drivers, in their
+various incarnations (ISA, PCI, Pcmcia...).
+	This separate directory is needed because a lot of driver work
+on different bus (typically PCI + Pcmcia) and share 95% of the
+code. This allow the code and the config options to be in one single
+place instead of scattered all over the driver tree, which is never
+100% satisfactory.
+
+	Note : if you want more info on the topic of Wireless LANs,
+you are kindly invited to have a look at the Wireless Howto :
+		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
+	Some Wireless LAN drivers, like orinoco_cs, require the use of
+Wireless Tools to be configured :
+		http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
+
+	Special notes for distribution maintainers :
+	1) wvlan_cs will be discontinued soon in favor of orinoco_cs
+	2) Please add Wireless Tools support in your scripts
+
+	Have fun...
+
+	Jean
diff -urN linux-2.4.5-pre1/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c
--- linux-2.4.5-pre1/drivers/net/wireless/airport.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/airport.c	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,270 @@
+/* airport.c 0.05
+ *
+ * A driver for "Hermes" chipset based Apple Airport wireless
+ * card.
+ *
+ * Copyright notice & release notes in file orinoco.c
+ * 
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+
+#include <asm/prom.h>
+#include <asm/feature.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+typedef struct dldwd_card {
+	struct device_node* node;
+	int irq_requested;
+	int ndev_registered;
+	/* Common structure (fully included), see orinoco.h */
+	struct dldwd_priv priv;
+} dldwd_card_t;
+
+static char *version = "airport.c 0.05 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+
+/*
+ * Function prototypes
+ */
+
+static dldwd_priv_t* airport_attach(struct device_node *of_node);
+static void airport_detach(dldwd_priv_t* priv);
+static int airport_init(struct net_device *dev);
+static int airport_open(struct net_device *dev);
+static int airport_stop(struct net_device *dev);
+
+/*
+   A linked list of "instances" of the dummy device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dldwd_priv_t *airport_dev;
+
+static int airport_init(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	int rc;
+	
+	TRACE_ENTER(priv->ndev.name);
+
+	MOD_INC_USE_COUNT;
+
+	feature_set_airport_power(card->node, 1);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	rc = dldwd_init(dev);
+	if (rc) {	
+		feature_set_airport_power(card->node, 0);
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ);
+	}
+	priv->hw_ready = 1;
+
+	MOD_DEC_USE_COUNT;
+
+	return rc;
+}
+
+static int
+airport_open(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int rc;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	netif_device_attach(dev);
+	rc = dldwd_reset(priv);
+	if (rc)
+		airport_stop(dev);
+	else
+		netif_start_queue(dev);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return rc;
+}
+
+static int
+airport_stop(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	netif_stop_queue(dev);
+
+	dldwd_shutdown(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return 0;
+}
+
+static dldwd_priv_t*
+airport_attach(struct device_node* of_node)
+{
+	dldwd_priv_t *priv;
+	struct net_device *ndev;
+	dldwd_card_t* card;
+	hermes_t *hw;
+
+	TRACE_ENTER("dldwd");
+
+	if (of_node->n_addrs < 1 || of_node->n_intrs < 1) {
+		printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
+		return NULL;
+	}
+
+	/* Allocate space for private device-specific data */
+	card = kmalloc(sizeof(*card), GFP_KERNEL);
+	if (!card) {
+		printk(KERN_ERR "airport: can't allocate device datas\n");
+		return NULL;
+	}
+	memset(card, 0, sizeof(*card));
+
+	priv = &(card->priv);
+	priv->card = card;
+	ndev = &priv->ndev;
+	hw = &priv->hw;
+	card->node = of_node;
+
+	/* Setup the common part */
+	if (dldwd_setup(priv) < 0) {
+		kfree(card);
+		return NULL;
+	}
+
+	/* Overrides */
+	ndev->init = airport_init;
+	ndev->open = airport_open;
+	ndev->stop = airport_stop;
+
+	/* Setup interrupts & base address */
+	ndev->irq = of_node->intrs[0].line;
+	ndev->base_addr = (unsigned long)ioremap(of_node->addrs[0].address, 0x1000) - _IO_BASE;
+
+	hermes_struct_init(hw, ndev->base_addr);
+		
+	if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) {
+		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq);
+		goto failed;
+	}
+	card->irq_requested = 1;
+	
+	/* register_netdev will give us an ethX name */
+	ndev->name[0] = '\0';
+	/* Tell the stack we exist */
+	if (register_netdev(ndev) != 0) {
+		printk(KERN_ERR "airport: register_netdev() failed\n");
+		goto failed;
+	}
+	printk(KERN_INFO "airport: card registered for interface %s\n", ndev->name);
+	card->ndev_registered = 1;
+
+	SET_MODULE_OWNER(ndev);
+
+	/* And give us the proc nodes for debugging */
+	if (dldwd_proc_dev_init(priv) != 0)
+		printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
+		       ndev->name);
+
+	return priv;
+	
+failed:
+	airport_detach(priv);
+	return NULL;
+}				/* airport_attach */
+
+/*======================================================================
+  This deletes a driver "instance".  
+  ======================================================================*/
+
+static void
+airport_detach(dldwd_priv_t *priv)
+{
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+
+	priv->hw_ready = 0;
+	
+	/* Unregister proc entry */
+	dldwd_proc_dev_cleanup(priv);
+
+	if (card->ndev_registered)
+		unregister_netdev(&priv->ndev);
+	card->ndev_registered = 0;
+	
+	if (card->irq_requested)
+		free_irq(priv->ndev.irq, priv);
+	card->irq_requested = 0;
+
+// FIXME
+//	if (ndev->base_addr)
+//		iounmap(ndev->base_addr + _IO_BASE);
+//	ndev->base_addr = 0;
+	
+	feature_set_airport_power(card->node, 0);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+	
+	kfree(card);
+}				/* airport_detach */
+
+static int __init
+init_airport(void)
+{
+	struct device_node* airport_node;
+
+	printk(KERN_INFO "%s\n", version);
+
+	MOD_INC_USE_COUNT;
+
+	/* Lookup card in device tree */
+	airport_node = find_devices("radio");
+	if (airport_node && !strcmp(airport_node->parent->name, "mac-io"))
+		airport_dev = airport_attach(airport_node);
+
+	MOD_DEC_USE_COUNT;
+
+	return airport_dev ? 0 : -ENODEV;
+}
+
+static void __exit
+exit_airport(void)
+{
+	if (airport_dev)
+		airport_detach(airport_dev);
+	airport_dev = NULL;
+}
+
+MODULE_DESCRIPTION("Apple Airport driver");
+
+module_init(init_airport);
+module_exit(exit_airport);
diff -urN linux-2.4.5-pre1/drivers/net/wireless/hermes.c linux/drivers/net/wireless/hermes.c
--- linux-2.4.5-pre1/drivers/net/wireless/hermes.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/hermes.c	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,502 @@
+/* hermes.c
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism I & II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver.
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ * 
+ * This file distributed under the GPL, version 2.
+ */
+
+static const char *version = "hermes.c: 12 Dec 2000 David Gibson <hermes@gibson.dropbear.id.au>";
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/threads.h>
+#include <linux/smp.h>
+#include <asm/io.h>
+#include <linux/ptrace.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/errno.h>
+
+#include "hermes.h"
+
+#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
+#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
+#define CMD_COMPL_TIMEOUT (10000) /* in iterations of ~10us */
+#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
+#define BAP_BUSY_TIMEOUT (500) /* In iterations of ~1us */
+#define BAP_ERROR_RETRY (10) /* How many times to retry a BAP seek when there is an error */
+
+#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+
+/*
+ * Debugging helpers
+ */
+
+#undef HERMES_DEBUG
+#ifdef HERMES_DEBUG
+
+#include <stdarg.h>
+
+#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ 0x%x: " , hw->iobase); \
+			printk(#stuff);} while (0)
+
+#define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(#stuff)
+
+#else /* ! HERMES_DEBUG */
+
+#define DEBUG(lvl, stuff...) do { } while (0)
+
+#endif /* ! HERMES_DEBUG */
+
+/*
+ * Prototypes
+ */
+
+static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0);
+
+/*
+ * Internal inline functions
+ */
+
+/*
+ * Internal functions
+ */
+
+/* Issue a command to the chip. Waiting for it to complete is the caller's
+   problem.
+
+   Returns -EBUSY if the command register is busy, 0 on success.
+
+   Callable from any context.
+*/
+static int hermes_issue_cmd(hermes_t *hw, uint16_t cmd, uint16_t param0)
+{
+	uint16_t reg;
+/*  	unsigned long k = CMD_BUSY_TIMEOUT; */
+
+	/* First check that the command register is not busy */
+	reg = hermes_read_regn(hw, CMD);
+	if (reg & HERMES_CMD_BUSY) {
+		return -EBUSY;
+	}
+
+	hermes_write_regn(hw, PARAM2, 0);
+	hermes_write_regn(hw, PARAM1, 0);
+	hermes_write_regn(hw, PARAM0, param0);
+	hermes_write_regn(hw, CMD, cmd);
+	
+	return 0;
+}
+
+/*
+ * Function definitions
+ */
+
+void hermes_struct_init(hermes_t *hw, uint io)
+{
+	hw->iobase = io;
+	hw->inten = 0x0;
+}
+
+int hermes_reset(hermes_t *hw)
+{
+	uint16_t status, reg;
+	int err = 0;
+	int k;
+
+	/* We don't want to be interrupted while resetting the chipset */
+	hw->inten = 0x0;
+	hermes_write_regn(hw, INTEN, 0);
+	hermes_write_regn(hw, EVACK, 0xffff);
+
+	/* Because we hope we can reset the card even if it gets into
+	   a stupid state, we actually wait to see if the command
+	   register will unbusy itself */
+	k = CMD_BUSY_TIMEOUT;
+	reg = hermes_read_regn(hw, CMD);
+	while (k && (reg & HERMES_CMD_BUSY)) {
+		if (reg == 0xffff) /* Special case - the card has probably been removed,
+				      so don't wait for the timeout */
+			return -ENODEV;
+
+		k--;
+		udelay(1);
+		reg = hermes_read_regn(hw, CMD);
+	}
+	
+	/* No need to explicitly handle the timeout - hermes_issue_cmd() will
+	   probably return -EBUSY */
+
+	/* We don't use hermes_docmd_wait here, because the reset wipes
+	   the magic constant in SWSUPPORT0 away, and it gets confused */
+	err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
+	if (err)
+		return err;
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = CMD_INIT_TIMEOUT;
+	while ( (! (reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+
+	DEBUG(0, "Reset completed in %d iterations\n", CMD_INIT_TIMEOUT - k);
+
+	hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
+
+	if (! hermes_present(hw)) {
+		DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
+		       hw->iobase);
+		err = -ENODEV;
+		goto out;
+	}
+		
+	if (! (reg & HERMES_EV_CMD)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for card to reset (reg=0x%04x)!\n",
+		       hw->iobase, reg);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	status = hermes_read_regn(hw, STATUS);
+
+	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+	err = status & HERMES_STATUS_RESULT;
+
+ out:
+	return err;
+}
+
+/* Issue a command to the chip, and (busy!) wait for it to
+ * complete.
+ *
+ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
+ *
+ * Callable from any context, but locking is your problem. */
+int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp)
+{
+	int err;
+	int k;
+	uint16_t reg;
+
+	err = hermes_issue_cmd(hw, cmd, parm0);
+	if (err) {
+		if (! hermes_present(hw)) {
+			printk(KERN_WARNING "hermes @ 0x%x: Card removed while issuing command.\n",
+			       hw->iobase);
+			err = -ENODEV;
+		} else 
+			printk(KERN_ERR "hermes @ 0x%x: CMD register busy in hermes_issue_command().\n",
+			       hw->iobase);
+		goto out;
+	}
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = CMD_COMPL_TIMEOUT;
+	while ( (! (reg & HERMES_EV_CMD)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+
+	if (! hermes_present(hw)) {
+		printk(KERN_WARNING "hermes @ 0x%x: Card removed while waiting for command completion.\n",
+		       hw->iobase);
+		err = -ENODEV;
+		goto out;
+	}
+		
+	if (! (reg & HERMES_EV_CMD)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for command completion.\n",
+		       hw->iobase);
+		err = -ETIMEDOUT;
+		goto out;
+	}
+
+	resp->status = hermes_read_regn(hw, STATUS);
+	resp->resp0 = hermes_read_regn(hw, RESP0);
+	resp->resp1 = hermes_read_regn(hw, RESP1);
+	resp->resp2 = hermes_read_regn(hw, RESP2);
+
+	hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
+
+	err = resp->status & HERMES_STATUS_RESULT;
+
+ out:
+	return err;
+}
+
+int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid)
+{
+	int err = 0;
+	hermes_response_t resp;
+	int k;
+	uint16_t reg;
+	
+	if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
+		return -EINVAL;
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp);
+	if (err) {
+		printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n",
+		       hw->iobase, err);
+		return err;
+	}
+
+	reg = hermes_read_regn(hw, EVSTAT);
+	k = ALLOC_COMPL_TIMEOUT;
+	while ( (! (reg & HERMES_EV_ALLOC)) && k) {
+		k--;
+		udelay(10);
+		reg = hermes_read_regn(hw, EVSTAT);
+	}
+	
+	if (! hermes_present(hw)) {
+		printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n",
+		       hw->iobase);
+		return -ENODEV;
+	}
+		
+	if (! (reg & HERMES_EV_ALLOC)) {
+		printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n",
+		       hw->iobase);
+		return -ETIMEDOUT;
+	}
+
+	*fid = hermes_read_regn(hw, ALLOCFID);
+	hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
+	
+	return 0;
+}
+
+/* Set up a BAP to read a particular chunk of data from card's internal buffer.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
+ * from firmware
+ *
+ * Callable from any context */
+static int hermes_bap_seek(hermes_t *hw, int bap, uint16_t id, uint16_t offset)
+{
+	int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
+	int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
+	int k;
+	int l = BAP_ERROR_RETRY;
+	uint16_t reg;
+
+	/* Paranoia.. */
+	if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
+		return -EINVAL;
+
+	k = BAP_BUSY_TIMEOUT;
+	reg = hermes_read_reg(hw, oreg);
+
+	if (reg & HERMES_OFFSET_BUSY)
+		return -EBUSY;
+
+	/* Now we actually set up the transfer */
+ retry:
+	hermes_write_reg(hw, sreg, id);
+	hermes_write_reg(hw, oreg, offset);
+
+	/* Wait for the BAP to be ready */
+	k = BAP_BUSY_TIMEOUT;
+	reg = hermes_read_reg(hw, oreg);
+	while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
+		k--;
+		udelay(1);
+		reg = hermes_read_reg(hw, oreg);
+	}
+
+	if (reg & HERMES_OFFSET_BUSY)
+		return -ETIMEDOUT;
+
+	/* For some reason, seeking the BAP seems to randomly fail somewhere
+	   (firmware bug?). We retry a few times before giving up. */
+	if (reg & HERMES_OFFSET_ERR) {
+		if (l--) {
+			udelay(1);
+			goto retry;
+		} else
+			return -EIO;
+	}
+
+	return 0;
+}
+
+/* Read a block of data from the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem.  len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+		     uint16_t id, uint16_t offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+
+	if (len % 2)
+		return -EINVAL;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		goto out;
+
+	/* Actually do the transfer */
+	hermes_read_data(hw, dreg, buf, len/2);
+
+ out:
+	return err;
+}
+
+/* Write a block of data to the chip's buffer, via the
+ * BAP. Synchronization/serialization is the caller's problem. len
+ * must be even.
+ *
+ * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
+ */
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+		      uint16_t id, uint16_t offset)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+
+	if (len % 2)
+		return -EINVAL;
+
+	err = hermes_bap_seek(hw, bap, id, offset);
+	if (err)
+		goto out;
+	
+	/* Actually do the transfer */
+	hermes_write_data(hw, dreg, buf, len/2);
+
+ out:	
+	return err;
+}
+
+/* Read a Length-Type-Value record from the card.
+ *
+ * If length is NULL, we ignore the length read from the card, and
+ * read the entire buffer regardless. This is useful because some of
+ * the configuration records appear to have incorrect lengths in
+ * practice.
+ *
+ * Callable from user or bh context.  */
+int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
+		    uint16_t *length, void *buf)
+{
+	int err = 0;
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	uint16_t rlength, rtype;
+	hermes_response_t resp;
+	int count;
+
+	if (buflen % 2)
+		return -EINVAL;
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, &resp);
+	if (err)
+		goto out;
+
+	err = hermes_bap_seek(hw, bap, rid, 0);
+	if (err)
+		goto out;
+
+	rlength = hermes_read_reg(hw, dreg);
+	rtype = hermes_read_reg(hw, dreg);
+
+	if (length)
+		*length = rlength;
+
+	if (rtype != rid)
+		printk(KERN_WARNING "hermes_read_ltv(): rid  (0x%04x) does "
+		       "not match type (0x%04x)\n", rid, rtype);
+	if (HERMES_RECLEN_TO_BYTES(rlength) > buflen)
+		printk(KERN_WARNING "hermes @ 0x%x: Truncating LTV record from %d to %d bytes. "
+		       "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
+		       HERMES_RECLEN_TO_BYTES(rlength), buflen, rid, rlength);
+	
+	/* For now we always read the whole buffer, the
+	   lengths in the records seem to be wrong, frequently */
+	count = buflen / 2;
+
+#if 0
+	if (length)
+		count = (MIN(buflen, rlength) + 1) / 2;
+	else {
+		count = buflen / 2;
+		if (rlength != buflen)
+			printk(KERN_WARNING "hermes_read_ltv(): Incorrect \
+record length %d instead of %d on RID 0x%04x\n", rlength, buflen, rid);
+	}
+#endif
+	hermes_read_data(hw, dreg, buf, count);
+
+ out:
+	return err;
+}
+
+int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid, 
+		     uint16_t length, const void *value)
+{
+	int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
+	int err = 0;
+	hermes_response_t resp;
+	int count;
+	
+	DEBUG(3, "write_ltv(): bap=%d rid=0x%04x length=%d (value=0x%04x)\n",
+	      bap, rid, length, * ((uint16_t *)value));
+
+	err = hermes_bap_seek(hw, bap, rid, 0);
+	if (err)
+		goto out;
+
+	hermes_write_reg(hw, dreg, length);
+	hermes_write_reg(hw, dreg, rid);
+
+	count = length - 1;
+
+	hermes_write_data(hw, dreg, value, count);
+
+	err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
+				rid, &resp);
+
+ out:
+	return err;
+}
+
+EXPORT_SYMBOL(hermes_struct_init);
+EXPORT_SYMBOL(hermes_reset);
+EXPORT_SYMBOL(hermes_docmd_wait);
+EXPORT_SYMBOL(hermes_allocate);
+
+EXPORT_SYMBOL(hermes_bap_pread);
+EXPORT_SYMBOL(hermes_bap_pwrite);
+EXPORT_SYMBOL(hermes_read_ltv);
+EXPORT_SYMBOL(hermes_write_ltv);
+
+static int __init init_hermes(void)
+{
+	printk(KERN_INFO "%s\n", version);
+
+	return 0;
+}
+
+module_init(init_hermes);
diff -urN linux-2.4.5-pre1/drivers/net/wireless/hermes.h linux/drivers/net/wireless/hermes.h
--- linux-2.4.5-pre1/drivers/net/wireless/hermes.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/hermes.h	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,402 @@
+/* hermes.h
+ *
+ * Driver core for the "Hermes" wireless MAC controller, as used in
+ * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
+ * work on the hfa3841 and hfa3842 MAC controller chips used in the
+ * Prism I & II chipsets.
+ *
+ * This is not a complete driver, just low-level access routines for
+ * the MAC controller itself.
+ *
+ * Based on the prism2 driver from Absolute Value Systems' linux-wlan
+ * project, the Linux wvlan_cs driver, Lucent's HCF-Light
+ * (wvlan_hcf.c) library, and the NetBSD wireless driver.
+ *
+ * Copyright (C) 2000, David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ *
+ * Portions taken from hfa384x.h, Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
+ *
+ * This file distributed under the GPL, version 2.
+ */
+
+#ifndef _HERMES_H
+#define _HERMES_H
+
+/* Notes on locking:
+ *
+ * As a module of low level hardware access routines, there is no
+ * locking. Users of this module should ensure that they serialize
+ * access to the hermes_t structure, and to the hardware
+*/
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+
+/*
+ * Limits and constants
+ */
+#define		HERMES_ALLOC_LEN_MIN		(4)
+#define		HERMES_ALLOC_LEN_MAX		(2400)
+#define		HERMES_LTV_LEN_MAX		(34)
+#define		HERMES_BAP_DATALEN_MAX		(4096)
+#define		HERMES_BAP_OFFSET_MAX		(4096)
+#define		HERMES_PORTID_MAX		(7)
+#define		HERMES_NUMPORTS_MAX		(HERMES_PORTID_MAX+1)
+#define		HERMES_PDR_LEN_MAX		(260)	/* in bytes, from EK */
+#define		HERMES_PDA_RECS_MAX		(200)	/* a guess */
+#define		HERMES_PDA_LEN_MAX		(1024)	/* in bytes, from EK */
+#define		HERMES_SCANRESULT_MAX		(35)
+#define		HERMES_CHINFORESULT_MAX		(8)
+#define		HERMES_FRAME_LEN_MAX		(2304)
+#define		HERMES_MAX_MULTICAST		(16)
+#define		HERMES_MAGIC			(0x7d1f)
+
+/*
+ * Hermes register offsets
+ */
+#define		HERMES_CMD			(0x00)
+#define		HERMES_PARAM0			(0x02)
+#define		HERMES_PARAM1			(0x04)
+#define		HERMES_PARAM2			(0x06)
+#define		HERMES_STATUS			(0x08)
+#define		HERMES_RESP0			(0x0A)
+#define		HERMES_RESP1			(0x0C)
+#define		HERMES_RESP2			(0x0E)
+#define		HERMES_INFOFID			(0x10)
+#define		HERMES_RXFID			(0x20)
+#define		HERMES_ALLOCFID			(0x22)
+#define		HERMES_TXCOMPLFID		(0x24)
+#define		HERMES_SELECT0			(0x18)
+#define		HERMES_OFFSET0			(0x1C)
+#define		HERMES_DATA0			(0x36)
+#define		HERMES_SELECT1			(0x1A)
+#define		HERMES_OFFSET1			(0x1E)
+#define		HERMES_DATA1			(0x38)
+#define		HERMES_EVSTAT			(0x30)
+#define		HERMES_INTEN			(0x32)
+#define		HERMES_EVACK			(0x34)
+#define		HERMES_CONTROL			(0x14)
+#define		HERMES_SWSUPPORT0		(0x28)
+#define		HERMES_SWSUPPORT1		(0x2A)
+#define		HERMES_SWSUPPORT2		(0x2C)
+#define		HERMES_AUXPAGE			(0x3A)
+#define		HERMES_AUXOFFSET		(0x3C)
+#define		HERMES_AUXDATA			(0x3E)
+
+/*
+ * CMD register bitmasks
+ */
+#define		HERMES_CMD_BUSY			(0x8000)
+#define		HERMES_CMD_AINFO		(0x7f00)
+#define		HERMES_CMD_MACPORT		(0x0700)
+#define		HERMES_CMD_RECL			(0x0100)
+#define		HERMES_CMD_WRITE		(0x0100)
+#define		HERMES_CMD_PROGMODE		(0x0300)
+#define		HERMES_CMD_CMDCODE		(0x003f)
+
+/*
+ * STATUS register bitmasks
+ */
+#define		HERMES_STATUS_RESULT		(0x7f00)
+#define		HERMES_STATUS_CMDCODE		(0x003f)
+
+/*
+ * OFFSET refister bitmasks
+ */
+#define		HERMES_OFFSET_BUSY		(0x8000)
+#define		HERMES_OFFSET_ERR		(0x4000)
+#define		HERMES_OFFSET_DATAOFF		(0x0ffe)
+
+/*
+ * Event register bitmasks (INTEN, EVSTAT, EVACK)
+ */
+#define		HERMES_EV_TICK			(0x8000)
+#define		HERMES_EV_WTERR			(0x4000)
+#define		HERMES_EV_INFDROP		(0x2000)
+#define		HERMES_EV_INFO			(0x0080)
+#define		HERMES_EV_DTIM			(0x0020)
+#define		HERMES_EV_CMD			(0x0010)
+#define		HERMES_EV_ALLOC			(0x0008)
+#define		HERMES_EV_TXEXC			(0x0004)
+#define		HERMES_EV_TX			(0x0002)
+#define		HERMES_EV_RX			(0x0001)
+
+/*
+ * Command codes
+ */
+/*--- Controller Commands --------------------------*/
+#define		HERMES_CMD_INIT			(0x0000)
+#define		HERMES_CMD_ENABLE		(0x0001)
+#define		HERMES_CMD_DISABLE		(0x0002)
+#define		HERMES_CMD_DIAG			(0x0003)
+
+/*--- Buffer Mgmt Commands --------------------------*/
+#define		HERMES_CMD_ALLOC		(0x000A)
+#define		HERMES_CMD_TX			(0x000B)
+#define		HERMES_CMD_CLRPRST		(0x0012)
+
+/*--- Regulate Commands --------------------------*/
+#define		HERMES_CMD_NOTIFY		(0x0010)
+#define		HERMES_CMD_INQ			(0x0011)
+
+/*--- Configure Commands --------------------------*/
+#define		HERMES_CMD_ACCESS		(0x0021)
+#define		HERMES_CMD_DOWNLD		(0x0022)
+
+/*--- Debugging Commands -----------------------------*/
+#define 	HERMES_CMD_MONITOR		(0x0038)
+#define		HERMES_MONITOR_ENABLE		(0x000b)
+#define		HERMES_MONITOR_DISABLE		(0x000f)
+
+/*
+ * Configuration RIDs
+ */
+
+#define		HERMES_RID_CNF_PORTTYPE		(0xfc00)
+#define		HERMES_RID_CNF_MACADDR		(0xfc01)
+#define		HERMES_RID_CNF_DESIRED_SSID	(0xfc02)
+#define		HERMES_RID_CNF_CHANNEL		(0xfc03)
+#define		HERMES_RID_CNF_OWN_SSID		(0xfc04)
+#define		HERMES_RID_CNF_SYSTEM_SCALE	(0xfc06)
+#define		HERMES_RID_CNF_MAX_DATA_LEN	(0xfc07)
+#define		HERMES_RID_CNF_PM_ENABLE	(0xfc09)
+#define		HERMES_RID_CNF_PM_MCAST_RX	(0xfc0b)
+#define		HERMES_RID_CNF_PM_PERIOD	(0xfc0c)
+#define		HERMES_RID_CNF_PM_HOLDOVER	(0xfc0d)
+#define		HERMES_RID_CNF_NICKNAME		(0xfc0e)
+#define		HERMES_RID_CNF_WEP_ON		(0xfc20)
+#define		HERMES_RID_CNF_MWO_ROBUST	(0xfc25)
+#define		HERMES_RID_CNF_PRISM2_WEP_ON	(0xfc28)
+#define		HERMES_RID_CNF_MULTICAST_LIST	(0xfc80)
+#define		HERMES_RID_CNF_CREATEIBSS	(0xfc81)
+#define		HERMES_RID_CNF_FRAG_THRESH	(0xfc82)
+#define		HERMES_RID_CNF_RTS_THRESH	(0xfc83)
+#define		HERMES_RID_CNF_TX_RATE_CTRL	(0xfc84)
+#define		HERMES_RID_CNF_PROMISCUOUS	(0xfc85)
+#define		HERMES_RID_CNF_KEYS		(0xfcb0)
+#define		HERMES_RID_CNF_TX_KEY		(0xfcb1)
+#define		HERMES_RID_CNF_TICKTIME		(0xfce0)
+
+#define		HERMES_RID_CNF_PRISM2_TX_KEY	(0xfc23)
+#define		HERMES_RID_CNF_PRISM2_KEY0	(0xfc24)
+#define		HERMES_RID_CNF_PRISM2_KEY1	(0xfc25)
+#define		HERMES_RID_CNF_PRISM2_KEY2	(0xfc26)
+#define		HERMES_RID_CNF_PRISM2_KEY3	(0xfc27)
+#define		HERMES_RID_CNF_SYMBOL_MANDATORY_BSSID	(0xfc21)
+#define		HERMES_RID_CNF_SYMBOL_AUTH_TYPE		(0xfc2A)
+#define		HERMES_RID_CNF_SYMBOL_BASIC_RATES	(0xfc8A)
+#define		HERMES_RID_CNF_SYMBOL_PREAMBLE		(0xfc8C)
+
+/*
+ * Information RIDs
+ */
+#define		HERMES_RID_CHANNEL_LIST		(0xfd10)
+#define		HERMES_RID_STAIDENTITY		(0xfd20)
+#define		HERMES_RID_CURRENT_SSID		(0xfd41)
+#define		HERMES_RID_CURRENT_BSSID	(0xfd42)
+#define		HERMES_RID_COMMSQUALITY		(0xfd43)
+#define 	HERMES_RID_CURRENT_TX_RATE	(0xfd44)
+#define 	HERMES_RID_SHORT_RETRY_LIMIT	(0xfd48)
+#define 	HERMES_RID_LONG_RETRY_LIMIT	(0xfd49)
+#define 	HERMES_RID_MAX_TX_LIFETIME	(0xfd4A)
+#define		HERMES_RID_WEP_AVAIL		(0xfd4f)
+#define		HERMES_RID_CURRENT_CHANNEL	(0xfdc1)
+#define		HERMES_RID_DATARATES		(0xfdc6)
+#define		HERMES_RID_SYMBOL_PRIMARY_VER	(0xfd03)
+#define		HERMES_RID_SYMBOL_SECONDARY_VER	(0xfd21)
+#define		HERMES_RID_SYMBOL_KEY_LENGTH	(0xfc2B)
+
+/*
+ * Frame structures and constants
+ */
+
+typedef struct hermes_frame_desc {
+	/* Hermes - i.e. little-endian byte-order */
+	uint16_t status; /* 0x0 */
+	uint16_t res1, res2; /* 0x2, 0x4 */
+	uint16_t q_info; /* 0x6 */
+	uint16_t res3, res4; /* 0x8, 0xA */
+	uint16_t tx_ctl; /* 0xC */
+} __attribute__ ((packed)) hermes_frame_desc_t;
+
+#define		HERMES_RXSTAT_ERR		(0x0003)
+#define		HERMES_RXSTAT_MACPORT		(0x0700)
+#define		HERMES_RXSTAT_MSGTYPE		(0xE000)
+
+#define		HERMES_RXSTAT_BADCRC		(0x0001)
+#define		HERMES_RXSTAT_UNDECRYPTABLE	(0x0002)
+
+/* RFC-1042 encoded frame */
+#define		HERMES_RXSTAT_1042		(0x2000)
+/* Bridge-tunnel encoded frame */
+#define		HERMES_RXSTAT_TUNNEL		(0x4000)
+/* Wavelan-II Management Protocol frame */
+#define		HERMES_RXSTAT_WMP		(0x6000)
+
+#ifdef __KERNEL__
+
+/* Basic control structure */
+typedef struct hermes {
+	uint iobase;
+
+	uint16_t inten; /* Which interrupts should be enabled? */
+} hermes_t;
+
+typedef struct hermes_response {
+	uint16_t status, resp0, resp1, resp2;
+} hermes_response_t;
+
+/* Firmware information structure */
+typedef struct hermes_identity {
+	uint16_t id, vendor, major, minor;
+} __attribute__ ((packed)) hermes_identity_t;
+
+/* "ID" structure - used for ESSID and station nickname */
+typedef struct hermes_id {
+	uint16_t len;
+	uint16_t val[16];
+} __attribute__ ((packed)) hermes_id_t;
+
+typedef struct hermes_commsqual {
+	uint16_t qual, signal, noise;
+} __attribute__ ((packed)) hermes_commsqual_t;
+
+typedef struct hermes_multicast {
+	uint8_t addr[HERMES_MAX_MULTICAST][ETH_ALEN];
+} __attribute__ ((packed)) hermes_multicast_t;
+
+/* Register access convenience macros */
+#define hermes_read_reg(hw, off) (inw((hw)->iobase + (off)))
+#define hermes_write_reg(hw, off, val) (outw_p((val), (hw)->iobase + (off)))
+
+#define hermes_read_regn(hw, name) (hermes_read_reg((hw), HERMES_##name))
+#define hermes_write_regn(hw, name, val) (hermes_write_reg((hw), HERMES_##name, (val)))
+
+/* Note that for the next two, the count is in 16-bit words, not bytes */
+#define hermes_read_data(hw, off, buf, count) (insw((hw)->iobase + (off), (buf), (count)))
+#define hermes_write_data(hw, off, buf, count) (outsw((hw)->iobase + (off), (buf), (count)))
+
+/* Function prototypes */
+void hermes_struct_init(hermes_t *hw, uint io);
+int hermes_reset(hermes_t *hw);
+int hermes_docmd_wait(hermes_t *hw, uint16_t cmd, uint16_t parm0, hermes_response_t *resp);
+int hermes_allocate(hermes_t *hw, uint16_t size, uint16_t *fid);
+
+
+int hermes_bap_pread(hermes_t *hw, int bap, void *buf, uint16_t len,
+		       uint16_t id, uint16_t offset);
+int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, uint16_t len,
+			uint16_t id, uint16_t offset);
+int hermes_read_ltv(hermes_t *hw, int bap, uint16_t rid, int buflen,
+		    uint16_t *length, void *buf);
+int hermes_write_ltv(hermes_t *hw, int bap, uint16_t rid,
+		      uint16_t length, const void *value);
+
+/* Inline functions */
+
+static inline int hermes_present(hermes_t *hw)
+{
+	return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
+}
+
+static inline void hermes_enable_interrupt(hermes_t *hw, uint16_t events)
+{
+	hw->inten |= events;
+	hermes_write_regn(hw, INTEN, hw->inten);
+}
+
+static inline void hermes_set_irqmask(hermes_t *hw, uint16_t events)
+{
+	hw->inten = events;
+	hermes_write_regn(hw, INTEN, events);
+}
+
+static inline int hermes_enable_port(hermes_t *hw, int port)
+{
+	hermes_response_t resp;
+
+	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
+				 0, &resp);
+}
+
+static inline int hermes_disable_port(hermes_t *hw, int port)
+{
+	hermes_response_t resp;
+
+	return hermes_docmd_wait(hw, HERMES_CMD_ENABLE | (port << 8), 
+				 0, &resp);
+}
+
+#define HERMES_BYTES_TO_RECLEN(n) ( ((n) % 2) ? (((n)+1)/2)+1 : ((n)/2)+1 )
+#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
+
+#define HERMES_READ_RECORD(hw, bap, rid, buf) \
+	(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
+#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
+	(hermes_write_ltv((hw),(bap),(rid),HERMES_BYTES_TO_RECLEN(sizeof(*buf)),(buf)))
+
+static inline int hermes_read_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t *word)
+{
+	uint16_t rec;
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, rid, &rec);
+	*word = le16_to_cpu(rec);
+	return err;
+}
+
+static inline int hermes_write_wordrec(hermes_t *hw, int bap, uint16_t rid, uint16_t word)
+{
+	uint16_t rec = cpu_to_le16(word);
+	return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
+}
+
+static inline int hermes_read_staidentity(hermes_t *hw, int bap, hermes_identity_t *buf)
+{
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_STAIDENTITY, buf);
+	if (err)
+		return err;
+
+	le16_to_cpus(&buf->id);
+	le16_to_cpus(&buf->vendor);
+	le16_to_cpus(&buf->major);
+	le16_to_cpus(&buf->minor);
+	
+	return 0;
+}
+
+static inline int hermes_read_commsqual(hermes_t *hw, int bap, hermes_commsqual_t *buf)
+{
+	int err;
+
+	err = HERMES_READ_RECORD(hw, bap, HERMES_RID_COMMSQUALITY, buf);
+	if (err)
+		return err;
+
+	le16_to_cpus(&buf->qual);
+	le16_to_cpus(&buf->signal);
+	le16_to_cpus(&buf->noise);
+	
+	return 0;
+}
+
+#else /* ! __KERNEL__ */
+
+/* These are provided for the benefit of userspace drivers and testing programs
+   which use ioperm() or iopl() */
+
+#define hermes_read_reg(base, off) (inw((base) + (off)))
+#define hermes_write_reg(base, off, val) (outw((val), (base) + (off)))
+
+#define hermes_read_regn(base, name) (hermes_read_reg((base), HERMES_##name))
+#define hermes_write_regn(base, name, val) (hermes_write_reg((base), HERMES_##name, (val)))
+
+/* Note that for the next two, the count is in 16-bit words, not bytes */
+#define hermes_read_data(base, off, buf, count) (insw((base) + (off), (buf), (count)))
+#define hermes_write_data(base, off, buf, count) (outsw((base) + (off), (buf), (count)))
+
+#endif /* ! __KERNEL__ */
+
+#endif  /* _HERMES_H */
diff -urN linux-2.4.5-pre1/drivers/net/wireless/orinoco.c linux/drivers/net/wireless/orinoco.c
--- linux-2.4.5-pre1/drivers/net/wireless/orinoco.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/orinoco.c	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,3551 @@
+/* orinoco.c 0.05	- (formerly known as dldwd_cs.c and orinoco_cs.c)
+ *
+ * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+ * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
+ * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
+ * It should also be usable on various Prism II based cards such as the
+ * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
+ * cards such as the 3Com AirConnect and Ericsson WLAN.
+ *
+ * Copyright (C) 2000 David Gibson, Linuxcare Australia <hermes@gibson.dropbear.id.au>
+ *	With some help from :
+ * Copyright (C) 2001 Jean Tourrilhes, HP Labs <jt@hpl.hp.com>
+ * Copyright (C) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
+ *
+ * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+ *      http://www.fasta.fh-dortmund.de/users/andy/wvlan/
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David
+ * A. Hinds are Copyright (C) 1999 David A. Hinds.  All Rights
+ * Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), 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 MPL, 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 MPL or the GPL.
+ */
+
+/* Notes on locking:
+ *
+ * The basic principle of operation is that everything except the
+ * interrupt handler is serialized through a single spinlock in the
+ * dldwd_priv_t structure, using dldwd_lock() and
+ * dldwd_unlock() (which in turn use spin_lock_bh() and spin_unlock_bh()).
+ *
+ * The kernel's IRQ handling stuff ensures that the interrupt handler
+ * does not re-enter itself. The interrupt handler is written such
+ * that everything it does is safe without a lock: chiefly this means
+ * that the Rx path uses one of the Hermes chipset's BAPs while
+ * everything else uses the other.
+ *
+ * For the moment access to the device statistics from the interrupt
+ * handler is unsafe - we just put up with any resulting errors in the
+ * statisics. FIXME: This should probably be changed to store the
+ * stats in atomic types.
+ *
+ * EXCEPT that we don't want the irq handler running when we actually
+ * reset or shut down the card, because strange things might happen
+ * (probably the worst would be one packet of garbage, but you can't
+ * be too careful). For this we use __dldwd_stop_irqs() which will set
+ * a flag to disable the interrupt handler, and wait for any
+ * outstanding instances of the handler to complete. THIS WILL LOSE
+ * INTERRUPTS! so it shouldn't be used except for resets, when we
+ * don't care about that.*/
+
+/*
+ * Tentative changelog...
+ *
+ * v0.01 -> v0.02 - 21/3/2001 - Jean II
+ *	o Allow to use regular ethX device name instead of dldwdX
+ *	o Warning on IBSS with ESSID=any for firmware 6.06
+ *	o Put proper range.throughput values (optimistic)
+ *	o IWSPY support (IOCTL and stat gather in Rx path)
+ *	o Allow setting frequency in Ad-Hoc mode
+ *	o Disable WEP setting if !has_wep to work on old firmware
+ *	o Fix txpower range
+ *	o Start adding support for Samsung/Compaq firmware
+ *
+ * v0.02 -> v0.03 - 23/3/2001 - Jean II
+ *	o Start adding Symbol support - need to check all that
+ *	o Fix Prism2/Symbol WEP to accept 128 bits keys
+ *	o Add Symbol WEP (add authentication type)
+ *	o Add Prism2/Symbol rate
+ *	o Add PM timeout (holdover duration)
+ *	o Enable "iwconfig eth0 key off" and friends (toggle flags)
+ *	o Enable "iwconfig eth0 power unicast/all" (toggle flags)
+ *	o Try with an intel card. It report firmware 1.01, behave like
+ *	  an antiquated firmware, however on windows it says 2.00. Yuck !
+ *	o Workaround firmware bug in allocate buffer (Intel 1.01)
+ *	o Finish external renaming to orinoco...
+ *	o Testing with various Wavelan firmwares
+ *
+ * v0.03 -> v0.04 - 30/3/2001 - Jean II
+ *	o Update to Wireless 11 -> add retry limit/lifetime support
+ *	o Tested with a D-Link DWL 650 card, fill in firmware support
+ *	o Warning on Vcc mismatch (D-Link 3.3v card in Lucent 5v only slot)
+ *	o Fixed the Prims2 WEP bugs that I introduced in v0.03 :-(
+ *	  It work on D-Link *only* after a tcpdump. Weird...
+ *	  And still doesn't work on Intel card. Grrrr...
+ *	o Update the mode after a setport3
+ *	o Add preamble setting for Symbol cards (not yet enabled)
+ *	o Don't complain as much about Symbol cards...
+ *
+ * v0.04 -> v0.04b - 22/4/2001 - David Gibson
+ *      o Removed the 'eth' parameter - always use ethXX as the
+ *        interface name instead of dldwdXX.  The other was racy
+ *        anyway.
+ *	o Clean up RID definitions in hermes.h, other cleanups
+ *
+ * v0.04b -> v0.04c - 24/4/2001 - Jean II
+ *	o Tim Hurley <timster@seiki.bliztech.com> reported a D-Link card
+ *	  with vendor 02 and firmware 0.08. Added in the capabilities...
+ *	o Tested Lucent firmware 7.28, everything works...
+ *
+ * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
+ *	o Spin-off Pcmcia code. This file is renamed orinoco.c,
+ *	  and orinoco_cs.c now contains only the Pcmcia specific stuff
+ *	o Add Airport driver support on top of orinoco.c (see airport.c)
+ *
+ * v0.05 -> v0.05a - 4/5/2001 - Jean II
+ *	o Revert to old Pcmcia code to fix breakage of Ben's changes...
+ *
+ * v0.05a -> v0.05b - 4/5/2001 - Jean II
+ *	o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
+ *	o D-Link firmware doesn't support multicast. We just print a few
+ *	  error messages, but otherwise everything works...
+ *	o For David : set/getport3 works fine, just upgrade iwpriv...
+ *
+ * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
+ *	o Adapt airport.c to latest changes in orinoco.c
+ *	o Remove deferred power enabling code
+ *
+ * v0.05c -> v0.05d - 5/5/2001 - Jean II
+ *	o Workaround to SNAP decapsulate frame from LinkSys AP
+ *	  original patch from : Dong Liu <dliu@research.bell-labs.com>
+ *	  (note : the memcmp bug was mine - fixed)
+ *	o Remove set_retry stuff, no firmware support it (bloat--).
+ *
+ * TODO - Jean II
+ *	o inline functions (lot's of candidate, need to reorder code)
+ *	o Test PrismII/Symbol cards & firmware versions
+ *	o Mini-PCI support
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+static char *version = "orinoco.c 0.05d (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
+/* Level of debugging. Used in the macros in orinoco.h */
+#ifdef ORINOCO_DEBUG
+int dldwd_debug = ORINOCO_DEBUG;
+MODULE_PARM(dldwd_debug, "i");
+#endif
+
+const long channel_frequency[] = {
+	2412, 2417, 2422, 2427, 2432, 2437, 2442,
+	2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+#define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
+
+/* This tables gives the actual meanings of the bitrate IDs returned by the firmware.
+   It gives the rate in halfMb/s, negative indicates auto mode */
+const int rate_list[] = { 0, 2, 4, -22, 11, 22, -4, -11, 0, 0, 0, 0};
+
+#define NUM_RATES (sizeof(rate_list) / sizeof(rate_list[0]))
+
+struct p80211_hdr {
+	uint16_t frame_ctl;
+	uint16_t duration_id;
+	uint8_t addr1[ETH_ALEN];
+	uint8_t addr2[ETH_ALEN];
+	uint8_t addr3[ETH_ALEN];
+	uint16_t seq_ctl;
+	uint8_t addr4[ETH_ALEN];
+	uint16_t data_len;
+} __attribute__ ((packed));
+
+/* Frame control field constants */
+#define DLDWD_FCTL_VERS			0x0002
+#define DLDWD_FCTL_FTYPE		0x000c
+#define DLDWD_FCTL_STYPE		0x00f0
+#define DLDWD_FCTL_TODS			0x0100
+#define DLDWD_FCTL_FROMDS		0x0200
+#define DLDWD_FCTL_MOREFRAGS		0x0400
+#define DLDWD_FCTL_RETRY		0x0800
+#define DLDWD_FCTL_PM			0x1000
+#define DLDWD_FCTL_MOREDATA		0x2000
+#define DLDWD_FCTL_WEP			0x4000
+#define DLDWD_FCTL_ORDER		0x8000
+
+#define DLDWD_FTYPE_MGMT		0x0000
+#define DLDWD_FTYPE_CTL			0x0004
+#define DLDWD_FTYPE_DATA		0x0008
+
+struct p8022_hdr {
+	uint8_t dsap;
+	uint8_t ssap;
+	uint8_t ctrl;
+	uint8_t oui[3];
+} __attribute__ ((packed));
+
+struct dldwd_frame_hdr {
+	hermes_frame_desc_t desc;
+	struct p80211_hdr p80211;
+	struct ethhdr p8023;
+	struct p8022_hdr p8022;
+	uint16_t ethertype;
+} __attribute__ ((packed));
+
+#define P8023_OFFSET		(sizeof(hermes_frame_desc_t) + \
+				sizeof(struct p80211_hdr))
+#define ENCAPS_OVERHEAD		(sizeof(struct p8022_hdr) + 2)
+
+/* 802.2 LLL header SNAP used for SNAP encapsulation over 802.11 */
+struct p8022_hdr encaps_hdr = {
+	0xaa, 0xaa, 0x03, {0x00, 0x00, 0xf8}
+};
+
+/*
+ * Function prototypes
+ */
+
+static void dldwd_stat_gather(struct net_device *dev,
+			      struct sk_buff *skb,
+			      struct dldwd_frame_hdr *hdr);
+
+static struct net_device_stats *dldwd_get_stats(struct net_device *dev);
+static struct iw_statistics *dldwd_get_wireless_stats(struct net_device *dev);
+
+/* Hardware control routines */
+
+static int __dldwd_hw_reset(dldwd_priv_t *priv);
+static int __dldwd_hw_setup_wep(dldwd_priv_t *priv);
+static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN]);
+static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);
+static long dldwd_hw_get_freq(dldwd_priv_t *priv);
+static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+				    int32_t *rates, int max);
+
+/* Interrupt handling routines */
+static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw);
+static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw);
+
+static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);
+static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq);
+static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);
+static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);
+static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);
+static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq);
+static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq);
+static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);
+static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *frq);
+static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq);
+static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq);
+static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);
+static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);
+static void __dldwd_set_multicast_list(struct net_device *dev);
+
+/* /proc debugging stuff */
+static int dldwd_proc_init(void);
+static void dldwd_proc_cleanup(void);
+
+/*
+ * Inline functions
+ */
+static inline void
+dldwd_lock(dldwd_priv_t *priv)
+{
+	spin_lock_bh(&priv->lock);
+}
+
+static inline void
+dldwd_unlock(dldwd_priv_t *priv)
+{
+	spin_unlock_bh(&priv->lock);
+}
+
+static inline int
+dldwd_irqs_allowed(dldwd_priv_t *priv)
+{
+	return test_bit(DLDWD_STATE_DOIRQ, &priv->state);
+}
+
+static inline void
+__dldwd_stop_irqs(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+
+	hermes_set_irqmask(hw, 0);
+	clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	while (test_bit(DLDWD_STATE_INIRQ, &priv->state))
+		;
+}
+
+static inline void
+__dldwd_start_irqs(dldwd_priv_t *priv, uint16_t irqmask)
+{
+	hermes_t *hw = &priv->hw;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	__cli();
+	set_bit(DLDWD_STATE_DOIRQ, &priv->state);
+	hermes_set_irqmask(hw, irqmask);
+	__sti();
+
+	TRACE_EXIT(priv->ndev.name);
+}
+
+static inline void
+set_port_type(dldwd_priv_t *priv)
+{
+	switch (priv->iw_mode) {
+	case IW_MODE_INFRA:
+		priv->port_type = 1;
+		priv->allow_ibss = 0;
+		break;
+	case IW_MODE_ADHOC:
+		if (priv->prefer_port3) {
+			priv->port_type = 3;
+			priv->allow_ibss = 0;
+		} else {
+			priv->port_type = 1;
+			priv->allow_ibss = 1;
+		}
+		break;
+	default:
+		printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
+		       priv->ndev.name);
+	}
+}
+
+extern void
+dldwd_set_multicast_list(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+
+	dldwd_lock(priv);
+	__dldwd_set_multicast_list(dev);
+	dldwd_unlock(priv);
+}
+
+/*
+ * Hardware control routines
+ */
+
+static int
+__dldwd_hw_reset(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err;
+
+	if (! priv->broken_reset)
+		return hermes_reset(hw);
+	else {
+		hw->inten = 0;
+		hermes_write_regn(hw, INTEN, 0);
+		err = hermes_disable_port(hw, 0);
+		hermes_write_regn(hw, EVACK, 0xffff);
+		return err;
+	}
+}
+
+void
+dldwd_shutdown(dldwd_priv_t *priv)
+{
+/* 	hermes_t *hw = &priv->hw; */
+	int err = 0;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+	__dldwd_stop_irqs(priv);
+
+	err = __dldwd_hw_reset(priv);
+	if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */
+		printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev.name, err);
+
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+}
+
+int
+dldwd_reset(dldwd_priv_t *priv)
+{
+	struct net_device *dev = &priv->ndev;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t idbuf;
+	int frame_size;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+
+	__dldwd_stop_irqs(priv);
+
+	err = __dldwd_hw_reset(priv);
+	if (err)
+		goto out;
+
+	frame_size = TX_NICBUF_SIZE;
+	/* This stupid bug is present in Intel firmware 1.10, and
+	 * may be fixed in later firmwares - Jean II */
+	if(priv->broken_allocate)
+		frame_size = TX_NICBUF_SIZE_BUG;
+	err = hermes_allocate(hw, frame_size, &priv->txfid);
+	if (err)
+		goto out;
+
+	/* Now set up all the parameters on the card */
+	
+	/* Set up the link mode */
+	
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PORTTYPE, priv->port_type);
+	if (err)
+		goto out;
+	if (priv->has_ibss) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CREATEIBSS,
+					   priv->allow_ibss);
+		if (err)
+			goto out;
+		if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss)
+		   && (!priv->has_ibss_any)) {
+			printk(KERN_WARNING "%s: This firmware requires an \
+ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+			/* With wvlan_cs, in this case, we would crash.
+			 * hopefully, this driver will behave better...
+			 * Jean II */
+		}
+	}
+
+	/* Set up encryption */
+	if (priv->has_wep) {
+		err = __dldwd_hw_setup_wep(priv);
+		if (err)
+			goto out;
+	}
+
+	/* Set the desired ESSID */
+	idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+	memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+	err = hermes_write_ltv(hw, USER_BAP, (priv->port_type == 3) ?
+			       HERMES_RID_CNF_OWN_SSID : HERMES_RID_CNF_DESIRED_SSID,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+			       &idbuf);
+	if (err)
+		goto out;
+
+	/* Set the station name */
+	idbuf.len = cpu_to_le16(strlen(priv->nick));
+	memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+	err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+			       HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+			       &idbuf);
+	if (err)
+		goto out;
+
+	/* Set the channel/frequency */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_CHANNEL, priv->channel);
+	if (err)
+		goto out;
+
+	/* Set AP density */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, priv->ap_density);
+	if (err)
+		goto out;
+
+	/* Set RTS threshold */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, priv->rts_thresh);
+	if (err)
+		goto out;
+
+	/* Set fragmentation threshold or MWO robustness */
+	if (priv->has_mwo)
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNF_MWO_ROBUST, priv->mwo_robust);
+	else
+		err = hermes_write_wordrec(hw, USER_BAP,
+					   HERMES_RID_CNF_FRAG_THRESH, priv->frag_thresh);
+	if (err)
+		goto out;
+
+	/* Set bitrate */
+	err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL,
+				   priv->tx_rate_ctrl);
+	if (err)
+		goto out;
+
+	/* Set power management */
+	if (priv->has_pm) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE,
+					   priv->pm_on);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX,
+					   priv->pm_mcast);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+					   priv->pm_period);
+		if (err)
+			goto out;
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
+					   priv->pm_timeout);
+		if (err)
+			goto out;
+	}
+
+	/* Set preamble - only for Symbol so far... */
+	if (priv->has_preamble) {
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE,
+					   priv->preamble);
+		if (err) {
+			printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name);
+			goto out;
+		}
+	}
+
+	/* Set promiscuity / multicast*/
+	priv->promiscuous = 0;
+	priv->allmulti = 0;
+	priv->mc_count = 0;
+	__dldwd_set_multicast_list(dev);
+	
+	err = hermes_enable_port(hw, DLDWD_MACPORT);
+	if (err)
+		goto out;
+	
+	__dldwd_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC |
+			   HERMES_EV_TX | HERMES_EV_TXEXC |
+			   HERMES_EV_WTERR | HERMES_EV_INFO |
+			   HERMES_EV_INFDROP);
+
+ out:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return err;
+}
+
+static int __dldwd_hw_setup_wep(dldwd_priv_t *priv)
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int	extra_wep_flag = 0;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_LUCENT: /* Lucent style WEP */
+		if (priv->wep_on) {
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_KEY, priv->tx_key);
+			if (err)
+				return err;
+			
+			err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_KEYS, &priv->keys);
+			if (err)
+				return err;
+		}
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_WEP_ON, priv->wep_on);
+		if (err)
+			return err;
+		break;
+
+	case FIRMWARE_TYPE_PRISM2: /* Prism II style WEP */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
+		if (priv->wep_on) {
+			char keybuf[LARGE_KEY_SIZE+1];
+			int keylen;
+			int i;
+			
+			/* Write all 4 keys */
+			for(i = 0; i < MAX_KEYS; i++) {
+				keylen = priv->keys[i].len;
+				keybuf[keylen] = '\0';
+				memcpy(keybuf, priv->keys[i].data, keylen);
+				err = hermes_write_ltv(hw, USER_BAP,
+						       HERMES_RID_CNF_PRISM2_KEY0 + i,
+						       HERMES_BYTES_TO_RECLEN(keylen + 1),
+						       &keybuf);
+				if (err)
+					return err;
+			}
+
+			err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_TX_KEY,
+						   priv->tx_key);
+			if (err)
+				return err;
+
+			/* Authentication is where Prism2 and Symbol
+			 * firmware differ... */
+			if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) {
+				/* Symbol cards : set the authentication :
+				 * 0 -> no encryption, 1 -> open,
+				 * 2 -> shared key, 3 -> shared key 128bit */
+				if(priv->wep_restrict) {
+					if(priv->keys[priv->tx_key].len >
+					   SMALL_KEY_SIZE)
+						extra_wep_flag = 3;
+					else
+						extra_wep_flag = 2;
+				} else
+					extra_wep_flag = 1;
+				err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_AUTH_TYPE, priv->wep_restrict);
+				if (err)
+					return err;
+			} else {
+				/* Prism2 card : we need to modify master
+				 * WEP setting */
+				if(priv->wep_restrict)
+					extra_wep_flag = 2;
+				else
+					extra_wep_flag = 0;
+			}
+		}
+		
+		/* Master WEP setting : on/off */
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PRISM2_WEP_ON, (priv->wep_on | extra_wep_flag));
+		if (err)
+			return err;	
+		break;
+
+	default:
+		if (priv->wep_on) {
+			printk(KERN_ERR "%s: WEP enabled, although not supported!\n",
+			       priv->ndev.name);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int dldwd_hw_get_bssid(dldwd_priv_t *priv, char buf[ETH_ALEN])
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+
+	dldwd_lock(priv);
+
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_BSSID,
+			      ETH_ALEN, NULL, buf);
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_hw_get_essid(dldwd_priv_t *priv, int *active,
+			      char buf[IW_ESSID_MAX_SIZE+1])
+{
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t essidbuf;
+	char *p = (char *)(&essidbuf.val);
+	int len;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	dldwd_lock(priv);
+
+	if (strlen(priv->desired_essid) > 0) {
+		/* We read the desired SSID from the hardware rather
+		   than from priv->desired_essid, just in case the
+		   firmware is allowed to change it on us. I'm not
+		   sure about this */
+		/* My guess is that the OWN_SSID should always be whatever
+		 * we set to the card, whereas CURRENT_SSID is the one that
+		 * may change... - Jean II */
+		uint16_t rid;
+
+		*active = 1;
+
+		rid = (priv->port_type == 3) ? HERMES_RID_CNF_OWN_SSID :
+			HERMES_RID_CNF_DESIRED_SSID;
+		
+		err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
+				      NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	} else {
+		*active = 0;
+
+		err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_SSID,
+				      sizeof(essidbuf), NULL, &essidbuf);
+		if (err)
+			goto fail_unlock;
+	}
+
+	len = le16_to_cpu(essidbuf.len);
+
+	memset(buf, 0, sizeof(buf));
+	memcpy(buf, p, len);
+	buf[len] = '\0';
+
+ fail_unlock:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return err;       
+}
+
+static long dldwd_hw_get_freq(dldwd_priv_t *priv)
+{
+	
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t channel;
+	long freq = 0;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_CHANNEL, &channel);
+	if (err)
+		goto out;
+
+	if ( (channel < 1) || (channel > NUM_CHANNELS) ) {
+		struct net_device *dev = &priv->ndev;
+
+		printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel);
+		err = -EBUSY;
+		goto out;
+
+	}
+	freq = channel_frequency[channel-1] * 100000;
+
+ out:
+	dldwd_unlock(priv);
+
+	if (err > 0)
+		err = -EBUSY;
+	return err ? err : freq;
+}
+
+static int dldwd_hw_get_bitratelist(dldwd_priv_t *priv, int *numrates,
+				    int32_t *rates, int max)
+{
+	hermes_t *hw = &priv->hw;
+	hermes_id_t list;
+	unsigned char *p = (unsigned char *)&list.val;
+	int err = 0;
+	int num;
+	int i;
+
+	dldwd_lock(priv);
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_DATARATES, sizeof(list),
+			      NULL, &list);
+	dldwd_unlock(priv);
+
+	if (err)
+		return err;
+	
+	num = le16_to_cpu(list.len);
+	*numrates = num;
+	num = MIN(num, max);
+
+	for (i = 0; i < num; i++) {
+		rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
+	}
+
+	return 0;
+}
+
+#ifndef PCMCIA_DEBUG
+static inline void show_rx_frame(struct dldwd_frame_hdr *frame) {}
+#else
+static void show_rx_frame(struct dldwd_frame_hdr *frame)
+{
+	printk(KERN_DEBUG "RX descriptor:\n");
+	printk(KERN_DEBUG "  status      = 0x%04x\n", frame->desc.status);
+	printk(KERN_DEBUG "  res1        = 0x%04x\n", frame->desc.res1);
+	printk(KERN_DEBUG "  res2        = 0x%04x\n", frame->desc.res2);
+	printk(KERN_DEBUG "  q_info      = 0x%04x\n", frame->desc.q_info);
+	printk(KERN_DEBUG "  res3        = 0x%04x\n", frame->desc.res3);
+	printk(KERN_DEBUG "  res4        = 0x%04x\n", frame->desc.res4);
+	printk(KERN_DEBUG "  tx_ctl      = 0x%04x\n", frame->desc.tx_ctl);
+
+	printk(KERN_DEBUG "IEEE 802.11 header:\n");
+	printk(KERN_DEBUG "  frame_ctl   = 0x%04x\n",
+	       frame->p80211.frame_ctl);
+	printk(KERN_DEBUG "  duration_id = 0x%04x\n",
+	       frame->p80211.duration_id);
+	printk(KERN_DEBUG "  addr1       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr1[0], frame->p80211.addr1[1],
+	       frame->p80211.addr1[2], frame->p80211.addr1[3],
+	       frame->p80211.addr1[4], frame->p80211.addr1[5]);
+	printk(KERN_DEBUG "  addr2       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr2[0], frame->p80211.addr2[1],
+	       frame->p80211.addr2[2], frame->p80211.addr2[3],
+	       frame->p80211.addr2[4], frame->p80211.addr2[5]);
+	printk(KERN_DEBUG "  addr3       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr3[0], frame->p80211.addr3[1],
+	       frame->p80211.addr3[2], frame->p80211.addr3[3],
+	       frame->p80211.addr3[4], frame->p80211.addr3[5]);
+	printk(KERN_DEBUG "  seq_ctl     = 0x%04x\n",
+	       frame->p80211.seq_ctl);
+	printk(KERN_DEBUG "  addr4       = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p80211.addr4[0], frame->p80211.addr4[1],
+	       frame->p80211.addr4[2], frame->p80211.addr4[3],
+	       frame->p80211.addr4[4], frame->p80211.addr4[5]);
+	printk(KERN_DEBUG "  data_len    = 0x%04x\n",
+	       frame->p80211.data_len);
+
+	printk(KERN_DEBUG "IEEE 802.3 header:\n");
+	printk(KERN_DEBUG "  dest        = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p8023.h_dest[0], frame->p8023.h_dest[1],
+	       frame->p8023.h_dest[2], frame->p8023.h_dest[3],
+	       frame->p8023.h_dest[4], frame->p8023.h_dest[5]);
+	printk(KERN_DEBUG "  src         = %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       frame->p8023.h_source[0], frame->p8023.h_source[1],
+	       frame->p8023.h_source[2], frame->p8023.h_source[3],
+	       frame->p8023.h_source[4], frame->p8023.h_source[5]);
+	printk(KERN_DEBUG "  len         = 0x%04x\n", frame->p8023.h_proto);
+
+	printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n");
+	printk(KERN_DEBUG "  DSAP        = 0x%02x\n", frame->p8022.dsap);
+	printk(KERN_DEBUG "  SSAP        = 0x%02x\n", frame->p8022.ssap);
+	printk(KERN_DEBUG "  ctrl        = 0x%02x\n", frame->p8022.ctrl);
+	printk(KERN_DEBUG "  OUI         = %02x:%02x:%02x\n",
+	       frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]);
+	printk(KERN_DEBUG "  ethertype  = 0x%04x\n", frame->ethertype);
+}
+#endif
+
+/*
+ * Interrupt handler
+ */
+void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *) dev_id;
+	hermes_t *hw = &priv->hw;
+	struct net_device *dev = &priv->ndev;
+	int count = IRQ_LOOP_MAX;
+	uint16_t evstat, events;
+	static int old_time = 0, timecount = 0; /* Eugh, revolting hack for now */
+
+	if (test_and_set_bit(DLDWD_STATE_INIRQ, &priv->state))
+		BUG();
+
+	if (! dldwd_irqs_allowed(priv)) {
+		clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+		return;
+	}
+
+	DEBUG(3, "%s: dldwd_interrupt()\n", priv->ndev.name);
+
+	while (1) {
+		if (jiffies != old_time)
+			timecount = 0;
+		if ( (++timecount > 50) || (! count--) ) {
+			printk(KERN_CRIT "%s: IRQ handler is looping too \
+much! Shutting down.\n",
+			       dev->name);
+			/* Perform an emergency shutdown */
+			clear_bit(DLDWD_STATE_DOIRQ, &priv->state);
+			hermes_set_irqmask(hw, 0);
+			break;
+		}
+
+		evstat = hermes_read_regn(hw, EVSTAT);
+		DEBUG(3, "__dldwd_interrupt(): count=%d EVSTAT=0x%04x inten=0x%04x\n",
+		      count, evstat, hw->inten);
+
+		events = evstat & hw->inten;
+
+		if (! events) {
+			if (netif_queue_stopped(dev)) {
+				/* There seems to be a firmware bug which
+				   sometimes causes the card to give an
+				   interrupt with no event set, when there
+				   sould be a Tx completed event. */
+				DEBUG(3, "%s: Interrupt with no event (ALLOCFID=0x%04x)\n",
+				      dev->name, (int)hermes_read_regn(hw, ALLOCFID));
+				events = HERMES_EV_TX | HERMES_EV_ALLOC;
+			} else /* Nothing's happening, we're done */
+				break;
+		}
+
+		/* Check the card hasn't been removed */
+		if (! hermes_present(hw)) {
+			DEBUG(0, "dldwd_interrupt(): card removed\n");
+			break;
+		}
+
+		if (events & HERMES_EV_TICK)
+			__dldwd_ev_tick(priv, hw);
+		if (events & HERMES_EV_WTERR)
+			__dldwd_ev_wterr(priv, hw);
+		if (events & HERMES_EV_INFDROP)
+			__dldwd_ev_infdrop(priv, hw);
+		if (events & HERMES_EV_INFO)
+			__dldwd_ev_info(priv, hw);
+		if (events & HERMES_EV_RX)
+			__dldwd_ev_rx(priv, hw);
+		if (events & HERMES_EV_TXEXC)
+			__dldwd_ev_txexc(priv, hw);
+		if (events & HERMES_EV_TX)
+			__dldwd_ev_tx(priv, hw);
+		if (events & HERMES_EV_ALLOC)
+			__dldwd_ev_alloc(priv, hw);
+		
+		hermes_write_regn(hw, EVACK, events);
+	}
+
+	clear_bit(DLDWD_STATE_INIRQ, &priv->state);
+}
+
+static void __dldwd_ev_tick(dldwd_priv_t *priv, hermes_t *hw)
+{
+	printk(KERN_DEBUG "%s: TICK\n", priv->ndev.name);
+}
+
+static void __dldwd_ev_wterr(dldwd_priv_t *priv, hermes_t *hw)
+{
+	/* This seems to happen a fair bit under load, but ignoring it
+	   seems to work fine...*/
+	DEBUG(1, "%s: MAC controller error (WTERR). Ignoring.\n",
+	      priv->ndev.name);
+}
+
+static void __dldwd_ev_infdrop(dldwd_priv_t *priv, hermes_t *hw)
+{
+	printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev.name);
+}
+
+static void __dldwd_ev_info(dldwd_priv_t *priv, hermes_t *hw)
+{
+	DEBUG(3, "%s: Information frame received.\n", priv->ndev.name);
+	/* We don't actually do anything about it - we assume the MAC
+	   controller can deal with it */
+}
+
+static void __dldwd_ev_rx(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+	struct iw_statistics *wstats = &priv->wstats;
+	struct sk_buff *skb = NULL;
+	uint16_t rxfid, status;
+	int length, data_len, data_off;
+	char *p;
+	struct dldwd_frame_hdr hdr;
+	struct ethhdr *eh;
+	int err;
+
+	rxfid = hermes_read_regn(hw, RXFID);
+	DEBUG(3, "__dldwd_ev_rx(): RXFID=0x%04x\n", rxfid);
+
+	/* We read in the entire frame header here. This isn't really
+	   necessary, since we ignore most of it, but it's
+	   conceptually simpler. We can tune this later if
+	   necessary. */
+	err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), rxfid, 0);
+	if (err) {
+		printk(KERN_ERR "%s: error %d reading frame header. "
+		       "Frame dropped.\n", dev->name, err);
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	status = le16_to_cpu(hdr.desc.status);
+	
+	if (status & HERMES_RXSTAT_ERR) {
+		if ((status & HERMES_RXSTAT_ERR) == HERMES_RXSTAT_BADCRC) {
+			stats->rx_crc_errors++;
+			printk(KERN_WARNING "%s: Bad CRC on Rx. Frame dropped.\n",
+			       dev->name);
+			show_rx_frame(&hdr);
+		} else if ((status & HERMES_RXSTAT_ERR)
+			   == HERMES_RXSTAT_UNDECRYPTABLE) {
+			wstats->discard.code++;
+			printk(KERN_WARNING "%s: Undecryptable frame on Rx. Frame dropped.\n",
+			       dev->name);
+		} else {
+			wstats->discard.misc++;
+			printk("%s: Unknown Rx error (0x%x). Frame dropped.\n",
+			       dev->name, status & HERMES_RXSTAT_ERR);
+		}
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	length = le16_to_cpu(hdr.p80211.data_len);
+	/* Yes, you heard right, that's le16. 802.2 and 802.3 are
+	   big-endian, but 802.11 is little-endian believe it or
+	   not. */
+	/* Correct. 802.3 is big-endian byte order and little endian bit
+	 * order, whereas 802.11 is little endian for both byte and bit
+	 * order. That's specified in the 802.11 spec. - Jean II */
+	
+	/* Sanity check */
+	if (length > MAX_FRAME_SIZE) {
+		printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
+		       dev->name, length);
+		stats->rx_length_errors++;
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	/* We need space for the packet data itself, plus an ethernet
+	   header, plus 2 bytes so we can align the IP header on a
+	   32bit boundary, plus 1 byte so we can read in odd length
+	   packets from the card, which has an IO granularity of 16
+	   bits */  
+	skb = dev_alloc_skb(length+ETH_HLEN+2+1);
+	if (!skb) {
+		printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
+		       dev->name);
+		stats->rx_dropped++;
+		goto drop;
+	}
+
+	skb_reserve(skb, 2); /* This way the IP header is aligned */
+
+	/* Handle decapsulation
+	 * In most cases, the firmware tell us about SNAP frames.
+	 * For some reason, the SNAP frames sent by LinkSys APs
+	 * are not properly recognised by most firmwares.
+	 * So, check ourselves (note : only 3 bytes out of 6).
+	 */
+	if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+	   ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+	   (!memcmp(&hdr.p8022, &encaps_hdr, 3))) {
+		/* These indicate a SNAP within 802.2 LLC within
+		   802.11 frame which we'll need to de-encapsulate to
+		   the original EthernetII frame.
+		   IEEE and ISO OSI have a lot to answer for.  */
+
+		/* Remove SNAP header, reconstruct EthernetII frame */
+		data_len = length - ENCAPS_OVERHEAD;
+		data_off = sizeof(hdr);
+
+		eh = (struct ethhdr *)skb_put(skb, ETH_HLEN);
+
+		memcpy(eh, &hdr.p8023, sizeof(hdr.p8023));
+		eh->h_proto = hdr.ethertype;
+	} else {
+		/* All other cases indicate a genuine 802.3 frame.
+		 * No decapsulation needed */
+
+		/* Otherwise, we just throw the whole thing in,
+		 * and hope the protocol layer can deal with it
+		 * as 802.3 */
+		data_len = length;
+		data_off = P8023_OFFSET;
+	}
+
+	p = skb_put(skb, data_len);
+	if (hermes_bap_pread(hw, IRQ_BAP, p, RUP_EVEN(data_len),
+			     rxfid, data_off) != 0) {
+		printk(KERN_WARNING "%s: Error reading packet data\n",
+		       dev->name);
+		stats->rx_errors++;
+		goto drop;
+	}
+
+	dev->last_rx = jiffies;
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+	
+	/* Process the wireless stats if needed */
+	dldwd_stat_gather(dev, skb, &hdr);
+
+	/* Pass the packet to the networking stack */
+	netif_rx(skb);
+	stats->rx_packets++;
+	stats->rx_bytes += length;
+
+	return;
+
+ drop:	
+	if (skb)
+		dev_kfree_skb_irq(skb);
+	return;
+}
+
+static void __dldwd_ev_txexc(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+
+	printk(KERN_WARNING "%s: Tx error!\n", dev->name);
+
+	netif_wake_queue(dev);
+	stats->tx_errors++;
+}
+
+static void __dldwd_ev_tx(dldwd_priv_t *priv, hermes_t *hw)
+{
+	struct net_device *dev = &priv->ndev;
+	struct net_device_stats *stats = &priv->stats;
+
+	DEBUG(3, "%s: Transmit completed\n", dev->name);
+
+	stats->tx_packets++;
+	netif_wake_queue(dev);
+}
+
+static void __dldwd_ev_alloc(dldwd_priv_t *priv, hermes_t *hw)
+{
+	uint16_t allocfid;
+
+	allocfid = hermes_read_regn(hw, ALLOCFID);
+	DEBUG(3, "%s: Allocation complete FID=0x%04x\n", priv->ndev.name, allocfid);
+
+	/* For some reason we don't seem to get transmit completed events properly */
+	if (allocfid == priv->txfid)
+		__dldwd_ev_tx(priv, hw);
+
+/* 	hermes_write_regn(hw, ALLOCFID, 0); */
+}
+
+/*
+ * struct net_device methods
+ */
+
+int
+dldwd_init(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	hermes_id_t nickbuf;
+	uint16_t reclen;
+	int len;
+	char *vendor_str;
+	uint32_t firmver;
+
+	TRACE_ENTER("dldwd");
+	
+	dldwd_lock(priv);
+
+	err = hermes_reset(hw);
+	if (err != 0) {
+		printk(KERN_ERR "%s: failed to reset hardware\n", dev->name);
+		goto out;
+	}
+	
+	/* Get the firmware version */
+	err = hermes_read_staidentity(hw, USER_BAP, &priv->firmware_info);
+	if (err) {
+		printk(KERN_WARNING "%s: Error %d reading firmware info. Wildly guessing capabilities...\n",
+		       dev->name, err);
+		memset(&priv->firmware_info, 0, sizeof(priv->firmware_info));
+	}
+
+	firmver = ((uint32_t)priv->firmware_info.major << 16) | priv->firmware_info.minor;
+	DEBUG(2, "%s: firmver = 0x%X\n", dev->name, firmver);
+
+	/* Determine capabilities from the firmware version */
+
+	switch (priv->firmware_info.vendor) {
+	case 0x1:
+		/* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+		 * ELSA, Melco, HP, IBM, Dell 1150 cards */
+		vendor_str = "Lucent";
+		/* Lucent MAC : 00:60:1D:* & 00:02:2D:* */
+
+		priv->firmware_type = FIRMWARE_TYPE_LUCENT;
+		priv->broken_reset = 0;
+		priv->broken_allocate = 0;
+		priv->has_port3 = 1;		/* Still works in 7.28 */
+		priv->has_ibss = (firmver >= 0x60006);
+		priv->has_ibss_any = (firmver >= 0x60010);
+		priv->has_wep = (firmver >= 0x40020);
+		priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+					  Gold cards from the others? */
+		priv->has_mwo = (firmver >= 0x60000);
+		priv->has_pm = (firmver >= 0x40020);
+		priv->has_preamble = 0;
+		/* Tested with Lucent firmware :
+		 *	1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+		 * Tested CableTron firmware : 4.32 => Anton */
+		break;
+	case 0x2:
+		vendor_str = "Generic Prism II";
+		/* Some D-Link cards report vendor 0x02... */
+
+		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->broken_reset = 0;
+		priv->broken_allocate = 0;
+		priv->has_port3 = 1;
+		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
+		priv->has_wep = (firmver >= 0x00007); /* FIXME */
+		priv->has_big_wep = 0;
+		priv->has_mwo = 0;
+		priv->has_pm = (firmver >= 0x00007); /* FIXME */
+		priv->has_preamble = 0;
+
+		/* Tim Hurley -> D-Link card, vendor 02, firmware 0.08 */
+
+		/* Special case for Symbol cards */
+		if(firmver == 0x10001) {
+			/* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+			vendor_str = "Symbol";
+			/* Intel MAC : 00:02:B3:* */
+			/* 3Com MAC : 00:50:DA:* */
+
+			/* FIXME : probably need to use SYMBOL_***ARY_VER
+			 * to get proper firmware version */
+			priv->firmware_type = FIRMWARE_TYPE_SYMBOL;
+			priv->broken_reset = 0;
+			priv->broken_allocate = 1;
+			priv->has_port3 = 1;
+			priv->has_ibss = 1; /* FIXME */
+			priv->has_wep = 1; /* FIXME */
+			priv->has_big_wep = 1;	/* RID_SYMBOL_KEY_LENGTH */
+			priv->has_mwo = 0;
+			priv->has_pm = 1; /* FIXME */
+			priv->has_preamble = 0; /* FIXME */
+			/* Tested with Intel firmware : v15 => Jean II */
+		}
+		break;
+	case 0x3:
+		vendor_str = "Samsung";
+		/* To check - Should cover Samsung & Compaq */
+
+		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->broken_reset = 0;
+		priv->broken_allocate = 0;
+		priv->has_port3 = 1;
+		priv->has_ibss = 0; /* FIXME: available in later firmwares */
+		priv->has_wep = (firmver >= 0x20000); /* FIXME */
+		priv->has_big_wep = 0; /* FIXME */
+		priv->has_mwo = 0;
+		priv->has_pm = (firmver >= 0x20000); /* FIXME */
+		priv->has_preamble = 0;
+		break;
+	case 0x6:
+		/* D-Link DWL 650, ... */
+		vendor_str = "LinkSys/D-Link";
+		/* D-Link MAC : 00:40:05:* */
+
+		priv->firmware_type = FIRMWARE_TYPE_PRISM2;
+		priv->broken_reset = 0;
+		priv->broken_allocate = 0;
+		priv->has_port3 = 1;
+		priv->has_ibss = (firmver >= 0x00007); /* FIXME */
+		priv->has_wep = (firmver >= 0x00007); /* FIXME */
+		priv->has_big_wep = 0;
+		priv->has_mwo = 0;
+		priv->has_pm = (firmver >= 0x00007); /* FIXME */
+		priv->has_preamble = 0;
+		/* Tested with D-Link firmware 0.07 => Jean II */
+		/* Note : with 0.07, IBSS to a Lucent card seem flaky */
+		break;
+	default:
+		vendor_str = "UNKNOWN";
+
+		priv->firmware_type = 0;
+		priv->broken_reset = 0;
+		priv->broken_allocate = 0;
+		priv->has_port3 = 0;
+		priv->has_ibss = 0;
+		priv->has_wep = 0;
+		priv->has_big_wep = 0;
+		priv->has_mwo = 0;
+		priv->has_pm = 0;
+		priv->has_preamble = 0;
+	}
+
+	printk(KERN_INFO "%s: Firmware ID %02X vendor 0x%x (%s) version %d.%02d\n",
+	       dev->name, priv->firmware_info.id, priv->firmware_info.vendor,
+	       vendor_str, priv->firmware_info.major, priv->firmware_info.minor);
+	
+	if (priv->has_port3)
+		printk(KERN_INFO "%s: Ad-hoc demo mode supported.\n", dev->name);
+	if (priv->has_ibss)
+		printk(KERN_INFO "%s: IEEE standard IBSS ad-hoc mode supported.\n",
+		       dev->name);
+	if (priv->has_wep) {
+		printk(KERN_INFO "%s: WEP supported, ", dev->name);
+		if (priv->has_big_wep)
+			printk("\"128\"-bit key.\n");
+		else
+			printk("40-bit key.\n");
+	}
+
+	/* Get the MAC address */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_MACADDR,
+			      ETH_ALEN, NULL, dev->dev_addr);
+	if (err) {
+		printk(KERN_WARNING "%s: failed to read MAC address!\n",
+		       dev->name);
+		goto out;
+	}
+
+	printk(KERN_INFO "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
+	       dev->name, dev->dev_addr[0], dev->dev_addr[1],
+	       dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
+	       dev->dev_addr[5]);
+
+	/* Get the station name */
+	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNF_NICKNAME,
+			      sizeof(nickbuf), &reclen, &nickbuf);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read station name!n",
+		       dev->name);
+		goto out;
+	}
+	if ( nickbuf.len )
+		len = MIN(IW_ESSID_MAX_SIZE, le16_to_cpu(nickbuf.len));
+	else
+		len = MIN(IW_ESSID_MAX_SIZE, 2 * reclen);
+	memcpy(priv->nick, &nickbuf.val, len);
+	priv->nick[len] = '\0';
+
+	printk(KERN_INFO "%s: Station name \"%s\"\n", dev->name, priv->nick);
+
+	/* Get allowed channels */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNEL_LIST, &priv->channel_mask);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read channel list!\n",
+		       dev->name);
+		goto out;
+	}
+
+	/* Get initial AP density */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &priv->ap_density);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read AP density!\n", dev->name);
+		goto out;
+	}
+
+	/* Get initial RTS threshold */
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_RTS_THRESH, &priv->rts_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read RTS threshold!\n", dev->name);
+		goto out;
+	}
+
+	/* Get initial fragmentation settings */
+	if (priv->has_mwo)
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST,
+					  &priv->mwo_robust);
+	else
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH,
+					  &priv->frag_thresh);
+	if (err) {
+		printk(KERN_ERR "%s: failed to read fragmentation settings!\n", dev->name);
+		goto out;
+	}
+
+	/* Set initial bitrate control*/
+	priv->tx_rate_ctrl = 3;
+
+	/* Power management setup */
+	if (priv->has_pm) {
+		priv->pm_on = 0;
+		priv->pm_mcast = 1;
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD,
+					  &priv->pm_period);
+		if (err) {
+			printk(KERN_ERR "%s: failed to read power management period!\n",
+			       dev->name);
+			goto out;
+		}
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER,
+					  &priv->pm_timeout);
+		if (err) {
+			printk(KERN_ERR "%s: failed to read power management timeout!\n",
+			       dev->name);
+			goto out;
+		}
+	}
+
+	/* Preamble setup */
+	if (priv->has_preamble) {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYMBOL_PREAMBLE, &priv->preamble);
+		if (err)
+			goto out;
+	}
+		
+	/* Set up the default configuration */
+	priv->iw_mode = IW_MODE_INFRA;
+	/* By default use IEEE/IBSS ad-hoc mode if we have it */
+	priv->prefer_port3 = priv->has_port3 && (! priv->has_ibss);
+	set_port_type(priv);
+
+	priv->promiscuous = 0;
+	priv->allmulti = 0;
+	priv->wep_on = 0;
+	priv->tx_key = 0;
+
+	printk(KERN_INFO "%s: ready\n", dev->name);
+
+ out:
+	dldwd_unlock(priv);
+
+	TRACE_EXIT("dldwd");
+
+	return err;
+}
+
+struct net_device_stats *
+dldwd_get_stats(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	
+	return &priv->stats;
+}
+
+struct iw_statistics *
+dldwd_get_wireless_stats(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	hermes_t *hw = &priv->hw;
+	struct iw_statistics *wstats = &priv->wstats;
+	int err = 0;
+	hermes_commsqual_t cq;
+
+	if (!priv->hw_ready)
+		return NULL;
+
+	dldwd_lock(priv);
+
+	if (priv->port_type == 3) {
+		memset(&wstats->qual, 0, sizeof(wstats->qual));
+#ifdef WIRELESS_SPY
+		/* If a spy address is defined, we report stats of the
+		 * first spy address - Jean II */
+		if (priv->spy_number > 0) {
+			wstats->qual.qual = priv->spy_stat[0].qual;
+			wstats->qual.level = priv->spy_stat[0].level;
+			wstats->qual.noise = priv->spy_stat[0].noise;
+			wstats->qual.updated = priv->spy_stat[0].updated;
+		}
+#endif /* WIRELESS_SPY */
+	} else {
+		err = hermes_read_commsqual(hw, USER_BAP, &cq);
+		
+		DEBUG(3, "%s: Global stats = %X-%X-%X\n", dev->name,
+		      cq.qual, cq.signal, cq.noise);
+
+		/* Why are we using MIN/MAX ? We don't really care
+		 * if the value goes above max, because we export the
+		 * raw dBm values anyway. The normalisation should be done
+		 * in user space - Jean II */
+		wstats->qual.qual = MAX(MIN(cq.qual, 0x8b-0x2f), 0);
+		wstats->qual.level = MAX(MIN(cq.signal, 0x8a), 0x2f) - 0x95;
+		wstats->qual.noise = MAX(MIN(cq.noise, 0x8a), 0x2f) - 0x95;
+		wstats->qual.updated = 7;
+	}
+
+	dldwd_unlock(priv);
+
+	if (err)
+		return NULL;
+		
+	return wstats;
+}
+
+#ifdef WIRELESS_SPY
+static inline void dldwd_spy_gather(struct net_device *dev,
+				    u_char *mac,
+				    hermes_commsqual_t *cq)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	int i;
+
+	/* Gather wireless spy statistics: for each packet, compare the
+	 * source address with out list, and if match, get the stats... */
+	for (i = 0; i < priv->spy_number; i++)
+		if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) {
+			priv->spy_stat[i].qual = MAX(MIN(cq->qual, 0x8b-0x2f), 0);
+			priv->spy_stat[i].level = MAX(MIN(cq->signal, 0x8a), 0x2f) - 0x95;
+			priv->spy_stat[i].noise = MAX(MIN(cq->noise, 0x8a), 0x2f) - 0x95;
+			priv->spy_stat[i].updated = 7;
+		}
+}
+#endif /* WIRELESS_SPY */
+
+void
+dldwd_stat_gather( struct net_device *dev,
+		   struct sk_buff *skb,
+		   struct dldwd_frame_hdr *hdr)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	hermes_commsqual_t cq;
+
+	/* Using spy support with lots of Rx packets, like in an
+	 * infrastructure (AP), will really slow down everything, because
+	 * the MAC address must be compared to each entry of the spy list.
+	 * If the user really asks for it (set some address in the
+	 * spy list), we do it, but he will pay the price.
+	 * Note that to get here, you need both WIRELESS_SPY
+	 * compiled in AND some addresses in the list !!!
+	 */
+#ifdef WIRELESS_EXT
+	/* Note : gcc will optimise the whole section away if
+	 * WIRELESS_SPY is not defined... - Jean II */
+	if (
+#ifdef WIRELESS_SPY
+		(priv->spy_number > 0) ||
+#endif
+		0 )
+	{
+		u_char *stats = (u_char *) &(hdr->desc.q_info);
+		/* This code may look strange. Everywhere we are using 16 bit
+		 * ints except here. I've verified that these are are the
+		 * correct values. Please check on PPC - Jean II */
+		cq.signal = stats[1];	/* High order byte */
+		cq.noise = stats[0];	/* Low order byte */
+		cq.qual = stats[0] - stats[1];	/* Better than nothing */
+
+		DEBUG(3, "%s: Packet stats = %X-%X-%X\n", dev->name,
+		      cq.qual, cq.signal, cq.noise);
+
+#ifdef WIRELESS_SPY
+		dldwd_spy_gather(dev, skb->mac.raw + ETH_ALEN, &cq);  
+#endif
+	}
+#endif /* WIRELESS_EXT */
+}
+
+int
+dldwd_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t txfid = priv->txfid;
+	char *p;
+	struct ethhdr *eh;
+	int len, data_len, data_off;
+	struct dldwd_frame_hdr hdr;
+	hermes_response_t resp;
+
+	if (! netif_running(dev)) {
+		printk(KERN_ERR "%s: Tx on stopped device!\n",
+		       dev->name);
+		return 1;
+
+	}
+	
+	if (netif_queue_stopped(dev)) {
+		printk(KERN_ERR "%s: Tx while transmitter busy!\n", 
+		       dev->name);
+		return 1;
+	}
+	
+	dldwd_lock(priv);
+
+	/* Length of the packet body */
+	len = MAX(skb->len - ETH_HLEN, ETH_ZLEN);
+
+	eh = (struct ethhdr *)skb->data;
+
+	/* Build the IEEE 802.11 header */
+	memset(&hdr, 0, sizeof(hdr));
+	memcpy(hdr.p80211.addr1, eh->h_dest, ETH_ALEN);
+	memcpy(hdr.p80211.addr2, eh->h_source, ETH_ALEN);
+	hdr.p80211.frame_ctl = DLDWD_FTYPE_DATA;
+
+	/* Encapsulate Ethernet-II frames */
+	if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */
+		data_len = len;
+		data_off = sizeof(hdr);
+		p = skb->data + ETH_HLEN;
+
+		/* 802.11 header */
+		hdr.p80211.data_len = cpu_to_le16(data_len + ENCAPS_OVERHEAD);
+
+		/* 802.3 header */
+		memcpy(hdr.p8023.h_dest, eh->h_dest, ETH_ALEN);
+		memcpy(hdr.p8023.h_source, eh->h_source, ETH_ALEN);
+		hdr.p8023.h_proto = htons(data_len + ENCAPS_OVERHEAD);
+		
+		/* 802.2 header */
+		memcpy(&hdr.p8022, &encaps_hdr, sizeof(encaps_hdr));
+
+		hdr.ethertype = eh->h_proto;
+		err  = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr),
+					 txfid, 0);
+		if (err) {
+			printk(KERN_ERR
+			       "%s: Error %d writing packet header to BAP\n",
+			       dev->name, err);
+			stats->tx_errors++;
+			goto fail;
+		}
+	} else { /* IEEE 802.3 frame */
+		data_len = len + ETH_HLEN;
+		data_off = P8023_OFFSET;
+		p = skb->data;
+		
+		/* 802.11 header */
+		hdr.p80211.data_len = cpu_to_le16(len);
+		err = hermes_bap_pwrite(hw, USER_BAP, &hdr, P8023_OFFSET,
+					txfid, 0);
+		if (err) {
+			printk(KERN_ERR
+			       "%s: Error %d writing packet header to BAP\n",
+			       dev->name, err);
+			stats->tx_errors++;
+			goto fail;
+		}
+	}
+
+	/* Round up for odd length packets */
+	err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d writing packet data to BAP\n",
+		       dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
+	
+
+	/* Finally, we actually initiate the send */
+	err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, txfid, &resp);
+	if (err) {
+		printk(KERN_ERR "%s: Error %d transmitting packet\n", dev->name, err);
+		stats->tx_errors++;
+		goto fail;
+	}
+
+	dev->trans_start = jiffies;
+	stats->tx_bytes += data_off + data_len;
+
+	netif_stop_queue(dev);
+
+	dldwd_unlock(priv);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+ fail:
+
+	dldwd_unlock(priv);
+	return err;
+}
+
+void
+dldwd_tx_timeout(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	struct net_device_stats *stats = &priv->stats;
+	int err = 0;
+
+	printk(KERN_WARNING "%s: Tx timeout! Resetting card.\n", dev->name);
+
+	stats->tx_errors++;
+
+	err = dldwd_reset(priv);
+	if (err)
+		printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
+		       dev->name, err);
+	else {
+		dev->trans_start = jiffies;
+		netif_wake_queue(dev);
+	}
+}
+
+static int dldwd_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+	int ptype;
+	struct iw_range range;
+	int numrates;
+	int i, k;
+
+	TRACE_ENTER(dev->name);
+
+	err = verify_area(VERIFY_WRITE, rrq->pointer, sizeof(range));
+	if (err)
+		return err;
+
+	rrq->length = sizeof(range);
+
+	dldwd_lock(priv);
+	ptype = priv->port_type;
+	dldwd_unlock(priv);
+
+	memset(&range, 0, sizeof(range));
+
+	/* Much of this shamelessly taken from wvlan_cs.c. No idea
+	 * what it all means -dgibson */
+#if WIRELESS_EXT > 10
+	range.we_version_compiled = WIRELESS_EXT;
+	range.we_version_source = 11;
+#endif /* WIRELESS_EXT > 10 */
+
+	range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+
+	/* Set available channels/frequencies */
+	range.num_channels = NUM_CHANNELS;
+	k = 0;
+	for (i = 0; i < NUM_CHANNELS; i++) {
+		if (priv->channel_mask & (1 << i)) {
+			range.freq[k].i = i + 1;
+			range.freq[k].m = channel_frequency[i] * 100000;
+			range.freq[k].e = 1;
+			k++;
+		}
+		
+		if (k >= IW_MAX_FREQUENCIES)
+			break;
+	}
+	range.num_frequency = k;
+
+	range.sensitivity = 3;
+
+	if ((ptype == 3) && (priv->spy_number == 0)){
+		/* Quality stats meaningless in ad-hoc mode */
+		range.max_qual.qual = 0;
+		range.max_qual.level = 0;
+		range.max_qual.noise = 0;
+	} else {
+		range.max_qual.qual = 0x8b - 0x2f;
+		range.max_qual.level = 0x2f - 0x95 - 1;
+		range.max_qual.noise = 0x2f - 0x95 - 1;
+	}
+
+	err = dldwd_hw_get_bitratelist(priv, &numrates,
+				       range.bitrate, IW_MAX_BITRATES);
+	if (err)
+		return err;
+	range.num_bitrates = numrates;
+	
+	/* Set an indication of the max TCP throughput in bit/s that we can
+	 * expect using this interface. May be use for QoS stuff...
+	 * Jean II */
+	if(numrates > 2)
+		range.throughput = 5 * 1000 * 1000;	/* ~5 Mb/s */
+	else
+		range.throughput = 1.5 * 1000 * 1000;	/* ~1.5 Mb/s */
+
+	range.min_rts = 0;
+	range.max_rts = 2347;
+	range.min_frag = 256;
+	range.max_frag = 2346;
+
+	dldwd_lock(priv);
+	if (priv->has_wep) {
+		range.max_encoding_tokens = MAX_KEYS;
+
+		range.encoding_size[0] = SMALL_KEY_SIZE;
+		range.num_encoding_sizes = 1;
+
+		if (priv->has_big_wep) {
+			range.encoding_size[1] = LARGE_KEY_SIZE;
+			range.num_encoding_sizes = 2;
+		}
+	} else {
+		range.num_encoding_sizes = 0;
+		range.max_encoding_tokens = 0;
+	}
+	dldwd_unlock(priv);
+		
+	range.min_pmp = 0;
+	range.max_pmp = 65535000;
+	range.min_pmt = 0;
+	range.max_pmt = 65535 * 1000;	/* ??? */
+	range.pmp_flags = IW_POWER_PERIOD;
+	range.pmt_flags = IW_POWER_TIMEOUT;
+	range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+	range.num_txpower = 1;
+	range.txpower[0] = 15; /* 15dBm */
+	range.txpower_capa = IW_TXPOW_DBM;
+
+#if WIRELESS_EXT > 10
+	range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+	range.retry_flags = IW_RETRY_LIMIT;
+	range.r_time_flags = IW_RETRY_LIFETIME;
+	range.min_retry = 0;
+	range.max_retry = 65535;	/* ??? */
+	range.min_r_time = 0;
+	range.max_r_time = 65535 * 1000;	/* ??? */
+#endif /* WIRELESS_EXT > 10 */
+
+	if (copy_to_user(rrq->pointer, &range, sizeof(range)))
+		return -EFAULT;
+
+	TRACE_EXIT(dev->name);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	int setindex = priv->tx_key;
+	int enable = priv->wep_on;
+	int restricted = priv->wep_restrict;
+	uint16_t xlen = 0;
+	int err = 0;
+	char keybuf[MAX_KEY_SIZE];
+
+	if (erq->pointer) {
+		/* We actually have a key to set */
+		
+		if (copy_from_user(keybuf, erq->pointer, erq->length))
+			return -EFAULT;
+	}
+	
+	dldwd_lock(priv);
+	
+	if (erq->pointer) {
+		if (erq->length > MAX_KEY_SIZE) {
+			err = -E2BIG;
+			goto out;
+		}
+		
+		if ( (erq->length > LARGE_KEY_SIZE)
+		     || ( ! priv->has_big_wep && (erq->length > SMALL_KEY_SIZE))  ) {
+			err = -EINVAL;
+			goto out;
+		}
+		
+		if ((index < 0) || (index >= MAX_KEYS))
+			index = priv->tx_key;
+		
+		if (erq->length > SMALL_KEY_SIZE) {
+			xlen = LARGE_KEY_SIZE;
+		} else if (erq->length > 0) {
+			xlen = SMALL_KEY_SIZE;
+		} else
+			xlen = 0;
+		
+		/* Switch on WEP if off */
+		if ((!enable) && (xlen > 0)) {
+			setindex = index;
+			enable = 1;
+		}
+	} else {
+		/* Important note : if the user do "iwconfig eth0 enc off",
+		 * we will arrive there with an index of -1. This is valid
+		 * but need to be taken care off... Jean II */
+		if ((index < 0) || (index >= MAX_KEYS)) {
+			if((index != -1) || (erq->flags == 0)) {
+				err = -EINVAL;
+				goto out;
+			}
+		} else {
+			/* Set the index : Check that the key is valid */
+			if(priv->keys[index].len == 0) {
+				err = -EINVAL;
+				goto out;
+			}
+			setindex = index;
+		}
+	}
+	
+	if (erq->flags & IW_ENCODE_DISABLED)
+		enable = 0;
+	/* Only for Prism2 & Symbol cards (so far) - Jean II */
+	if (erq->flags & IW_ENCODE_OPEN)
+		restricted = 0;
+	if (erq->flags & IW_ENCODE_RESTRICTED)
+		restricted = 1;
+
+	if (erq->pointer) {
+		priv->keys[index].len = cpu_to_le16(xlen);
+		memset(priv->keys[index].data, 0, sizeof(priv->keys[index].data));
+		memcpy(priv->keys[index].data, keybuf, erq->length);
+	}
+	priv->tx_key = setindex;
+	priv->wep_on = enable;
+	priv->wep_restrict = restricted;
+	
+ out:
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int index = (erq->flags & IW_ENCODE_INDEX) - 1;
+	uint16_t xlen = 0;
+	char keybuf[MAX_KEY_SIZE];
+
+	
+	dldwd_lock(priv);
+
+	if ((index < 0) || (index >= MAX_KEYS))
+		index = priv->tx_key;
+
+	erq->flags = 0;
+	if (! priv->wep_on)
+		erq->flags |= IW_ENCODE_DISABLED;
+	erq->flags |= index + 1;
+	
+	/* Only for symbol cards - Jean II */
+	if (priv->firmware_type != FIRMWARE_TYPE_LUCENT) {
+		if(priv->wep_restrict)
+			erq->flags |= IW_ENCODE_RESTRICTED;
+		else
+			erq->flags |= IW_ENCODE_OPEN;
+	}
+
+	xlen = le16_to_cpu(priv->keys[index].len);
+
+	erq->length = xlen;
+
+	if (erq->pointer) {
+		memcpy(keybuf, priv->keys[index].data, MAX_KEY_SIZE);
+	}
+	
+	dldwd_unlock(priv);
+
+	if (erq->pointer) {
+		if (copy_to_user(erq->pointer, keybuf, xlen))
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int dldwd_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char essidbuf[IW_ESSID_MAX_SIZE+1];
+
+	/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
+	 * anyway... - Jean II */
+
+	memset(&essidbuf, 0, sizeof(essidbuf));
+
+	if (erq->flags) { 
+		if (erq->length > IW_ESSID_MAX_SIZE)
+			return -E2BIG;
+		
+		if (copy_from_user(&essidbuf, erq->pointer, erq->length))
+			return -EFAULT;
+
+		essidbuf[erq->length] = '\0';
+	}
+
+	dldwd_lock(priv);
+
+	memcpy(priv->desired_essid, essidbuf, IW_ESSID_MAX_SIZE+1);
+
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char essidbuf[IW_ESSID_MAX_SIZE+1];
+	int active;
+	int err = 0;
+
+	TRACE_ENTER(dev->name);
+
+	err = dldwd_hw_get_essid(priv, &active, essidbuf);
+	if (err)
+		return err;
+
+	erq->flags = 1;
+	erq->length = strlen(essidbuf) + 1;
+	if (erq->pointer)
+		if ( copy_to_user(erq->pointer, essidbuf, erq->length) )
+			return -EFAULT;
+
+	TRACE_EXIT(dev->name);
+	
+	return 0;
+}
+
+static int dldwd_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char nickbuf[IW_ESSID_MAX_SIZE+1];
+
+	if (nrq->length > IW_ESSID_MAX_SIZE)
+		return -E2BIG;
+
+	memset(nickbuf, 0, sizeof(nickbuf));
+
+	if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
+		return -EFAULT;
+
+	nickbuf[nrq->length] = '\0';
+	
+	dldwd_lock(priv);
+
+	memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	char nickbuf[IW_ESSID_MAX_SIZE+1];
+
+	dldwd_lock(priv);
+	memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
+	dldwd_unlock(priv);
+
+	nrq->length = strlen(nickbuf)+1;
+
+	if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int dldwd_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int chan = -1;
+
+	/* We can only use this in Ad-Hoc demo mode to set the operating
+	 * frequency, or in IBSS mode to set the frequency where the IBSS
+	 * will be created - Jean II */
+	if (priv->iw_mode != IW_MODE_ADHOC)
+		return -EOPNOTSUPP;
+
+	if ( (frq->e == 0) && (frq->m <= 1000) ) {
+		/* Setting by channel number */
+		chan = frq->m;
+	} else {
+		/* Setting by frequency - search the table */
+		int mult = 1;
+		int i;
+
+		for (i = 0; i < (6 - frq->e); i++)
+			mult *= 10;
+
+		for (i = 0; i < NUM_CHANNELS; i++)
+			if (frq->m == (channel_frequency[i] * mult))
+				chan = i+1;
+	}
+
+	if ( (chan < 1) || (chan > NUM_CHANNELS) ||
+	     ! (priv->channel_mask & (1 << (chan-1)) ) )
+		return -EINVAL;
+
+	dldwd_lock(priv);
+	priv->channel = chan;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	uint16_t val;
+	int err;
+
+	dldwd_lock(priv);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_SYSTEM_SCALE, &val);
+	dldwd_unlock(priv);
+
+	if (err)
+		return err;
+
+	srq->value = val;
+	srq->fixed = 0; /* auto */
+
+	return 0;
+}
+
+static int dldwd_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = srq->value;
+
+	if ((val < 1) || (val > 3))
+		return -EINVAL;
+	
+	dldwd_lock(priv);
+	priv->ap_density = val;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = rrq->value;
+
+	if (rrq->disabled)
+		val = 2347;
+
+	if ( (val < 0) || (val > 2347) )
+		return -EINVAL;
+
+	dldwd_lock(priv);
+	priv->rts_thresh = val;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+static int dldwd_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+
+	dldwd_lock(priv);
+
+	if (priv->has_mwo) {
+		if (frq->disabled)
+			priv->mwo_robust = 0;
+		else {
+			if (frq->fixed)
+				printk(KERN_WARNING "%s: Fixed fragmentation not \
+supported on this firmware. Using MWO robust instead.\n", dev->name);
+			priv->mwo_robust = 1;
+		}
+	} else {
+		if (frq->disabled)
+			priv->frag_thresh = 2346;
+		else {
+			if ( (frq->value < 256) || (frq->value > 2346) )
+				err = -EINVAL;
+			else
+				priv->frag_thresh = frq->value & ~0x1; /* must be even */
+		}
+	}
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t val;
+
+	dldwd_lock(priv);
+	
+	if (priv->has_mwo) {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_MWO_ROBUST, &val);
+		if (err)
+			val = 0;
+
+		frq->value = val ? 2347 : 0;
+		frq->disabled = ! val;
+		frq->fixed = 0;
+	} else {
+		err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_FRAG_THRESH, &val);
+		if (err)
+			val = 0;
+
+		frq->value = val;
+		frq->disabled = (val >= 2346);
+		frq->fixed = 1;
+	}
+
+	dldwd_unlock(priv);
+	
+	return err;
+}
+
+static int dldwd_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+	int rate_ctrl = -1;
+	int fixed, upto;
+	int brate;
+	int i;
+
+	dldwd_lock(priv);
+
+	/* Normalise value */
+	brate = rrq->value / 500000;
+
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
+		if (! rrq->fixed) {
+			if (brate > 0)
+				brate = -brate;
+			else
+				brate = -22;
+		}
+	
+		for (i = 0; i < NUM_RATES; i++)
+			if (rate_list[i] == brate) {
+				rate_ctrl = i;
+				break;
+			}
+	
+		if ( (rate_ctrl < 1) || (rate_ctrl >= NUM_RATES) )
+			err = -EINVAL;
+		else
+			priv->tx_rate_ctrl = rate_ctrl;
+		break;
+	case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+		switch(brate) {
+		case 0:
+			fixed = 0x0;
+			upto = 0x15;
+			break;
+		case 2:
+			fixed = 0x1;
+			upto = 0x1;
+			break;
+		case 4:
+			fixed = 0x2;
+			upto = 0x3;
+			break;
+		case 11:
+			fixed = 0x4;
+			upto = 0x7;
+			break;
+		case 22:
+			fixed = 0x8;
+			upto = 0x15;
+			break;
+		default:
+			fixed = 0x0;
+			upto = 0x0;
+		}
+		if (rrq->fixed)
+			rate_ctrl = fixed;
+		else
+			rate_ctrl = upto;
+		if (rate_ctrl == 0)
+			err = -EINVAL;
+		else
+			priv->tx_rate_ctrl = rate_ctrl;
+		break;
+	}
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t val;
+	int brate = 0;
+
+	dldwd_lock(priv);
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_TX_RATE_CTRL, &val);
+	if (err)
+		goto out;
+	
+	switch (priv->firmware_type) {
+	case FIRMWARE_TYPE_LUCENT: /* Lucent style rate */
+		brate = rate_list[val];
+	
+		if (brate < 0) {
+			rrq->fixed = 0;
+
+			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
+			if (err)
+				goto out;
+
+			if (val == 6)
+				brate = 11;
+			else
+				brate = 2*val;
+		} else
+			rrq->fixed = 1;
+		break;
+	case FIRMWARE_TYPE_PRISM2: /* Prism II style rate */
+	case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
+		/* Check if auto or fixed (crude approximation) */
+		if((val & 0x1) && (val > 1)) {
+			rrq->fixed = 0;
+
+			err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENT_TX_RATE, &val);
+			if (err)
+				goto out;
+		} else
+			rrq->fixed = 1;
+
+		if(val >= 8)
+			brate = 22;
+		else if(val >= 4)
+			brate = 11;
+		else if(val >= 2)
+			brate = 4;
+		else
+			brate = 2;
+		break;
+	}
+
+	rrq->value = brate * 500000;
+	rrq->disabled = 0;
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int err = 0;
+
+
+	dldwd_lock(priv);
+
+	if (prq->disabled) {
+		priv->pm_on = 0;
+	} else {
+		switch (prq->flags & IW_POWER_MODE) {
+		case IW_POWER_UNICAST_R:
+			priv->pm_mcast = 0;
+			priv->pm_on = 1;
+			break;
+		case IW_POWER_ALL_R:
+			priv->pm_mcast = 1;
+			priv->pm_on = 1;
+			break;
+		case IW_POWER_ON:
+			/* No flags : but we may have a value - Jean II */
+			break;
+		default:
+			err = -EINVAL;
+		}
+		if (err)
+			goto out;
+		
+		if (prq->flags & IW_POWER_TIMEOUT) {
+			priv->pm_on = 1;
+			priv->pm_timeout = prq->value / 1000;
+		}
+		if (prq->flags & IW_POWER_PERIOD) {
+			priv->pm_on = 1;
+			priv->pm_period = prq->value / 1000;
+		}
+		/* It's valid to not have a value if we are just toggling
+		 * the flags... Jean II */
+		if(!priv->pm_on) {
+			err = -EINVAL;
+			goto out;
+		}			
+	}
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t enable, period, timeout, mcast;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_ENABLE, &enable);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_PERIOD, &period);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_HOLDOVER, &timeout);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNF_PM_MCAST_RX, &mcast);
+	if (err)
+		goto out;
+
+	prq->disabled = !enable;
+	/* Note : by default, display the period */
+	if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+		prq->flags = IW_POWER_TIMEOUT;
+		prq->value = timeout * 1000;
+	} else {
+		prq->flags = IW_POWER_PERIOD;
+		prq->value = period * 1000;
+	}
+	if (mcast)
+		prq->flags |= IW_POWER_ALL_R;
+	else
+		prq->flags |= IW_POWER_UNICAST_R;
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+#if WIRELESS_EXT > 10
+static int dldwd_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	uint16_t short_limit, long_limit, lifetime;
+
+	dldwd_lock(priv);
+	
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_SHORT_RETRY_LIMIT, &short_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_LONG_RETRY_LIMIT, &long_limit);
+	if (err)
+		goto out;
+
+	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_MAX_TX_LIFETIME, &lifetime);
+	if (err)
+		goto out;
+
+	rrq->disabled = 0;		/* Can't be disabled */
+
+	/* Note : by default, display the retry number */
+	if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
+		rrq->flags = IW_RETRY_LIFETIME;
+		rrq->value = lifetime * 1000;	/* ??? */
+	} else {
+		/* By default, display the min number */
+		if ((rrq->flags & IW_RETRY_MAX)) {
+			rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+			rrq->value = long_limit;
+		} else {
+			rrq->flags = IW_RETRY_LIMIT;
+			rrq->value = short_limit;
+			if(short_limit != long_limit)
+				rrq->flags |= IW_RETRY_MIN;
+		}
+	}
+
+ out:
+	dldwd_unlock(priv);
+
+	return err;
+}
+#endif /* WIRELESS_EXT > 10 */
+
+static int dldwd_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int val = *( (int *) wrq->u.name );
+	int err = 0;
+
+	dldwd_lock(priv);
+	switch (val) {
+	case 0: /* Try to do IEEE ad-hoc mode */
+		if (! priv->has_ibss) {
+			err = -EINVAL;
+			break;
+		}
+		DEBUG(2, "%s: Prefer IBSS Ad-Hoc mode\n", dev->name);
+		priv->prefer_port3 = 0;
+			
+		break;
+
+	case 1: /* Try to do Lucent proprietary ad-hoc mode */
+		if (! priv->has_port3) {
+			err = -EINVAL;
+			break;
+		}
+		DEBUG(2, "%s: Prefer Ad-Hoc demo mode\n", dev->name);
+		priv->prefer_port3 = 1;
+		break;
+
+	default:
+		err = -EINVAL;
+	}
+
+	if (! err)
+		/* Actually update the mode we are using */
+		set_port_type(priv);
+
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	int *val = (int *)wrq->u.name;
+
+	dldwd_lock(priv);
+	*val = priv->prefer_port3;
+	dldwd_unlock(priv);
+
+	return 0;
+}
+
+/* Spy is used for link quality/strength measurements in Ad-Hoc mode
+ * Jean II */
+static int dldwd_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	struct sockaddr address[IW_MAX_SPY];
+	int number = srq->length;
+	int i;
+	int err = 0;
+
+	/* Check the number of addresses */
+	if (number > IW_MAX_SPY)
+		return -E2BIG;
+
+	/* Get the data in the driver */
+	if (srq->pointer) {
+		if (copy_from_user(address, srq->pointer,
+				   sizeof(struct sockaddr) * number))
+			return -EFAULT;
+	}
+
+	/* Make sure nobody mess with the structure while we do */
+	dldwd_lock(priv);
+
+	/* dldwd_lock() doesn't disable interrupts, so make sure the
+	 * interrupt rx path don't get confused while we copy */
+	priv->spy_number = 0;
+
+	if (number > 0) {
+		/* Extract the addresses */
+		for (i = 0; i < number; i++)
+			memcpy(priv->spy_address[i], address[i].sa_data,
+			       ETH_ALEN);
+		/* Reset stats */
+		memset(priv->spy_stat, 0,
+		       sizeof(struct iw_quality) * IW_MAX_SPY);
+		/* Set number of addresses */
+		priv->spy_number = number;
+	}
+
+	/* Time to show what we have done... */
+	DEBUG(0, "%s: New spy list:\n", dev->name);
+	for (i = 0; i < number; i++) {
+		DEBUG(0, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n",
+		      dev->name, i+1,
+		      priv->spy_address[i][0], priv->spy_address[i][1],
+		      priv->spy_address[i][2], priv->spy_address[i][3],
+		      priv->spy_address[i][4], priv->spy_address[i][5]);
+	}
+
+	/* Now, let the others play */
+	dldwd_unlock(priv);
+
+	return err;
+}
+
+static int dldwd_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+{
+	dldwd_priv_t *priv = dev->priv;
+	struct sockaddr address[IW_MAX_SPY];
+	struct iw_quality spy_stat[IW_MAX_SPY];
+	int number;
+	int i;
+
+	dldwd_lock(priv);
+
+	number = priv->spy_number;
+	if ((number > 0) && (srq->pointer)) {
+		/* Create address struct */
+		for (i = 0; i < number; i++) {
+			memcpy(address[i].sa_data, priv->spy_address[i],
+			       ETH_ALEN);
+			address[i].sa_family = AF_UNIX;
+		}
+		/* Copy stats */
+		/* In theory, we should disable irqs while copying the stats
+		 * because the rx path migh update it in the middle...
+		 * Bah, who care ? - Jean II */
+		memcpy(&spy_stat, priv->spy_stat,
+		       sizeof(struct iw_quality) * IW_MAX_SPY);
+		for (i=0; i < number; i++)
+			priv->spy_stat[i].updated = 0;
+	}
+
+	dldwd_unlock(priv);
+
+	/* Push stuff to user space */
+	srq->length = number;
+	if(copy_to_user(srq->pointer, address,
+			 sizeof(struct sockaddr) * number))
+		return -EFAULT;
+	if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
+			&spy_stat, sizeof(struct iw_quality) * number))
+		return -EFAULT;
+
+	return 0;
+}
+
+int
+dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	dldwd_priv_t *priv = dev->priv;
+	struct iwreq *wrq = (struct iwreq *)rq;
+	int err = 0;
+	int changed = 0;
+
+	TRACE_ENTER(dev->name);
+
+	/* In theory, we could allow most of the the SET stuff to be done
+	 * In practice, the laps of time at startup when the card is not
+	 * ready is very short, so why bother...
+	 * Note that hw_ready is different from up/down (ifconfig), when
+	 * the device is not yet up, it is usually already ready...
+	 * Jean II */
+	if (!priv->hw_ready)
+		return -ENODEV;
+
+	switch (cmd) {
+	case SIOCGIWNAME:
+		DEBUG(1, "%s: SIOCGIWNAME\n", dev->name);
+		strcpy(wrq->u.name, "IEEE 802.11-DS");
+		break;
+		
+	case SIOCGIWAP:
+		DEBUG(1, "%s: SIOCGIWAP\n", dev->name);
+		wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+		err = dldwd_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
+		break;
+
+	case SIOCGIWRANGE:
+		DEBUG(1, "%s: SIOCGIWRANGE\n", dev->name);
+		err = dldwd_ioctl_getiwrange(dev, &wrq->u.data);
+		break;
+
+	case SIOCSIWMODE:
+		DEBUG(1, "%s: SIOCSIWMODE\n", dev->name);
+		dldwd_lock(priv);
+		switch (wrq->u.mode) {
+		case IW_MODE_ADHOC:
+			if (! (priv->has_ibss || priv->has_port3) )
+				err = -EINVAL;
+			else {
+				priv->iw_mode = IW_MODE_ADHOC;
+				changed = 1;
+			}
+			break;
+
+		case IW_MODE_INFRA:
+			priv->iw_mode = IW_MODE_INFRA;
+			changed = 1;
+			break;
+
+		default:
+			err = -EINVAL;
+			break;
+		}
+		set_port_type(priv);
+		dldwd_unlock(priv);
+		break;
+
+	case SIOCGIWMODE:
+		DEBUG(1, "%s: SIOCGIWMODE\n", dev->name);
+		dldwd_lock(priv);
+		wrq->u.mode = priv->iw_mode;
+		dldwd_unlock(priv);
+		break;
+
+	case SIOCSIWENCODE:
+		DEBUG(1, "%s: SIOCSIWENCODE\n", dev->name);
+		if (! priv->has_wep) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+
+		err = dldwd_ioctl_setiwencode(dev, &wrq->u.encoding);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWENCODE:
+		DEBUG(1, "%s: SIOCGIWENCODE\n", dev->name);
+		if (! priv->has_wep) {
+			err = -EOPNOTSUPP;
+			break;
+		}
+
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		err = dldwd_ioctl_getiwencode(dev, &wrq->u.encoding);
+		break;
+
+	case SIOCSIWESSID:
+		DEBUG(1, "%s: SIOCSIWESSID\n", dev->name);
+		err = dldwd_ioctl_setessid(dev, &wrq->u.essid);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWESSID:
+		DEBUG(1, "%s: SIOCGIWESSID\n", dev->name);
+		err = dldwd_ioctl_getessid(dev, &wrq->u.essid);
+		break;
+
+	case SIOCSIWNICKN:
+		DEBUG(1, "%s: SIOCSIWNICKN\n", dev->name);
+		err = dldwd_ioctl_setnick(dev, &wrq->u.data);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWNICKN:
+		DEBUG(1, "%s: SIOCGIWNICKN\n", dev->name);
+		err = dldwd_ioctl_getnick(dev, &wrq->u.data);
+		break;
+
+	case SIOCGIWFREQ:
+		DEBUG(1, "%s: SIOCGIWFREQ\n", dev->name);
+		wrq->u.freq.m = dldwd_hw_get_freq(priv);
+		wrq->u.freq.e = 1;
+		break;
+
+	case SIOCSIWFREQ:
+		DEBUG(1, "%s: SIOCSIWFREQ\n", dev->name);
+		err = dldwd_ioctl_setfreq(dev, &wrq->u.freq);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWSENS:
+		DEBUG(1, "%s: SIOCGIWSENS\n", dev->name);
+		err = dldwd_ioctl_getsens(dev, &wrq->u.sens);
+		break;
+
+	case SIOCSIWSENS:
+		DEBUG(1, "%s: SIOCSIWSENS\n", dev->name);
+		err = dldwd_ioctl_setsens(dev, &wrq->u.sens);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWRTS:
+		DEBUG(1, "%s: SIOCGIWRTS\n", dev->name);
+		wrq->u.rts.value = priv->rts_thresh;
+		wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
+		wrq->u.rts.fixed = 1;
+		break;
+
+	case SIOCSIWRTS:
+		DEBUG(1, "%s: SIOCSIWRTS\n", dev->name);
+		err = dldwd_ioctl_setrts(dev, &wrq->u.rts);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCSIWFRAG:
+		DEBUG(1, "%s: SIOCSIWFRAG\n", dev->name);
+		err = dldwd_ioctl_setfrag(dev, &wrq->u.frag);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWFRAG:
+		DEBUG(1, "%s: SIOCGIWFRAG\n", dev->name);
+		err = dldwd_ioctl_getfrag(dev, &wrq->u.frag);
+		break;
+
+	case SIOCSIWRATE:
+		DEBUG(1, "%s: SIOCSIWRATE\n", dev->name);
+		err = dldwd_ioctl_setrate(dev, &wrq->u.bitrate);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWRATE:
+		DEBUG(1, "%s: SIOCGIWRATE\n", dev->name);
+		err = dldwd_ioctl_getrate(dev, &wrq->u.bitrate);
+		break;
+
+	case SIOCSIWPOWER:
+		DEBUG(1, "%s: SIOCSIWPOWER\n", dev->name);
+		err = dldwd_ioctl_setpower(dev, &wrq->u.power);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCGIWPOWER:
+		DEBUG(1, "%s: SIOCGIWPOWER\n", dev->name);
+		err = dldwd_ioctl_getpower(dev, &wrq->u.power);
+		break;
+
+	case SIOCGIWTXPOW:
+		DEBUG(1, "%s: SIOCGIWTXPOW\n", dev->name);
+		/* The card only supports one tx power, so this is easy */
+		wrq->u.txpower.value = 15; /* dBm */
+		wrq->u.txpower.fixed = 1;
+		wrq->u.txpower.disabled = 0;
+		wrq->u.txpower.flags = IW_TXPOW_DBM;
+		break;
+
+#if WIRELESS_EXT > 10
+	case SIOCSIWRETRY:
+		DEBUG(1, "%s: SIOCSIWRETRY\n", dev->name);
+		err = -EOPNOTSUPP;
+		break;
+
+	case SIOCGIWRETRY:
+		DEBUG(1, "%s: SIOCGIWRETRY\n", dev->name);
+		err = dldwd_ioctl_getretry(dev, &wrq->u.retry);
+		break;
+#endif /* WIRELESS_EXT > 10 */
+
+	case SIOCSIWSPY:
+		DEBUG(1, "%s: SIOCSIWSPY\n", dev->name);
+
+		err = dldwd_ioctl_setspy(dev, &wrq->u.data);
+		break;
+
+	case SIOCGIWSPY:
+		DEBUG(1, "%s: SIOCGIWSPY\n", dev->name);
+
+		err = dldwd_ioctl_getspy(dev, &wrq->u.data);
+		break;
+
+	case SIOCGIWPRIV:
+		DEBUG(1, "%s: SIOCGIWPRIV\n", dev->name);
+		if (wrq->u.data.pointer) {
+			struct iw_priv_args privtab[] = {
+				{ SIOCDEVPRIVATE + 0x0, 0, 0, "force_reset" },
+				{ SIOCDEVPRIVATE + 0x2,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  0, "set_port3" },
+				{ SIOCDEVPRIVATE + 0x3, 0,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  "get_port3" },
+				{ SIOCDEVPRIVATE + 0x4,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  0, "set_preamble" },
+				{ SIOCDEVPRIVATE + 0x5, 0,
+				  IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+				  "get_preamble" }
+			};
+
+			err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab));
+			if (err)
+				break;
+			
+			wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
+			if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
+				err = -EFAULT;
+		}
+		break;
+	       
+	case SIOCDEVPRIVATE + 0x0: /* force_reset */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x0 (force_reset)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+		
+		printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+		dldwd_reset(priv);
+		break;
+
+	case SIOCDEVPRIVATE + 0x2: /* set_port3 */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x2 (set_port3)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		err = dldwd_ioctl_setport3(dev, wrq);
+		if (! err)
+			changed = 1;
+		break;
+
+	case SIOCDEVPRIVATE + 0x3: /* get_port3 */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x3 (get_port3)\n",
+		      dev->name);
+		err = dldwd_ioctl_getport3(dev, wrq);
+		break;
+
+	case SIOCDEVPRIVATE + 0x4: /* set_preamble */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x4 (set_preamble)\n",
+		      dev->name);
+		if (! capable(CAP_NET_ADMIN)) {
+			err = -EPERM;
+			break;
+		}
+
+		/* 802.11b has recently defined some short preamble.
+		 * Basically, the Phy header has been reduced in size.
+		 * This increase performance, especially at high rates
+		 * (the preamble is transmitted at 1Mb/s), unfortunately
+		 * this give compatibility troubles... - Jean II */
+		if(priv->has_preamble) {
+			int val = *( (int *) wrq->u.name );
+
+			dldwd_lock(priv);
+			if(val)
+				priv->preamble = 1;
+			else
+				priv->preamble = 0;
+			dldwd_unlock(priv);
+			changed = 1;
+		} else
+			err = -EOPNOTSUPP;
+		break;
+
+	case SIOCDEVPRIVATE + 0x5: /* get_preamble */
+		DEBUG(1, "%s: SIOCDEVPRIVATE + 0x5 (get_preamble)\n",
+		      dev->name);
+		if(priv->has_preamble) {
+			int *val = (int *)wrq->u.name;
+
+			dldwd_lock(priv);
+			*val = priv->preamble;
+			dldwd_unlock(priv);
+		} else
+			err = -EOPNOTSUPP;
+		break;
+
+	default:
+		err = -EOPNOTSUPP;
+	}
+	
+	if (! err && changed && netif_running(dev)) {
+		err = dldwd_reset(priv);
+		if (err) {
+			/* Ouch ! What are we supposed to do ? */
+			printk(KERN_ERR "orinoco_cs: Failed to set parameters on %s\n",
+			       dev->name);
+			netif_stop_queue(dev);
+			dldwd_shutdown(priv);
+			priv->hw_ready = 0;
+		}
+	}		
+
+	TRACE_EXIT(dev->name);
+		
+	return err;
+}
+
+int
+dldwd_change_mtu(struct net_device *dev, int new_mtu)
+{
+	TRACE_ENTER(dev->name);
+
+	if ( (new_mtu < DLDWD_MIN_MTU) || (new_mtu > DLDWD_MAX_MTU) )
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	TRACE_EXIT(dev->name);
+
+	return 0;
+}
+
+static void
+__dldwd_set_multicast_list(struct net_device *dev)
+{
+	dldwd_priv_t *priv = dev->priv;
+	hermes_t *hw = &priv->hw;
+	int err = 0;
+	int promisc, allmulti, mc_count;
+
+	/* We'll wait until it's ready. Anyway, the network doesn't call us
+	 * here until we are open - Jean II */
+	if (!priv->hw_ready)
+		return;
+
+
+	TRACE_ENTER(dev->name);
+
+	DEBUG(3, "dev->flags=0x%x, priv->promiscuous=%d, dev->mc_count=%d priv->mc_count=%d\n",
+	      dev->flags, priv->promiscuous, dev->mc_count, priv->mc_count);
+
+	/* The Hermes doesn't seem to have an allmulti mode, so we go
+	 * into promiscuous mode and let the upper levels deal. */
+	if ( (dev->flags & IFF_PROMISC) ) {
+		promisc = 1;
+		allmulti = 0;
+		mc_count = 0;
+	} else if ( (dev->flags & IFF_ALLMULTI) ||
+		    (dev->mc_count > HERMES_MAX_MULTICAST) ) {
+		promisc = 0;
+		allmulti = 1;
+		mc_count = HERMES_MAX_MULTICAST;
+	} else {
+		promisc = 0;
+		allmulti = 0;
+		mc_count = dev->mc_count;
+	}
+
+	DEBUG(3, "promisc=%d mc_count=%d\n",
+	      promisc, mc_count);
+
+	if (promisc != priv->promiscuous) { /* Don't touch the hardware if we don't have to */
+		err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNF_PROMISCUOUS,
+					   promisc);
+		if (err) {
+			printk(KERN_ERR "%s: Error %d setting promiscuity to %d.\n",
+			       dev->name, err, promisc);
+		} else 
+			priv->promiscuous = promisc;
+	}
+
+	if (allmulti) {
+		/* FIXME: This method of doing allmulticast reception
+		   comes from the NetBSD driver. Haven't actually
+		   tested whether it works or not. */
+		hermes_multicast_t mclist;
+
+		memset(&mclist, 0, sizeof(mclist));
+		err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST, &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       dev->name, err);
+		else
+			priv->allmulti = 1;
+		       
+	} else if (mc_count || (! mc_count && priv->mc_count) ) {
+		struct dev_mc_list *p = dev->mc_list;
+		hermes_multicast_t mclist;
+		int i;
+
+		for (i = 0; i < mc_count; i++) {
+			/* First some paranoid checks */
+			if (! p) {
+				printk(KERN_ERR "%s: Multicast list shorter than mc_count.\n",
+				       dev->name);
+				break;
+			}
+			if (p->dmi_addrlen != ETH_ALEN) {
+
+				printk(KERN_ERR "%s: Bad address size (%d) in multicast list.\n",
+				       dev->name, p->dmi_addrlen);
+				break;
+			}
+
+			memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
+			p = p->next;
+		}
+
+		/* More paranoia */
+		if (p)
+			printk(KERN_ERR "%s: Multicast list longer than mc_count.\n",
+			       dev->name);
+
+		priv->mc_count = i;			
+
+		DEBUG(3, "priv->mc_count = %d\n", priv->mc_count);
+
+		err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNF_MULTICAST_LIST,
+				       HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN),
+				       &mclist);
+		if (err)
+			printk(KERN_ERR "%s: Error %d setting multicast list.\n",
+			       dev->name, err);
+		else
+			priv->allmulti = 0;
+	}
+
+	/* Since we can set the promiscuous flag when it wasn't asked
+	   for, make sure the net_device knows about it. */
+	if (priv->promiscuous)
+		dev->flags |= IFF_PROMISC;
+	else
+		dev->flags &= ~IFF_PROMISC;
+
+	if (priv->allmulti)
+		dev->flags |= IFF_ALLMULTI;
+	else
+		dev->flags &= ~IFF_ALLMULTI;
+
+	TRACE_EXIT(dev->name);
+}
+
+/*
+ * procfs stuff
+ */
+
+static struct proc_dir_entry *dir_base = NULL;
+
+/*
+ * This function updates the total amount of data printed so far. It then
+ * determines if the amount of data printed into a buffer  has reached the
+ * offset requested. If it hasn't, then the buffer is shifted over so that
+ * the next bit of data can be printed over the old bit. If the total
+ * amount printed so far exceeds the total amount requested, then this
+ * function returns 1, otherwise 0.
+ */
+static int 
+
+shift_buffer(char *buffer, int requested_offset, int requested_len,
+	     int *total, int *slop, char **buf)
+{
+	int printed;
+	
+	printed = *buf - buffer;
+	if (*total + printed <= requested_offset) {
+		*total += printed;
+		*buf = buffer;
+	}
+	else {
+		if (*total < requested_offset) {
+			*slop = requested_offset - *total;
+		}
+		*total = requested_offset + printed - *slop;
+	}
+	if (*total > requested_offset + requested_len) {
+		return 1;
+	}
+	else {
+		return 0;
+	}
+}
+
+/*
+ * This function calculates the actual start of the requested data
+ * in the buffer. It also calculates actual length of data returned,
+ * which could be less that the amount of data requested.
+ */
+#define PROC_BUFFER_SIZE 4096
+#define PROC_SAFE_SIZE 3072
+
+static int
+calc_start_len(char *buffer, char **start, int requested_offset,
+	       int requested_len, int total, char *buf)
+{
+	int return_len, buffer_len;
+	
+	buffer_len = buf - buffer;
+	if (buffer_len >= PROC_BUFFER_SIZE - 1) {
+		printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n");
+	}
+	
+	/*
+	 * There may be bytes before and after the
+	 * chunk that was actually requested.
+	 */
+	return_len = total - requested_offset;
+	if (return_len < 0) {
+		return_len = 0;
+	}
+	*start = buf - return_len;
+	if (return_len > requested_len) {
+		return_len = requested_len;
+	}
+	return return_len;
+}
+
+static int
+dldwd_proc_get_hermes_regs(char *page, char **start, off_t requested_offset,
+			   int requested_len, int *eof, void *data)
+{
+	dldwd_priv_t *dev = (dldwd_priv_t *)data;
+	hermes_t *hw = &dev->hw;
+	char *buf;
+	int total = 0, slop = 0;
+
+	/* Hum, in this case hardware register are probably not readable... */
+	if (!dev->hw_ready)
+		return -ENODEV;
+
+	buf = page;
+
+#define DHERMESREG(name) buf += sprintf(buf, "%-16s: %04x\n", #name, hermes_read_regn(hw, name))
+
+	DHERMESREG(CMD);
+	DHERMESREG(PARAM0);
+	DHERMESREG(PARAM1);
+	DHERMESREG(PARAM2);
+	DHERMESREG(STATUS);
+	DHERMESREG(RESP0);
+	DHERMESREG(RESP1);
+	DHERMESREG(RESP2);
+	DHERMESREG(INFOFID);
+	DHERMESREG(RXFID);
+	DHERMESREG(ALLOCFID);
+	DHERMESREG(TXCOMPLFID);
+	DHERMESREG(SELECT0);
+	DHERMESREG(OFFSET0);
+	DHERMESREG(SELECT1);
+	DHERMESREG(OFFSET1);
+	DHERMESREG(EVSTAT);
+	DHERMESREG(INTEN);
+	DHERMESREG(EVACK);
+	DHERMESREG(CONTROL);
+	DHERMESREG(SWSUPPORT0);
+	DHERMESREG(SWSUPPORT1);
+	DHERMESREG(SWSUPPORT2);
+	DHERMESREG(AUXPAGE);
+	DHERMESREG(AUXOFFSET);
+	DHERMESREG(AUXDATA);
+#undef DHERMESREG
+
+	shift_buffer(page, requested_offset, requested_len, &total,
+		     &slop, &buf);
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+struct {
+	uint16_t rid;
+	char *name;
+	int minlen, maxlen;
+	int displaytype;
+#define DISPLAY_WORDS	0
+#define DISPLAY_BYTES	1
+#define DISPLAY_STRING	2
+} record_table[] = {
+#define RTCNFENTRY(name, type) { HERMES_RID_CNF_##name, #name, 0, LTV_BUF_SIZE, type }
+	RTCNFENTRY(PORTTYPE, DISPLAY_WORDS),
+	RTCNFENTRY(MACADDR, DISPLAY_BYTES),
+	RTCNFENTRY(DESIRED_SSID, DISPLAY_STRING),
+	RTCNFENTRY(CHANNEL, DISPLAY_WORDS),
+	RTCNFENTRY(OWN_SSID, DISPLAY_STRING),
+	RTCNFENTRY(SYSTEM_SCALE, DISPLAY_WORDS),
+	RTCNFENTRY(MAX_DATA_LEN, DISPLAY_WORDS),
+	RTCNFENTRY(PM_ENABLE, DISPLAY_WORDS),
+	RTCNFENTRY(PM_MCAST_RX, DISPLAY_WORDS),
+	RTCNFENTRY(PM_PERIOD, DISPLAY_WORDS),
+	RTCNFENTRY(NICKNAME, DISPLAY_STRING),
+	RTCNFENTRY(WEP_ON, DISPLAY_WORDS),
+	RTCNFENTRY(MWO_ROBUST, DISPLAY_WORDS),
+	RTCNFENTRY(MULTICAST_LIST, DISPLAY_BYTES),
+	RTCNFENTRY(CREATEIBSS, DISPLAY_WORDS),
+	RTCNFENTRY(FRAG_THRESH, DISPLAY_WORDS),
+	RTCNFENTRY(RTS_THRESH, DISPLAY_WORDS),
+	RTCNFENTRY(TX_RATE_CTRL, DISPLAY_WORDS),
+	RTCNFENTRY(PROMISCUOUS, DISPLAY_WORDS),
+	RTCNFENTRY(KEYS, DISPLAY_BYTES),
+	RTCNFENTRY(TX_KEY, DISPLAY_WORDS),
+	RTCNFENTRY(TICKTIME, DISPLAY_WORDS),
+	RTCNFENTRY(PRISM2_TX_KEY, DISPLAY_WORDS),
+	RTCNFENTRY(PRISM2_KEY0, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY1, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY2, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_KEY3, DISPLAY_BYTES),
+	RTCNFENTRY(PRISM2_WEP_ON, DISPLAY_WORDS),
+#undef RTCNFENTRY
+#define RTINFENTRY(name,type) { HERMES_RID_##name, #name, 0, LTV_BUF_SIZE, type }
+	RTINFENTRY(CHANNEL_LIST, DISPLAY_WORDS),
+	RTINFENTRY(STAIDENTITY, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_SSID, DISPLAY_STRING),
+	RTINFENTRY(CURRENT_BSSID, DISPLAY_BYTES),
+	RTINFENTRY(COMMSQUALITY, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_TX_RATE, DISPLAY_WORDS),
+	RTINFENTRY(WEP_AVAIL, DISPLAY_WORDS),
+	RTINFENTRY(CURRENT_CHANNEL, DISPLAY_WORDS),
+	RTINFENTRY(DATARATES, DISPLAY_BYTES),
+#undef RTINFENTRY
+};
+#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) )
+
+static int
+dldwd_proc_get_hermes_recs(char *page, char **start, off_t requested_offset,
+			   int requested_len, int *eof, void *data)
+{
+	dldwd_priv_t *dev = (dldwd_priv_t *)data;
+	hermes_t *hw = &dev->hw;
+	char *buf;
+	int total = 0, slop = 0;
+	int i;
+	uint16_t length;
+	int err;
+
+	/* Hum, in this case hardware register are probably not readable... */
+	if (!dev->hw_ready)
+		return -ENODEV;
+		
+	buf = page;
+
+	/* print out all the config RIDs */
+	for (i = 0; i < NUM_RIDS; i++) {
+		uint16_t rid = record_table[i].rid;
+		int minlen = record_table[i].minlen;
+		int maxlen = record_table[i].maxlen;
+		int len;
+		uint8_t *val8;
+		uint16_t *val16;
+		int j;
+
+		val8 = kmalloc(maxlen + 2, GFP_KERNEL);
+		if (! val8)
+			return -ENOMEM;
+
+		err = hermes_read_ltv(hw, USER_BAP, rid, maxlen,
+				      &length, val8);
+		if (err) {
+			DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid);
+			continue;
+		}
+		val16 = (uint16_t *)val8;
+
+		buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name,
+			       rid, length, (length-1)*2);
+		len = MIN( MAX(minlen, (length-1)*2), maxlen);
+
+		switch (record_table[i].displaytype) {
+		case DISPLAY_WORDS:
+			for (j = 0; j < len / 2; j++) {
+				buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j]));
+			}
+			buf--;
+			break;
+
+		case DISPLAY_BYTES:
+		default:
+			for (j = 0; j < len; j++) {
+				buf += sprintf(buf, "%02X:", val8[j]);
+			}
+			buf--;
+			break;
+
+		case DISPLAY_STRING:
+			len = MIN(len, le16_to_cpu(val16[0])+2);
+			val8[len] = '\0';
+			buf += sprintf(buf, "\"%s\"", (char *)&val16[1]);
+			break;
+		}
+
+		buf += sprintf(buf, "\n");
+
+		kfree(val8);
+
+		if (shift_buffer(page, requested_offset, requested_len,
+				 &total, &slop, &buf))
+			break;
+
+		if ( (buf - page) > PROC_SAFE_SIZE )
+			break;
+	}
+
+	return calc_start_len(page, start, requested_offset, requested_len,
+			      total, buf);
+}
+
+/* initialise the /proc subsystem for the hermes driver, creating the
+ * separate entries */
+static int
+dldwd_proc_init(void)
+{
+	int err = 0;
+
+	TRACE_ENTER("dldwd");
+
+	/* create the directory for it to sit in */
+	dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root);
+	if (dir_base == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/hermes.\n");
+		dldwd_proc_cleanup();
+		err = -ENOMEM;
+	}
+
+	TRACE_EXIT("dldwd");
+
+	return err;
+}
+
+int
+dldwd_proc_dev_init(dldwd_priv_t *dev)
+{
+	struct net_device *ndev = &dev->ndev;
+
+	dev->dir_dev = NULL;
+	/* create the directory for it to sit in */
+	dev->dir_dev = create_proc_entry(ndev->name, S_IFDIR | S_IRUGO | S_IXUGO,
+					 dir_base);
+	if (dev->dir_dev == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/hermes/%s.\n",  ndev->name);
+		goto fail;
+	}
+
+	dev->dir_regs = NULL;
+	dev->dir_regs = create_proc_read_entry("regs", S_IFREG | S_IRUGO,
+					       dev->dir_dev, dldwd_proc_get_hermes_regs, dev);
+	if (dev->dir_regs == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/regs.\n",  ndev->name);
+		goto fail;
+	}
+
+	dev->dir_recs = NULL;
+	dev->dir_recs = create_proc_read_entry("recs", S_IFREG | S_IRUGO,
+					       dev->dir_dev, dldwd_proc_get_hermes_recs, dev);
+	if (dev->dir_recs == NULL) {
+		printk(KERN_ERR "Unable to initialise /proc/hermes/%s/recs.\n",  ndev->name);
+		goto fail;
+	}
+
+	return 0;
+ fail:
+	dldwd_proc_dev_cleanup(dev);
+	return -ENOMEM;
+}
+
+void
+dldwd_proc_dev_cleanup(dldwd_priv_t *priv)
+{
+	struct net_device *ndev = &priv->ndev;
+
+	if (priv->dir_regs) {
+		remove_proc_entry("regs", priv->dir_dev);
+		priv->dir_regs = NULL;
+	}		
+	if (priv->dir_recs) {
+		remove_proc_entry("recs", priv->dir_dev);
+		priv->dir_recs = NULL;
+	}		
+	if (priv->dir_dev) {
+		remove_proc_entry(ndev->name, dir_base);
+		priv->dir_dev = NULL;
+	}
+}
+
+static void
+dldwd_proc_cleanup(void)
+{
+	TRACE_ENTER("dldwd");
+
+	if (dir_base) {
+		remove_proc_entry("hermes", &proc_root);
+		dir_base = NULL;
+	}
+	
+	TRACE_EXIT("dldwd");
+}
+
+int
+dldwd_setup(dldwd_priv_t* priv)
+{
+	struct net_device *ndev = &priv->ndev;;
+
+	spin_lock_init(&priv->lock);
+
+	/* Set up the net_device */
+	ether_setup(ndev);
+	ndev->priv = priv;
+
+	/* Setup up default routines */
+	ndev->init = dldwd_init;
+	ndev->open = NULL;		/* Caller *must* override */
+	ndev->stop = NULL;
+	ndev->hard_start_xmit = dldwd_xmit;
+	ndev->tx_timeout = dldwd_tx_timeout;
+	ndev->watchdog_timeo = 4*HZ; /* 4 second timeout */
+
+	ndev->get_stats = dldwd_get_stats;
+	ndev->get_wireless_stats = dldwd_get_wireless_stats;
+
+	ndev->do_ioctl = dldwd_ioctl;
+
+	ndev->change_mtu = dldwd_change_mtu;
+	ndev->set_multicast_list = dldwd_set_multicast_list;
+
+	netif_stop_queue(ndev);
+
+	return 0;
+}
+
+#ifdef ORINOCO_DEBUG
+EXPORT_SYMBOL(dldwd_debug);
+#endif
+EXPORT_SYMBOL(dldwd_init);
+EXPORT_SYMBOL(dldwd_xmit);
+EXPORT_SYMBOL(dldwd_tx_timeout);
+EXPORT_SYMBOL(dldwd_ioctl);
+EXPORT_SYMBOL(dldwd_change_mtu);
+EXPORT_SYMBOL(dldwd_set_multicast_list);
+EXPORT_SYMBOL(dldwd_shutdown);
+EXPORT_SYMBOL(dldwd_reset);
+EXPORT_SYMBOL(dldwd_setup);
+EXPORT_SYMBOL(dldwd_proc_dev_init);
+EXPORT_SYMBOL(dldwd_proc_dev_cleanup);
+EXPORT_SYMBOL(dldwd_interrupt);
+
+static int __init init_dldwd(void)
+{
+	int err;
+
+	err = dldwd_proc_init();
+
+	printk(KERN_INFO "%s\n", version);
+
+	return 0;
+}
+
+static void __exit exit_dldwd(void)
+{
+	dldwd_proc_cleanup();
+}
+
+module_init(init_dldwd);
+module_exit(exit_dldwd);
diff -urN linux-2.4.5-pre1/drivers/net/wireless/orinoco.h linux/drivers/net/wireless/orinoco.h
--- linux-2.4.5-pre1/drivers/net/wireless/orinoco.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/orinoco.h	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,145 @@
+/* orinoco.h
+ * 
+ * Common definitions to all pieces of the various orinoco
+ * drivers
+ */
+
+#ifndef _ORINOCO_H
+#define _ORINOCO_H
+
+/* To enable debug messages */
+//#define ORINOCO_DEBUG		3
+
+#if (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10)
+#error "orinoco_cs requires Wireless extensions v10 or later."
+#endif /* (! defined (WIRELESS_EXT)) || (WIRELESS_EXT < 10) */
+#define WIRELESS_SPY		// enable iwspy support
+
+
+#define DLDWD_MIN_MTU		256
+#define DLDWD_MAX_MTU		(HERMES_FRAME_LEN_MAX - ENCAPS_OVERHEAD)
+
+#define LTV_BUF_SIZE		128
+#define USER_BAP		0
+#define IRQ_BAP			1
+#define DLDWD_MACPORT		0
+#define IRQ_LOOP_MAX		10
+#define TX_NICBUF_SIZE		2048
+#define TX_NICBUF_SIZE_BUG	1585		/* Bug in Intel firmware */
+#define MAX_KEYS		4
+#define MAX_KEY_SIZE		14
+#define LARGE_KEY_SIZE		13
+#define SMALL_KEY_SIZE		5
+#define MAX_FRAME_SIZE		2304
+
+typedef struct dldwd_key {
+	uint16_t len;
+	char data[MAX_KEY_SIZE];
+} __attribute__ ((packed)) dldwd_key_t;
+
+typedef dldwd_key_t dldwd_keys_t[MAX_KEYS];
+
+/*====================================================================*/
+
+
+typedef struct dldwd_priv {
+	void* card;	/* Pointer to card dependant structure */
+
+	spinlock_t lock;
+	long state;
+#define DLDWD_STATE_INIRQ 0
+#define DLDWD_STATE_DOIRQ 1
+	int hw_ready;	/* HW may be suspended by platform */
+
+	/* Net device stuff */
+	struct net_device ndev;
+	struct net_device_stats stats;
+	struct iw_statistics wstats;
+
+
+	/* Hardware control variables */
+	hermes_t hw;
+	uint16_t txfid;
+
+	/* Capabilities of the hardware/firmware */
+	hermes_identity_t firmware_info;
+	int firmware_type;
+#define FIRMWARE_TYPE_LUCENT 1
+#define FIRMWARE_TYPE_PRISM2 2
+#define FIRMWARE_TYPE_SYMBOL 3
+	int has_ibss, has_port3, prefer_port3, has_ibss_any;
+	int has_wep, has_big_wep;
+	int has_mwo;
+	int has_pm;
+	int has_preamble;
+	int broken_reset, broken_allocate;
+	uint16_t channel_mask;
+
+	/* Current configuration */
+	uint32_t iw_mode;
+	int port_type, allow_ibss;
+	uint16_t wep_on, wep_restrict, tx_key;
+	dldwd_keys_t keys;
+ 	char nick[IW_ESSID_MAX_SIZE+1];
+	char desired_essid[IW_ESSID_MAX_SIZE+1];
+	uint16_t frag_thresh, mwo_robust;
+	uint16_t channel;
+	uint16_t ap_density, rts_thresh;
+	uint16_t tx_rate_ctrl;
+	uint16_t pm_on, pm_mcast, pm_period, pm_timeout;
+	uint16_t preamble;
+
+	int promiscuous, allmulti, mc_count;
+
+#ifdef WIRELESS_SPY
+	int			spy_number;
+	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
+	struct iw_quality	spy_stat[IW_MAX_SPY];
+#endif
+
+	/* /proc based debugging stuff */
+	struct proc_dir_entry *dir_dev;
+	struct proc_dir_entry *dir_regs;
+	struct proc_dir_entry *dir_recs;
+} dldwd_priv_t;
+
+/*====================================================================*/
+
+extern int dldwd_debug;
+extern struct list_head dldwd_instances;
+
+#ifdef ORINOCO_DEBUG
+#define DEBUG(n, args...) if (dldwd_debug>(n)) printk(KERN_DEBUG args)
+#define DEBUGMORE(n, args...) do { if (dldwd_debug>(n)) printk(args); } while (0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#define DEBUGMORE(n, args...) do { } while (0)
+#endif	/* ORINOCO_DEBUG */
+
+#define TRACE_ENTER(devname) DEBUG(2, "%s: -> " __FUNCTION__ "()\n", devname);
+#define TRACE_EXIT(devname)  DEBUG(2, "%s: <- " __FUNCTION__ "()\n", devname);
+
+#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
+#define MIN(a, b) ( (a) < (b) ? (a) : (b) )
+
+#define RUP_EVEN(a) ( (a) % 2 ? (a) + 1 : (a) )
+
+/* struct net_device methods */
+extern int dldwd_init(struct net_device *dev);
+extern int dldwd_xmit(struct sk_buff *skb, struct net_device *dev);
+extern void dldwd_tx_timeout(struct net_device *dev);
+
+extern int dldwd_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+extern int dldwd_change_mtu(struct net_device *dev, int new_mtu);
+extern void dldwd_set_multicast_list(struct net_device *dev);
+
+/* utility routines */
+extern void dldwd_shutdown(dldwd_priv_t *dev);
+extern int dldwd_reset(dldwd_priv_t *dev);
+extern int dldwd_setup(dldwd_priv_t* priv);
+extern int dldwd_proc_dev_init(dldwd_priv_t *dev);
+extern void dldwd_proc_dev_cleanup(dldwd_priv_t *priv);
+extern void dldwd_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+
+
+#endif
diff -urN linux-2.4.5-pre1/drivers/net/wireless/orinoco_cs.c linux/drivers/net/wireless/orinoco_cs.c
--- linux-2.4.5-pre1/drivers/net/wireless/orinoco_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/orinoco_cs.c	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,789 @@
+/* orinoco_cs.c 0.05	- (formerly known as dldwd_cs.c)
+ *
+ * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
+ * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
+ * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
+ * It should also be usable on various Prism II based cards such as the
+ * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
+ * cards such as the 3Com AirConnect and Ericsson WLAN.
+ * 
+ * Copyright notice & release notes in file orinoco.c
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/list.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+#include "hermes.h"
+#include "orinoco.h"
+
+/* Pcmcia specific structure */
+typedef struct dldwd_card {
+	dev_link_t link;
+	dev_node_t node;
+	int instance;
+
+	/* Common structure (fully included), see orinoco.h */
+	struct dldwd_priv  priv;
+} dldwd_card_t;
+
+static char *version = "orinoco_cs.c 0.05 (David Gibson <hermes@gibson.dropbear.id.au> and others)";
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static uint irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+/* Do a Pcmcia soft reset (may help some cards) */
+static int reset_cor = 0;
+/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
+ * don't have any CIS entry for it. This workaround it... */
+static int ignore_cis_vcc = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(reset_cor, "i");
+MODULE_PARM(ignore_cis_vcc, "i");
+
+/*
+ * Function prototypes
+ */
+
+/* struct net_device methods */
+static int dldwd_cs_open(struct net_device *dev);
+static int dldwd_cs_stop(struct net_device *dev);
+
+/* PCMCIA gumpf */
+static void dldwd_cs_config(dev_link_t * link);
+static void dldwd_cs_release(u_long arg);
+static int dldwd_cs_event(event_t event, int priority,
+		       event_callback_args_t * args);
+
+static dev_link_t *dldwd_cs_attach(void);
+static void dldwd_cs_detach(dev_link_t *);
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "orinoco_cs";
+
+/*
+   A linked list of "instances" of the dummy device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+static int num_instances = 0;
+
+/*====================================================================*/
+
+static void
+cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+static int
+dldwd_cs_open(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	dev_link_t *link = &card->link;
+	int err;
+	
+	TRACE_ENTER(priv->ndev.name);
+
+	link->open++;
+	netif_device_attach(dev);
+	
+	err = dldwd_reset(priv);
+	if (err)
+		dldwd_cs_stop(dev);
+	else
+		netif_start_queue(dev);
+
+	TRACE_EXIT(priv->ndev.name);
+
+	return err;
+}
+
+static int
+dldwd_cs_stop(struct net_device *dev)
+{
+	dldwd_priv_t *priv = (dldwd_priv_t *)dev->priv;
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
+	dev_link_t *link = &card->link;
+
+	TRACE_ENTER(priv->ndev.name);
+
+	netif_stop_queue(dev);
+
+	dldwd_shutdown(priv);
+	
+	link->open--;
+
+	if (link->state & DEV_STALE_CONFIG)
+		mod_timer(&link->release, jiffies + HZ/20);
+	
+	TRACE_EXIT(priv->ndev.name);
+	
+	return 0;
+}
+
+/*======================================================================
+  dldwd_cs_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+  
+  The dev_link structure is initialized, but we don't actually
+  configure the card at this point -- we wait until we receive a
+  card insertion event.
+  ======================================================================*/
+
+static dev_link_t *
+dldwd_cs_attach(void)
+{
+	dldwd_card_t *card;
+	dldwd_priv_t *priv;
+	dev_link_t *link;
+	struct net_device *ndev;
+	client_reg_t client_reg;
+	int ret, i;
+
+	TRACE_ENTER("dldwd");
+
+	/* Allocate space for private device-specific data */
+	card = kmalloc(sizeof(*card), GFP_KERNEL);
+	if (! card) {
+		link = NULL;
+		goto out;
+	}
+	memset(card, 0, sizeof(*card));
+
+	/* Link both structure together */
+	priv = &(card->priv);
+	priv->card = card;
+	card->instance = num_instances++; /* FIXME: Racy? */
+	link = &card->link;
+	ndev = &priv->ndev;
+	link->priv = priv;
+
+	/* Initialize the dev_link_t structure */
+	link->release.function = &dldwd_cs_release;
+	link->release.data = (u_long) link;
+
+	/* Interrupt setup */
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = NULL;
+
+	/*
+	   General socket configuration defaults can go here.  In this
+	   client, we assume very little, and rely on the CIS for almost
+	   everything.  In most clients, many details (i.e., number, sizes,
+	   and attributes of IO windows) are fixed by the nature of the
+	   device, and can be hard-wired here.
+	 */
+	link->conf.Attributes = 0;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	/* Setup the common part */
+	if(dldwd_setup(priv) < 0) {
+		kfree(card);
+		return NULL;
+	}
+
+	/* Overrides */
+	ndev->open = dldwd_cs_open;
+	ndev->stop = dldwd_cs_stop;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &dldwd_cs_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		dldwd_cs_detach(link);
+		link = NULL;
+		goto out;
+	}
+
+ out:
+	TRACE_EXIT("dldwd");
+	return link;
+}				/* dldwd_cs_attach */
+
+/*======================================================================
+  This deletes a driver "instance".  The device is de-registered
+  with Card Services.  If it has been released, all local data
+  structures are freed.  Otherwise, the structures will be freed
+  when the device is released.
+  ======================================================================*/
+
+static void
+dldwd_cs_detach(dev_link_t * link)
+{
+	dev_link_t **linkp;
+	dldwd_priv_t *priv = link->priv;
+
+	TRACE_ENTER("dldwd");
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+	if (*linkp == NULL)
+		goto out;
+
+	/*
+	   If the device is currently configured and active, we won't
+	   actually delete it yet.  Instead, it is marked so that when
+	   the release() function is called, that will trigger a proper
+	   detach().
+	 */
+	if (link->state & DEV_CONFIG) {
+#ifdef PCMCIA_DEBUG
+		printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
+		       "still locked\n", link->dev->dev_name);
+#endif
+		link->state |= DEV_STALE_LINK;
+		goto out;
+	}
+
+	/* Break the link with Card Services */
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+
+	/* Unlink device structure, and free it */
+	*linkp = link->next;
+	DEBUG(0, "orinoco_cs: detach: link=%p link->dev=%p\n", link, link->dev);
+	if (link->dev) {
+		DEBUG(0, "orinoco_cs: About to unregister net device %p\n",
+		      &priv->ndev);
+		unregister_netdev(&priv->ndev);
+	}
+	kfree(priv->card);
+
+	num_instances--; /* FIXME: Racy? */
+
+ out:
+	TRACE_EXIT("dldwd");
+}				/* dldwd_cs_detach */
+
+/*
+ * Do a soft reset of the Pcmcia card using the Configuration Option Register
+ * Can't do any harm, and actually may do some good on some cards...
+ */
+static int
+dldwd_cs_cor_reset(dev_link_t *link)
+{
+	conf_reg_t reg;
+	u_long default_cor; 
+
+	/* Save original COR value */
+	reg.Function = 0;
+	reg.Action = CS_READ;
+	reg.Offset = CISREG_COR;
+	reg.Value = 0;
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	default_cor = reg.Value;
+
+	DEBUG(2, "dldwd : dldwd_cs_cor_reset() : cor=0x%lX\n", default_cor);
+
+	/* Soft-Reset card */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_COR;
+	reg.Value = (default_cor | COR_SOFT_RESET);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has acknowledged our reset */
+	mdelay(1);
+
+	/* Restore original COR configuration index */
+	reg.Value = (default_cor & COR_CONFIG_MASK);
+	CardServices(AccessConfigurationRegister, link->handle, &reg);
+
+	/* Wait until the card has finished restarting */
+	mdelay(1);
+
+	return(0);
+}
+
+/*======================================================================
+  dldwd_cs_config() is scheduled to run after a CARD_INSERTION event
+  is received, to configure the PCMCIA socket, and to make the
+  device available to the system.
+  ======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void
+dldwd_cs_config(dev_link_t * link)
+{
+	client_handle_t handle = link->handle;
+	dldwd_priv_t *priv = link->priv;
+	dldwd_card_t *card = (dldwd_card_t *)priv->card;
+	hermes_t *hw = &priv->hw;
+	struct net_device *ndev = &priv->ndev;
+	tuple_t tuple;
+	cisparse_t parse;
+	int last_fn, last_ret;
+	u_char buf[64];
+	config_info_t conf;
+	cistpl_cftable_entry_t dflt = { 0 };
+	cisinfo_t info;
+
+	TRACE_ENTER("dldwd");
+
+	CS_CHECK(ValidateCIS, handle, &info);
+
+	/*
+	   This reads the card's CONFIG tuple to find its configuration
+	   registers.
+	 */
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	/* Look up the current Vcc */
+	CS_CHECK(GetConfigurationInfo, handle, &conf);
+	link->conf.Vcc = conf.Vcc;
+
+	DEBUG(0, "dldwd_cs_config: ConfigBase = 0x%x link->conf.Vcc = %d\n", 
+	      link->conf.ConfigBase, link->conf.Vcc);
+
+	/*
+	   In this loop, we scan the CIS for configuration table entries,
+	   each of which describes a valid card configuration, including
+	   voltage, IO window, memory window, and interrupt settings.
+
+	   We make no assumptions about the card to be configured: we use
+	   just the information available in the CIS.  In an ideal world,
+	   this would work for any PCMCIA card, but it requires a complete
+	   and accurate CIS.  In practice, a driver usually "knows" most of
+	   these things without consulting the CIS, and most client drivers
+	   will only use the CIS to fill in implementation-defined details.
+	 */
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+		DEBUG(0, "dldwd_cs_config: index = 0x%x, flags = 0x%x\n",
+		      cfg->index, cfg->flags);
+
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+			dflt = *cfg;
+		if (cfg->index == 0)
+			goto next_entry;
+		link->conf.ConfigIndex = cfg->index;
+
+		/* Does this card need audio output? */
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (conf.Vcc !=
+			    cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
+				if(!ignore_cis_vcc)
+					goto next_entry;
+			}
+		} else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+			if (conf.Vcc !=
+			    dflt.vcc.param[CISTPL_POWER_VNOM] / 10000) {
+				DEBUG(2, "dldwd_cs_config: Vcc mismatch (conf.Vcc = %d, CIS = %d)\n",  conf.Vcc, dflt.vcc.param[CISTPL_POWER_VNOM] / 10000);
+				if(!ignore_cis_vcc)
+					goto next_entry;
+			}
+		}
+
+		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+			    cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+			    dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		
+		DEBUG(0, "dldwd_cs_config: We seem to have configured Vcc and Vpp\n");
+
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io =
+			    (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 =
+				    IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 =
+				    IO_DATA_PATH_WIDTH_8;
+			link->io.IOAddrLines =
+			    io->flags & CISTPL_IO_LINES_MASK;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 =
+				    link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+
+			/* This reserves IO space but doesn't actually enable it */
+			CFG_CHECK(RequestIO, link->handle, &link->io);
+		}
+
+
+		/* If we got this far, we're cool! */
+
+		break;
+		
+	next_entry:
+		if (link->io.NumPorts1)
+			CardServices(ReleaseIO, link->handle, &link->io);
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+
+	/*
+	   Allocate an interrupt line.  Note that this does not assign a
+	   handler to the interrupt, unless the 'Handler' member of the
+	   irq structure is initialized.
+	 */
+	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+		int i;
+
+		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+		link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+		if (irq_list[0] == -1)
+			link->irq.IRQInfo2 = irq_mask;
+		else
+			for (i=0; i<4; i++)
+				link->irq.IRQInfo2 |= 1 << irq_list[i];
+		
+  		link->irq.Handler = dldwd_interrupt; 
+  		link->irq.Instance = priv; 
+		
+		CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	}
+
+	/* We initialize the hermes structure before completing PCMCIA
+	   configuration just in case the interrupt handler gets
+	   called. */
+	hermes_struct_init(hw, link->io.BasePort1);
+
+	/*
+	   This actually configures the PCMCIA socket -- setting up
+	   the I/O windows and the interrupt mapping, and putting the
+	   card and host interface into "Memory and IO" mode.
+	 */
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+	ndev->base_addr = link->io.BasePort1;
+	ndev->irq = link->irq.AssignedIRQ;
+
+	/* Do a Pcmcia soft reset of the card (optional) */
+	if(reset_cor)
+		dldwd_cs_cor_reset(link);
+
+	/* register_netdev will give us an ethX name */
+	ndev->name[0] = '\0';
+	/* Tell the stack we exist */
+	if (register_netdev(ndev) != 0) {
+		printk(KERN_ERR "orinoco_cs: register_netdev() failed\n");
+		goto failed;
+	}
+	strcpy(card->node.dev_name, ndev->name);
+
+	/* Finally, report what we've done */
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	       ndev->name, link->conf.ConfigIndex,
+	       link->conf.Vcc / 10, link->conf.Vcc % 10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1 / 10,
+		       link->conf.Vpp1 % 10);
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		printk(", irq %d", link->irq.AssignedIRQ);
+	if (link->io.NumPorts1)
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1 + link->io.NumPorts1 - 1);
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+		       link->io.BasePort2 + link->io.NumPorts2 - 1);
+	printk("\n");
+
+	/* Allow /proc & ioctls to act */
+	priv->hw_ready = 1;
+	
+	/* And give us the proc nodes for debugging */
+	if (dldwd_proc_dev_init(priv) != 0) {
+		printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
+		       ndev->name);
+		goto failed;
+	}
+	
+	/* Note to myself : this replace MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT */
+	SET_MODULE_OWNER(ndev);
+	
+	/*
+	   At this point, the dev_node_t structure(s) need to be
+	   initialized and arranged in a linked list at link->dev.
+	 */
+	card->node.major = card->node.minor = 0;
+	link->dev = &card->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	TRACE_EXIT("dldwd");
+
+	return;
+
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+ failed:
+	dldwd_cs_release((u_long) link);
+
+	TRACE_EXIT("dldwd");
+}				/* dldwd_cs_config */
+
+/*======================================================================
+  After a card is removed, dldwd_cs_release() will unregister the
+  device, and release the PCMCIA configuration.  If the device is
+  still open, this will be postponed until it is closed.
+  ======================================================================*/
+
+static void
+dldwd_cs_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *) arg;
+	dldwd_priv_t *priv = link->priv;
+
+	TRACE_ENTER(link->dev->dev_name);
+
+	/*
+	   If the device is currently in use, we won't release until it
+	   is actually closed, because until then, we can't be sure that
+	   no one will try to access the device or its data structures.
+	 */
+	if (link->open) {
+		DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
+		      link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	/* Unregister proc entry */
+	dldwd_proc_dev_cleanup(priv);
+
+	/* Don't bother checking to see if these succeed or not */
+	CardServices(ReleaseConfiguration, link->handle);
+	if (link->io.NumPorts1)
+		CardServices(ReleaseIO, link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		CardServices(ReleaseIRQ, link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+
+	TRACE_EXIT(link->dev->dev_name);
+}				/* dldwd_cs_release */
+
+/*======================================================================
+  The card status event handler.  Mostly, this schedules other
+  stuff to run after an event is received.
+
+  When a CARD_REMOVAL event is received, we immediately set a
+  private flag to block future accesses to this device.  All the
+  functions that actually access the device should check this flag
+  to make sure the card is still present.
+  ======================================================================*/
+
+static int
+dldwd_cs_event(event_t event, int priority,
+		       event_callback_args_t * args)
+{
+	dev_link_t *link = args->client_data;
+	dldwd_priv_t *priv = (dldwd_priv_t *)link->priv;
+	struct net_device *dev = &priv->ndev;
+
+	TRACE_ENTER("dldwd");
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		priv->hw_ready = 0;
+		dldwd_shutdown(priv);
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			netif_stop_queue(dev);
+			netif_device_detach(dev);
+			mod_timer(&link->release, jiffies + HZ / 20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		dldwd_cs_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		dldwd_shutdown(priv);
+		/* Mark the device as stopped, to block IO until later */
+
+		if (link->state & DEV_CONFIG) {
+			if (link->open) {
+				netif_stop_queue(dev);
+				netif_device_detach(dev);
+			}
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle,
+				     &link->conf);
+
+			if (link->open) {
+				if (dldwd_reset(priv) == 0) {
+					netif_device_attach(dev);
+					netif_start_queue(dev);
+				} else {
+					printk(KERN_ERR "%s: Error resetting device on PCMCIA event\n",
+					       dev->name);
+					dldwd_cs_stop(dev);
+				}
+			}
+		}
+		/*
+		   In a normal driver, additional code may go here to restore
+		   the device state and restart IO. 
+		 */
+		break;
+	}
+
+	TRACE_EXIT("dldwd");
+
+	return 0;
+}				/* dldwd_cs_event */
+
+static int __init
+init_dldwd_cs(void)
+{
+	servinfo_t serv;
+
+	TRACE_ENTER("dldwd");
+
+	printk(KERN_INFO "dldwd: David's Less Dodgy WaveLAN/IEEE Driver\n");
+
+	DEBUG(0, "%s\n", version);
+
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "orinoco_cs: Card Services release "
+		       "does not match!\n");
+		return -1;
+	}
+
+	register_pccard_driver(&dev_info, &dldwd_cs_attach, &dldwd_cs_detach);
+
+
+	TRACE_EXIT("dldwd");
+	return 0;
+}
+
+static void __exit
+exit_dldwd_cs(void)
+{
+	TRACE_ENTER("dldwd");
+
+	unregister_pccard_driver(&dev_info);
+
+	if (dev_list)
+		DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
+	while (dev_list != NULL) {
+		del_timer(&dev_list->release);
+		if (dev_list->state & DEV_CONFIG)
+			dldwd_cs_release((u_long) dev_list);
+		dldwd_cs_detach(dev_list);
+	}
+
+	TRACE_EXIT("dldwd");
+}
+
+module_init(init_dldwd_cs);
+module_exit(exit_dldwd_cs);
diff -urN linux-2.4.5-pre1/drivers/net/wireless/todo.txt linux/drivers/net/wireless/todo.txt
--- linux-2.4.5-pre1/drivers/net/wireless/todo.txt	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/wireless/todo.txt	Mon Dec  3 22:41:47 2001
@@ -0,0 +1,24 @@
+	Wireless Todo
+	-------------
+
+1) Bring other kernel Wireless LAN drivers here
+	Already done :
+	 o hermes.c/orinoco.c	-> Wavelan IEEE driver + Airport driver
+	Drivers I have control over :
+	 o wavelan.c		-> old Wavelan ISA driver
+	 o wavelan_cs.c		-> old Wavelan Pcmcia driver (warning : header)
+	 o netwave_cs.c		-> Netwave Pcmcia driver
+	Drivers likely to go :
+	 o ray_cs.c		-> Raytheon/Aviator driver (maintainer MIA)
+	Drivers I have absolutely no control over :
+	 o arlan.c		-> old Aironet Arlan 655 (need to ask Elmer)
+	 o aironet4500_xxx.c	-> Elmer's Aironet driver (need to ask Elmer)
+	 o airo.c/airo_cs.c	-> Ben's Aironet driver (not yet in kernel)
+	 o strip.c		-> Metricom's stuff. Not a wlan. Hum...
+
+	ETA : Kernel 2.5.X
+
+2) Bring new Wireless LAN driver not yet in the kernel there
+	See my web page for details
+
+	Jean II
diff -urN linux-2.4.5-pre1/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- linux-2.4.5-pre1/drivers/sbus/char/su.c	Thu Apr 26 22:17:26 2001
+++ linux/drivers/sbus/char/su.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: su.c,v 1.47 2001/04/18 21:06:15 davem Exp $
+/* $Id: su.c,v 1.48 2001/04/27 07:02:42 davem Exp $
  * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -2220,7 +2220,7 @@
  */
 static __inline__ void __init show_su_version(void)
 {
-	char *revision = "$Revision: 1.47 $";
+	char *revision = "$Revision: 1.48 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -urN linux-2.4.5-pre1/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c
--- linux-2.4.5-pre1/drivers/sbus/char/zs.c	Thu Apr 26 22:17:26 2001
+++ linux/drivers/sbus/char/zs.c	Mon Dec  3 22:41:47 2001
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.63 2001/04/17 06:30:36 davem Exp $
+/* $Id: zs.c,v 1.64 2001/04/27 07:02:42 davem Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -1922,7 +1922,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.63 $";
+	char *revision = "$Revision: 1.64 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -urN linux-2.4.5-pre1/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux-2.4.5-pre1/drivers/scsi/Makefile	Mon Mar 26 15:36:30 2001
+++ linux/drivers/scsi/Makefile	Mon Dec  3 22:41:47 2001
@@ -6,6 +6,12 @@
 #
 # 20 Sep 2000, Torben Mathiasen <tmm@image.dk>
 # Changed link order to reflect new scsi initialization.
+#
+# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
+# The link order must be, SCSI Core, SCSI HBA drivers, and
+# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to
+# satisfy certain initialization assumptions in the SCSI layer.
+# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
 
 O_TARGET := scsidrv.o
 
@@ -64,6 +70,9 @@
 obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
 obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
 obj-$(CONFIG_SCSI_AHA1740)	+= aha1740.o
+ifeq ($(CONFIG_SCSI_AIC7XXX),y)
+obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx/aic7xxx_drv.o
+endif
 obj-$(CONFIG_SCSI_AIC7XXX_OLD)	+= aic7xxx_old.o
 obj-$(CONFIG_SCSI_IPS)		+= ips.o
 obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/Config.in linux/drivers/scsi/aic7xxx/Config.in
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/Config.in	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/Config.in	Mon Dec  3 22:41:47 2001
@@ -2,6 +2,7 @@
    dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
    if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
       int  '  Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 253
-      int  '  Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY 5000
+      int  '  Initial bus reset delay in milli-seconds' CONFIG_AIC7XXX_RESET_DELAY_MS 15000
+      bool  '  Build Adapter Firmware with Kernel Build' CONFIG_AIC7XXX_BUILD_FIRMWARE
    fi
 fi
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/Makefile linux/drivers/scsi/aic7xxx/Makefile
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/Makefile	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/Makefile	Mon Dec  3 22:41:47 2001
@@ -4,7 +4,7 @@
 # Makefile for the Linux aic7xxx SCSI driver.
 #
 
-O_TARGET = aic7xxx_drv.o
+O_TARGET := aic7xxx_drv.o
 
 list-multi	:= aic7xxx_mod.o
 
@@ -25,8 +25,13 @@
 aic7xxx_mod.o: aic7xxx_seq.h aic7xxx_reg.h $(AIC7XXX_OBJS)
 	$(LD) $(LD_RFLAG) -r -o $@ $(AIC7XXX_OBJS)
 
+ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
 aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm
 	aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq
+else
+aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg
+	echo "Warning, generated aic7xxx firmware files may be out of date!\n"
+endif
 
 aicasm/aicasm: aicasm/*.[chyl]
 	$(MAKE) -C aicasm
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7770.c linux/drivers/scsi/aic7xxx/aic7770.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7770.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7770.c	Mon Dec  3 22:41:47 2001
@@ -29,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7770.c#6 $
+ * $Id: //depot/src/aic7xxx/aic7770.c#11 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $
  */
@@ -95,8 +95,6 @@
 	u_int	hostconf;
 	u_int   irq;
 	u_int	intdef;
-	u_int	hcntrl;
-	int	shared;
 
 	ahc_init_probe_config(&probe_config);
 	error = entry->setup(ahc->dev_softc, &probe_config);
@@ -107,15 +105,15 @@
 	if (error != 0)
 		return (error);
 
-	/* Pause the card preseving the IRQ type */
-	hcntrl = ahc_inb(ahc, HCNTRL) & IRQMS;
-	ahc_outb(ahc, HCNTRL, hcntrl | PAUSE);
-	while ((ahc_inb(ahc, HCNTRL) & PAUSE) == 0)
-		;
+	probe_config.description = entry->name;
+	error = ahc_softc_init(ahc, &probe_config);
+
+	error = ahc_reset(ahc);
+	if (error != 0)
+		return (error);
 
 	/* Make sure we have a valid interrupt vector */
 	intdef = ahc_inb(ahc, INTDEF);
-	shared = (intdef & EDGE_TRIG) ? 0 : 1;
 	irq = intdef & VECTOR;
 	switch (irq) {
 	case 9:
@@ -130,16 +128,8 @@
 		return (ENXIO);
 	}
 
-	probe_config.description = entry->name;
-	error = ahc_softc_init(ahc, &probe_config);
-
-	error = aic7770_map_int(ahc, irq, shared);
-	if (error != 0)
-		return (error);
-
-	error = ahc_reset(ahc);
-	if (error != 0)
-		return (error);
+	if ((intdef & EDGE_TRIG) != 0)
+		ahc->flags |= AHC_EDGE_INTERRUPT;
 
 	switch (probe_config.chip & (AHC_EISA|AHC_VL)) {
 	case AHC_EISA:
@@ -154,7 +144,7 @@
 
 		/* Get the primary channel information */
 		if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
-			ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+			ahc->flags |= 1;
 
 		if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
 			ahc->flags |= AHC_USEDEFAULTS;
@@ -210,10 +200,19 @@
 	 */
 	ahc_softc_insert(ahc);
 
+	error = aic7770_map_int(ahc, irq);
+	if (error != 0)
+		return (error);
+
 	/*
 	 * Enable the board's BUS drivers
 	 */
 	ahc_outb(ahc, BCTL, ENABLE);
+
+	/*
+	 * Allow interrupts.
+	 */
+	ahc_intr_enable(ahc, TRUE);
 
 	return (0);
 }
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7770_linux.c linux/drivers/scsi/aic7xxx/aic7770_linux.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7770_linux.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7770_linux.c	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#5 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7770_linux.c#7 $
  */
 
 #include "aic7xxx_osm.h"
@@ -128,19 +128,18 @@
 }
 
 int
-aic7770_map_int(struct ahc_softc *ahc, u_int irq, int shared)
+aic7770_map_int(struct ahc_softc *ahc, u_int irq)
 {
 	int error;
+	int shared;
 
-	if (shared)
+	shared = 0;
+	if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
 		shared = SA_SHIRQ;
 
 	ahc->platform_data->irq = irq;
-	error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
-			    SA_INTERRUPT|shared, "aic7xxx", ahc);
-	if (error < 0)
-		error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
-				    shared, "aic7xxx", ahc);
+	error = request_irq(ahc->platform_data->irq, ahc_linux_isr,
+			    shared, "aic7xxx", ahc);
 	
 	return (-error);
 }
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.c	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx.c#32 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.c#39 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.c,v 1.61 2000/11/13 03:35:43 gibbs Exp $
  */
@@ -58,9 +58,17 @@
 	"aic7892",
 	"aic7899"
 };
-const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
+static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
 
-struct hard_error_entry hard_error[] = {
+/*
+ * Hardware error codes.
+ */
+struct ahc_hard_error_entry {
+        uint8_t errno;
+	char *errmesg;
+};
+
+static struct ahc_hard_error_entry ahc_hard_errors[] = {
 	{ ILLHADDR,	"Illegal Host Access" },
 	{ ILLSADDR,	"Illegal Sequencer Address referrenced" },
 	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },
@@ -70,9 +78,9 @@
 	{ PCIERRSTAT,	"PCI Error detected" },
 	{ CIOPARERR,	"CIOBUS Parity Error" },
 };
-const u_int num_errors = NUM_ELEMENTS(hard_error);
+static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors);
 
-struct phase_table_entry phase_table[] =
+static struct ahc_phase_table_entry ahc_phase_table[] =
 {
 	{ P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	},
 	{ P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	},
@@ -90,14 +98,14 @@
  * In most cases we only wish to itterate over real phases, so
  * exclude the last element from the count.
  */
-const u_int num_phases = NUM_ELEMENTS(phase_table) - 1;
+static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1;
 
 /*
  * Valid SCSIRATE values.  (p. 3-17)
  * Provides a mapping of tranfer periods in ns to the proper value to
  * stick in the scsixfer reg.
  */
-struct ahc_syncrate ahc_syncrates[] =
+static struct ahc_syncrate ahc_syncrates[] =
 {
       /* ultra2    fast/ultra  period     rate */
 	{ 0x42,      0x000,      9,      "80.0" },
@@ -121,7 +129,7 @@
 #include "aic7xxx_seq.h"
 
 /**************************** Function Declarations ***************************/
-static struct tmode_tstate*
+static struct ahc_tmode_tstate*
 			ahc_alloc_tstate(struct ahc_softc *ahc,
 					 u_int scsi_id, char channel);
 #ifdef AHC_TARGET_MODE
@@ -134,12 +142,13 @@
 						u_int *period,
 						u_int *ppr_options,
 						role_t role);
-static void		ahc_update_pending_syncrates(struct ahc_softc *ahc);
+static void		ahc_update_pending_scbs(struct ahc_softc *ahc);
 static void		ahc_fetch_devinfo(struct ahc_softc *ahc,
 					  struct ahc_devinfo *devinfo);
 static void		ahc_scb_devinfo(struct ahc_softc *ahc,
 					struct ahc_devinfo *devinfo,
 					struct scb *scb);
+static void		ahc_assert_atn(struct ahc_softc *ahc);
 static void		ahc_setup_initiator_msgout(struct ahc_softc *ahc,
 						   struct ahc_devinfo *devinfo,
 						   struct scb *scb);
@@ -174,6 +183,11 @@
 					    struct ahc_devinfo *devinfo,
 					    cam_status status, char *message,
 					    int verbose_level);
+#if AHC_TARGET_MODE
+static void		ahc_setup_target_msgin(struct ahc_softc *ahc,
+					       struct ahc_devinfo *devinfo,
+					       struct scb *scb);
+#endif
 
 static bus_dmamap_callback_t	ahc_dmamap_cb; 
 static void			ahc_build_free_scb_list(struct ahc_softc *ahc);
@@ -192,7 +206,6 @@
 				       char channel, int lun, u_int tag,
 				       role_t role, uint32_t status);
 static void		ahc_reset_current_bus(struct ahc_softc *ahc);
-static void		ahc_calc_residual(struct scb *scb);
 #ifdef AHC_DUMP_SEQ
 static void		ahc_dumpseq(struct ahc_softc *ahc);
 #endif
@@ -204,7 +217,7 @@
 					   u_int instrptr, uint8_t *dconsts);
 #ifdef AHC_TARGET_MODE
 static void		ahc_queue_lstate_event(struct ahc_softc *ahc,
-					       struct tmode_lstate *lstate,
+					       struct ahc_tmode_lstate *lstate,
 					       u_int initiator_id,
 					       u_int event_type,
 					       u_int event_arg);
@@ -218,10 +231,10 @@
  * Restart the sequencer program from address zero
  */
 void
-restart_sequencer(struct ahc_softc *ahc)
+ahc_restart(struct ahc_softc *ahc)
 {
 
-	pause_sequencer(ahc);
+	ahc_pause(ahc);
 
 	ahc_outb(ahc, SCSISIGO, 0);		/* De-assert BSY */
 	ahc_outb(ahc, MSG_OUT, MSG_NOOP);	/* No message to send */
@@ -259,7 +272,7 @@
 	ahc_outb(ahc, SEQCTL, FASTMODE);
 	ahc_outb(ahc, SEQADDR0, 0);
 	ahc_outb(ahc, SEQADDR1, 0);
-	unpause_sequencer(ahc);
+	ahc_unpause(ahc);
 }
 
 /************************* Input/Output Queues ********************************/
@@ -300,10 +313,7 @@
 		 * Save off the residual
 		 * if there is one.
 		 */
-		if (ahc_check_residual(scb) != 0)
-			ahc_calc_residual(scb);
-		else
-			ahc_set_residual(scb, 0);
+		ahc_update_residual(scb);
 		ahc_done(ahc, scb);
 	}
 }
@@ -340,14 +350,14 @@
 	 * We upset the sequencer :-(
 	 * Lookup the error message
 	 */
-	int i, error, num_errors;
+	int i;
+	int error;
 
 	error = ahc_inb(ahc, ERROR);
-	num_errors =  sizeof(hard_error)/sizeof(hard_error[0]);
 	for (i = 0; error != 1 && i < num_errors; i++)
 		error >>= 1;
 	printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
-	       ahc_name(ahc), hard_error[i].errmesg,
+	       ahc_name(ahc), ahc_hard_errors[i].errmesg,
 	       ahc_inb(ahc, SEQADDR0) |
 	       (ahc_inb(ahc, SEQADDR1) << 8));
 
@@ -436,6 +446,12 @@
 			break;
 		case SCSI_STATUS_CMD_TERMINATED:
 		case SCSI_STATUS_CHECK_COND:
+		{
+			struct ahc_dma_seg *sg;
+			struct scsi_sense *sc;
+			struct ahc_initiator_tinfo *targ_info;
+			struct ahc_tmode_tstate *tstate;
+			struct ahc_transinfo *tinfo;
 #ifdef AHC_DEBUG
 			if (ahc_debug & AHC_SHOWSENSE) {
 				ahc_print_path(ahc, scb);
@@ -444,99 +460,94 @@
 			}
 #endif
 
-			if (ahc_perform_autosense(scb)) {
-				struct ahc_dma_seg *sg;
-				struct scsi_sense *sc;
-				struct ahc_initiator_tinfo *targ_info;
-				struct tmode_tstate *tstate;
-				struct ahc_transinfo *tinfo;
+			if (ahc_perform_autosense(scb) == 0)
+				break;
 
-				targ_info =
-				    ahc_fetch_transinfo(ahc,
+			targ_info = ahc_fetch_transinfo(ahc,
 							devinfo.channel,
 							devinfo.our_scsiid,
 							devinfo.target,
 							&tstate);
-				tinfo = &targ_info->current;
-				sg = scb->sg_list;
-				sc = (struct scsi_sense *)
-				     (&hscb->shared_data.cdb); 
-				/*
-				 * Save off the residual if there is one.
-				 */
-				if (ahc_check_residual(scb))
-					ahc_calc_residual(scb);
-				else
-					ahc_set_residual(scb, 0);
+			tinfo = &targ_info->curr;
+			sg = scb->sg_list;
+			sc = (struct scsi_sense *)(&hscb->shared_data.cdb); 
+			/*
+			 * Save off the residual if there is one.
+			 */
+			ahc_update_residual(scb);
 #ifdef AHC_DEBUG
-				if (ahc_debug & AHC_SHOWSENSE) {
-					ahc_print_path(ahc, scb);
-					printf("Sending Sense\n");
-				}
+			if (ahc_debug & AHC_SHOWSENSE) {
+				ahc_print_path(ahc, scb);
+				printf("Sending Sense\n");
+			}
 #endif
-				sg->addr = ahc_get_sense_bufaddr(ahc, scb);
-				sg->len = ahc_get_sense_bufsize(ahc, scb);
-				sg->len |= AHC_DMA_LAST_SEG;
-
-				/* Fixup byte order */
-				sg->addr = ahc_htole32(sg->addr);
-				sg->len = ahc_htole32(sg->len);
-
-				sc->opcode = REQUEST_SENSE;
-				sc->byte2 = 0;
-				if (tinfo->protocol_version <= SCSI_REV_2
-				 && SCB_GET_LUN(scb) < 8)
-					sc->byte2 = SCB_GET_LUN(scb) << 5;
-				sc->unused[0] = 0;
-				sc->unused[1] = 0;
-				sc->length = sg->len;
-				sc->control = 0;
+			sg->addr = ahc_get_sense_bufaddr(ahc, scb);
+			sg->len = ahc_get_sense_bufsize(ahc, scb);
+			sg->len |= AHC_DMA_LAST_SEG;
+
+			/* Fixup byte order */
+			sg->addr = ahc_htole32(sg->addr);
+			sg->len = ahc_htole32(sg->len);
+
+			sc->opcode = REQUEST_SENSE;
+			sc->byte2 = 0;
+			if (tinfo->protocol_version <= SCSI_REV_2
+			 && SCB_GET_LUN(scb) < 8)
+				sc->byte2 = SCB_GET_LUN(scb) << 5;
+			sc->unused[0] = 0;
+			sc->unused[1] = 0;
+			sc->length = sg->len;
+			sc->control = 0;
 
-				/*
-				 * XXX Still true???
-				 * Would be nice to preserve DISCENB here,
-				 * but due to the way we manage busy targets,
-				 * we can't.
-				 */
-				hscb->control = 0;
+			/*
+			 * We can't allow the target to disconnect.
+			 * This will be an untagged transaction and
+			 * having the target disconnect will make this
+			 * transaction indestinguishable from outstanding
+			 * tagged transactions.
+			 */
+			hscb->control = 0;
 
-				/*
-				 * This request sense could be because the
-				 * the device lost power or in some other
-				 * way has lost our transfer negotiations.
-				 * Renegotiate if appropriate.  Unit attention
-				 * errors will be reported before any data
-				 * phases occur.
-				 */
-				if (ahc_get_residual(scb) 
-				 == ahc_get_transfer_length(scb)) {
-					ahc_update_target_msg_request(ahc,
-							      &devinfo,
-							      targ_info,
-							      /*force*/TRUE,
-							      /*paused*/TRUE);
-				}
-				hscb->cdb_len = sizeof(*sc);
-				hscb->dataptr = sg->addr; 
-				hscb->datacnt = sg->len;
-				hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
-				hscb->sgptr = ahc_htole32(hscb->sgptr);
-				scb->sg_count = 1;
-				scb->flags |= SCB_SENSE;
-				ahc_qinfifo_requeue_tail(ahc, scb);
-				ahc_outb(ahc, RETURN_1, SEND_SENSE);
+			/*
+			 * This request sense could be because the
+			 * the device lost power or in some other
+			 * way has lost our transfer negotiations.
+			 * Renegotiate if appropriate.  Unit attention
+			 * errors will be reported before any data
+			 * phases occur.
+			 */
+			if (ahc_get_residual(scb) 
+			 == ahc_get_transfer_length(scb)) {
+				ahc_update_neg_request(ahc, &devinfo,
+						       tstate, targ_info,
+						       /*force*/TRUE);
+			}
+			if (tstate->auto_negotiate & devinfo.target_mask) {
+				hscb->control |= MK_MESSAGE;
+				scb->flags &= ~SCB_NEGOTIATE;
+				scb->flags |= SCB_AUTO_NEGOTIATE;
+			}
+			hscb->cdb_len = sizeof(*sc);
+			hscb->dataptr = sg->addr; 
+			hscb->datacnt = sg->len;
+			hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+			hscb->sgptr = ahc_htole32(hscb->sgptr);
+			scb->sg_count = 1;
+			scb->flags |= SCB_SENSE;
+			ahc_qinfifo_requeue_tail(ahc, scb);
+			ahc_outb(ahc, RETURN_1, SEND_SENSE);
 #ifdef __FreeBSD__
-				/*
-				 * Ensure we have enough time to actually
-				 * retrieve the sense.
-				 */
-				untimeout(ahc_timeout, (caddr_t)scb,
-					  scb->io_ctx->ccb_h.timeout_ch);
-				scb->io_ctx->ccb_h.timeout_ch =
-				    timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
+			/*
+			 * Ensure we have enough time to actually
+			 * retrieve the sense.
+			 */
+			untimeout(ahc_timeout, (caddr_t)scb,
+				  scb->io_ctx->ccb_h.timeout_ch);
+			scb->io_ctx->ccb_h.timeout_ch =
+			    timeout(ahc_timeout, (caddr_t)scb, 5 * hz);
 #endif
-			}
 			break;
+		}
 		default:
 			break;
 		}
@@ -577,7 +588,7 @@
 		ahc->msgout_index = 0;
 		ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
 		ahc_outb(ahc, MSG_OUT, HOST_MSG);
-		ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, LASTPHASE) | ATNO);
+		ahc_assert_atn(ahc);
 		break;
 	}
 	case SEND_REJECT: 
@@ -633,7 +644,7 @@
 		       "Lastphase = 0x%x, Curphase = 0x%x\n",
 		       ahc_name(ahc), devinfo.channel, devinfo.target,
 		       lastphase, ahc_inb(ahc, SCSISIGI));
-		restart_sequencer(ahc);
+		ahc_restart(ahc);
 		return;
 	}
 	case HOST_MSG_LOOP:
@@ -650,6 +661,8 @@
 		 * loop.
 		 */
 		if (ahc->msg_type == MSG_TYPE_NONE) {
+			struct scb *scb;
+			u_int scb_index;
 			u_int bus_phase;
 
 			bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
@@ -663,17 +676,13 @@
 				 * we got here.  Just punt the message.
 				 */
 				ahc_clear_intstat(ahc);
-				restart_sequencer(ahc);
+				ahc_restart(ahc);
 				return;
 			}
 
+			scb_index = ahc_inb(ahc, SCB_TAG);
+			scb = ahc_lookup_scb(ahc, scb_index);
 			if (devinfo.role == ROLE_INITIATOR) {
-				struct scb *scb;
-				u_int scb_index;
-
-				scb_index = ahc_inb(ahc, SCB_TAG);
-				scb = ahc_lookup_scb(ahc, scb_index);
-
 				if (scb == NULL)
 					panic("HOST_MSG_LOOP with "
 					      "invalid SCB %x\n", scb_index);
@@ -695,7 +704,9 @@
 				}
 #if AHC_TARGET_MODE
 				else 
-					ahc_setup_target_msgin(ahc, &devinfo);
+					ahc_setup_target_msgin(ahc,
+							       &devinfo,
+							       scb);
 #endif
 			}
 		}
@@ -718,17 +729,20 @@
 		 */
 		if ((intstat & SCSIINT) == 0
 		 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) {
-			u_int curphase;
 
-			/*
-			 * The hardware will only let you ack bytes
-			 * if the expected phase in SCSISIGO matches
-			 * the current phase.  Make sure this is
-			 * currently the case.
-			 */
-			curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
-			ahc_outb(ahc, LASTPHASE, curphase);
-			ahc_outb(ahc, SCSISIGO, curphase);
+			if ((ahc->features & AHC_DT) == 0) {
+				u_int curphase;
+
+				/*
+				 * The hardware will only let you ack bytes
+				 * if the expected phase in SCSISIGO matches
+				 * the current phase.  Make sure this is
+				 * currently the case.
+				 */
+				curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+				ahc_outb(ahc, LASTPHASE, curphase);
+				ahc_outb(ahc, SCSISIGO, curphase);
+			}
 			ahc_inb(ahc, SCSIDATL);
 		}
 		break;
@@ -749,13 +763,13 @@
 
 		scb = ahc_lookup_scb(ahc, scbindex);
 		for (i = 0; i < num_phases; i++) {
-			if (lastphase == phase_table[i].phase)
+			if (lastphase == ahc_phase_table[i].phase)
 				break;
 		}
 		ahc_print_path(ahc, scb);
 		printf("data overrun detected %s."
 		       "  Tag == 0x%x.\n",
-		       phase_table[i].phasemsg,
+		       ahc_phase_table[i].phasemsg,
   		       scb->hscb->tag);
 		ahc_print_path(ahc, scb);
 		printf("%s seen Data Phase.  Length = %ld.  NumSGs = %d.\n",
@@ -858,7 +872,7 @@
 	 *  a SEQINT, so we should restart it when
 	 *  we're done.
 	 */
-	unpause_sequencer(ahc);
+	ahc_unpause(ahc);
 }
 
 void
@@ -897,7 +911,7 @@
 		if (status == 0) {
 			printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
 			ahc_outb(ahc, CLRINT, CLRSCSIINT);
-			unpause_sequencer(ahc);
+			ahc_unpause(ahc);
 			return;
 		}
 	}
@@ -975,10 +989,10 @@
 			errorphase = lastphase;
 
 		for (i = 0; i < num_phases; i++) {
-			if (errorphase == phase_table[i].phase)
+			if (errorphase == ahc_phase_table[i].phase)
 				break;
 		}
-		mesg_out = phase_table[i].mesg_out;
+		mesg_out = ahc_phase_table[i].mesg_out;
 		if (scb != NULL)
 			ahc_print_path(ahc, scb);
 		else
@@ -987,7 +1001,7 @@
 		scsirate = ahc_inb(ahc, SCSIRATE);
 		printf("parity error detected %s. "
 		       "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
-		       phase_table[i].phasemsg,
+		       ahc_phase_table[i].phasemsg,
 		       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8),
 		       scsirate);
 
@@ -1018,7 +1032,45 @@
 				ahc_outb(ahc, MSG_OUT, mesg_out);
 		}
 		ahc_outb(ahc, CLRINT, CLRSCSIINT);
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
+	} else if ((status & SELTO) != 0) {
+		u_int scbptr;
+
+		/* Stop the selection */
+		ahc_outb(ahc, SCSISEQ, 0);
+
+		/* No more pending messages */
+		ahc_clear_msg_state(ahc);
+
+		/* Clear interrupt state */
+		ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+		ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Although the driver does not care about the
+		 * 'Selection in Progress' status bit, the busy
+		 * LED does.  SELINGO is only cleared by a sucessful
+		 * selection, so we must manually clear it to insure
+		 * the LED turns off just incase no future successful
+		 * selections occur (e.g. no devices on the bus).
+		 */
+		ahc_outb(ahc, CLRSINT0, CLRSELINGO);
+
+		scbptr = ahc_inb(ahc, WAITING_SCBH);
+		ahc_outb(ahc, SCBPTR, scbptr);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s: ahc_intr - referenced scb not "
+			       "valid during SELTO scb(%d, %d)\n",
+			       ahc_name(ahc), scbptr, scb_index);
+		} else {
+			ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
+			ahc_freeze_devq(ahc, scb);
+		}
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		ahc_restart(ahc);
 	} else if ((status & BUSFREE) != 0
 		&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
 		u_int lastphase;
@@ -1113,7 +1165,7 @@
 			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
 						MSG_EXT_PPR, FALSE)) {
 				struct ahc_initiator_tinfo *tinfo;
-				struct tmode_tstate *tstate;
+				struct ahc_tmode_tstate *tstate;
 
 				/*
 				 * PPR Rejected.  Try non-ppr negotiation
@@ -1124,7 +1176,7 @@
 							    devinfo.our_scsiid,
 							    devinfo.target,
 							    &tstate);
-				tinfo->current.transport_version = 2;
+				tinfo->curr.transport_version = 2;
 				tinfo->goal.transport_version = 2;
 				tinfo->goal.ppr_options = 0;
 				ahc_qinfifo_requeue_tail(ahc, scb);
@@ -1174,54 +1226,18 @@
 				printf("%s: ", ahc_name(ahc));
 			}
 			for (i = 0; i < num_phases; i++) {
-				if (lastphase == phase_table[i].phase)
+				if (lastphase == ahc_phase_table[i].phase)
 					break;
 			}
 			printf("Unexpected busfree %s\n"
 			       "SEQADDR == 0x%x\n",
-			       phase_table[i].phasemsg, ahc_inb(ahc, SEQADDR0)
+			       ahc_phase_table[i].phasemsg,
+			       ahc_inb(ahc, SEQADDR0)
 				| (ahc_inb(ahc, SEQADDR1) << 8));
 		}
 		ahc_clear_msg_state(ahc);
 		ahc_outb(ahc, CLRINT, CLRSCSIINT);
-		restart_sequencer(ahc);
-	} else if ((status & SELTO) != 0) {
-		u_int scbptr;
-
-		/* Stop the selection */
-		ahc_outb(ahc, SCSISEQ, 0);
-
-		/* No more pending messages */
-		ahc_clear_msg_state(ahc);
-
-		/* Clear interrupt state */
-		ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
-
-		/*
-		 * Although the driver does not care about the
-		 * 'Selection in Progress' status bit, the busy
-		 * LED does.  SELINGO is only cleared by a sucessful
-		 * selection, so we must manually clear it to insure
-		 * the LED turns off just incase no future successful
-		 * selections occur (e.g. no devices on the bus).
-		 */
-		ahc_outb(ahc, CLRSINT0, CLRSELINGO);
-
-		scbptr = ahc_inb(ahc, WAITING_SCBH);
-		ahc_outb(ahc, SCBPTR, scbptr);
-		scb_index = ahc_inb(ahc, SCB_TAG);
-
-		scb = ahc_lookup_scb(ahc, scb_index);
-		if (scb == NULL) {
-			printf("%s: ahc_intr - referenced scb not "
-			       "valid during SELTO scb(%d, %d)\n",
-			       ahc_name(ahc), scbptr, scb_index);
-		} else {
-			ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
-			ahc_freeze_devq(ahc, scb);
-		}
-		ahc_outb(ahc, CLRINT, CLRSCSIINT);
-		restart_sequencer(ahc);
+		ahc_restart(ahc);
 	} else {
 		printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
 		       ahc_name(ahc), status);
@@ -1290,7 +1306,7 @@
 		ahc_outb(ahc, HCNTRL, ahc->unpause);
 		do {
 			ahc_delay(200);
-		} while (!sequencer_paused(ahc));
+		} while (!ahc_is_paused(ahc));
 	}
 	if (stepping) {
 		ahc_outb(ahc, SIMODE0, simode0);
@@ -1363,11 +1379,11 @@
  * Allocate per target mode instance (ID we respond to as a target)
  * transfer negotiation data structures.
  */
-static struct tmode_tstate *
+static struct ahc_tmode_tstate *
 ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
 {
-	struct tmode_tstate *master_tstate;
-	struct tmode_tstate *tstate;
+	struct ahc_tmode_tstate *master_tstate;
+	struct ahc_tmode_tstate *tstate;
 	int i;
 
 	master_tstate = ahc->enabled_targets[ahc->our_id];
@@ -1394,8 +1410,8 @@
 		memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
 		tstate->ultraenb = 0;
 		for (i = 0; i < 16; i++) {
-			memset(&tstate->transinfo[i].current, 0,
-			      sizeof(tstate->transinfo[i].current));
+			memset(&tstate->transinfo[i].curr, 0,
+			      sizeof(tstate->transinfo[i].curr));
 			memset(&tstate->transinfo[i].goal, 0,
 			      sizeof(tstate->transinfo[i].goal));
 		}
@@ -1413,11 +1429,13 @@
 static void
 ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
 {
-	struct tmode_tstate *tstate;
+	struct ahc_tmode_tstate *tstate;
 
-	/* Don't clean up the entry for our initiator role */
-	if ((ahc->flags & AHC_INITIATORROLE) != 0
-	 && ((channel == 'B' && scsi_id == ahc->our_id_b)
+	/*
+	 * Don't clean up our "master" tstate.
+	 * It has our default user settings.
+	 */
+	if (((channel == 'B' && scsi_id == ahc->our_id_b)
 	  || (channel == 'A' && scsi_id == ahc->our_id))
 	 && force == FALSE)
 		return;
@@ -1496,6 +1514,11 @@
 
 	if ((ahc->features & AHC_DT) == 0)
 		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+
+	/* Skip all DT only entries if DT is not available */
+	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+	 && maxsync < AHC_SYNCRATE_ULTRA2)
+		maxsync = AHC_SYNCRATE_ULTRA2;
 	
 	for (syncrate = &ahc_syncrates[maxsync];
 	     syncrate->rate != NULL;
@@ -1509,11 +1532,6 @@
 		 && (syncrate->sxfr_u2 == 0))
 			break;
 
-		/* Skip any DT entries if DT is not available */
-		if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
-		 && (syncrate->sxfr_u2 & DT_SXFR) != 0)
-			continue;
-
 		if (*period <= syncrate->period) {
 			/*
 			 * When responding to a target that requests
@@ -1647,44 +1665,31 @@
  * means the next time we send the initial identify messages for
  * a new transaction.
  */
-void
-ahc_update_target_msg_request(struct ahc_softc *ahc,
-			      struct ahc_devinfo *devinfo,
-			      struct ahc_initiator_tinfo *tinfo,
-			      int force, int paused)
-{
-	u_int targ_msg_req_orig;
-
-	targ_msg_req_orig = ahc->targ_msg_req;
-	if (tinfo->current.period != tinfo->goal.period
-	 || tinfo->current.width != tinfo->goal.width
-	 || tinfo->current.offset != tinfo->goal.offset
-	 || tinfo->current.ppr_options != tinfo->goal.ppr_options
+int
+ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		       struct ahc_tmode_tstate *tstate,
+		       struct ahc_initiator_tinfo *tinfo, int force)
+{
+	u_int auto_negotiate_orig;
+
+	auto_negotiate_orig = tstate->auto_negotiate;
+	if (tinfo->curr.period != tinfo->goal.period
+	 || tinfo->curr.width != tinfo->goal.width
+	 || tinfo->curr.offset != tinfo->goal.offset
+	 || tinfo->curr.ppr_options != tinfo->goal.ppr_options
 	 || (force
 	  && (tinfo->goal.period != 0
 	   || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
 	   || tinfo->goal.ppr_options != 0)))
-		ahc->targ_msg_req |= devinfo->target_mask;
+		tstate->auto_negotiate |= devinfo->target_mask;
 	else
-		ahc->targ_msg_req &= ~devinfo->target_mask;
+		tstate->auto_negotiate &= ~devinfo->target_mask;
 
-	if (ahc->targ_msg_req != targ_msg_req_orig) {
-		/* Update the message request bit for this target */
-		if (!paused)
-			pause_sequencer(ahc);
-
-		ahc_outb(ahc, TARGET_MSG_REQUEST,
-			 ahc->targ_msg_req & 0xFF);
-		ahc_outb(ahc, TARGET_MSG_REQUEST + 1,
-			 (ahc->targ_msg_req >> 8) & 0xFF);
-
-		if (!paused)
-			unpause_sequencer(ahc);
-	}
+	return (auto_negotiate_orig != tstate->auto_negotiate);
 }
 
 /*
- * Update the user/goal/current tables of synchronous negotiation
+ * Update the user/goal/curr tables of synchronous negotiation
  * parameters as well as, in the case of a current or active update,
  * any data structures on the host controller.  In the case of an
  * active update, the specified target is currently talking to us on
@@ -1697,11 +1702,15 @@
 		 u_int offset, u_int ppr_options, u_int type, int paused)
 {
 	struct	ahc_initiator_tinfo *tinfo;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	u_int	old_period;
 	u_int	old_offset;
 	u_int	old_ppr;
-	int	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	int	active;
+	int	update_needed;
+
+	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	update_needed = 0;
 
 	if (syncrate == NULL) {
 		period = 0;
@@ -1723,9 +1732,9 @@
 		tinfo->goal.ppr_options = ppr_options;
 	}
 
-	old_period = tinfo->current.period;
-	old_offset = tinfo->current.offset;
-	old_ppr	   = tinfo->current.ppr_options;
+	old_period = tinfo->curr.period;
+	old_offset = tinfo->curr.offset;
+	old_ppr	   = tinfo->curr.ppr_options;
 
 	if ((type & AHC_TRANS_CUR) != 0
 	 && (old_period != period
@@ -1733,6 +1742,7 @@
 	  || old_ppr != ppr_options)) {
 		u_int	scsirate;
 
+		update_needed++;
 		scsirate = tinfo->scsirate;
 		if ((ahc->features & AHC_ULTRA2) != 0) {
 
@@ -1777,15 +1787,12 @@
 		}
 
 		tinfo->scsirate = scsirate;
-		tinfo->current.period = period;
-		tinfo->current.offset = offset;
-		tinfo->current.ppr_options = ppr_options;
-
-		/* Update the syncrates in any pending scbs */
-		ahc_update_pending_syncrates(ahc);
+		tinfo->curr.period = period;
+		tinfo->curr.offset = offset;
+		tinfo->curr.ppr_options = ppr_options;
 
 		ahc_send_async(ahc, devinfo->channel, devinfo->target,
-			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
 		if (bootverbose) {
 			if (offset != 0) {
 				printf("%s: target %d synchronous at %sMHz%s, "
@@ -1801,13 +1808,15 @@
 		}
 	}
 
-	ahc_update_target_msg_request(ahc, devinfo, tinfo,
-				      /*force*/FALSE,
-				      paused);
+	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
+						tinfo, /*force*/FALSE);
+
+	if (update_needed)
+		ahc_update_pending_scbs(ahc);
 }
 
 /*
- * Update the user/goal/current tables of wide negotiation
+ * Update the user/goal/curr tables of wide negotiation
  * parameters as well as, in the case of a current or active update,
  * any data structures on the host controller.  In the case of an
  * active update, the specified target is currently talking to us on
@@ -1818,11 +1827,14 @@
 ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
 	      u_int width, u_int type, int paused)
 {
-	struct ahc_initiator_tinfo *tinfo;
-	struct tmode_tstate *tstate;
-	u_int  oldwidth;
-	int    active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	u_int	oldwidth;
+	int	active;
+	int	update_needed;
 
+	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	update_needed = 0;
 	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
 				    devinfo->target, &tstate);
 
@@ -1832,10 +1844,11 @@
 	if ((type & AHC_TRANS_GOAL) != 0)
 		tinfo->goal.width = width;
 
-	oldwidth = tinfo->current.width;
+	oldwidth = tinfo->curr.width;
 	if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {
 		u_int	scsirate;
 
+		update_needed++;
 		scsirate =  tinfo->scsirate;
 		scsirate &= ~WIDEXFER;
 		if (width == MSG_EXT_WDTR_BUS_16_BIT)
@@ -1846,10 +1859,10 @@
 		if (active)
 			ahc_outb(ahc, SCSIRATE, scsirate);
 
-		tinfo->current.width = width;
+		tinfo->curr.width = width;
 
 		ahc_send_async(ahc, devinfo->channel, devinfo->target,
-			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
 		if (bootverbose) {
 			printf("%s: target %d using %dbit transfers\n",
 			       ahc_name(ahc), devinfo->target,
@@ -1857,35 +1870,22 @@
 		}
 	}
 
-	ahc_update_target_msg_request(ahc, devinfo, tinfo,
-				      /*force*/FALSE, paused);
+	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
+						tinfo, /*force*/FALSE);
+	if (update_needed)
+		ahc_update_pending_scbs(ahc);
 }
 
 /*
  * Update the current state of tagged queuing for a given target.
  */
 void
-ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, int enable)
+ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+	     ahc_queue_alg alg)
 {
-	struct ahc_initiator_tinfo *tinfo;
-	struct tmode_tstate *tstate;
-	uint16_t orig_tagenable;
-
-	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
-				    devinfo->target, &tstate);
-
-	orig_tagenable = tstate->tagenable;
-	if (enable)
-		tstate->tagenable |= devinfo->target_mask;
-	else
-		tstate->tagenable &= ~devinfo->target_mask;
-
-	if (orig_tagenable != tstate->tagenable) {
-		ahc_platform_set_tags(ahc, devinfo, enable);
-		ahc_send_async(ahc, devinfo->channel, devinfo->target,
-			       devinfo->lun, AC_TRANSFER_NEG);
-	}
-
+ 	ahc_platform_set_tags(ahc, devinfo, alg);
+ 	ahc_send_async(ahc, devinfo->channel, devinfo->target,
+ 		       devinfo->lun, AC_TRANSFER_NEG, &alg);
 }
 
 /*
@@ -1894,11 +1894,12 @@
  * be set correctly during future (re)selections.
  */
 static void
-ahc_update_pending_syncrates(struct ahc_softc *ahc)
+ahc_update_pending_scbs(struct ahc_softc *ahc)
 {
 	struct	scb *pending_scb;
 	int	pending_scb_count;
 	int	i;
+	int	paused;
 	u_int	saved_scbptr;
 
 	/*
@@ -1910,7 +1911,7 @@
 		struct ahc_devinfo devinfo;
 		struct hardware_scb *pending_hscb;
 		struct ahc_initiator_tinfo *tinfo;
-		struct tmode_tstate *tstate;
+		struct ahc_tmode_tstate *tstate;
 		
 		ahc_scb_devinfo(ahc, &devinfo, pending_scb);
 		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
@@ -1921,13 +1922,25 @@
 		if ((tstate->ultraenb & devinfo.target_mask) != 0)
 			pending_hscb->control |= ULTRAENB;
 		pending_hscb->scsirate = tinfo->scsirate;
-		pending_hscb->scsioffset = tinfo->current.offset;
+		pending_hscb->scsioffset = tinfo->curr.offset;
+		if ((tstate->auto_negotiate & devinfo.target_mask) == 0
+		 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {
+			pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
+			pending_hscb->control &= ~MK_MESSAGE;
+		}
 		pending_scb_count++;
 	}
 
 	if (pending_scb_count == 0)
 		return;
 
+	if (ahc_is_paused(ahc)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahc_pause(ahc);
+	}
+
 	saved_scbptr = ahc_inb(ahc, SCBPTR);
 	/* Ensure that the hscbs down on the card match the new information */
 	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
@@ -1943,14 +1956,16 @@
 
 		pending_hscb = pending_scb->hscb;
 		control = ahc_inb(ahc, SCB_CONTROL);
-		control &= ~ULTRAENB;
-		if ((pending_hscb->control & ULTRAENB) != 0)
-			control |= ULTRAENB;
+		control &= ~(ULTRAENB|MK_MESSAGE);
+		control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE);
 		ahc_outb(ahc, SCB_CONTROL, control);
 		ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate);
 		ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset);
 	}
 	ahc_outb(ahc, SCBPTR, saved_scbptr);
+
+	if (paused == 0)
+		ahc_unpause(ahc);
 }
 
 /**************************** Pathing Information *****************************/
@@ -1985,6 +2000,24 @@
 			    role);
 }
 
+struct ahc_phase_table_entry*
+ahc_lookup_phase_entry(int phase)
+{
+	struct ahc_phase_table_entry *entry;
+	struct ahc_phase_table_entry *last_entry;
+
+	/*
+	 * num_phases doesn't include the default entry which
+	 * will be returned if the phase doesn't match.
+	 */
+	last_entry = &ahc_phase_table[num_phases];
+	for (entry = ahc_phase_table; entry < last_entry; entry++) {
+		if (phase == entry->phase)
+			break;
+	}
+	return (entry);
+}
+
 void
 ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
 		    u_int lun, char channel, role_t role)
@@ -2017,6 +2050,17 @@
 
 
 /************************ Message Phase Processing ****************************/
+static void
+ahc_assert_atn(struct ahc_softc *ahc)
+{
+	u_int scsisigo;
+
+	scsisigo = ATNO;
+	if ((ahc->features & AHC_DT) == 0)
+		scsisigo |= ahc_inb(ahc, SCSISIGI);
+	ahc_outb(ahc, SCSISIGO, scsisigo);
+}
+
 /*
  * When an initiator transaction with the MK_MESSAGE flag either reconnects
  * or enters the initial message out phase, we are interrupted.  Fill our
@@ -2083,8 +2127,7 @@
 		 * away.
 		 */
 		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
-	} else if ((ahc->targ_msg_req & devinfo->target_mask) != 0
-		|| (scb->flags & SCB_NEGOTIATE) != 0) {
+	} else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) {
 		ahc_build_transfer_msg(ahc, devinfo);
 	} else {
 		printf("ahc_intr: AWAITING_MSG for an SCB that "
@@ -2101,6 +2144,7 @@
 	 * asked to send this message again.
 	 */
 	ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE);
+	scb->hscb->control &= ~MK_MESSAGE;
 	ahc->msgout_index = 0;
 	ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
 }
@@ -2118,7 +2162,7 @@
 	 * we want to renegotiate due to a check condition.
 	 */
 	struct	ahc_initiator_tinfo *tinfo;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	struct	ahc_syncrate *rate;
 	int	dowide;
 	int	dosync;
@@ -2130,9 +2174,19 @@
 
 	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
 				    devinfo->target, &tstate);
-	dowide = tinfo->current.width != tinfo->goal.width;
-	dosync = tinfo->current.period != tinfo->goal.period;
-	doppr = tinfo->current.ppr_options != tinfo->goal.ppr_options;
+	/*
+	 * Filter our period based on the current connection.
+	 * If we can't perform DT transfers on this segment (not in LVD
+	 * mode for instance), then our decision to issue a PPR message
+	 * may change.
+	 */
+	period = tinfo->goal.period;
+	ppr_options = tinfo->goal.ppr_options;
+	rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+				       &ppr_options, devinfo->role);
+	dowide = tinfo->curr.width != tinfo->goal.width;
+	dosync = tinfo->curr.period != period;
+	doppr = tinfo->curr.ppr_options != ppr_options;
 
 	if (!dowide && !dosync && !doppr) {
 		dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
@@ -2145,7 +2199,7 @@
 		      "but no negotiation needed\n");	
 	}
 
-	use_ppr = (tinfo->current.transport_version >= 3) || doppr;
+	use_ppr = (tinfo->curr.transport_version >= 3) || doppr;
 	/* Target initiated PPR is not allowed in the SCSI spec */
 	if (devinfo->role == ROLE_TARGET)
 		use_ppr = 0;
@@ -2160,16 +2214,10 @@
 	 */
 	if (use_ppr || (dosync && !dowide)) {
 
-		period = tinfo->goal.period;
-		ppr_options = tinfo->goal.ppr_options;
-		if (use_ppr == 0)
-			ppr_options = 0;
-		rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
-					       &ppr_options, devinfo->role);
 		offset = tinfo->goal.offset;
 		ahc_validate_offset(ahc, tinfo, rate, &offset,
 				    use_ppr ? tinfo->goal.width
-					    : tinfo->current.width,
+					    : tinfo->curr.width,
 				    devinfo->role);
 		if (use_ppr) {
 			ahc_construct_ppr(ahc, devinfo, period, offset,
@@ -2258,7 +2306,7 @@
 	ahc->msgout_len = 0;
 	ahc->msgin_index = 0;
 	ahc->msg_type = MSG_TYPE_NONE;
-	if ((ahc_inb(ahc, SCSISIGI) & ATNI) == 0) {
+	if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) {
 		/*
 		 * The target didn't care to respond to our
 		 * message request, so clear ATN.
@@ -2327,7 +2375,7 @@
 			 * 0, and try again.
 			 */
 			ahc->msgout_index = 0;
-			ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+			ahc_assert_atn(ahc);
 		}
 
 		lastbyte = ahc->msgout_index == (ahc->msgout_len - 1);
@@ -2382,8 +2430,7 @@
 			 * message out phase.
 			 */
 			if (ahc->msgout_len != 0)
-				ahc_outb(ahc, SCSISIGO,
-					 ahc_inb(ahc, SCSISIGO) | ATNO);
+				ahc_assert_atn(ahc);
 		} else 
 			ahc->msgin_index++;
 
@@ -2548,7 +2595,7 @@
 					found = TRUE;
 			}
 			index = end_index;
-		} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_Q_TAG
+		} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK
 			&& ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
 
 			/* Skip tag type and tag id or residue param*/
@@ -2575,7 +2622,7 @@
 ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
 {
 	struct	ahc_initiator_tinfo *tinfo;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	int	reject;
 	int	done;
 	int	response;
@@ -2674,7 +2721,8 @@
 				/*
 				 * Send our own SDTR in reply
 				 */
-				if (bootverbose) {
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
 					printf("(%s:%c:%d:%d): Target "
 					       "Initiated SDTR\n",
 					       ahc_name(ahc), devinfo->channel,
@@ -2744,7 +2792,8 @@
 				/*
 				 * Send our own WDTR in reply
 				 */
-				if (bootverbose) {
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
 					printf("(%s:%c:%d:%d): Target "
 					       "Initiated WDTR\n",
 					       ahc_name(ahc), devinfo->channel,
@@ -2879,7 +2928,7 @@
 				       "offset %x, options %x\n",
 				       ahc_name(ahc), devinfo->channel,
 				       devinfo->target, devinfo->lun,
-				       ahc->msgin_buf[3], saved_width,
+				       saved_width, ahc->msgin_buf[3],
 				       saved_offset, saved_ppr_options,
 				       bus_width, period, offset, ppr_options);
 			}
@@ -2906,7 +2955,7 @@
 				    CAM_BDR_SENT,
 				    "Bus Device Reset Received",
 				    /*verbose_level*/0);
-		restart_sequencer(ahc);
+		ahc_restart(ahc);
 		done = MSGLOOP_TERMINATED;
 		break;
 	case MSG_ABORT_TAG:
@@ -2927,7 +2976,7 @@
 
 		tstate = ahc->enabled_targets[devinfo->our_scsiid];
 		if (tstate != NULL) {
-			struct tmode_lstate* lstate;
+			struct ahc_tmode_lstate* lstate;
 
 			lstate = tstate->enabled_luns[devinfo->lun];
 			if (lstate != NULL) {
@@ -2979,7 +3028,7 @@
 	 */
 	struct scb *scb;
 	struct ahc_initiator_tinfo *tinfo;
-	struct tmode_tstate *tstate;
+	struct ahc_tmode_tstate *tstate;
 	u_int scb_index;
 	u_int last_msg;
 	int   response = 0;
@@ -3004,7 +3053,7 @@
 			       devinfo->target, devinfo->lun);
 		}
 		tinfo->goal.ppr_options = 0;
-		tinfo->current.transport_version = 2;
+		tinfo->curr.transport_version = 2;
 		tinfo->goal.transport_version = 2;
 		ahc->msgout_index = 0;
 		ahc->msgout_len = 0;
@@ -3046,24 +3095,39 @@
 		       "Using asynchronous transfers\n",
 		       ahc_name(ahc), devinfo->channel,
 		       devinfo->target, devinfo->lun);
-	} else if ((scb->hscb->control & MSG_SIMPLE_Q_TAG) != 0) {
-
-		printf("(%s:%c:%d:%d): refuses tagged commands.  Performing "
-		       "non-tagged I/O\n", ahc_name(ahc),
-		       devinfo->channel, devinfo->target, devinfo->lun);
-		ahc_set_tags(ahc, devinfo, FALSE);
+	} else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) {
+		int tag_type;
+		int mask;
+
+		tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
+
+		if (tag_type == MSG_SIMPLE_TASK) {
+			printf("(%s:%c:%d:%d): refuses tagged commands.  "
+			       "Performing non-tagged I/O\n", ahc_name(ahc),
+			       devinfo->channel, devinfo->target, devinfo->lun);
+			ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE);
+			mask = ~0x23;
+		} else {
+			printf("(%s:%c:%d:%d): refuses %s tagged commands.  "
+			       "Performing simple queue tagged I/O only\n",
+			       ahc_name(ahc), devinfo->channel, devinfo->target,
+			       devinfo->lun, tag_type == MSG_ORDERED_TASK
+			       ? "ordered" : "head of queue");
+			ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC);
+			mask = ~0x03;
+		}
 
 		/*
 		 * Resend the identify for this CCB as the target
 		 * may believe that the selection is invalid otherwise.
 		 */
 		ahc_outb(ahc, SCB_CONTROL,
-			 ahc_inb(ahc, SCB_CONTROL) & ~MSG_SIMPLE_Q_TAG);
-	 	scb->hscb->control &= ~MSG_SIMPLE_Q_TAG;
+			 ahc_inb(ahc, SCB_CONTROL) & mask);
+	 	scb->hscb->control &= mask;
 		ahc_set_transaction_tag(scb, /*enabled*/FALSE,
-					/*type*/MSG_SIMPLE_Q_TAG);
+					/*type*/MSG_SIMPLE_TASK);
 		ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG);
-		ahc_outb(ahc, SCSISIGO, ahc_inb(ahc, SCSISIGO) | ATNO);
+		ahc_assert_atn(ahc);
 
 		/*
 		 * This transaction is now at the head of
@@ -3225,7 +3289,7 @@
 		    cam_status status, char *message, int verbose_level)
 {
 #ifdef AHC_TARGET_MODE
-	struct tmode_tstate* tstate;
+	struct ahc_tmode_tstate* tstate;
 	u_int lun;
 #endif
 	int found;
@@ -3242,7 +3306,7 @@
 	tstate = ahc->enabled_targets[devinfo->our_scsiid];
 	if (tstate != NULL) {
 		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
-			struct tmode_lstate* lstate;
+			struct ahc_tmode_lstate* lstate;
 
 			lstate = tstate->enabled_luns[lun];
 			if (lstate == NULL)
@@ -3265,7 +3329,7 @@
 			 AHC_TRANS_CUR, /*paused*/TRUE);
 	
 	ahc_send_async(ahc, devinfo->channel, devinfo->target,
-		       CAM_LUN_WILDCARD, AC_SENT_BDR);
+		       CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
 
 	if (message != NULL
 	 && (verbose_level <= bootverbose))
@@ -3274,9 +3338,11 @@
 }
 
 #ifdef AHC_TARGET_MODE
-void
-ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+static void
+ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		       struct scb *scb)
 {
+
 	/*              
 	 * To facilitate adding multiple messages together,
 	 * each routine should increment the index and len
@@ -3285,7 +3351,7 @@
 	ahc->msgout_index = 0;
 	ahc->msgout_len = 0;
 
-	if ((ahc->targ_msg_req & devinfo->target_mask) != 0)
+	if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0)
 		ahc_build_transfer_msg(ahc, devinfo);
 	else
 		panic("ahc_intr: AWAITING target message with no message");
@@ -3319,6 +3385,7 @@
 	LIST_INIT(&ahc->pending_scbs);
 	/* We don't know our unit number until the OSM sets it */
 	ahc->name = name;
+	ahc->unit = -1;
 	for (i = 0; i < 16; i++)
 		TAILQ_INIT(&ahc->untagged_queues[i]);
 	if (ahc_platform_alloc(ahc, platform_arg) != 0) {
@@ -3337,7 +3404,7 @@
 	ahc->bugs = config->bugs;
 	ahc->flags = config->flags;
 	ahc->channel = config->channel; 
-	ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN;
+	ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS);
 	ahc->description = config->description;
 	/* The IRQMS bit is only valid on VL and EISA chips */
 	if ((ahc->chip & AHC_PCI) != 0)
@@ -3360,29 +3427,37 @@
 {
 	struct ahc_softc *list_ahc;
 
-#ifdef AHC_SUPPORT_PCI
+#if AHC_PCI_CONFIG > 0
 	/*
 	 * Second Function PCI devices need to inherit some
-	 * settings from function 0.  We assume that function 0
-	 * will always be found prior to function 1.
+	 * settings from function 0.
 	 */
 	if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI
-	 && ahc_get_pci_function(ahc->dev_softc) == 1) {
+	 && (ahc->features & AHC_MULTI_FUNC) != 0) {
 		TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
 			ahc_dev_softc_t list_pci;
 			ahc_dev_softc_t pci;
 
 			list_pci = list_ahc->dev_softc;
 			pci = ahc->dev_softc;
-			if (ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)
-			 && ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
-			 && ahc_get_pci_function(list_pci) == 0) {
-				ahc->flags &= ~AHC_BIOS_ENABLED; 
-				ahc->flags |=
-				    list_ahc->flags & AHC_BIOS_ENABLED;
-				ahc->flags &= ~AHC_CHANNEL_B_PRIMARY; 
-				ahc->flags |=
-				    list_ahc->flags & AHC_CHANNEL_B_PRIMARY;
+			if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
+			 && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) {
+				struct ahc_softc *master;
+				struct ahc_softc *slave;
+
+				if (ahc_get_pci_function(list_pci) == 0) {
+					master = list_ahc;
+					slave = ahc;
+				} else {
+					master = ahc;
+					slave = list_ahc;
+				}
+				slave->flags &= ~AHC_BIOS_ENABLED; 
+				slave->flags |=
+				    master->flags & AHC_BIOS_ENABLED;
+				slave->flags &= ~AHC_PRIMARY_CHANNEL; 
+				slave->flags |=
+				    master->flags & AHC_PRIMARY_CHANNEL;
 				break;
 			}
 		}
@@ -3455,7 +3530,7 @@
 #endif
 	ahc_platform_free(ahc);
 	for (i = 0; i < AHC_NUM_TARGETS; i++) {
-		struct tmode_tstate *tstate;
+		struct ahc_tmode_tstate *tstate;
 
 		tstate = ahc->enabled_targets[i];
 		if (tstate != NULL) {
@@ -3463,7 +3538,7 @@
 			int j;
 
 			for (j = 0; j < AHC_NUM_LUNS; j++) {
-				struct tmode_lstate *lstate;
+				struct ahc_tmode_lstate *lstate;
 
 				lstate = tstate->enabled_luns[j];
 				if (lstate != NULL) {
@@ -3523,7 +3598,7 @@
 	 * It contains settings that affect termination and we don't want
 	 * to disturb the integrity of the bus.
 	 */
-	pause_sequencer(ahc);
+	ahc_pause(ahc);
 	sxfrctl1_b = 0;
 	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
 		u_int sblkctl;
@@ -3961,17 +4036,26 @@
  		len = sprintf(buf, "Twin Channel, A SCSI Id=%d, "
 			      "B SCSI Id=%d, primary %c, ",
 			      ahc->our_id, ahc->our_id_b,
-			      ahc->flags & AHC_CHANNEL_B_PRIMARY ? 'B': 'A');
+			      (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A');
 	else {
+		const char *speed;
 		const char *type;
 
+		speed = "";
+		if ((ahc->features & AHC_ULTRA) != 0) {
+			speed = "Ultra ";
+		} else if ((ahc->features & AHC_DT) != 0) {
+			speed = "Ultra160 ";
+		} else if ((ahc->features & AHC_ULTRA2) != 0) {
+			speed = "Ultra2 ";
+		}
 		if ((ahc->features & AHC_WIDE) != 0) {
 			type = "Wide";
 		} else {
 			type = "Single";
 		}
-		len = sprintf(buf, "%s Channel %c, SCSI Id=%d, ",
-			      type, ahc->channel, ahc->our_id);
+		len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ",
+			      speed, type, ahc->channel, ahc->our_id);
 	}
 	buf += len;
 
@@ -4124,16 +4208,16 @@
 	 * data for any target mode initiator.
 	 */
 	if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
-		printf("%s: unable to allocate tmode_tstate.  "
+		printf("%s: unable to allocate ahc_tmode_tstate.  "
 		       "Failing attach\n", ahc_name(ahc));
-		return (-1);
+		return (ENOMEM);
 	}
 
 	if ((ahc->features & AHC_TWIN) != 0) {
 		if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
-			printf("%s: unable to allocate tmode_tstate.  "
+			printf("%s: unable to allocate ahc_tmode_tstate.  "
 			       "Failing attach\n", ahc_name(ahc));
-			return (-1);
+			return (ENOMEM);
 		}
 	}
 
@@ -4231,7 +4315,7 @@
 
 	for (i = 0; i <= max_targ; i++) {
 		struct ahc_initiator_tinfo *tinfo;
-		struct tmode_tstate *tstate;
+		struct ahc_tmode_tstate *tstate;
 		u_int our_id;
 		u_int target_id;
 		char channel;
@@ -4324,12 +4408,10 @@
 				tinfo->user.transport_version = 2;
 			tinfo->goal.protocol_version = 2;
 			tinfo->goal.transport_version = 2;
-			tinfo->current.protocol_version = 2;
-			tinfo->current.transport_version = 2;
+			tinfo->curr.protocol_version = 2;
+			tinfo->curr.transport_version = 2;
 		}
 		tstate->ultraenb = ultraenb;
-		tstate->discenable = discenable;
-		tstate->tagenable = 0; /* Wait until the XPT says its okay */
 	}
 	ahc->user_discenable = discenable;
 	ahc->user_tagenable = tagenable;
@@ -4395,10 +4477,6 @@
 	ahc_outb(ahc, QINPOS, 0);
 	ahc_outb(ahc, QOUTPOS, 0);
 
-	/* Don't have any special messages to send to targets */
-	ahc_outb(ahc, TARGET_MSG_REQUEST, 0);
-	ahc_outb(ahc, TARGET_MSG_REQUEST + 1, 0);
-
 	/*
 	 * Use the built in queue management registers
 	 * if they are available.
@@ -4450,16 +4528,33 @@
 		 * never settle, so don't complain if we
 		 * fail here.
 		 */
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		for (wait = 5000;
 		     (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
 		     wait--)
 			ahc_delay(100);
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 	}
 	return (0);
 }
 
+void
+ahc_intr_enable(struct ahc_softc *ahc, int enable)
+{
+	u_int hcntrl;
+
+	hcntrl = ahc_inb(ahc, HCNTRL);
+	hcntrl &= ~INTEN;
+	ahc->pause &= ~INTEN;
+	ahc->unpause &= ~INTEN;
+	if (enable) {
+		hcntrl |= INTEN;
+		ahc->pause |= INTEN;
+		ahc->unpause |= INTEN;
+	}
+	ahc_outb(ahc, HCNTRL, hcntrl);
+}
+
 /*
  * Ensure that the card is paused in a location
  * outside of all critical sections and that all
@@ -4478,7 +4573,7 @@
 	intstat = 0;
 	do {
 		ahc_intr(ahc);
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		ahc_clear_critical_section(ahc);
 		if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
 			break;
@@ -5409,7 +5504,7 @@
 			    CAM_TARGET_WILDCARD,
 			    CAM_LUN_WILDCARD,
 			    channel, ROLE_UNKNOWN);
-	pause_sequencer(ahc);
+	ahc_pause(ahc);
 
 	/* Make sure the sequencer is in a safe location. */
 	ahc_clear_critical_section(ahc);
@@ -5478,14 +5573,14 @@
 	 * drivers affected by this action.
 	 */
 	for (target = 0; target <= max_scsiid; target++) {
-		struct tmode_tstate* tstate;
+		struct ahc_tmode_tstate* tstate;
 		u_int lun;
 
 		tstate = ahc->enabled_targets[target];
 		if (tstate == NULL)
 			continue;
 		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
-			struct tmode_lstate* lstate;
+			struct ahc_tmode_lstate* lstate;
 
 			lstate = tstate->enabled_luns[lun];
 			if (lstate == NULL)
@@ -5499,7 +5594,7 @@
 #endif
 	/* Notify the XPT that a bus reset occurred */
 	ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
-		       CAM_LUN_WILDCARD, AC_BUS_RESET);
+		       CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
 
 	/*
 	 * Revert to async/narrow transfers until we renegotiate.
@@ -5524,9 +5619,9 @@
 	}
 
 	if (restart_needed)
-		restart_sequencer(ahc);
+		ahc_restart(ahc);
 	else
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 	return found;
 }
 
@@ -5535,7 +5630,7 @@
 /*
  * Calculate the residual for a just completed SCB.
  */
-static void
+void
 ahc_calc_residual(struct scb *scb)
 {
 	struct hardware_scb *hscb;
@@ -5623,7 +5718,7 @@
  * Add a target mode event to this lun's queue
  */
 static void
-ahc_queue_lstate_event(struct ahc_softc *ahc, struct tmode_lstate *lstate,
+ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate,
 		       u_int initiator_id, u_int event_type, u_int event_arg)
 {
 	struct ahc_tmode_event *event;
@@ -5674,7 +5769,7 @@
  * for immediate notify resources.
  */
 void
-ahc_send_lstate_events(struct ahc_softc *ahc, struct tmode_lstate *lstate)
+ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate)
 {
 	struct ccb_hdr *ccbh;
 	struct ccb_immed_notify *inot;
@@ -5825,7 +5920,7 @@
 		memcpy(ahc->critical_sections, cs_table, cs_count);
 	}
 	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
-	restart_sequencer(ahc);
+	ahc_restart(ahc);
 
 	if (bootverbose)
 		printf(" %d instructions downloaded\n", downloaded);
@@ -6000,6 +6095,7 @@
 	int target;
 	int maxtarget;
 	int i;
+	uint8_t last_phase;
 	uint8_t qinpos;
 	uint8_t qintail;
 	uint8_t qoutpos;
@@ -6008,13 +6104,25 @@
 
 	saved_scbptr = ahc_inb(ahc, SCBPTR);
 
-	printf("%s: Dumping Card State at SEQADDR 0x%x\n",
-	       ahc_name(ahc),
+	last_phase = ahc_inb(ahc, LASTPHASE);
+	printf("%s: Dumping Card State %s, at SEQADDR 0x%x\n",
+	       ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
 	       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
-
-	printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x, SSTAT0 0x%x\n",
-	       ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL),
-	       ahc_inb(ahc, SSTAT0));
+	printf("SCSISEQ = 0x%x, SBLKCTL = 0x%x\n",
+	       ahc_inb(ahc, SCSISEQ), ahc_inb(ahc, SBLKCTL));
+	printf(" DFCNTRL = 0x%x, DFSTATUS = 0x%x\n",
+	       ahc_inb(ahc, DFCNTRL), ahc_inb(ahc, DFSTATUS));
+	printf("LASTPHASE = 0x%x, SCSISIGI = 0x%x, SXFRCTL0 = 0x%x\n",
+	       last_phase, ahc_inb(ahc, SCSISIGI), ahc_inb(ahc, SXFRCTL0));
+	printf("SSTAT0 = 0x%x, SSTAT1 = 0x%x\n",
+	       ahc_inb(ahc, SSTAT0), ahc_inb(ahc, SSTAT1));
+	if ((ahc->features & AHC_DT) != 0)
+		printf("SCSIPHASE = 0x%x\n", ahc_inb(ahc, SCSIPHASE));
+	printf("STACK == 0x%x, 0x%x, 0x%x, 0x%x\n",
+		ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
+		ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
+		ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8),
+		ahc_inb(ahc, STACK) | (ahc_inb(ahc, STACK) << 8));
 	printf("SCB count = %d\n", ahc->scb_data->numscbs);
 	printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
 	printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
@@ -6112,7 +6220,8 @@
 #ifdef AHC_TARGET_MODE
 cam_status
 ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb,
-		    struct tmode_tstate **tstate, struct tmode_lstate **lstate,
+		    struct ahc_tmode_tstate **tstate,
+		    struct ahc_tmode_lstate **lstate,
 		    int notfound_failure)
 {
 
@@ -6153,8 +6262,8 @@
 void
 ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
 {
-	struct	   tmode_tstate *tstate;
-	struct	   tmode_lstate *lstate;
+	struct	   ahc_tmode_tstate *tstate;
+	struct	   ahc_tmode_lstate *lstate;
 	struct	   ccb_en_lun *cel;
 	cam_status status;
 	u_int	   target;
@@ -6227,7 +6336,7 @@
 		ahc->flags |= AHC_TARGETROLE;
 		if ((ahc->features & AHC_MULTIROLE) == 0)
 			ahc->flags &= ~AHC_INITIATORROLE;
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		ahc_loadseq(ahc);
 		ahc_unlock(ahc, &s);
 	}
@@ -6296,7 +6405,7 @@
 		SLIST_INIT(&lstate->accept_tios);
 		SLIST_INIT(&lstate->immed_notifies);
 		ahc_lock(ahc, &s);
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		if (target != CAM_TARGET_WILDCARD) {
 			tstate->enabled_luns[lun] = lstate;
 			ahc->enabled_luns++;
@@ -6360,7 +6469,7 @@
 			scsiseq |= ENSELI;
 			ahc_outb(ahc, SCSISEQ, scsiseq);
 		}
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 		ahc_unlock(ahc, &s);
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		xpt_print_path(ccb->ccb_h.path);
@@ -6410,7 +6519,7 @@
 		xpt_free_path(lstate->path);
 		free(lstate, M_DEVBUF);
 
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		/* Can we clean up the target too? */
 		if (target != CAM_TARGET_WILDCARD) {
 			tstate->enabled_luns[lun] = NULL;
@@ -6463,11 +6572,11 @@
 				printf("Configuring Initiator Mode\n");
 				ahc->flags &= ~AHC_TARGETROLE;
 				ahc->flags |= AHC_INITIATORROLE;
-				pause_sequencer(ahc);
+				ahc_pause(ahc);
 				ahc_loadseq(ahc);
 			}
 		}
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 		ahc_unlock(ahc, &s);
 	}
 }
@@ -6549,11 +6658,11 @@
 				ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
 			} else {
 				if (!paused)
-					pause_sequencer(ahc);	
+					ahc_pause(ahc);	
 				ahc_outb(ahc, KERNEL_TQINPOS,
 					 ahc->tqinfifonext & HOST_TQINPOS);
 				if (!paused)
-					unpause_sequencer(ahc);
+					ahc_unpause(ahc);
 			}
 		}
 	}
@@ -6562,8 +6671,8 @@
 static int
 ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
 {
-	struct	  tmode_tstate *tstate;
-	struct	  tmode_lstate *lstate;
+	struct	  ahc_tmode_tstate *tstate;
+	struct	  ahc_tmode_lstate *lstate;
 	struct	  ccb_accept_tio *atio;
 	uint8_t *byte;
 	int	  initiator;
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.h linux/drivers/scsi/aic7xxx/aic7xxx.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.h	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.h	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx.h#19 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.h#27 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.h,v 1.30 2000/11/10 20:13:40 gibbs Exp $
  */
@@ -209,9 +209,15 @@
 	AHC_MULTIROLE	= 0x40000,	/* Space for two roles at a time */
 	AHC_REMOVABLE	= 0x80000,	/* Hot-Swap supported */
 	AHC_AIC7770_FE	= AHC_FENONE,
-	AHC_AIC7850_FE	= AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE,
-	AHC_AIC7855_FE	= AHC_AIC7850_FE,
-	AHC_AIC7860_FE	= AHC_AIC7850_FE|AHC_ULTRA,
+	/*
+	 * The real 7850 does not support Ultra modes, but there are
+	 * several cards that use the generic 7850 PCI ID even though
+	 * they are using an Ultra capable chip (7859/7860).  We start
+	 * out with the AHC_ULTRA feature set and then check the DEVSTATUS
+	 * register to determine if the capability is really present.
+	 */
+	AHC_AIC7850_FE	= AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA,
+	AHC_AIC7860_FE	= AHC_AIC7850_FE,
 	AHC_AIC7870_FE	= AHC_TARGETMODE,
 	AHC_AIC7880_FE	= AHC_AIC7870_FE|AHC_ULTRA,
 	/*
@@ -286,56 +292,56 @@
  * chip/controller's configuration.
  */
 typedef enum {
-	AHC_FNONE		= 0x000,
-	AHC_PAGESCBS		= 0x001,/* Enable SCB paging */
-	AHC_CHANNEL_B_PRIMARY	= 0x002,/*
-					 * On twin channel adapters, probe
-					 * channel B first since it is the
-					 * primary bus.
+	AHC_FNONE	      = 0x000,
+	AHC_PRIMARY_CHANNEL   = 0x003,/*
+					 * The channel that should
+					 * be probed first.
 					 */
-	AHC_USEDEFAULTS		= 0x004,/*
+	AHC_USEDEFAULTS	      = 0x004,/*
 					 * For cards without an seeprom
 					 * or a BIOS to initialize the chip's
 					 * SRAM, we use the default target
 					 * settings.
 					 */
-	AHC_SEQUENCER_DEBUG	= 0x008,
-	AHC_SHARED_SRAM		= 0x010,
-	AHC_LARGE_SEEPROM	= 0x020,/* Uses C56_66 not C46 */
-	AHC_RESET_BUS_A		= 0x040,
-	AHC_RESET_BUS_B		= 0x080,
-	AHC_EXTENDED_TRANS_A	= 0x100,
-	AHC_EXTENDED_TRANS_B	= 0x200,
-	AHC_TERM_ENB_A		= 0x400,
-	AHC_TERM_ENB_B		= 0x800,
-	AHC_INITIATORROLE	= 0x1000,/*
+	AHC_SEQUENCER_DEBUG   = 0x008,
+	AHC_SHARED_SRAM	      = 0x010,
+	AHC_LARGE_SEEPROM     = 0x020,/* Uses C56_66 not C46 */
+	AHC_RESET_BUS_A	      = 0x040,
+	AHC_RESET_BUS_B	      = 0x080,
+	AHC_EXTENDED_TRANS_A  = 0x100,
+	AHC_EXTENDED_TRANS_B  = 0x200,
+	AHC_TERM_ENB_A	      = 0x400,
+	AHC_TERM_ENB_B	      = 0x800,
+	AHC_INITIATORROLE     = 0x1000,/*
 					  * Allow initiator operations on
 					  * this controller.
 					  */
-	AHC_TARGETROLE		= 0x2000,/*
+	AHC_TARGETROLE	      = 0x2000,/*
 					  * Allow target operations on this
 					  * controller.
 					  */
-	AHC_NEWEEPROM_FMT	= 0x4000,
-	AHC_RESOURCE_SHORTAGE	= 0x8000,
-	AHC_TQINFIFO_BLOCKED	= 0x10000,/* Blocked waiting for ATIOs */
-	AHC_INT50_SPEEDFLEX	= 0x20000,/*
+	AHC_NEWEEPROM_FMT     = 0x4000,
+	AHC_RESOURCE_SHORTAGE = 0x8000,
+	AHC_TQINFIFO_BLOCKED  = 0x10000,/* Blocked waiting for ATIOs */
+	AHC_INT50_SPEEDFLEX   = 0x20000,/*
 					   * Internal 50pin connector
 					   * sits behind an aic3860
 					   */
-	AHC_SCB_BTT		= 0x40000,/*
+	AHC_SCB_BTT	      = 0x40000,/*
 					   * The busy targets table is
 					   * stored in SCB space rather
 					   * than SRAM.
 					   */
-	AHC_BIOS_ENABLED	= 0x80000,
-	AHC_ALL_INTERRUPTS	= 0x100000,
-	AHC_ULTRA_DISABLED	= 0x200000/*
+	AHC_BIOS_ENABLED      = 0x80000,
+	AHC_ALL_INTERRUPTS    = 0x100000,
+	AHC_ULTRA_DISABLED    = 0x200000, /*
 					   * The precision resistor for
 					   * ultra transmission speeds is
 					   * missing, so we must limit
 					   * ourselves to fast SCSI.
 					   */
+	AHC_PAGESCBS	      = 0x400000, /* Enable SCB paging */
+	AHC_EDGE_INTERRUPT    = 0x800000  /* Device uses edge triggered ints */
 } ahc_flag;
 
 /*
@@ -515,8 +521,9 @@
 	SCB_DEVICE_RESET	= 0x0004,
 	SCB_SENSE		= 0x0008,
 	SCB_CDB32_PTR		= 0x0010,
-	SCB_RECOVERY_SCB	= 0x0040,
-	SCB_NEGOTIATE		= 0x0080,
+	SCB_RECOVERY_SCB	= 0x0020,
+	SCB_AUTO_NEGOTIATE	= 0x0040,/* Negotiate to achieve goal. */
+	SCB_NEGOTIATE		= 0x0080,/* Negotiation forced for command. */
 	SCB_ABORT		= 0x1000,
 	SCB_UNTAGGEDQ		= 0x2000,
 	SCB_ACTIVE		= 0x4000,
@@ -625,7 +632,7 @@
  * data structures.
  */
 #ifdef AHC_TARGET_MODE 
-struct tmode_lstate {
+struct ahc_tmode_lstate {
 	struct cam_path *path;
 	struct ccb_hdr_slist accept_tios;
 	struct ccb_hdr_slist immed_notifies;
@@ -634,7 +641,7 @@
 	uint8_t event_w_idx;
 };
 #else
-struct tmode_lstate;
+struct ahc_tmode_lstate;
 #endif
 
 /******************** Transfer Negotiation Datastructures *********************/
@@ -659,7 +666,7 @@
  * Per-initiator current, goal and user transfer negotiation information. */
 struct ahc_initiator_tinfo {
 	uint8_t scsirate;		/* Computed value for SCSIRATE reg */
-	struct ahc_transinfo current;
+	struct ahc_transinfo curr;
 	struct ahc_transinfo goal;
 	struct ahc_transinfo user;
 };
@@ -671,16 +678,17 @@
  * that we are the target and the targets are the initiators since the
  * negotiation is the same regardless of role.
  */
-struct tmode_tstate {
-	struct tmode_lstate*		enabled_luns[AHC_NUM_LUNS];
+struct ahc_tmode_tstate {
+	struct ahc_tmode_lstate*	enabled_luns[AHC_NUM_LUNS];
 	struct ahc_initiator_tinfo	transinfo[AHC_NUM_TARGETS];
 
 	/*
 	 * Per initiator state bitmasks.
 	 */
-	uint16_t		 ultraenb;	/* Using ultra sync rate  */
-	uint16_t	 	 discenable;	/* Disconnection allowed  */
-	uint16_t		 tagenable;	/* Tagged Queuing allowed */
+	uint16_t	 auto_negotiate;/* Auto Negotiation Required */
+	uint16_t	 ultraenb;	/* Using ultra sync rate  */
+	uint16_t	 discenable;	/* Disconnection allowed  */
+	uint16_t	 tagenable;	/* Tagged Queuing allowed */
 };
 
 /*
@@ -711,32 +719,14 @@
 
 /***************************** Lookup Tables **********************************/
 /*
- * Textual descriptions of the different chips indexed by chip type.
- */
-extern char *ahc_chip_names[];
-extern const u_int num_chip_names;
-
-/*
- * Hardware error codes.
- */
-struct hard_error_entry {
-        uint8_t errno;
-	char *errmesg;
-};
-extern struct hard_error_entry hard_error[];
-extern const u_int num_errors;
-
-/*
  * Phase -> name and message out response
  * to parity errors in each phase table. 
  */
-struct phase_table_entry {
+struct ahc_phase_table_entry {
         uint8_t phase;
         uint8_t mesg_out; /* Message response to parity errors */
 	char *phasemsg;
 };
-extern struct phase_table_entry phase_table[];
-extern const u_int num_phases;
 
 /************************** Serial EEPROM Format ******************************/
 
@@ -765,12 +755,19 @@
 #define		CFSUPREM	0x0001	/* support all removeable drives */
 #define		CFSUPREMB	0x0002	/* support removeable boot drives */
 #define		CFBIOSEN	0x0004	/* BIOS enabled */
-/*		UNUSED		0x0008	*/
+#define		CFBIOS_BUSSCAN	0x0008	/* Have the BIOS Scan the Bus */
 #define		CFSM2DRV	0x0010	/* support more than two drives */
-#define		CF284XEXTEND	0x0020	/* extended translation (284x cards) */	
 #define		CFSTPWLEVEL	0x0010	/* Termination level control */
+#define		CF284XEXTEND	0x0020	/* extended translation (284x cards) */	
+#define		CFCTRL_A	0x0020	/* BIOS displays Ctrl-A message */	
+#define		CFTERM_MENU	0x0040	/* BIOS displays termination menu */	
 #define		CFEXTEND	0x0080	/* extended translation enabled */
 #define		CFSCAMEN	0x0100	/* SCAM enable */
+#define		CFMSG_LEVEL	0x0600	/* BIOS Message Level */
+#define			CFMSG_VERBOSE	0x0000
+#define			CFMSG_SILENT	0x0200
+#define			CFMSG_DIAG	0x0400
+#define		CFBOOTCD	0x0800  /* Support Bootable CD-ROM */
 /*		UNUSED		0xff00	*/
 
 /*
@@ -785,10 +782,11 @@
 #define		CFWSTERM	0x0008	/* SCSI high byte termination */
 #define		CFSPARITY	0x0010	/* SCSI parity */
 #define		CF284XSTERM     0x0020	/* SCSI low byte term (284x cards) */	
-#define		CFMULTILUN	0x0020	/* SCSI low byte term (284x cards) */	
+#define		CFMULTILUN	0x0020
 #define		CFRESETB	0x0040	/* reset SCSI bus at boot */
 #define		CFCLUSTERENB	0x0080	/* Cluster Enable */
-#define		CFCHNLBPRIMARY	0x0100	/* aic7895 probe B channel first */
+#define		CFBOOTCHAN	0x0300	/* probe this channel first */
+#define		CFBOOTCHANSHIFT 8
 #define		CFSEAUTOTERM	0x0400	/* Ultra2 Perform secondary Auto Term*/
 #define		CFSELOWTERM	0x0800	/* Ultra2 secondary low term */
 #define		CFSEHIGHTERM	0x1000	/* Ultra2 secondary high term */
@@ -812,6 +810,7 @@
 	uint16_t res_1[10];		/* words 20-29 */
 	uint16_t signature;		/* Signature == 0x250 */
 #define		CFSIGNATURE	0x250
+#define		CFSIGNATURE2	0x300
 	uint16_t checksum;		/* word 31 */
 };
 
@@ -857,6 +856,8 @@
 	uint8_t	*btt;
 };
 
+typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
+
 struct ahc_softc {
 	bus_space_tag_t           tag;
 	bus_space_handle_t        bsh;
@@ -900,24 +901,29 @@
 	ahc_dev_softc_t		  dev_softc;
 
 	/*
+	 * Bus specific device information.
+	 */
+	ahc_bus_intr_t		  bus_intr;
+
+	/*
 	 * Target mode related state kept on a per enabled lun basis.
 	 * Targets that are not enabled will have null entries.
 	 * As an initiator, we keep one target entry for our initiator
 	 * ID to store our sync/wide transfer settings.
 	 */
-	struct tmode_tstate*	  enabled_targets[AHC_NUM_TARGETS];
+	struct ahc_tmode_tstate  *enabled_targets[AHC_NUM_TARGETS];
 
 	/*
 	 * The black hole device responsible for handling requests for
 	 * disabled luns on enabled targets.
 	 */
-	struct tmode_lstate*	  black_hole;
+	struct ahc_tmode_lstate  *black_hole;
 
 	/*
 	 * Device instance currently on the bus awaiting a continue TIO
 	 * for a command that was not given the disconnect priveledge.
 	 */
-	struct tmode_lstate*	  pending_device;
+	struct ahc_tmode_lstate  *pending_device;
 
 	/*
 	 * Card characteristics
@@ -952,9 +958,6 @@
 	uint8_t			  our_id;
 	uint8_t			  our_id_b;
 
-	/* Targets that need negotiation messages */
-	uint16_t		  targ_msg_req;
-
 	/*
 	 * PCI error detection.
 	 */
@@ -1102,6 +1105,7 @@
 					struct ahc_probe_config*);
 void			 ahc_controller_info(struct ahc_softc *ahc, char *buf);
 int			 ahc_init(struct ahc_softc *ahc);
+void			 ahc_intr_enable(struct ahc_softc *ahc, int enable);
 void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
 int			 ahc_suspend(struct ahc_softc *ahc); 
 int			 ahc_resume(struct ahc_softc *ahc);
@@ -1143,8 +1147,11 @@
 void			ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
 int			ahc_reset_channel(struct ahc_softc *ahc, char channel,
 					  int initiate_reset);
-void			restart_sequencer(struct ahc_softc *ahc);
+void			ahc_restart(struct ahc_softc *ahc);
+void			ahc_calc_residual(struct scb *scb);
 /*************************** Utility Functions ********************************/
+struct ahc_phase_table_entry*
+			ahc_lookup_phase_entry(int phase);
 void			ahc_compile_devinfo(struct ahc_devinfo *devinfo,
 					    u_int our_id, u_int target,
 					    u_int lun, char channel,
@@ -1163,10 +1170,11 @@
 					   struct ahc_initiator_tinfo *tinfo,
 					   u_int *bus_width,
 					   role_t role);
-void			ahc_update_target_msg_request(struct ahc_softc *ahc,
-					struct ahc_devinfo *dinfo,
-					struct ahc_initiator_tinfo *tinfo,
-					int force, int paused);
+int			ahc_update_neg_request(struct ahc_softc*,
+					       struct ahc_devinfo*,
+					       struct ahc_tmode_tstate*,
+					       struct ahc_initiator_tinfo*,
+					       int /*force*/);
 void			ahc_set_width(struct ahc_softc *ahc,
 				      struct ahc_devinfo *devinfo,
 				      u_int width, u_int type, int paused);
@@ -1176,22 +1184,27 @@
 					 u_int period, u_int offset,
 					 u_int ppr_options,
 					 u_int type, int paused);
+typedef enum {
+	AHC_QUEUE_NONE,
+	AHC_QUEUE_BASIC,
+	AHC_QUEUE_TAGGED
+} ahc_queue_alg;
+
 void			ahc_set_tags(struct ahc_softc *ahc,
-				     struct ahc_devinfo *devinfo, int enable);
+				     struct ahc_devinfo *devinfo,
+				     ahc_queue_alg alg);
 
 /**************************** Target Mode *************************************/
 #ifdef AHC_TARGET_MODE
 void		ahc_send_lstate_events(struct ahc_softc *,
-				       struct tmode_lstate *);
+				       struct ahc_tmode_lstate *);
 void		ahc_handle_en_lun(struct ahc_softc *ahc,
 				  struct cam_sim *sim, union ccb *ccb);
 cam_status	ahc_find_tmode_devs(struct ahc_softc *ahc,
 				    struct cam_sim *sim, union ccb *ccb,
-				    struct tmode_tstate **tstate,
-				    struct tmode_lstate **lstate,
+				    struct ahc_tmode_tstate **tstate,
+				    struct ahc_tmode_lstate **lstate,
 				    int notfound_failure);
-void		ahc_setup_target_msgin(struct ahc_softc *ahc,
-				       struct ahc_devinfo *devinfo);
 #ifndef AHC_TMODE_ENABLE
 #define AHC_TMODE_ENABLE 0
 #endif
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.reg linux/drivers/scsi/aic7xxx/aic7xxx.reg
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.reg	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.reg	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx.reg#13 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.reg#17 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.reg,v 1.31 2000/11/10 20:13:40 gibbs Exp $
  */
@@ -877,7 +877,8 @@
 	address			0x094
 	access_mode RO
 	bit	PRELOAD_AVAIL	0x80
-	bit	DWORDEMP	0x20
+	bit	DFCACHETH	0x40
+	bit	FIFOQWDEMP	0x20
 	bit	MREQPEND	0x10
 	bit	HDONE		0x08
 	bit	DFTHRESH	0x04
@@ -969,6 +970,7 @@
 	bit	MSG_OUT_PHASE	0x04
 	bit	DATA_IN_PHASE	0x02
 	bit	DATA_OUT_PHASE	0x01
+	mask	DATA_PHASE_MASK	0x03
 }
 
 /*
@@ -1415,15 +1417,6 @@
 	 */
 	LAST_MSG {
 		size		1
-	}
-
-	/*
-	 * Interrupt kernel for a message to this target on
-	 * the next transaction.  This is usually used for
-	 * negotiation requests.
-	 */
-	TARGET_MSG_REQUEST {
-		size		2
 	}
 
 	/*
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.seq linux/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx.seq	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx.seq#22 $
+ * $Id: //depot/src/aic7xxx/aic7xxx.seq#27 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx.seq,v 1.106 2000/11/12 05:19:46 gibbs Exp $
  */
@@ -153,7 +153,9 @@
 	 * the kernel driver if it happens.
 	 */
 	mvi	CLRSINT1,CLRBUSFREE;
-	or	SIMODE1, ENBUSFREE;
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SIMODE1, ENBUSFREE;
+	}
 
 	/*
 	 * Guard against a bus free after (re)selection
@@ -479,6 +481,9 @@
 		 */
 		mov	SEQ_FLAGS, SCB_TARGET_INFO[SCB_TARGET_PHASES];
 		
+		test	SCB_CONTROL, MK_MESSAGE	jz target_ITloop;
+		mvi	P_MESGIN|BSYO call change_phase;
+		jmp	host_target_message_loop;
 target_ITloop:
 		/*
 		 * Start honoring ATN signals now that
@@ -494,12 +499,12 @@
 		 * on the state of NO_DISCONNECT.
 		 */
 		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
-		if ((ahc->flags & AHC_PAGESCBS) != 0) {
-			mov	ALLZEROS	call	get_free_or_disc_scb;
-		}
 		mov	RETURN_1, ALLZEROS;
 		call	complete_target_cmd;
 		cmp	RETURN_1, CONT_MSG_LOOP jne .;
+		if ((ahc->flags & AHC_PAGESCBS) != 0) {
+			mov	ALLZEROS	call	get_free_or_disc_scb;
+		}
 		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
 		mov	SCB_TAG	 call dma_scb;
 		jmp	target_synccmd;
@@ -703,6 +708,11 @@
 	test	CCSGCTL, CCSGEN jnz .;
 	ret;
 idle_loop:
+	/*
+	 * Do we need any more segments for this transfer?
+	 */
+	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
+
 	/* Did we just finish fetching segs? */
 	cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
 
@@ -710,11 +720,6 @@
 	test	CCSGCTL, CCSGEN jnz return;
 
 	/*
-	 * Do we need any more segments?
-	 */
-	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
-
-	/*
 	 * Do we have any prefetch left???
 	 */
 	cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
@@ -758,8 +763,8 @@
 		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
 		or	SINDEX, LAST_SEG;
 		mov	SG_CACHE_PRE, SINDEX;
-		/* Load the segment by writing DFCNTRL again */
-		mov	DFCNTRL, DMAPARAMS;
+		/* Load the segment */
+		or	DFCNTRL, PRELOADEN;
 	}
 	ret;
 }
@@ -882,7 +887,11 @@
 	and	DMAPARAMS, DIRECTION;
 	mov	DFCNTRL, DMAPARAMS;
 	or	SXFRCTL1,BITBUCKET;
-	test	SSTAT1,PHASEMIS	jz .;
+	if ((ahc->features & AHC_DT) == 0) {
+		test	SSTAT1,PHASEMIS	jz .;
+	} else {
+		test	SCSIPHASE, DATA_PHASE_MASK jnz .;
+	}
 	and	SXFRCTL1, ~BITBUCKET;
 	mvi	DATA_OVERRUN call set_seqint;
 	jmp	ITloop;
@@ -903,54 +912,48 @@
 		 * completes or the target changes phase.
 		 */
 		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
-		if ((ahc->flags & AHC_TARGETROLE) != 0) {
-			 /*
-			  * As a target, we control the phases,
-			  * so ignore PHASEMIS.
-			  */
-			test	SSTAT0, TARGET jnz ultra2_dma_loop;
-		}
-		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
-			test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
+		if ((ahc->features & AHC_DT) == 0) {
+			if ((ahc->flags & AHC_TARGETROLE) != 0) {
+				 /*
+				  * As a target, we control the phases,
+				  * so ignore PHASEMIS.
+				  */
+				test	SSTAT0, TARGET jnz ultra2_dma_loop;
+			}
+			if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+				test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
+			}
+		} else {
+			test	DFCNTRL, SCSIEN jnz ultra2_dma_loop;
 		}
 
 ultra2_dmafinish:
-		test	DFCNTRL, DIRECTION jnz ultra2_dmafifoempty;
-		if ((ahc->features & AHC_DT) == 0) {
-			and	DFCNTRL, ~SCSIEN;
-			test	DFCNTRL, SCSIEN jnz .;
-		}
-ultra2_dmafifoflush:
+		/*
+		 * The transfer has terminated either due to a phase
+		 * change, and/or the completion of the last segment.
+		 * We have two goals here.  Do as much other work
+		 * as possible while the data fifo drains on a read
+		 * and respond as quickly as possible to the standard
+		 * messages (save data pointers/disconnect and command
+		 * complete) that usually follow a data phase.
+		 */
 		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
 			/*
-			 * On Rev A of the aic7890, the autoflush
-			 * features doesn't function correctly.
-			 * Perform an explicit manual flush.  During
-			 * a manual flush, the FIFOEMP bit becomes
-			 * true every time the PCI FIFO empties
-			 * regardless of the state of the SCSI FIFO.
-			 * It can take up to 4 clock cycles for the
-			 * SCSI FIFO to get data into the PCI FIFO
-			 * and for FIFOEMP to de-assert.  Here we
-			 * guard against this condition by making
-			 * sure the FIFOEMP bit stays on for 5 full
-			 * clock cycles.
+			 * On chips with broken auto-flush, start
+			 * the flushing process now.  We'll poke
+			 * the chip from time to time to keep the
+			 * flush process going as we complete the
+			 * data phase.
 			 */
 			or	DFCNTRL, FIFOFLUSH;
-			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
 		}
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-ultra2_dmafifoempty:
-		/* Don't clobber an inprogress host data transfer */
-		test	DFSTATUS, MREQPEND	jnz ultra2_dmafifoempty;
-ultra2_dmahalt:
-		and     DFCNTRL, ~(SCSIEN|HDMAEN);
-		test	DFCNTRL, HDMAEN jnz .;
-
 		/*
+		 * We assume that, even though data may still be
+		 * transferring to the host, that the SCSI side of
+		 * the DMA engine is now in a static state.  This
+		 * allows us to update our notion of where we are
+		 * in this transfer.
+		 *
 		 * If, by chance, we stopped before being able
 		 * to fetch additional segments for this transfer,
 		 * yet the last S/G was completely exhausted,
@@ -961,14 +964,14 @@
 		 * If we happened to stop on the last segment, then
 		 * our residual information is still correct from
 		 * the idle loop and there is no need to perform
-		 * any fixups.  Just jump to data_phase_finish.
+		 * any fixups.
 		 */
 ultra2_ensure_sg:
 		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
 		/* Record if we've consumed all S/G entries */
-		test	SG_CACHE_SHADOW, LAST_SEG_DONE jz data_phase_finish;
+		test    SSTAT2, SHVALID	jnz residuals_correct;
 		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
-		jmp	data_phase_finish;
+		jmp	residuals_correct;
 
 ultra2_shvalid:
                 test    SSTAT2, SHVALID	jnz sgptr_fixup;
@@ -998,6 +1001,62 @@
 		test	SG_CACHE_SHADOW, ODD_SEG jz . + 2;
 		or	DATA_COUNT_ODD, 0x1;
 		clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
+residuals_correct:
+		/*
+		 * Go ahead and shut down the DMA engine now.
+		 * In the future, we'll want to handle end of
+		 * transfer messages prior to doing this, but this
+		 * requires similar restructuring for pre-ULTRA2
+		 * controllers.
+		 */
+		test	DMAPARAMS, DIRECTION jnz ultra2_fifoempty;
+ultra2_fifoflush:
+		if ((ahc->features & AHC_DT) == 0) {
+			if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
+				/*
+				 * On Rev A of the aic7890, the autoflush
+				 * feature doesn't function correctly.
+				 * Perform an explicit manual flush.  During
+				 * a manual flush, the FIFOEMP bit becomes
+				 * true every time the PCI FIFO empties
+				 * regardless of the state of the SCSI FIFO.
+				 * It can take up to 4 clock cycles for the
+				 * SCSI FIFO to get data into the PCI FIFO
+				 * and for FIFOEMP to de-assert.  Here we
+				 * guard against this condition by making
+				 * sure the FIFOEMP bit stays on for 5 full
+				 * clock cycles.
+				 */
+				or	DFCNTRL, FIFOFLUSH;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+			}
+			test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+		} else {
+			/*
+			 * We enable the auto-ack feature on DT capable
+			 * controllers.  This means that the controller may
+			 * have already transferred some overrun bytes into
+			 * the data FIFO and acked them on the bus.  The only
+			 * way to detect this situation is to wait for
+			 * LAST_SEG_DONE to come true on a completed transfer
+			 * and then test to see if the data FIFO is non-empty.
+			 */
+			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4;
+			test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+			/* Overrun */
+			jmp	data_phase_loop;
+			test	DFSTATUS, FIFOEMP jz .;
+		}
+ultra2_fifoempty:
+		/* Don't clobber an inprogress host data transfer */
+		test	DFSTATUS, MREQPEND	jnz ultra2_fifoempty;
+ultra2_dmahalt:
+		and     DFCNTRL, ~(SCSIEN|HDMAEN);
+		test	DFCNTRL, SCSIEN|HDMAEN jnz .;
 	} else {
 		/* If we are the last SG block, tell the hardware. */
 		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
@@ -1156,7 +1215,11 @@
 	}
 	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
 		test	SSTAT1, REQINIT jz .;
-		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+		if ((ahc->features & AHC_DT) == 0) {
+			test	SSTAT1,PHASEMIS	jz data_phase_loop;
+		} else {
+			test	SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop;
+		}
 	}
 
 data_phase_done:
@@ -1296,13 +1359,17 @@
 		or	DFCNTRL, FIFOFLUSH;
 	}
 p_command_loop:
-	test	SSTAT0, SDONE jnz . + 2;
-	test    SSTAT1, PHASEMIS jz p_command_loop;
-	/*
-	 * Wait for our ACK to go-away on it's own
-	 * instead of being killed by SCSIEN getting cleared.
-	 */
-	test	SCSISIGI, ACKI jnz .;
+	if ((ahc->features & AHC_DT) == 0) {
+		test	SSTAT0, SDONE jnz . + 2;
+		test    SSTAT1, PHASEMIS jz p_command_loop;
+		/*
+		 * Wait for our ACK to go-away on it's own
+		 * instead of being killed by SCSIEN getting cleared.
+		 */
+		test	SCSISIGI, ACKI jnz .;
+	} else {
+		test	DFCNTRL, SCSIEN jnz p_command_loop;
+	}
 	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
 	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
 	if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -1346,23 +1413,16 @@
  * reason.
  */
 p_mesgout_retry:
-	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+	/* Turn on ATN for the retry */
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SCSISIGO, ATNO, LASTPHASE;
+	} else {
+		mvi	SCSISIGO, ATNO;
+	}
 p_mesgout:
 	mov	SINDEX, MSG_OUT;
 	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
 	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
-	mov	FUNCTION1, SCB_SCSIID;
-	mov	A, FUNCTION1;
-	mov	SINDEX, TARGET_MSG_REQUEST[0];
-	if ((ahc->features & AHC_TWIN) != 0) {
-		/* Second Channel uses high byte bits */
-		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
-		mov	SINDEX, TARGET_MSG_REQUEST[1];
-	} else if ((ahc->features & AHC_WIDE) != 0) {
-		test	SCB_SCSIID, 0x80	jz . + 2; /* target > 7 */
-		mov	SINDEX, TARGET_MSG_REQUEST[1];
-	}
-	test	SINDEX, A	jnz host_message_loop;
 p_mesgout_identify:
 	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
 	test	SCB_CONTROL, DISCENB jnz . + 2;
@@ -1555,10 +1615,17 @@
  * only if we've actually been into a data phase to change them.  This
  * protects against bogus data in scratch ram and the residual counts
  * since they are only initialized when we go into data_in or data_out.
+ * Ack the message as soon as possible.  For chips without S/G pipelining,
+ * we can only ack the message after SHADDR has been saved.  On these
+ * chips, SHADDR increments with every bus transaction, even PIO.
  */
 mesgin_sdptrs:
-	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
-
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+		test	SEQ_FLAGS, DPHASE	jz ITloop;
+	} else {
+		test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+	}
 	/*
 	 * The SCB_SGPTR becomes the next one we'll download,
 	 * and the SCB_DATAPTR becomes the current SHADDR.
@@ -1567,13 +1634,17 @@
 	 */
 	if ((ahc->features & AHC_CMD_CHAN) != 0) {
 		bmov	SCB_DATAPTR, SHADDR, 4;
+		if ((ahc->features & AHC_ULTRA2) == 0) {
+			mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
+		}
 		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
 	} else {
 		mvi	DINDEX, SCB_DATAPTR;
 		mvi	SHADDR call bcopy_4;
+		mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
 		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
 	}
-	jmp	mesgin_done;
+	jmp	ITloop;
 
 /*
  * Restore pointers message?  Data pointers are recopied from the
@@ -1751,7 +1822,11 @@
 	jmp	mesgin_done;
 
 mk_mesg:
-	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SCSISIGO, ATNO, LASTPHASE;
+	} else {
+		mvi	SCSISIGO, ATNO;
+	}
 	mov	MSG_OUT,SINDEX ret;
 
 /*
@@ -1924,7 +1999,9 @@
 	test	SSTAT1, REQINIT jz phase_lock;
 	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
 phase_lock_latch_phase:
-	and	SCSISIGO, PHASE_MASK, SCSISIGI;
+	if ((ahc->features & AHC_DT) == 0) {
+		and	SCSISIGO, PHASE_MASK, SCSISIGI;
+	}
 	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
 
 if ((ahc->features & AHC_CMD_CHAN) == 0) {
@@ -2068,9 +2145,9 @@
 			 * latch is full.
 			 */
 			clr	A;
-			/* Wait for some data to arrive. */
+			/* Wait for at least 8 bytes of data to arrive. */
 dma_scb_hang_fifo:
-			test	DFSTATUS, FIFOEMP jnz dma_scb_hang_fifo;
+			test	DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo;
 dma_scb_hang_wait:
 			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
 			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
@@ -2078,8 +2155,7 @@
 			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
 			/*
 			 * The PCI module no longer intends to perform
-			 * a PCI transaction and HDONE has not come true.
-			 * We are hung.  Drain the fifo.
+			 * a PCI transaction.  Drain the fifo.
 			 */
 dma_scb_hang_empty_fifo:
 			/*
@@ -2101,6 +2177,7 @@
 			 */
 			not	SINDEX;
 			add	A, 5, SINDEX;
+			cmp	A, 4	je dma_finish_nowait;
 			jmp	dma_scb_hang_fifo;
 dma_scb_hang_dma_done:
 			and	DFCNTRL, ~HDMAEN;
@@ -2146,6 +2223,7 @@
  */
 dma_finish:
 	test	DFSTATUS,HDONE	jz dma_finish;
+dma_finish_nowait:
 	/* Turn off DMA */
 	and	DFCNTRL, ~HDMAEN;
 	test	DFCNTRL, HDMAEN jnz .;
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_inline.h linux/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_inline.h	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_inline.h	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#15 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_inline.h#21 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.8 2000/11/12 05:19:46 gibbs Exp $
  */
@@ -37,10 +37,10 @@
 #define _AIC7XXX_INLINE_H_
 
 /************************* Sequencer Execution Control ************************/
-static __inline int  sequencer_paused(struct ahc_softc *ahc);
+static __inline int  ahc_is_paused(struct ahc_softc *ahc);
 static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
-static __inline void pause_sequencer(struct ahc_softc *ahc);
-static __inline void unpause_sequencer(struct ahc_softc *ahc);
+static __inline void ahc_pause(struct ahc_softc *ahc);
+static __inline void ahc_unpause(struct ahc_softc *ahc);
 
 /*
  * Work around any chip bugs related to halting sequencer execution.
@@ -62,7 +62,7 @@
  * Returns non-zero status if the sequencer is stopped.
  */
 static __inline int
-sequencer_paused(struct ahc_softc *ahc)
+ahc_is_paused(struct ahc_softc *ahc)
 {
 	return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
 }
@@ -75,7 +75,7 @@
  * for critical sections.
  */
 static __inline void
-pause_sequencer(struct ahc_softc *ahc)
+ahc_pause(struct ahc_softc *ahc)
 {
 	ahc_outb(ahc, HCNTRL, ahc->pause);
 
@@ -83,7 +83,7 @@
 	 * Since the sequencer can disable pausing in a critical section, we
 	 * must loop until it actually stops.
 	 */
-	while (sequencer_paused(ahc) == 0)
+	while (ahc_is_paused(ahc) == 0)
 		;
 
 	ahc_pause_bug_fix(ahc);
@@ -100,7 +100,7 @@
  * condition.
  */
 static __inline void
-unpause_sequencer(struct ahc_softc *ahc)
+ahc_unpause(struct ahc_softc *ahc)
 {
 	if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
 		ahc_outb(ahc, HCNTRL, ahc->unpause);
@@ -188,12 +188,12 @@
 
 /*********************** Miscelaneous Support Functions ***********************/
 
-static __inline int	ahc_check_residual(struct scb *scb);
+static __inline void	ahc_update_residual(struct scb *scb);
 static __inline struct ahc_initiator_tinfo *
 			ahc_fetch_transinfo(struct ahc_softc *ahc,
 					    char channel, u_int our_id,
 					    u_int remote_id,
-					    struct tmode_tstate **tstate);
+					    struct ahc_tmode_tstate **tstate);
 static __inline struct scb*
 			ahc_get_scb(struct ahc_softc *ahc);
 static __inline void	ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
@@ -211,15 +211,16 @@
  * Determine whether the sequencer reported a residual
  * for this SCB/transaction.
  */
-static __inline int
-ahc_check_residual(struct scb *scb)
+static __inline void
+ahc_update_residual(struct scb *scb)
 {
-	struct status_pkt *sp;
+	uint32_t sgptr;
 
-	sp = &scb->hscb->shared_data.status;
-	if ((scb->hscb->sgptr & SG_RESID_VALID) != 0)
-		return (1);
-	return (0);
+	sgptr = ahc_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_RESID_VALID) != 0)
+		ahc_calc_residual(scb);
+	else
+		ahc_set_residual(scb, 0);
 }
 
 /*
@@ -228,7 +229,7 @@
  */
 static __inline struct ahc_initiator_tinfo *
 ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
-		    u_int remote_id, struct tmode_tstate **tstate)
+		    u_int remote_id, struct ahc_tmode_tstate **tstate)
 {
 	/*
 	 * Transfer data structures are stored from the perspective
@@ -345,10 +346,10 @@
 		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
 	} else {
 		if ((ahc->features & AHC_AUTOPAUSE) == 0)
-			pause_sequencer(ahc);
+			ahc_pause(ahc);
 		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
 		if ((ahc->features & AHC_AUTOPAUSE) == 0)
-			unpause_sequencer(ahc);
+			ahc_unpause(ahc);
 	}
 }
 
@@ -412,19 +413,28 @@
 	 * completion queues.  This avoids a costly PCI bus read in
 	 * most cases.
 	 */
-	intstat = 0;
-	if ((queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
+	if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
+	 && (queuestat = ahc_check_cmdcmpltqueues(ahc)) != 0)
 		intstat = CMDCMPLT;
-
-	if ((intstat & INT_PEND) == 0
-	 || (ahc->flags & AHC_ALL_INTERRUPTS) != 0) {
-
+	else {
 		intstat = ahc_inb(ahc, INTSTAT);
+		/*
+		 * We can't generate queuestat once above
+		 * or we are exposed to a race when our
+		 * interrupt is shared with another device.
+		 * if instat showed a command complete interrupt,
+		 * but our first generation of queue stat
+		 * "just missed" the delivery of this transaction,
+		 * we would clear the command complete interrupt
+		 * below without ever servicing the completed
+		 * command.
+		 */
+		queuestat = ahc_check_cmdcmpltqueues(ahc);
 #if AHC_PCI_CONFIG > 0
 		if (ahc->unsolicited_ints > 500
 		 && (ahc->chip & AHC_PCI) != 0
 		 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
-			ahc_pci_intr(ahc);
+			ahc->bus_intr(ahc);
 #endif
 	}
 
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Mon Dec  3 22:41:47 2001
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#54 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c#66 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -112,7 +112,6 @@
  *  8: SMP friendliness has been improved
  *
  */
-#include <linux/config.h>
 
 /*
  * The next three defines are user configurable.  These should be the only
@@ -158,8 +157,8 @@
  * The scsi error recovery code performs its own bus settle
  * delay handling for error recovery actions.
  */
-#ifdef CONFIG_AIC7XXX_RESET_DELAY
-#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS
 #else
 #define AIC7XXX_RESET_DELAY 5000
 #endif
@@ -479,45 +478,48 @@
 
 #endif
 
-static void ahc_handle_scsi_status(struct ahc_softc *,
-				   struct ahc_linux_device *, struct scb *);
-static void ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
-static void ahc_sem_timeout(u_long arg);
-static void ahc_release_sim_queue(u_long arg);
-static int aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
-static void aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc);
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
-				       Scsi_Device *scsi_devs);
-static void aic7xxx_device_queue_depth(struct ahc_softc *ahc,
-				       Scsi_Device *device);
-static struct ahc_linux_target*	ahc_alloc_target(struct ahc_softc *,
-						 u_int, u_int);
-static void			ahc_free_target(struct ahc_softc *ahc,
-						struct ahc_linux_target *targ);
-static struct ahc_linux_device*	ahc_alloc_device(struct ahc_softc *,
-						 struct ahc_linux_target *,
-						 u_int);
-static void			ahc_free_device(struct ahc_softc *ahc,
-						struct ahc_linux_device *dev);
-static void ahc_run_device_queue(struct ahc_softc *ahc,
-				 struct ahc_linux_device *dev);
-static void ahc_setup_tag_info(char *p, char *end);
-static int ahc_next_unit(void);
+static void ahc_linux_handle_scsi_status(struct ahc_softc *,
+					 struct ahc_linux_device *,
+					 struct scb *);
+static void ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
+static void ahc_linux_sem_timeout(u_long arg);
+static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc);
+static void ahc_linux_release_sim_queue(u_long arg);
+static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
+static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
+static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
+					 Scsi_Device *scsi_devs);
+static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
+					 Scsi_Device *device);
+static struct ahc_linux_target*	ahc_linux_alloc_target(struct ahc_softc*,
+						       u_int, u_int);
+static void			ahc_linux_free_target(struct ahc_softc*,
+						      struct ahc_linux_target*);
+static struct ahc_linux_device*	ahc_linux_alloc_device(struct ahc_softc*,
+						       struct ahc_linux_target*,
+						       u_int);
+static void			ahc_linux_free_device(struct ahc_softc*,
+						      struct ahc_linux_device*);
+static void ahc_linux_run_device_queue(struct ahc_softc*,
+				       struct ahc_linux_device*);
+static void ahc_linux_setup_tag_info(char *p, char *end);
+static int ahc_linux_next_unit(void);
+static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf);
 
 static __inline struct ahc_linux_device*
-		     ahc_get_device(struct ahc_softc *ahc, u_int channel,
-				    u_int target, u_int lun, int /*alloc*/);
-static __inline void ahc_queue_cmd_complete(struct ahc_softc *ahc,
-					    Scsi_Cmnd *cmd);
-static __inline void ahc_run_complete_queue(struct ahc_softc *ahc,
-					    struct ahc_cmd *acmd);
-static __inline void ahc_check_device_queue(struct ahc_softc *ahc,
-					  struct ahc_linux_device *dev);
-static __inline void ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd);
-static __inline void ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb);
+		     ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
+					  u_int target, u_int lun, int alloc);
+static __inline void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
+						  Scsi_Cmnd *cmd);
+static __inline void ahc_linux_run_complete_queue(struct ahc_softc *ahc,
+						  struct ahc_cmd *acmd);
+static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc,
+						  struct ahc_linux_device *dev);
+static __inline void ahc_linux_sniff_command(struct ahc_softc*, Scsi_Cmnd*);
+static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
 
 static __inline struct ahc_linux_device*
-ahc_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
+ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
 	       u_int lun, int alloc)
 {
 	struct ahc_linux_target *targ;
@@ -530,7 +532,7 @@
 	targ = ahc->platform_data->targets[target_offset];
 	if (targ == NULL) {
 		if (alloc != 0) {
-			targ = ahc_alloc_target(ahc, channel, target);
+			targ = ahc_linux_alloc_target(ahc, channel, target);
 			if (targ == NULL)
 				return (NULL);
 		} else
@@ -538,17 +540,17 @@
 	}
 	dev = targ->devices[lun];
 	if (dev == NULL && alloc != 0)
-		dev = ahc_alloc_device(ahc, targ, lun);
+		dev = ahc_linux_alloc_device(ahc, targ, lun);
 	return (dev);
 }
 
 static __inline void
-ahc_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	/*
 	 * Typically, the complete queue has very few entries
 	 * queued to it before the queue is emptied by
-	 * ahc_run_complete_queue, so sorting the entries
+	 * ahc_linux_run_complete_queue, so sorting the entries
 	 * by generation number should be inexpensive.
 	 * We perform the sort so that commands that complete
 	 * with an error are retuned in the order origionally
@@ -584,7 +586,7 @@
 }
 
 static __inline void
-ahc_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
+ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
 {	
 	u_long done_flags;
 
@@ -601,7 +603,8 @@
 }
 
 static __inline void
-ahc_check_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_check_device_queue(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev)
 {
 	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0
 	 && dev->active == 0) {
@@ -613,11 +616,11 @@
 	 || dev->openings == 0 || dev->qfrozen != 0)
 		return;
 
-	ahc_run_device_queue(ahc, dev);
+	ahc_linux_run_device_queue(ahc, dev);
 }
 
 static __inline void
-ahc_run_device_queues(struct ahc_softc *ahc)
+ahc_linux_run_device_queues(struct ahc_softc *ahc)
 {
 	struct ahc_linux_device *dev;
 
@@ -626,25 +629,25 @@
 	    && (dev = LIST_FIRST(&ahc->platform_data->device_runq)) != NULL) {
 		LIST_REMOVE(dev, links);
 		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
-		ahc_check_device_queue(ahc, dev);
+		ahc_linux_check_device_queue(ahc, dev);
 	}
 }
 
 static __inline void
-ahc_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_sniff_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	/*
 	 * Determine whether we care to filter
 	 * information out of this command.  If so,
-	 * pass it on to ahc_filter_command() for more
+	 * pass it on to ahc_linux_filter_command() for more
 	 * heavy weight processing.
 	 */
 	if (cmd->cmnd[0] == INQUIRY)
-		ahc_filter_command(ahc, cmd);
+		ahc_linux_filter_command(ahc, cmd);
 }
 
 static __inline void
-ahc_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
+ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
 {
 	Scsi_Cmnd *cmd;
 
@@ -662,6 +665,24 @@
 				 scsi_to_pci_dma_dir(cmd->sc_data_direction));
 }
 
+/************************ Shutdown/halt/reboot hook ***************************/
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+
+static struct notifier_block ahc_linux_notifier = {
+	ahc_linux_halt, NULL, 0
+};
+
+static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf)
+{
+	struct ahc_softc *ahc;
+
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		ahc_shutdown(ahc);
+	}
+	return (NOTIFY_OK);
+}
+
 /******************************** Macros **************************************/
 #define BUILD_SCSIID(ahc, cmd)						\
 	((((cmd)->target << TID_SHIFT) & TID)				\
@@ -820,6 +841,9 @@
 	/* Still equal.  Sort by BIOS address, ioport, or bus/slot/func. */
 	switch (rvalue) {
 	case AHC_PCI:
+	{
+		char primary_channel;
+
 		value = ahc_get_pci_bus(lahc->dev_softc)
 		      - ahc_get_pci_bus(rahc->dev_softc);
 		if (value != 0)
@@ -828,19 +852,18 @@
 		      - ahc_get_pci_slot(rahc->dev_softc);
 		if (value != 0)
 			break;
-		value = ahc_get_pci_function(lahc->dev_softc)
-		      - ahc_get_pci_function(rahc->dev_softc);
 		/*
 		 * On multi-function devices, the user can choose
 		 * to have function 1 probed before function 0.
-		 * Function 0 is the only one that will have
-		 * CHANNEL_B_PRIMARY set.
+		 * Give whichever channel is the primary channel
+		 * the lowest priority.
 		 */
-		if (value < 0
-		 && (lahc->flags & AHC_CHANNEL_B_PRIMARY) != 0)
-			/* Swap the two */
-			value = -value;
+		primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A';
+		value = 1;
+		if (lahc->channel == primary_channel)
+			value = -1;
 		break;
+	}
 	case AHC_EISA:
 		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {
 			value = lahc->platform_data->bios_address
@@ -857,7 +880,7 @@
 }
 
 static void
-ahc_setup_tag_info(char *p, char *end)
+ahc_linux_setup_tag_info(char *p, char *end)
 {
 	char	*base;
 	char	*tok;
@@ -865,7 +888,7 @@
 	char	*tok_end2;
 	int      i;
 	int      instance;
-	int	 device;
+	int	 targ;
 	int	 done;
 	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
 
@@ -873,7 +896,7 @@
 		return;
 
 	instance = -1;
-	device = -1;
+	targ = -1;
 	done = FALSE;
 	base = p;
 	/* Forward us just past the ':' */
@@ -886,13 +909,13 @@
 		case '{':
 			if (instance == -1)
 				instance = 0;
-			else if (device == -1)
-				device = 0;
+			else if (targ == -1)
+				targ = 0;
 			tok++;
 			break;
 		case '}':
-			if (device != -1)
-				device = -1;
+			if (targ != -1)
+				targ = -1;
 			else if (instance != -1)
 				instance = -1;
 			tok++;
@@ -901,11 +924,11 @@
 		case '.':
 			if (instance == -1)
 				done = TRUE;
-			else if (device >= 0)
-				device++;
+			else if (targ >= 0)
+				targ++;
 			else if (instance >= 0)
 				instance++;
-			if ((device >= AHC_NUM_TARGETS) ||
+			if ((targ >= AHC_NUM_TARGETS) ||
 			    (instance >= NUM_ELEMENTS(aic7xxx_tag_info)))
 				done = TRUE;
 			tok++;
@@ -926,11 +949,12 @@
 					done = FALSE;
 				}
 			}
-			if ((instance >= 0) && (device >= 0) &&
-			    (instance < NUM_ELEMENTS(aic7xxx_tag_info)) &&
-			    (device < AHC_NUM_TARGETS))
-				aic7xxx_tag_info[instance].tag_commands[device] =
+			if ((instance >= 0) && (targ >= 0)
+			 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))
+			 && (targ < AHC_NUM_TARGETS)) {
+				aic7xxx_tag_info[instance].tag_commands[targ] =
 				    simple_strtoul(tok, NULL, 0) & 0xff;
+			}
 			tok = tok_end;
 			break;
 		}
@@ -980,7 +1004,7 @@
 				continue;
 
 			if (strncmp(p, "tag_info", n) == 0) {
-				ahc_setup_tag_info(p + n, end);
+				ahc_linux_setup_tag_info(p + n, end);
 			} else if (p[n] == ':') {
 				*(options[i].flag) =
 				    simple_strtoul(p + n + 1, NULL, 0);
@@ -989,8 +1013,10 @@
 			} else {
 				*(options[i].flag) = ~(*(options[i].flag));
 			}
+			break;
 		}
 	}
+	register_reboot_notifier(&ahc_linux_notifier);
 	return 1;
 }
 
@@ -1004,7 +1030,7 @@
  * Try to detect an Adaptec 7XXX controller.
  */
 int
-aic7xxx_detect(Scsi_Host_Template *template)
+ahc_linux_detect(Scsi_Host_Template *template)
 {
 	struct	ahc_softc *ahc;
 	int     found;
@@ -1016,8 +1042,8 @@
 	 */
 	if (offsetof(struct ahc_cmd_internal, end)
 	  > offsetof(struct scsi_cmnd, host_scribble)) {
-		printf("aic7xxx_detect: SCSI data structures changed.\n");
-		printf("aic7xxx_detect: Unable to attach\n");
+		printf("ahc_linux_detect: SCSI data structures changed.\n");
+		printf("ahc_linux_detect: Unable to attach\n");
 		return (0);
 	}
 #ifdef MODULE
@@ -1054,7 +1080,7 @@
 	found = 0;
 	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
 
-		if (aic7xxx_register_host(ahc, template) == 0)
+		if (ahc_linux_register_host(ahc, template) == 0)
 			found++;
 	}
 	aic7xxx_detect_complete++;
@@ -1062,7 +1088,7 @@
 }
 
 int
-aic7xxx_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
+ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
 {
 	char  buf[80];
 	struct Scsi_Host *host;
@@ -1081,12 +1107,13 @@
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
 	host->sg_tablesize = AHC_NSEG;
-	host->select_queue_depths = aic7xxx_select_queue_depth;
+	host->select_queue_depths = ahc_linux_select_queue_depth;
+	/* XXX No way to communicate the ID for multiple channels */
 	host->this_id = ahc->our_id;
 	host->irq = ahc->platform_data->irq;
 	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
 	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
-	ahc_set_unit(ahc, ahc_next_unit());
+	ahc_set_unit(ahc, ahc_linux_next_unit());
 	sprintf(buf, "scsi%d", host->host_no);
 	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
 	if (new_name != NULL) {
@@ -1094,8 +1121,10 @@
 		ahc_set_name(ahc, new_name);
 	}
 	host->unique_id = ahc->unit;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,4)
 	scsi_set_pci_device(host, ahc->dev_softc);
-	aic7xxx_initialize_scsi_bus(ahc);
+#endif
+	ahc_linux_initialize_scsi_bus(ahc);
 	ahc_unlock(ahc, &s);
 	return (0);
 }
@@ -1107,7 +1136,7 @@
  * scenario.
  */
 static int
-ahc_next_unit()
+ahc_linux_next_unit()
 {
 	struct ahc_softc *ahc;
 	int unit;
@@ -1129,7 +1158,7 @@
  * target.
  */
 void
-aic7xxx_initialize_scsi_bus(struct ahc_softc *ahc)
+ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc)
 {
 	int i;
 	int numtarg;
@@ -1159,7 +1188,7 @@
 	for (; i < numtarg; i++) {
 		struct ahc_devinfo devinfo;
 		struct ahc_initiator_tinfo *tinfo;
-		struct tmode_tstate *tstate;
+		struct ahc_tmode_tstate *tstate;
 		u_int our_id;
 		u_int target_id;
 		char channel;
@@ -1175,20 +1204,27 @@
 		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
 					    target_id, &tstate);
 		tinfo->goal = tinfo->user;
+		/*
+		 * Don't try negotiations that require PPR messages
+		 * until we successfully retrieve Inquiry data.
+		 */
+		tinfo->goal.ppr_options = 0;
+		if (tinfo->goal.transport_version > SCSI_REV_2)
+			tinfo->goal.transport_version = SCSI_REV_2;
 		ahc_compile_devinfo(&devinfo, our_id, target_id,
 				   CAM_LUN_WILDCARD, channel, ROLE_INITIATOR);
-		ahc_update_target_msg_request(ahc, &devinfo, tinfo,
-					     /*force*/FALSE, /*paused*/FALSE);
+		ahc_update_neg_request(ahc, &devinfo, tstate,
+				       tinfo, /*force*/FALSE);
 	}
 	/* Give the bus some time to recover */
 	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
-		ahc->platform_data->qfrozen++;
+		ahc_linux_freeze_sim_queue(ahc);
 		init_timer(&ahc->platform_data->reset_timer);
 		ahc->platform_data->reset_timer.data = (u_long)ahc;
 		ahc->platform_data->reset_timer.expires =
 		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
 		ahc->platform_data->reset_timer.function =
-		    ahc_release_sim_queue;
+		    ahc_linux_release_sim_queue;
 		add_timer(&ahc->platform_data->reset_timer);
 	}
 }
@@ -1238,6 +1274,11 @@
 					   0x1000);
 #endif
 		}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		/* XXX Need an instance detach in the PCI code */
+		if (ahc->dev_softc != NULL)
+			ahc->dev_softc->driver = NULL;
+#endif
 		free(ahc->platform_data, M_DEVBUF);
 	}
 }
@@ -1252,28 +1293,41 @@
 }
 
 void
-ahc_platform_set_tags(struct ahc_softc *ahc,
-		      struct ahc_devinfo *devinfo, int enable)
+ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		      ahc_queue_alg alg)
 {
 	struct ahc_linux_device *dev;
+	int was_queuing;
+	int now_queuing;
 
-	dev = ahc_get_device(ahc, devinfo->channel - 'A',
-			     devinfo->target,
-			     devinfo->lun, /*alloc*/FALSE);
+	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
+				   devinfo->target,
+				   devinfo->lun, /*alloc*/FALSE);
+	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+	now_queuing = alg != AHC_QUEUE_NONE;
 	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0
+	 && (was_queuing != now_queuing)
 	 && (dev->active != 0)) {
 		dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY;
 		dev->qfrozen++;
 	}
 
-	if (enable) {
-		/*
-		 * Start out agressively and allow our
-		 * dynamic queue depth algorithm take
-		 * care of the rest.
-		 */
-		dev->maxtags = AHC_MAX_QUEUE;
-		dev->openings = dev->maxtags - dev->active;
+	dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+	if (now_queuing) {
+
+		if (!was_queuing) {
+			/*
+			 * Start out agressively and allow our
+			 * dynamic queue depth algorithm to take
+			 * care of the rest.
+			 */
+			dev->maxtags = AHC_MAX_QUEUE;
+			dev->openings = dev->maxtags - dev->active;
+		}
+		if (alg == AHC_QUEUE_TAGGED)
+			dev->flags |= AHC_DEV_Q_TAGGED;
+		else
+			dev->flags |= AHC_DEV_Q_BASIC;
 	} else {
 		/* We can only have one opening */
 		dev->maxtags = 0;
@@ -1326,9 +1380,9 @@
 				struct ahc_busyq *busyq;
 				struct ahc_cmd *acmd;
 
-				dev = ahc_get_device(ahc, chan, targ,
-						     clun, /*alloc*/FALSE);
-
+				dev = ahc_linux_get_device(ahc, chan,
+							   targ, clun,
+							   /*alloc*/FALSE);
 				if (dev == NULL)
 					continue;
 
@@ -1341,7 +1395,7 @@
 						     acmd_links.tqe);
 					count++;
 					cmd->result = status << 16;
-					ahc_queue_cmd_complete(ahc, cmd);
+					ahc_linux_queue_cmd_complete(ahc, cmd);
 				}
 			}
 		}
@@ -1355,8 +1409,8 @@
  * off the input host adapter.
  */
 static void
-aic7xxx_select_queue_depth(struct Scsi_Host * host,
-			   Scsi_Device * scsi_devs)
+ahc_linux_select_queue_depth(struct Scsi_Host * host,
+			     Scsi_Device * scsi_devs)
 {
 	Scsi_Device *device;
 	struct	ahc_softc *ahc;
@@ -1368,7 +1422,7 @@
 	scbnum = 0;
 	for (device = scsi_devs; device != NULL; device = device->next) {
 		if (device->host == host) {
-			aic7xxx_device_queue_depth(ahc, device);
+			ahc_linux_device_queue_depth(ahc, device);
 			scbnum += device->queue_depth;
 		}
 	}
@@ -1379,11 +1433,11 @@
  * Determines the queue depth for a given device.
  */
 static void
-aic7xxx_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
+ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
 {
 	struct	ahc_devinfo devinfo;
 	struct	ahc_initiator_tinfo *targ_info;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	uint8_t tags;
 
 	ahc_compile_devinfo(&devinfo,
@@ -1397,7 +1451,7 @@
 
 	tags = 0;
 	if (device->tagged_supported != 0
-	 && (tstate->discenable & devinfo.target_mask) != 0) {
+	 && (ahc->user_discenable & devinfo.target_mask) != 0) {
 		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
 
 			printf("aic7xxx: WARNING, insufficient "
@@ -1418,7 +1472,7 @@
 	}
 	if (tags != 0) {
 		device->queue_depth = tags;
-		ahc_set_tags(ahc, &devinfo, TRUE);
+		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
 		printf("scsi%d:%d:%d:%d: Tagged Queuing enabled.  Depth %d\n",
 	       	       ahc->platform_data->host->host_no, device->channel,
 		       device->id, device->lun, tags);
@@ -1437,7 +1491,7 @@
  * Queue an SCB to the controller.
  */
 int
-aic7xxx_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
 {
 	struct	 ahc_softc *ahc;
 	struct	 ahc_linux_device *dev;
@@ -1451,29 +1505,29 @@
 	cmd->scsi_done = scsi_done;
 
 	ahc_lock(ahc, &flags);
-	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
-			     cmd->lun, /*alloc*/TRUE);
+	dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
+				   cmd->lun, /*alloc*/TRUE);
 	if (dev == NULL) {
 		ahc_unlock(ahc, &flags);
-		printf("aic7xxx_queue: Unable to allocate device!\n");
+		printf("aic7xxx_linux_queue: Unable to allocate device!\n");
 		return (-ENOMEM);
 	}
 	cmd->result = CAM_REQ_INPROG << 16;
 	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
-	ahc_run_device_queue(ahc, dev);
+	ahc_linux_run_device_queue(ahc, dev);
 	ahc_unlock(ahc, &flags);
 	return (0);
 }
 
 static void
-ahc_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct	 ahc_cmd *acmd;
 	struct	 scsi_cmnd *cmd;
 	struct	 scb *scb;
 	struct	 hardware_scb *hscb;
 	struct	 ahc_initiator_tinfo *tinfo;
-	struct	 tmode_tstate *tstate;
+	struct	 ahc_tmode_tstate *tstate;
 	uint16_t mask;
 
 	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
@@ -1524,19 +1578,26 @@
 					    SCB_GET_OUR_ID(scb),
 					    SCB_GET_TARGET(ahc, scb), &tstate);
 		hscb->scsirate = tinfo->scsirate;
-		hscb->scsioffset = tinfo->current.offset;
+		hscb->scsioffset = tinfo->curr.offset;
 		if ((tstate->ultraenb & mask) != 0)
 			hscb->control |= ULTRAENB;
 
-		if ((tstate->discenable & mask) != 0)
+		if ((ahc->user_discenable & mask) != 0)
 			hscb->control |= DISCENB;
 
-		if ((tstate->tagenable & mask) != 0) {
-			/* XXX What about devices that dislike ordered tags? */
-			if ((dev->num_commands % 256) == 0)
-				hscb->control |= MSG_ORDERED_Q_TAG;
-			else
-				hscb->control |= MSG_SIMPLE_Q_TAG;
+		if ((tstate->auto_negotiate & mask) != 0) {
+			scb->flags |= SCB_AUTO_NEGOTIATE;
+			scb->hscb->control |= MK_MESSAGE;
+		}
+
+		if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
+			if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
+			 && (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
+				hscb->control |= MSG_ORDERED_TASK;
+				dev->commands_since_idle_or_otag = 0;
+			} else {
+				hscb->control |= MSG_SIMPLE_TASK;
+			}
 		}
 
 		hscb->cdb_len = cmd->cmd_len;
@@ -1632,7 +1693,8 @@
 		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
 		dev->openings--;
 		dev->active++;
-		dev->num_commands++;
+		dev->commands_issued++;
+		dev->commands_since_idle_or_otag++;
 
 		/*
 		 * We only allow one untagged transaction
@@ -1661,7 +1723,7 @@
  * SCSI controller interrupt handler.
  */
 void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -1676,12 +1738,12 @@
 	 * dynamically register one, we'll have to postpone
 	 * that until we get integrated into the kernel.
 	 */
-	ahc_run_device_queues(ahc);
+	ahc_linux_run_device_queues(ahc);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	ahc_unlock(ahc, &flags);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 }
 
 void
@@ -1692,11 +1754,11 @@
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 }
 
 static struct ahc_linux_target*
-ahc_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
+ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
 {
 	struct ahc_linux_target *targ;
 	u_int target_offset;
@@ -1715,7 +1777,7 @@
 }
 
 static void
-ahc_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
+ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
 {
 	u_int target_offset;
 
@@ -1727,7 +1789,7 @@
 }
 
 static struct ahc_linux_device*
-ahc_alloc_device(struct ahc_softc *ahc,
+ahc_linux_alloc_device(struct ahc_softc *ahc,
 		 struct ahc_linux_target *targ, u_int lun)
 {
 	struct ahc_linux_device *dev;
@@ -1760,7 +1822,7 @@
 }
 
 static void
-ahc_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
 {
 	struct ahc_linux_target *targ;
 
@@ -1769,14 +1831,14 @@
 	free(dev, M_DEVBUF);
 	targ->refcount--;
 	if (targ->refcount == 0)
-		ahc_free_target(ahc, targ);
+		ahc_linux_free_target(ahc, targ);
 }
 
 /*
  * Return a string describing the driver.
  */
 const char *
-aic7xxx_info(struct Scsi_Host *host)
+ahc_linux_info(struct Scsi_Host *host)
 {
 	static char buffer[512];
 	char	ahc_info[256];
@@ -1802,7 +1864,7 @@
 
 void
 ahc_send_async(struct ahc_softc *ahc, char channel,
-	       u_int target, u_int lun, ac_code code)
+	       u_int target, u_int lun, ac_code code, void *arg)
 {
 	switch (code) {
 	case AC_TRANSFER_NEG:
@@ -1811,7 +1873,7 @@
 		struct	ahc_linux_target *targ;
 		struct	info_str info;
 		struct	ahc_initiator_tinfo *tinfo;
-		struct	tmode_tstate *tstate;
+		struct	ahc_tmode_tstate *tstate;
 		int	target_offset;
 
 		info.buffer = buf;
@@ -1827,10 +1889,10 @@
 		 * Don't bother reporting results while
 		 * negotiations are still pending.
 		 */
-		if (tinfo->current.period != tinfo->goal.period
-		 || tinfo->current.width != tinfo->goal.width
-		 || tinfo->current.offset != tinfo->goal.offset
-		 || tinfo->current.ppr_options != tinfo->goal.ppr_options)
+		if (tinfo->curr.period != tinfo->goal.period
+		 || tinfo->curr.width != tinfo->goal.width
+		 || tinfo->curr.offset != tinfo->goal.offset
+		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
 			if (bootverbose == 0)
 				break;
 
@@ -1843,24 +1905,24 @@
 			target_offset += 8;
 		targ = ahc->platform_data->targets[target_offset];
 		if (targ != NULL
-		 && tinfo->current.period == targ->last_tinfo.period
-		 && tinfo->current.width == targ->last_tinfo.width
-		 && tinfo->current.offset == targ->last_tinfo.offset
-		 && tinfo->current.ppr_options == targ->last_tinfo.ppr_options)
+		 && tinfo->curr.period == targ->last_tinfo.period
+		 && tinfo->curr.width == targ->last_tinfo.width
+		 && tinfo->curr.offset == targ->last_tinfo.offset
+		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
 			if (bootverbose == 0)
 				break;
 
-		targ->last_tinfo.period = tinfo->current.period;
-		targ->last_tinfo.width = tinfo->current.width;
-		targ->last_tinfo.offset = tinfo->current.offset;
-		targ->last_tinfo.ppr_options = tinfo->current.ppr_options;
+		targ->last_tinfo.period = tinfo->curr.period;
+		targ->last_tinfo.width = tinfo->curr.width;
+		targ->last_tinfo.offset = tinfo->curr.offset;
+		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
 
 		printf("(%s:%c:", ahc_name(ahc), channel);
 		if (target == CAM_TARGET_WILDCARD)
 			printf("*): ");
 		else
 			printf("%d): ", target);
-		ahc_format_transinfo(&info, &tinfo->current);
+		ahc_format_transinfo(&info, &tinfo->curr);
 		if (info.pos < info.length)
 			*info.buffer = '\0';
 		else
@@ -1909,7 +1971,7 @@
 	dev = scb->platform_data->dev;
 	dev->active--;
 	dev->openings++;
-	ahc_unmap_scb(ahc, scb);
+	ahc_linux_unmap_scb(ahc, scb);
 	if (scb->flags & SCB_SENSE) {
 		memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb),
 		       MIN(sizeof(struct scsi_sense_data),
@@ -1928,10 +1990,19 @@
 			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
 		} else {
 			ahc_set_transaction_status(scb, CAM_REQ_CMP);
-			ahc_sniff_command(ahc, cmd);
+			ahc_linux_sniff_command(ahc, cmd);
 		}
 	} else if (ahc_get_transaction_status(scb) == DID_OK) {
-		ahc_handle_scsi_status(ahc, dev, scb);
+		ahc_linux_handle_scsi_status(ahc, dev, scb);
+	} else if (ahc_get_transaction_status(scb) == DID_NO_CONNECT) {
+		/*
+		 * Should a selection timeout kill the device?
+		 * That depends on whether the selection timeout
+		 * is persistent.  Since we have no guarantee that
+		 * the mid-layer will issue an inquiry for this device
+		 * again, we can't just kill it off.
+		dev->flags |= AHC_DEV_UNCONFIGURED;
+		 */
 	}
 
 	if (dev->openings == 1
@@ -1950,10 +2021,14 @@
 		dev->openings++;
 	}
 
-	if (dev->active == 0
-	 && (dev->flags & AHC_DEV_UNCONFIGURED) != 0)
-		ahc_free_device(ahc, dev);
-	else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
+	if (dev->active == 0)
+		dev->commands_since_idle_or_otag = 0;
+
+	if (TAILQ_EMPTY(&dev->busyq)) {
+		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
+		 && dev->active == 0)
+			ahc_linux_free_device(ahc, dev);
+	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
 		LIST_INSERT_HEAD(&ahc->platform_data->device_runq, dev, links);
 		dev->flags |= AHC_DEV_ON_RUN_LIST;
 	}
@@ -1964,12 +2039,12 @@
 	}
 
 	ahc_free_scb(ahc, scb);
-	ahc_queue_cmd_complete(ahc, cmd);
+	ahc_linux_queue_cmd_complete(ahc, cmd);
 }
 
 static void
-ahc_handle_scsi_status(struct ahc_softc *ahc,
-		       struct ahc_linux_device *dev, struct scb *scb)
+ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev, struct scb *scb)
 {
 	/*
 	 * We don't currently trust the mid-layer to
@@ -2050,7 +2125,7 @@
 }
 
 static void
-ahc_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+ahc_linux_filter_command(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
 {
 	switch (cmd->cmnd[0]) {
 	case INQUIRY:
@@ -2058,8 +2133,9 @@
 		struct	ahc_devinfo devinfo;
 		struct	scsi_inquiry_data *sid;
 		struct	ahc_initiator_tinfo *targ_info;
-		struct	tmode_tstate *tstate;
+		struct	ahc_tmode_tstate *tstate;
 		struct	ahc_syncrate *syncrate;
+		struct	ahc_linux_device *dev;
 		u_int	scsiid;
 		u_int	maxsync;
 		int	minlen;
@@ -2078,15 +2154,20 @@
 		/*
 		 * Determine if this lun actually exists.  If so,
 		 * hold on to its corresponding device structure.
-		 */
+		 * If not, make sure we release the device and
+		 * don't bother processing the rest of this inquiry
+		 * command.
+		 */
+		dev = ahc_linux_get_device(ahc, cmd->channel,
+					   cmd->target, cmd->lun,
+					   /*alloc*/FALSE);
 		if (cmd->request_bufflen >= 1
 		 && SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
-			struct ahc_linux_device *dev;
 
-			dev = ahc_get_device(ahc, cmd->channel,
-					     cmd->target, cmd->lun,
-					     /*alloc*/FALSE);
 			dev->flags &= ~AHC_DEV_UNCONFIGURED;
+		} else {
+			dev->flags |= AHC_DEV_UNCONFIGURED;
+			break;
 		}
 
 		/*
@@ -2108,17 +2189,17 @@
 		ppr_options = targ_info->user.ppr_options;
 		minlen = offsetof(struct scsi_inquiry_data, version) + 1;
 		if (cmd->request_bufflen >= minlen) {
-			targ_info->current.protocol_version = SID_ANSI_REV(sid);
+			targ_info->curr.protocol_version = SID_ANSI_REV(sid);
 
 			/*
 			 * Only attempt SPI3 once we've verified that
 			 * the device claims to support SPI3 features.
 			 */
-			if (targ_info->current.protocol_version < SCSI_REV_2)
-				targ_info->current.transport_version =
+			if (targ_info->curr.protocol_version < SCSI_REV_2)
+				targ_info->curr.transport_version =
 				    SID_ANSI_REV(sid);
 			else
-				targ_info->current.transport_version =
+				targ_info->curr.transport_version =
 				     SCSI_REV_2;
 		}
 
@@ -2137,18 +2218,26 @@
 			break;
 		}
 		minlen = offsetof(struct scsi_inquiry_data, spi3data) + 1;
-		if (cmd->request_bufflen >= minlen
-		 && (sid->additional_length + 4) >= minlen) {
-			if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
+		/*
+		 * This is a kludge to deal with inquiry requests that
+		 * are not large enough for us to pull the spi3 bits.
+		 * In this case, we assume that a device that tells us
+		 * they can provide inquiry data that spans the SPI3
+		 * bits can handle a PPR request.  If the inquiry
+		 * request has sufficient buffer space to cover these
+		 * bits, we check them to see if any ppr options are
+		 * available.
+		 */
+		if ((sid->additional_length + 4) >= minlen) {
+			if (cmd->request_bufflen >= minlen
+			 && (sid->spi3data & SID_SPI_CLOCK_DT) == 0)
 				ppr_options = 0;
 
-			if ((sid->spi3data & SID_SPI_MASK) != 0
-			 && targ_info->current.protocol_version > SCSI_REV_2)
-				targ_info->current.transport_version = 3;
+			if (targ_info->curr.protocol_version > SCSI_REV_2)
+				targ_info->curr.transport_version = 3;
 		} else {
 			ppr_options = 0;
 		}
-
 		ahc_validate_width(ahc, /*tinfo limit*/NULL, &width,
 				   ROLE_UNKNOWN);
 		if ((ahc->features & AHC_ULTRA2) != 0)
@@ -2162,6 +2251,11 @@
 					     &ppr_options, maxsync);
 		ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate,
 				    &offset, width, ROLE_UNKNOWN);
+		if (offset == 0 || period == 0) {
+			period = 0;
+			offset = 0;
+			ppr_options = 0;
+		}
 		/* Apply our filtered user settings. */
 		ahc_set_width(ahc, &devinfo, width,
 			      AHC_TRANS_GOAL, /*paused*/FALSE);
@@ -2171,14 +2265,14 @@
 		break;
 	}
 	default:
-		panic("ahc_filter_command: Unexpected Command type  %x\n",
+		panic("ahc_linux_filter_command: Unexpected Command type  %x\n",
 		      cmd->cmnd[0]);
 		break;
 	}
 }
 
 static void
-ahc_sem_timeout(u_long arg)
+ahc_linux_sem_timeout(u_long arg)
 {
 	struct semaphore *sem;
 
@@ -2187,22 +2281,42 @@
 }
 
 static void
-ahc_release_sim_queue(u_long arg)
+ahc_linux_freeze_sim_queue(struct ahc_softc *ahc)
+{
+	ahc->platform_data->qfrozen++;
+	if (ahc->platform_data->qfrozen == 1)
+		scsi_block_requests(ahc->platform_data->host);
+}
+
+static void
+ahc_linux_release_sim_queue(u_long arg)
 {
 	struct ahc_softc *ahc;
 	u_long s;
+	int    unblock_reqs;
 
 	ahc = (struct ahc_softc *)arg;
+	unblock_reqs = 0;
 	ahc_lock(ahc, &s);
 	if (ahc->platform_data->qfrozen > 0)
 		ahc->platform_data->qfrozen--;
-	if (ahc->platform_data->qfrozen == 0)
-		ahc_run_device_queues(ahc);
+	if (ahc->platform_data->qfrozen == 0) {
+		unblock_reqs = 1;
+		ahc_linux_run_device_queues(ahc);
+	}
 	ahc_unlock(ahc, &s);
+	/*
+	 * There is still a race here.  The mid-layer
+	 * should keep its own freeze count and use
+	 * a bottom half handler to run the queues
+	 * so we can unblock with our own lock held.
+	 */
+	if (unblock_reqs)
+		scsi_unblock_requests(ahc->platform_data->host);
 }
 
 static int
-aic7xxx_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
+ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -2242,8 +2356,8 @@
 	 * at all, and the system wanted us to just abort the
 	 * command return success.
 	 */
-	dev = ahc_get_device(ahc, cmd->channel, cmd->target,
-			     cmd->lun, /*alloc*/FALSE);
+	dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
+				   cmd->lun, /*alloc*/FALSE);
 
 	if (dev == NULL) {
 		/*
@@ -2267,7 +2381,7 @@
 		if (flag == SCB_ABORT) {
 			TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
 			cmd->result = DID_ABORT << 16;
-			ahc_queue_cmd_complete(ahc, cmd);
+			ahc_linux_queue_cmd_complete(ahc, cmd);
 			retval = SUCCESS;
 			goto done;
 		}
@@ -2315,7 +2429,7 @@
 	ahc->flags |= AHC_ALL_INTERRUPTS;
 	do {
 		ahc_intr(ahc);
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		ahc_clear_critical_section(ahc);
 	} while (ahc_inb(ahc, INTSTAT) & INT_PEND);
 	ahc->flags &= ~AHC_ALL_INTERRUPTS;
@@ -2455,7 +2569,7 @@
 	retval = SUCCESS;
 done:
 	if (paused)
-		unpause_sequencer(ahc);
+		ahc_unpause(ahc);
 	if (wait) {
     		struct timer_list timer;
 		int ret;
@@ -2464,7 +2578,7 @@
 		init_timer(&timer);
 		timer.data = (u_long)&ahc->platform_data->eh_sem;
 		timer.expires = jiffies + (5 * HZ);
-		timer.function = ahc_sem_timeout;
+		timer.function = ahc_linux_sem_timeout;
 		add_timer(&timer);
 		printf("Recovery code sleeping\n");
 		down(&ahc->platform_data->eh_sem);
@@ -2476,12 +2590,12 @@
 		}
 		ahc_lock(ahc, &s);
 	}
-	ahc_run_device_queues(ahc);
+	ahc_linux_run_device_queues(ahc);
 	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
 	TAILQ_INIT(&ahc->platform_data->completeq);
 	ahc_unlock(ahc, &s);
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 	spin_lock_irq(&io_request_lock);
 	return (retval);
 }
@@ -2490,11 +2604,11 @@
  * Abort the current SCSI command(s).
  */
 int
-aic7xxx_abort(Scsi_Cmnd *cmd)
+ahc_linux_abort(Scsi_Cmnd *cmd)
 {
 	int error;
 
-	error = aic7xxx_queue_recovery_cmd(cmd, SCB_ABORT);
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
 	if (error != 0)
 		printf("aic7xxx_abort returns %d\n", error);
 	return (error);
@@ -2504,11 +2618,11 @@
  * Attempt to send a target reset message to the device that timed out.
  */
 int
-aic7xxx_dev_reset(Scsi_Cmnd *cmd)
+ahc_linux_dev_reset(Scsi_Cmnd *cmd)
 {
 	int error;
 
-	error = aic7xxx_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
 	if (error != 0)
 		printf("aic7xxx_dev_reset returns %d\n", error);
 	return (error);
@@ -2518,7 +2632,7 @@
  * Reset the SCSI bus.
  */
 int
-aic7xxx_bus_reset(Scsi_Cmnd *cmd)
+ahc_linux_bus_reset(Scsi_Cmnd *cmd)
 {
 	struct ahc_softc *ahc;
 	struct ahc_cmd *acmd;
@@ -2543,7 +2657,7 @@
 		       "%d SCBs aborted.\n", ahc_name(ahc), found);
 
 	if (acmd != NULL)
-		ahc_run_complete_queue(ahc, acmd);
+		ahc_linux_run_complete_queue(ahc, acmd);
 
 	spin_lock_irq(&io_request_lock);
 	return SUCCESS;
@@ -2553,7 +2667,7 @@
  * Return the disk geometry for the given SCSI device.
  */
 int
-aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
+ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
 {
 	int	heads;
 	int	sectors;
@@ -2597,14 +2711,23 @@
  * module.
  */
 int
-aic7xxx_release(struct Scsi_Host * host)
+ahc_linux_release(struct Scsi_Host * host)
 {
 	struct ahc_softc *ahc;
 
 	if (host != NULL) {
+
 		ahc = *(struct ahc_softc **)host->hostdata;
 		ahc_free(ahc);
 	}
+	if (TAILQ_EMPTY(&ahc_tailq)) {
+		unregister_reboot_notifier(&ahc_linux_notifier);
+#ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+		pci_unregister_driver(&aic7xxx_pci_driver);
+#endif
+#endif
+	}
 	return (0);
 }
 
@@ -2626,8 +2749,8 @@
 			for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
 				struct ahc_cmd *acmd;
 
-				dev = ahc_get_device(ahc, channel, target,
-						     lun, /*alloc*/FALSE);
+				dev = ahc_linux_get_device(ahc, channel, target,
+							   lun, /*alloc*/FALSE);
 				if (dev == NULL)
 					continue;
 
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_host.h linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Mon Dec  3 22:41:47 2001
@@ -28,24 +28,24 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#2 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_host.h#3 $
  */
 
 #ifndef _AIC7XXX_LINUX_HOST_H_
 #define _AIC7XXX_LINUX_HOST_H_
 
-int		 aic7xxx_proc_info(char *, char **, off_t, int, int, int);
-int		 aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-int		 aic7xxx_detect(Scsi_Host_Template *);
-int		 aic7xxx_release(struct Scsi_Host *);
-const char	*aic7xxx_info(struct Scsi_Host *);
-int		 aic7xxx_biosparam(Disk *, kdev_t, int[]);
-int		 aic7xxx_bus_reset(Scsi_Cmnd *);
-int		 aic7xxx_dev_reset(Scsi_Cmnd *);
-int		 aic7xxx_abort(Scsi_Cmnd *);
+int		 ahc_linux_proc_info(char *, char **, off_t, int, int, int);
+int		 ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+int		 ahc_linux_detect(Scsi_Host_Template *);
+int		 ahc_linux_release(struct Scsi_Host *);
+const char	*ahc_linux_info(struct Scsi_Host *);
+int		 ahc_linux_biosparam(Disk *, kdev_t, int[]);
+int		 ahc_linux_bus_reset(Scsi_Cmnd *);
+int		 ahc_linux_dev_reset(Scsi_Cmnd *);
+int		 ahc_linux_abort(Scsi_Cmnd *);
 
 #if defined(__i386__)
-#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#  define AIC7XXX_BIOSPARAM ahc_linux_biosparam
 #else
 #  define AIC7XXX_BIOSPARAM NULL
 #endif
@@ -58,23 +58,23 @@
 	next: NULL,						\
 	module: NULL,						\
 	proc_dir: NULL,						\
-	proc_info: aic7xxx_proc_info,				\
+	proc_info: ahc_linux_proc_info,				\
 	name: NULL,						\
-	detect: aic7xxx_detect,					\
-	release: aic7xxx_release,				\
-	info: aic7xxx_info,					\
+	detect: ahc_linux_detect,				\
+	release: ahc_linux_release,				\
+	info: ahc_linux_info,					\
 	command: NULL,						\
-	queuecommand: aic7xxx_queue,				\
+	queuecommand: ahc_linux_queue,				\
 	eh_strategy_handler: NULL,				\
-	eh_abort_handler: aic7xxx_abort,			\
-	eh_device_reset_handler: aic7xxx_dev_reset,		\
-	eh_bus_reset_handler: aic7xxx_bus_reset,		\
+	eh_abort_handler: ahc_linux_abort,			\
+	eh_device_reset_handler: ahc_linux_dev_reset,		\
+	eh_bus_reset_handler: ahc_linux_bus_reset,		\
 	eh_host_reset_handler: NULL,				\
 	abort: NULL,						\
 	reset: NULL,						\
 	slave_attach: NULL,					\
 	bios_param: AIC7XXX_BIOSPARAM,				\
-	can_queue: 254,		/* max simultaneous cmds      */\
+	can_queue: 253,		/* max simultaneous cmds      */\
 	this_id: -1,		/* scsi id of host adapter    */\
 	sg_tablesize: 0,	/* max scatter-gather cmds    */\
 	cmd_per_lun: 2,		/* cmds per lun		      */\
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Tue Mar  6 22:44:16 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#15 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux_pci.c#17 $
  */
 
 #include "aic7xxx_osm.h"
@@ -57,7 +57,7 @@
 	{ 0 }
 };
 
-static struct pci_driver aic7xxx_pci_driver = {
+struct pci_driver aic7xxx_pci_driver = {
 	name:		"aic7xxx",
 	probe:		ahc_linux_pci_dev_probe,
 	remove:		ahc_linux_pci_dev_remove,
@@ -133,7 +133,7 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	pdev->driver_data = ahc;
 	if (aic7xxx_detect_complete)
-		aic7xxx_register_host(ahc, aic7xxx_driver_template);
+		ahc_linux_register_host(ahc, aic7xxx_driver_template);
 #endif
 	return (0);
 }
@@ -191,11 +191,9 @@
 {
 	uint32_t command;
 	u_long	 base;
-#ifdef MMAPIO
 	u_long	 start;
 	u_long	 base_page;
 	u_long	 base_offset;
-#endif
 	uint8_t *maddr;
 
 	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
@@ -306,11 +304,47 @@
 	int error;
 
 	ahc->platform_data->irq = ahc->dev_softc->irq;
-	error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
-			    SA_INTERRUPT|SA_SHIRQ, "aic7xxx", ahc);
-	if (error < 0)
-		error = request_irq(ahc->platform_data->irq, aic7xxx_isr,
-				    SA_SHIRQ, "aic7xxx", ahc);
+	error = request_irq(ahc->platform_data->irq, ahc_linux_isr,
+			    SA_SHIRQ, "aic7xxx", ahc);
 	
 	return (-error);
+}
+
+void
+ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pci_set_power_state(ahc->dev_softc, new_state);
+#else
+	uint32_t cap;
+	u_int cap_offset;
+
+	/*
+	 * Traverse the capability list looking for
+	 * the power management capability.
+	 */
+	cap = 0;
+	cap_offset = ahc_pci_read_config(ahc->dev_softc,
+					 PCIR_CAP_PTR, /*bytes*/1);
+	while (cap_offset != 0) {
+
+		cap = ahc_pci_read_config(ahc->dev_softc,
+					  cap_offset, /*bytes*/4);
+		if ((cap & 0xFF) == 1
+		 && ((cap >> 16) & 0x3) > 0) {
+			uint32_t pm_control;
+
+			pm_control = ahc_pci_read_config(ahc->dev_softc,
+							 cap_offset + 4,
+							 /*bytes*/4);
+			pm_control &= ~0x3;
+			pm_control |= new_state;
+			ahc_pci_write_config(ahc->dev_softc,
+					     cap_offset + 4,
+					     pm_control, /*bytes*/2);
+			break;
+		}
+		cap_offset = (cap >> 8) & 0xFF;
+	}
+#endif 
 }
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_osm.h linux/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_osm.h	Thu Apr 12 12:16:35 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon Dec  3 22:41:47 2001
@@ -18,7 +18,7 @@
  * along with this program; see the file COPYING.  If not, write to
  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  * 
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $
  *
  * Copyright (c) 2000, 2001 Adaptec Inc.
  * All rights reserved.
@@ -47,7 +47,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#45 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_linux.h#59 $
  *
  */
 #ifndef _AIC7XXX_LINUX_H_
@@ -62,6 +62,10 @@
 #include <linux/pci.h>
 #include <linux/version.h>
 
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #include <linux/config.h>
 #endif
@@ -79,14 +83,6 @@
 #include "queue.h"
 #include "scsi_message.h"
 
-/*
- * We never have to reference the current task, and the driver core
- * makes ample use of this "name".
- */
-#ifdef current
-#undef current
-#endif
-
 /************************* Forward Declarations *******************************/
 struct ahc_softc;
 typedef struct pci_dev *ahc_dev_softc_t;
@@ -114,7 +110,7 @@
 
 /***************************** Bus Space/DMA **********************************/
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17)
 typedef dma_addr_t bus_addr_t;
 #else
 typedef uint32_t bus_addr_t;
@@ -353,11 +349,7 @@
 #include <linux/smp.h>
 #endif
 
-#define AIC7XXX_DRIVER_VERSION  "6.1.5"
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-#endif
+#define AIC7XXX_DRIVER_VERSION  "6.1.13"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -401,7 +393,9 @@
 	AHC_DEV_UNCONFIGURED	 = 0x01,
 	AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
 	AHC_DEV_TIMER_ACTIVE	 = 0x04, /* Our timer is active */
-	AHC_DEV_ON_RUN_LIST	 = 0x08	 /* Queued to be run later */
+	AHC_DEV_ON_RUN_LIST	 = 0x08, /* Queued to be run later */
+	AHC_DEV_Q_BASIC		 = 0x10, /* Allow basic device queuing */
+	AHC_DEV_Q_TAGGED	 = 0x20  /* Allow full SCSI2 command queueing */
 } ahc_dev_flags;
 
 struct ahc_linux_target;
@@ -434,7 +428,7 @@
 	/*
 	 * Cumulative command counter.
 	 */
-	u_int		num_commands;
+	u_long		commands_issued;
 
 	/*
 	 * The number of tagged transactions when
@@ -465,8 +459,16 @@
 	 * on devices with a fixed number of tags.
 	 */
 	u_int		last_queuefull_same_count;
-
 #define AHC_LOCK_TAGS_COUNT 50
+
+	/*
+	 * How many transactions have been queued
+	 * without the device going idle.  We use
+	 * this statistic to 
+	 */
+	u_int		commands_since_idle_or_otag;
+#define AHC_OTAG_THRESH	250
+
 	int		lun;
 	struct		ahc_linux_target *target;
 };
@@ -570,9 +572,6 @@
 #endif
 #define mb() \
 	__asm__ __volatile__("mb": : :"memory")
-#elif defined(__sparc__)
-#define MMAPIO
-/* The default mb() define does what this driver wants. -DaveM */
 #endif
 
 static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
@@ -644,8 +643,8 @@
 }
 
 /**************************** Initialization **********************************/
-int	aic7xxx_register_host(struct ahc_softc *ahc,
-			      Scsi_Host_Template *template);
+int	ahc_linux_register_host(struct ahc_softc *,
+				Scsi_Host_Template *);
 
 /*************************** Pretty Printing **********************************/
 struct info_str {
@@ -784,11 +783,24 @@
 #define PCIR_SUBVEND_0	0x2c
 #define PCIR_SUBDEV_0	0x2e
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+extern struct pci_driver aic7xxx_pci_driver;
+#endif
+
+typedef enum
+{
+	AHC_POWER_STATE_D0,
+	AHC_POWER_STATE_D1,
+	AHC_POWER_STATE_D2,
+	AHC_POWER_STATE_D3
+} ahc_power_state;
+
+void ahc_power_state_change(struct ahc_softc *ahc,
+			    ahc_power_state new_state);
 /**************************** VL/EISA Routines ********************************/
 int			 aic7770_linux_probe(Scsi_Host_Template *);
 int			 aic7770_map_registers(struct ahc_softc *ahc);
-int			 aic7770_map_int(struct ahc_softc *ahc,
-					 u_int irq, int shared);
+int			 aic7770_map_int(struct ahc_softc *ahc, u_int irq);
 
 /******************************* PCI Routines *********************************/
 /*
@@ -1047,16 +1059,16 @@
 }
 
 void	ahc_platform_set_tags(struct ahc_softc *ahc,
-			      struct ahc_devinfo *devinfo, int enable);
+			      struct ahc_devinfo *devinfo, ahc_queue_alg);
 int	ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
 				char channel, int lun, u_int tag,
 				role_t role, uint32_t status);
-void	aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs);
+void	ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
 void	ahc_platform_flushwork(struct ahc_softc *ahc);
 int	ahc_softc_comp(struct ahc_softc *, struct ahc_softc *);
 void	ahc_done(struct ahc_softc*, struct scb*);
 void	ahc_send_async(struct ahc_softc *, char channel,
-		       u_int target, u_int lun, ac_code);
+		       u_int target, u_int lun, ac_code, void *);
 void	ahc_print_path(struct ahc_softc *, struct scb *);
 void	ahc_platform_dump_card_state(struct ahc_softc *ahc);
 
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_pci.c linux/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_pci.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon Dec  3 22:41:47 2001
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#17 $
+ * $Id: //depot/src/aic7xxx/aic7xxx_pci.c#24 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_pci.c,v 1.6 2000/11/10 20:13:41 gibbs Exp $
  */
@@ -263,7 +263,7 @@
 	{
 		ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK,
 		ID_DEV_VENDOR_MASK,
-		"Adaptec 2930C SCSI adapter (VAR)",
+		"Adaptec 2930C Ultra SCSI adapter (VAR)",
 		ahc_aic7860_setup
 	},
 	/* aic7870 based controllers */
@@ -452,7 +452,7 @@
 	{
 		ID_AIC7892_ARO,
 		ID_ALL_MASK,
-		"Adaptec aic7892 Ultra2 SCSI adapter (ARO)",
+		"Adaptec aic7892 Ultra160 SCSI adapter (ARO)",
 		ahc_aic7892_setup
 	},
 	/* aic7895 based controllers */	
@@ -546,13 +546,13 @@
 	{
 		ID_AIC7859 & ID_DEV_VENDOR_MASK,
 		ID_DEV_VENDOR_MASK,
-		"Adaptec aic7859 Ultra SCSI adapter",
+		"Adaptec aic7859 SCSI adapter",
 		ahc_aic7860_setup
 	},
 	{
 		ID_AIC7860 & ID_DEV_VENDOR_MASK,
 		ID_DEV_VENDOR_MASK,
-		"Adaptec aic7860 SCSI adapter",
+		"Adaptec aic7860 Ultra SCSI adapter",
 		ahc_aic7860_setup
 	},
 	{
@@ -644,16 +644,6 @@
 #define		CACHESIZE	0x0000003ful	/* only 5 bits */
 #define		LATTIME		0x0000ff00ul
 
-typedef enum
-{
-	AHC_POWER_STATE_D0,
-	AHC_POWER_STATE_D1,
-	AHC_POWER_STATE_D2,
-	AHC_POWER_STATE_D3
-} ahc_power_state;
-
-static void ahc_power_state_change(struct ahc_softc *ahc,
-				   ahc_power_state new_state);
 static int ahc_ext_scbram_present(struct ahc_softc *ahc);
 static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
 				  int pcheck, int fast, int large);
@@ -761,9 +751,11 @@
 	if (error != 0)
 		return (error);
 
+	ahc->bus_intr = ahc_pci_intr;
+
 	/* Remeber how the card was setup in case there is no SEEPROM */
 	if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
-		pause_sequencer(ahc);
+		ahc_pause(ahc);
 		if ((ahc->features & AHC_ULTRA2) != 0)
 			our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
 		else
@@ -786,7 +778,8 @@
 		/* Perform ALT-Mode Setup */
 		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
 		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
-		ahc_outb(ahc, OPTIONMODE, OPTIONMODE_DEFAULTS);
+		ahc_outb(ahc, OPTIONMODE,
+			 OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS);
 		ahc_outb(ahc, SFUNCT, sfunct);
 
 		/* Normal mode setup */
@@ -794,9 +787,6 @@
 					  |TARGCRCENDEN);
 	}
 
-	error = ahc_pci_map_int(ahc);
-	if (error != 0)
-		return (error);
 	dscommand0 = ahc_inb(ahc, DSCOMMAND0);
 	dscommand0 |= MPARCKEN|CACHETHEN;
 	if ((ahc->features & AHC_ULTRA2) != 0) {
@@ -825,6 +815,19 @@
 				/*bytes*/1) & CACHESIZE;
 	ahc->pci_cachesize *= 4;
 
+	/*
+	 * We cannot perform ULTRA speeds without the presense
+	 * of the external precision resistor.
+	 */
+	if ((ahc->features & AHC_ULTRA) != 0) {
+		uint32_t devconfig;
+
+		devconfig = ahc_pci_read_config(ahc->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		if ((devconfig & REXTVALID) == 0)
+			ahc->features &= ~AHC_ULTRA;
+	}
+
 	/* See if we have a SEEPROM and perform auto-term */
 	check_extport(ahc, &sxfrctl1);
 
@@ -879,20 +882,6 @@
 	if ((sxfrctl1 & STPWEN) != 0)
 		ahc->flags |= AHC_TERM_ENB_A;
 
-	/*
-	 * We cannot perform ULTRA speeds without
-	 * the presense of the external precision
-	 * resistor.
-	 */
-	if ((ahc->features & AHC_ULTRA) != 0) {
-		uint32_t devconfig;
-
-		devconfig = ahc_pci_read_config(ahc->dev_softc,
-						DEVCONFIG, /*bytes*/4);
-		if ((devconfig & REXTVALID) == 0)
-			ahc->flags |= AHC_ULTRA_DISABLED;
-	}
-
 	/* Core initialization */
 	error = ahc_init(ahc);
 	if (error != 0)
@@ -903,42 +892,16 @@
 	 */
 	ahc_softc_insert(ahc);
 
-	return (0);
-}
-
-static void
-ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
-{
-	uint32_t cap;
-	u_int cap_offset;
-
 	/*
-	 * Traverse the capability list looking for
-	 * the power management capability.
+	 * Allow interrupts now that we are completely setup.
 	 */
-	cap = 0;
-	cap_offset = ahc_pci_read_config(ahc->dev_softc,
-					 PCIR_CAP_PTR, /*bytes*/1);
-	while (cap_offset != 0) {
-
-		cap = ahc_pci_read_config(ahc->dev_softc,
-					  cap_offset, /*bytes*/4);
-		if ((cap & 0xFF) == 1
-		 && ((cap >> 16) & 0x3) > 0) {
-			uint32_t pm_control;
-
-			pm_control = ahc_pci_read_config(ahc->dev_softc,
-							 cap_offset + 4,
-							 /*bytes*/4);
-			pm_control &= ~0x3;
-			pm_control |= new_state;
-			ahc_pci_write_config(ahc->dev_softc,
-					     cap_offset + 4,
-					     pm_control, /*bytes*/2);
-			break;
-		}
-		cap_offset = (cap >> 8) & 0xFF;
-	}
+	error = ahc_pci_map_int(ahc);
+	if (error != 0)
+		return (error);
+
+	ahc_intr_enable(ahc, TRUE);
+
+	return (0);
 }
 
 /*
@@ -1190,32 +1153,37 @@
 			}
 			sd.sd_chip = C56_66;
 		}
+		release_seeprom(&sd);
 	}
 
-#if 0
 	if (!have_seeprom) {
 		/*
 		 * Pull scratch ram settings and treat them as
 		 * if they are the contents of an seeprom if
 		 * the 'ADPT' signature is found in SCB2.
+		 * We manually compose the data as 16bit values
+		 * to avoid endian issues.
 		 */
 		ahc_outb(ahc, SCBPTR, 2);
 		if (ahc_inb(ahc, SCB_BASE) == 'A'
 		 && ahc_inb(ahc, SCB_BASE + 1) == 'D'
 		 && ahc_inb(ahc, SCB_BASE + 2) == 'P'
 		 && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
-			uint8_t *sc_bytes;
+			uint16_t *sc_data;
 			int	  i;
 
-			sc_bytes = (uint8_t *)&sc;
-			for (i = 0; i < 64; i++)
-				sc_bytes[i] = ahc_inb(ahc, TARG_SCSIRATE + i);
-			/* Byte 0x1c is stored in byte 4 of SCB2 */
-			sc_bytes[0x1c] = ahc_inb(ahc, SCB_BASE + 4);
+			sc_data = (uint16_t *)&sc;
+			for (i = 0; i < 32; i++) {
+				uint16_t val;
+				int	 j;
+
+				j = i * 2;
+				val = ahc_inb(ahc, SRAM_BASE + j)
+				    | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
+			}
 			have_seeprom = verify_cksum(&sc);
 		}
 	}
-#endif
 
 	if (!have_seeprom) {
 		if (bootverbose)
@@ -1301,9 +1269,8 @@
 		if (sc.adapter_control & CFRESETB)
 			scsi_conf |= RESET_SCSI;
 
-		if ((sc.adapter_control & CFCHNLBPRIMARY) != 0
-		 && (ahc->features & AHC_MULTI_FUNC) != 0)
-			ahc->flags |= AHC_CHANNEL_B_PRIMARY;
+		ahc->flags |=
+		    (sc.adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
 
 		if (sc.bios_control & CFEXTEND)
 			ahc->flags |= AHC_EXTENDED_TRANS_A;
@@ -1318,7 +1285,8 @@
 				ultraenb = 0;
 		}
 
-		if (sc.signature == CFSIGNATURE) {
+		if (sc.signature == CFSIGNATURE
+		 || sc.signature == CFSIGNATURE2) {
 			uint32_t devconfig;
 
 			/* Honor the STPWLEVEL settings */
@@ -1362,10 +1330,11 @@
 			have_autoterm = FALSE;
 	}
 
-	if (have_autoterm)
+	if (have_autoterm) {
+		acquire_seeprom(ahc, &sd);
 		configure_termination(ahc, &sd, adapter_control, sxfrctl1);
-
-	release_seeprom(&sd);
+		release_seeprom(&sd);
+	}
 }
 
 static void
@@ -1806,7 +1775,7 @@
 		ahc_outb(ahc, CLRINT, CLRPARERR);
 	}
 
-	unpause_sequencer(ahc);
+	ahc_unpause(ahc);
 }
 
 static int
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_proc.c linux/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_proc.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon Dec  3 22:41:47 2001
@@ -29,7 +29,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#7 $
+ * $Id: //depot/src/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#11 $
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
@@ -174,7 +174,7 @@
 {
 	struct	ahc_linux_target *targ;
 	struct	ahc_initiator_tinfo *tinfo;
-	struct	tmode_tstate *tstate;
+	struct	ahc_tmode_tstate *tstate;
 	int	lun;
 
 	tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
@@ -190,7 +190,7 @@
 	copy_info(info, "\tGoal: ");
 	ahc_format_transinfo(info, &tinfo->goal);
 	copy_info(info, "\tCurr: ");
-	ahc_format_transinfo(info, &tinfo->current);
+	ahc_format_transinfo(info, &tinfo->curr);
 
 	for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
 		struct ahc_linux_device *dev;
@@ -210,7 +210,7 @@
 	copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
 		  dev->target->channel + 'A', dev->target->target, dev->lun);
 
-	copy_info(info, "\t\tCommands Queued %d\n", dev->num_commands);
+	copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
 	copy_info(info, "\t\tCommands Active %d\n", dev->active);
 	copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
 	copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
@@ -221,7 +221,7 @@
  * Return information to handle /proc support for the driver.
  */
 int
-aic7xxx_proc_info(char *buffer, char **start, off_t offset,
+ahc_linux_proc_info(char *buffer, char **start, off_t offset,
 		  int length, int hostno, int inout)
 {
 	struct	ahc_softc *ahc;
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_reg.h linux/drivers/scsi/aic7xxx/aic7xxx_reg.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_reg.h	Tue Mar  6 19:18:16 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_reg.h	Mon Dec  3 22:41:47 2001
@@ -86,8 +86,8 @@
 #define		SELDO           	0x40
 #define		SELDI           	0x20
 #define		SELINGO         	0x10
-#define		IOERR           	0x08
 #define		SWRAP           	0x08
+#define		IOERR           	0x08
 #define		SDONE           	0x04
 #define		SPIORDY         	0x02
 #define		DMADONE         	0x01
@@ -191,8 +191,8 @@
 #define		BRDDAT5         	0x20
 #define		BRDDAT4         	0x10
 #define		BRDSTB          	0x10
-#define		BRDCS           	0x08
 #define		BRDDAT3         	0x08
+#define		BRDCS           	0x08
 #define		BRDDAT2         	0x04
 #define		BRDRW           	0x04
 #define		BRDRW_ULTRA2    	0x02
@@ -242,8 +242,8 @@
 #define		PRELOADEN       	0x80
 #define		WIDEODD         	0x40
 #define		SCSIEN          	0x20
-#define		SDMAENACK       	0x10
 #define		SDMAEN          	0x10
+#define		SDMAENACK       	0x10
 #define		HDMAEN          	0x08
 #define		HDMAENACK       	0x08
 #define		DIRECTION       	0x04
@@ -271,8 +271,8 @@
 #define		P_MESGOUT       	0xa0
 #define		P_COMMAND       	0x80
 #define		CDI             	0x80
-#define		IOI             	0x40
 #define		P_DATAIN        	0x40
+#define		IOI             	0x40
 #define		MSGI            	0x20
 #define		P_BUSFREE       	0x01
 #define		P_DATAOUT       	0x00
@@ -314,9 +314,7 @@
 
 #define	LAST_MSG        		0x53
 
-#define	TARGET_MSG_REQUEST		0x54
-
-#define	SCSISEQ_TEMPLATE		0x56
+#define	SCSISEQ_TEMPLATE		0x54
 #define		ENSELO          	0x40
 #define		ENSELI          	0x20
 #define		ENRSELI         	0x10
@@ -324,11 +322,11 @@
 #define		ENAUTOATNI      	0x04
 #define		ENAUTOATNP      	0x02
 
-#define	DATA_COUNT_ODD  		0x57
+#define	DATA_COUNT_ODD  		0x55
 
-#define	INITIATOR_TAG   		0x58
+#define	INITIATOR_TAG   		0x56
 
-#define	SEQ_FLAGS2      		0x59
+#define	SEQ_FLAGS2      		0x57
 #define		SCB_DMA         	0x01
 
 #define	SCSICONF        		0x5a
@@ -345,8 +343,8 @@
 #define	HOSTCONF        		0x5d
 
 #define	HA_274_BIOSCTRL 		0x5f
-#define		BIOSMODE        	0x30
 #define		BIOSDISABLED    	0x30
+#define		BIOSMODE        	0x30
 #define		CHANNEL_B_PRIMARY	0x08
 
 #define	SEQCTL          		0x60
@@ -483,7 +481,8 @@
 
 #define	DFSTATUS        		0x94
 #define		PRELOAD_AVAIL   	0x80
-#define		DWORDEMP        	0x20
+#define		DFCACHETH       	0x40
+#define		FIFOQWDEMP      	0x20
 #define		MREQPEND        	0x10
 #define		HDONE           	0x08
 #define		DFTHRESH        	0x04
@@ -521,18 +520,19 @@
 #define		COMMAND_PHASE   	0x10
 #define		MSG_IN_PHASE    	0x08
 #define		MSG_OUT_PHASE   	0x04
+#define		DATA_PHASE_MASK 	0x03
 #define		DATA_IN_PHASE   	0x02
 #define		DATA_OUT_PHASE  	0x01
 
 #define	SFUNCT          		0x9f
 #define		ALT_MODE        	0x80
 
+#define	SCB_BASE        		0xa0
+
 #define	SCB_CDB_PTR     		0xa0
+#define	SCB_RESIDUAL_DATACNT		0xa0
 #define	SCB_CDB_STORE   		0xa0
 #define	SCB_TARGET_INFO 		0xa0
-#define	SCB_RESIDUAL_DATACNT		0xa0
-
-#define	SCB_BASE        		0xa0
 
 #define	SCB_RESIDUAL_SGPTR		0xa4
 
@@ -579,13 +579,13 @@
 
 #define	SCB_NEXT        		0xbf
 
+#define	SCB_64_SPARE    		0xc0
+
 #define	SEECTL_2840     		0xc0
 #define		CS_2840         	0x04
 #define		CK_2840         	0x02
 #define		DO_2840         	0x01
 
-#define	SCB_64_SPARE    		0xc0
-
 #define	STATUS_2840     		0xc1
 #define		EEPROM_TF       	0x80
 #define		BIOS_SEL        	0x60
@@ -648,8 +648,8 @@
 #define		WR_DFTHRSH_63   	0x30
 #define		WR_DFTHRSH_50   	0x20
 #define		WR_DFTHRSH_25   	0x10
-#define		RD_DFTHRSH_MAX  	0x07
 #define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_MAX  	0x07
 #define		RD_DFTHRSH_90   	0x06
 #define		RD_DFTHRSH_85   	0x05
 #define		RD_DFTHRSH_75   	0x04
@@ -668,39 +668,39 @@
 #define	SG_CACHE_PRE    		0xfc
 
 
-#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	SCB_INITIATOR_TAG	0x03
+#define	SCB_TARGET_DATA_DIR	0x01
+#define	SCB_TARGET_PHASES	0x00
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
 #define	BUS_8_BIT	0x00
-#define	CCSGRAM_MAXSEGS	0x10
-#define	TARGET_DATA_IN	0x01
+#define	TARGET_CMD_CMPLT	0xfe
 #define	STATUS_QUEUE_FULL	0x28
 #define	STATUS_BUSY	0x08
 #define	MAX_OFFSET_8BIT	0x0f
-#define	BUS_16_BIT	0x01
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
 #define	TID_SHIFT	0x04
 #define	SCB_DOWNLOAD_SIZE_64	0x30
-#define	SCB_UPLOAD_SIZE	0x20
 #define	HOST_MAILBOX_SHIFT	0x04
-#define	SCB_INITIATOR_TAG	0x03
 #define	SCB_TARGET_STATUS	0x02
-#define	SCB_TARGET_DATA_DIR	0x01
-#define	SCB_TARGET_PHASES	0x00
-#define	MAX_OFFSET_ULTRA2	0x7f
-#define	MAX_OFFSET_16BIT	0x08
-#define	TARGET_CMD_CMPLT	0xfe
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	CCSGRAM_MAXSEGS	0x10
 #define	SCB_LIST_NULL	0xff
 #define	SG_SIZEOF	0x08
 #define	SCB_DOWNLOAD_SIZE	0x20
 #define	SEQ_MAILBOX_SHIFT	0x00
+#define	TARGET_DATA_IN	0x01
 #define	HOST_MSG	0xff
-#define	BUS_32_BIT	0x02
-#define	CCSGADDR_MAX	0x80
+#define	BUS_16_BIT	0x01
+#define	SCB_UPLOAD_SIZE	0x20
 
 
 /* Downloaded Constant Definitions */
+#define	INVERTED_CACHESIZE_MASK	0x03
 #define	SG_PREFETCH_ADDR_MASK	0x06
 #define	SG_PREFETCH_ALIGN_MASK	0x05
 #define	QOUTFIFO_OFFSET	0x00
 #define	SG_PREFETCH_CNT	0x04
-#define	INVERTED_CACHESIZE_MASK	0x03
 #define	CACHESIZE_MASK	0x02
 #define	QINFIFO_OFFSET	0x01
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_seq.h linux/drivers/scsi/aic7xxx/aic7xxx_seq.h
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aic7xxx_seq.h	Tue Mar  6 19:18:16 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx_seq.h	Mon Dec  3 22:41:47 2001
@@ -4,7 +4,7 @@
 static uint8_t seqprog[] = {
 	0xb2, 0x00, 0x00, 0x08,
 	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0xde, 0x59,
+	0x00, 0x65, 0xe4, 0x59,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x6a, 0x24, 0x08,
 	0x40, 0x00, 0x40, 0x68,
@@ -17,21 +17,21 @@
 	0x01, 0x4d, 0xc8, 0x30,
 	0x00, 0x4c, 0x12, 0x70,
 	0x01, 0x39, 0xa2, 0x30,
-	0x00, 0x6a, 0x7e, 0x5e,
+	0x00, 0x6a, 0x92, 0x5e,
 	0x01, 0x51, 0x20, 0x31,
-	0x01, 0x59, 0xb2, 0x00,
+	0x01, 0x57, 0xae, 0x00,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0xda, 0x5d,
+	0x00, 0x51, 0xec, 0x5d,
 	0x01, 0x51, 0xc8, 0x30,
 	0x00, 0x39, 0xde, 0x60,
 	0x00, 0xbb, 0x30, 0x70,
-	0xc1, 0x6a, 0x96, 0x5e,
+	0xc1, 0x6a, 0xaa, 0x5e,
 	0x01, 0xbf, 0x72, 0x30,
 	0x01, 0x40, 0x7e, 0x31,
 	0x01, 0x90, 0x80, 0x30,
 	0x01, 0xf6, 0xd4, 0x30,
 	0x01, 0x4d, 0x9a, 0x18,
-	0xfe, 0x59, 0xb2, 0x08,
+	0xfe, 0x57, 0xae, 0x08,
 	0x01, 0x40, 0x20, 0x31,
 	0x00, 0x65, 0xe2, 0x58,
 	0x60, 0x0b, 0x40, 0x78,
@@ -48,10 +48,10 @@
 	0x08, 0x3c, 0x78, 0x00,
 	0x01, 0x50, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xc4, 0x5d,
+	0x48, 0x6a, 0xd6, 0x5d,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xc4, 0x5d,
+	0x48, 0x6a, 0xd6, 0x5d,
 	0x01, 0x6a, 0x26, 0x01,
 	0xf0, 0x19, 0x7a, 0x08,
 	0x0f, 0x18, 0xc8, 0x08,
@@ -62,7 +62,7 @@
 	0x80, 0x3d, 0x7a, 0x00,
 	0x01, 0x3d, 0xd8, 0x31,
 	0x01, 0x3d, 0x32, 0x31,
-	0x10, 0x03, 0x56, 0x79,
+	0x10, 0x03, 0x5c, 0x79,
 	0x00, 0x65, 0x0a, 0x59,
 	0x80, 0x66, 0xa8, 0x78,
 	0x01, 0x66, 0xd8, 0x31,
@@ -77,33 +77,33 @@
 	0x00, 0x65, 0xb0, 0x48,
 	0x01, 0x66, 0xd8, 0x31,
 	0x01, 0x66, 0x32, 0x31,
-	0x10, 0x03, 0x56, 0x79,
+	0x10, 0x03, 0x5c, 0x79,
 	0x00, 0x65, 0x0a, 0x59,
 	0x01, 0x66, 0xd8, 0x31,
 	0x01, 0x66, 0x32, 0x31,
-	0x01, 0x66, 0xb0, 0x30,
+	0x01, 0x66, 0xac, 0x30,
 	0x40, 0x3c, 0x78, 0x00,
 	0x10, 0x03, 0xa6, 0x78,
 	0x00, 0x65, 0x0a, 0x59,
 	0x00, 0x65, 0xb0, 0x40,
-	0x61, 0x6a, 0x96, 0x5e,
-	0x08, 0x51, 0x2e, 0x71,
+	0x61, 0x6a, 0xaa, 0x5e,
+	0x08, 0x51, 0x34, 0x71,
 	0x02, 0x0b, 0xac, 0x78,
 	0x00, 0x65, 0xa8, 0x40,
 	0x80, 0x86, 0xc8, 0x08,
 	0x01, 0x4f, 0xc8, 0x30,
 	0x00, 0x50, 0xc2, 0x60,
-	0xc4, 0x6a, 0x32, 0x5d,
+	0xc4, 0x6a, 0x44, 0x5d,
 	0x40, 0x3c, 0xbe, 0x78,
-	0x28, 0x6a, 0x48, 0x5d,
-	0x00, 0x65, 0x54, 0x41,
-	0x08, 0x6a, 0x48, 0x5d,
-	0x00, 0x65, 0x54, 0x41,
+	0x28, 0x6a, 0x5a, 0x5d,
+	0x00, 0x65, 0x5a, 0x41,
+	0x08, 0x6a, 0x5a, 0x5d,
+	0x00, 0x65, 0x5a, 0x41,
 	0xff, 0x6a, 0xd8, 0x01,
 	0xff, 0x6a, 0x32, 0x01,
 	0x90, 0x3c, 0x78, 0x00,
-	0x10, 0x03, 0x4a, 0x69,
-	0x00, 0x65, 0x2e, 0x41,
+	0x10, 0x03, 0x50, 0x69,
+	0x00, 0x65, 0x34, 0x41,
 	0x1a, 0x01, 0x02, 0x00,
 	0xf0, 0x19, 0x7a, 0x08,
 	0x0f, 0x0f, 0xc8, 0x08,
@@ -112,8 +112,8 @@
 	0x08, 0x1f, 0xda, 0x78,
 	0x80, 0x3d, 0x7a, 0x00,
 	0x20, 0x6a, 0x16, 0x00,
-	0x00, 0x65, 0xbe, 0x41,
-	0x00, 0x65, 0x76, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
+	0x00, 0x65, 0x8a, 0x5e,
 	0x00, 0x65, 0x12, 0x40,
 	0x20, 0x11, 0xe8, 0x68,
 	0x20, 0x6a, 0x18, 0x00,
@@ -125,11 +125,11 @@
 	0x01, 0xb9, 0x1e, 0x30,
 	0x7f, 0xb9, 0x0a, 0x08,
 	0x01, 0xb9, 0x0a, 0x30,
-	0x01, 0x56, 0xca, 0x30,
+	0x01, 0x54, 0xca, 0x30,
 	0x80, 0xb8, 0xfc, 0x78,
 	0x80, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0x00, 0x34,
-	0x01, 0x56, 0x00, 0x34,
+	0x01, 0x54, 0x00, 0x34,
 	0x1a, 0x01, 0x02, 0x00,
 	0x08, 0xb8, 0x06, 0x79,
 	0x20, 0x01, 0x02, 0x00,
@@ -146,40 +146,43 @@
 	0x01, 0xb9, 0x7a, 0x30,
 	0x01, 0xba, 0x7c, 0x30,
 	0x00, 0x65, 0x00, 0x59,
-	0x80, 0x0b, 0xba, 0x79,
-	0xe4, 0x6a, 0x32, 0x5d,
-	0x80, 0xba, 0x48, 0x5d,
+	0x80, 0x0b, 0xc0, 0x79,
+	0xe4, 0x6a, 0x44, 0x5d,
+	0x80, 0xba, 0x5a, 0x5d,
 	0x20, 0xb8, 0x2c, 0x79,
-	0x20, 0x6a, 0x48, 0x5d,
-	0x00, 0xa3, 0x48, 0x5d,
+	0x20, 0x6a, 0x5a, 0x5d,
+	0x00, 0xa3, 0x5a, 0x5d,
 	0x01, 0xa0, 0x78, 0x30,
-	0x10, 0x03, 0x46, 0x69,
-	0x08, 0x3c, 0x62, 0x69,
-	0x04, 0x3c, 0x88, 0x69,
-	0x02, 0x3c, 0x8e, 0x69,
-	0x01, 0x3c, 0x4c, 0x79,
-	0x00, 0x6a, 0x7e, 0x5e,
+	0x10, 0xb8, 0x34, 0x79,
+	0xe4, 0x6a, 0x44, 0x5d,
+	0x00, 0x65, 0xa8, 0x40,
+	0x10, 0x03, 0x4c, 0x69,
+	0x08, 0x3c, 0x68, 0x69,
+	0x04, 0x3c, 0x8e, 0x69,
+	0x02, 0x3c, 0x94, 0x69,
+	0x01, 0x3c, 0x52, 0x79,
 	0x01, 0x6a, 0xa2, 0x30,
-	0x00, 0x65, 0x9a, 0x59,
-	0x04, 0x51, 0x3e, 0x61,
+	0x00, 0x65, 0xa0, 0x59,
+	0x04, 0x51, 0x42, 0x61,
+	0x00, 0x6a, 0x92, 0x5e,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0xda, 0x5d,
+	0x00, 0xbb, 0xec, 0x5d,
 	0x00, 0x65, 0x2c, 0x41,
 	0xa4, 0x6a, 0x06, 0x00,
 	0x00, 0x65, 0x0a, 0x59,
 	0x00, 0x65, 0xa8, 0x40,
-	0xe4, 0x6a, 0x32, 0x5d,
-	0x20, 0x3c, 0x52, 0x79,
-	0x02, 0x6a, 0x48, 0x5d,
-	0x04, 0x6a, 0x48, 0x5d,
-	0x01, 0x03, 0x54, 0x69,
+	0xe4, 0x6a, 0x44, 0x5d,
+	0x20, 0x3c, 0x58, 0x79,
+	0x02, 0x6a, 0x5a, 0x5d,
+	0x04, 0x6a, 0x5a, 0x5d,
+	0x01, 0x03, 0x5a, 0x69,
 	0xf7, 0x11, 0x22, 0x08,
 	0xff, 0x6a, 0x24, 0x08,
 	0xff, 0x6a, 0x06, 0x08,
 	0x01, 0x6a, 0x7e, 0x00,
-	0x00, 0x65, 0x9a, 0x59,
+	0x00, 0x65, 0xa0, 0x59,
 	0x00, 0x65, 0x04, 0x40,
-	0x84, 0x6a, 0x32, 0x5d,
+	0x84, 0x6a, 0x44, 0x5d,
 	0x00, 0x65, 0x0a, 0x59,
 	0x01, 0x66, 0xc8, 0x30,
 	0x01, 0x64, 0xd8, 0x31,
@@ -187,60 +190,60 @@
 	0x5b, 0x64, 0xc8, 0x28,
 	0x30, 0x64, 0xca, 0x18,
 	0x01, 0x6c, 0xc8, 0x30,
-	0xff, 0x64, 0x84, 0x79,
+	0xff, 0x64, 0x8a, 0x79,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x76, 0x79,
-	0x01, 0x64, 0x7c, 0x61,
+	0x02, 0x0b, 0x7c, 0x79,
+	0x01, 0x64, 0x82, 0x61,
 	0xf7, 0x01, 0x02, 0x08,
 	0x01, 0x06, 0xd8, 0x31,
 	0x01, 0x06, 0x32, 0x31,
 	0xff, 0x64, 0xc8, 0x18,
-	0xff, 0x64, 0x76, 0x69,
+	0xff, 0x64, 0x7c, 0x69,
 	0xf7, 0x3c, 0x78, 0x08,
-	0x00, 0x65, 0x2e, 0x41,
+	0x00, 0x65, 0x34, 0x41,
 	0x40, 0xa1, 0x7e, 0x10,
-	0x04, 0xa1, 0x32, 0x5d,
-	0x00, 0x65, 0x62, 0x42,
-	0xc4, 0x6a, 0x32, 0x5d,
+	0x04, 0xa1, 0x44, 0x5d,
+	0x00, 0x65, 0x68, 0x42,
+	0xc4, 0x6a, 0x44, 0x5d,
 	0xc0, 0x6a, 0x7e, 0x00,
-	0x00, 0xa2, 0x48, 0x5d,
+	0x00, 0xa2, 0x5a, 0x5d,
 	0xe4, 0x6a, 0x06, 0x00,
-	0x00, 0x6a, 0x48, 0x5d,
-	0x00, 0x65, 0x54, 0x41,
-	0x10, 0x3c, 0x9e, 0x69,
-	0x00, 0xbb, 0x64, 0x44,
+	0x00, 0x6a, 0x5a, 0x5d,
+	0x00, 0x65, 0x5a, 0x41,
+	0x10, 0x3c, 0xa4, 0x69,
+	0x00, 0xbb, 0x6c, 0x44,
 	0x18, 0x6a, 0xda, 0x01,
 	0x01, 0x69, 0xd8, 0x31,
 	0x1c, 0x6a, 0xd0, 0x01,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xa6, 0x79,
+	0x80, 0xee, 0xac, 0x79,
 	0xff, 0x6a, 0xdc, 0x09,
 	0x01, 0x93, 0x26, 0x01,
 	0x03, 0x6a, 0x2a, 0x01,
 	0x01, 0x69, 0x32, 0x31,
-	0x1c, 0x6a, 0xa8, 0x5d,
+	0x1c, 0x6a, 0xba, 0x5d,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x6c, 0x5e,
+	0x00, 0x65, 0x80, 0x5e,
 	0x01, 0x50, 0xa0, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
 	0x80, 0x6a, 0x74, 0x00,
 	0x80, 0x3c, 0x78, 0x00,
-	0x00, 0x65, 0xa0, 0x5d,
+	0x00, 0x65, 0xb2, 0x5d,
 	0x01, 0x3f, 0xc8, 0x30,
-	0xbf, 0x64, 0x62, 0x7a,
-	0x80, 0x64, 0x82, 0x73,
-	0xa0, 0x64, 0xd8, 0x73,
-	0xc0, 0x64, 0xd0, 0x73,
-	0xe0, 0x64, 0x18, 0x74,
-	0x01, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0xbe, 0x41,
+	0xbf, 0x64, 0x68, 0x7a,
+	0x80, 0x64, 0x96, 0x73,
+	0xa0, 0x64, 0xf0, 0x73,
+	0xc0, 0x64, 0xe6, 0x73,
+	0xe0, 0x64, 0x20, 0x74,
+	0x01, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
 	0xf7, 0x11, 0x22, 0x08,
 	0x01, 0x06, 0xd4, 0x30,
 	0xff, 0x6a, 0x24, 0x08,
 	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0xd8, 0x79,
+	0x09, 0x0c, 0xde, 0x79,
 	0x08, 0x0c, 0x04, 0x68,
-	0xb1, 0x6a, 0x96, 0x5e,
+	0xb1, 0x6a, 0xaa, 0x5e,
 	0xff, 0x6a, 0x26, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0x02, 0x6a, 0x08, 0x30,
@@ -253,47 +256,47 @@
 	0x00, 0xa5, 0x4a, 0x21,
 	0x00, 0xa6, 0x4c, 0x21,
 	0x00, 0xa7, 0x4e, 0x25,
-	0x08, 0xeb, 0x9a, 0x7e,
-	0x80, 0xeb, 0xf8, 0x79,
+	0x08, 0xeb, 0xae, 0x7e,
+	0x80, 0xeb, 0xfe, 0x79,
 	0xff, 0x6a, 0xd6, 0x09,
-	0x08, 0xeb, 0xfc, 0x69,
+	0x08, 0xeb, 0x02, 0x6a,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x88, 0xeb, 0x12, 0x72,
-	0x08, 0xeb, 0x9a, 0x6e,
-	0x80, 0xa3, 0x9a, 0x6e,
-	0x04, 0xea, 0x16, 0xe2,
-	0x08, 0xee, 0x9a, 0x6e,
+	0x80, 0xa3, 0xae, 0x6e,
+	0x88, 0xeb, 0x18, 0x72,
+	0x08, 0xeb, 0xae, 0x6e,
+	0x04, 0xea, 0x1c, 0xe2,
+	0x08, 0xee, 0xae, 0x6e,
 	0x04, 0x6a, 0xd0, 0x81,
 	0x05, 0xa4, 0xc0, 0x89,
 	0x03, 0xa5, 0xc2, 0x31,
 	0x09, 0x6a, 0xd6, 0x05,
-	0x00, 0x65, 0xfa, 0x59,
+	0x00, 0x65, 0x00, 0x5a,
 	0x06, 0xa4, 0xd4, 0x89,
-	0x80, 0x94, 0x9a, 0x7e,
+	0x80, 0x94, 0xae, 0x7e,
 	0x04, 0xe9, 0x10, 0x31,
 	0x01, 0xe9, 0xca, 0x30,
-	0x01, 0x65, 0x20, 0x7a,
-	0x01, 0x57, 0xae, 0x10,
+	0x01, 0x65, 0x26, 0x7a,
+	0x01, 0x55, 0xaa, 0x10,
 	0x01, 0x65, 0x18, 0x31,
 	0x02, 0xe9, 0x1a, 0x31,
 	0x01, 0xe9, 0x46, 0x31,
-	0x00, 0x65, 0xec, 0x59,
+	0x00, 0x65, 0xf2, 0x59,
 	0x01, 0xa4, 0xca, 0x30,
-	0x01, 0x57, 0x2e, 0x7a,
+	0x01, 0x55, 0x34, 0x7a,
 	0x04, 0x65, 0xca, 0x00,
-	0x80, 0xa3, 0x32, 0x7a,
+	0x80, 0xa3, 0x38, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
-	0x01, 0x3b, 0x26, 0x31,
+	0x80, 0x93, 0x26, 0x01,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x01, 0x8c, 0xc8, 0x30,
 	0x00, 0x88, 0xc8, 0x18,
 	0x02, 0x64, 0xc8, 0x88,
-	0xff, 0x64, 0x9a, 0x7e,
-	0xff, 0x8d, 0x48, 0x6a,
-	0xff, 0x8e, 0x48, 0x6a,
+	0xff, 0x64, 0xae, 0x7e,
+	0xff, 0x8d, 0x4e, 0x6a,
+	0xff, 0x8e, 0x4e, 0x6a,
 	0x03, 0x8c, 0xd4, 0x98,
-	0x00, 0x65, 0x9a, 0x56,
+	0x00, 0x65, 0xae, 0x56,
 	0x01, 0x64, 0x70, 0x30,
 	0xff, 0x64, 0xc8, 0x10,
 	0x01, 0x64, 0xc8, 0x18,
@@ -304,139 +307,146 @@
 	0x03, 0xa0, 0x18, 0x31,
 	0x03, 0xa0, 0x10, 0x30,
 	0x08, 0x6a, 0xcc, 0x00,
-	0xa0, 0x6a, 0xbe, 0x5d,
-	0x01, 0xa0, 0xae, 0x08,
-	0x00, 0x65, 0x88, 0x42,
+	0xa0, 0x6a, 0xd0, 0x5d,
+	0x01, 0xa0, 0xaa, 0x08,
+	0x00, 0x65, 0x8e, 0x42,
 	0xa8, 0x6a, 0x76, 0x00,
 	0x79, 0x6a, 0x76, 0x00,
-	0x40, 0x3f, 0x6a, 0x6a,
+	0x40, 0x3f, 0x70, 0x6a,
 	0x04, 0x3b, 0x76, 0x00,
-	0x00, 0x65, 0x52, 0x5d,
+	0x00, 0x65, 0x64, 0x5d,
 	0x04, 0x6a, 0xd4, 0x81,
-	0x20, 0x3c, 0x54, 0x6a,
+	0x20, 0x3c, 0x5a, 0x6a,
 	0x20, 0x3c, 0x78, 0x00,
 	0x07, 0xac, 0x10, 0x31,
 	0x05, 0xb3, 0x46, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xb6, 0x5d,
+	0xac, 0x6a, 0xc8, 0x5d,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0xb3, 0x6a, 0xba, 0x5d,
-	0x00, 0x65, 0x38, 0x5a,
+	0xb3, 0x6a, 0xcc, 0x5d,
+	0x00, 0x65, 0x3e, 0x5a,
 	0xfd, 0xa4, 0x48, 0x09,
-	0x01, 0x8c, 0xae, 0x08,
+	0x01, 0x8c, 0xaa, 0x08,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xae, 0x5d,
-	0x01, 0xa4, 0x98, 0x7a,
+	0x00, 0x65, 0xc0, 0x5d,
+	0x01, 0xa4, 0xa0, 0x7a,
 	0x04, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
 	0x80, 0x02, 0x04, 0x00,
-	0x10, 0x0c, 0x90, 0x7a,
+	0x10, 0x0c, 0x96, 0x7a,
+	0x03, 0x9e, 0x98, 0x6a,
 	0x7f, 0x02, 0x04, 0x08,
-	0x91, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0xbe, 0x41,
+	0x91, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0xc4, 0x41,
 	0x01, 0xa4, 0xca, 0x30,
-	0x80, 0xa3, 0x9e, 0x7a,
+	0x80, 0xa3, 0xa6, 0x7a,
 	0x02, 0x65, 0xca, 0x00,
-	0x01, 0x57, 0xa2, 0x7a,
+	0x01, 0x55, 0xaa, 0x7a,
 	0x04, 0x65, 0xca, 0x00,
 	0x01, 0x65, 0xf8, 0x31,
 	0x01, 0x3b, 0x26, 0x31,
-	0x00, 0x65, 0x00, 0x5a,
-	0x01, 0xfc, 0xae, 0x6a,
-	0x80, 0x0b, 0xa6, 0x6a,
-	0x10, 0x0c, 0xa6, 0x7a,
-	0x04, 0x93, 0xc0, 0x6a,
-	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0xb2, 0x6a,
+	0x00, 0x65, 0x06, 0x5a,
+	0x01, 0xfc, 0xb8, 0x6a,
+	0x80, 0x0b, 0xae, 0x6a,
+	0x10, 0x0c, 0xae, 0x7a,
+	0x20, 0x93, 0xae, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0xb4, 0x7a,
-	0x01, 0x94, 0xb4, 0x7a,
-	0x01, 0x94, 0xb4, 0x7a,
-	0x01, 0x94, 0xb4, 0x7a,
-	0x01, 0x94, 0xb4, 0x7a,
-	0x10, 0x94, 0xc0, 0x6a,
-	0xd7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0xc4, 0x6a,
-	0x02, 0xfc, 0xce, 0x7a,
-	0x01, 0xfc, 0x4e, 0x7b,
+	0x02, 0xfc, 0xc2, 0x7a,
+	0x40, 0x0d, 0xdc, 0x6a,
 	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0x4e, 0x43,
-	0x40, 0x0d, 0xd4, 0x6a,
-	0x00, 0x65, 0x00, 0x5a,
-	0x00, 0x65, 0xc6, 0x42,
-	0x80, 0xfc, 0xde, 0x7a,
-	0x80, 0xa4, 0xde, 0x6a,
+	0x00, 0x65, 0xdc, 0x42,
+	0x40, 0x0d, 0xc8, 0x6a,
+	0x00, 0x65, 0x06, 0x5a,
+	0x00, 0x65, 0xba, 0x42,
+	0x80, 0xfc, 0xd2, 0x7a,
+	0x80, 0xa4, 0xd2, 0x6a,
 	0xff, 0xa5, 0x4a, 0x19,
 	0xff, 0xa6, 0x4c, 0x21,
 	0xff, 0xa7, 0x4e, 0x21,
 	0xf8, 0xfc, 0x48, 0x09,
-	0xff, 0x6a, 0xae, 0x08,
-	0x04, 0xfc, 0xe6, 0x7a,
-	0x01, 0x57, 0xae, 0x00,
+	0xff, 0x6a, 0xaa, 0x08,
+	0x04, 0xfc, 0xda, 0x7a,
+	0x01, 0x55, 0xaa, 0x00,
 	0xff, 0x6a, 0x46, 0x09,
-	0xff, 0x38, 0xf2, 0x6a,
-	0x80, 0xa3, 0xf2, 0x7a,
-	0x80, 0x0b, 0xf0, 0x7a,
-	0x04, 0x3b, 0xf2, 0x7a,
+	0x04, 0x3b, 0xf4, 0x6a,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xde, 0x7a,
+	0x01, 0x94, 0xde, 0x7a,
+	0x01, 0x94, 0xde, 0x7a,
+	0x01, 0x94, 0xde, 0x7a,
+	0x01, 0x94, 0xde, 0x7a,
+	0x01, 0xa4, 0xf2, 0x7a,
+	0x01, 0xfc, 0xec, 0x7a,
+	0x01, 0x94, 0xf4, 0x6a,
+	0x00, 0x65, 0x8e, 0x42,
+	0x01, 0x94, 0xf2, 0x7a,
+	0x10, 0x94, 0xf4, 0x6a,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xf8, 0x6a,
+	0xff, 0x38, 0x04, 0x6b,
+	0x80, 0xa3, 0x04, 0x7b,
+	0x80, 0x0b, 0x02, 0x7b,
+	0x04, 0x3b, 0x04, 0x7b,
 	0xbf, 0x3b, 0x76, 0x08,
 	0x01, 0x3b, 0x26, 0x31,
-	0x00, 0x65, 0x00, 0x5a,
-	0x01, 0x0b, 0x00, 0x6b,
-	0x10, 0x0c, 0xf4, 0x7a,
-	0x04, 0x93, 0xfe, 0x6a,
-	0x01, 0x94, 0xfc, 0x7a,
-	0x10, 0x94, 0xfe, 0x6a,
+	0x00, 0x65, 0x06, 0x5a,
+	0x01, 0x0b, 0x12, 0x6b,
+	0x10, 0x0c, 0x06, 0x7b,
+	0x04, 0x93, 0x10, 0x6b,
+	0x01, 0x94, 0x0e, 0x7b,
+	0x10, 0x94, 0x10, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
 	0x01, 0x99, 0xd4, 0x30,
-	0x38, 0x93, 0x02, 0x6b,
-	0xff, 0x08, 0x4e, 0x6b,
-	0xff, 0x09, 0x4e, 0x6b,
-	0xff, 0x0a, 0x4e, 0x6b,
-	0xff, 0x38, 0x1e, 0x7b,
+	0x38, 0x93, 0x14, 0x6b,
+	0xff, 0x08, 0x60, 0x6b,
+	0xff, 0x09, 0x60, 0x6b,
+	0xff, 0x0a, 0x60, 0x6b,
+	0xff, 0x38, 0x30, 0x7b,
 	0x04, 0x14, 0x10, 0x31,
 	0x01, 0x38, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xbc, 0x5d,
-	0x00, 0x38, 0xa8, 0x5d,
+	0x14, 0x6a, 0xce, 0x5d,
+	0x00, 0x38, 0xba, 0x5d,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x44, 0x43,
-	0x80, 0xa3, 0x24, 0x7b,
+	0x00, 0x65, 0x56, 0x43,
+	0x80, 0xa3, 0x36, 0x7b,
 	0x01, 0xa4, 0x48, 0x01,
-	0x00, 0x65, 0x4e, 0x43,
-	0x08, 0xeb, 0x2a, 0x7b,
-	0x00, 0x65, 0x00, 0x5a,
-	0x08, 0xeb, 0x26, 0x6b,
+	0x00, 0x65, 0x60, 0x43,
+	0x08, 0xeb, 0x3c, 0x7b,
+	0x00, 0x65, 0x06, 0x5a,
+	0x08, 0xeb, 0x38, 0x6b,
 	0x07, 0xe9, 0x10, 0x31,
-	0x80, 0xe9, 0x30, 0x7b,
+	0x80, 0xe9, 0x42, 0x7b,
 	0x80, 0xa3, 0x46, 0x01,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa4, 0x6a, 0xbc, 0x5d,
-	0x08, 0x6a, 0xa8, 0x5d,
+	0xa4, 0x6a, 0xce, 0x5d,
+	0x08, 0x6a, 0xba, 0x5d,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x6c, 0x5e,
+	0x00, 0x65, 0x80, 0x5e,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x00, 0x65, 0x4e, 0x5e,
+	0x00, 0x65, 0x62, 0x5e,
 	0x01, 0x99, 0x46, 0x31,
-	0x00, 0x65, 0x38, 0x5a,
-	0x00, 0x65, 0xec, 0x59,
+	0x00, 0x65, 0x3e, 0x5a,
+	0x00, 0x65, 0xf2, 0x59,
 	0x03, 0x8c, 0x10, 0x30,
-	0x00, 0x65, 0xae, 0x5d,
-	0x01, 0x8c, 0x4c, 0x7b,
-	0x01, 0x57, 0xae, 0x10,
-	0x80, 0x0b, 0x88, 0x6a,
-	0x80, 0x0b, 0x54, 0x6b,
-	0x01, 0x0c, 0x50, 0x7b,
-	0x10, 0x0c, 0x88, 0x7a,
-	0x00, 0x65, 0xf6, 0x59,
-	0xff, 0x38, 0x66, 0x7b,
+	0x00, 0x65, 0xc0, 0x5d,
+	0x01, 0x8c, 0x5e, 0x7b,
+	0x01, 0x55, 0xaa, 0x10,
+	0x80, 0x0b, 0x8e, 0x6a,
+	0x80, 0x0b, 0x68, 0x6b,
+	0x01, 0x0c, 0x62, 0x7b,
+	0x10, 0x0c, 0x8e, 0x7a,
+	0x03, 0x9e, 0x8e, 0x6a,
+	0x00, 0x65, 0xfc, 0x59,
+	0xff, 0x38, 0x7a, 0x7b,
 	0x01, 0x38, 0xc8, 0x30,
 	0x00, 0x08, 0x40, 0x19,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x00, 0x09, 0x42, 0x21,
 	0x00, 0x0a, 0x44, 0x21,
 	0xff, 0x6a, 0x70, 0x08,
-	0x00, 0x65, 0x68, 0x43,
+	0x00, 0x65, 0x7c, 0x43,
 	0x03, 0x08, 0x40, 0x31,
 	0x03, 0x08, 0x40, 0x31,
 	0x01, 0x08, 0x40, 0x31,
@@ -445,13 +455,13 @@
 	0xfd, 0xb4, 0x68, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0x12, 0x01, 0x02, 0x00,
-	0x04, 0x3c, 0xbe, 0x79,
+	0x04, 0x3c, 0xc4, 0x79,
 	0xfb, 0x3c, 0x78, 0x08,
-	0x04, 0x93, 0x2e, 0x79,
-	0x01, 0x0c, 0x7c, 0x6b,
-	0x00, 0x65, 0x2e, 0x41,
-	0x00, 0x65, 0xbe, 0x41,
-	0x00, 0x65, 0x52, 0x5d,
+	0x04, 0x93, 0x34, 0x79,
+	0x01, 0x0c, 0x90, 0x6b,
+	0x00, 0x65, 0x34, 0x41,
+	0x00, 0x65, 0xc4, 0x41,
+	0x00, 0x65, 0x64, 0x5d,
 	0x01, 0xbc, 0x18, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x02, 0x6a, 0xf8, 0x01,
@@ -461,16 +471,16 @@
 	0xff, 0x6a, 0x12, 0x08,
 	0xff, 0x6a, 0x14, 0x08,
 	0xf3, 0xbc, 0xd4, 0x18,
-	0xa0, 0x6a, 0xaa, 0x53,
+	0xa0, 0x6a, 0xbe, 0x53,
 	0x04, 0xa0, 0x10, 0x31,
 	0xac, 0x6a, 0x26, 0x01,
 	0x04, 0xa0, 0x10, 0x31,
 	0x03, 0x08, 0x18, 0x31,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xa0, 0x6a, 0xbc, 0x5d,
-	0x00, 0xbc, 0xa8, 0x5d,
+	0xa0, 0x6a, 0xce, 0x5d,
+	0x00, 0xbc, 0xba, 0x5d,
 	0x3d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xc2, 0x43,
+	0x00, 0x65, 0xd6, 0x43,
 	0xff, 0x6a, 0x10, 0x09,
 	0xa4, 0x6a, 0x26, 0x01,
 	0x0c, 0xa0, 0x32, 0x31,
@@ -480,114 +490,112 @@
 	0x36, 0x6a, 0x26, 0x01,
 	0x02, 0x93, 0x26, 0x01,
 	0x35, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x60, 0x5e,
-	0x00, 0x65, 0x60, 0x5e,
+	0x00, 0x65, 0x74, 0x5e,
+	0x00, 0x65, 0x74, 0x5e,
 	0x02, 0x93, 0x26, 0x01,
-	0x04, 0x0b, 0xc6, 0x6b,
-	0x10, 0x0c, 0xc2, 0x7b,
-	0x01, 0x03, 0xc6, 0x6b,
+	0x04, 0x0b, 0xda, 0x6b,
+	0x10, 0x0c, 0xd6, 0x7b,
+	0x01, 0x03, 0xda, 0x6b,
+	0x20, 0x93, 0xd6, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
-	0x38, 0x93, 0xca, 0x6b,
+	0x38, 0x93, 0xe0, 0x6b,
 	0x10, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0xbe, 0x41,
-	0x00, 0x65, 0x52, 0x5d,
+	0x00, 0x65, 0xc4, 0x41,
+	0x00, 0x65, 0x64, 0x5d,
 	0x01, 0x06, 0x50, 0x31,
-	0x00, 0x65, 0xbe, 0x41,
+	0x00, 0x65, 0xc4, 0x41,
 	0x10, 0x3f, 0x06, 0x00,
+	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x3a, 0xca, 0x30,
-	0x80, 0x65, 0x04, 0x64,
-	0x10, 0xb8, 0x28, 0x6c,
-	0x01, 0xb9, 0xdc, 0x30,
-	0x01, 0x6e, 0xc8, 0x30,
-	0x01, 0x54, 0xca, 0x30,
-	0x80, 0xb9, 0xe8, 0x7b,
-	0x01, 0x55, 0xca, 0x30,
-	0x80, 0xb9, 0xec, 0x7b,
-	0x01, 0x55, 0xca, 0x30,
-	0x00, 0x65, 0x28, 0x6c,
+	0x80, 0x65, 0x0c, 0x64,
+	0x10, 0xb8, 0x30, 0x6c,
 	0xc0, 0xba, 0xca, 0x00,
-	0x40, 0xb8, 0xf4, 0x6b,
+	0x40, 0xb8, 0xfc, 0x6b,
 	0xbf, 0x65, 0xca, 0x08,
-	0x20, 0xb8, 0x08, 0x7c,
+	0x20, 0xb8, 0x10, 0x7c,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xa0, 0x5d,
-	0xa0, 0x3f, 0x10, 0x64,
+	0x00, 0x65, 0xb2, 0x5d,
+	0xa0, 0x3f, 0x18, 0x64,
 	0x23, 0xb8, 0x0c, 0x08,
-	0x00, 0x65, 0xa0, 0x5d,
-	0xa0, 0x3f, 0x10, 0x64,
-	0x00, 0xbb, 0x08, 0x44,
-	0xff, 0x65, 0x08, 0x64,
-	0x00, 0x65, 0x28, 0x44,
+	0x00, 0x65, 0xb2, 0x5d,
+	0xa0, 0x3f, 0x18, 0x64,
+	0x00, 0xbb, 0x10, 0x44,
+	0xff, 0x65, 0x10, 0x64,
+	0x00, 0x65, 0x30, 0x44,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x65, 0x0c, 0x30,
-	0x00, 0x65, 0xa0, 0x5d,
-	0xa0, 0x3f, 0xd6, 0x73,
+	0x00, 0x65, 0xb2, 0x5d,
+	0xa0, 0x3f, 0xec, 0x73,
 	0x40, 0x6a, 0x18, 0x00,
 	0x01, 0x3a, 0xa6, 0x30,
 	0x08, 0x6a, 0x74, 0x00,
-	0x00, 0x65, 0xbe, 0x41,
-	0x64, 0x6a, 0x2c, 0x5d,
-	0x80, 0x64, 0x9e, 0x6c,
-	0x04, 0x64, 0x74, 0x74,
-	0x02, 0x64, 0x82, 0x74,
-	0x00, 0x6a, 0x44, 0x74,
-	0x03, 0x64, 0x90, 0x74,
-	0x23, 0x64, 0x30, 0x74,
-	0x08, 0x64, 0x40, 0x74,
-	0x61, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0xa0, 0x5d,
-	0x08, 0x51, 0xc0, 0x71,
-	0x00, 0x65, 0x28, 0x44,
-	0x80, 0x04, 0x3e, 0x7c,
-	0x51, 0x6a, 0x22, 0x5d,
-	0x01, 0x51, 0x3e, 0x64,
-	0x01, 0xa4, 0x3a, 0x7c,
-	0x01, 0x57, 0x40, 0x7c,
-	0x41, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0x40, 0x44,
-	0x07, 0x6a, 0x1a, 0x5d,
+	0x00, 0x65, 0xc4, 0x41,
+	0x64, 0x6a, 0x3e, 0x5d,
+	0x80, 0x64, 0xae, 0x6c,
+	0x04, 0x64, 0x7c, 0x74,
+	0x02, 0x64, 0x8a, 0x74,
+	0x00, 0x6a, 0x4c, 0x74,
+	0x03, 0x64, 0xa0, 0x74,
+	0x23, 0x64, 0x38, 0x74,
+	0x08, 0x64, 0x48, 0x74,
+	0x61, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0xb2, 0x5d,
+	0x08, 0x51, 0xc6, 0x71,
+	0x00, 0x65, 0x30, 0x44,
+	0x80, 0x04, 0x46, 0x7c,
+	0x51, 0x6a, 0x34, 0x5d,
+	0x01, 0x51, 0x46, 0x64,
+	0x01, 0xa4, 0x42, 0x7c,
+	0x01, 0x55, 0x48, 0x7c,
+	0x41, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0x48, 0x44,
+	0x07, 0x6a, 0x2a, 0x5d,
 	0x01, 0x06, 0xd4, 0x30,
-	0x00, 0x65, 0xbe, 0x41,
-	0x10, 0xb8, 0x48, 0x7c,
-	0xa1, 0x6a, 0x96, 0x5e,
-	0x01, 0xb4, 0x4e, 0x6c,
-	0x02, 0xb4, 0x50, 0x6c,
-	0x01, 0xa4, 0x50, 0x7c,
-	0xff, 0xa8, 0x60, 0x7c,
+	0x00, 0x65, 0xc4, 0x41,
+	0x10, 0xb8, 0x50, 0x7c,
+	0xa1, 0x6a, 0xaa, 0x5e,
+	0x01, 0xb4, 0x56, 0x6c,
+	0x02, 0xb4, 0x58, 0x6c,
+	0x01, 0xa4, 0x58, 0x7c,
+	0xff, 0xa8, 0x68, 0x7c,
 	0x04, 0xb4, 0x68, 0x01,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0xda, 0x5d,
-	0xff, 0xa8, 0x60, 0x7c,
-	0x71, 0x6a, 0x96, 0x5e,
-	0x40, 0x51, 0x60, 0x64,
-	0x00, 0x65, 0x76, 0x5e,
-	0x00, 0x65, 0xd0, 0x41,
-	0x00, 0xbb, 0x64, 0x5c,
-	0x00, 0x65, 0xd0, 0x41,
-	0x00, 0x65, 0x76, 0x5e,
+	0x00, 0xbb, 0xec, 0x5d,
+	0xff, 0xa8, 0x68, 0x7c,
+	0x71, 0x6a, 0xaa, 0x5e,
+	0x40, 0x51, 0x68, 0x64,
+	0x00, 0x65, 0x8a, 0x5e,
+	0x00, 0x65, 0xd6, 0x41,
+	0x00, 0xbb, 0x6c, 0x5c,
+	0x00, 0x65, 0xd6, 0x41,
+	0x00, 0x65, 0x8a, 0x5e,
 	0x01, 0x65, 0xa2, 0x30,
 	0x01, 0xf8, 0xc8, 0x30,
 	0x01, 0x4e, 0xc8, 0x30,
-	0x00, 0x6a, 0x7e, 0xdd,
-	0x00, 0x51, 0x90, 0x5d,
+	0x00, 0x6a, 0x90, 0xdd,
+	0x00, 0x51, 0xa2, 0x5d,
 	0x01, 0x4e, 0x9c, 0x18,
 	0x02, 0x6a, 0x22, 0x05,
 	0x04, 0xb8, 0x70, 0x01,
-	0x00, 0x65, 0x92, 0x5e,
-	0x20, 0xb8, 0xd0, 0x69,
+	0x00, 0x65, 0xa6, 0x5e,
+	0x20, 0xb8, 0xd6, 0x69,
 	0x01, 0xbb, 0xa2, 0x30,
 	0x01, 0xba, 0x7c, 0x30,
-	0x00, 0xb9, 0x94, 0x5c,
-	0x00, 0x65, 0xd0, 0x41,
-	0x20, 0x3c, 0x40, 0x7c,
+	0x00, 0xb9, 0xa4, 0x5c,
+	0x00, 0x65, 0xd6, 0x41,
+	0x01, 0x06, 0xd4, 0x30,
+	0x20, 0x3c, 0xc4, 0x79,
+	0x20, 0x3c, 0x48, 0x7c,
 	0x04, 0x14, 0x58, 0x31,
+	0x01, 0x06, 0xd4, 0x30,
 	0x08, 0xa0, 0x60, 0x31,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xbc, 0x5d,
-	0xa0, 0x6a, 0xb4, 0x5d,
-	0x00, 0x65, 0x40, 0x44,
+	0x14, 0x6a, 0xce, 0x5d,
+	0x01, 0x06, 0xd4, 0x30,
+	0xa0, 0x6a, 0xc6, 0x5d,
+	0x00, 0x65, 0xc4, 0x41,
 	0xdf, 0x3c, 0x78, 0x08,
-	0x00, 0x65, 0x40, 0x44,
+	0x00, 0x65, 0x48, 0x44,
 	0x4c, 0x65, 0xcc, 0x28,
 	0x01, 0x3e, 0x20, 0x31,
 	0xd0, 0x66, 0xcc, 0x18,
@@ -598,103 +606,104 @@
 	0xd0, 0x65, 0xca, 0x18,
 	0x01, 0x3e, 0x20, 0x31,
 	0x30, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xac, 0x4c,
+	0x00, 0x65, 0xbc, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xb4, 0x54,
+	0x00, 0x65, 0xc4, 0x54,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x20, 0x65, 0xca, 0x18,
 	0xe0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xbe, 0x4c,
+	0x00, 0x65, 0xce, 0x4c,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xd0, 0x65, 0xd4, 0x18,
-	0x00, 0x65, 0xc6, 0x54,
+	0x00, 0x65, 0xd6, 0x54,
 	0xe1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
 	0x01, 0x6c, 0xa2, 0x30,
-	0xff, 0x51, 0xd8, 0x74,
-	0x00, 0x51, 0x56, 0x5d,
+	0xff, 0x51, 0xe8, 0x74,
+	0x00, 0x51, 0x68, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
-	0x00, 0x65, 0xfa, 0x44,
+	0x00, 0x65, 0x0a, 0x45,
 	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0xfa, 0x74,
-	0x00, 0x65, 0x74, 0x5e,
+	0x00, 0x3e, 0x0a, 0x75,
+	0x00, 0x65, 0x88, 0x5e,
 	0x80, 0x3c, 0x78, 0x00,
 	0x01, 0x06, 0xd4, 0x30,
-	0x00, 0x65, 0xa0, 0x5d,
+	0x00, 0x65, 0xb2, 0x5d,
 	0x01, 0x3c, 0x78, 0x00,
-	0xe0, 0x3f, 0x16, 0x65,
+	0xe0, 0x3f, 0x26, 0x65,
 	0x02, 0x3c, 0x78, 0x00,
-	0x20, 0x12, 0x16, 0x65,
-	0x51, 0x6a, 0x22, 0x5d,
-	0x00, 0x51, 0x56, 0x5d,
-	0x51, 0x6a, 0x22, 0x5d,
+	0x20, 0x12, 0x26, 0x65,
+	0x51, 0x6a, 0x34, 0x5d,
+	0x00, 0x51, 0x68, 0x5d,
+	0x51, 0x6a, 0x34, 0x5d,
 	0x01, 0x51, 0x20, 0x31,
 	0x04, 0x3c, 0x78, 0x00,
 	0x01, 0xb9, 0xc8, 0x30,
-	0x00, 0x3d, 0x14, 0x65,
+	0x00, 0x3d, 0x24, 0x65,
 	0x08, 0x3c, 0x78, 0x00,
 	0x01, 0xba, 0xc8, 0x30,
-	0x00, 0x3e, 0x14, 0x65,
+	0x00, 0x3e, 0x24, 0x65,
 	0x10, 0x3c, 0x78, 0x00,
-	0x04, 0xb8, 0x14, 0x7d,
+	0x04, 0xb8, 0x24, 0x7d,
 	0xfb, 0xb8, 0x70, 0x09,
-	0x20, 0xb8, 0x0a, 0x6d,
+	0x20, 0xb8, 0x1a, 0x6d,
 	0x01, 0x90, 0xc8, 0x30,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3d, 0x94, 0x5c,
+	0x00, 0x3d, 0xa4, 0x5c,
 	0x01, 0x64, 0x20, 0x31,
 	0x80, 0x6a, 0x78, 0x00,
 	0x00, 0x65, 0x02, 0x59,
-	0x10, 0xb8, 0x40, 0x7c,
-	0xff, 0x6a, 0x1a, 0x5d,
-	0x00, 0x65, 0x40, 0x44,
-	0x00, 0x65, 0x74, 0x5e,
-	0x31, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0x40, 0x44,
+	0x10, 0xb8, 0x48, 0x7c,
+	0xff, 0x6a, 0x2a, 0x5d,
+	0x00, 0x65, 0x48, 0x44,
+	0x00, 0x65, 0x88, 0x5e,
+	0x31, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0x48, 0x44,
 	0x10, 0x3f, 0x06, 0x00,
+	0x10, 0x6a, 0x06, 0x00,
 	0x01, 0x65, 0x74, 0x34,
-	0x81, 0x6a, 0x96, 0x5e,
-	0x00, 0x65, 0x24, 0x45,
+	0x81, 0x6a, 0xaa, 0x5e,
+	0x00, 0x65, 0x36, 0x45,
 	0x01, 0x06, 0xd4, 0x30,
-	0x01, 0x0c, 0x24, 0x7d,
-	0x04, 0x0c, 0x1e, 0x6d,
+	0x01, 0x0c, 0x36, 0x7d,
+	0x04, 0x0c, 0x30, 0x6d,
 	0xe0, 0x03, 0x7e, 0x08,
-	0xe0, 0x3f, 0xbe, 0x61,
+	0xe0, 0x3f, 0xc4, 0x61,
 	0x01, 0x65, 0xcc, 0x30,
 	0x01, 0x12, 0xda, 0x34,
 	0x01, 0x06, 0xd4, 0x34,
-	0x01, 0x03, 0x32, 0x6d,
+	0x01, 0x03, 0x44, 0x6d,
 	0x40, 0x03, 0xcc, 0x08,
 	0x01, 0x65, 0x06, 0x30,
 	0x40, 0x65, 0xc8, 0x08,
-	0x00, 0x66, 0x40, 0x75,
-	0x40, 0x65, 0x40, 0x7d,
-	0x00, 0x65, 0x40, 0x5d,
+	0x00, 0x66, 0x52, 0x75,
+	0x40, 0x65, 0x52, 0x7d,
+	0x00, 0x65, 0x52, 0x5d,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x08,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x4a, 0x7d,
+	0x02, 0x0b, 0x5c, 0x7d,
 	0x01, 0x65, 0x0c, 0x30,
-	0x02, 0x0b, 0x4e, 0x7d,
+	0x02, 0x0b, 0x60, 0x7d,
 	0xf7, 0x01, 0x02, 0x0c,
-	0x80, 0x3c, 0x9a, 0x6e,
-	0x21, 0x6a, 0x96, 0x46,
+	0x80, 0x3c, 0xae, 0x6e,
+	0x21, 0x6a, 0xaa, 0x46,
 	0x01, 0x65, 0xc8, 0x30,
-	0xff, 0x41, 0x76, 0x75,
+	0xff, 0x41, 0x88, 0x75,
 	0x01, 0x41, 0x20, 0x31,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x66, 0x45,
-	0xff, 0xbf, 0x76, 0x75,
+	0x00, 0x65, 0x78, 0x45,
+	0xff, 0xbf, 0x88, 0x75,
 	0x01, 0x90, 0xa4, 0x30,
 	0x01, 0xbf, 0x20, 0x31,
-	0x00, 0xbb, 0x60, 0x65,
-	0xff, 0x52, 0x74, 0x75,
+	0x00, 0xbb, 0x72, 0x65,
+	0xff, 0x52, 0x86, 0x75,
 	0x01, 0xbf, 0xcc, 0x30,
 	0x01, 0x90, 0xca, 0x30,
 	0x01, 0x52, 0x20, 0x31,
@@ -702,28 +711,28 @@
 	0x01, 0x65, 0x20, 0x35,
 	0x01, 0xbf, 0x82, 0x34,
 	0x01, 0x64, 0xa2, 0x30,
-	0x00, 0x6a, 0x7e, 0x5e,
+	0x00, 0x6a, 0x92, 0x5e,
 	0x0d, 0x6a, 0x76, 0x00,
-	0x00, 0x51, 0xda, 0x45,
+	0x00, 0x51, 0xec, 0x45,
 	0x01, 0x65, 0xa4, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xce, 0x5d,
+	0x48, 0x6a, 0xe0, 0x5d,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x48, 0x6a, 0xce, 0x5d,
-	0x01, 0x6a, 0xa8, 0x5d,
+	0x48, 0x6a, 0xe0, 0x5d,
+	0x01, 0x6a, 0xba, 0x5d,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x94, 0x7d,
+	0x80, 0xee, 0xa6, 0x7d,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0x01, 0x65, 0x32, 0x31,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x6c, 0x46,
-	0x81, 0x6a, 0x96, 0x5e,
-	0x01, 0x0c, 0xa0, 0x7d,
-	0x04, 0x0c, 0x9e, 0x6d,
+	0x00, 0x65, 0x80, 0x46,
+	0x81, 0x6a, 0xaa, 0x5e,
+	0x01, 0x0c, 0xb2, 0x7d,
+	0x04, 0x0c, 0xb0, 0x6d,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7e, 0x0c,
 	0x01, 0x65, 0x18, 0x31,
@@ -742,7 +751,7 @@
 	0x01, 0x6c, 0xda, 0x34,
 	0x3d, 0x64, 0xa4, 0x28,
 	0x55, 0x64, 0xc8, 0x28,
-	0x00, 0x65, 0xce, 0x45,
+	0x00, 0x65, 0xe0, 0x45,
 	0x2e, 0x64, 0xa4, 0x28,
 	0x66, 0x64, 0xc8, 0x28,
 	0x00, 0x6c, 0xda, 0x18,
@@ -753,61 +762,62 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0x01, 0x65, 0xc8, 0x30,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0xca, 0x5d,
+	0x44, 0x6a, 0xdc, 0x5d,
 	0x01, 0x90, 0xe2, 0x31,
-	0x04, 0x3b, 0xee, 0x7d,
+	0x04, 0x3b, 0x00, 0x7e,
 	0x30, 0x6a, 0xd0, 0x01,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0xea, 0x65,
-	0x00, 0x65, 0x06, 0x46,
+	0xdc, 0xee, 0xfc, 0x65,
+	0x00, 0x65, 0x18, 0x46,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xf6, 0x7d,
+	0x80, 0xee, 0x08, 0x7e,
 	0x11, 0x6a, 0xdc, 0x01,
-	0x50, 0xee, 0xfa, 0x65,
+	0x50, 0xee, 0x0c, 0x66,
 	0x20, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xdc, 0x01,
-	0x88, 0xee, 0x00, 0x66,
+	0x88, 0xee, 0x12, 0x66,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x04, 0x66,
+	0xd8, 0xee, 0x16, 0x66,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x08, 0x6e,
+	0x18, 0xee, 0x1a, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x44, 0x6a, 0xca, 0x5d,
-	0x20, 0x6a, 0xa8, 0x5d,
+	0x44, 0x6a, 0xdc, 0x5d,
+	0x20, 0x6a, 0xba, 0x5d,
 	0x01, 0x3b, 0x26, 0x31,
-	0x04, 0x3b, 0x22, 0x6e,
+	0x04, 0x3b, 0x34, 0x6e,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0x5c, 0x5e,
-	0x00, 0x65, 0x1a, 0x66,
+	0x00, 0x65, 0x70, 0x5e,
+	0x00, 0x65, 0x2c, 0x66,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x6c, 0x46,
+	0x00, 0x65, 0x80, 0x46,
 	0xa0, 0x6a, 0xcc, 0x00,
 	0xff, 0x6a, 0xc8, 0x08,
-	0x01, 0x94, 0x26, 0x6e,
-	0x10, 0x94, 0x28, 0x6e,
-	0x08, 0x94, 0x3e, 0x6e,
-	0x08, 0x94, 0x3e, 0x6e,
-	0x08, 0x94, 0x3e, 0x6e,
+	0x20, 0x94, 0x38, 0x6e,
+	0x10, 0x94, 0x3a, 0x6e,
+	0x08, 0x94, 0x52, 0x6e,
+	0x08, 0x94, 0x52, 0x6e,
+	0x08, 0x94, 0x52, 0x6e,
 	0x07, 0x8c, 0xca, 0x18,
 	0x3d, 0x65, 0xca, 0x28,
 	0x00, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0x42, 0x5e,
+	0x00, 0x65, 0x56, 0x5e,
 	0xff, 0x65, 0xca, 0x10,
 	0x05, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0x26, 0x46,
+	0x04, 0x64, 0x82, 0x76,
+	0x00, 0x65, 0x38, 0x46,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x40, 0x6e,
+	0x08, 0x93, 0x54, 0x6e,
 	0x00, 0x62, 0xc4, 0x18,
-	0x00, 0x65, 0x6c, 0x5e,
-	0x00, 0x65, 0x4c, 0x5e,
-	0x00, 0x65, 0x4c, 0x5e,
-	0x00, 0x65, 0x4c, 0x5e,
+	0x00, 0x65, 0x80, 0x5e,
+	0x00, 0x65, 0x60, 0x5e,
+	0x00, 0x65, 0x60, 0x5e,
+	0x00, 0x65, 0x60, 0x5e,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
 	0x01, 0x99, 0xda, 0x30,
@@ -824,23 +834,23 @@
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x31,
 	0x01, 0x6c, 0x32, 0x35,
-	0x08, 0x94, 0x6c, 0x7e,
+	0x08, 0x94, 0x80, 0x7e,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x70, 0x6e,
+	0x08, 0x93, 0x84, 0x6e,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x04, 0xb8, 0x92, 0x6e,
+	0x04, 0xb8, 0xa6, 0x6e,
 	0x01, 0x42, 0x7e, 0x31,
 	0xff, 0x6a, 0x76, 0x01,
 	0x01, 0x90, 0x84, 0x34,
 	0xff, 0x6a, 0x76, 0x05,
-	0xff, 0x42, 0x8e, 0x66,
-	0xff, 0x41, 0x86, 0x66,
-	0xd1, 0x6a, 0x96, 0x5e,
+	0xff, 0x42, 0xa2, 0x66,
+	0xff, 0x41, 0x9a, 0x66,
+	0xd1, 0x6a, 0xaa, 0x5e,
 	0xff, 0x6a, 0xca, 0x04,
 	0x01, 0x41, 0x20, 0x31,
 	0x01, 0xbf, 0x82, 0x30,
 	0x01, 0x6a, 0x76, 0x00,
-	0x00, 0xbb, 0xda, 0x45,
+	0x00, 0xbb, 0xec, 0x45,
 	0x01, 0x42, 0x20, 0x31,
 	0x01, 0xbf, 0x84, 0x34,
 	0x01, 0x41, 0x7e, 0x31,
@@ -919,7 +929,7 @@
 static int
 ahc_patch14_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_DT) == 0);
+	return ((ahc->features & AHC_ULTRA2) == 0);
 }
 
 static int ahc_patch13_func(struct ahc_softc *ahc);
@@ -927,7 +937,7 @@
 static int
 ahc_patch13_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_ULTRA2) == 0);
+	return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0);
 }
 
 static int ahc_patch12_func(struct ahc_softc *ahc);
@@ -935,7 +945,7 @@
 static int
 ahc_patch12_func(struct ahc_softc *ahc)
 {
-	return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0);
+	return ((ahc->features & AHC_ULTRA) != 0);
 }
 
 static int ahc_patch11_func(struct ahc_softc *ahc);
@@ -943,7 +953,7 @@
 static int
 ahc_patch11_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_ULTRA) != 0);
+	return ((ahc->features & AHC_HS_MAILBOX) != 0);
 }
 
 static int ahc_patch10_func(struct ahc_softc *ahc);
@@ -951,7 +961,7 @@
 static int
 ahc_patch10_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_HS_MAILBOX) != 0);
+	return ((ahc->features & AHC_MULTI_TID) != 0);
 }
 
 static int ahc_patch9_func(struct ahc_softc *ahc);
@@ -959,7 +969,7 @@
 static int
 ahc_patch9_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_MULTI_TID) != 0);
+	return ((ahc->features & AHC_CMD_CHAN) != 0);
 }
 
 static int ahc_patch8_func(struct ahc_softc *ahc);
@@ -967,7 +977,7 @@
 static int
 ahc_patch8_func(struct ahc_softc *ahc)
 {
-	return ((ahc->features & AHC_CMD_CHAN) != 0);
+	return ((ahc->flags & AHC_INITIATORROLE) != 0);
 }
 
 static int ahc_patch7_func(struct ahc_softc *ahc);
@@ -975,7 +985,7 @@
 static int
 ahc_patch7_func(struct ahc_softc *ahc)
 {
-	return ((ahc->flags & AHC_INITIATORROLE) != 0);
+	return ((ahc->flags & AHC_TARGETROLE) != 0);
 }
 
 static int ahc_patch6_func(struct ahc_softc *ahc);
@@ -983,7 +993,7 @@
 static int
 ahc_patch6_func(struct ahc_softc *ahc)
 {
-	return ((ahc->flags & AHC_TARGETROLE) != 0);
+	return ((ahc->features & AHC_DT) == 0);
 }
 
 static int ahc_patch5_func(struct ahc_softc *ahc);
@@ -1051,28 +1061,29 @@
 	{ ahc_patch5_func, 22, 2, 1 },
 	{ ahc_patch3_func, 27, 1, 2 },
 	{ ahc_patch0_func, 28, 1, 1 },
-	{ ahc_patch6_func, 37, 65, 21 },
-	{ ahc_patch7_func, 37, 1, 1 },
-	{ ahc_patch8_func, 45, 3, 2 },
+	{ ahc_patch6_func, 34, 1, 1 },
+	{ ahc_patch7_func, 37, 65, 21 },
+	{ ahc_patch8_func, 37, 1, 1 },
+	{ ahc_patch9_func, 45, 3, 2 },
 	{ ahc_patch0_func, 48, 3, 1 },
-	{ ahc_patch9_func, 52, 1, 2 },
+	{ ahc_patch10_func, 52, 1, 2 },
 	{ ahc_patch0_func, 53, 2, 3 },
 	{ ahc_patch1_func, 53, 1, 2 },
 	{ ahc_patch0_func, 54, 1, 1 },
 	{ ahc_patch2_func, 56, 2, 1 },
-	{ ahc_patch8_func, 58, 1, 2 },
+	{ ahc_patch9_func, 58, 1, 2 },
 	{ ahc_patch0_func, 59, 1, 1 },
-	{ ahc_patch8_func, 63, 1, 2 },
+	{ ahc_patch9_func, 63, 1, 2 },
 	{ ahc_patch0_func, 64, 1, 1 },
-	{ ahc_patch8_func, 73, 1, 2 },
+	{ ahc_patch9_func, 73, 1, 2 },
 	{ ahc_patch0_func, 74, 1, 1 },
-	{ ahc_patch8_func, 77, 1, 2 },
+	{ ahc_patch9_func, 77, 1, 2 },
 	{ ahc_patch0_func, 78, 1, 1 },
-	{ ahc_patch10_func, 88, 1, 2 },
+	{ ahc_patch11_func, 88, 1, 2 },
 	{ ahc_patch0_func, 89, 1, 1 },
-	{ ahc_patch8_func, 97, 1, 2 },
+	{ ahc_patch9_func, 97, 1, 2 },
 	{ ahc_patch0_func, 98, 1, 1 },
-	{ ahc_patch7_func, 102, 9, 4 },
+	{ ahc_patch8_func, 102, 9, 4 },
 	{ ahc_patch1_func, 104, 1, 2 },
 	{ ahc_patch0_func, 105, 1, 1 },
 	{ ahc_patch2_func, 107, 2, 1 },
@@ -1081,147 +1092,162 @@
 	{ ahc_patch0_func, 121, 2, 3 },
 	{ ahc_patch2_func, 121, 1, 2 },
 	{ ahc_patch0_func, 122, 1, 1 },
-	{ ahc_patch6_func, 123, 4, 2 },
+	{ ahc_patch7_func, 123, 4, 2 },
 	{ ahc_patch0_func, 127, 1, 1 },
-	{ ahc_patch11_func, 129, 2, 1 },
+	{ ahc_patch12_func, 129, 2, 1 },
 	{ ahc_patch1_func, 131, 1, 2 },
 	{ ahc_patch0_func, 132, 1, 1 },
-	{ ahc_patch6_func, 133, 4, 1 },
-	{ ahc_patch6_func, 144, 77, 9 },
-	{ ahc_patch4_func, 156, 1, 1 },
-	{ ahc_patch1_func, 172, 1, 1 },
-	{ ahc_patch8_func, 180, 1, 2 },
-	{ ahc_patch0_func, 181, 1, 1 },
-	{ ahc_patch8_func, 190, 1, 2 },
-	{ ahc_patch0_func, 191, 1, 1 },
-	{ ahc_patch8_func, 207, 6, 2 },
-	{ ahc_patch0_func, 213, 6, 1 },
-	{ ahc_patch7_func, 221, 18, 2 },
-	{ ahc_patch1_func, 234, 1, 1 },
-	{ ahc_patch1_func, 241, 1, 2 },
-	{ ahc_patch0_func, 242, 2, 2 },
-	{ ahc_patch11_func, 243, 1, 1 },
-	{ ahc_patch8_func, 251, 33, 2 },
-	{ ahc_patch1_func, 267, 16, 1 },
-	{ ahc_patch12_func, 284, 14, 1 },
-	{ ahc_patch1_func, 298, 2, 2 },
-	{ ahc_patch0_func, 300, 3, 3 },
-	{ ahc_patch8_func, 300, 1, 2 },
-	{ ahc_patch0_func, 301, 2, 1 },
-	{ ahc_patch1_func, 305, 1, 2 },
-	{ ahc_patch0_func, 306, 1, 1 },
-	{ ahc_patch8_func, 310, 1, 1 },
-	{ ahc_patch8_func, 313, 2, 2 },
-	{ ahc_patch0_func, 315, 4, 1 },
-	{ ahc_patch12_func, 319, 1, 1 },
-	{ ahc_patch13_func, 322, 2, 3 },
-	{ ahc_patch8_func, 322, 1, 2 },
-	{ ahc_patch0_func, 323, 1, 1 },
-	{ ahc_patch1_func, 332, 40, 6 },
-	{ ahc_patch6_func, 341, 1, 1 },
-	{ ahc_patch7_func, 342, 1, 1 },
-	{ ahc_patch14_func, 344, 2, 1 },
-	{ ahc_patch15_func, 346, 5, 1 },
-	{ ahc_patch0_func, 372, 51, 15 },
-	{ ahc_patch12_func, 372, 1, 1 },
-	{ ahc_patch6_func, 374, 2, 2 },
-	{ ahc_patch16_func, 375, 1, 1 },
-	{ ahc_patch8_func, 378, 1, 1 },
-	{ ahc_patch17_func, 385, 1, 1 },
-	{ ahc_patch12_func, 390, 9, 3 },
-	{ ahc_patch8_func, 391, 3, 2 },
-	{ ahc_patch0_func, 394, 3, 1 },
-	{ ahc_patch8_func, 402, 6, 2 },
-	{ ahc_patch0_func, 408, 8, 1 },
-	{ ahc_patch12_func, 416, 1, 1 },
-	{ ahc_patch8_func, 418, 1, 2 },
-	{ ahc_patch0_func, 419, 1, 1 },
-	{ ahc_patch6_func, 422, 1, 1 },
-	{ ahc_patch6_func, 423, 1, 1 },
-	{ ahc_patch7_func, 424, 2, 1 },
-	{ ahc_patch8_func, 426, 1, 1 },
-	{ ahc_patch12_func, 427, 9, 4 },
-	{ ahc_patch8_func, 427, 1, 1 },
-	{ ahc_patch8_func, 434, 2, 1 },
-	{ ahc_patch0_func, 436, 4, 3 },
-	{ ahc_patch8_func, 436, 1, 2 },
-	{ ahc_patch0_func, 437, 3, 1 },
-	{ ahc_patch1_func, 441, 2, 1 },
-	{ ahc_patch6_func, 443, 5, 2 },
-	{ ahc_patch0_func, 448, 1, 1 },
-	{ ahc_patch7_func, 449, 113, 22 },
-	{ ahc_patch1_func, 450, 3, 2 },
-	{ ahc_patch0_func, 453, 5, 3 },
-	{ ahc_patch8_func, 453, 2, 2 },
-	{ ahc_patch0_func, 455, 3, 1 },
-	{ ahc_patch1_func, 460, 2, 2 },
-	{ ahc_patch0_func, 462, 6, 3 },
-	{ ahc_patch8_func, 462, 2, 2 },
-	{ ahc_patch0_func, 464, 3, 1 },
+	{ ahc_patch7_func, 133, 4, 1 },
+	{ ahc_patch7_func, 144, 80, 9 },
+	{ ahc_patch4_func, 162, 1, 1 },
+	{ ahc_patch1_func, 175, 1, 1 },
+	{ ahc_patch9_func, 183, 1, 2 },
+	{ ahc_patch0_func, 184, 1, 1 },
+	{ ahc_patch9_func, 193, 1, 2 },
+	{ ahc_patch0_func, 194, 1, 1 },
+	{ ahc_patch9_func, 210, 6, 2 },
+	{ ahc_patch0_func, 216, 6, 1 },
+	{ ahc_patch8_func, 224, 18, 2 },
+	{ ahc_patch1_func, 237, 1, 1 },
+	{ ahc_patch1_func, 244, 1, 2 },
+	{ ahc_patch0_func, 245, 2, 2 },
+	{ ahc_patch12_func, 246, 1, 1 },
+	{ ahc_patch9_func, 254, 33, 2 },
+	{ ahc_patch1_func, 270, 16, 1 },
+	{ ahc_patch13_func, 287, 14, 1 },
+	{ ahc_patch1_func, 301, 2, 2 },
+	{ ahc_patch0_func, 303, 3, 3 },
+	{ ahc_patch9_func, 303, 1, 2 },
+	{ ahc_patch0_func, 304, 2, 1 },
+	{ ahc_patch1_func, 308, 1, 2 },
+	{ ahc_patch0_func, 309, 1, 1 },
+	{ ahc_patch9_func, 313, 1, 1 },
+	{ ahc_patch9_func, 316, 2, 2 },
+	{ ahc_patch0_func, 318, 4, 1 },
+	{ ahc_patch13_func, 322, 1, 1 },
+	{ ahc_patch14_func, 325, 2, 3 },
+	{ ahc_patch9_func, 325, 1, 2 },
+	{ ahc_patch0_func, 326, 1, 1 },
+	{ ahc_patch6_func, 331, 1, 2 },
+	{ ahc_patch0_func, 332, 1, 1 },
+	{ ahc_patch1_func, 336, 45, 10 },
+	{ ahc_patch6_func, 345, 2, 4 },
+	{ ahc_patch7_func, 345, 1, 1 },
+	{ ahc_patch8_func, 346, 1, 1 },
+	{ ahc_patch0_func, 347, 1, 1 },
+	{ ahc_patch15_func, 348, 1, 1 },
+	{ ahc_patch6_func, 367, 6, 3 },
+	{ ahc_patch15_func, 367, 5, 1 },
+	{ ahc_patch0_func, 373, 5, 1 },
+	{ ahc_patch0_func, 381, 51, 15 },
+	{ ahc_patch13_func, 381, 1, 1 },
+	{ ahc_patch7_func, 383, 2, 2 },
+	{ ahc_patch16_func, 384, 1, 1 },
+	{ ahc_patch9_func, 387, 1, 1 },
+	{ ahc_patch17_func, 394, 1, 1 },
+	{ ahc_patch13_func, 399, 9, 3 },
+	{ ahc_patch9_func, 400, 3, 2 },
+	{ ahc_patch0_func, 403, 3, 1 },
+	{ ahc_patch9_func, 411, 6, 2 },
+	{ ahc_patch0_func, 417, 8, 1 },
+	{ ahc_patch13_func, 425, 1, 1 },
+	{ ahc_patch9_func, 427, 1, 2 },
+	{ ahc_patch0_func, 428, 1, 1 },
+	{ ahc_patch7_func, 431, 1, 1 },
+	{ ahc_patch7_func, 432, 1, 1 },
+	{ ahc_patch8_func, 433, 3, 3 },
+	{ ahc_patch6_func, 434, 1, 2 },
+	{ ahc_patch0_func, 435, 1, 1 },
+	{ ahc_patch9_func, 436, 1, 1 },
+	{ ahc_patch13_func, 437, 9, 4 },
+	{ ahc_patch9_func, 437, 1, 1 },
+	{ ahc_patch9_func, 444, 2, 1 },
+	{ ahc_patch0_func, 446, 4, 3 },
+	{ ahc_patch9_func, 446, 1, 2 },
+	{ ahc_patch0_func, 447, 3, 1 },
+	{ ahc_patch1_func, 451, 2, 1 },
+	{ ahc_patch7_func, 453, 5, 2 },
+	{ ahc_patch0_func, 458, 1, 1 },
+	{ ahc_patch8_func, 459, 107, 23 },
+	{ ahc_patch1_func, 460, 3, 2 },
+	{ ahc_patch0_func, 463, 5, 3 },
+	{ ahc_patch9_func, 463, 2, 2 },
+	{ ahc_patch0_func, 465, 3, 1 },
 	{ ahc_patch1_func, 470, 2, 2 },
-	{ ahc_patch0_func, 472, 9, 7 },
-	{ ahc_patch8_func, 472, 5, 6 },
-	{ ahc_patch18_func, 472, 1, 2 },
-	{ ahc_patch0_func, 473, 1, 1 },
-	{ ahc_patch18_func, 475, 1, 2 },
-	{ ahc_patch0_func, 476, 1, 1 },
-	{ ahc_patch0_func, 477, 4, 1 },
-	{ ahc_patch1_func, 486, 1, 1 },
-	{ ahc_patch2_func, 498, 2, 2 },
-	{ ahc_patch0_func, 500, 2, 2 },
-	{ ahc_patch19_func, 500, 2, 1 },
-	{ ahc_patch19_func, 536, 7, 1 },
-	{ ahc_patch3_func, 564, 1, 2 },
-	{ ahc_patch0_func, 565, 1, 1 },
-	{ ahc_patch20_func, 568, 1, 1 },
-	{ ahc_patch7_func, 570, 95, 26 },
-	{ ahc_patch4_func, 571, 1, 1 },
-	{ ahc_patch8_func, 578, 2, 2 },
-	{ ahc_patch0_func, 580, 3, 1 },
-	{ ahc_patch18_func, 587, 2, 2 },
-	{ ahc_patch0_func, 589, 1, 1 },
-	{ ahc_patch18_func, 593, 10, 3 },
-	{ ahc_patch5_func, 595, 8, 1 },
-	{ ahc_patch0_func, 603, 9, 2 },
-	{ ahc_patch5_func, 604, 8, 1 },
-	{ ahc_patch4_func, 614, 1, 2 },
-	{ ahc_patch0_func, 615, 1, 1 },
-	{ ahc_patch18_func, 616, 1, 2 },
-	{ ahc_patch0_func, 617, 3, 2 },
-	{ ahc_patch4_func, 619, 1, 1 },
-	{ ahc_patch5_func, 620, 1, 1 },
-	{ ahc_patch5_func, 623, 1, 1 },
-	{ ahc_patch5_func, 625, 1, 1 },
-	{ ahc_patch4_func, 627, 2, 2 },
-	{ ahc_patch0_func, 629, 2, 1 },
+	{ ahc_patch0_func, 472, 6, 3 },
+	{ ahc_patch9_func, 472, 2, 2 },
+	{ ahc_patch0_func, 474, 3, 1 },
+	{ ahc_patch1_func, 480, 2, 2 },
+	{ ahc_patch0_func, 482, 9, 7 },
+	{ ahc_patch9_func, 482, 5, 6 },
+	{ ahc_patch18_func, 482, 1, 2 },
+	{ ahc_patch0_func, 483, 1, 1 },
+	{ ahc_patch18_func, 485, 1, 2 },
+	{ ahc_patch0_func, 486, 1, 1 },
+	{ ahc_patch0_func, 487, 4, 1 },
+	{ ahc_patch6_func, 491, 3, 2 },
+	{ ahc_patch0_func, 494, 1, 1 },
+	{ ahc_patch1_func, 497, 1, 1 },
+	{ ahc_patch6_func, 502, 1, 2 },
+	{ ahc_patch0_func, 503, 1, 1 },
+	{ ahc_patch19_func, 540, 7, 1 },
+	{ ahc_patch3_func, 568, 1, 2 },
+	{ ahc_patch0_func, 569, 1, 1 },
+	{ ahc_patch20_func, 572, 1, 1 },
+	{ ahc_patch8_func, 574, 100, 31 },
+	{ ahc_patch4_func, 575, 1, 1 },
+	{ ahc_patch1_func, 581, 2, 2 },
+	{ ahc_patch0_func, 583, 1, 1 },
+	{ ahc_patch9_func, 584, 3, 3 },
+	{ ahc_patch14_func, 585, 1, 1 },
+	{ ahc_patch0_func, 587, 4, 1 },
+	{ ahc_patch18_func, 595, 2, 2 },
+	{ ahc_patch0_func, 597, 1, 1 },
+	{ ahc_patch18_func, 601, 10, 3 },
+	{ ahc_patch5_func, 603, 8, 1 },
+	{ ahc_patch0_func, 611, 9, 2 },
+	{ ahc_patch5_func, 612, 8, 1 },
+	{ ahc_patch4_func, 622, 1, 2 },
+	{ ahc_patch0_func, 623, 1, 1 },
+	{ ahc_patch18_func, 624, 1, 2 },
+	{ ahc_patch0_func, 625, 3, 2 },
+	{ ahc_patch4_func, 627, 1, 1 },
+	{ ahc_patch5_func, 628, 1, 1 },
 	{ ahc_patch5_func, 631, 1, 1 },
-	{ ahc_patch5_func, 634, 1, 1 },
-	{ ahc_patch5_func, 637, 1, 1 },
-	{ ahc_patch18_func, 641, 1, 1 },
-	{ ahc_patch18_func, 644, 1, 1 },
-	{ ahc_patch4_func, 650, 1, 1 },
-	{ ahc_patch6_func, 665, 16, 1 },
-	{ ahc_patch4_func, 683, 20, 1 },
-	{ ahc_patch8_func, 704, 4, 2 },
-	{ ahc_patch0_func, 708, 4, 1 },
-	{ ahc_patch8_func, 712, 4, 2 },
-	{ ahc_patch0_func, 716, 3, 1 },
-	{ ahc_patch21_func, 724, 14, 1 },
-	{ ahc_patch6_func, 738, 3, 1 },
-	{ ahc_patch8_func, 750, 24, 8 },
-	{ ahc_patch18_func, 754, 1, 2 },
-	{ ahc_patch0_func, 755, 1, 1 },
-	{ ahc_patch13_func, 760, 4, 2 },
-	{ ahc_patch0_func, 764, 7, 3 },
-	{ ahc_patch22_func, 764, 5, 2 },
-	{ ahc_patch0_func, 769, 2, 1 },
-	{ ahc_patch0_func, 774, 40, 3 },
-	{ ahc_patch17_func, 786, 16, 2 },
-	{ ahc_patch0_func, 802, 1, 1 },
-	{ ahc_patch4_func, 826, 1, 1 },
-	{ ahc_patch4_func, 827, 3, 2 },
-	{ ahc_patch0_func, 830, 1, 1 },
-	{ ahc_patch4_func, 831, 12, 1 }
+	{ ahc_patch5_func, 633, 1, 1 },
+	{ ahc_patch4_func, 635, 2, 2 },
+	{ ahc_patch0_func, 637, 2, 1 },
+	{ ahc_patch5_func, 639, 1, 1 },
+	{ ahc_patch5_func, 642, 1, 1 },
+	{ ahc_patch5_func, 645, 1, 1 },
+	{ ahc_patch18_func, 649, 1, 1 },
+	{ ahc_patch18_func, 652, 1, 1 },
+	{ ahc_patch4_func, 658, 1, 1 },
+	{ ahc_patch6_func, 661, 1, 2 },
+	{ ahc_patch0_func, 662, 1, 1 },
+	{ ahc_patch7_func, 674, 16, 1 },
+	{ ahc_patch4_func, 692, 20, 1 },
+	{ ahc_patch9_func, 713, 4, 2 },
+	{ ahc_patch0_func, 717, 4, 1 },
+	{ ahc_patch9_func, 721, 4, 2 },
+	{ ahc_patch0_func, 725, 3, 1 },
+	{ ahc_patch6_func, 731, 1, 1 },
+	{ ahc_patch21_func, 733, 14, 1 },
+	{ ahc_patch7_func, 747, 3, 1 },
+	{ ahc_patch9_func, 759, 24, 8 },
+	{ ahc_patch18_func, 763, 1, 2 },
+	{ ahc_patch0_func, 764, 1, 1 },
+	{ ahc_patch14_func, 769, 4, 2 },
+	{ ahc_patch0_func, 773, 7, 3 },
+	{ ahc_patch22_func, 773, 5, 2 },
+	{ ahc_patch0_func, 778, 2, 1 },
+	{ ahc_patch0_func, 783, 41, 3 },
+	{ ahc_patch17_func, 795, 17, 2 },
+	{ ahc_patch0_func, 812, 1, 1 },
+	{ ahc_patch4_func, 836, 1, 1 },
+	{ ahc_patch4_func, 837, 3, 2 },
+	{ ahc_patch0_func, 840, 1, 1 },
+	{ ahc_patch4_func, 841, 12, 1 }
 };
 struct cs {
 	u_int16_t	begin;
@@ -1229,11 +1255,11 @@
 } critical_sections[] = {
 	{ 11, 18 },
 	{ 21, 30 },
-	{ 683, 699 },
-	{ 827, 830 },
-	{ 831, 837 },
-	{ 839, 841 },
-	{ 841, 843 }
+	{ 692, 708 },
+	{ 837, 840 },
+	{ 841, 847 },
+	{ 849, 851 },
+	{ 851, 853 }
 };
 const int num_critical_sections = sizeof(critical_sections)
 				 / sizeof(*critical_sections);
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aicasm/Makefile linux/drivers/scsi/aic7xxx/aicasm/Makefile
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aicasm/Makefile	Tue Mar  6 22:44:16 2001
+++ linux/drivers/scsi/aic7xxx/aicasm/Makefile	Mon Dec  3 22:41:47 2001
@@ -2,17 +2,23 @@
 
 CSRCS=	aicasm.c aicasm_symbol.c
 GENSRCS= aicasm_gram.c aicasm_scan.c
-
-GENHDRS=	y.tab.h
+DEPHDRS= aicdb.h
+GENHDRS= y.tab.h aicdb.h
 
 SRCS=	${GENSRCS} ${CSRCS}
 CLEANFILES= ${GENSRCS} ${GENHDRS} y.output
 # Override default kernel CFLAGS.  This is a userland app.
-AICASM_CFLAGS:= -I/usr/include -ldb1
+AICASM_CFLAGS:= -I/usr/include -I. -ldb
 YFLAGS= -d
 
 NOMAN=	noman
 
+ifneq ($(HOSTCC),)
+AICASM_CC= $(HOSTCC)
+else
+AICASM_CC= $(CC)
+endif
+
 ifdef DEBUG
 CFLAGS+= -DDEBUG -g
 YFLAGS+= -t -v
@@ -21,8 +27,21 @@
 
 .SUFFIXES= .l .y .c
 
-$(PROG): $(SRCS)
-	$(HOSTCC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG)
+$(PROG): $(SRCS) $(DEPHDRS)
+	$(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG)
+
+aicdb.h:
+	@if [ -e "/usr/include/db3/db_185.h" ]; then		\
+		echo "#include <db3/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db2/db_185.h" ]; then		\
+		echo "#include <db2/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db/db_185.h" ]; then		\
+		echo "#include <db/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db_185.h" ]; then		\
+		echo "#include <db_185.h>" > aicdb.h;		\
+	 else							\
+		echo "*** Install db development libraries";	\
+	 fi
 
 clean:
 	rm -f $(CLEANFILES) $(PROG)
diff -urN linux-2.4.5-pre1/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
--- linux-2.4.5-pre1/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Sun Mar  4 14:30:18 2001
+++ linux/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c	Mon Dec  3 22:41:47 2001
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#4 $
+ * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#5 $
  *
  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $
  */
@@ -36,7 +36,7 @@
 #include <sys/types.h>
 
 #ifdef __linux__
-#include <db1/db.h>
+#include "aicdb.h"
 #else
 #include <db.h>
 #endif
diff -urN linux-2.4.5-pre1/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- linux-2.4.5-pre1/drivers/scsi/fdomain.c	Fri Apr 27 13:59:18 2001
+++ linux/drivers/scsi/fdomain.c	Mon Dec  3 22:41:47 2001
@@ -587,9 +587,7 @@
 
 static void do_pause( unsigned amount )	/* Pause for amount*10 milliseconds */
 {
-   do {
-	udelay(10*1000);
-   } while (--amount);
+   mdelay(10*amount);
 }
 
 inline static void fdomain_make_bus_idle( void )
@@ -971,7 +969,7 @@
    	return 0;
    shpnt->irq = interrupt_level;
    shpnt->io_port = port_base;
-   scsi_set_pci_device(shpnt->pci_dev, pdev);
+   scsi_set_pci_device(shpnt, pdev);
    shpnt->n_io_port = 0x10;
    print_banner( shpnt );
 
diff -urN linux-2.4.5-pre1/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- linux-2.4.5-pre1/drivers/scsi/scsi_lib.c	Fri Mar  2 18:38:39 2001
+++ linux/drivers/scsi/scsi_lib.c	Mon Dec  3 22:41:47 2001
@@ -1108,9 +1108,13 @@
  */
 void scsi_unblock_requests(struct Scsi_Host * SHpnt)
 {
+	Scsi_Device *SDloop;
+
 	SHpnt->host_self_blocked = FALSE;
+	/* Now that we are unblocked, try to start the queues. */
+	for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next)
+		scsi_queue_next_request(&SDloop->request_queue, NULL);
 }
-
 
 /*
  * Function:    scsi_report_bus_reset()
diff -urN linux-2.4.5-pre1/drivers/sound/ymfpci.c linux/drivers/sound/ymfpci.c
--- linux-2.4.5-pre1/drivers/sound/ymfpci.c	Thu Apr 26 22:17:27 2001
+++ linux/drivers/sound/ymfpci.c	Mon Dec  3 22:41:47 2001
@@ -989,11 +989,6 @@
 
 	status = ymfpci_readl(codec, YDSXGR_STATUS);
 	if (status & 0x80000000) {
-		spin_lock(&codec->reg_lock);
-		ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
-		mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
-		ymfpci_writel(codec, YDSXGR_MODE, mode);
-		spin_unlock(&codec->reg_lock);
 		codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1;
 		spin_lock(&codec->voice_lock);
 		for (nvoice = 0; nvoice < 64; nvoice++) {
@@ -1007,6 +1002,11 @@
 				ymf_cap_interrupt(codec, cap);
 		}
 		spin_unlock(&codec->voice_lock);
+		spin_lock(&codec->reg_lock);
+		ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
+		mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
+		ymfpci_writel(codec, YDSXGR_MODE, mode);
+		spin_unlock(&codec->reg_lock);
 	}
 
 	status = ymfpci_readl(codec, YDSXGR_INTFLAG);
@@ -2106,6 +2106,8 @@
 		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
 		pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
 	}
+	pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
+	pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
 }
 
 static void ymfpci_enable_dsp(ymfpci_t *codec)
diff -urN linux-2.4.5-pre1/drivers/video/sis/sis_main.c linux/drivers/video/sis/sis_main.c
--- linux-2.4.5-pre1/drivers/video/sis/sis_main.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/sis/sis_main.c	Mon Dec  3 22:41:47 2001
@@ -1029,6 +1029,8 @@
 
 	if (heap.pohFreeList == NULL) {
 		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+		if (!poha)
+			return NULL;
 
 		poha->pohaNext = heap.pohaChain;
 		heap.pohaChain = poha;
diff -urN linux-2.4.5-pre1/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.5-pre1/fs/buffer.c	Fri Apr 27 14:23:25 2001
+++ linux/fs/buffer.c	Mon Dec  3 22:41:47 2001
@@ -1034,7 +1034,6 @@
 int balance_dirty_state(kdev_t dev)
 {
 	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
-	int shortage;
 
 	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
 	tot = nr_free_buffer_pages();
@@ -1050,16 +1049,6 @@
 		return 0;
 	}
 
-	/*
-	 * If we are about to get low on free pages and
-	 * cleaning the inactive_dirty pages would help
-	 * fix this, wake up bdflush.
-	 */
-	shortage = free_shortage();
-	if (shortage && nr_inactive_dirty_pages > shortage &&
-			nr_inactive_dirty_pages > freepages.high)
-		return 0;
-
 	return -1;
 }
 
@@ -2578,16 +2567,15 @@
 	return flushed;
 }
 
-struct task_struct *bdflush_tsk = 0;
+DECLARE_WAIT_QUEUE_HEAD(bdflush_wait);
 
 void wakeup_bdflush(int block)
 {
-	if (current != bdflush_tsk) {
-		wake_up_process(bdflush_tsk);
+	if (waitqueue_active(&bdflush_wait))
+		wake_up_interruptible(&bdflush_wait);
 
-		if (block)
-			flush_dirty_buffers(0);
-	}
+	if (block)
+		flush_dirty_buffers(0);
 }
 
 /* 
@@ -2688,7 +2676,6 @@
 	tsk->session = 1;
 	tsk->pgrp = 1;
 	strcpy(tsk->comm, "bdflush");
-	bdflush_tsk = tsk;
 
 	/* avoid getting signals */
 	spin_lock_irq(&tsk->sigmask_lock);
@@ -2703,22 +2690,16 @@
 		CHECK_EMERGENCY_SYNC
 
 		flushed = flush_dirty_buffers(0);
-		if (free_shortage())
-			flushed += page_launder(GFP_KERNEL, 0);
 
 		/*
 		 * If there are still a lot of dirty buffers around,
 		 * skip the sleep and flush some more. Otherwise, we
 		 * go to sleep waiting a wakeup.
 		 */
-		set_current_state(TASK_INTERRUPTIBLE);
 		if (!flushed || balance_dirty_state(NODEV) < 0) {
 			run_task_queue(&tq_disk);
-			schedule();
+			interruptible_sleep_on(&bdflush_wait);
 		}
-		/* Remember to mark us as running otherwise
-		   the next schedule will block. */
-		__set_current_state(TASK_RUNNING);
 	}
 }
 
diff -urN linux-2.4.5-pre1/fs/nls/nls_koi8-u.c linux/fs/nls/nls_koi8-u.c
--- linux-2.4.5-pre1/fs/nls/nls_koi8-u.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/nls/nls_koi8-u.c	Mon Dec  3 22:41:47 2001
@@ -146,9 +146,9 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
 
-	0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
 };
 
 static unsigned char page22[256] = {
diff -urN linux-2.4.5-pre1/fs/proc/Makefile linux/fs/proc/Makefile
--- linux-2.4.5-pre1/fs/proc/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/fs/proc/Makefile	Mon Dec  3 22:41:47 2001
@@ -9,10 +9,10 @@
 
 O_TARGET := proc.o
 
-export-objs := procfs_syms.o
+export-objs := root.o
 
 obj-y    := inode.o root.o base.o generic.o array.o \
-		kmsg.o proc_tty.o proc_misc.o kcore.o procfs_syms.o
+		kmsg.o proc_tty.o proc_misc.o kcore.o
 
 ifeq ($(CONFIG_PROC_DEVICETREE),y)
 obj-y += proc_devtree.o
diff -urN linux-2.4.5-pre1/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.4.5-pre1/fs/proc/array.c	Fri Apr  6 10:51:19 2001
+++ linux/fs/proc/array.c	Mon Dec  3 22:41:47 2001
@@ -157,7 +157,7 @@
 		"Uid:\t%d\t%d\t%d\t%d\n"
 		"Gid:\t%d\t%d\t%d\t%d\n",
 		get_task_state(p),
-		p->pid, p->p_opptr->pid, p->p_pptr->pid != p->p_opptr->pid ? p->p_pptr->pid : 0,
+		p->pid, p->pid ? p->p_opptr->pid : 0, 0,
 		p->uid, p->euid, p->suid, p->fsuid,
 		p->gid, p->egid, p->sgid, p->fsgid);
 	read_unlock(&tasklist_lock);	
@@ -339,7 +339,7 @@
 	nice = task->nice;
 
 	read_lock(&tasklist_lock);
-	ppid = task->p_opptr->pid;
+	ppid = task->pid ? task->p_opptr->pid : 0;
 	read_unlock(&tasklist_lock);
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
diff -urN linux-2.4.5-pre1/fs/proc/base.c linux/fs/proc/base.c
--- linux-2.4.5-pre1/fs/proc/base.c	Mon Mar 19 12:34:55 2001
+++ linux/fs/proc/base.c	Mon Dec  3 22:41:47 2001
@@ -586,7 +586,7 @@
 	struct pid_entry *p;
 
 	pid = inode->u.proc_i.task->pid;
-	if (!inode->u.proc_i.task->p_pptr)
+	if (!pid)
 		return -ENOENT;
 	i = filp->f_pos;
 	switch (i) {
@@ -641,7 +641,7 @@
 	 */
 	inode->u.proc_i.task = task;
 	get_task_struct(task);
-	if (!task->p_pptr)
+	if (!task->pid)
 		goto out_unlock;
 
 	inode->i_uid = 0;
@@ -673,7 +673,7 @@
  */
 static int pid_base_revalidate(struct dentry * dentry, int flags)
 {
-	if (dentry->d_inode->u.proc_i.task->p_pptr)
+	if (dentry->d_inode->u.proc_i.task->pid)
 		return 1;
 	d_drop(dentry);
 	return 0;
diff -urN linux-2.4.5-pre1/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- linux-2.4.5-pre1/fs/proc/procfs_syms.c	Mon Sep 11 08:41:07 2000
+++ linux/fs/proc/procfs_syms.c	Wed Dec 31 16:00:00 1969
@@ -1,46 +0,0 @@
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-
-extern struct proc_dir_entry *proc_sys_root;
-
-#ifdef CONFIG_SYSCTL
-EXPORT_SYMBOL(proc_sys_root);
-#endif
-EXPORT_SYMBOL(proc_symlink);
-EXPORT_SYMBOL(proc_mknod);
-EXPORT_SYMBOL(proc_mkdir);
-EXPORT_SYMBOL(create_proc_entry);
-EXPORT_SYMBOL(remove_proc_entry);
-EXPORT_SYMBOL(proc_root);
-EXPORT_SYMBOL(proc_root_fs);
-EXPORT_SYMBOL(proc_net);
-EXPORT_SYMBOL(proc_bus);
-EXPORT_SYMBOL(proc_root_driver);
-
-static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
-
-static int __init init_proc_fs(void)
-{
-	int err = register_filesystem(&proc_fs_type);
-	if (!err) {
-		proc_mnt = kern_mount(&proc_fs_type);
-		err = PTR_ERR(proc_mnt);
-		if (IS_ERR(proc_mnt))
-			unregister_filesystem(&proc_fs_type);
-		else
-			err = 0;
-	}
-	return err;
-}
-
-static void __exit exit_proc_fs(void)
-{
-	unregister_filesystem(&proc_fs_type);
-	kern_umount(proc_mnt);
-}
-
-module_init(init_proc_fs)
-module_exit(exit_proc_fs)
diff -urN linux-2.4.5-pre1/fs/proc/root.c linux/fs/proc/root.c
--- linux-2.4.5-pre1/fs/proc/root.c	Thu Nov 23 09:07:36 2000
+++ linux/fs/proc/root.c	Mon Dec  3 22:41:47 2001
@@ -14,6 +14,7 @@
 #include <linux/stat.h>
 #include <linux/config.h>
 #include <linux/init.h>
+#include <linux/module.h>
 #include <asm/bitops.h>
 
 struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver;
@@ -22,8 +23,19 @@
 struct proc_dir_entry *proc_sys_root;
 #endif
 
+static DECLARE_FSTYPE(proc_fs_type, "proc", proc_read_super, FS_SINGLE);
+
 void __init proc_root_init(void)
 {
+	int err = register_filesystem(&proc_fs_type);
+	if (err)
+		return;
+	proc_mnt = kern_mount(&proc_fs_type);
+	err = PTR_ERR(proc_mnt);
+	if (IS_ERR(proc_mnt)) {
+		unregister_filesystem(&proc_fs_type);
+		return;
+	}
 	proc_misc_init();
 	proc_net = proc_mkdir("net", 0);
 #ifdef CONFIG_SYSVIPC
@@ -106,3 +118,17 @@
 	proc_fops:	&proc_root_operations,
 	parent:		&proc_root,
 };
+
+#ifdef CONFIG_SYSCTL
+EXPORT_SYMBOL(proc_sys_root);
+#endif
+EXPORT_SYMBOL(proc_symlink);
+EXPORT_SYMBOL(proc_mknod);
+EXPORT_SYMBOL(proc_mkdir);
+EXPORT_SYMBOL(create_proc_entry);
+EXPORT_SYMBOL(remove_proc_entry);
+EXPORT_SYMBOL(proc_root);
+EXPORT_SYMBOL(proc_root_fs);
+EXPORT_SYMBOL(proc_net);
+EXPORT_SYMBOL(proc_bus);
+EXPORT_SYMBOL(proc_root_driver);
diff -urN linux-2.4.5-pre1/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- linux-2.4.5-pre1/include/asm-i386/pci.h	Fri Apr 27 15:49:20 2001
+++ linux/include/asm-i386/pci.h	Mon Dec  3 22:41:47 2001
@@ -9,8 +9,9 @@
 
 #define pcibios_assign_all_busses()	0
 
+extern unsigned long pci_mem_start;
 #define PCIBIOS_MIN_IO		0x1000
-#define PCIBIOS_MIN_MEM		0x10000000
+#define PCIBIOS_MIN_MEM		(pci_mem_start)
 
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq);
diff -urN linux-2.4.5-pre1/include/asm-i386/system.h linux/include/asm-i386/system.h
--- linux-2.4.5-pre1/include/asm-i386/system.h	Fri Apr 27 15:48:21 2001
+++ linux/include/asm-i386/system.h	Mon Dec  3 22:41:47 2001
@@ -288,7 +288,7 @@
 
 /* interrupt control.. */
 #define __save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
-#define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
+#define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
 #define __cli() 		__asm__ __volatile__("cli": : :"memory")
 #define __sti()			__asm__ __volatile__("sti": : :"memory")
 /* used in the idle loop; sti takes one instruction cycle to complete */
diff -urN linux-2.4.5-pre1/include/linux/skbuff.h linux/include/linux/skbuff.h
--- linux-2.4.5-pre1/include/linux/skbuff.h	Fri Apr 27 15:48:50 2001
+++ linux/include/linux/skbuff.h	Mon Dec  3 22:41:47 2001
@@ -1069,7 +1069,7 @@
 static inline int
 skb_cow(struct sk_buff *skb, unsigned int headroom)
 {
-	int delta = headroom - skb_headroom(skb);
+	int delta = (headroom > 16 ? headroom : 16) - skb_headroom(skb);
 
 	if (delta < 0)
 		delta = 0;
diff -urN linux-2.4.5-pre1/include/net/ipconfig.h linux/include/net/ipconfig.h
--- linux-2.4.5-pre1/include/net/ipconfig.h	Mon Jan  4 15:31:35 1999
+++ linux/include/net/ipconfig.h	Mon Dec  3 22:41:47 2001
@@ -1,21 +1,38 @@
 /*
- *  $Id: ipconfig.h,v 1.3 1999/01/04 20:13:29 davem Exp $
+ *  $Id: ipconfig.h,v 1.4 2001/04/30 04:51:46 davem Exp $
  *
  *  Copyright (C) 1997 Martin Mares
  *
  *  Automatic IP Layer Configuration
  */
 
-extern __u32 root_server_addr;
-extern u8 root_server_path[];
-extern u32 ic_myaddr;
-extern u32 ic_servaddr;
-extern u32 ic_gateway;
-extern u32 ic_netmask;
-extern int ic_enable;
-extern int ic_host_name_set;
-extern int ic_set_manually;
-extern int ic_proto_enabled;
+/* The following are initdata: */
 
-#define IC_BOOTP 1
-#define IC_RARP 2
+extern int ic_enable;		/* Enable or disable the whole shebang */
+
+extern int ic_proto_enabled;	/* Protocols enabled (see IC_xxx) */
+extern int ic_host_name_set;	/* Host name set by ipconfig? */
+extern int ic_set_manually;	/* IPconfig parameters set manually */
+
+extern u32 ic_myaddr;		/* My IP address */
+extern u32 ic_netmask;		/* Netmask for local subnet */
+extern u32 ic_gateway;		/* Gateway IP address */
+
+extern u32 ic_servaddr;		/* Boot server IP address */
+
+extern u32 root_server_addr;	/* Address of NFS server */
+extern u8 root_server_path[];	/* Path to mount as root */
+
+
+
+/* The following are persistent (not initdata): */
+
+extern int ic_proto_used;	/* Protocol used, if any */
+extern u32 ic_nameserver;	/* DNS server IP address */
+extern u8 ic_domain[];		/* DNS (not NIS) domain name */
+
+/* bits in ic_proto_{enabled,used} */
+#define IC_PROTO	0xFF	/* Protocols mask: */
+#define IC_BOOTP	0x01	/*   BOOTP (or DHCP, see below) */
+#define IC_RARP		0x02	/*   RARP */
+#define IC_USE_DHCP    0x100	/* If on, use DHCP instead of BOOTP */
diff -urN linux-2.4.5-pre1/init/main.c linux/init/main.c
--- linux-2.4.5-pre1/init/main.c	Mon Dec  3 22:41:06 2001
+++ linux/init/main.c	Mon Dec  3 22:41:47 2001
@@ -561,9 +561,6 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
-#ifdef CONFIG_PROC_FS
-	proc_root_init();
-#endif
 	mempages = num_physpages;
 
 	fork_init(mempages);
@@ -577,6 +574,9 @@
 	signals_init();
 	bdev_init();
 	inode_init(mempages);
+#ifdef CONFIG_PROC_FS
+	proc_root_init();
+#endif
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
diff -urN linux-2.4.5-pre1/kernel/exit.c linux/kernel/exit.c
--- linux-2.4.5-pre1/kernel/exit.c	Fri Feb  9 11:29:44 2001
+++ linux/kernel/exit.c	Mon Dec  3 22:41:47 2001
@@ -62,6 +62,7 @@
 		current->counter += p->counter;
 		if (current->counter >= MAX_COUNTER)
 			current->counter = MAX_COUNTER;
+		p->pid = 0;
 		free_task_struct(p);
 	} else {
 		printk("task releasing itself\n");
diff -urN linux-2.4.5-pre1/mm/oom_kill.c linux/mm/oom_kill.c
--- linux-2.4.5-pre1/mm/oom_kill.c	Tue Nov 14 10:56:46 2000
+++ linux/mm/oom_kill.c	Mon Dec  3 22:41:47 2001
@@ -191,8 +191,6 @@
  */
 int out_of_memory(void)
 {
-	struct sysinfo swp_info;
-
 	/* Enough free memory?  Not OOM. */
 	if (nr_free_pages() > freepages.min)
 		return 0;
@@ -201,8 +199,7 @@
 		return 0;
 
 	/* Enough swap space left?  Not OOM. */
-	si_swapinfo(&swp_info);
-	if (swp_info.freeswap > 0)
+	if (nr_swap_pages > 0)
 		return 0;
 
 	/* Else... */
diff -urN linux-2.4.5-pre1/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.4.5-pre1/mm/vmscan.c	Thu Apr 12 12:10:25 2001
+++ linux/mm/vmscan.c	Mon Dec  3 22:41:47 2001
@@ -869,7 +869,6 @@
 
 DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
 DECLARE_WAIT_QUEUE_HEAD(kswapd_done);
-struct task_struct *kswapd_task;
 
 /*
  * The background pageout daemon, started as a kernel thread
@@ -892,7 +891,6 @@
 	tsk->pgrp = 1;
 	strcpy(tsk->comm, "kswapd");
 	sigfillset(&tsk->blocked);
-	kswapd_task = tsk;
 	
 	/*
 	 * Tell the memory management that we're a "memory allocator",
@@ -964,8 +962,8 @@
 
 void wakeup_kswapd(void)
 {
-	if (current != kswapd_task)
-		wake_up_process(kswapd_task);
+	if (waitqueue_active(&kswapd_wait))
+		wake_up_interruptible(&kswapd_wait);
 }
 
 /*
diff -urN linux-2.4.5-pre1/net/ipv4/Config.in linux/net/ipv4/Config.in
--- linux-2.4.5-pre1/net/ipv4/Config.in	Tue Aug 22 08:59:00 2000
+++ linux/net/ipv4/Config.in	Mon Dec  3 22:41:47 2001
@@ -20,6 +20,7 @@
 fi
 bool '  IP: kernel level autoconfiguration' CONFIG_IP_PNP
 if [ "$CONFIG_IP_PNP" = "y" ]; then
+   bool '    IP: DHCP support' CONFIG_IP_PNP_DHCP
    bool '    IP: BOOTP support' CONFIG_IP_PNP_BOOTP
    bool '    IP: RARP support' CONFIG_IP_PNP_RARP
 # not yet ready..
diff -urN linux-2.4.5-pre1/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux-2.4.5-pre1/net/ipv4/af_inet.c	Thu Apr 12 12:11:39 2001
+++ linux/net/ipv4/af_inet.c	Mon Dec  3 22:41:47 2001
@@ -5,7 +5,7 @@
  *
  *		PF_INET protocol family socket handler.
  *
- * Version:	$Id: af_inet.c,v 1.129 2001/03/02 03:13:05 davem Exp $
+ * Version:	$Id: af_inet.c,v 1.130 2001/04/29 08:21:32 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -135,11 +135,11 @@
 #endif
 
 #ifdef CONFIG_DLCI_MODULE
-int (*dlci_ioctl_hook)(unsigned int, void *) = NULL;
+int (*dlci_ioctl_hook)(unsigned int, void *);
 #endif
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-int (*br_ioctl_hook)(unsigned long) = NULL;
+int (*br_ioctl_hook)(unsigned long);
 #endif
 
 /* New destruction routine */
@@ -361,19 +361,19 @@
 
 	sk->destruct = inet_sock_destruct;
 
-	sk->zapped = 0;
-	sk->family = PF_INET;
-	sk->protocol = protocol;
+	sk->zapped	= 0;
+	sk->family	= PF_INET;
+	sk->protocol	= protocol;
 
-	sk->prot = prot;
+	sk->prot	= prot;
 	sk->backlog_rcv = prot->backlog_rcv;
 
-	sk->protinfo.af_inet.ttl=sysctl_ip_default_ttl;
+	sk->protinfo.af_inet.ttl	= sysctl_ip_default_ttl;
 
-	sk->protinfo.af_inet.mc_loop=1;
-	sk->protinfo.af_inet.mc_ttl=1;
-	sk->protinfo.af_inet.mc_index=0;
-	sk->protinfo.af_inet.mc_list=NULL;
+	sk->protinfo.af_inet.mc_loop	= 1;
+	sk->protinfo.af_inet.mc_ttl	= 1;
+	sk->protinfo.af_inet.mc_index	= 0;
+	sk->protinfo.af_inet.mc_list	= NULL;
 
 #ifdef INET_REFCNT_DEBUG
 	atomic_inc(&inet_sock_nr);
@@ -815,8 +815,7 @@
 	int err;
 	int pid;
 
-	switch(cmd) 
-	{
+	switch(cmd) {
 		case FIOSETOWN:
 		case SIOCSPGRP:
 			err = get_user(pid, (int *) arg);
@@ -962,8 +961,8 @@
 };
 
 struct net_proto_family inet_family_ops = {
-	PF_INET,
-	inet_create
+	family:	PF_INET,
+	create:	inet_create
 };
 
 
@@ -982,8 +981,7 @@
 
 	printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n");
 
-	if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb))
-	{
+	if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
 		printk(KERN_CRIT "inet_proto_init: panic\n");
 		return -EINVAL;
 	}
@@ -999,8 +997,7 @@
 	 */
 
 	printk(KERN_INFO "IP Protocols: ");
-	for(p = inet_protocol_base; p != NULL;) 
-	{
+	for (p = inet_protocol_base; p != NULL;) {
 		struct inet_protocol *tmp = (struct inet_protocol *) p->next;
 		inet_add_protocol(p);
 		printk("%s%s",p->name,tmp?", ":"\n");
diff -urN linux-2.4.5-pre1/net/ipv4/arp.c linux/net/ipv4/arp.c
--- linux-2.4.5-pre1/net/ipv4/arp.c	Thu Apr 12 12:11:39 2001
+++ linux/net/ipv4/arp.c	Mon Dec  3 22:41:47 2001
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.96 2001/02/02 08:42:59 davem Exp $
+ * Version:	$Id: arp.c,v 1.97 2001/04/30 04:36:12 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
@@ -123,69 +123,71 @@
 static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb);
 static void parp_redo(struct sk_buff *skb);
 
-static struct neigh_ops arp_generic_ops =
-{
-	AF_INET,
-	NULL,
-	arp_solicit,
-	arp_error_report,
-	neigh_resolve_output,
-	neigh_connected_output,
-	dev_queue_xmit,
-	dev_queue_xmit
+static struct neigh_ops arp_generic_ops = {
+	family:			AF_INET,
+	solicit:		arp_solicit,
+	error_report:		arp_error_report,
+	output:			neigh_resolve_output,
+	connected_output:	neigh_connected_output,
+	hh_output:		dev_queue_xmit,
+	queue_xmit:		dev_queue_xmit,
 };
 
-static struct neigh_ops arp_hh_ops =
-{
-	AF_INET,
-	NULL,
-	arp_solicit,
-	arp_error_report,
-	neigh_resolve_output,
-	neigh_resolve_output,
-	dev_queue_xmit,
-	dev_queue_xmit
+static struct neigh_ops arp_hh_ops = {
+	family:			AF_INET,
+	solicit:		arp_solicit,
+	error_report:		arp_error_report,
+	output:			neigh_resolve_output,
+	connected_output:	neigh_resolve_output,
+	hh_output:		dev_queue_xmit,
+	queue_xmit:		dev_queue_xmit,
 };
 
-static struct neigh_ops arp_direct_ops =
-{
-	AF_INET,
-	NULL,
-	NULL,
-	NULL,
-	dev_queue_xmit,
-	dev_queue_xmit,
-	dev_queue_xmit,
-	dev_queue_xmit
+static struct neigh_ops arp_direct_ops = {
+	family:			AF_INET,
+	output:			dev_queue_xmit,
+	connected_output:	dev_queue_xmit,
+	hh_output:		dev_queue_xmit,
+	queue_xmit:		dev_queue_xmit,
 };
 
-struct neigh_ops arp_broken_ops =
-{
-	AF_INET,
-	NULL,
-	arp_solicit,
-	arp_error_report,
-	neigh_compat_output,
-	neigh_compat_output,
-	dev_queue_xmit,
-	dev_queue_xmit,
+struct neigh_ops arp_broken_ops = {
+	family:			AF_INET,
+	solicit:		arp_solicit,
+	error_report:		arp_error_report,
+	output:			neigh_compat_output,
+	connected_output:	neigh_compat_output,
+	hh_output:		dev_queue_xmit,
+	queue_xmit:		dev_queue_xmit,
 };
 
-struct neigh_table arp_tbl =
-{
-	NULL,
-	AF_INET,
-	sizeof(struct neighbour) + 4,
-	4,
-	arp_hash,
-	arp_constructor,
-	NULL,
-	NULL,
-	parp_redo,
-	"arp_cache",
-        { NULL, NULL, &arp_tbl, 0, NULL, NULL,
-		  30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ },
-	30*HZ, 128, 512, 1024,
+struct neigh_table arp_tbl = {
+	family:		AF_INET,
+	entry_size:	sizeof(struct neighbour) + 4,
+	key_len:	4,
+	hash:		arp_hash,
+	constructor:	arp_constructor,
+	proxy_redo:	parp_redo,
+	id:		"arp_cache",
+	parms: {
+		tbl:			&arp_tbl,
+		base_reachable_time:	30 * HZ,
+		retrans_time:		1 * HZ,
+		gc_staletime:		60 * HZ,
+		reachable_time:		30 * HZ,
+		delay_probe_time:	5 * HZ,
+		queue_len:		3,
+		ucast_probes:		3,
+		mcast_probes:		3,
+		anycast_delay:		1 * HZ,
+		proxy_delay:		(8 * HZ) / 10,
+		proxy_qlen:		64,
+		locktime:		1 * HZ,
+	},
+	gc_interval:	30 * HZ,
+	gc_thresh1:	128,
+	gc_thresh2:	512,
+	gc_thresh3:	1024,
 };
 
 int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir)
@@ -194,10 +196,10 @@
 	case ARPHRD_ETHER:
 	case ARPHRD_FDDI:
 	case ARPHRD_IEEE802:
-		ip_eth_mc_map(addr, haddr) ; 
-		return 0 ; 
+		ip_eth_mc_map(addr, haddr);
+		return 0; 
 	case ARPHRD_IEEE802_TR:
-		ip_tr_mc_map(addr, haddr) ; 
+		ip_tr_mc_map(addr, haddr);
 		return 0;
 	default:
 		if (dir) {
@@ -1162,13 +1164,10 @@
  *	Called once on startup.
  */
 
-static struct packet_type arp_packet_type =
-{
-	__constant_htons(ETH_P_ARP),
-	NULL,		/* All devices */
-	arp_rcv,
-	(void*)1,
-	NULL
+static struct packet_type arp_packet_type = {
+	type:	__constant_htons(ETH_P_ARP),
+	func:	arp_rcv,
+	data:	(void*) 1, /* understand shared skbs */
 };
 
 void __init arp_init (void)
diff -urN linux-2.4.5-pre1/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- linux-2.4.5-pre1/net/ipv4/fib_frontend.c	Wed Dec 22 19:55:38 1999
+++ linux/net/ipv4/fib_frontend.c	Mon Dec  3 22:41:47 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: FIB frontend.
  *
- * Version:	$Id: fib_frontend.c,v 1.21 1999/12/15 22:39:07 davem Exp $
+ * Version:	$Id: fib_frontend.c,v 1.23 2001/05/01 23:21:37 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -569,9 +569,9 @@
 #undef BRD1_OK
 }
 
-static void fib_disable_ip(struct net_device *dev, int force)
+static void fib_disable_ip(struct net_device *dev, u32 addr, int force)
 {
-	if (fib_sync_down(0, dev, force))
+	if (fib_sync_down(addr, dev, force))
 		fib_flush();
 	rt_cache_flush(0);
 	arp_ifdown(dev);
@@ -591,7 +591,7 @@
 			/* Last address was deleted from this interface.
 			   Disable IP.
 			 */
-			fib_disable_ip(ifa->ifa_dev->dev, 1);
+			fib_disable_ip(ifa->ifa_dev->dev, ifa->ifa_local, 1);
 		} else {
 			fib_del_ifaddr(ifa);
 			rt_cache_flush(-1);
@@ -620,10 +620,10 @@
 		rt_cache_flush(-1);
 		break;
 	case NETDEV_DOWN:
-		fib_disable_ip(dev, 0);
+		fib_disable_ip(dev, 0, 0);
 		break;
 	case NETDEV_UNREGISTER:
-		fib_disable_ip(dev, 1);
+		fib_disable_ip(dev, 0, 1);
 		break;
 	case NETDEV_CHANGEMTU:
 	case NETDEV_CHANGE:
@@ -634,15 +634,11 @@
 }
 
 struct notifier_block fib_inetaddr_notifier = {
-	fib_inetaddr_event,
-	NULL,
-	0
+	notifier_call:	fib_inetaddr_event,
 };
 
 struct notifier_block fib_netdev_notifier = {
-	fib_netdev_event,
-	NULL,
-	0
+	notifier_call:	fib_netdev_event,
 };
 
 void __init ip_fib_init(void)
diff -urN linux-2.4.5-pre1/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
--- linux-2.4.5-pre1/net/ipv4/fib_rules.c	Mon Apr 24 13:59:56 2000
+++ linux/net/ipv4/fib_rules.c	Mon Dec  3 22:41:47 2001
@@ -5,7 +5,7 @@
  *
  *		IPv4 Forwarding Information Base: policy rules.
  *
- * Version:	$Id: fib_rules.c,v 1.15 2000/04/15 01:48:10 davem Exp $
+ * Version:	$Id: fib_rules.c,v 1.16 2001/04/30 04:39:14 davem Exp $
  *
  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -76,9 +76,27 @@
 	int		r_dead;
 };
 
-static struct fib_rule default_rule = { NULL, ATOMIC_INIT(2), 0x7FFF, RT_TABLE_DEFAULT, RTN_UNICAST, };
-static struct fib_rule main_rule = { &default_rule, ATOMIC_INIT(2), 0x7FFE, RT_TABLE_MAIN, RTN_UNICAST, };
-static struct fib_rule local_rule = { &main_rule, ATOMIC_INIT(2), 0, RT_TABLE_LOCAL, RTN_UNICAST, };
+static struct fib_rule default_rule = {
+	r_clntref:	ATOMIC_INIT(2),
+	r_preference:	0x7FFF,
+	r_table:	RT_TABLE_DEFAULT,
+	r_action:	RTN_UNICAST,
+};
+
+static struct fib_rule main_rule = {
+	r_next:		&default_rule,
+	r_clntref:	ATOMIC_INIT(2),
+	r_preference:	0x7FFE,
+	r_table:	RT_TABLE_MAIN,
+	r_action:	RTN_UNICAST,
+};
+
+static struct fib_rule local_rule = {
+	r_next:		&main_rule,
+	r_clntref:	ATOMIC_INIT(2),
+	r_table:	RT_TABLE_LOCAL,
+	r_action:	RTN_UNICAST,
+};
 
 static struct fib_rule *fib_rules = &local_rule;
 static rwlock_t fib_rules_lock = RW_LOCK_UNLOCKED;
@@ -374,9 +392,7 @@
 
 
 struct notifier_block fib_rules_notifier = {
-	fib_rules_event,
-	NULL,
-	0
+	notifier_call:	fib_rules_event,
 };
 
 #ifdef CONFIG_RTNETLINK
diff -urN linux-2.4.5-pre1/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- linux-2.4.5-pre1/net/ipv4/icmp.c	Thu Apr 19 08:38:50 2001
+++ linux/net/ipv4/icmp.c	Mon Dec  3 22:41:47 2001
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.74 2001/04/16 23:58:51 davem Exp $
+ *	Version: $Id: icmp.c,v 1.75 2001/04/30 04:40:40 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -139,11 +139,11 @@
 };
 
 /* Control parameters for ECHO relies. */
-int sysctl_icmp_echo_ignore_all = 0;
-int sysctl_icmp_echo_ignore_broadcasts = 0;
+int sysctl_icmp_echo_ignore_all;
+int sysctl_icmp_echo_ignore_broadcasts;
 
 /* Control parameter - ignore bogus broadcast responses? */
-int sysctl_icmp_ignore_bogus_error_responses =0;
+int sysctl_icmp_ignore_bogus_error_responses;
 
 /*
  *	ICMP control array. This specifies what to do with each ICMP.
@@ -167,7 +167,7 @@
  */
 	
 struct inode icmp_inode;
-struct socket *icmp_socket=&icmp_inode.u.socket_i;
+struct socket *icmp_socket = &icmp_inode.u.socket_i;
 
 /* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
    which is strongly non-reenterable). A bit later it will be made
@@ -651,7 +651,7 @@
 	 */
 
 	ipprot = (struct inet_protocol *) inet_protos[hash];
-	while(ipprot != NULL) {
+	while (ipprot) {
 		struct inet_protocol *nextip;
 
 		nextip = (struct inet_protocol *) ipprot->next;
@@ -695,7 +695,7 @@
 	iph = (struct iphdr *) skb->data;
 	ip = iph->daddr;
 
-	switch(skb->h.icmph->code & 7) {
+	switch (skb->h.icmph->code & 7) {
 		case ICMP_REDIR_NET:
 		case ICMP_REDIR_NETTOS:
 			/*
@@ -753,7 +753,7 @@
 	 *	Too short.
 	 */
 	 
-	if(skb->len<4) {
+	if (skb->len < 4) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
@@ -945,7 +945,7 @@
 int sysctl_icmp_destunreach_time = 1*HZ;
 int sysctl_icmp_timeexceed_time = 1*HZ;
 int sysctl_icmp_paramprob_time = 1*HZ;
-int sysctl_icmp_echoreply_time = 0; /* don't limit it per default. */
+int sysctl_icmp_echoreply_time; /* don't limit it per default. */
 
 /*
  *	This table is the definition of how we handle ICMP.
diff -urN linux-2.4.5-pre1/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- linux-2.4.5-pre1/net/ipv4/ipconfig.c	Fri Feb  9 11:34:13 2001
+++ linux/net/ipv4/ipconfig.c	Mon Dec  3 22:41:47 2001
@@ -1,10 +1,10 @@
 /*
- *  $Id: ipconfig.c,v 1.35 2000/12/30 06:46:36 davem Exp $
+ *  $Id: ipconfig.c,v 1.37 2001/04/30 18:54:12 davem Exp $
  *
- *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
- *  information to configure own IP address and routes.
+ *  Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or
+ *  user-supplied information to configure own IP address and routes.
  *
- *  Copyright (C) 1996--1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *  Copyright (C) 1996-1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  *
  *  Derived from network configuration code in fs/nfs/nfsroot.c,
  *  originally Copyright (C) 1995, 1996 Gero Kuhlmann and me.
@@ -16,6 +16,16 @@
  *  Fixed ip_auto_config_setup calling at startup in the new "Linker Magic"
  *  initialization scheme.
  *	- Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 08/11/1999
+ *
+ *  DHCP support added.  To users this looks like a whole separate
+ *  protocol, but we know it's just a bag on the side of BOOTP.
+ *		-- Chip Salzenberg <chip@valinux.com>, May 2000
+ *
+ *  Ported DHCP support from 2.2.16 to 2.4.0-test4
+ *              -- Eric Biederman <ebiederman@lnxi.com>, 30 Aug 2000
+ *
+ *  Merged changes from 2.2.19 into 2.4.3
+ *              -- Eric Biederman <ebiederman@lnxi.com>, 22 April Aug 2001
  */
 
 #include <linux/config.h>
@@ -36,6 +46,7 @@
 #include <linux/socket.h>
 #include <linux/route.h>
 #include <linux/udp.h>
+#include <linux/proc_fs.h>
 #include <net/arp.h>
 #include <net/ip.h>
 #include <net/ipconfig.h>
@@ -52,48 +63,94 @@
 #define DBG(x) do { } while(0)
 #endif
 
-/* Define the timeout for waiting for a RARP/BOOTP reply */
-#define CONF_BASE_TIMEOUT	(HZ*5)	/* Initial timeout: 5 seconds */
-#define CONF_RETRIES	 	10	/* 10 retries */
+#if defined(CONFIG_IP_PNP_DHCP)
+#define IPCONFIG_DHCP
+#endif
+#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP)
+#define IPCONFIG_BOOTP
+#endif
+#if defined(CONFIG_IP_PNP_RARP)
+#define IPCONFIG_RARP
+#endif
+#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP)
+#define IPCONFIG_DYNAMIC
+#endif
+
+/* Define the friendly delay before and after opening net devices */
+#define CONF_PRE_OPEN		(HZ/2)	/* Before opening: 1/2 second */
+#define CONF_POST_OPEN		(1*HZ)	/* After opening: 1 second */
+
+/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */
+#define CONF_OPEN_RETRIES 	2	/* (Re)open devices twice */
+#define CONF_SEND_RETRIES 	6	/* Send six requests per open */
+#define CONF_INTER_TIMEOUT	(HZ/2)	/* Inter-device timeout: 1/2 second */
+#define CONF_BASE_TIMEOUT	(HZ*2)	/* Initial timeout: 2 seconds */
 #define CONF_TIMEOUT_RANDOM	(HZ)	/* Maximum amount of randomization */
-#define CONF_TIMEOUT_MULT	*5/4	/* Rate of timeout growth */
+#define CONF_TIMEOUT_MULT	*7/4	/* Rate of timeout growth */
 #define CONF_TIMEOUT_MAX	(HZ*30)	/* Maximum allowed timeout */
 
-/* IP configuration */
-static char user_dev_name[IFNAMSIZ] __initdata = { 0, };/* Name of user-selected boot device */
-u32 ic_myaddr __initdata = INADDR_NONE;		/* My IP address */
-u32 ic_servaddr __initdata = INADDR_NONE;	/* Server IP address */
-u32 ic_gateway __initdata = INADDR_NONE;	/* Gateway IP address */
-u32 ic_netmask __initdata = INADDR_NONE;	/* Netmask for local subnet */
-int ic_enable __initdata = 1;			/* Automatic IP configuration enabled */
-int ic_host_name_set __initdata = 0;		/* Host name configured manually */
-int ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
 
-u32 root_server_addr __initdata = INADDR_NONE;		/* Address of boot server */
-u8 root_server_path[256] __initdata = { 0, };		/* Path to mount as root */
+/*
+ * Public IP configuration
+ */
 
-#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_RARP)
+/* This is used by platforms which might be able to set the ipconfig
+ * variabled using firmware environment vars.  If this is set, it will
+ * ignore such firmware variables.
+ */
+int ic_set_manually __initdata = 0;		/* IPconfig parameters set manually */
 
-#define CONFIG_IP_PNP_DYNAMIC
+int ic_enable __initdata = 0;			/* IP config enabled? */
 
-int ic_proto_enabled __initdata = 0			/* Protocols enabled */
-#ifdef CONFIG_IP_PNP_BOOTP
+/* Protocol choice */
+int ic_proto_enabled __initdata = 0
+#ifdef IPCONFIG_BOOTP
 			| IC_BOOTP
 #endif
-#ifdef CONFIG_IP_PNP_RARP
+#ifdef CONFIG_IP_PNP_DHCP
+			| IC_USE_DHCP
+#endif
+#ifdef IPCONFIG_RARP
 			| IC_RARP
 #endif
 			;
-static int ic_got_reply __initdata = 0;				/* Protocol(s) we got reply from */
 
-#else
+int ic_host_name_set __initdata = 0;		/* Host name set by us? */
 
-static int ic_proto_enabled __initdata = 0;
+u32 ic_myaddr __initdata = INADDR_NONE;		/* My IP address */
+u32 ic_netmask __initdata = INADDR_NONE;	/* Netmask for local subnet */
+u32 ic_gateway __initdata = INADDR_NONE;	/* Gateway IP address */
 
-#endif
+u32 ic_servaddr __initdata = INADDR_NONE;	/* Boot server IP address */
 
+u32 root_server_addr __initdata = INADDR_NONE;	/* Address of NFS server */
+u8 root_server_path[256] __initdata = { 0, };	/* Path to mount as root */
+
+/* Persistent data: */
+
+int ic_proto_used;			/* Protocol used, if any */
+u32 ic_nameserver = INADDR_NONE;	/* DNS Server IP address */
+u8 ic_domain[64];		/* DNS (not NIS) domain name */
+
+/*
+ * Private state.
+ */
+
+/* Name of user-selected boot device */
+static char user_dev_name[IFNAMSIZ] __initdata = { 0, };
+
+/* Protocols supported by available interfaces */
 static int ic_proto_have_if __initdata = 0;
 
+#ifdef IPCONFIG_DYNAMIC
+static spinlock_t ic_recv_lock = SPIN_LOCK_UNLOCKED;
+static volatile int ic_got_reply __initdata = 0;    /* Proto(s) that replied */
+#endif
+#ifdef IPCONFIG_DHCP
+static int ic_dhcp_msgtype __initdata = 0;	/* DHCP msg type received */
+#endif
+
+
 /*
  *	Network devices
  */
@@ -102,11 +159,12 @@
 	struct ic_device *next;
 	struct net_device *dev;
 	unsigned short flags;
-	int able;
+	short able;
+	u32 xid;
 };
 
 static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
-static struct net_device *ic_dev __initdata = NULL;		/* Selected device */
+static struct net_device *ic_dev __initdata = NULL;	/* Selected device */
 
 static int __init ic_open_devs(void)
 {
@@ -125,7 +183,7 @@
 			if (dev->mtu >= 364)
 				able |= IC_BOOTP;
 			else
-				printk(KERN_WARNING "BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
+				printk(KERN_WARNING "DHCP/BOOTP: Ignoring device %s, MTU %d too small", dev->name, dev->mtu);
 			if (!(dev->flags & IFF_NOARP))
 				able |= IC_RARP;
 			able &= ic_proto_enabled;
@@ -143,8 +201,13 @@
 			last = &d->next;
 			d->flags = oflags;
 			d->able = able;
+			if (able & IC_BOOTP)
+				get_random_bytes(&d->xid, sizeof(u32));
+			else
+				d->xid = 0;
 			ic_proto_have_if |= able;
-			DBG(("IP-Config: Opened %s (able=%d)\n", dev->name, able));
+			DBG(("IP-Config: %s UP (able=%d, xid=%08x)\n",
+				dev->name, able, d->xid));
 		}
 	}
 	rtnl_shunlock();
@@ -282,18 +345,18 @@
 	 */
 	 
 	if (!ic_host_name_set)
-		strcpy(system_utsname.nodename, in_ntoa(ic_myaddr));
+		sprintf(system_utsname.nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
 
 	if (root_server_addr == INADDR_NONE)
 		root_server_addr = ic_servaddr;
 
 	if (ic_netmask == INADDR_NONE) {
 		if (IN_CLASSA(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSA_NET);
+			ic_netmask = __constant_htonl(IN_CLASSA_NET);
 		else if (IN_CLASSB(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSB_NET);
+			ic_netmask = __constant_htonl(IN_CLASSB_NET);
 		else if (IN_CLASSC(ntohl(ic_myaddr)))
-			ic_netmask = htonl(IN_CLASSC_NET);
+			ic_netmask = __constant_htonl(IN_CLASSC_NET);
 		else {
 			printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n",
 				NIPQUAD(ic_myaddr));
@@ -309,16 +372,13 @@
  *	RARP support.
  */
 
-#ifdef CONFIG_IP_PNP_RARP
+#ifdef IPCONFIG_RARP
 
 static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);
 
 static struct packet_type rarp_packet_type __initdata = {
-	__constant_htons(ETH_P_RARP),
-	NULL,			/* Listen to all devices */
-	ic_rarp_recv,
-	NULL,
-	NULL
+	type:	__constant_htons(ETH_P_RARP),
+	func:	ic_rarp_recv,
 };
 
 static inline void ic_rarp_init(void)
@@ -341,21 +401,32 @@
 	unsigned char *rarp_ptr = (unsigned char *) (rarp + 1);
 	unsigned long sip, tip;
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
+	struct ic_device *d;
+
+	/* One reply at a time, please. */
+	spin_lock(&ic_recv_lock);
 
 	/* If we already have a reply, just drop the packet */
 	if (ic_got_reply)
 		goto drop;
 
+	/* Find the ic_device that the packet arrived on */
+	d = ic_first_dev;
+	while (d && d->dev != dev)
+		d = d->next;
+	if (!d)
+		goto drop;	/* should never happen */
+
 	/* If this test doesn't pass, it's not IP, or we should ignore it anyway */
 	if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd))
 		goto drop;
 
 	/* If it's not a RARP reply, delete it. */
-	if (rarp->ar_op != htons(ARPOP_RREPLY))
+	if (rarp->ar_op != __constant_htons(ARPOP_RREPLY))
 		goto drop;
 
 	/* If it's not Ethernet, delete it. */
-	if (rarp->ar_pro != htons(ETH_P_IP))
+	if (rarp->ar_pro != __constant_htons(ETH_P_IP))
 		goto drop;
 
 	/* Extract variable-width fields */
@@ -375,44 +446,39 @@
 	if (ic_servaddr != INADDR_NONE && ic_servaddr != sip)
 		goto drop;
 
-	/* Victory! The packet is what we were looking for! */
-	if (!ic_got_reply) {
-		ic_got_reply = IC_RARP;
-		ic_dev = dev;
-		if (ic_myaddr == INADDR_NONE)
-			ic_myaddr = tip;
-		ic_servaddr = sip;
-	}
+	/* We have a winner! */
+	ic_dev = dev;
+	if (ic_myaddr == INADDR_NONE)
+		ic_myaddr = tip;
+	ic_servaddr = sip;
+	ic_got_reply = IC_RARP;
 
-	/* And throw the packet out... */
 drop:
+	/* Show's over.  Nothing to see here.  */
+	spin_unlock(&ic_recv_lock);
+
+	/* Throw the packet out. */
 	kfree_skb(skb);
 	return 0;
 }
 
 
 /*
- *  Send RARP request packet over all devices which allow RARP.
+ *  Send RARP request packet over a signle interface.
  */
-static void __init ic_rarp_send(void)
+static void __init ic_rarp_send_if(struct ic_device *d)
 {
-	struct ic_device *d;
-
-	for (d=ic_first_dev; d; d=d->next)
-		if (d->able & IC_RARP) {
-			struct net_device *dev = d->dev;
-			arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
-				 dev->dev_addr, dev->dev_addr);
-		}
+	struct net_device *dev = d->dev;
+	arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL,
+		 dev->dev_addr, dev->dev_addr);
 }
-
 #endif
 
 /*
- *	BOOTP support.
+ *	DHCP/BOOTP support.
  */
 
-#ifdef CONFIG_IP_PNP_BOOTP
+#ifdef IPCONFIG_BOOTP
 
 struct bootp_pkt {		/* BOOTP packet format */
 	struct iphdr iph;	/* IP header */
@@ -426,45 +492,110 @@
 	u16 flags;		/* Just what it says */
 	u32 client_ip;		/* Client's IP address if known */
 	u32 your_ip;		/* Assigned IP address */
-	u32 server_ip;		/* Server's IP address */
+	u32 server_ip;		/* (Next, e.g. NFS) Server's IP address */
 	u32 relay_ip;		/* IP address of BOOTP relay */
 	u8 hw_addr[16];		/* Client's HW address */
 	u8 serv_name[64];	/* Server host name */
 	u8 boot_file[128];	/* Name of boot file */
-	u8 vendor_area[128];	/* Area for extensions */
+	u8 exten[312];		/* DHCP options / BOOTP vendor extensions */
 };
 
-#define BOOTP_REQUEST 1
-#define BOOTP_REPLY 2
-
-static u32 ic_bootp_xid;
+/* packet ops */
+#define BOOTP_REQUEST	1
+#define BOOTP_REPLY	2
+
+/* DHCP message types */
+#define DHCPDISCOVER	1
+#define DHCPOFFER	2
+#define DHCPREQUEST	3
+#define DHCPDECLINE	4
+#define DHCPACK		5
+#define DHCPNAK		6
+#define DHCPRELEASE	7
+#define DHCPINFORM	8
 
 static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt);
 
 static struct packet_type bootp_packet_type __initdata = {
-	__constant_htons(ETH_P_IP),
-	NULL,			/* Listen to all devices */
-	ic_bootp_recv,
-	NULL,
-	NULL
+	type:	__constant_htons(ETH_P_IP),
+	func:	ic_bootp_recv,
 };
 
 
 /*
- *  Initialize BOOTP extension fields in the request.
+ *  Initialize DHCP/BOOTP extension fields in the request.
  */
+
+static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };
+
+#ifdef IPCONFIG_DHCP
+
+static void __init
+ic_dhcp_init_options(u8 *options)
+{
+	u8 mt = ((ic_servaddr == INADDR_NONE)
+		 ? DHCPDISCOVER : DHCPREQUEST);
+	u8 *e = options;
+
+#ifdef IPCONFIG_DEBUG
+	printk("DHCP: Sending message type %d\n", mt);
+#endif
+
+	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
+	e += 4;
+
+	*e++ = 53;		/* DHCP message type */
+	*e++ = 1;
+	*e++ = mt;
+
+	if (mt == DHCPREQUEST) {
+		*e++ = 54;	/* Server ID (IP address) */
+		*e++ = 4;
+		memcpy(e, &ic_servaddr, 4);
+		e += 4;
+
+		*e++ = 50;	/* Requested IP address */
+		*e++ = 4;
+		memcpy(e, &ic_myaddr, 4);
+		e += 4;
+	}
+
+	/* always? */
+	{
+		static const u8 ic_req_params[] = {
+			1,	/* Subnet mask */
+			3,	/* Default gateway */
+			6,	/* DNS server */
+			12,	/* Host name */
+			15,	/* Domain name */
+			17,	/* Boot path */
+			40,	/* NIS domain name */
+		};
+
+		*e++ = 55;	/* Parameter request list */
+		*e++ = sizeof(ic_req_params);
+		memcpy(e, ic_req_params, sizeof(ic_req_params));
+		e += sizeof(ic_req_params);
+	}
+
+	*e++ = 255;	/* End of the list */
+}
+
+#endif /* IPCONFIG_DHCP */
+
 static void __init ic_bootp_init_ext(u8 *e)
 {
-	*e++ = 99;		/* RFC1048 Magic Cookie */
-	*e++ = 130;
-	*e++ = 83;
-	*e++ = 99;
+	memcpy(e, ic_bootp_cookie, 4);	/* RFC1048 Magic Cookie */
+	e += 4;
 	*e++ = 1;		/* Subnet mask request */
 	*e++ = 4;
 	e += 4;
 	*e++ = 3;		/* Default gateway request */
 	*e++ = 4;
 	e += 4;
+	*e++ = 5;		/* Name server reqeust */
+	*e++ = 8;
+	e += 8;
 	*e++ = 12;		/* Host name request */
 	*e++ = 32;
 	e += 32;
@@ -472,25 +603,23 @@
 	*e++ = 32;
 	e += 32;
 	*e++ = 17;		/* Boot path */
-	*e++ = 32;
-	e += 32;
-	*e = 255;		/* End of the list */
+	*e++ = 40;
+	e += 40;
+	*e++ = 255;		/* End of the list */
 }
 
 
 /*
- *  Initialize the BOOTP mechanism.
+ *  Initialize the DHCP/BOOTP mechanism.
  */
 static inline void ic_bootp_init(void)
 {
-	get_random_bytes(&ic_bootp_xid, sizeof(u32));
-	DBG(("BOOTP: XID=%08x\n", ic_bootp_xid));
 	dev_add_pack(&bootp_packet_type);
 }
 
 
 /*
- *  BOOTP cleanup.
+ *  DHCP/BOOTP cleanup.
  */
 static inline void ic_bootp_cleanup(void)
 {
@@ -499,7 +628,7 @@
 
 
 /*
- *  Send BOOTP request to single interface.
+ *  Send DHCP/BOOTP request to single interface.
  */
 static void __init ic_bootp_send_if(struct ic_device *d, u32 jiffies)
 {
@@ -522,19 +651,19 @@
 	h->version = 4;
 	h->ihl = 5;
 	h->tot_len = htons(sizeof(struct bootp_pkt));
-	h->frag_off = htons(IP_DF);
+	h->frag_off = __constant_htons(IP_DF);
 	h->ttl = 64;
 	h->protocol = IPPROTO_UDP;
 	h->daddr = INADDR_BROADCAST;
 	h->check = ip_fast_csum((unsigned char *) h, h->ihl);
 
 	/* Construct UDP header */
-	b->udph.source = htons(68);
-	b->udph.dest = htons(67);
+	b->udph.source = __constant_htons(68);
+	b->udph.dest = __constant_htons(67);
 	b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr));
 	/* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */
 
-	/* Construct BOOTP header */
+	/* Construct DHCP/BOOTP header */
 	b->op = BOOTP_REQUEST;
 	if (dev->type < 256) /* check for false types */
 		b->htype = dev->type;
@@ -545,10 +674,19 @@
 		b->htype = dev->type; /* can cause undefined behavior */
 	}
 	b->hlen = dev->addr_len;
+	b->your_ip = INADDR_NONE;
+	b->server_ip = INADDR_NONE;
 	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
 	b->secs = htons(jiffies / HZ);
-	b->xid = ic_bootp_xid;
-	ic_bootp_init_ext(b->vendor_area);
+	b->xid = d->xid;
+
+	/* add DHCP options or BOOTP extensions */
+#ifdef IPCONFIG_DHCP
+	if (ic_proto_enabled & IC_USE_DHCP)
+		ic_dhcp_init_options(b->exten);
+	else
+#endif
+		ic_bootp_init_ext(b->exten);
 
 	/* Chain packet down the line... */
 	skb->dev = dev;
@@ -561,19 +699,6 @@
 
 
 /*
- *  Send BOOTP requests to all interfaces.
- */
-static void __init ic_bootp_send(u32 jiffies)
-{
-	struct ic_device *d;
-
-	for(d=ic_first_dev; d; d=d->next)
-		if (d->able & IC_BOOTP)
-			ic_bootp_send_if(d, jiffies);
-}
-
-
-/*
  *  Copy BOOTP-supplied string if not already set.
  */
 static int __init ic_bootp_string(char *dest, char *src, int len, int max)
@@ -582,21 +707,21 @@
 		return 0;
 	if (len > max-1)
 		len = max-1;
-	strncpy(dest, src, len);
+	memcpy(dest, src, len);
 	dest[len] = '\0';
 	return 1;
 }
 
 
 /*
- *  Process BOOTP extension.
+ *  Process BOOTP extensions.
  */
 static void __init ic_do_bootp_ext(u8 *ext)
 {
 #ifdef IPCONFIG_DEBUG
 	u8 *c;
 
-	printk("BOOTP: Got extension %02x",*ext);
+	printk("DHCP/BOOTP: Got extension %d:",*ext);
 	for(c=ext+2; c<ext+2+ext[1]; c++)
 		printk(" %02x", *c);
 	printk("\n");
@@ -611,17 +736,24 @@
 			if (ic_gateway == INADDR_NONE)
 				memcpy(&ic_gateway, ext+1, 4);
 			break;
+		case 6:		/* DNS server */
+			if (ic_nameserver == INADDR_NONE)
+				memcpy(&ic_nameserver, ext+1, 4);
+			break;
 		case 12:	/* Host name */
 			ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
 			ic_host_name_set = 1;
 			break;
-		case 40:	/* NIS Domain name */
-			ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
+		case 15:	/* Domain name (DNS) */
+			ic_bootp_string(ic_domain, ext+1, *ext, sizeof(ic_domain));
 			break;
 		case 17:	/* Root path */
 			if (!root_server_path[0])
 				ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
 			break;
+		case 40:	/* NIS Domain name (_not_ DNS) */
+			ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
+			break;
 	}
 }
 
@@ -633,12 +765,23 @@
 {
 	struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph;
 	struct iphdr *h = &b->iph;
+	struct ic_device *d;
 	int len;
 
+	/* One reply at a time, please. */
+	spin_lock(&ic_recv_lock);
+
 	/* If we already have a reply, just drop the packet */
 	if (ic_got_reply)
 		goto drop;
 
+	/* Find the ic_device that the packet arrived on */
+	d = ic_first_dev;
+	while (d && d->dev != dev)
+		d = d->next;
+	if (!d)
+		goto drop;  /* should never happen */
+
 	/* Check whether it's a BOOTP packet */
 	if (skb->pkt_type == PACKET_OTHERHOST ||
 	    skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) ||
@@ -647,14 +790,14 @@
 	    ip_fast_csum((char *) h, h->ihl) != 0 ||
 	    skb->len < ntohs(h->tot_len) ||
 	    h->protocol != IPPROTO_UDP ||
-	    b->udph.source != htons(67) ||
-	    b->udph.dest != htons(68) ||
+	    b->udph.source != __constant_htons(67) ||
+	    b->udph.dest != __constant_htons(68) ||
 	    ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr))
 		goto drop;
 
 	/* Fragments are not supported */
-	if (h->frag_off & htons(IP_OFFSET|IP_MF)) {
-		printk(KERN_ERR "BOOTP: Ignoring fragmented reply.\n");
+	if (h->frag_off & __constant_htons(IP_OFFSET | IP_MF)) {
+		printk(KERN_ERR "DHCP/BOOTP: Ignoring fragmented reply.\n");
 		goto drop;
 	}
 
@@ -662,41 +805,103 @@
 	len = ntohs(b->udph.len) - sizeof(struct udphdr);
 	if (len < 300 ||				    /* See RFC 951:2.1 */
 	    b->op != BOOTP_REPLY ||
-	    b->xid != ic_bootp_xid) {
+	    b->xid != d->xid) {
 		printk("?");
 		goto drop;
 	}
 
-	/* Extract basic fields */
-	ic_myaddr = b->your_ip;
-	ic_servaddr = b->server_ip;
-	ic_got_reply = IC_BOOTP;
-	ic_dev = dev;
-
 	/* Parse extensions */
-	if (b->vendor_area[0] == 99 &&	/* Check magic cookie */
-	    b->vendor_area[1] == 130 &&
-	    b->vendor_area[2] == 83 &&
-	    b->vendor_area[3] == 99) {
-		u8 *ext = &b->vendor_area[4];
+	if (!memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */
                 u8 *end = (u8 *) b + ntohs(b->iph.tot_len);
+		u8 *ext;
+
+#ifdef IPCONFIG_DHCP
+
+		u32 server_id = INADDR_NONE;
+		int mt = 0;
+
+		ext = &b->exten[4];
 		while (ext < end && *ext != 0xff) {
-			if (*ext == 0)		/* Padding */
-				ext++;
-			else {
-				u8 *opt = ext;
-				ext += ext[1] + 2;
-				if (ext <= end)
-					ic_do_bootp_ext(opt);
+			u8 *opt = ext++;
+			if (*opt == 0)	/* Padding */
+				continue;
+			ext += *ext + 1;
+			if (ext >= end)
+				break;
+			switch (*opt) {
+			case 53:	/* Message type */
+				if (opt[1])
+					mt = opt[2];
+				break;
+			case 54:	/* Server ID (IP address) */
+				if (opt[1] >= 4)
+					memcpy(&server_id, opt + 2, 4);
+				break;
 			}
 		}
+
+#ifdef IPCONFIG_DEBUG
+		printk("DHCP: Got message type %d\n", mt);
+#endif
+
+		switch (mt) {
+		    case DHCPOFFER:
+			/* While in the process of accepting one offer,
+			   ignore all others. */
+			if (ic_myaddr != INADDR_NONE)
+				goto drop;
+			/* Let's accept that offer. */
+			ic_myaddr = b->your_ip;
+			ic_servaddr = server_id;
+#ifdef IPCONFIG_DEBUG
+			printk("DHCP: Offered address %u.%u.%u.%u", NIPQUAD(ic_myaddr));
+			printk(" by server %u.%u.%u.%u\n", NIPQUAD(ic_servaddr));
+#endif
+			break;
+
+		    case DHCPACK:
+			/* Yeah! */
+			break;
+
+		    default:
+			/* Urque.  Forget it*/
+			ic_myaddr = INADDR_NONE;
+			ic_servaddr = INADDR_NONE;
+			goto drop;
+		}
+
+		ic_dhcp_msgtype = mt;
+
+#endif /* IPCONFIG_DHCP */
+
+		ext = &b->exten[4];
+		while (ext < end && *ext != 0xff) {
+			u8 *opt = ext++;
+			if (*opt == 0)	/* Padding */
+				continue;
+			ext += *ext + 1;
+			if (ext < end)
+				ic_do_bootp_ext(opt);
+		}
 	}
 
+	/* We have a winner! */
+	ic_dev = dev;
+	ic_myaddr = b->your_ip;
+	ic_servaddr = b->server_ip;
 	if (ic_gateway == INADDR_NONE && b->relay_ip)
 		ic_gateway = b->relay_ip;
+	if (ic_nameserver == INADDR_NONE)
+		ic_nameserver = ic_servaddr;
+	ic_got_reply = IC_BOOTP;
 
 drop:
+	/* Show's over.  Nothing to see here.  */
+	spin_unlock(&ic_recv_lock);
+
+	/* Throw the packet out. */
 	kfree_skb(skb);
+
 	return 0;
 }	
 
@@ -705,36 +910,34 @@
 
 
 /*
- *	Dynamic IP configuration -- BOOTP and RARP.
+ *	Dynamic IP configuration -- DHCP, BOOTP, RARP.
  */
 
-#ifdef CONFIG_IP_PNP_DYNAMIC
+#ifdef IPCONFIG_DYNAMIC
 
 static int __init ic_dynamic(void)
 {
 	int retries;
-	unsigned long timeout, jiff;
-	unsigned long start_jiffies;
-	int do_rarp = ic_proto_have_if & IC_RARP;
+	struct ic_device *d;
+	unsigned long start_jiffies, timeout, jiff;
 	int do_bootp = ic_proto_have_if & IC_BOOTP;
+	int do_rarp = ic_proto_have_if & IC_RARP;
 
 	/*
-	 * If neither BOOTP nor RARP was selected, return with an error. This
-	 * routine gets only called when some pieces of information are mis-
-	 * sing, and without BOOTP and RARP we are not able to get that in-
-	 * formation.
+	 * If none of DHCP/BOOTP/RARP was selected, return with an error.
+	 * This routine gets only called when some pieces of information
+	 * are missing, and without DHCP/BOOTP/RARP we are unable to get it.
 	 */
 	if (!ic_proto_enabled) {
 		printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
 		return -1;
 	}
 
-#ifdef CONFIG_IP_PNP_BOOTP
+#ifdef IPCONFIG_BOOTP
 	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP)
-		printk(KERN_ERR "BOOTP: No suitable device found.\n");
+		printk(KERN_ERR "DHCP/BOOTP: No suitable device found.\n");
 #endif
-
-#ifdef CONFIG_IP_PNP_RARP
+#ifdef IPCONFIG_RARP
 	if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP)
 		printk(KERN_ERR "RARP: No suitable device found.\n");
 #endif
@@ -744,16 +947,16 @@
 		return -1;
 
 	/*
-	 * Setup RARP and BOOTP protocols
+	 * Setup protocols
 	 */
-#ifdef CONFIG_IP_PNP_RARP
-	if (do_rarp)
-		ic_rarp_init();
-#endif
-#ifdef CONFIG_IP_PNP_BOOTP
+#ifdef IPCONFIG_BOOTP
 	if (do_bootp)
 		ic_bootp_init();
 #endif
+#ifdef IPCONFIG_RARP
+	if (do_rarp)
+		ic_rarp_init();
+#endif
 
 	/*
 	 * Send requests and wait, until we get an answer. This loop
@@ -763,61 +966,119 @@
 	 * [Actually we could now, but the nothing else running note still 
 	 *  applies.. - AC]
 	 */
-	printk(KERN_NOTICE "Sending %s%s%s requests...",
-	        do_bootp ? "BOOTP" : "",
-		do_bootp && do_rarp ? " and " : "",
-		do_rarp ? "RARP" : "");
+	printk(KERN_NOTICE "Sending %s%s%s requests .",
+	       do_bootp
+		? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "",
+	       (do_bootp && do_rarp) ? " and " : "",
+	       do_rarp ? "RARP" : "");
+
 	start_jiffies = jiffies;
-	retries = CONF_RETRIES;
+	d = ic_first_dev;
+	retries = CONF_SEND_RETRIES;
 	get_random_bytes(&timeout, sizeof(timeout));
 	timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM);
 	for(;;) {
-#ifdef CONFIG_IP_PNP_BOOTP
-		if (do_bootp)
-			ic_bootp_send(jiffies - start_jiffies);
+#ifdef IPCONFIG_BOOTP
+		if (do_bootp && (d->able & IC_BOOTP))
+			ic_bootp_send_if(d, jiffies - start_jiffies);
 #endif
-#ifdef CONFIG_IP_PNP_RARP
-		if (do_rarp)
-			ic_rarp_send();
+#ifdef IPCONFIG_RARP
+		if (do_rarp && (d->able & IC_RARP))
+			ic_rarp_send_if(d);
 #endif
-		printk(".");
-		jiff = jiffies + timeout;
+
+		jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
 		while (jiffies < jiff && !ic_got_reply)
 			barrier();
+#ifdef IPCONFIG_DHCP
+		/* DHCP isn't done until we get a DHCPACK. */
+		if ((ic_got_reply & IC_BOOTP)
+		    && (ic_proto_enabled & IC_USE_DHCP)
+		    && ic_dhcp_msgtype != DHCPACK)
+		{
+			ic_got_reply = 0;
+			printk(",");
+			continue;
+		}
+#endif /* IPCONFIG_DHCP */
+
 		if (ic_got_reply) {
 			printk(" OK\n");
 			break;
 		}
+
+		if ((d = d->next))
+			continue;
+
 		if (! --retries) {
 			printk(" timed out!\n");
 			break;
 		}
+
+		d = ic_first_dev;
+
 		timeout = timeout CONF_TIMEOUT_MULT;
 		if (timeout > CONF_TIMEOUT_MAX)
 			timeout = CONF_TIMEOUT_MAX;
+
+		printk(".");
 	}
 
-#ifdef CONFIG_IP_PNP_RARP
-	if (do_rarp)
-		ic_rarp_cleanup();
-#endif
-#ifdef CONFIG_IP_PNP_BOOTP
+#ifdef IPCONFIG_BOOTP
 	if (do_bootp)
 		ic_bootp_cleanup();
 #endif
+#ifdef IPCONFIG_RARP
+	if (do_rarp)
+		ic_rarp_cleanup();
+#endif
 
 	if (!ic_got_reply)
 		return -1;
 
 	printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
-		(ic_got_reply & IC_BOOTP) ? "BOOTP" : "RARP",
+		((ic_got_reply & IC_RARP) ? "RARP" 
+		 : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"),
 		NIPQUAD(ic_servaddr));
 	printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr));
 
 	return 0;
 }
 
-#endif
+#endif /* IPCONFIG_DYNAMIC */
+
+#ifdef CONFIG_PROC_FS
+
+static int pnp_get_info(char *buffer, char **start,
+			off_t offset, int length)
+{
+	int len;
+
+	if (ic_proto_used & IC_PROTO)
+	    sprintf(buffer, "#PROTO: %s\n",
+		    (ic_proto_used & IC_RARP) ? "RARP"
+		    : (ic_proto_used & IC_USE_DHCP) ? "DHCP" : "BOOTP");
+	else
+	    strcpy(buffer, "#MANUAL\n");
+	len = strlen(buffer);
+
+	if (ic_domain[0])
+		len += sprintf(buffer + len,
+			       "domain %s\n", ic_domain);
+	if (ic_nameserver != INADDR_NONE)
+		len += sprintf(buffer + len,
+			       "nameserver %u.%u.%u.%u\n", NIPQUAD(ic_nameserver));
+
+	if (offset > len)
+		offset = len;
+	*start = buffer + offset;
+
+	if (offset + length > len)
+		length = len - offset;
+	return length;
+}
+
+#endif /* CONFIG_PROC_FS */
 
 /*
  *	IP Autoconfig dispatcher.
@@ -825,15 +1086,33 @@
 
 static int __init ip_auto_config(void)
 {
+	int retries = CONF_OPEN_RETRIES;
+	unsigned long jiff;
+
+#ifdef CONFIG_PROC_FS
+	proc_net_create("pnp", 0, pnp_get_info);
+#endif /* CONFIG_PROC_FS */
+
 	if (!ic_enable)
 		return 0;
 
 	DBG(("IP-Config: Entered.\n"));
 
+ try_try_again:
+	/* Give hardware a chance to settle */
+	jiff = jiffies + CONF_PRE_OPEN;
+	while (jiffies < jiff)
+		;
+
 	/* Setup all network devices */
 	if (ic_open_devs() < 0)
 		return -1;
 
+	/* Give drivers a chance to settle */
+	jiff = jiffies + CONF_POST_OPEN;
+	while (jiffies < jiff)
+			;
+
 	/*
 	 * If the config information is insufficient (e.g., our IP address or
 	 * IP address of the boot server is missing or we have multiple network
@@ -845,19 +1124,51 @@
 	    (root_server_addr == INADDR_NONE && ic_servaddr == INADDR_NONE) ||
 #endif
 	    ic_first_dev->next) {
-#ifdef CONFIG_IP_PNP_DYNAMIC
+#ifdef IPCONFIG_DYNAMIC
+
 		if (ic_dynamic() < 0) {
-			printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n");
 			ic_close_devs();
+
+			/*
+			 * I don't know why, but sometimes the
+			 * eepro100 driver (at least) gets upset and
+			 * doesn't work the first time it's opened.
+			 * But then if you close it and reopen it, it
+			 * works just fine.  So we need to try that at
+			 * least once before giving up.
+			 *
+			 * Also, if the root will be NFS-mounted, we
+			 * have nowhere to go if DHCP fails.  So we
+			 * just have to keep trying forever.
+			 *
+			 * 				-- Chip
+			 */
+#ifdef CONFIG_ROOT_NFS
+			if (ROOT_DEV == MKDEV(UNNAMED_MAJOR, 255)) {
+				printk(KERN_ERR 
+					"IP-Config: Retrying forever (NFS root)...\n");
+				goto try_try_again;
+			}
+#endif
+
+			if (--retries) {
+				printk(KERN_ERR 
+				       "IP-Config: Reopening network devices...\n");
+				goto try_try_again;
+			}
+
+			/* Oh, well.  At least we tried. */
+			printk(KERN_ERR "IP-Config: Auto-configuration of network failed.\n");
 			return -1;
 		}
-#else
+#else /* !DYNAMIC */
 		printk(KERN_ERR "IP-Config: Incomplete network configuration information.\n");
 		ic_close_devs();
 		return -1;
-#endif
+#endif /* IPCONFIG_DYNAMIC */
 	} else {
-		ic_dev = ic_first_dev->dev;	/* Device selected manually or only one device -> use it */
+		/* Device selected manually or only one device -> use it */
+		ic_dev = ic_first_dev->dev;
 	}
 
 	/*
@@ -874,10 +1185,30 @@
 	if (ic_setup_if() < 0 || ic_setup_routes() < 0)
 		return -1;
 
-	DBG(("IP-Config: device=%s, local=%08x, server=%08x, boot=%08x, gw=%08x, mask=%08x\n",
-	    ic_dev->name, ic_myaddr, ic_servaddr, root_server_addr, ic_gateway, ic_netmask));
-	DBG(("IP-Config: host=%s, domain=%s, path=`%s'\n", system_utsname.nodename,
-	    system_utsname.domainname, root_server_path));
+	/*
+	 * Record which protocol was actually used.
+	 */
+#ifdef IPCONFIG_DYNAMIC
+	ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP);
+#endif
+
+#ifndef IPCONFIG_SILENT
+	/*
+	 * Clue in the operator.
+	 */
+	printk("IP-Config: Complete:");
+	printk("\n      device=%s", ic_dev->name);
+	printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr));
+	printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
+	printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
+	printk(",\n     host=%s, domain=%s, nis-domain=%s",
+	       system_utsname.nodename, ic_domain, system_utsname.domainname);
+	printk(",\n     bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr));
+	printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr));
+	printk(", rootpath=%s", root_server_path);
+	printk("\n");
+#endif /* !SILENT */
+
 	return 0;
 }
 
@@ -889,7 +1220,7 @@
  *  command line parameter. It consists of option fields separated by colons in
  *  the following order:
  *
- *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<bootp|rarp>
+ *  <client-ip>:<server-ip>:<gw-ip>:<netmask>:<host name>:<device>:<PROTO>
  *
  *  Any of the fields can be empty which means to use a default value:
  *	<client-ip>	- address given by BOOTP or RARP
@@ -900,28 +1231,38 @@
  *	<host name>	- <client-ip> in ASCII notation, or the name returned
  *			  by BOOTP
  *	<device>	- use all available devices
- *	<bootp|rarp|both|off> - use both protocols to determine my own address
+ *	<PROTO>:
+ *	   off|none	    - don't do autoconfig at all (DEFAULT)
+ *	   on|any           - use any configured protocol
+ *	   dhcp|bootp|rarp  - use only the specified protocol
+ *	   both             - use both BOOTP and RARP (not DHCP)
  */
 static int __init ic_proto_name(char *name)
 {
-	if (!strcmp(name, "off")) {
-		ic_proto_enabled = 0;
+	if (!strcmp(name, "on") || !strcmp(name, "any")) {
+		return 1;
+	}
+#ifdef CONFIG_IP_PNP_DHCP
+	else if (!strcmp(name, "dhcp")) {
+		ic_proto_enabled &= ~IC_RARP;
 		return 1;
 	}
+#endif
 #ifdef CONFIG_IP_PNP_BOOTP
 	else if (!strcmp(name, "bootp")) {
-		ic_proto_enabled &= ~IC_RARP;
+		ic_proto_enabled &= ~(IC_RARP | IC_USE_DHCP);
 		return 1;
 	}
 #endif
 #ifdef CONFIG_IP_PNP_RARP
 	else if (!strcmp(name, "rarp")) {
-		ic_proto_enabled &= ~IC_BOOTP;
+		ic_proto_enabled &= ~(IC_BOOTP | IC_USE_DHCP);
 		return 1;
 	}
 #endif
-#ifdef CONFIG_IP_PNP_DYNAMIC
+#ifdef IPCONFIG_DYNAMIC
 	else if (!strcmp(name, "both")) {
+		ic_proto_enabled &= ~IC_USE_DHCP; /* backward compat :-( */
 		return 1;
 	}
 #endif
@@ -934,10 +1275,13 @@
 	int num = 0;
 
 	ic_set_manually = 1;
-	if (!strcmp(addrs, "off")) {
-		ic_enable = 0;
+
+	ic_enable = (*addrs && 
+		(strcmp(addrs, "off") != 0) && 
+		(strcmp(addrs, "none") != 0));
+	if (!ic_enable)
 		return 1;
-	}
+
 	if (ic_proto_name(addrs))
 		return 1;
 
diff -urN linux-2.4.5-pre1/net/ipv4/protocol.c linux/net/ipv4/protocol.c
--- linux-2.4.5-pre1/net/ipv4/protocol.c	Tue Oct 10 10:33:52 2000
+++ linux/net/ipv4/protocol.c	Mon Dec  3 22:41:47 2001
@@ -5,7 +5,7 @@
  *
  *		INET protocol dispatch tables.
  *
- * Version:	$Id: protocol.c,v 1.12 2000/10/03 07:29:00 anton Exp $
+ * Version:	$Id: protocol.c,v 1.13 2001/04/30 01:59:55 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -50,15 +50,11 @@
 
 #ifdef CONFIG_IP_MULTICAST
 
-static struct inet_protocol igmp_protocol = 
-{
-	igmp_rcv,		/* IGMP handler		*/
-	NULL,			/* IGMP error control	*/
-	IPPROTO_PREVIOUS,	/* next			*/
-	IPPROTO_IGMP,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"IGMP"			/* name			*/
+static struct inet_protocol igmp_protocol = {
+	handler:	igmp_rcv,
+	next:		IPPROTO_PREVIOUS,
+	protocol:	IPPROTO_IGMP,
+	name:		"IGMP"
 };
 
 #undef  IPPROTO_PREVIOUS
@@ -66,44 +62,33 @@
 
 #endif
 
-static struct inet_protocol tcp_protocol = 
-{
-	tcp_v4_rcv,		/* TCP handler		*/
-	tcp_v4_err,		/* TCP error control	*/  
-	IPPROTO_PREVIOUS,
-	IPPROTO_TCP,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"TCP"			/* name			*/
+static struct inet_protocol tcp_protocol = {
+	handler:	tcp_v4_rcv,
+	err_handler:	tcp_v4_err,
+	next:		IPPROTO_PREVIOUS,
+	protocol:	IPPROTO_TCP,
+	name:		"TCP"
 };
 
 #undef  IPPROTO_PREVIOUS
 #define IPPROTO_PREVIOUS &tcp_protocol
 
-static struct inet_protocol udp_protocol = 
-{
-	udp_rcv,		/* UDP handler		*/
-	udp_err,		/* UDP error control	*/
-	IPPROTO_PREVIOUS,	/* next			*/
-	IPPROTO_UDP,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"UDP"			/* name			*/
+static struct inet_protocol udp_protocol = {
+	handler:	udp_rcv,
+	err_handler:	udp_err,
+	next:		IPPROTO_PREVIOUS,
+	protocol:	IPPROTO_UDP,
+	name:		"UDP"
 };
 
 #undef  IPPROTO_PREVIOUS
 #define IPPROTO_PREVIOUS &udp_protocol
 
-
-static struct inet_protocol icmp_protocol = 
-{
-	icmp_rcv,		/* ICMP handler		*/
-	NULL,			/* ICMP error control	*/
-	IPPROTO_PREVIOUS,	/* next			*/
-	IPPROTO_ICMP,		/* protocol ID		*/
-	0,			/* copy			*/
-	NULL,			/* data			*/
-	"ICMP"			/* name			*/
+static struct inet_protocol icmp_protocol = {
+	handler:	icmp_rcv,
+	next:		IPPROTO_PREVIOUS,
+	protocol:	IPPROTO_ICMP,
+	name:		"ICMP"
 };
 
 #undef  IPPROTO_PREVIOUS
@@ -134,10 +119,8 @@
 	 */
 	 
 	p2 = (struct inet_protocol *) prot->next;
-	while(p2 != NULL) 
-	{
-		if (p2->protocol == prot->protocol) 
-		{
+	while (p2) {
+		if (p2->protocol == prot->protocol) {
 			prot->copy = 1;
 			break;
 		}
@@ -158,23 +141,20 @@
 
 	hash = prot->protocol & (MAX_INET_PROTOS - 1);
 	br_write_lock_bh(BR_NETPROTO_LOCK);
-	if (prot == inet_protos[hash]) 
-	{
+	if (prot == inet_protos[hash]) {
 		inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
 		br_write_unlock_bh(BR_NETPROTO_LOCK);
-		return(0);
+		return 0;
 	}
 
 	p = (struct inet_protocol *) inet_protos[hash];
-	while(p != NULL) 
-	{
+	while (p) {
 		/*
 		 * We have to worry if the protocol being deleted is
 		 * the last one on the list, then we may need to reset
 		 * someone's copied bit.
 		 */
-		if (p->next != NULL && p->next == prot) 
-		{
+		if (p->next && p->next == prot) {
 			/*
 			 * if we are the last one with this protocol and
 			 * there is a previous one, reset its copy bit.
@@ -183,7 +163,7 @@
 				lp->copy = 0;
 			p->next = prot->next;
 			br_write_unlock_bh(BR_NETPROTO_LOCK);
-			return(0);
+			return 0;
 		}
 		if (p->next != NULL && p->next->protocol == prot->protocol) 
 			lp = p;
@@ -191,5 +171,5 @@
 		p = (struct inet_protocol *) p->next;
 	}
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
-	return(-1);
+	return -1;
 }
diff -urN linux-2.4.5-pre1/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux-2.4.5-pre1/net/ipv4/tcp.c	Mon Dec  3 22:41:06 2001
+++ linux/net/ipv4/tcp.c	Mon Dec  3 22:41:48 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.202 2001/04/20 20:46:19 davem Exp $
+ * Version:	$Id: tcp.c,v 1.204 2001/05/01 23:07:49 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1122,8 +1122,16 @@
 
 				/* Time to copy data. We are close to the end! */
 				err = tcp_copy_to_page(sk, from, skb, page, off, copy);
-				if (err)
+				if (err) {
+					/* If this page was new, give it to the
+					 * socket so it does not get leaked.
+					 */
+					if (TCP_PAGE(sk) == NULL) {
+						TCP_PAGE(sk) = page;
+						TCP_OFF(sk) = 0;
+					}
 					goto do_error;
+				}
 
 				/* Update the skb. */
 				if (merge) {
@@ -1182,12 +1190,9 @@
 	return copied;
 
 do_fault:
-	if (skb->len==0) {
-		if (tp->send_head == skb) {
-			tp->send_head = skb->prev;
-			if (TCP_SKB_CB(skb)->seq == tp->snd_nxt)
-				tp->send_head = NULL;
-		}
+	if (skb->len == 0) {
+		if (tp->send_head == skb)
+			tp->send_head = NULL;
 		__skb_unlink(skb, skb->list);
 		tcp_free_skb(sk, skb);
 	}
diff -urN linux-2.4.5-pre1/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- linux-2.4.5-pre1/net/ipv6/addrconf.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv6/addrconf.c	Mon Dec  3 22:41:48 2001
@@ -6,7 +6,7 @@
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *	Alexey Kuznetsov	<kuznet@ms2.inr.ac.ru>
  *
- *	$Id: addrconf.c,v 1.62 2001/04/26 19:11:59 davem Exp $
+ *	$Id: addrconf.c,v 1.64 2001/05/01 23:05:47 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -22,6 +22,10 @@
  *	Andi Kleen			:	kill doube kfree on module
  *						unload.
  *	Maciej W. Rozycki		:	FDDI support
+ *	sekiya@USAGI			:	Don't send too many RS
+ *						packets.
+ *	yoshfuji@USAGI			:       Fixed interval between DAD
+ *						packets.
  */
 
 #include <linux/config.h>
@@ -1509,7 +1513,7 @@
 	}
 
 	ifp->probes--;
-	addrconf_mod_timer(ifp, AC_DAD, ifp->idev->cnf.rtr_solicit_interval);
+	addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
 	spin_unlock_bh(&ifp->lock);
 
 	/* send a neighbour solicitation for our addr */
