Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 6 Jul 2006 04:08:35 +0000 (21:08 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 6 Jul 2006 04:08:35 +0000 (21:08 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Fix stack overflow checking in modular non-SMP kernels.
  [SPARC64]: Fix sparc64 build errors when CONFIG_PCI=n.

95 files changed:
MAINTAINERS
arch/arm/mach-at91rm9200/at91rm9200.c
arch/arm/mach-at91rm9200/generic.h
arch/arm/mach-at91rm9200/irq.c
arch/arm/mach-pnx4008/core.c
arch/arm/mach-pnx4008/dma.c
arch/arm/mach-pnx4008/irq.c
arch/arm/mach-pnx4008/time.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/b44.c
drivers/net/bnx2.c
drivers/net/cassini.c
drivers/net/declance.c
drivers/net/dl2k.c
drivers/net/eepro100.c
drivers/net/epic100.c
drivers/net/fealnx.c
drivers/net/gt96100eth.c
drivers/net/gt96100eth.h
drivers/net/hamachi.c
drivers/net/myri10ge/myri10ge.c
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/ni5010.c
drivers/net/ns83820.c
drivers/net/pci-skeleton.c
drivers/net/pcnet32.c
drivers/net/phy/cicada.c
drivers/net/r8169.c
drivers/net/starfire.c
drivers/net/sundance.c
drivers/net/tulip/winbond-840.c
drivers/net/tulip/xircom_tulip_cb.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/via-velocity.h
drivers/net/wan/Kconfig
drivers/net/wan/Makefile
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_main.h
drivers/net/wireless/bcm43xx/bcm43xx_radio.c
drivers/net/wireless/bcm43xx/bcm43xx_wx.c
drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/zd1211rw/Kconfig [new file with mode: 0644]
drivers/net/wireless/zd1211rw/Makefile [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_chip.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_chip.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_def.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_ieee80211.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_ieee80211.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_mac.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_mac.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_netdev.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_netdev.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_rf.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_rf.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_rf_al2230.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_rf_rf2959.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_types.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_usb.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_usb.h [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_util.c [new file with mode: 0644]
drivers/net/wireless/zd1211rw/zd_util.h [new file with mode: 0644]
drivers/net/yellowfin.c
drivers/scsi/ahci.c
drivers/scsi/libata-core.c
drivers/scsi/libata-eh.c
drivers/scsi/libata-scsi.c
drivers/scsi/sata_sil.c
drivers/scsi/sata_sil24.c
drivers/scsi/sata_vsc.c
drivers/serial/at91_serial.c
fs/lockd/clntproc.c
fs/locks.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/nfs4proc.c
fs/nfs/write.c
include/asm-arm/arch-at91rm9200/irqs.h
include/linux/fs.h
include/linux/libata.h
include/linux/nfs_xdr.h
include/linux/pci_ids.h
include/net/ieee80211softmac.h
net/ieee80211/ieee80211_rx.c
net/ieee80211/ieee80211_tx.c
net/ieee80211/softmac/ieee80211softmac_assoc.c
net/ieee80211/softmac/ieee80211softmac_auth.c
net/ieee80211/softmac/ieee80211softmac_io.c
net/ieee80211/softmac/ieee80211softmac_wx.c
net/sunrpc/xdr.c

index 5f76a4f..196a31c 100644 (file)
@@ -2039,9 +2039,10 @@ L:       linux-kernel@vger.kernel.org
 S:     Maintained
 
 NI5010 NETWORK DRIVER
-P:     Jan-Pascal van Best and Andreas Mohr
-M:     Jan-Pascal van Best <jvbest@qv3pluto.leidenuniv.nl>
-M:     Andreas Mohr <100.30936@germany.net>
+P:     Jan-Pascal van Best
+M:     janpascal@vanbest.org
+P:     Andreas Mohr
+M:     andi@lisas.de
 L:     netdev@vger.kernel.org
 S:     Maintained
 
index 7e1d072..0985b1c 100644 (file)
@@ -107,3 +107,48 @@ void __init at91rm9200_map_io(void)
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
 }
 
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
+       7,      /* Advanced Interrupt Controller (FIQ) */
+       7,      /* System Peripherals */
+       0,      /* Parallel IO Controller A */
+       0,      /* Parallel IO Controller B */
+       0,      /* Parallel IO Controller C */
+       0,      /* Parallel IO Controller D */
+       6,      /* USART 0 */
+       6,      /* USART 1 */
+       6,      /* USART 2 */
+       6,      /* USART 3 */
+       0,      /* Multimedia Card Interface */
+       4,      /* USB Device Port */
+       0,      /* Two-Wire Interface */
+       6,      /* Serial Peripheral Interface */
+       5,      /* Serial Synchronous Controller 0 */
+       5,      /* Serial Synchronous Controller 1 */
+       5,      /* Serial Synchronous Controller 2 */
+       0,      /* Timer Counter 0 */
+       0,      /* Timer Counter 1 */
+       0,      /* Timer Counter 2 */
+       0,      /* Timer Counter 3 */
+       0,      /* Timer Counter 4 */
+       0,      /* Timer Counter 5 */
+       3,      /* USB Host port */
+       3,      /* Ethernet MAC */
+       0,      /* Advanced Interrupt Controller (IRQ0) */
+       0,      /* Advanced Interrupt Controller (IRQ1) */
+       0,      /* Advanced Interrupt Controller (IRQ2) */
+       0,      /* Advanced Interrupt Controller (IRQ3) */
+       0,      /* Advanced Interrupt Controller (IRQ4) */
+       0,      /* Advanced Interrupt Controller (IRQ5) */
+       0       /* Advanced Interrupt Controller (IRQ6) */
+};
+
+void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
+{
+       if (!priority)
+               priority = at91rm9200_default_irq_priority;
+
+       at91_aic_init(priority);
+}
index f0d969d..7979d8a 100644 (file)
@@ -8,13 +8,19 @@
  * published by the Free Software Foundation.
  */
 
-void at91_gpio_irq_setup(unsigned banks);
+ /* Interrupts */
+extern void __init at91rm9200_init_irq(unsigned int priority[]);
+extern void __init at91_aic_init(unsigned int priority[]);
+extern void __init at91_gpio_irq_setup(unsigned banks);
 
+ /* Timer */
 struct sys_timer;
 extern struct sys_timer at91rm9200_timer;
 
+ /* Memory Map */
 extern void __init at91rm9200_map_io(void);
 
+ /* Clocks */
 extern int __init at91_clock_init(unsigned long main_clock);
 struct device;
 extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
index dcd560d..9b09113 100644 (file)
 
 #include "generic.h"
 
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
-       7,      /* Advanced Interrupt Controller */
-       7,      /* System Peripheral */
-       0,      /* Parallel IO Controller A */
-       0,      /* Parallel IO Controller B */
-       0,      /* Parallel IO Controller C */
-       0,      /* Parallel IO Controller D */
-       6,      /* USART 0 */
-       6,      /* USART 1 */
-       6,      /* USART 2 */
-       6,      /* USART 3 */
-       0,      /* Multimedia Card Interface */
-       4,      /* USB Device Port */
-       0,      /* Two-Wire Interface */
-       6,      /* Serial Peripheral Interface */
-       5,      /* Serial Synchronous Controller */
-       5,      /* Serial Synchronous Controller */
-       5,      /* Serial Synchronous Controller */
-       0,      /* Timer Counter 0 */
-       0,      /* Timer Counter 1 */
-       0,      /* Timer Counter 2 */
-       0,      /* Timer Counter 3 */
-       0,      /* Timer Counter 4 */
-       0,      /* Timer Counter 5 */
-       3,      /* USB Host port */
-       3,      /* Ethernet MAC */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0,      /* Advanced Interrupt Controller */
-       0       /* Advanced Interrupt Controller */
-};
 
-
-static void at91rm9200_mask_irq(unsigned int irq)
+static void at91_aic_mask_irq(unsigned int irq)
 {
        /* Disable interrupt on AIC */
        at91_sys_write(AT91_AIC_IDCR, 1 << irq);
 }
 
-static void at91rm9200_unmask_irq(unsigned int irq)
+static void at91_aic_unmask_irq(unsigned int irq)
 {
        /* Enable interrupt on AIC */
        at91_sys_write(AT91_AIC_IECR, 1 << irq);
 }
 
-static int at91rm9200_irq_type(unsigned irq, unsigned type)
+static int at91_aic_set_type(unsigned irq, unsigned type)
 {
        unsigned int smr, srctype;
 
@@ -122,7 +84,7 @@ static int at91rm9200_irq_type(unsigned irq, unsigned type)
 static u32 wakeups;
 static u32 backups;
 
-static int at91rm9200_irq_set_wake(unsigned irq, unsigned value)
+static int at91_aic_set_wake(unsigned irq, unsigned value)
 {
        if (unlikely(irq >= 32))
                return -EINVAL;
@@ -149,28 +111,24 @@ void at91_irq_resume(void)
 }
 
 #else
-#define at91rm9200_irq_set_wake        NULL
+#define at91_aic_set_wake      NULL
 #endif
 
-static struct irqchip at91rm9200_irq_chip = {
-       .ack            = at91rm9200_mask_irq,
-       .mask           = at91rm9200_mask_irq,
-       .unmask         = at91rm9200_unmask_irq,
-       .set_type       = at91rm9200_irq_type,
-       .set_wake       = at91rm9200_irq_set_wake,
+static struct irqchip at91_aic_chip = {
+       .ack            = at91_aic_mask_irq,
+       .mask           = at91_aic_mask_irq,
+       .unmask         = at91_aic_unmask_irq,
+       .set_type       = at91_aic_set_type,
+       .set_wake       = at91_aic_set_wake,
 };
 
 /*
  * Initialize the AIC interrupt controller.
  */
-void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
+void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
 {
        unsigned int i;
 
-       /* No priority list specified for this board -> use defaults */
-       if (priority == NULL)
-               priority = at91rm9200_default_irq_priority;
-
        /*
         * The IVR is used by macro get_irqnr_and_base to read and verify.
         * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
@@ -178,10 +136,10 @@ void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
        for (i = 0; i < NR_AIC_IRQS; i++) {
                /* Put irq number in Source Vector Register: */
                at91_sys_write(AT91_AIC_SVR(i), i);
-               /* Store the Source Mode Register as defined in table above */
+               /* Active Low interrupt, with the specified priority */
                at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
 
-               set_irq_chip(i, &at91rm9200_irq_chip);
+               set_irq_chip(i, &at91_aic_chip);
                set_irq_handler(i, do_level_IRQ);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
 
index ba91daa..3d73c1e 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/spi/spi.h>
 
 #include <asm/hardware.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -36,7 +35,6 @@
 #include <asm/system.h>
 
 #include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
 
index 981aa9d..ec01574 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 
 #include <asm/system.h>
-#include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/dma.h>
 #include <asm/dma-mapping.h>
index 9b0a8e0..3a4bcf3 100644 (file)
@@ -22,8 +22,8 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/device.h>
+#include <linux/irq.h>
 #include <asm/hardware.h>
-#include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
@@ -96,26 +96,24 @@ void __init pnx4008_init_irq(void)
 {
        unsigned int i;
 
-       /* configure and enable IRQ 0,1,30,31 (cascade interrupts) mask all others */
+       /* configure IRQ's */
+       for (i = 0; i < NR_IRQS; i++) {
+               set_irq_flags(i, IRQF_VALID);
+               set_irq_chip(i, &pnx4008_irq_chip);
+               pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
+       }
+
+       /* configure and enable IRQ 0,1,30,31 (cascade interrupts) */
        pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
        pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
        pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
        pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
 
+       /* mask all others */
        __raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
                        (1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
                INTC_ER(MAIN_BASE_INT));
        __raw_writel(0, INTC_ER(SIC1_BASE_INT));
        __raw_writel(0, INTC_ER(SIC2_BASE_INT));
-
-       /* configure all other IRQ's */
-       for (i = 0; i < NR_IRQS; i++) {
-               if (i == SUB2_FIQ_N || i == SUB1_FIQ_N ||
-                       i == SUB2_IRQ_N || i == SUB1_IRQ_N)
-                       continue;
-               set_irq_flags(i, IRQF_VALID);
-               set_irq_chip(i, &pnx4008_irq_chip);
-               pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
-       }
 }
 
index 888bf6c..756228d 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/irq.h>
 
 #include <asm/system.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
 #include <asm/leds.h>
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
 #include <asm/mach/time.h>
-
-#include <linux/time.h>
-#include <linux/timex.h>
 #include <asm/errno.h>
 
 /*! Note: all timers are UPCOUNTING */
index 1959654..d2150ba 100644 (file)
@@ -1836,9 +1836,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
        if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
            pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
-               printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
-                      pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
-               printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+               dev_err(&pdev->dev,
+                          "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+                          pdev->vendor, pdev->device, pci_rev);
+               dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
                return -ENODEV;
        }
 
@@ -1876,14 +1877,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        pciaddr = pci_resource_start(pdev, 1);
        if (!pciaddr) {
                rc = -EIO;
-               printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "no MMIO resource\n");
                goto err_out_res;
        }
        if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
                rc = -EIO;
-               printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
-                      (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
+               dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
+                      (unsigned long long)pci_resource_len(pdev, 1));
                goto err_out_res;
        }
 
@@ -1897,14 +1897,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 
                rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
-                       printk(KERN_ERR PFX "No usable DMA configuration, "
-                              "aborting.\n");
+                       dev_err(&pdev->dev,
+                                  "No usable DMA configuration, aborting.\n");
                        goto err_out_res;
                }
                rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
-                       printk(KERN_ERR PFX "No usable consistent DMA configuration, "
-                              "aborting.\n");
+                       dev_err(&pdev->dev,
+                                  "No usable consistent DMA configuration, "
+                                  "aborting.\n");
                        goto err_out_res;
                }
        }
@@ -1915,9 +1916,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        regs = ioremap(pciaddr, CP_REGS_SIZE);
        if (!regs) {
                rc = -EIO;
-               printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%llx) on pci dev %s\n",
-                       (unsigned long long)pci_resource_len(pdev, 1),
-                       (unsigned long long)pciaddr, pci_name(pdev));
+               dev_err(&pdev->dev, "Cannot map PCI MMIO (%lx@%lx)\n",
+                      (unsigned long long)pci_resource_len(pdev, 1),
+                      (unsigned long long)pciaddr);
                goto err_out_res;
        }
        dev->base_addr = (unsigned long) regs;
@@ -1986,7 +1987,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        /* enable busmastering and memory-write-invalidate */
        pci_set_master(pdev);
 
-       if (cp->wol_enabled) cp_set_d3_state (cp);
+       if (cp->wol_enabled)
+               cp_set_d3_state (cp);
 
        return 0;
 
@@ -2011,7 +2013,8 @@ static void cp_remove_one (struct pci_dev *pdev)
        BUG_ON(!dev);
        unregister_netdev(dev);
        iounmap(cp->regs);
-       if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
+       if (cp->wol_enabled)
+               pci_set_power_state (pdev, PCI_D0);
        pci_release_regions(pdev);
        pci_clear_mwi(pdev);
        pci_disable_device(pdev);
index 717506b..cd97185 100644 (file)
@@ -768,7 +768,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
        /* dev and priv zeroed in alloc_etherdev */
        dev = alloc_etherdev (sizeof (*tp));
        if (dev == NULL) {
-               printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+               dev_err(&pdev->dev, "Unable to alloc new net device\n");
                return -ENOMEM;
        }
        SET_MODULE_OWNER(dev);
@@ -800,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 #ifdef USE_IO_OPS
        /* make sure PCI base addr 0 is PIO */
        if (!(pio_flags & IORESOURCE_IO)) {
-               printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
        /* check for weird/broken PCI region reporting */
        if (pio_len < RTL_MIN_IO_SIZE) {
-               printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
 #else
        /* make sure PCI base addr 1 is MMIO */
        if (!(mmio_flags & IORESOURCE_MEM)) {
-               printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
        if (mmio_len < RTL_MIN_IO_SIZE) {
-               printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
 #endif
 
-       rc = pci_request_regions (pdev, "8139too");
+       rc = pci_request_regions (pdev, DRV_NAME);
        if (rc)
                goto err_out;
        disable_dev_on_err = 1;
@@ -835,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 #ifdef USE_IO_OPS
        ioaddr = ioport_map(pio_start, pio_len);
        if (!ioaddr) {
-               printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "cannot map PIO, aborting\n");
                rc = -EIO;
                goto err_out;
        }
@@ -846,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
        /* ioremap MMIO region */
        ioaddr = pci_iomap(pdev, 1, 0);
        if (ioaddr == NULL) {
-               printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+               dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
                rc = -EIO;
                goto err_out;
        }
@@ -860,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
 
        /* check for missing/broken hardware */
        if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
-               printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
-                       pci_name(pdev));
+               dev_err(&pdev->dev, "Chip not responding, ignoring board\n");
                rc = -EIO;
                goto err_out;
        }
@@ -875,9 +874,10 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
                }
 
        /* if unknown chip, assume array element #0, original RTL-8139 in this case */
-       printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
-               pci_name(pdev));
-       printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+       dev_printk (KERN_DEBUG, &pdev->dev,
+                   "unknown chip version, assuming RTL-8139\n");
+       dev_printk (KERN_DEBUG, &pdev->dev,
+                   "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
        tp->chipset = 0;
 
 match:
@@ -954,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
 
        if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
            pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
-               printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
-                      pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
-               printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+               dev_info(&pdev->dev,
+                          "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+                          pdev->vendor, pdev->device, pci_rev);
+               dev_info(&pdev->dev,
+                          "Use the \"8139cp\" driver for improved performance and stability.\n");
        }
 
        i = rtl8139_init_board (pdev, &dev);
index cd98d31..bea0fc0 100644 (file)
@@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device, "
+               dev_err(&pdev->dev, "Cannot enable PCI device, "
                       "aborting.\n");
                return err;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find proper PCI device "
+               dev_err(&pdev->dev,
+                       "Cannot find proper PCI device "
                       "base address, aborting.\n");
                err = -ENODEV;
                goto err_out_disable_pdev;
@@ -2134,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_request_regions(pdev, DRV_MODULE_NAME);
        if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Cannot obtain PCI resources, aborting.\n");
                goto err_out_disable_pdev;
        }
 
@@ -2143,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
        if (err) {
-               printk(KERN_ERR PFX "No usable DMA configuration, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
 
        err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
        if (err) {
-               printk(KERN_ERR PFX "No usable DMA configuration, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
                goto err_out_free_res;
        }
 
@@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        dev = alloc_etherdev(sizeof(*bp));
        if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
                err = -ENOMEM;
                goto err_out_free_res;
        }
@@ -2181,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        bp->regs = ioremap(b44reg_base, b44reg_len);
        if (bp->regs == 0UL) {
-               printk(KERN_ERR PFX "Cannot map device registers, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
                err = -ENOMEM;
                goto err_out_free_dev;
        }
@@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = b44_get_invariants(bp);
        if (err) {
-               printk(KERN_ERR PFX "Problem fetching invariants of chip, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Problem fetching invariants of chip, aborting.\n");
                goto err_out_iounmap;
        }
 
@@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
                goto err_out_iounmap;
        }
 
index 4f4db5a..64b6a72 100644 (file)
@@ -5575,20 +5575,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        /* enable device (incl. PCI PM wakeup), and bus-mastering */
        rc = pci_enable_device(pdev);
        if (rc) {
-               printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+               dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
                goto err_out;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find PCI device base address, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Cannot find PCI device base address, aborting.\n");
                rc = -ENODEV;
                goto err_out_disable;
        }
 
        rc = pci_request_regions(pdev, DRV_MODULE_NAME);
        if (rc) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
+               dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
                goto err_out_disable;
        }
 
@@ -5596,15 +5596,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
        if (bp->pm_cap == 0) {
-               printk(KERN_ERR PFX "Cannot find power management capability, "
-                              "aborting.\n");
+               dev_err(&pdev->dev,
+                       "Cannot find power management capability, aborting.\n");
                rc = -EIO;
                goto err_out_release;
        }
 
        bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
        if (bp->pcix_cap == 0) {
-               printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
+               dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
                rc = -EIO;
                goto err_out_release;
        }
@@ -5612,14 +5612,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
                bp->flags |= USING_DAC_FLAG;
                if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
-                       printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
-                              "failed, aborting.\n");
+                       dev_err(&pdev->dev,
+                               "pci_set_consistent_dma_mask failed, aborting.\n");
                        rc = -EIO;
                        goto err_out_release;
                }
        }
        else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
-               printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+               dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
                rc = -EIO;
                goto err_out_release;
        }
@@ -5639,7 +5639,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->regview = ioremap_nocache(dev->base_addr, mem_len);
 
        if (!bp->regview) {
-               printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
+               dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
                rc = -ENOMEM;
                goto err_out_release;
        }
@@ -5711,8 +5711,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
                !(bp->flags & PCIX_FLAG)) {
 
-               printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
-                      "aborting.\n");
+               dev_err(&pdev->dev,
+                       "5706 A1 can only be used in a PCIX bus, aborting.\n");
                goto err_out_unmap;
        }
 
@@ -5733,7 +5733,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
 
        if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
            BNX2_DEV_INFO_SIGNATURE_MAGIC) {
-               printk(KERN_ERR PFX "Firmware not running, aborting.\n");
+               dev_err(&pdev->dev, "Firmware not running, aborting.\n");
                rc = -ENODEV;
                goto err_out_unmap;
        }
@@ -5895,7 +5895,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #endif
 
        if ((rc = register_netdev(dev))) {
-               printk(KERN_ERR PFX "Cannot register net device\n");
+               dev_err(&pdev->dev, "Cannot register net device\n");
                if (bp->regview)
                        iounmap(bp->regview);
                pci_release_regions(pdev);
index d33130f..a31544c 100644 (file)
@@ -4887,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "Cannot enable PCI device, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
                return err;
        }
 
        if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX "Cannot find proper PCI device "
+               dev_err(&pdev->dev, "Cannot find proper PCI device "
                       "base address, aborting.\n");
                err = -ENODEV;
                goto err_out_disable_pdev;
@@ -4901,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
        dev = alloc_etherdev(sizeof(*cp));
        if (!dev) {
-               printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+               dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
                err = -ENOMEM;
                goto err_out_disable_pdev;
        }
@@ -4910,8 +4909,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
 
        err = pci_request_regions(pdev, dev->name);
        if (err) {
-               printk(KERN_ERR PFX "Cannot obtain PCI resources, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
                goto err_out_free_netdev;
        }
        pci_set_master(pdev);
@@ -4941,7 +4939,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                if (pci_write_config_byte(pdev, 
                                          PCI_CACHE_LINE_SIZE, 
                                          cas_cacheline_size)) {
-                       printk(KERN_ERR PFX "Could not set PCI cache "
+                       dev_err(&pdev->dev, "Could not set PCI cache "
                               "line size\n");
                        goto err_write_cacheline;
                }
@@ -4955,7 +4953,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                err = pci_set_consistent_dma_mask(pdev,
                                                  DMA_64BIT_MASK);
                if (err < 0) {
-                       printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
+                       dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
                               "for consistent allocations\n");
                        goto err_out_free_res;
                }
@@ -4963,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
        } else {
                err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (err) {
-                       printk(KERN_ERR PFX "No usable DMA configuration, "
+                       dev_err(&pdev->dev, "No usable DMA configuration, "
                               "aborting.\n");
                        goto err_out_free_res;
                }
@@ -5023,8 +5021,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
        /* give us access to cassini registers */
        cp->regs = pci_iomap(pdev, 0, casreg_len);
        if (cp->regs == 0UL) {
-               printk(KERN_ERR PFX "Cannot map device registers, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
                goto err_out_free_res;
        }
        cp->casreg_len = casreg_len;
@@ -5040,8 +5037,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
                                     &cp->block_dvma);
        if (!cp->init_block) {
-               printk(KERN_ERR PFX "Cannot allocate init block, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
                goto err_out_iounmap;
        }
 
@@ -5085,8 +5081,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
                dev->features |= NETIF_F_HIGHDMA;
 
        if (register_netdev(dev)) {
-               printk(KERN_ERR PFX "Cannot register net device, "
-                      "aborting.\n");
+               dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
                goto err_out_free_consistent;
        }
 
index 2038ca7..6ad5796 100644 (file)
@@ -703,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
        return IRQ_HANDLED;
 }
 
-static irqreturn_t
-lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(const int irq, void *dev_id,
+                                  struct pt_regs *regs)
 {
        struct net_device *dev = (struct net_device *) dev_id;
        struct lance_private *lp = netdev_priv(dev);
@@ -1253,7 +1253,7 @@ static int __init dec_lance_init(const int type, const int slot)
        return 0;
 
 err_out_free_dev:
-       kfree(dev);
+       free_netdev(dev);
 
 err_out:
        return ret;
@@ -1299,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
        while (root_lance_dev) {
                struct net_device *dev = root_lance_dev;
                struct lance_private *lp = netdev_priv(dev);
+
                unregister_netdev(dev);
 #ifdef CONFIG_TC
                if (lp->slot >= 0)
index 4b6ddb7..402961e 100644 (file)
@@ -9,49 +9,10 @@
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 */
-/*
-    Rev                Date            Description
-    ==========================================================================
-    0.01       2001/05/03      Created DL2000-based linux driver
-    0.02       2001/05/21      Added VLAN and hardware checksum support.
-    1.00       2001/06/26      Added jumbo frame support.
-    1.01       2001/08/21      Added two parameters, rx_coalesce and rx_timeout.
-    1.02       2001/10/08      Supported fiber media.
-                               Added flow control parameters.
-    1.03       2001/10/12      Changed the default media to 1000mbps_fd for 
-                               the fiber devices.
-    1.04       2001/11/08      Fixed Tx stopped when tx very busy.
-    1.05       2001/11/22      Fixed Tx stopped when unidirectional tx busy.
-    1.06       2001/12/13      Fixed disconnect bug at 10Mbps mode.
-                               Fixed tx_full flag incorrect.
-                               Added tx_coalesce paramter.
-    1.07       2002/01/03      Fixed miscount of RX frame error.
-    1.08       2002/01/17      Fixed the multicast bug.
-    1.09       2002/03/07      Move rx-poll-now to re-fill loop.       
-                               Added rio_timer() to watch rx buffers. 
-    1.10       2002/04/16      Fixed miscount of carrier error.
-    1.11       2002/05/23      Added ISR schedule scheme
-                               Fixed miscount of rx frame error for DGE-550SX.
-                               Fixed VLAN bug.
-    1.12       2002/06/13      Lock tx_coalesce=1 on 10/100Mbps mode.
-    1.13       2002/08/13      1. Fix disconnection (many tx:carrier/rx:frame
-                                  errs) with some mainboards.
-                               2. Use definition "DRV_NAME" "DRV_VERSION" 
-                                  "DRV_RELDATE" for flexibility.       
-    1.14       2002/08/14      Support ethtool.        
-    1.15       2002/08/27      Changed the default media to Auto-Negotiation
-                               for the fiber devices.    
-    1.16       2002/09/04      More power down time for fiber devices auto-
-                               negotiation.
-                               Fix disconnect bug after ifup and ifdown.
-    1.17       2002/10/03      Fix RMON statistics overflow. 
-                               Always use I/O mapping to access eeprom, 
-                               avoid system freezing with some chipsets.
 
-*/
 #define DRV_NAME       "D-Link DL2000-based linux driver"
-#define DRV_VERSION    "v1.17b"
-#define DRV_RELDATE    "2006/03/10"
+#define DRV_VERSION    "v1.18"
+#define DRV_RELDATE    "2006/06/27"
 #include "dl2k.h"
 #include <linux/dma-mapping.h>
 
index 2ad3275..e445988 100644 (file)
@@ -555,12 +555,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
 
        if (!request_region(pci_resource_start(pdev, 1),
                        pci_resource_len(pdev, 1), "eepro100")) {
-               printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+               dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
                goto err_out_none;
        }
        if (!request_mem_region(pci_resource_start(pdev, 0),
                        pci_resource_len(pdev, 0), "eepro100")) {
-               printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
+               dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
                goto err_out_free_pio_region;
        }
 
@@ -573,7 +573,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
 
        ioaddr = pci_iomap(pdev, pci_bar, 0);
        if (!ioaddr) {
-               printk (KERN_ERR "eepro100: cannot remap IO\n");
+               dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
                goto err_out_free_mmio_region;
        }
 
index 9f3e09a..a67650c 100644 (file)
 
        Information and updates available at
        http://www.scyld.com/network/epic100.html
+       [this link no longer provides anything useful -jgarzik]
 
        ---------------------------------------------------------------------
 
-       Linux kernel-specific changes:
-
-       LK1.1.2 (jgarzik):
-       * Merge becker version 1.09 (4/08/2000)
-
-       LK1.1.3:
-       * Major bugfix to 1.09 driver (Francis Romieu)
-
-       LK1.1.4 (jgarzik):
-       * Merge becker test version 1.09 (5/29/2000)
-
-       LK1.1.5:
-       * Fix locking (jgarzik)
-       * Limit 83c175 probe to ethernet-class PCI devices (rgooch)
-
-       LK1.1.6:
-       * Merge becker version 1.11
-       * Move pci_enable_device before any PCI BAR len checks
-
-       LK1.1.7:
-       * { fill me in }
-
-       LK1.1.8:
-       * ethtool driver info support (jgarzik)
-
-       LK1.1.9:
-       * ethtool media get/set support (jgarzik)
-
-       LK1.1.10:
-       * revert MII transceiver init change (jgarzik)
-
-       LK1.1.11:
-       * implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
-       * replace some MII-related magic numbers with constants
-
-       LK1.1.12:
-       * fix power-up sequence
-
-       LK1.1.13:
-       * revert version 1.1.12, power-up sequence "fix"
-
-       LK1.1.14 (Kryzsztof Halasa):
-       * fix spurious bad initializations
-       * pound phy a la SMSC's app note on the subject
-
-       AC1.1.14ac
-       * fix power up/down for ethtool that broke in 1.11
-
 */
 
 #define DRV_NAME        "epic100"
-#define DRV_VERSION     "1.11+LK1.1.14+AC1.1.14"
-#define DRV_RELDATE     "June 2, 2004"
+#define DRV_VERSION     "2.0"
+#define DRV_RELDATE     "June 27, 2006"
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -204,19 +157,15 @@ typedef enum {
 
 struct epic_chip_info {
        const char *name;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
 
 /* indexed by chip_t */
 static const struct epic_chip_info pci_id_tbl[] = {
-       { "SMSC EPIC/100 83c170",
-         EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
-       { "SMSC EPIC/100 83c170",
-         EPIC_TOTAL_SIZE, TYPE2_INTR },
-       { "SMSC EPIC/C 83c175",
-         EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+       { "SMSC EPIC/100 83c170",       TYPE2_INTR | NO_MII | MII_PWRDWN },
+       { "SMSC EPIC/100 83c170",       TYPE2_INTR },
+       { "SMSC EPIC/C 83c175",         TYPE2_INTR | MII_PWRDWN },
 };
 
 
@@ -385,8 +334,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
                goto out;
        irq = pdev->irq;
 
-       if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
-               printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
+       if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
+               dev_err(&pdev->dev, "no PCI region space\n");
                ret = -ENODEV;
                goto err_out_disable;
        }
@@ -401,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
 
        dev = alloc_etherdev(sizeof (*ep));
        if (!dev) {
-               printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
+               dev_err(&pdev->dev, "no memory for eth device\n");
                goto err_out_free_res;
        }
        SET_MODULE_OWNER(dev);
@@ -413,7 +362,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
        ioaddr = pci_resource_start (pdev, 1);
        ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
        if (!ioaddr) {
-               printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
+               dev_err(&pdev->dev, "ioremap failed\n");
                goto err_out_free_netdev;
        }
 #endif
@@ -473,8 +422,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
                ((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
 
        if (debug > 2) {
-               printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
-                      pci_name(pdev));
+               dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
                for (i = 0; i < 64; i++)
                        printk(" %4.4x%s", read_eeprom(ioaddr, i),
                                   i % 16 == 15 ? "\n" : "");
@@ -496,21 +444,23 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
                        int mii_status = mdio_read(dev, phy, MII_BMSR);
                        if (mii_status != 0xffff  &&  mii_status != 0x0000) {
                                ep->phys[phy_idx++] = phy;
-                               printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
-                                          "%4.4x status %4.4x.\n",
-                                          pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status);
+                               dev_info(&pdev->dev,
+                                       "MII transceiver #%d control "
+                                       "%4.4x status %4.4x.\n",
+                                       phy, mdio_read(dev, phy, 0), mii_status);
                        }
                }
                ep->mii_phy_cnt = phy_idx;
                if (phy_idx != 0) {
                        phy = ep->phys[0];
                        ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
-                       printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
+                       dev_info(&pdev->dev,
+                               "Autonegotiation advertising %4.4x link "
                                   "partner %4.4x.\n",
-                                  pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5));
+                                  ep->mii.advertising, mdio_read(dev, phy, 5));
                } else if ( ! (ep->chip_flags & NO_MII)) {
-                       printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
-                              pci_name(pdev));
+                       dev_warn(&pdev->dev,
+                               "***WARNING***: No MII transceiver found!\n");
                        /* Use the known PHY address of the EPII. */
                        ep->phys[0] = 3;
                }
@@ -525,8 +475,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
        /* The lower four bits are the media type. */
        if (duplex) {
                ep->mii.force_media = ep->mii.full_duplex = 1;
-               printk(KERN_INFO DRV_NAME "(%s):  Forced full duplex operation requested.\n",
-                      pci_name(pdev));
+               dev_info(&pdev->dev, "Forced full duplex requested.\n");
        }
        dev->if_port = ep->default_port = option;
 
index c701951..97d34fe 100644 (file)
@@ -124,7 +124,9 @@ MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered mult
 MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
 
-#define MIN_REGION_SIZE 136
+enum {
+       MIN_REGION_SIZE         = 136,
+};
 
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
 enum chip_capability_flags {
@@ -146,14 +148,13 @@ enum phy_type_flags {
 
 struct chip_info {
        char *chip_name;
-       int io_size;
        int flags;
 };
 
-static const struct chip_info skel_netdrv_tbl[] = {
-       {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
-       {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR},
-       {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
+static const struct chip_info skel_netdrv_tbl[] __devinitdata = {
+       { "100/10M Ethernet PCI Adapter",       HAS_MII_XCVR },
+       { "100/10M Ethernet PCI Adapter",       HAS_CHIP_XCVR },
+       { "1000/100/10M Ethernet PCI Adapter",  HAS_MII_XCVR },
 };
 
 /* Offsets to the Command and Status Registers. */
@@ -504,13 +505,14 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
        
        len = pci_resource_len(pdev, bar);
        if (len < MIN_REGION_SIZE) {
-               printk(KERN_ERR "%s: region size %ld too small, aborting\n",
-                      boardname, len);
+               dev_err(&pdev->dev,
+                          "region size %ld too small, aborting\n", len);
                return -ENODEV;
        }
 
        i = pci_request_regions(pdev, boardname);
-       if (i) return i;
+       if (i)
+               return i;
        
        irq = pdev->irq;
 
@@ -576,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
 
                        if (mii_status != 0xffff && mii_status != 0x0000) {
                                np->phys[phy_idx++] = phy;
-                               printk(KERN_INFO
-                                      "%s: MII PHY found at address %d, status "
-                                      "0x%4.4x.\n", dev->name, phy, mii_status);
+                               dev_info(&pdev->dev,
+                                      "MII PHY found at address %d, status "
+                                      "0x%4.4x.\n", phy, mii_status);
                                /* get phy type */
                                {
                                        unsigned int data;
@@ -601,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
                }
 
                np->mii_cnt = phy_idx;
-               if (phy_idx == 0) {
-                       printk(KERN_WARNING "%s: MII PHY not found -- this device may "
-                              "not operate correctly.\n", dev->name);
-               }
+               if (phy_idx == 0)
+                       dev_warn(&pdev->dev,
+                               "MII PHY not found -- this device may "
+                              "not operate correctly.\n");
        } else {
                np->phys[0] = 32;
 /* 89/6/23 add, (begin) */
@@ -630,7 +632,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
                np->mii.full_duplex = full_duplex[card_idx];
 
        if (np->mii.full_duplex) {
-               printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+               dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");
 /* 89/6/13 add, (begin) */
 //      if (np->PHYType==MarvellPHY)
                if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
index 49dacc6..2b4db74 100644 (file)
@@ -699,7 +699,6 @@ static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
        memset(gp, 0, sizeof(*gp)); // clear it
 
        gp->port_num = port_num;
-       gp->io_size = GT96100_ETH_IO_SIZE;
        gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
        gp->phy_addr = phy_addr;
        gp->chip_rev = chip_rev;
@@ -1531,7 +1530,7 @@ static void gt96100_cleanup_module(void)
                                + sizeof(gt96100_td_t) * TX_RING_SIZE,
                                gp->rx_ring);
                        free_netdev(gtif->dev);
-                       release_region(gtif->iobase, gp->io_size);
+                       release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
                }
        }
 }
index 2a83319..3b62a87 100644 (file)
@@ -331,7 +331,6 @@ struct gt96100_private {
        mib_counters_t mib;
        struct net_device_stats stats;
 
-       int io_size;
        int port_num;  // 0 or 1
        int chip_rev;
        u32 port_offset;
@@ -340,7 +339,6 @@ struct gt96100_private {
        u32 last_psr; // last value of the port status register
 
        int options;     /* User-settable misc. driver options. */
-       int drv_flags;
        struct timer_list timer;
        spinlock_t lock; /* Serialise access to device */
 };
index 7bcd939..409c6aa 100644 (file)
 
        Support and updates available at
        http://www.scyld.com/network/hamachi.html
+       [link no longer provides useful info -jgarzik]
        or
        http://www.parl.clemson.edu/~keithu/hamachi.html
 
-
-
-       Linux kernel changelog:
-
-       LK1.0.1:
-       - fix lack of pci_dev<->dev association
-       - ethtool support (jgarzik)
-
 */
 
 #define DRV_NAME       "hamachi"
-#define DRV_VERSION    "1.01+LK1.0.1"
-#define DRV_RELDATE    "5/18/2001"
+#define DRV_VERSION    "2.0"
+#define DRV_RELDATE    "June 27, 2006"
 
 
 /* A few user-configurable values. */
@@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
        pci_set_master(pdev);
 
        i = pci_request_regions(pdev, DRV_NAME);
-       if (i) return i;
+       if (i)
+               return i;
 
        irq = pdev->irq;
        ioaddr = ioremap(base, 0x400);
index 72aad42..f4c8fd3 100644 (file)
@@ -188,7 +188,6 @@ struct myri10ge_priv {
        int vendor_specific_offset;
        u32 devctl;
        u16 msi_flags;
-       u32 pm_state[16];
        u32 read_dma;
        u32 write_dma;
        u32 read_write_dma;
@@ -1289,6 +1288,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
        "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
        "tx_heartbeat_errors", "tx_window_errors",
        /* device-specific stats */
+       "tx_boundary", "WC", "irq", "MSI",
        "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
        "serial_number", "tx_pkt_start", "tx_pkt_done",
        "tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
@@ -1327,6 +1327,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
        for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
                data[i] = ((unsigned long *)&mgp->stats)[i];
 
+       data[i++] = (unsigned int)mgp->tx.boundary;
+       data[i++] = (unsigned int)(mgp->mtrr >= 0);
+       data[i++] = (unsigned int)mgp->pdev->irq;
+       data[i++] = (unsigned int)mgp->msi_enabled;
        data[i++] = (unsigned int)mgp->read_dma;
        data[i++] = (unsigned int)mgp->write_dma;
        data[i++] = (unsigned int)mgp->read_write_dma;
@@ -2197,8 +2201,6 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
  * any other device, except if forced with myri10ge_ecrc_enable > 1.
  */
 
-#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
-
 static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
 {
        struct pci_dev *bridge = mgp->pdev->bus->self;
@@ -2737,11 +2739,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
                goto abort_with_irq;
        }
-
-       printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
-              netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
-              pdev->irq, mgp->tx.boundary, mgp->fw_name,
-              (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+       dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+                (mgp->msi_enabled ? "MSI" : "xPIC"),
+                pdev->irq, mgp->tx.boundary, mgp->fw_name,
+                (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
 
        return 0;
 
index 9df2628..db0475a 100644 (file)
 
        Support information and updates available at
        http://www.scyld.com/network/netsemi.html
+       [link no longer provides useful info -jgarzik]
 
 
-       Linux kernel modifications:
-
-       Version 1.0.1:
-               - Spinlock fixes
-               - Bug fixes and better intr performance (Tjeerd)
-       Version 1.0.2:
-               - Now reads correct MAC address from eeprom
-       Version 1.0.3:
-               - Eliminate redundant priv->tx_full flag
-               - Call netif_start_queue from dev->tx_timeout
-               - wmb() in start_tx() to flush data
-               - Update Tx locking
-               - Clean up PCI enable (davej)
-       Version 1.0.4:
-               - Merge Donald Becker's natsemi.c version 1.07
-       Version 1.0.5:
-               - { fill me in }
-       Version 1.0.6:
-               * ethtool support (jgarzik)
-               * Proper initialization of the card (which sometimes
-               fails to occur and leaves the card in a non-functional
-               state). (uzi)
-
-               * Some documented register settings to optimize some
-               of the 100Mbit autodetection circuitry in rev C cards. (uzi)
-
-               * Polling of the PHY intr for stuff like link state
-               change and auto- negotiation to finally work properly. (uzi)
-
-               * One-liner removal of a duplicate declaration of
-               netdev_error(). (uzi)
-
-       Version 1.0.7: (Manfred Spraul)
-               * pci dma
-               * SMP locking update
-               * full reset added into tx_timeout
-               * correct multicast hash generation (both big and little endian)
-                       [copied from a natsemi driver version
-                        from Myrio Corporation, Greg Smith]
-               * suspend/resume
-
-       version 1.0.8 (Tim Hockin <thockin@sun.com>)
-               * ETHTOOL_* support
-               * Wake on lan support (Erik Gilling)
-               * MXDMA fixes for serverworks
-               * EEPROM reload
-
-       version 1.0.9 (Manfred Spraul)
-               * Main change: fix lack of synchronize
-               netif_close/netif_suspend against a last interrupt
-               or packet.
-               * do not enable superflous interrupts (e.g. the
-               drivers relies on TxDone - TxIntr not needed)
-               * wait that the hardware has really stopped in close
-               and suspend.
-               * workaround for the (at least) gcc-2.95.1 compiler
-               problem. Also simplifies the code a bit.
-               * disable_irq() in tx_timeout - needed to protect
-               against rx interrupts.
-               * stop the nic before switching into silent rx mode
-               for wol (required according to docu).
-
-       version 1.0.10:
-               * use long for ee_addr (various)
-               * print pointers properly (DaveM)
-               * include asm/irq.h (?)
-
-       version 1.0.11:
-               * check and reset if PHY errors appear (Adrian Sun)
-               * WoL cleanup (Tim Hockin)
-               * Magic number cleanup (Tim Hockin)
-               * Don't reload EEPROM on every reset (Tim Hockin)
-               * Save and restore EEPROM state across reset (Tim Hockin)
-               * MDIO Cleanup (Tim Hockin)
-               * Reformat register offsets/bits (jgarzik)
-
-       version 1.0.12:
-               * ETHTOOL_* further support (Tim Hockin)
-
-       version 1.0.13:
-               * ETHTOOL_[G]EEPROM support (Tim Hockin)
-
-       version 1.0.13:
-               * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
-
-       version 1.0.14:
-               * Cleanup some messages and autoneg in ethtool (Tim Hockin)
-
-       version 1.0.15:
-               * Get rid of cable_magic flag
-               * use new (National provided) solution for cable magic issue
-
-       version 1.0.16:
-               * call netdev_rx() for RxErrors (Manfred Spraul)
-               * formatting and cleanups
-               * change options and full_duplex arrays to be zero
-                 initialized
-               * enable only the WoL and PHY interrupts in wol mode
-
-       version 1.0.17:
-               * only do cable_magic on 83815 and early 83816 (Tim Hockin)
-               * create a function for rx refill (Manfred Spraul)
-               * combine drain_ring and init_ring (Manfred Spraul)
-               * oom handling (Manfred Spraul)
-               * hands_off instead of playing with netif_device_{de,a}ttach
-                 (Manfred Spraul)
-               * be sure to write the MAC back to the chip (Manfred Spraul)
-               * lengthen EEPROM timeout, and always warn about timeouts
-                 (Manfred Spraul)
-               * comments update (Manfred)
-               * do the right thing on a phy-reset (Manfred and Tim)
-
        TODO:
        * big endian support with CFG:BEM instead of cpu_to_le32
 */
 #include <asm/uaccess.h>
 
 #define DRV_NAME       "natsemi"
-#define DRV_VERSION    "1.07+LK1.0.17"
-#define DRV_RELDATE    "Sep 27, 2002"
+#define DRV_VERSION    "2.0"
+#define DRV_RELDATE    "June 27, 2006"
 
 #define RX_OFFSET      2
 
index fa50eb8..34bdba9 100644 (file)
@@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
        irq = pdev->irq;
 
        if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
-               printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
+               dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
                return -ENODEV;
        }
 
        if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
-               printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
+               dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
                        NE_IO_EXTENT, ioaddr);
                return -EBUSY;
        }
@@ -263,7 +263,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
        /* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
        dev = alloc_ei_netdev();
        if (!dev) {
-               printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+               dev_err(&pdev->dev, "cannot allocate ethernet device\n");
                goto err_out_free_res;
        }
        SET_MODULE_OWNER(dev);
@@ -281,7 +281,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
                while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
                        /* Limit wait: '2' avoids jiffy roll-over. */
                        if (jiffies - reset_start_time > 2) {
-                               printk(KERN_ERR PFX "Card failure (no reset ack).\n");
+                               dev_err(&pdev->dev,
+                                       "Card failure (no reset ack).\n");
                                goto err_out_free_netdev;
                        }
 
index a68bf47..d4be207 100644 (file)
@@ -1,17 +1,12 @@
 /*     ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
  *
- *     Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr.
+ *     Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
  *
  *     This software may be used and distributed according to the terms
  *     of the GNU General Public License, incorporated herein by reference.
  *
  *     The authors may be reached as:
- *             jvbest@wi.leidenuniv.nl         a.mohr@mailto.de
- *     or by snail mail as
- *             Jan-Pascal van Best             Andreas Mohr
- *             Klikspaanweg 58-4               Stauferstr. 6
- *             2324 LZ  Leiden                 D-71272 Renningen
- *             The Netherlands                 Germany
+ *             janpascal@vanbest.org           andi@lisas.de
  *
  *     Sources:
  *             Donald Becker's "skeleton.c"
@@ -27,8 +22,9 @@
  *     970503  v0.93: Fixed auto-irq failure on warm reboot (JB)
  *     970623  v1.00: First kernel version (AM)
  *     970814  v1.01: Added detection of onboard receive buffer size (AM)
+ *     060611  v1.02: slight cleanup: email addresses, driver modernization.
  *     Bugs:
- *             - None known...
+ *             - not SMP-safe (no locking of I/O accesses)
  *             - Note that you have to patch ifconfig for the new /proc/net/dev
  *             format. It gives incorrect stats otherwise.
  *
@@ -39,7 +35,7 @@
  *             Complete merge with Andreas' driver
  *             Implement ring buffers (Is this useful? You can't squeeze
  *                     too many packet in a 2k buffer!)
- *             Implement DMA (Again, is this useful? Some docs says DMA is
+ *             Implement DMA (Again, is this useful? Some docs say DMA is
  *                     slower than programmed I/O)
  *
  *     Compile with:
@@ -47,7 +43,7 @@
  *                     -DMODULE -c ni5010.c 
  *
  *     Insert with e.g.:
- *             insmod ni5010.o io=0x300 irq=5  
+ *             insmod ni5010.ko io=0x300 irq=5
  */
 
 #include <linux/module.h>
 
 #include "ni5010.h"
 
-static const char *boardname = "NI5010";
-static char *version =
-       "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
+static const char boardname[] = "NI5010";
+static char version[] __initdata =
+       "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
        
 /* bufsize_rcv == 0 means autoprobing */
 static unsigned int bufsize_rcv;
 
-#define jumpered_interrupts    /* IRQ line jumpered on board */
-#undef jumpered_dma            /* No DMA used */
+#define JUMPERED_INTERRUPTS    /* IRQ line jumpered on board */
+#undef JUMPERED_DMA            /* No DMA used */
 #undef FULL_IODETECT           /* Only detect in portlist */
 
 #ifndef FULL_IODETECT
@@ -281,7 +277,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
 
        PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
 
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
        if (dev->irq == 0xff)
                ;
        else if (dev->irq < 2) {
@@ -305,7 +301,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
        } else if (dev->irq == 2) {
                dev->irq = 9;
        }
-#endif /* jumpered_irq */
+#endif /* JUMPERED_INTERRUPTS */
        PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
 
        /* DMA is not supported (yet?), so no use detecting it */
@@ -334,7 +330,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
                outw(0, IE_GP);         /* Point GP at start of packet */
                outb(0, IE_RBUF);       /* set buffer byte 0 to 0 again */
        }
-        printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
+        printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
        memset(dev->priv, 0, sizeof(struct ni5010_local));
        
        dev->open               = ni5010_open;
@@ -354,11 +350,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
        outb(0xff, EDLC_XCLR);  /* Kill all pending xmt interrupts */
 
        printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
-       if (dev->dma) printk(" & DMA %d", dev->dma);
+       if (dev->dma)
+               printk(" & DMA %d", dev->dma);
        printk(".\n");
-
-       printk(KERN_INFO "Join the NI5010 driver development team!\n");
-       printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n");
        return 0;
 out:
        release_region(dev->base_addr, NI5010_IO_EXTENT);
@@ -371,7 +365,7 @@ out:
  *
  * This routine should set everything up anew at each open, even
  * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * there is non-reboot way to recover if something goes wrong.
  */
    
 static int ni5010_open(struct net_device *dev)
@@ -390,13 +384,13 @@ static int ni5010_open(struct net_device *dev)
          * Always allocate the DMA channel after the IRQ,
          * and clean up on failure.
          */
-#ifdef jumpered_dma
+#ifdef JUMPERED_DMA
         if (request_dma(dev->dma, cardname)) {
                printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
                 free_irq(dev->irq, NULL);
                 return -EAGAIN;
         }
-#endif /* jumpered_dma */
+#endif /* JUMPERED_DMA */
 
        PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
        /* Reset the hardware here.  Don't forget to set the station address. */
@@ -633,7 +627,7 @@ static int ni5010_close(struct net_device *dev)
        int ioaddr = dev->base_addr;
 
        PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef jumpered_interrupts     
+#ifdef JUMPERED_INTERRUPTS
        free_irq(dev->irq, NULL);
 #endif
        /* Put card in held-RESET state */
@@ -771,7 +765,7 @@ module_param(irq, int, 0);
 MODULE_PARM_DESC(io, "ni5010 I/O base address");
 MODULE_PARM_DESC(irq, "ni5010 IRQ number");
 
-int init_module(void)
+static int __init ni5010_init_module(void)
 {
        PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
        /*
@@ -792,13 +786,15 @@ int init_module(void)
         return 0;
 }
 
-void cleanup_module(void)
+static void __exit ni5010_cleanup_module(void)
 {
        PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
        unregister_netdev(dev_ni5010);
        release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
        free_netdev(dev_ni5010);
 }
+module_init(ni5010_init_module);
+module_exit(ni5010_cleanup_module);
 #endif /* MODULE */
 MODULE_LICENSE("GPL");
 
index 7042910..0e76859 100644 (file)
@@ -803,7 +803,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
 
                writel(dev->IMR_cache, dev->base + IMR);
                writel(1, dev->base + IER);
-               spin_unlock_irq(&dev->misc_lock);
+               spin_unlock(&dev->misc_lock);
 
                kick_rx(ndev);
 
@@ -1012,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
        struct ns83820 *dev = PRIV(ndev);
        u32 cmdsts, tx_done_idx, *desc;
 
-       spin_lock_irq(&dev->tx_lock);
-
        dprintk("do_tx_done(%p)\n", ndev);
        tx_done_idx = dev->tx_done_idx;
        desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1069,7 +1067,6 @@ static void do_tx_done(struct net_device *ndev)
                netif_start_queue(ndev);
                netif_wake_queue(ndev);
        }
-       spin_unlock_irq(&dev->tx_lock);
 }
 
 static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -1281,11 +1278,13 @@ static struct ethtool_ops ops = {
        .get_link = ns83820_get_link
 };
 
+/* this function is called in irq context from the ISR */
 static void ns83820_mib_isr(struct ns83820 *dev)
 {
-       spin_lock(&dev->misc_lock);
+       unsigned long flags;
+       spin_lock_irqsave(&dev->misc_lock, flags);
        ns83820_update_stats(dev);
-       spin_unlock(&dev->misc_lock);
+       spin_unlock_irqrestore(&dev->misc_lock, flags);
 }
 
 static void ns83820_do_isr(struct net_device *ndev, u32 isr);
@@ -1307,6 +1306,8 @@ static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
 static void ns83820_do_isr(struct net_device *ndev, u32 isr)
 {
        struct ns83820 *dev = PRIV(ndev);
+       unsigned long flags;
+
 #ifdef DEBUG
        if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
                Dprintk("odd isr? 0x%08x\n", isr);
@@ -1321,10 +1322,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
        if ((ISR_RXDESC | ISR_RXOK) & isr) {
                prefetch(dev->rx_info.next_rx_desc);
 
-               spin_lock_irq(&dev->misc_lock);
+               spin_lock_irqsave(&dev->misc_lock, flags);
                dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
                writel(dev->IMR_cache, dev->base + IMR);
-               spin_unlock_irq(&dev->misc_lock);
+               spin_unlock_irqrestore(&dev->misc_lock, flags);
 
                tasklet_schedule(&dev->rx_tasklet);
                //rx_irq(ndev);
@@ -1370,16 +1371,18 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
         * work has accumulated
         */
        if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
+               spin_lock_irqsave(&dev->tx_lock, flags);
                do_tx_done(ndev);
+               spin_unlock_irqrestore(&dev->tx_lock, flags);
 
                /* Disable TxOk if there are no outstanding tx packets.
                 */
                if ((dev->tx_done_idx == dev->tx_free_idx) &&
                    (dev->IMR_cache & ISR_TXOK)) {
-                       spin_lock_irq(&dev->misc_lock);
+                       spin_lock_irqsave(&dev->misc_lock, flags);
                        dev->IMR_cache &= ~ISR_TXOK;
                        writel(dev->IMR_cache, dev->base + IMR);
-                       spin_unlock_irq(&dev->misc_lock);
+                       spin_unlock_irqrestore(&dev->misc_lock, flags);
                }
        }
 
@@ -1390,10 +1393,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
         * nature are expected, we must enable TxOk.
         */
        if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
-               spin_lock_irq(&dev->misc_lock);
+               spin_lock_irqsave(&dev->misc_lock, flags);
                dev->IMR_cache |= ISR_TXOK;
                writel(dev->IMR_cache, dev->base + IMR);
-               spin_unlock_irq(&dev->misc_lock);
+               spin_unlock_irqrestore(&dev->misc_lock, flags);
        }
 
        /* MIB interrupt: one of the statistics counters is about to overflow */
@@ -1455,7 +1458,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
         u32 tx_done_idx, *desc;
        unsigned long flags;
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&dev->tx_lock, flags);
 
        tx_done_idx = dev->tx_done_idx;
        desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1482,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
                ndev->name,
                tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
 
-       local_irq_restore(flags);
+       spin_unlock_irqrestore(&dev->tx_lock, flags);
 }
 
 static void ns83820_tx_watch(unsigned long data)
@@ -1832,7 +1835,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        } else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
                using_dac = 0;
        } else {
-               printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
+               dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n");
                return -ENODEV;
        }
 
@@ -1855,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
 
        err = pci_enable_device(pci_dev);
        if (err) {
-               printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
+               dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
                goto out_free;
        }
 
@@ -1884,8 +1887,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
                          DRV_NAME, ndev);
        if (err) {
-               printk(KERN_INFO "ns83820: unable to register irq %d\n",
-                       pci_dev->irq);
+               dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
+                       pci_dev->irq, err);
                goto out_disable;
        }
 
@@ -1899,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
        rtnl_lock();
        err = dev_alloc_name(ndev, ndev->name);
        if (err < 0) {
-               printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err);
+               dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err);
                goto out_free_irq;
        }
 
index 3388ee1..e0e2939 100644 (file)
@@ -601,7 +601,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
        /* dev zeroed in alloc_etherdev */
        dev = alloc_etherdev (sizeof (*tp));
        if (dev == NULL) {
-               printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+               dev_err(&pdev->dev, "unable to alloc new ethernet\n");
                DPRINTK ("EXIT, returning -ENOMEM\n");
                return -ENOMEM;
        }
@@ -631,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
 
        /* make sure PCI base addr 0 is PIO */
        if (!(pio_flags & IORESOURCE_IO)) {
-               printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
+               dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
 
        /* make sure PCI base addr 1 is MMIO */
        if (!(mmio_flags & IORESOURCE_MEM)) {
-               printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
+               dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
@@ -646,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
        /* check for weird/broken PCI region reporting */
        if ((pio_len < NETDRV_MIN_IO_SIZE) ||
            (mmio_len < NETDRV_MIN_IO_SIZE)) {
-               printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+               dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
                rc = -ENODEV;
                goto err_out;
        }
 
-       rc = pci_request_regions (pdev, "pci-skeleton");
+       rc = pci_request_regions (pdev, MODNAME);
        if (rc)
                goto err_out;
 
@@ -663,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
        /* ioremap MMIO region */
        ioaddr = ioremap (mmio_start, mmio_len);
        if (ioaddr == NULL) {
-               printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+               dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
                rc = -EIO;
                goto err_out_free_res;
        }
@@ -699,9 +699,10 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
                }
 
        /* if unknown chip, assume array element #0, original RTL-8139 in this case */
-       printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
-               pci_name(pdev));
-       printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));
+       dev_printk (KERN_DEBUG, &pdev->dev,
+               "unknown chip version, assuming RTL-8139\n");
+       dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
+               NETDRV_R32 (TxConfig));
        tp->chipset = 0;
 
 match:
index d768f3d..4daafe3 100644 (file)
@@ -58,18 +58,15 @@ static const char *const version =
  * PCI device identifiers for "new style" Linux PCI Device Drivers
  */
 static struct pci_device_id pcnet32_pci_tbl[] = {
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
-         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
 
        /*
         * Adapters that were sold with IBM's RS/6000 or pSeries hardware have
         * the incorrect vendor id.
         */
-       { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
-         PCI_ANY_ID, PCI_ANY_ID,
-         PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+       { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+         .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
 
        { }     /* terminate list */
 };
@@ -188,6 +185,23 @@ static int homepna[MAX_UNITS];
 
 #define PCNET32_TOTAL_SIZE     0x20
 
+#define CSR0           0
+#define CSR0_INIT      0x1
+#define CSR0_START     0x2
+#define CSR0_STOP      0x4
+#define CSR0_TXPOLL    0x8
+#define CSR0_INTEN     0x40
+#define CSR0_IDON      0x0100
+#define CSR0_NORMAL    (CSR0_START | CSR0_INTEN)
+#define PCNET32_INIT_LOW       1
+#define PCNET32_INIT_HIGH      2
+#define CSR3           3
+#define CSR4           4
+#define CSR5           5
+#define CSR5_SUSPEND   0x0001
+#define CSR15          15
+#define PCNET32_MC_FILTER      8
+
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
        u32     base;
@@ -277,7 +291,6 @@ struct pcnet32_private {
        u32                     phymask;
 };
 
-static void pcnet32_probe_vlbus(void);
 static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
 static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
 static int pcnet32_open(struct net_device *);
@@ -419,6 +432,238 @@ static struct pcnet32_access pcnet32_dwio = {
        .reset = pcnet32_dwio_reset
 };
 
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+       dev->trans_start = jiffies;
+       netif_poll_disable(dev);
+       netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+       netif_wake_queue(dev);
+       netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+                                   struct pcnet32_private *lp,
+                                   unsigned int size)
+{
+       dma_addr_t new_ring_dma_addr;
+       dma_addr_t *new_dma_addr_list;
+       struct pcnet32_tx_head *new_tx_ring;
+       struct sk_buff **new_skb_list;
+
+       pcnet32_purge_tx_ring(dev);
+
+       new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+                                          sizeof(struct pcnet32_tx_head) *
+                                          (1 << size),
+                                          &new_ring_dma_addr);
+       if (new_tx_ring == NULL) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Consistent memory allocation failed.\n",
+                              dev->name);
+               return;
+       }
+       memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+       new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+                               GFP_ATOMIC);
+       if (!new_dma_addr_list) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Memory allocation failed.\n", dev->name);
+               goto free_new_tx_ring;
+       }
+
+       new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+                               GFP_ATOMIC);
+       if (!new_skb_list) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Memory allocation failed.\n", dev->name);
+               goto free_new_lists;
+       }
+
+       kfree(lp->tx_skbuff);
+       kfree(lp->tx_dma_addr);
+       pci_free_consistent(lp->pci_dev,
+                           sizeof(struct pcnet32_tx_head) *
+                           lp->tx_ring_size, lp->tx_ring,
+                           lp->tx_ring_dma_addr);
+
+       lp->tx_ring_size = (1 << size);
+       lp->tx_mod_mask = lp->tx_ring_size - 1;
+       lp->tx_len_bits = (size << 12);
+       lp->tx_ring = new_tx_ring;
+       lp->tx_ring_dma_addr = new_ring_dma_addr;
+       lp->tx_dma_addr = new_dma_addr_list;
+       lp->tx_skbuff = new_skb_list;
+       return;
+
+    free_new_lists:
+       kfree(new_dma_addr_list);
+    free_new_tx_ring:
+       pci_free_consistent(lp->pci_dev,
+                           sizeof(struct pcnet32_tx_head) *
+                           (1 << size),
+                           new_tx_ring,
+                           new_ring_dma_addr);
+       return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ *   alloc extra buffers
+ *   free unneeded buffers
+ *   free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+                                   struct pcnet32_private *lp,
+                                   unsigned int size)
+{
+       dma_addr_t new_ring_dma_addr;
+       dma_addr_t *new_dma_addr_list;
+       struct pcnet32_rx_head *new_rx_ring;
+       struct sk_buff **new_skb_list;
+       int new, overlap;
+
+       new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+                                          sizeof(struct pcnet32_rx_head) *
+                                          (1 << size),
+                                          &new_ring_dma_addr);
+       if (new_rx_ring == NULL) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Consistent memory allocation failed.\n",
+                              dev->name);
+               return;
+       }
+       memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+       new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+                               GFP_ATOMIC);
+       if (!new_dma_addr_list) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Memory allocation failed.\n", dev->name);
+               goto free_new_rx_ring;
+       }
+
+       new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+                               GFP_ATOMIC);
+       if (!new_skb_list) {
+               if (netif_msg_drv(lp))
+                       printk("\n" KERN_ERR
+                              "%s: Memory allocation failed.\n", dev->name);
+               goto free_new_lists;
+       }
+
+       /* first copy the current receive buffers */
+       overlap = min(size, lp->rx_ring_size);
+       for (new = 0; new < overlap; new++) {
+               new_rx_ring[new] = lp->rx_ring[new];
+               new_dma_addr_list[new] = lp->rx_dma_addr[new];
+               new_skb_list[new] = lp->rx_skbuff[new];
+       }
+       /* now allocate any new buffers needed */
+       for (; new < size; new++ ) {
+               struct sk_buff *rx_skbuff;
+               new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+               if (!(rx_skbuff = new_skb_list[new])) {
+                       /* keep the original lists and buffers */
+                       if (netif_msg_drv(lp))
+                               printk(KERN_ERR
+                                      "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+                                      dev->name);
+                       goto free_all_new;
+               }
+               skb_reserve(rx_skbuff, 2);
+
+               new_dma_addr_list[new] =
+                           pci_map_single(lp->pci_dev, rx_skbuff->data,
+                                          PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+               new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+               new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+               new_rx_ring[new].status = le16_to_cpu(0x8000);
+       }
+       /* and free any unneeded buffers */
+       for (; new < lp->rx_ring_size; new++) {
+               if (lp->rx_skbuff[new]) {
+                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(lp->rx_skbuff[new]);
+               }
+       }
+
+       kfree(lp->rx_skbuff);
+       kfree(lp->rx_dma_addr);
+       pci_free_consistent(lp->pci_dev,
+                           sizeof(struct pcnet32_rx_head) *
+                           lp->rx_ring_size, lp->rx_ring,
+                           lp->rx_ring_dma_addr);
+
+       lp->rx_ring_size = (1 << size);
+       lp->rx_mod_mask = lp->rx_ring_size - 1;
+       lp->rx_len_bits = (size << 4);
+       lp->rx_ring = new_rx_ring;
+       lp->rx_ring_dma_addr = new_ring_dma_addr;
+       lp->rx_dma_addr = new_dma_addr_list;
+       lp->rx_skbuff = new_skb_list;
+       return;
+
+    free_all_new:
+       for (; --new >= lp->rx_ring_size; ) {
+               if (new_skb_list[new]) {
+                       pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb(new_skb_list[new]);
+               }
+       }
+       kfree(new_skb_list);
+    free_new_lists:
+       kfree(new_dma_addr_list);
+    free_new_rx_ring:
+       pci_free_consistent(lp->pci_dev,
+                           sizeof(struct pcnet32_rx_head) *
+                           (1 << size),
+                           new_rx_ring,
+                           new_ring_dma_addr);
+       return;
+}
+
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+       struct pcnet32_private *lp = dev->priv;
+       int i;
+
+       /* free all allocated skbuffs */
+       for (i = 0; i < lp->rx_ring_size; i++) {
+               lp->rx_ring[i].status = 0;      /* CPU owns buffer */
+               wmb();          /* Make sure adapter sees owner change */
+               if (lp->rx_skbuff[i]) {
+                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+                       dev_kfree_skb_any(lp->rx_skbuff[i]);
+               }
+               lp->rx_skbuff[i] = NULL;
+               lp->rx_dma_addr[i] = 0;
+       }
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void pcnet32_poll_controller(struct net_device *dev)
 {
@@ -519,10 +764,10 @@ static void pcnet32_get_ringparam(struct net_device *dev,
 {
        struct pcnet32_private *lp = dev->priv;
 
-       ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
-       ering->tx_pending = lp->tx_ring_size - 1;
-       ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
-       ering->rx_pending = lp->rx_ring_size - 1;
+       ering->tx_max_pending = TX_MAX_RING_SIZE;
+       ering->tx_pending = lp->tx_ring_size;
+       ering->rx_max_pending = RX_MAX_RING_SIZE;
+       ering->rx_pending = lp->rx_ring_size;
 }
 
 static int pcnet32_set_ringparam(struct net_device *dev,
@@ -530,56 +775,53 @@ static int pcnet32_set_ringparam(struct net_device *dev,
 {
        struct pcnet32_private *lp = dev->priv;
        unsigned long flags;
+       unsigned int size;
+       ulong ioaddr = dev->base_addr;
        int i;
 
        if (ering->rx_mini_pending || ering->rx_jumbo_pending)
                return -EINVAL;
 
        if (netif_running(dev))
-               pcnet32_close(dev);
+               pcnet32_netif_stop(dev);
 
        spin_lock_irqsave(&lp->lock, flags);
-       pcnet32_free_ring(dev);
-       lp->tx_ring_size =
-           min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
-       lp->rx_ring_size =
-           min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* stop the chip */
+
+       size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
 
        /* set the minimum ring size to 4, to allow the loopback test to work
         * unchanged.
         */
        for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
-               if (lp->tx_ring_size <= (1 << i))
+               if (size <= (1 << i))
                        break;
        }
-       lp->tx_ring_size = (1 << i);
-       lp->tx_mod_mask = lp->tx_ring_size - 1;
-       lp->tx_len_bits = (i << 12);
-
+       if ((1 << i) != lp->tx_ring_size)
+               pcnet32_realloc_tx_ring(dev, lp, i);
+       
+       size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
        for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
-               if (lp->rx_ring_size <= (1 << i))
+               if (size <= (1 << i))
                        break;
        }
-       lp->rx_ring_size = (1 << i);
-       lp->rx_mod_mask = lp->rx_ring_size - 1;
-       lp->rx_len_bits = (i << 4);
+       if ((1 << i) != lp->rx_ring_size)
+               pcnet32_realloc_rx_ring(dev, lp, i);
+       
+       dev->weight = lp->rx_ring_size / 2;
 
-       if (pcnet32_alloc_ring(dev, dev->name)) {
-               pcnet32_free_ring(dev);
-               spin_unlock_irqrestore(&lp->lock, flags);
-               return -ENOMEM;
+       if (netif_running(dev)) {
+               pcnet32_netif_start(dev);
+               pcnet32_restart(dev, CSR0_NORMAL);
        }
 
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       if (pcnet32_debug & NETIF_MSG_DRV)
-               printk(KERN_INFO PFX
+       if (netif_msg_drv(lp))
+               printk(KERN_INFO
                       "%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
                       lp->rx_ring_size, lp->tx_ring_size);
 
-       if (netif_running(dev))
-               pcnet32_open(dev);
-
        return 0;
 }
 
@@ -633,29 +875,27 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
        unsigned long flags;
        unsigned long ticks;
 
-       *data1 = 1;             /* status of test, default to fail */
        rc = 1;                 /* default to fail */
 
        if (netif_running(dev))
                pcnet32_close(dev);
 
        spin_lock_irqsave(&lp->lock, flags);
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* stop the chip */
+
+       numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
 
        /* Reset the PCNET32 */
        lp->a.reset(ioaddr);
+       lp->a.write_csr(ioaddr, CSR4, 0x0915);
 
        /* switch pcnet32 to 32bit mode */
        lp->a.write_bcr(ioaddr, 20, 2);
 
-       lp->init_block.mode =
-           le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
-       lp->init_block.filter[0] = 0;
-       lp->init_block.filter[1] = 0;
-
        /* purge & init rings but don't actually restart */
        pcnet32_restart(dev, 0x0000);
 
-       lp->a.write_csr(ioaddr, 0, 0x0004);     /* Set STOP bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* Set STOP bit */
 
        /* Initialize Transmit buffers. */
        size = data_len + 15;
@@ -697,14 +937,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
        }
 
-       x = a->read_bcr(ioaddr, 32);    /* set internal loopback in BSR32 */
-       x = x | 0x0002;
-       a->write_bcr(ioaddr, 32, x);
+       x = a->read_bcr(ioaddr, 32);    /* set internal loopback in BCR32 */
+       a->write_bcr(ioaddr, 32, x | 0x0002);
 
-       lp->a.write_csr(ioaddr, 15, 0x0044);    /* set int loopback in CSR15 */
+       /* set int loopback in CSR15 */
+       x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+       lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
 
        teststatus = le16_to_cpu(0x8000);
-       lp->a.write_csr(ioaddr, 0, 0x0002);     /* Set STRT bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_START);      /* Set STRT bit */
 
        /* Check status of descriptors */
        for (x = 0; x < numbuffs; x++) {
@@ -712,7 +953,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                rmb();
                while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
                        spin_unlock_irqrestore(&lp->lock, flags);
-                       mdelay(1);
+                       msleep(1);
                        spin_lock_irqsave(&lp->lock, flags);
                        rmb();
                        ticks++;
@@ -725,7 +966,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
        }
 
-       lp->a.write_csr(ioaddr, 0, 0x0004);     /* Set STOP bit */
+       lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);       /* Set STOP bit */
        wmb();
        if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
                printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -758,25 +999,24 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                }
                x++;
        }
-       if (!rc) {
-               *data1 = 0;
-       }
 
       clean_up:
+       *data1 = rc;
        pcnet32_purge_tx_ring(dev);
-       x = a->read_csr(ioaddr, 15) & 0xFFFF;
-       a->write_csr(ioaddr, 15, (x & ~0x0044));        /* reset bits 6 and 2 */
 
-       x = a->read_bcr(ioaddr, 32);    /* reset internal loopback */
-       x = x & ~0x0002;
-       a->write_bcr(ioaddr, 32, x);
+       x = a->read_csr(ioaddr, CSR15);
+       a->write_csr(ioaddr, CSR15, (x & ~0x0044));     /* reset bits 6 and 2 */
 
-       spin_unlock_irqrestore(&lp->lock, flags);
+       x = a->read_bcr(ioaddr, 32);    /* reset internal loopback */
+       a->write_bcr(ioaddr, 32, (x & ~0x0002));
 
        if (netif_running(dev)) {
+               spin_unlock_irqrestore(&lp->lock, flags);
                pcnet32_open(dev);
        } else {
+               pcnet32_purge_rx_ring(dev);
                lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+               spin_unlock_irqrestore(&lp->lock, flags);
        }
 
        return (rc);
@@ -839,6 +1079,43 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
        return 0;
 }
 
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+               int can_sleep)
+{
+       int csr5;
+       struct pcnet32_private *lp = dev->priv;
+       struct pcnet32_access *a = &lp->a;
+       ulong ioaddr = dev->base_addr;
+       int ticks;
+
+       /* set SUSPEND (SPND) - CSR5 bit 0 */
+       csr5 = a->read_csr(ioaddr, CSR5);
+       a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+       /* poll waiting for bit to be set */
+       ticks = 0;
+       while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+               spin_unlock_irqrestore(&lp->lock, *flags);
+               if (can_sleep)
+                       msleep(1);
+               else
+                       mdelay(1);
+               spin_lock_irqsave(&lp->lock, *flags);
+               ticks++;
+               if (ticks > 200) {
+                       if (netif_msg_hw(lp))
+                               printk(KERN_DEBUG
+                                      "%s: Error getting into suspend!\n",
+                                      dev->name);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
 #define PCNET32_REGS_PER_PHY   32
 #define PCNET32_MAX_PHYS       32
 static int pcnet32_get_regs_len(struct net_device *dev)
@@ -857,32 +1134,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
        struct pcnet32_private *lp = dev->priv;
        struct pcnet32_access *a = &lp->a;
        ulong ioaddr = dev->base_addr;
-       int ticks;
        unsigned long flags;
 
        spin_lock_irqsave(&lp->lock, flags);
 
-       csr0 = a->read_csr(ioaddr, 0);
-       if (!(csr0 & 0x0004)) { /* If not stopped */
-               /* set SUSPEND (SPND) - CSR5 bit 0 */
-               a->write_csr(ioaddr, 5, 0x0001);
-
-               /* poll waiting for bit to be set */
-               ticks = 0;
-               while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
-                       spin_unlock_irqrestore(&lp->lock, flags);
-                       mdelay(1);
-                       spin_lock_irqsave(&lp->lock, flags);
-                       ticks++;
-                       if (ticks > 200) {
-                               if (netif_msg_hw(lp))
-                                       printk(KERN_DEBUG
-                                              "%s: Error getting into suspend!\n",
-                                              dev->name);
-                               break;
-                       }
-               }
-       }
+       csr0 = a->read_csr(ioaddr, CSR0);
+       if (!(csr0 & CSR0_STOP))        /* If not stopped */
+               pcnet32_suspend(dev, &flags, 1);
 
        /* read address PROM */
        for (i = 0; i < 16; i += 2)
@@ -919,9 +1177,12 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
                }
        }
 
-       if (!(csr0 & 0x0004)) { /* If not stopped */
+       if (!(csr0 & CSR0_STOP)) {      /* If not stopped */
+               int csr5;
+
                /* clear SUSPEND (SPND) - CSR5 bit 0 */
-               a->write_csr(ioaddr, 5, 0x0000);
+               csr5 = a->read_csr(ioaddr, CSR5);
+               a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
        }
 
        spin_unlock_irqrestore(&lp->lock, flags);
@@ -952,7 +1213,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
 /* only probes for non-PCI devices, the rest are handled by
  * pci_register_driver via pcnet32_probe_pci */
 
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
 {
        unsigned int *port, ioaddr;
 
@@ -1436,7 +1697,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
                                           lp->tx_ring_size,
                                           &lp->tx_ring_dma_addr);
        if (lp->tx_ring == NULL) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Consistent memory allocation failed.\n",
                               name);
@@ -1448,52 +1709,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
                                           lp->rx_ring_size,
                                           &lp->rx_ring_dma_addr);
        if (lp->rx_ring == NULL) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Consistent memory allocation failed.\n",
                               name);
                return -ENOMEM;
        }
 
-       lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
+       lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
                                  GFP_ATOMIC);
        if (!lp->tx_dma_addr) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
-       memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
 
-       lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
+       lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
                                  GFP_ATOMIC);
        if (!lp->rx_dma_addr) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
-       memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
 
-       lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
+       lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
                                GFP_ATOMIC);
        if (!lp->tx_skbuff) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
-       memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
 
-       lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
+       lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
                                GFP_ATOMIC);
        if (!lp->rx_skbuff) {
-               if (pcnet32_debug & NETIF_MSG_DRV)
+               if (netif_msg_drv(lp))
                        printk("\n" KERN_ERR PFX
                               "%s: Memory allocation failed.\n", name);
                return -ENOMEM;
        }
-       memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
 
        return 0;
 }
@@ -1757,16 +2014,7 @@ static int pcnet32_open(struct net_device *dev)
 
       err_free_ring:
        /* free any allocated skbuffs */
-       for (i = 0; i < lp->rx_ring_size; i++) {
-               lp->rx_ring[i].status = 0;
-               if (lp->rx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
-                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(lp->rx_skbuff[i]);
-               }
-               lp->rx_skbuff[i] = NULL;
-               lp->rx_dma_addr[i] = 0;
-       }
+       pcnet32_purge_rx_ring(dev);
 
        /*
         * Switch back to 16bit mode to avoid problems with dumb
@@ -2348,7 +2596,6 @@ static int pcnet32_close(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr;
        struct pcnet32_private *lp = dev->priv;
-       int i;
        unsigned long flags;
 
        del_timer_sync(&lp->watchdog_timer);
@@ -2379,31 +2626,8 @@ static int pcnet32_close(struct net_device *dev)
 
        spin_lock_irqsave(&lp->lock, flags);
 
-       /* free all allocated skbuffs */
-       for (i = 0; i < lp->rx_ring_size; i++) {
-               lp->rx_ring[i].status = 0;
-               wmb();          /* Make sure adapter sees owner change */
-               if (lp->rx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
-                                        PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(lp->rx_skbuff[i]);
-               }
-               lp->rx_skbuff[i] = NULL;
-               lp->rx_dma_addr[i] = 0;
-       }
-
-       for (i = 0; i < lp->tx_ring_size; i++) {
-               lp->tx_ring[i].status = 0;      /* CPU owns buffer */
-               wmb();          /* Make sure adapter sees owner change */
-               if (lp->tx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
-                                        lp->tx_skbuff[i]->len,
-                                        PCI_DMA_TODEVICE);
-                       dev_kfree_skb(lp->tx_skbuff[i]);
-               }
-               lp->tx_skbuff[i] = NULL;
-               lp->tx_dma_addr[i] = 0;
-       }
+       pcnet32_purge_rx_ring(dev);
+       pcnet32_purge_tx_ring(dev);
 
        spin_unlock_irqrestore(&lp->lock, flags);
 
@@ -2433,6 +2657,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
        volatile struct pcnet32_init_block *ib = &lp->init_block;
        volatile u16 *mcast_table = (u16 *) & ib->filter;
        struct dev_mc_list *dmi = dev->mc_list;
+       unsigned long ioaddr = dev->base_addr;
        char *addrs;
        int i;
        u32 crc;
@@ -2441,6 +2666,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
        if (dev->flags & IFF_ALLMULTI) {
                ib->filter[0] = 0xffffffff;
                ib->filter[1] = 0xffffffff;
+               lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+               lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+               lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+               lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
                return;
        }
        /* clear the multicast filter */
@@ -2462,6 +2691,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
                    le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
                                (1 << (crc & 0xf)));
        }
+       for (i = 0; i < 4; i++)
+               lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+                               le16_to_cpu(mcast_table[i]));
        return;
 }
 
@@ -2472,8 +2704,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
 {
        unsigned long ioaddr = dev->base_addr, flags;
        struct pcnet32_private *lp = dev->priv;
+       int csr15, suspended;
 
        spin_lock_irqsave(&lp->lock, flags);
+       suspended = pcnet32_suspend(dev, &flags, 0);
+       csr15 = lp->a.read_csr(ioaddr, CSR15);
        if (dev->flags & IFF_PROMISC) {
                /* Log any net taps. */
                if (netif_msg_hw(lp))
@@ -2482,15 +2717,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
                lp->init_block.mode =
                    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
                                7);
+               lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
        } else {
                lp->init_block.mode =
                    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+               lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
                pcnet32_load_multicast(dev);
        }
 
-       lp->a.write_csr(ioaddr, 0, 0x0004);     /* Temporarily stop the lance. */
-       pcnet32_restart(dev, 0x0042);   /*  Resume normal operation */
-       netif_wake_queue(dev);
+       if (suspended) {
+               int csr5;
+               /* clear SUSPEND (SPND) - CSR5 bit 0 */
+               csr5 = lp->a.read_csr(ioaddr, CSR5);
+               lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+       } else { 
+               lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+               pcnet32_restart(dev, CSR0_NORMAL);
+               netif_wake_queue(dev);
+       }
 
        spin_unlock_irqrestore(&lp->lock, flags);
 }
@@ -2730,7 +2974,7 @@ static int __init pcnet32_init_module(void)
 
        /* should we find any remaining VLbus devices ? */
        if (pcnet32vlb)
-               pcnet32_probe_vlbus();
+               pcnet32_probe_vlbus(pcnet32_portlist);
 
        if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
                printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
index 3efb715..ae60e6e 100644 (file)
@@ -103,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
        return err;
 }
 
-/* Cicada 820x */
+/* Cicada 8201, a.k.a Vitesse VSC8201 */
+static struct phy_driver cis8201_driver = {
+       .phy_id         = 0x000fc410,
+       .name           = "Cicada Cis8201",
+       .phy_id_mask    = 0x000ffff0,
+       .features       = PHY_GBIT_FEATURES,
+       .flags          = PHY_HAS_INTERRUPT,
+       .config_init    = &cis820x_config_init,
+       .config_aneg    = &genphy_config_aneg,
+       .read_status    = &genphy_read_status,
+       .ack_interrupt  = &cis820x_ack_interrupt,
+       .config_intr    = &cis820x_config_intr,
+       .driver         = { .owner = THIS_MODULE,},
+};
+
+/* Cicada 8204 */
 static struct phy_driver cis8204_driver = {
        .phy_id         = 0x000fc440,
        .name           = "Cicada Cis8204",
@@ -118,15 +133,30 @@ static struct phy_driver cis8204_driver = {
        .driver         = { .owner = THIS_MODULE,},
 };
 
-static int __init cis8204_init(void)
+static int __init cicada_init(void)
 {
-       return phy_driver_register(&cis8204_driver);
+       int ret;
+
+       ret = phy_driver_register(&cis8204_driver);
+       if (ret)
+               goto err1;
+
+       ret = phy_driver_register(&cis8201_driver);
+       if (ret)
+               goto err2;
+       return 0;
+
+err2:
+       phy_driver_unregister(&cis8204_driver);
+err1:
+       return ret;
 }
 
-static void __exit cis8204_exit(void)
+static void __exit cicada_exit(void)
 {
        phy_driver_unregister(&cis8204_driver);
+       phy_driver_unregister(&cis8201_driver);
 }
 
-module_init(cis8204_init);
-module_exit(cis8204_exit);
+module_init(cicada_init);
+module_exit(cicada_exit);
index 16a0ef1..4c2f575 100644 (file)
@@ -1406,7 +1406,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        dev = alloc_etherdev(sizeof (*tp));
        if (dev == NULL) {
                if (netif_msg_drv(&debug))
-                       printk(KERN_ERR PFX "unable to alloc new ethernet\n");
+                       dev_err(&pdev->dev, "unable to alloc new ethernet\n");
                goto err_out;
        }
 
@@ -1418,10 +1418,8 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        /* enable device (incl. PCI PM wakeup and hotplug setup) */
        rc = pci_enable_device(pdev);
        if (rc < 0) {
-               if (netif_msg_probe(tp)) {
-                       printk(KERN_ERR PFX "%s: enable failure\n",
-                              pci_name(pdev));
-               }
+               if (netif_msg_probe(tp))
+                       dev_err(&pdev->dev, "enable failure\n");
                goto err_out_free_dev;
        }
 
@@ -1437,37 +1435,32 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
                pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
                acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
        } else {
-               if (netif_msg_probe(tp)) {
-                       printk(KERN_ERR PFX
+               if (netif_msg_probe(tp))
+                       dev_err(&pdev->dev,
                               "PowerManagement capability not found.\n");
-               }
        }
 
        /* make sure PCI base addr 1 is MMIO */
        if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
-               if (netif_msg_probe(tp)) {
-                       printk(KERN_ERR PFX
+               if (netif_msg_probe(tp))
+                       dev_err(&pdev->dev,
                               "region #1 not an MMIO resource, aborting\n");
-               }
                rc = -ENODEV;
                goto err_out_mwi;
        }
        /* check for weird/broken PCI region reporting */
        if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
-               if (netif_msg_probe(tp)) {
-                       printk(KERN_ERR PFX
+               if (netif_msg_probe(tp))
+                       dev_err(&pdev->dev,
                               "Invalid PCI region size(s), aborting\n");
-               }
                rc = -ENODEV;
                goto err_out_mwi;
        }
 
        rc = pci_request_regions(pdev, MODULENAME);
        if (rc < 0) {
-               if (netif_msg_probe(tp)) {
-                       printk(KERN_ERR PFX "%s: could not request regions.\n",
-                              pci_name(pdev));
-               }
+               if (netif_msg_probe(tp))
+                       dev_err(&pdev->dev, "could not request regions.\n");
                goto err_out_mwi;
        }
 
@@ -1480,10 +1473,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        } else {
                rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc < 0) {
-                       if (netif_msg_probe(tp)) {
-                               printk(KERN_ERR PFX
+                       if (netif_msg_probe(tp))
+                               dev_err(&pdev->dev,
                                       "DMA configuration failed.\n");
-                       }
                        goto err_out_free_res;
                }
        }
@@ -1494,7 +1486,7 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
        if (ioaddr == NULL) {
                if (netif_msg_probe(tp))
-                       printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+                       dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
                rc = -EIO;
                goto err_out_free_res;
        }
@@ -1526,9 +1518,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
        if (i < 0) {
                /* Unknown chip: assume array element #0, original RTL-8169 */
                if (netif_msg_probe(tp)) {
-                       printk(KERN_DEBUG PFX "PCI device %s: "
+                       dev_printk(KERN_DEBUG, &pdev->dev,
                               "unknown chip version, assuming %s\n",
-                              pci_name(pdev), rtl_chip_info[0].name);
+                              rtl_chip_info[0].name);
                }
                i++;
        }
index ed1f599..c0a62b0 100644 (file)
 
        Support and updates available at
        http://www.scyld.com/network/starfire.html
+       [link no longer provides useful info -jgarzik]
 
-       -----------------------------------------------------------
-
-       Linux kernel-specific changes:
-
-       LK1.1.1 (jgarzik):
-       - Use PCI driver interface
-       - Fix MOD_xxx races
-       - softnet fixups
-
-       LK1.1.2 (jgarzik):
-       - Merge Becker version 0.15
-
-       LK1.1.3 (Andrew Morton)
-       - Timer cleanups
-
-       LK1.1.4 (jgarzik):
-       - Merge Becker version 1.03
-
-       LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
-       - Support hardware Rx/Tx checksumming
-       - Use the GFP firmware taken from Adaptec's Netware driver
-
-       LK1.2.2 (Ion Badulescu)
-       - Backported to 2.2.x
-
-       LK1.2.3 (Ion Badulescu)
-       - Fix the flaky mdio interface
-       - More compat clean-ups
-
-       LK1.2.4 (Ion Badulescu)
-       - More 2.2.x initialization fixes
-
-       LK1.2.5 (Ion Badulescu)
-       - Several fixes from Manfred Spraul
-
-       LK1.2.6 (Ion Badulescu)
-       - Fixed ifup/ifdown/ifup problem in 2.4.x
-
-       LK1.2.7 (Ion Badulescu)
-       - Removed unused code
-       - Made more functions static and __init
-
-       LK1.2.8 (Ion Badulescu)
-       - Quell bogus error messages, inform about the Tx threshold
-       - Removed #ifdef CONFIG_PCI, this driver is PCI only
-
-       LK1.2.9 (Ion Badulescu)
-       - Merged Jeff Garzik's changes from 2.4.4-pre5
-       - Added 2.2.x compatibility stuff required by the above changes
-
-       LK1.2.9a (Ion Badulescu)
-       - More updates from Jeff Garzik
-
-       LK1.3.0 (Ion Badulescu)
-       - Merged zerocopy support
-
-       LK1.3.1 (Ion Badulescu)
-       - Added ethtool support
-       - Added GPIO (media change) interrupt support
-
-       LK1.3.2 (Ion Badulescu)
-       - Fixed 2.2.x compatibility issues introduced in 1.3.1
-       - Fixed ethtool ioctl returning uninitialized memory
-
-       LK1.3.3 (Ion Badulescu)
-       - Initialize the TxMode register properly
-       - Don't dereference dev->priv after freeing it
-
-       LK1.3.4 (Ion Badulescu)
-       - Fixed initialization timing problems
-       - Fixed interrupt mask definitions
-
-       LK1.3.5 (jgarzik)
-       - ethtool NWAY_RST, GLINK, [GS]MSGLVL support
-
-       LK1.3.6:
-       - Sparc64 support and fixes (Ion Badulescu)
-       - Better stats and error handling (Ion Badulescu)
-       - Use new pci_set_mwi() PCI API function (jgarzik)
-
-       LK1.3.7 (Ion Badulescu)
-       - minimal implementation of tx_timeout()
-       - correctly shutdown the Rx/Tx engines in netdev_close()
-       - added calls to netif_carrier_on/off
-       (patch from Stefan Rompf <srompf@isg.de>)
-       - VLAN support
-
-       LK1.3.8 (Ion Badulescu)
-       - adjust DMA burst size on sparc64
-       - 64-bit support
-       - reworked zerocopy support for 64-bit buffers
-       - working and usable interrupt mitigation/latency
-       - reduced Tx interrupt frequency for lower interrupt overhead
-
-       LK1.3.9 (Ion Badulescu)
-       - bugfix for mcast filter
-       - enable the right kind of Tx interrupts (TxDMADone, not TxDone)
-
-       LK1.4.0 (Ion Badulescu)
-       - NAPI support
-
-       LK1.4.1 (Ion Badulescu)
-       - flush PCI posting buffers after disabling Rx interrupts
-       - put the chip to a D3 slumber on driver unload
-       - added config option to enable/disable NAPI
-
-       LK1.4.2 (Ion Badulescu)
-       - finally added firmware (GPL'ed by Adaptec)
-       - removed compatibility code for 2.2.x
-
-       LK1.4.2.1 (Ion Badulescu)
-       - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
-       - added 32-bit padding to outgoing skb's, removed previous workaround
-
-TODO:  - fix forced speed/duplexing code (broken a long time ago, when
-       somebody converted the driver to use the generic MII code)
-       - fix VLAN support
 */
 
 #define DRV_NAME       "starfire"
-#define DRV_VERSION    "1.03+LK1.4.2.1"
-#define DRV_RELDATE    "October 3, 2005"
+#define DRV_VERSION    "2.0"
+#define DRV_RELDATE    "June 27, 2006"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -846,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
                goto err_out_free_netdev;
        }
 
-       /* ioremap is borken in Linux-2.2.x/sparc64 */
        base = ioremap(ioaddr, io_size);
        if (!base) {
                printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
index 643fcea..ac17377 100644 (file)
 
        Support and updates available at
        http://www.scyld.com/network/sundance.html
+       [link no longer provides useful info -jgarzik]
 
-
-       Version LK1.01a (jgarzik):
-       - Replace some MII-related magic numbers with constants
-
-       Version LK1.02 (D-Link):
-       - Add new board to PCI ID list
-       - Fix multicast bug
-
-       Version LK1.03 (D-Link):
-       - New Rx scheme, reduce Rx congestion
-       - Option to disable flow control
-
-       Version LK1.04 (D-Link):
-       - Tx timeout recovery
-       - More support for ethtool.
-
-       Version LK1.04a:
-       - Remove unused/constant members from struct pci_id_info
-       (which then allows removal of 'drv_flags' from private struct)
-       (jgarzik)
-       - If no phy is found, fail to load that board (jgarzik)
-       - Always start phy id scan at id 1 to avoid problems (Donald Becker)
-       - Autodetect where mii_preable_required is needed,
-       default to not needed.  (Donald Becker)
-
-       Version LK1.04b:
-       - Remove mii_preamble_required module parameter (Donald Becker)
-       - Add per-interface mii_preamble_required (setting is autodetected)
-         (Donald Becker)
-       - Remove unnecessary cast from void pointer (jgarzik)
-       - Re-align comments in private struct (jgarzik)
-
-       Version LK1.04c (jgarzik):
-       - Support bitmapped message levels (NETIF_MSG_xxx), and the
-         two ethtool ioctls that get/set them
-       - Don't hand-code MII ethtool support, use standard API/lib
-
-       Version LK1.04d:
-       - Merge from Donald Becker's sundance.c: (Jason Lunz)
-               * proper support for variably-sized MTUs
-               * default to PIO, to fix chip bugs
-       - Add missing unregister_netdev (Jason Lunz)
-       - Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
-       - Better rx buf size calculation (Donald Becker)
-
-       Version LK1.05 (D-Link):
-       - Fix DFE-580TX packet drop issue (for DL10050C)
-       - Fix reset_tx logic
-
-       Version LK1.06 (D-Link):
-       - Fix crash while unloading driver
-
-       Versin LK1.06b (D-Link):
-       - New tx scheme, adaptive tx_coalesce
-       
-       Version LK1.07 (D-Link):
-       - Fix tx bugs in big-endian machines
-       - Remove unused max_interrupt_work module parameter, the new 
-         NAPI-like rx scheme doesn't need it.
-       - Remove redundancy get_stats() in intr_handler(), those 
-         I/O access could affect performance in ARM-based system
-       - Add Linux software VLAN support
-       
-       Version LK1.08 (Philippe De Muyter phdm@macqel.be):
-       - Fix bug of custom mac address 
-       (StationAddr register only accept word write) 
-
-       Version LK1.09 (D-Link):
-       - Fix the flowctrl bug. 
-       - Set Pause bit in MII ANAR if flow control enabled.    
-
-       Version LK1.09a (ICPlus):
-       - Add the delay time in reading the contents of EEPROM
-
-       Version LK1.10 (Philippe De Muyter phdm@macqel.be):
-       - Make 'unblock interface after Tx underrun' work
-
-       Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
-       - Add support for IC Plus Corporation IP100A chipset
 */
 
 #define DRV_NAME       "sundance"
-#define DRV_VERSION    "1.01+LK1.11"
-#define DRV_RELDATE    "14-Jun-2006"
+#define DRV_VERSION    "1.1"
+#define DRV_RELDATE    "27-Jun-2006"
 
 
 /* The user-configurable values.
@@ -282,15 +204,15 @@ IVc. Errata
 #define USE_IO_OPS 1
 #endif
 
-static struct pci_device_id sundance_pci_tbl[] = {
-       {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
-       {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
-       {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
-       {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
-       {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
-       {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
-       {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
-       {0,}
+static const struct pci_device_id sundance_pci_tbl[] = {
+       { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
+       { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
+       { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
+       { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
+       { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+       { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+       { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+       { }
 };
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
 
@@ -301,7 +223,7 @@ enum {
 struct pci_id_info {
         const char *name;
 };
-static const struct pci_id_info pci_id_tbl[] = {
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
        {"D-Link DFE-550TX FAST Ethernet Adapter"},
        {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
        {"D-Link DFE-580TX 4 port Server Adapter"},
@@ -309,7 +231,7 @@ static const struct pci_id_info pci_id_tbl[] = {
        {"D-Link DL10050-based FAST Ethernet Adapter"},
        {"Sundance Technology Alta"},
        {"IC Plus Corporation IP100A FAST Ethernet Adapter"},
-       {NULL,},                        /* 0 terminated list. */
+       { }     /* terminate list. */
 };
 
 /* This driver was written to use PCI memory space, however x86-oriented
index b4c0d10..7f41481 100644 (file)
@@ -224,24 +224,21 @@ static const struct pci_device_id w840_pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
 
+enum {
+       netdev_res_size         = 128,  /* size of PCI BAR resource */
+};
+
 struct pci_id_info {
         const char *name;
-        struct match_info {
-                int     pci, pci_mask, subsystem, subsystem_mask;
-                int revision, revision_mask;                            /* Only 8 bits. */
-        } id;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
-        int drv_flags;                          /* Driver use, intended as capability flags. */
+        int drv_flags;         /* Driver use, intended as capability flags. */
 };
-static struct pci_id_info pci_id_tbl[] = {
-       {"Winbond W89c840",                     /* Sometime a Level-One switch card. */
-        { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
-          128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
-       {"Winbond W89c840", { 0x08401050, 0xffffffff, },
-          128, CanHaveMII | HasBrokenTx},
-       {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
-          128, CanHaveMII | HasBrokenTx},
-       {NULL,},                                        /* 0 terminated list. */
+
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
+       {                               /* Sometime a Level-One switch card. */
+         "Winbond W89c840",    CanHaveMII | HasBrokenTx | FDXOnNoMII},
+       { "Winbond W89c840",    CanHaveMII | HasBrokenTx},
+       { "Compex RL100-ATX",   CanHaveMII | HasBrokenTx},
+       { }     /* terminate list. */
 };
 
 /* This driver was written to use PCI memory space, however some x86 systems
@@ -399,7 +396,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
 #ifdef USE_IO_OPS
        bar = 0;
 #endif
-       ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
+       ioaddr = pci_iomap(pdev, bar, netdev_res_size);
        if (!ioaddr)
                goto err_out_free_res;
 
index 091ebb7..17ca7dc 100644 (file)
        410 Severn Ave., Suite 210
        Annapolis MD 21403
 
-       -----------------------------------------------------------
-
-       Linux kernel-specific changes:
-
-       LK1.0 (Ion Badulescu)
-       - Major cleanup
-       - Use 2.4 PCI API
-       - Support ethtool
-       - Rewrite perfect filter/hash code
-       - Use interrupts for media changes
-
-       LK1.1 (Ion Badulescu)
-       - Disallow negotiation of unsupported full-duplex modes
 */
 
 #define DRV_NAME       "xircom_tulip_cb"
-#define DRV_VERSION    "0.91+LK1.1"
-#define DRV_RELDATE    "October 11, 2001"
-
-#define CARDBUS 1
+#define DRV_VERSION    "0.92"
+#define DRV_RELDATE    "June 27, 2006"
 
 /* A few user-configurable values. */
 
@@ -306,10 +291,10 @@ struct xircom_private {
        struct xircom_tx_desc tx_ring[TX_RING_SIZE];
        /* The saved address of a sent-in-place packet/buffer, for skfree(). */
        struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
+
        /* The X3201-3 requires 4-byte aligned tx bufs */
        struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
+
        /* The addresses of receive-in-place skbuffs. */
        struct sk_buff* rx_skbuff[RX_RING_SIZE];
        u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)];    /* Pseudo-Tx frame to init address table. */
@@ -908,10 +893,8 @@ static void xircom_init_ring(struct net_device *dev)
                tp->tx_skbuff[i] = NULL;
                tp->tx_ring[i].status = 0;
                tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
                if (tp->chip_id == X3201_3)
                        tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
-#endif /* CARDBUS */
        }
        tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
 }
@@ -931,12 +914,10 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
        entry = tp->cur_tx % TX_RING_SIZE;
 
        tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
        if (tp->chip_id == X3201_3) {
                memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
                tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
        } else
-#endif
                tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
 
        if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
index 98b6f32..d3d0ec9 100644 (file)
        version. He may or may not be interested in bug reports on this
        code. You can find his versions at:
        http://www.scyld.com/network/via-rhine.html
-
-
-       Linux kernel version history:
-
-       LK1.1.0:
-       - Jeff Garzik: softnet 'n stuff
-
-       LK1.1.1:
-       - Justin Guyett: softnet and locking fixes
-       - Jeff Garzik: use PCI interface
-
-       LK1.1.2:
-       - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
-
-       LK1.1.3:
-       - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
-                        code) update "Theory of Operation" with
-                        softnet/locking changes
-       - Dave Miller: PCI DMA and endian fixups
-       - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
-
-       LK1.1.4:
-       - Urban Widmark: fix gcc 2.95.2 problem and
-                        remove writel's to fixed address 0x7c
-
-       LK1.1.5:
-       - Urban Widmark: mdio locking, bounce buffer changes
-                        merges from Beckers 1.05 version
-                        added netif_running_on/off support
-
-       LK1.1.6:
-       - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
-                        set netif_running_on/off on startup, del_timer_sync
-
-       LK1.1.7:
-       - Manfred Spraul: added reset into tx_timeout
-
-       LK1.1.9:
-       - Urban Widmark: merges from Beckers 1.10 version
-                        (media selection + eeprom reload)
-       - David Vrabel:  merges from D-Link "1.11" version
-                        (disable WOL and PME on startup)
-
-       LK1.1.10:
-       - Manfred Spraul: use "singlecopy" for unaligned buffers
-                         don't allocate bounce buffers for !ReqTxAlign cards
-
-       LK1.1.11:
-       - David Woodhouse: Set dev->base_addr before the first time we call
-                          wait_for_reset(). It's a lot happier that way.
-                          Free np->tx_bufs only if we actually allocated it.
-
-       LK1.1.12:
-       - Martin Eriksson: Allow Memory-Mapped IO to be enabled.
-
-       LK1.1.13 (jgarzik):
-       - Add ethtool support
-       - Replace some MII-related magic numbers with constants
-
-       LK1.1.14 (Ivan G.):
-       - fixes comments for Rhine-III
-       - removes W_MAX_TIMEOUT (unused)
-       - adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
-         is R-I and has Davicom chip, flag is referenced in kernel driver)
-       - sends chip_id as a parameter to wait_for_reset since np is not
-         initialized on first call
-       - changes mmio "else if (chip_id==VT6102)" to "else" so it will work
-         for Rhine-III's (documentation says same bit is correct)
-       - transmit frame queue message is off by one - fixed
-       - adds IntrNormalSummary to "Something Wicked" exclusion list
-         so normal interrupts will not trigger the message (src: Donald Becker)
-       (Roger Luethi)
-       - show confused chip where to continue after Tx error
-       - location of collision counter is chip specific
-       - allow selecting backoff algorithm (module parameter)
-
-       LK1.1.15 (jgarzik):
-       - Use new MII lib helper generic_mii_ioctl
-
-       LK1.1.16 (Roger Luethi)
-       - Etherleak fix
-       - Handle Tx buffer underrun
-       - Fix bugs in full duplex handling
-       - New reset code uses "force reset" cmd on Rhine-II
-       - Various clean ups
-
-       LK1.1.17 (Roger Luethi)
-       - Fix race in via_rhine_start_tx()
-       - On errors, wait for Tx engine to turn off before scavenging
-       - Handle Tx descriptor write-back race on Rhine-II
-       - Force flushing for PCI posted writes
-       - More reset code changes
-
-       LK1.1.18 (Roger Luethi)
-       - No filtering multicast in promisc mode (Edward Peng)
-       - Fix for Rhine-I Tx timeouts
-
-       LK1.1.19 (Roger Luethi)
-       - Increase Tx threshold for unspecified errors
-
-       LK1.2.0-2.6 (Roger Luethi)
-       - Massive clean-up
-       - Rewrite PHY, media handling (remove options, full_duplex, backoff)
-       - Fix Tx engine race for good
-       - Craig Brind: Zero padded aligned buffers for short packets.
+       [link no longer provides useful info -jgarzik]
 
 */
 
 #define DRV_NAME       "via-rhine"
-#define DRV_VERSION    "1.2.0-2.6"
-#define DRV_RELDATE    "June-10-2004"
+#define DRV_VERSION    "1.4.0"
+#define DRV_RELDATE    "June-27-2006"
 
 
 /* A few user-configurable values.
@@ -356,12 +252,11 @@ enum rhine_quirks {
 /* Beware of PCI posted writes */
 #define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
 
-static struct pci_device_id rhine_pci_tbl[] =
-{
-       {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
-       {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
-       {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
-       {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
+static const struct pci_device_id rhine_pci_tbl[] = {
+       { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, },    /* VT86C100A */
+       { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, },    /* VT6102 */
+       { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, },    /* 6105{,L,LOM} */
+       { 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, },    /* VT6105M */
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
index ba2972b..f5b0078 100644 (file)
@@ -229,7 +229,8 @@ static int rx_copybreak = 200;
 module_param(rx_copybreak, int, 0644);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
+                              const struct velocity_info_tbl *info);
 static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
 static void velocity_print_info(struct velocity_info *vptr);
 static int velocity_open(struct net_device *dev);
@@ -294,9 +295,9 @@ static void velocity_unregister_notifier(void)
  *     Internal board variants. At the moment we have only one
  */
 
-static struct velocity_info_tbl chip_info_table[] = {
-       {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
-       {0, NULL}
+static const struct velocity_info_tbl chip_info_table[] __devinitdata = {
+       {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
+       { }
 };
 
 /*
@@ -304,10 +305,9 @@ static struct velocity_info_tbl chip_info_table[] = {
  *     device driver. Used for hotplug autoloading.
  */
 
-static struct pci_device_id velocity_id_table[] __devinitdata = {
-       {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
-        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
-       {0, }
+static const struct pci_device_id velocity_id_table[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
+       { }
 };
 
 MODULE_DEVICE_TABLE(pci, velocity_id_table);
@@ -341,7 +341,7 @@ static char __devinit *get_chip_name(enum chip_type chip_id)
 static void __devexit velocity_remove1(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
 
 #ifdef CONFIG_PM
        unsigned long flags;
@@ -686,21 +686,23 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
        static int first = 1;
        struct net_device *dev;
        int i;
-       struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+       const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
        struct velocity_info *vptr;
        struct mac_regs __iomem * regs;
        int ret = -ENOMEM;
 
+       /* FIXME: this driver, like almost all other ethernet drivers,
+        * can support more than MAX_UNITS.
+        */
        if (velocity_nics >= MAX_UNITS) {
-               printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n", 
-                               velocity_nics);
+               dev_notice(&pdev->dev, "already found %d NICs.\n", 
+                          velocity_nics);
                return -ENODEV;
        }
 
        dev = alloc_etherdev(sizeof(struct velocity_info));
-
-       if (dev == NULL) {
-               printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+       if (!dev) {
+               dev_err(&pdev->dev, "allocate net device failed.\n");
                goto out;
        }
        
@@ -708,7 +710,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
        
        SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
-       vptr = dev->priv;
+       vptr = netdev_priv(dev);
 
 
        if (first) {
@@ -731,17 +733,17 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
 
        ret = velocity_get_pci_info(vptr, pdev);
        if (ret < 0) {
-               printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+               /* error message already printed */
                goto err_disable;
        }
 
        ret = pci_request_regions(pdev, VELOCITY_NAME);
        if (ret < 0) {
-               printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+               dev_err(&pdev->dev, "No PCI resources.\n");
                goto err_disable;
        }
 
-       regs = ioremap(vptr->memaddr, vptr->io_size);
+       regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
        if (regs == NULL) {
                ret = -EIO;
                goto err_release_res;
@@ -859,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
  *     discovered.
  */
 
-static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+                                        struct velocity_info *vptr,
+                                        const struct velocity_info_tbl *info)
 {
        memset(vptr, 0, sizeof(struct velocity_info));
 
        vptr->pdev = pdev;
        vptr->chip_id = info->chip_id;
-       vptr->io_size = info->io_size;
        vptr->num_txq = info->txqueue;
        vptr->multicast_limit = MCAM_SIZE;
        spin_lock_init(&vptr->lock);
@@ -883,8 +886,7 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
 
 static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
 {
-
-       if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+       if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
                return -EIO;
                
        pci_set_master(pdev);
@@ -892,24 +894,20 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
        vptr->ioaddr = pci_resource_start(pdev, 0);
        vptr->memaddr = pci_resource_start(pdev, 1);
        
-       if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
-       {
-               printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
-                               pci_name(pdev));
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+               dev_err(&pdev->dev,
+                          "region #0 is not an I/O resource, aborting.\n");
                return -EINVAL;
        }
 
-       if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
-       {
-               printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
-                               pci_name(pdev));
+       if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+               dev_err(&pdev->dev,
+                          "region #1 is an I/O resource, aborting.\n");
                return -EINVAL;
        }
 
-       if(pci_resource_len(pdev, 1) < 256)
-       {
-               printk(KERN_ERR "%s: region #1 is too small.\n", 
-                               pci_name(pdev));
+       if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+               dev_err(&pdev->dev, "region #1 is too small.\n");
                return -EINVAL;
        }
        vptr->pdev = pdev;
@@ -1728,7 +1726,7 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
  
 static int velocity_open(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        int ret;
 
        vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1785,7 +1783,7 @@ err_free_desc_rings:
  
 static int velocity_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        unsigned long flags;
        int oldmtu = dev->mtu;
        int ret = 0;
@@ -1861,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
 
 static int velocity_close(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
 
        netif_stop_queue(dev);
        velocity_shutdown(vptr);
@@ -1894,7 +1892,7 @@ static int velocity_close(struct net_device *dev)
  
 static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        int qnum = 0;
        struct tx_desc *td_ptr;
        struct velocity_td_info *tdinfo;
@@ -2049,7 +2047,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
 static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
 {
        struct net_device *dev = dev_instance;
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        u32 isr_status;
        int max_count = 0;
 
@@ -2104,7 +2102,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
  
 static void velocity_set_multi(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        struct mac_regs __iomem * regs = vptr->mac_regs;
        u8 rx_mode;
        int i;
@@ -2153,7 +2151,7 @@ static void velocity_set_multi(struct net_device *dev)
  
 static struct net_device_stats *velocity_get_stats(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        
        /* If the hardware is down, don't touch MII */
        if(!netif_running(dev))
@@ -2196,7 +2194,7 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
  
 static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        int ret;
 
        /* If we are asked for information and the device is power
@@ -2825,7 +2823,7 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
  
 static int velocity_ethtool_up(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        if (!netif_running(dev))
                pci_set_power_state(vptr->pdev, PCI_D0);
        return 0;
@@ -2841,14 +2839,14 @@ static int velocity_ethtool_up(struct net_device *dev)
  
 static void velocity_ethtool_down(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        if (!netif_running(dev))
                pci_set_power_state(vptr->pdev, PCI_D3hot);
 }
 
 static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        struct mac_regs __iomem * regs = vptr->mac_regs;
        u32 status;
        status = check_connection_type(vptr->mac_regs);
@@ -2873,7 +2871,7 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
 
 static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        u32 curr_status;
        u32 new_status = 0;
        int ret = 0;
@@ -2896,14 +2894,14 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
 
 static u32 velocity_get_link(struct net_device *dev)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        struct mac_regs __iomem * regs = vptr->mac_regs;
        return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0)  ? 0 : 1;
 }
 
 static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        strcpy(info->driver, VELOCITY_NAME);
        strcpy(info->version, VELOCITY_VERSION);
        strcpy(info->bus_info, pci_name(vptr->pdev));
@@ -2911,7 +2909,7 @@ static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
 
 static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
        wol->wolopts |= WAKE_MAGIC;
        /*
@@ -2927,7 +2925,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli
 
 static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
 
        if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
                return -EFAULT;
@@ -2992,7 +2990,7 @@ static struct ethtool_ops velocity_ethtool_ops = {
  
 static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       struct velocity_info *vptr = dev->priv;
+       struct velocity_info *vptr = netdev_priv(dev);
        struct mac_regs __iomem * regs = vptr->mac_regs;
        unsigned long flags;
        struct mii_ioctl_data *miidata = if_mii(ifr);
index f1b2640..496c3d5 100644 (file)
@@ -31,6 +31,8 @@
 #define VELOCITY_FULL_DRV_NAM  "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
 #define VELOCITY_VERSION       "1.13"
 
+#define VELOCITY_IO_SIZE       256
+
 #define PKT_BUF_SZ          1540
 
 #define MAX_UNITS           8
@@ -1191,7 +1193,6 @@ enum chip_type {
 struct velocity_info_tbl {
        enum chip_type chip_id;
        char *name;
-       int io_size;
        int txqueue;
        u32 flags;
 };
@@ -1751,7 +1752,6 @@ struct velocity_info {
        struct mac_regs __iomem * mac_regs;
        unsigned long memaddr;
        unsigned long ioaddr;
-       u32 io_size;
 
        u8 rev_id;
 
index b5328b0..54b8e49 100644 (file)
@@ -134,18 +134,6 @@ config SEALEVEL_4021
          The driver will be compiled as a module: the
          module will be called sealevel.
 
-config SYNCLINK_SYNCPPP
-       tristate "SyncLink HDLC/SYNCPPP support"
-       depends on WAN
-       help
-         Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
-
-         Normally the SyncLink WAN driver works with the main PPP driver
-         <file:drivers/net/ppp_generic.c> and pppd program.
-         HDLC/SYNCPPP support allows use of the Cisco HDLC/PPP driver
-         <file:drivers/net/wan/syncppp.c>. The SyncLink WAN driver (in
-         character devices) must also be enabled.
-
 # Generic HDLC
 config HDLC
        tristate "Generic HDLC layer"
index 823c6d5..316ca68 100644 (file)
@@ -28,7 +28,6 @@ obj-$(CONFIG_COSA)            +=              syncppp.o       cosa.o
 obj-$(CONFIG_FARSYNC)          +=              syncppp.o       farsync.o
 obj-$(CONFIG_DSCC4)             +=                             dscc4.o
 obj-$(CONFIG_LANMEDIA)         +=              syncppp.o
-obj-$(CONFIG_SYNCLINK_SYNCPPP) +=              syncppp.o
 obj-$(CONFIG_X25_ASY)          += x25_asy.o
 
 obj-$(CONFIG_LANMEDIA)         += lmc/
index 30ec235..fa9d2c4 100644 (file)
@@ -550,6 +550,7 @@ config USB_ZD1201
 
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
 
 # yes, this works even when no drivers are selected
 config NET_WIRELESS
index 512603d..c613af1 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54)         += prism54/
 
 obj-$(CONFIG_HOSTAP)           += hostap/
 obj-$(CONFIG_BCM43XX)          += bcm43xx/
+obj-$(CONFIG_ZD1211RW)         += zd1211rw/
 
 # 16-bit wireless PCMCIA client drivers
 obj-$(CONFIG_PCMCIA_RAYCS)     += ray_cs.o
index d8f5600..e1c5a93 100644 (file)
@@ -1885,6 +1885,15 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
 
        spin_lock(&bcm->irq_lock);
 
+       /* Only accept IRQs, if we are initialized properly.
+        * This avoids an RX race while initializing.
+        * We should probably not enable IRQs before we are initialized
+        * completely, but some careful work is needed to fix this. I think it
+        * is best to stay with this cheap workaround for now... .
+        */
+       if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED))
+               goto out;
+
        reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
        if (reason == 0xffffffff) {
                /* irq not for us (shared irq) */
@@ -1906,19 +1915,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
 
        bcm43xx_interrupt_ack(bcm, reason);
 
-       /* Only accept IRQs, if we are initialized properly.
-        * This avoids an RX race while initializing.
-        * We should probably not enable IRQs before we are initialized
-        * completely, but some careful work is needed to fix this. I think it
-        * is best to stay with this cheap workaround for now... .
-        */
-       if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
-               /* disable all IRQs. They are enabled again in the bottom half. */
-               bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
-               /* save the reason code and call our bottom half. */
-               bcm->irq_reason = reason;
-               tasklet_schedule(&bcm->isr_tasklet);
-       }
+       /* disable all IRQs. They are enabled again in the bottom half. */
+       bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+       /* save the reason code and call our bottom half. */
+       bcm->irq_reason = reason;
+       tasklet_schedule(&bcm->isr_tasklet);
 
 out:
        mmiowb();
@@ -3698,6 +3699,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
                secinfo->encrypt = sec->encrypt;
                dprintk(", .encrypt = %d", sec->encrypt);
        }
+       if (sec->flags & SEC_AUTH_MODE) {
+               secinfo->auth_mode = sec->auth_mode;
+               dprintk(", .auth_mode = %d\n", sec->auth_mode);
+       }
        dprintk("\n");
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
            !bcm->ieee->host_encrypt) {
index 30a202b..1164936 100644 (file)
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
        return bcm43xx_channel_to_freq_bg(channel);
 }
 
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
-       return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
-              && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
-       return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
-              && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
-                            u8 channel)
-{
-       if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
-               return bcm43xx_is_valid_channel_a(channel);
-       return bcm43xx_is_valid_channel_bg(channel);
-}
-
 void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
 
index af5c0bf..bb9c484 100644 (file)
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
        u16 r8, tmp;
        u16 freq;
 
+       if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+               return -EINVAL;
        if ((radio->manufact == 0x17F) &&
            (radio->version == 0x2060) &&
            (radio->revision == 1)) {
-               if (channel > 200)
-                       return -EINVAL;
                freq = channel2freq_a(channel);
 
                r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
                TODO(); //TODO: TSSI2dbm workaround
                bcm43xx_phy_xmitpower(bcm);//FIXME correct?
        } else {
-               if ((channel < 1) || (channel > 14))
-                       return -EINVAL;
-
                if (synthetic_pu_workaround)
                        bcm43xx_synth_pu_workaround(bcm, channel);
 
index c35cb3a..5c36e29 100644 (file)
@@ -119,7 +119,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
                channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
                freq = data->freq.m;
        }
-       if (!bcm43xx_is_valid_channel(bcm, channel))
+       if (!ieee80211_is_valid_channel(bcm->ieee, channel))
                goto out_unlock;
        if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
                //ieee80211softmac_disassoc(softmac, $REASON);
index d8ece28..6dbd855 100644 (file)
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
        u16 control = 0;
        u16 wsec_rate = 0;
        u16 encrypt_frame;
+       const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+       const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
 
        /* Now construct the TX header. */
        memset(txhdr, 0, sizeof(*txhdr));
 
-       bitrate = bcm->softmac->txrates.default_rate;
+       bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+               is_multicast_ether_addr(wireless_header->addr1), is_mgt);
        ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
        fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
        fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
index 49860fa..6dfa041 100644 (file)
@@ -66,10 +66,12 @@ static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
        PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
        PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
        PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+       PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
        PLXDEV(0x1385, 0x4100, "Netgear MA301"),
        PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
        PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
        PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+       PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
        PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
        PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
        PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
new file mode 100644 (file)
index 0000000..66ed55b
--- /dev/null
@@ -0,0 +1,19 @@
+config ZD1211RW
+       tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
+       depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+       select FW_LOADER
+       ---help---
+         This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
+         chip, present in many USB-wireless adapters.
+
+         Device firmware is required alongside this driver. You can download the
+         firmware distribution from http://zd1211.ath.cx/get-firmware
+
+config ZD1211RW_DEBUG
+       bool "ZyDAS ZD1211 debugging"
+       depends on ZD1211RW
+       ---help---
+         ZD1211 debugging messages. Choosing Y will result in additional debug
+         messages being saved to your kernel logs, which may help debug any
+         problems.
+
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
new file mode 100644 (file)
index 0000000..500314f
--- /dev/null
@@ -0,0 +1,11 @@
+obj-$(CONFIG_ZD1211RW) += zd1211rw.o
+
+zd1211rw-objs := zd_chip.o zd_ieee80211.o \
+               zd_mac.o zd_netdev.o \
+               zd_rf_al2230.o zd_rf_rf2959.o \
+               zd_rf.o zd_usb.o zd_util.o
+
+ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
new file mode 100644 (file)
index 0000000..efc9c4b
--- /dev/null
@@ -0,0 +1,1615 @@
+/* zd_chip.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* This file implements all the hardware specific functions for the ZD1211
+ * and ZD1211B chips. Support for the ZD1211B was possible after Timothy
+ * Legge sent me a ZD1211B device. Thank you Tim. -- Uli
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+void zd_chip_init(struct zd_chip *chip,
+                struct net_device *netdev,
+                struct usb_interface *intf)
+{
+       memset(chip, 0, sizeof(*chip));
+       mutex_init(&chip->mutex);
+       zd_usb_init(&chip->usb, netdev, intf);
+       zd_rf_init(&chip->rf);
+}
+
+void zd_chip_clear(struct zd_chip *chip)
+{
+       mutex_lock(&chip->mutex);
+       zd_usb_clear(&chip->usb);
+       zd_rf_clear(&chip->rf);
+       mutex_unlock(&chip->mutex);
+       mutex_destroy(&chip->mutex);
+       memset(chip, 0, sizeof(*chip));
+}
+
+static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+{
+       return scnprintf(buffer, size, "%02x-%02x-%02x",
+                        addr[0], addr[1], addr[2]);
+}
+
+/* Prints an identifier line, which will support debugging. */
+static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
+{
+       int i = 0;
+
+       i = scnprintf(buffer, size, "zd1211%s chip ",
+                     chip->is_zd1211b ? "b" : "");
+       i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
+       i += scnprintf(buffer+i, size-i, " ");
+       i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+       i += scnprintf(buffer+i, size-i, " ");
+       i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
+       i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c", chip->pa_type,
+               chip->patch_cck_gain ? 'g' : '-',
+               chip->patch_cr157 ? '7' : '-',
+               chip->patch_6m_band_edge ? '6' : '-');
+       return i;
+}
+
+static void print_id(struct zd_chip *chip)
+{
+       char buffer[80];
+
+       scnprint_id(chip, buffer, sizeof(buffer));
+       buffer[sizeof(buffer)-1] = 0;
+       dev_info(zd_chip_dev(chip), "%s\n", buffer);
+}
+
+/* Read a variable number of 32-bit values. Parameter count is not allowed to
+ * exceed USB_MAX_IOREAD32_COUNT.
+ */
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr,
+                unsigned int count)
+{
+       int r;
+       int i;
+       zd_addr_t *a16 = (zd_addr_t *)NULL;
+       u16 *v16;
+       unsigned int count16;
+
+       if (count > USB_MAX_IOREAD32_COUNT)
+               return -EINVAL;
+
+       /* Allocate a single memory block for values and addresses. */
+       count16 = 2*count;
+       a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+                                  GFP_NOFS);
+       if (!a16) {
+               dev_dbg_f(zd_chip_dev(chip),
+                         "error ENOMEM in allocation of a16\n");
+               r = -ENOMEM;
+               goto out;
+       }
+       v16 = (u16 *)(a16 + count16);
+
+       for (i = 0; i < count; i++) {
+               int j = 2*i;
+               /* We read the high word always first. */
+               a16[j] = zd_inc_word(addr[i]);
+               a16[j+1] = addr[i];
+       }
+
+       r = zd_ioread16v_locked(chip, v16, a16, count16);
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip),
+                         "error: zd_ioread16v_locked. Error number %d\n", r);
+               goto out;
+       }
+
+       for (i = 0; i < count; i++) {
+               int j = 2*i;
+               values[i] = (v16[j] << 16) | v16[j+1];
+       }
+
+out:
+       kfree((void *)a16);
+       return r;
+}
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+                  unsigned int count)
+{
+       int i, j, r;
+       struct zd_ioreq16 *ioreqs16;
+       unsigned int count16;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+
+       if (count == 0)
+               return 0;
+       if (count > USB_MAX_IOWRITE32_COUNT)
+               return -EINVAL;
+
+       /* Allocate a single memory block for values and addresses. */
+       count16 = 2*count;
+       ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+       if (!ioreqs16) {
+               r = -ENOMEM;
+               dev_dbg_f(zd_chip_dev(chip),
+                         "error %d in ioreqs16 allocation\n", r);
+               goto out;
+       }
+
+       for (i = 0; i < count; i++) {
+               j = 2*i;
+               /* We write the high word always first. */
+               ioreqs16[j].value   = ioreqs[i].value >> 16;
+               ioreqs16[j].addr    = zd_inc_word(ioreqs[i].addr);
+               ioreqs16[j+1].value = ioreqs[i].value;
+               ioreqs16[j+1].addr  = ioreqs[i].addr;
+       }
+
+       r = zd_usb_iowrite16v(&chip->usb, ioreqs16, count16);
+#ifdef DEBUG
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip),
+                         "error %d in zd_usb_write16v\n", r);
+       }
+#endif /* DEBUG */
+out:
+       kfree(ioreqs16);
+       return r;
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+                  const struct zd_ioreq16 *ioreqs, unsigned int count)
+{
+       int r;
+       unsigned int i, j, t, max;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       for (i = 0; i < count; i += j + t) {
+               t = 0;
+               max = count-i;
+               if (max > USB_MAX_IOWRITE16_COUNT)
+                       max = USB_MAX_IOWRITE16_COUNT;
+               for (j = 0; j < max; j++) {
+                       if (!ioreqs[i+j].addr) {
+                               t = 1;
+                               break;
+                       }
+               }
+
+               r = zd_usb_iowrite16v(&chip->usb, &ioreqs[i], j);
+               if (r) {
+                       dev_dbg_f(zd_chip_dev(chip),
+                                 "error zd_usb_iowrite16v. Error number %d\n",
+                                 r);
+                       return r;
+               }
+       }
+
+       return 0;
+}
+
+/* Writes a variable number of 32 bit registers. The functions will split
+ * that in several USB requests. A split can be forced by inserting an IO
+ * request with an zero address field.
+ */
+int zd_iowrite32a_locked(struct zd_chip *chip,
+                 const struct zd_ioreq32 *ioreqs, unsigned int count)
+{
+       int r;
+       unsigned int i, j, t, max;
+
+       for (i = 0; i < count; i += j + t) {
+               t = 0;
+               max = count-i;
+               if (max > USB_MAX_IOWRITE32_COUNT)
+                       max = USB_MAX_IOWRITE32_COUNT;
+               for (j = 0; j < max; j++) {
+                       if (!ioreqs[i+j].addr) {
+                               t = 1;
+                               break;
+                       }
+               }
+
+               r = _zd_iowrite32v_locked(chip, &ioreqs[i], j);
+               if (r) {
+                       dev_dbg_f(zd_chip_dev(chip),
+                               "error _zd_iowrite32v_locked."
+                               " Error number %d\n", r);
+                       return r;
+               }
+       }
+
+       return 0;
+}
+
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_ioread16_locked(chip, value, addr);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_ioread32_locked(chip, value, addr);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite16_locked(chip, value, addr);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite32_locked(chip, value, addr);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+                 u32 *values, unsigned int count)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_ioread32v_locked(chip, values, addresses, count);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+                 unsigned int count)
+{
+       int r;
+
+       ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite32a_locked(chip, ioreqs, count);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+static int read_pod(struct zd_chip *chip, u8 *rf_type)
+{
+       int r;
+       u32 value;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread32_locked(chip, &value, E2P_POD);
+       if (r)
+               goto error;
+       dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value);
+
+       /* FIXME: AL2230 handling (Bit 7 in POD) */
+       *rf_type = value & 0x0f;
+       chip->pa_type = (value >> 16) & 0x0f;
+       chip->patch_cck_gain = (value >> 8) & 0x1;
+       chip->patch_cr157 = (value >> 13) & 0x1;
+       chip->patch_6m_band_edge = (value >> 21) & 0x1;
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
+               "patch 6M %d\n",
+               zd_rf_name(*rf_type), *rf_type,
+               chip->pa_type, chip->patch_cck_gain,
+               chip->patch_cr157, chip->patch_6m_band_edge);
+       return 0;
+error:
+       *rf_type = 0;
+       chip->pa_type = 0;
+       chip->patch_cck_gain = 0;
+       chip->patch_cr157 = 0;
+       chip->patch_6m_band_edge = 0;
+       return r;
+}
+
+static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
+                         const zd_addr_t *addr)
+{
+       int r;
+       u32 parts[2];
+
+       r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip),
+                       "error: couldn't read e2p macs. Error number %d\n", r);
+               return r;
+       }
+
+       mac_addr[0] = parts[0];
+       mac_addr[1] = parts[0] >>  8;
+       mac_addr[2] = parts[0] >> 16;
+       mac_addr[3] = parts[0] >> 24;
+       mac_addr[4] = parts[1];
+       mac_addr[5] = parts[1] >>  8;
+
+       return 0;
+}
+
+static int read_e2p_mac_addr(struct zd_chip *chip)
+{
+       static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
+}
+
+/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
+ *              CR_MAC_ADDR_P2 must be overwritten
+ */
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+       mutex_lock(&chip->mutex);
+       memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
+       mutex_unlock(&chip->mutex);
+}
+
+static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+       static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
+       return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
+}
+
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+       int r;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+       mutex_lock(&chip->mutex);
+       r = read_mac_addr(chip, mac_addr);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
+{
+       int r;
+       struct zd_ioreq32 reqs[2] = {
+               [0] = { .addr = CR_MAC_ADDR_P1 },
+               [1] = { .addr = CR_MAC_ADDR_P2 },
+       };
+
+       reqs[0].value = (mac_addr[3] << 24)
+                     | (mac_addr[2] << 16)
+                     | (mac_addr[1] <<  8)
+                     |  mac_addr[0];
+       reqs[1].value = (mac_addr[5] <<  8)
+                     |  mac_addr[4];
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+#ifdef DEBUG
+       {
+               u8 tmp[ETH_ALEN];
+               read_mac_addr(chip, tmp);
+       }
+#endif /* DEBUG */
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain)
+{
+       int r;
+       u32 value;
+
+       mutex_lock(&chip->mutex);
+       r = zd_ioread32_locked(chip, &value, E2P_SUBID);
+       mutex_unlock(&chip->mutex);
+       if (r)
+               return r;
+
+       *regdomain = value >> 16;
+       dev_dbg_f(zd_chip_dev(chip), "regdomain: %#04x\n", *regdomain);
+
+       return 0;
+}
+
+static int read_values(struct zd_chip *chip, u8 *values, size_t count,
+                      zd_addr_t e2p_addr, u32 guard)
+{
+       int r;
+       int i;
+       u32 v;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       for (i = 0;;) {
+               r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+               if (r)
+                       return r;
+               v -= guard;
+               if (i+4 < count) {
+                       values[i++] = v;
+                       values[i++] = v >>  8;
+                       values[i++] = v >> 16;
+                       values[i++] = v >> 24;
+                       continue;
+               }
+               for (;i < count; i++)
+                       values[i] = v >> (8*(i%3));
+               return 0;
+       }
+}
+
+static int read_pwr_cal_values(struct zd_chip *chip)
+{
+       return read_values(chip, chip->pwr_cal_values,
+                       E2P_CHANNEL_COUNT, E2P_PWR_CAL_VALUE1,
+                       0);
+}
+
+static int read_pwr_int_values(struct zd_chip *chip)
+{
+       return read_values(chip, chip->pwr_int_values,
+                       E2P_CHANNEL_COUNT, E2P_PWR_INT_VALUE1,
+                       E2P_PWR_INT_GUARD);
+}
+
+static int read_ofdm_cal_values(struct zd_chip *chip)
+{
+       int r;
+       int i;
+       static const zd_addr_t addresses[] = {
+               E2P_36M_CAL_VALUE1,
+               E2P_48M_CAL_VALUE1,
+               E2P_54M_CAL_VALUE1,
+       };
+
+       for (i = 0; i < 3; i++) {
+               r = read_values(chip, chip->ofdm_cal_values[i],
+                               E2P_CHANNEL_COUNT, addresses[i], 0);
+               if (r)
+                       return r;
+       }
+       return 0;
+}
+
+static int read_cal_int_tables(struct zd_chip *chip)
+{
+       int r;
+
+       r = read_pwr_cal_values(chip);
+       if (r)
+               return r;
+       r = read_pwr_int_values(chip);
+       if (r)
+               return r;
+       r = read_ofdm_cal_values(chip);
+       if (r)
+               return r;
+       return 0;
+}
+
+/* phy means physical registers */
+int zd_chip_lock_phy_regs(struct zd_chip *chip)
+{
+       int r;
+       u32 tmp;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+       if (r) {
+               dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r);
+               return r;
+       }
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
+       tmp &= ~UNLOCK_PHY_REGS;
+
+       r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+       if (r)
+               dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+       return r;
+}
+
+int zd_chip_unlock_phy_regs(struct zd_chip *chip)
+{
+       int r;
+       u32 tmp;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+       if (r) {
+               dev_err(zd_chip_dev(chip),
+                       "error ioread32(CR_REG1): %d\n", r);
+               return r;
+       }
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
+       tmp |= UNLOCK_PHY_REGS;
+
+       r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+       if (r)
+               dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+       return r;
+}
+
+/* CR157 can be optionally patched by the EEPROM */
+static int patch_cr157(struct zd_chip *chip)
+{
+       int r;
+       u32 value;
+
+       if (!chip->patch_cr157)
+               return 0;
+
+       r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+       if (r)
+               return r;
+
+       dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
+       return zd_iowrite32_locked(chip, value >> 8, CR157);
+}
+
+/*
+ * 6M band edge can be optionally overwritten for certain RF's
+ * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
+ * bit (for AL2230, AL2230S)
+ */
+static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+{
+       struct zd_ioreq16 ioreqs[] = {
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR47,  0x1e },
+       };
+
+       if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
+               return 0;
+
+       /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+       if (channel == 1 || channel == 11)
+               ioreqs[0].value = 0x12;
+
+       dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_hw_reset_phy(struct zd_chip *chip)
+{
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR0,   0x0a }, { CR1,   0x06 }, { CR2,   0x26 },
+               { CR3,   0x38 }, { CR4,   0x80 }, { CR9,   0xa0 },
+               { CR10,  0x81 }, { CR11,  0x00 }, { CR12,  0x7f },
+               { CR13,  0x8c }, { CR14,  0x80 }, { CR15,  0x3d },
+               { CR16,  0x20 }, { CR17,  0x1e }, { CR18,  0x0a },
+               { CR19,  0x48 }, { CR20,  0x0c }, { CR21,  0x0c },
+               { CR22,  0x23 }, { CR23,  0x90 }, { CR24,  0x14 },
+               { CR25,  0x40 }, { CR26,  0x10 }, { CR27,  0x19 },
+               { CR28,  0x7f }, { CR29,  0x80 }, { CR30,  0x4b },
+               { CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
+               { CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
+               { CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
+               { CR40,  0x84 }, { CR41,  0x2a }, { CR42,  0x80 },
+               { CR43,  0x10 }, { CR44,  0x12 }, { CR46,  0xff },
+               { CR47,  0x1E }, { CR48,  0x26 }, { CR49,  0x5b },
+               { CR64,  0xd0 }, { CR65,  0x04 }, { CR66,  0x58 },
+               { CR67,  0xc9 }, { CR68,  0x88 }, { CR69,  0x41 },
+               { CR70,  0x23 }, { CR71,  0x10 }, { CR72,  0xff },
+               { CR73,  0x32 }, { CR74,  0x30 }, { CR75,  0x65 },
+               { CR76,  0x41 }, { CR77,  0x1b }, { CR78,  0x30 },
+               { CR79,  0x68 }, { CR80,  0x64 }, { CR81,  0x64 },
+               { CR82,  0x00 }, { CR83,  0x00 }, { CR84,  0x00 },
+               { CR85,  0x02 }, { CR86,  0x00 }, { CR87,  0x00 },
+               { CR88,  0xff }, { CR89,  0xfc }, { CR90,  0x00 },
+               { CR91,  0x00 }, { CR92,  0x00 }, { CR93,  0x08 },
+               { CR94,  0x00 }, { CR95,  0x00 }, { CR96,  0xff },
+               { CR97,  0xe7 }, { CR98,  0x00 }, { CR99,  0x00 },
+               { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
+               { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
+               { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
+               { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
+               { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
+               { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+               { },
+               { CR5,   0x00 }, { CR6,   0x00 }, { CR7,   0x00 },
+               { CR8,   0x00 }, { CR9,   0x20 }, { CR12,  0xf0 },
+               { CR20,  0x0e }, { CR21,  0x0e }, { CR27,  0x10 },
+               { CR44,  0x33 }, { CR47,  0x1E }, { CR83,  0x24 },
+               { CR84,  0x04 }, { CR85,  0x00 }, { CR86,  0x0C },
+               { CR87,  0x12 }, { CR88,  0x0C }, { CR89,  0x00 },
+               { CR90,  0x10 }, { CR91,  0x08 }, { CR93,  0x00 },
+               { CR94,  0x01 }, { CR95,  0x00 }, { CR96,  0x50 },
+               { CR97,  0x37 }, { CR98,  0x35 }, { CR101, 0x13 },
+               { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+               { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
+               { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+               { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+               { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
+               { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
+               { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
+               { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
+               { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
+               { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
+               { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
+               { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
+               { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
+               { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+               /* Note: CR204 must lead the CR203 */
+               { CR204, 0x7d },
+               { },
+               { CR203, 0x30 },
+       };
+
+       int r, t;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               goto out;
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               goto unlock;
+
+       r = patch_cr157(chip);
+unlock:
+       t = zd_chip_unlock_phy_regs(chip);
+       if (t && !r)
+               r = t;
+out:
+       return r;
+}
+
+static int zd1211b_hw_reset_phy(struct zd_chip *chip)
+{
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR0,   0x14 }, { CR1,   0x06 }, { CR2,   0x26 },
+               { CR3,   0x38 }, { CR4,   0x80 }, { CR9,   0xe0 },
+               { CR10,  0x81 },
+               /* power control { { CR11,  1 << 6 }, */
+               { CR11,  0x00 },
+               { CR12,  0xf0 }, { CR13,  0x8c }, { CR14,  0x80 },
+               { CR15,  0x3d }, { CR16,  0x20 }, { CR17,  0x1e },
+               { CR18,  0x0a }, { CR19,  0x48 },
+               { CR20,  0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+               { CR21,  0x0e }, { CR22,  0x23 }, { CR23,  0x90 },
+               { CR24,  0x14 }, { CR25,  0x40 }, { CR26,  0x10 },
+               { CR27,  0x10 }, { CR28,  0x7f }, { CR29,  0x80 },
+               { CR30,  0x49 }, /* jointly decoder, no ASIC */
+               { CR31,  0x60 }, { CR32,  0x43 }, { CR33,  0x08 },
+               { CR34,  0x06 }, { CR35,  0x0a }, { CR36,  0x00 },
+               { CR37,  0x00 }, { CR38,  0x38 }, { CR39,  0x0c },
+               { CR40,  0x84 }, { CR41,  0x2a }, { CR42,  0x80 },
+               { CR43,  0x10 }, { CR44,  0x33 }, { CR46,  0xff },
+               { CR47,  0x1E }, { CR48,  0x26 }, { CR49,  0x5b },
+               { CR64,  0xd0 }, { CR65,  0x04 }, { CR66,  0x58 },
+               { CR67,  0xc9 }, { CR68,  0x88 }, { CR69,  0x41 },
+               { CR70,  0x23 }, { CR71,  0x10 }, { CR72,  0xff },
+               { CR73,  0x32 }, { CR74,  0x30 }, { CR75,  0x65 },
+               { CR76,  0x41 }, { CR77,  0x1b }, { CR78,  0x30 },
+               { CR79,  0xf0 }, { CR80,  0x64 }, { CR81,  0x64 },
+               { CR82,  0x00 }, { CR83,  0x24 }, { CR84,  0x04 },
+               { CR85,  0x00 }, { CR86,  0x0c }, { CR87,  0x12 },
+               { CR88,  0x0c }, { CR89,  0x00 }, { CR90,  0x58 },
+               { CR91,  0x04 }, { CR92,  0x00 }, { CR93,  0x00 },
+               { CR94,  0x01 },
+               { CR95,  0x20 }, /* ZD1211B */
+               { CR96,  0x50 }, { CR97,  0x37 }, { CR98,  0x35 },
+               { CR99,  0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
+               { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+               { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
+               { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
+               { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+               { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+               { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
+               { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+               { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+               { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
+               { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
+               { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
+               { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
+               { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+               { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+               { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
+               { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+               { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+               { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+               { CR170, 0xba }, { CR171, 0xba },
+               /* Note: CR204 must lead the CR203 */
+               { CR204, 0x7d },
+               {},
+               { CR203, 0x30 },
+       };
+
+       int r, t;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               goto out;
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               goto unlock;
+
+       r = patch_cr157(chip);
+unlock:
+       t = zd_chip_unlock_phy_regs(chip);
+       if (t && !r)
+               r = t;
+out:
+       return r;
+}
+
+static int hw_reset_phy(struct zd_chip *chip)
+{
+       return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) :
+                                 zd1211_hw_reset_phy(chip);
+}
+
+static int zd1211_hw_init_hmac(struct zd_chip *chip)
+{
+       static const struct zd_ioreq32 ioreqs[] = {
+               { CR_ACK_TIMEOUT_EXT,           0x20 },
+               { CR_ADDA_MBIAS_WARMTIME,       0x30000808 },
+               { CR_ZD1211_RETRY_MAX,          0x2 },
+               { CR_SNIFFER_ON,                0 },
+               { CR_RX_FILTER,                 AP_RX_FILTER },
+               { CR_GROUP_HASH_P1,             0x00 },
+               { CR_GROUP_HASH_P2,             0x80000000 },
+               { CR_REG1,                      0xa4 },
+               { CR_ADDA_PWR_DWN,              0x7f },
+               { CR_BCN_PLCP_CFG,              0x00f00401 },
+               { CR_PHY_DELAY,                 0x00 },
+               { CR_ACK_TIMEOUT_EXT,           0x80 },
+               { CR_ADDA_PWR_DWN,              0x00 },
+               { CR_ACK_TIME_80211,            0x100 },
+               { CR_IFS_VALUE,                 0x547c032 },
+               { CR_RX_PE_DELAY,               0x70 },
+               { CR_PS_CTRL,                   0x10000000 },
+               { CR_RTS_CTS_RATE,              0x02030203 },
+               { CR_RX_THRESHOLD,              0x000c0640 },
+               { CR_AFTER_PNP,                 0x1 },
+               { CR_WEP_PROTECT,               0x114 },
+       };
+
+       int r;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+#ifdef DEBUG
+       if (r) {
+               dev_err(zd_chip_dev(chip),
+                       "error in zd_iowrite32a_locked. Error number %d\n", r);
+       }
+#endif /* DEBUG */
+       return r;
+}
+
+static int zd1211b_hw_init_hmac(struct zd_chip *chip)
+{
+       static const struct zd_ioreq32 ioreqs[] = {
+               { CR_ACK_TIMEOUT_EXT,           0x20 },
+               { CR_ADDA_MBIAS_WARMTIME,       0x30000808 },
+               { CR_ZD1211B_RETRY_MAX,         0x02020202 },
+               { CR_ZD1211B_TX_PWR_CTL4,       0x007f003f },
+               { CR_ZD1211B_TX_PWR_CTL3,       0x007f003f },
+               { CR_ZD1211B_TX_PWR_CTL2,       0x003f001f },
+               { CR_ZD1211B_TX_PWR_CTL1,       0x001f000f },
+               { CR_ZD1211B_AIFS_CTL1,         0x00280028 },
+               { CR_ZD1211B_AIFS_CTL2,         0x008C003C },
+               { CR_ZD1211B_TXOP,              0x01800824 },
+               { CR_SNIFFER_ON,                0 },
+               { CR_RX_FILTER,                 AP_RX_FILTER },
+               { CR_GROUP_HASH_P1,             0x00 },
+               { CR_GROUP_HASH_P2,             0x80000000 },
+               { CR_REG1,                      0xa4 },
+               { CR_ADDA_PWR_DWN,              0x7f },
+               { CR_BCN_PLCP_CFG,              0x00f00401 },
+               { CR_PHY_DELAY,                 0x00 },
+               { CR_ACK_TIMEOUT_EXT,           0x80 },
+               { CR_ADDA_PWR_DWN,              0x00 },
+               { CR_ACK_TIME_80211,            0x100 },
+               { CR_IFS_VALUE,                 0x547c032 },
+               { CR_RX_PE_DELAY,               0x70 },
+               { CR_PS_CTRL,                   0x10000000 },
+               { CR_RTS_CTS_RATE,              0x02030203 },
+               { CR_RX_THRESHOLD,              0x000c0640 },
+               { CR_AFTER_PNP,                 0x1 },
+               { CR_WEP_PROTECT,               0x114 },
+       };
+
+       int r;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip),
+                       "error in zd_iowrite32a_locked. Error number %d\n", r);
+       }
+       return r;
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+       return chip->is_zd1211b ?
+               zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
+}
+
+struct aw_pt_bi {
+       u32 atim_wnd_period;
+       u32 pre_tbtt;
+       u32 beacon_interval;
+};
+
+static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+       int r;
+       static const zd_addr_t aw_pt_bi_addr[] =
+               { CR_ATIM_WND_PERIOD, CR_PRE_TBTT, CR_BCN_INTERVAL };
+       u32 values[3];
+
+       r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr,
+                        ARRAY_SIZE(aw_pt_bi_addr));
+       if (r) {
+               memset(s, 0, sizeof(*s));
+               return r;
+       }
+
+       s->atim_wnd_period = values[0];
+       s->pre_tbtt = values[1];
+       s->beacon_interval = values[2];
+       dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
+               s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
+       return 0;
+}
+
+static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+       struct zd_ioreq32 reqs[3];
+
+       if (s->beacon_interval <= 5)
+               s->beacon_interval = 5;
+       if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval)
+               s->pre_tbtt = s->beacon_interval - 1;
+       if (s->atim_wnd_period >= s->pre_tbtt)
+               s->atim_wnd_period = s->pre_tbtt - 1;
+
+       reqs[0].addr = CR_ATIM_WND_PERIOD;
+       reqs[0].value = s->atim_wnd_period;
+       reqs[1].addr = CR_PRE_TBTT;
+       reqs[1].value = s->pre_tbtt;
+       reqs[2].addr = CR_BCN_INTERVAL;
+       reqs[2].value = s->beacon_interval;
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
+                                      s->beacon_interval);
+       return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+}
+
+
+static int set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+       int r;
+       struct aw_pt_bi s;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = get_aw_pt_bi(chip, &s);
+       if (r)
+               return r;
+       s.beacon_interval = interval;
+       return set_aw_pt_bi(chip, &s);
+}
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = set_beacon_interval(chip, interval);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+static int hw_init(struct zd_chip *chip)
+{
+       int r;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = hw_reset_phy(chip);
+       if (r)
+               return r;
+
+       r = hw_init_hmac(chip);
+       if (r)
+               return r;
+       r = set_beacon_interval(chip, 100);
+       if (r)
+               return r;
+       return 0;
+}
+
+#ifdef DEBUG
+static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
+                  const char *addr_string)
+{
+       int r;
+       u32 value;
+
+       r = zd_ioread32_locked(chip, &value, addr);
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip),
+                       "error reading %s. Error number %d\n", addr_string, r);
+               return r;
+       }
+
+       dev_dbg_f(zd_chip_dev(chip), "%s %#010x\n",
+               addr_string, (unsigned int)value);
+       return 0;
+}
+
+static int test_init(struct zd_chip *chip)
+{
+       int r;
+
+       r = dump_cr(chip, CR_AFTER_PNP, "CR_AFTER_PNP");
+       if (r)
+               return r;
+       r = dump_cr(chip, CR_GPI_EN, "CR_GPI_EN");
+       if (r)
+               return r;
+       return dump_cr(chip, CR_INTERRUPT, "CR_INTERRUPT");
+}
+
+static void dump_fw_registers(struct zd_chip *chip)
+{
+       static const zd_addr_t addr[4] = {
+               FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
+               FW_LINK_STATUS
+       };
+
+       int r;
+       u16 values[4];
+
+       r = zd_ioread16v_locked(chip, values, (const zd_addr_t*)addr,
+                        ARRAY_SIZE(addr));
+       if (r) {
+               dev_dbg_f(zd_chip_dev(chip), "error %d zd_ioread16v_locked\n",
+                        r);
+               return;
+       }
+
+       dev_dbg_f(zd_chip_dev(chip), "FW_FIRMWARE_VER %#06hx\n", values[0]);
+       dev_dbg_f(zd_chip_dev(chip), "FW_USB_SPEED %#06hx\n", values[1]);
+       dev_dbg_f(zd_chip_dev(chip), "FW_FIX_TX_RATE %#06hx\n", values[2]);
+       dev_dbg_f(zd_chip_dev(chip), "FW_LINK_STATUS %#06hx\n", values[3]);
+}
+#endif /* DEBUG */
+
+static int print_fw_version(struct zd_chip *chip)
+{
+       int r;
+       u16 version;
+
+       r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+       if (r)
+               return r;
+
+       dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+       return 0;
+}
+
+static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
+{
+       u32 rates;
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       /* This sets the mandatory rates, which only depend from the standard
+        * that the device is supporting. Until further notice we should try
+        * to support 802.11g also for full speed USB.
+        */
+       switch (std) {
+       case IEEE80211B:
+               rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
+               break;
+       case IEEE80211G:
+               rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
+                       CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL);
+}
+
+int zd_chip_enable_hwint(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite32_locked(chip, HWINT_ENABLED, CR_INTERRUPT);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+static int disable_hwint(struct zd_chip *chip)
+{
+       return zd_iowrite32_locked(chip, HWINT_DISABLED, CR_INTERRUPT);
+}
+
+int zd_chip_disable_hwint(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = disable_hwint(chip);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
+{
+       int r;
+       u8 rf_type;
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+
+       mutex_lock(&chip->mutex);
+       chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
+
+#ifdef DEBUG
+       r = test_init(chip);
+       if (r)
+               goto out;
+#endif
+       r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP);
+       if (r)
+               goto out;
+
+       r = zd_usb_init_hw(&chip->usb);
+       if (r)
+               goto out;
+
+       /* GPI is always disabled, also in the other driver.
+        */
+       r = zd_iowrite32_locked(chip, 0, CR_GPI_EN);
+       if (r)
+               goto out;
+       r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX);
+       if (r)
+               goto out;
+       /* Currently we support IEEE 802.11g for full and high speed USB.
+        * It might be discussed, whether we should suppport pure b mode for
+        * full speed USB.
+        */
+       r = set_mandatory_rates(chip, IEEE80211G);
+       if (r)
+               goto out;
+       /* Disabling interrupts is certainly a smart thing here.
+        */
+       r = disable_hwint(chip);
+       if (r)
+               goto out;
+       r = read_pod(chip, &rf_type);
+       if (r)
+               goto out;
+       r = hw_init(chip);
+       if (r)
+               goto out;
+       r = zd_rf_init_hw(&chip->rf, rf_type);
+       if (r)
+               goto out;
+
+       r = print_fw_version(chip);
+       if (r)
+               goto out;
+
+#ifdef DEBUG
+       dump_fw_registers(chip);
+       r = test_init(chip);
+       if (r)
+               goto out;
+#endif /* DEBUG */
+
+       r = read_e2p_mac_addr(chip);
+       if (r)
+               goto out;
+
+       r = read_cal_int_tables(chip);
+       if (r)
+               goto out;
+
+       print_id(chip);
+out:
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+static int update_pwr_int(struct zd_chip *chip, u8 channel)
+{
+       u8 value = chip->pwr_int_values[channel - 1];
+       dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
+                channel, value);
+       return zd_iowrite32_locked(chip, value, CR31);
+}
+
+static int update_pwr_cal(struct zd_chip *chip, u8 channel)
+{
+       u8 value = chip->pwr_cal_values[channel-1];
+       dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
+                channel, value);
+       return zd_iowrite32_locked(chip, value, CR68);
+}
+
+static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
+{
+       struct zd_ioreq32 ioreqs[3];
+
+       ioreqs[0].addr = CR67;
+       ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
+       ioreqs[1].addr = CR66;
+       ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
+       ioreqs[2].addr = CR65;
+       ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
+
+       dev_dbg_f(zd_chip_dev(chip),
+               "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
+               channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
+       return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int update_channel_integration_and_calibration(struct zd_chip *chip,
+                                                     u8 channel)
+{
+       int r;
+
+       r = update_pwr_int(chip, channel);
+       if (r)
+               return r;
+       if (chip->is_zd1211b) {
+               static const struct zd_ioreq32 ioreqs[] = {
+                       { CR69, 0x28 },
+                       {},
+                       { CR69, 0x2a },
+               };
+
+               r = update_ofdm_cal(chip, channel);
+               if (r)
+                       return r;
+               r = update_pwr_cal(chip, channel);
+               if (r)
+                       return r;
+               r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+/* The CCK baseband gain can be optionally patched by the EEPROM */
+static int patch_cck_gain(struct zd_chip *chip)
+{
+       int r;
+       u32 value;
+
+       if (!chip->patch_cck_gain)
+               return 0;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+       if (r)
+               return r;
+       dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
+       return zd_iowrite32_locked(chip, value & 0xff, CR47);
+}
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
+{
+       int r, t;
+
+       mutex_lock(&chip->mutex);
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               goto out;
+       r = zd_rf_set_channel(&chip->rf, channel);
+       if (r)
+               goto unlock;
+       r = update_channel_integration_and_calibration(chip, channel);
+       if (r)
+               goto unlock;
+       r = patch_cck_gain(chip);
+       if (r)
+               goto unlock;
+       r = patch_6m_band_edge(chip, channel);
+       if (r)
+               goto unlock;
+       r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS);
+unlock:
+       t = zd_chip_unlock_phy_regs(chip);
+       if (t && !r)
+               r = t;
+out:
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+u8 zd_chip_get_channel(struct zd_chip *chip)
+{
+       u8 channel;
+
+       mutex_lock(&chip->mutex);
+       channel = chip->rf.channel;
+       mutex_unlock(&chip->mutex);
+       return channel;
+}
+
+static u16 led_mask(int led)
+{
+       switch (led) {
+       case 1:
+               return LED1;
+       case 2:
+               return LED2;
+       default:
+               return 0;
+       }
+}
+
+static int read_led_reg(struct zd_chip *chip, u16 *status)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_ioread16_locked(chip, status, CR_LED);
+}
+
+static int write_led_reg(struct zd_chip *chip, u16 status)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_iowrite16_locked(chip, status, CR_LED);
+}
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
+{
+       int r, ret;
+       u16 mask = led_mask(led);
+       u16 reg;
+
+       if (!mask)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       r = read_led_reg(chip, &reg);
+       if (r)
+               return r;
+       switch (status) {
+       case LED_STATUS:
+               return (reg & mask) ? LED_ON : LED_OFF;
+       case LED_OFF:
+               reg &= ~mask;
+               ret = LED_OFF;
+               break;
+       case LED_FLIP:
+               reg ^= mask;
+               ret = (reg&mask) ? LED_ON : LED_OFF;
+               break;
+       case LED_ON:
+               reg |= mask;
+               ret = LED_ON;
+               break;
+       default:
+               return -EINVAL;
+       }
+       r = write_led_reg(chip, reg);
+       if (r) {
+               ret = r;
+               goto out;
+       }
+out:
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+       const unsigned int *phases_msecs, unsigned int count)
+{
+       int i, r;
+       enum led_status status;
+
+       r = zd_chip_led_status(chip, led, LED_STATUS);
+       if (r)
+               return r;
+       status = r;
+       for (i = 0; i < count; i++) {
+               r = zd_chip_led_status(chip, led, LED_FLIP);
+               if (r < 0)
+                       goto out;
+               msleep(phases_msecs[i]);
+       }
+
+out:
+       zd_chip_led_status(chip, led, status);
+       return r;
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
+{
+       int r;
+
+       if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+{
+       static const u16 constants[] = {
+               715, 655, 585, 540, 470, 410, 360, 315,
+               270, 235, 205, 175, 150, 125, 105,  85,
+                65,  50,  40,  25,  15
+       };
+
+       int i;
+       u32 x;
+
+       /* It seems that their quality parameter is somehow per signal
+        * and is now transferred per bit.
+        */
+       switch (rate) {
+       case ZD_OFDM_RATE_6M:
+       case ZD_OFDM_RATE_12M:
+       case ZD_OFDM_RATE_24M:
+               size *= 2;
+               break;
+       case ZD_OFDM_RATE_9M:
+       case ZD_OFDM_RATE_18M:
+       case ZD_OFDM_RATE_36M:
+       case ZD_OFDM_RATE_54M:
+               size *= 4;
+               size /= 3;
+               break;
+       case ZD_OFDM_RATE_48M:
+               size *= 3;
+               size /= 2;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       x = (10000 * status_quality)/size;
+       for (i = 0; i < ARRAY_SIZE(constants); i++) {
+               if (x > constants[i])
+                       break;
+       }
+
+       return i;
+}
+
+static unsigned int log10times100(unsigned int x)
+{
+       static const u8 log10[] = {
+                 0,
+                 0,   30,   47,   60,   69,   77,   84,   90,   95,  100,
+               104,  107,  111,  114,  117,  120,  123,  125,  127,  130,
+               132,  134,  136,  138,  139,  141,  143,  144,  146,  147,
+               149,  150,  151,  153,  154,  155,  156,  157,  159,  160,
+               161,  162,  163,  164,  165,  166,  167,  168,  169,  169,
+               170,  171,  172,  173,  174,  174,  175,  176,  177,  177,
+               178,  179,  179,  180,  181,  181,  182,  183,  183,  184,
+               185,  185,  186,  186,  187,  188,  188,  189,  189,  190,
+               190,  191,  191,  192,  192,  193,  193,  194,  194,  195,
+               195,  196,  196,  197,  197,  198,  198,  199,  199,  200,
+               200,  200,  201,  201,  202,  202,  202,  203,  203,  204,
+               204,  204,  205,  205,  206,  206,  206,  207,  207,  207,
+               208,  208,  208,  209,  209,  210,  210,  210,  211,  211,
+               211,  212,  212,  212,  213,  213,  213,  213,  214,  214,
+               214,  215,  215,  215,  216,  216,  216,  217,  217,  217,
+               217,  218,  218,  218,  219,  219,  219,  219,  220,  220,
+               220,  220,  221,  221,  221,  222,  222,  222,  222,  223,
+               223,  223,  223,  224,  224,  224,  224,
+       };
+
+       return x < ARRAY_SIZE(log10) ? log10[x] : 225;
+}
+
+enum {
+       MAX_CCK_EVM_DB = 45,
+};
+
+static int cck_evm_db(u8 status_quality)
+{
+       return (20 * log10times100(status_quality)) / 100;
+}
+
+static int cck_snr_db(u8 status_quality)
+{
+       int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
+       ZD_ASSERT(r >= 0);
+       return r;
+}
+
+static int rx_qual_db(const void *rx_frame, unsigned int size,
+                     const struct rx_status *status)
+{
+       return (status->frame_status&ZD_RX_OFDM) ?
+               ofdm_qual_db(status->signal_quality_ofdm,
+                            zd_ofdm_plcp_header_rate(rx_frame),
+                            size) :
+               cck_snr_db(status->signal_quality_cck);
+}
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+                     const struct rx_status *status)
+{
+       int r = rx_qual_db(rx_frame, size, status);
+       if (r < 0)
+               r = 0;
+       r = (r * 100) / 14;
+       if (r > 100)
+               r = 100;
+       return r;
+}
+
+u8 zd_rx_strength_percent(u8 rssi)
+{
+       int r = (rssi*100) / 30;
+       if (r > 100)
+               r = 100;
+       return (u8) r;
+}
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+{
+       static const u16 ofdm_rates[] = {
+               [ZD_OFDM_RATE_6M]  = 60,
+               [ZD_OFDM_RATE_9M]  = 90,
+               [ZD_OFDM_RATE_12M] = 120,
+               [ZD_OFDM_RATE_18M] = 180,
+               [ZD_OFDM_RATE_24M] = 240,
+               [ZD_OFDM_RATE_36M] = 360,
+               [ZD_OFDM_RATE_48M] = 480,
+               [ZD_OFDM_RATE_54M] = 540,
+       };
+       u16 rate;
+       if (status->frame_status & ZD_RX_OFDM) {
+               u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
+               rate = ofdm_rates[ofdm_rate & 0xf];
+       } else {
+               u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
+               switch (cck_rate) {
+               case ZD_CCK_SIGNAL_1M:
+                       rate = 10;
+                       break;
+               case ZD_CCK_SIGNAL_2M:
+                       rate = 20;
+                       break;
+               case ZD_CCK_SIGNAL_5M5:
+                       rate = 55;
+                       break;
+               case ZD_CCK_SIGNAL_11M:
+                       rate = 110;
+                       break;
+               default:
+                       rate = 0;
+               }
+       }
+
+       return rate;
+}
+
+int zd_chip_switch_radio_on(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = zd_switch_radio_on(&chip->rf);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_chip_switch_radio_off(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = zd_switch_radio_off(&chip->rf);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+int zd_chip_enable_int(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = zd_usb_enable_int(&chip->usb);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+void zd_chip_disable_int(struct zd_chip *chip)
+{
+       mutex_lock(&chip->mutex);
+       zd_usb_disable_int(&chip->usb);
+       mutex_unlock(&chip->mutex);
+}
+
+int zd_chip_enable_rx(struct zd_chip *chip)
+{
+       int r;
+
+       mutex_lock(&chip->mutex);
+       r = zd_usb_enable_rx(&chip->usb);
+       mutex_unlock(&chip->mutex);
+       return r;
+}
+
+void zd_chip_disable_rx(struct zd_chip *chip)
+{
+       mutex_lock(&chip->mutex);
+       zd_usb_disable_rx(&chip->usb);
+       mutex_unlock(&chip->mutex);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+                      const u32* values, unsigned int count, u8 bits)
+{
+       int r;
+       unsigned int i;
+
+       for (i = 0; i < count; i++) {
+               r = zd_rfwrite_locked(chip, values[i], bits);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
new file mode 100644 (file)
index 0000000..8051210
--- /dev/null
@@ -0,0 +1,825 @@
+/* zd_chip.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_CHIP_H
+#define _ZD_CHIP_H
+
+#include "zd_types.h"
+#include "zd_rf.h"
+#include "zd_usb.h"
+
+/* Header for the Media Access Controller (MAC) and the Baseband Processor
+ * (BBP). It appears that the ZD1211 wraps the old ZD1205 with USB glue and
+ * adds a processor for handling the USB protocol.
+ */
+
+/* 8-bit hardware registers */
+#define CR0   CTL_REG(0x0000)
+#define CR1   CTL_REG(0x0004)
+#define CR2   CTL_REG(0x0008)
+#define CR3   CTL_REG(0x000C)
+
+#define CR5   CTL_REG(0x0010)
+/*     bit 5: if set short preamble used
+ *     bit 6: filter band - Japan channel 14 on, else off
+ */
+#define CR6   CTL_REG(0x0014)
+#define CR7   CTL_REG(0x0018)
+#define CR8   CTL_REG(0x001C)
+
+#define CR4   CTL_REG(0x0020)
+
+#define CR9   CTL_REG(0x0024)
+/*     bit 2: antenna switch (together with CR10) */
+#define CR10  CTL_REG(0x0028)
+/*     bit 1: antenna switch (together with CR9)
+ *     RF2959 controls with CR11 radion on and off
+ */
+#define CR11  CTL_REG(0x002C)
+/*     bit 6:  TX power control for OFDM
+ *     RF2959 controls with CR10 radio on and off
+ */
+#define CR12  CTL_REG(0x0030)
+#define CR13  CTL_REG(0x0034)
+#define CR14  CTL_REG(0x0038)
+#define CR15  CTL_REG(0x003C)
+#define CR16  CTL_REG(0x0040)
+#define CR17  CTL_REG(0x0044)
+#define CR18  CTL_REG(0x0048)
+#define CR19  CTL_REG(0x004C)
+#define CR20  CTL_REG(0x0050)
+#define CR21  CTL_REG(0x0054)
+#define CR22  CTL_REG(0x0058)
+#define CR23  CTL_REG(0x005C)
+#define CR24  CTL_REG(0x0060)  /* CCA threshold */
+#define CR25  CTL_REG(0x0064)
+#define CR26  CTL_REG(0x0068)
+#define CR27  CTL_REG(0x006C)
+#define CR28  CTL_REG(0x0070)
+#define CR29  CTL_REG(0x0074)
+#define CR30  CTL_REG(0x0078)
+#define CR31  CTL_REG(0x007C)  /* TX power control for RF in CCK mode */
+#define CR32  CTL_REG(0x0080)
+#define CR33  CTL_REG(0x0084)
+#define CR34  CTL_REG(0x0088)
+#define CR35  CTL_REG(0x008C)
+#define CR36  CTL_REG(0x0090)
+#define CR37  CTL_REG(0x0094)
+#define CR38  CTL_REG(0x0098)
+#define CR39  CTL_REG(0x009C)
+#define CR40  CTL_REG(0x00A0)
+#define CR41  CTL_REG(0x00A4)
+#define CR42  CTL_REG(0x00A8)
+#define CR43  CTL_REG(0x00AC)
+#define CR44  CTL_REG(0x00B0)
+#define CR45  CTL_REG(0x00B4)
+#define CR46  CTL_REG(0x00B8)
+#define CR47  CTL_REG(0x00BC)  /* CCK baseband gain
+                                * (patch value might be in EEPROM)
+                                */
+#define CR48  CTL_REG(0x00C0)
+#define CR49  CTL_REG(0x00C4)
+#define CR50  CTL_REG(0x00C8)
+#define CR51  CTL_REG(0x00CC)  /* TX power control for RF in 6-36M modes */
+#define CR52  CTL_REG(0x00D0)  /* TX power control for RF in 48M mode */
+#define CR53  CTL_REG(0x00D4)  /* TX power control for RF in 54M mode */
+#define CR54  CTL_REG(0x00D8)
+#define CR55  CTL_REG(0x00DC)
+#define CR56  CTL_REG(0x00E0)
+#define CR57  CTL_REG(0x00E4)
+#define CR58  CTL_REG(0x00E8)
+#define CR59  CTL_REG(0x00EC)
+#define CR60  CTL_REG(0x00F0)
+#define CR61  CTL_REG(0x00F4)
+#define CR62  CTL_REG(0x00F8)
+#define CR63  CTL_REG(0x00FC)
+#define CR64  CTL_REG(0x0100)
+#define CR65  CTL_REG(0x0104) /* OFDM 54M calibration */
+#define CR66  CTL_REG(0x0108) /* OFDM 48M calibration */
+#define CR67  CTL_REG(0x010C) /* OFDM 36M calibration */
+#define CR68  CTL_REG(0x0110) /* CCK calibration */
+#define CR69  CTL_REG(0x0114)
+#define CR70  CTL_REG(0x0118)
+#define CR71  CTL_REG(0x011C)
+#define CR72  CTL_REG(0x0120)
+#define CR73  CTL_REG(0x0124)
+#define CR74  CTL_REG(0x0128)
+#define CR75  CTL_REG(0x012C)
+#define CR76  CTL_REG(0x0130)
+#define CR77  CTL_REG(0x0134)
+#define CR78  CTL_REG(0x0138)
+#define CR79  CTL_REG(0x013C)
+#define CR80  CTL_REG(0x0140)
+#define CR81  CTL_REG(0x0144)
+#define CR82  CTL_REG(0x0148)
+#define CR83  CTL_REG(0x014C)
+#define CR84  CTL_REG(0x0150)
+#define CR85  CTL_REG(0x0154)
+#define CR86  CTL_REG(0x0158)
+#define CR87  CTL_REG(0x015C)
+#define CR88  CTL_REG(0x0160)
+#define CR89  CTL_REG(0x0164)
+#define CR90  CTL_REG(0x0168)
+#define CR91  CTL_REG(0x016C)
+#define CR92  CTL_REG(0x0170)
+#define CR93  CTL_REG(0x0174)
+#define CR94  CTL_REG(0x0178)
+#define CR95  CTL_REG(0x017C)
+#define CR96  CTL_REG(0x0180)
+#define CR97  CTL_REG(0x0184)
+#define CR98  CTL_REG(0x0188)
+#define CR99  CTL_REG(0x018C)
+#define CR100 CTL_REG(0x0190)
+#define CR101 CTL_REG(0x0194)
+#define CR102 CTL_REG(0x0198)
+#define CR103 CTL_REG(0x019C)
+#define CR104 CTL_REG(0x01A0)
+#define CR105 CTL_REG(0x01A4)
+#define CR106 CTL_REG(0x01A8)
+#define CR107 CTL_REG(0x01AC)
+#define CR108 CTL_REG(0x01B0)
+#define CR109 CTL_REG(0x01B4)
+#define CR110 CTL_REG(0x01B8)
+#define CR111 CTL_REG(0x01BC)
+#define CR112 CTL_REG(0x01C0)
+#define CR113 CTL_REG(0x01C4)
+#define CR114 CTL_REG(0x01C8)
+#define CR115 CTL_REG(0x01CC)
+#define CR116 CTL_REG(0x01D0)
+#define CR117 CTL_REG(0x01D4)
+#define CR118 CTL_REG(0x01D8)
+#define CR119 CTL_REG(0x01DC)
+#define CR120 CTL_REG(0x01E0)
+#define CR121 CTL_REG(0x01E4)
+#define CR122 CTL_REG(0x01E8)
+#define CR123 CTL_REG(0x01EC)
+#define CR124 CTL_REG(0x01F0)
+#define CR125 CTL_REG(0x01F4)
+#define CR126 CTL_REG(0x01F8)
+#define CR127 CTL_REG(0x01FC)
+#define CR128 CTL_REG(0x0200)
+#define CR129 CTL_REG(0x0204)
+#define CR130 CTL_REG(0x0208)
+#define CR131 CTL_REG(0x020C)
+#define CR132 CTL_REG(0x0210)
+#define CR133 CTL_REG(0x0214)
+#define CR134 CTL_REG(0x0218)
+#define CR135 CTL_REG(0x021C)
+#define CR136 CTL_REG(0x0220)
+#define CR137 CTL_REG(0x0224)
+#define CR138 CTL_REG(0x0228)
+#define CR139 CTL_REG(0x022C)
+#define CR140 CTL_REG(0x0230)
+#define CR141 CTL_REG(0x0234)
+#define CR142 CTL_REG(0x0238)
+#define CR143 CTL_REG(0x023C)
+#define CR144 CTL_REG(0x0240)
+#define CR145 CTL_REG(0x0244)
+#define CR146 CTL_REG(0x0248)
+#define CR147 CTL_REG(0x024C)
+#define CR148 CTL_REG(0x0250)
+#define CR149 CTL_REG(0x0254)
+#define CR150 CTL_REG(0x0258)
+#define CR151 CTL_REG(0x025C)
+#define CR152 CTL_REG(0x0260)
+#define CR153 CTL_REG(0x0264)
+#define CR154 CTL_REG(0x0268)
+#define CR155 CTL_REG(0x026C)
+#define CR156 CTL_REG(0x0270)
+#define CR157 CTL_REG(0x0274)
+#define CR158 CTL_REG(0x0278)
+#define CR159 CTL_REG(0x027C)
+#define CR160 CTL_REG(0x0280)
+#define CR161 CTL_REG(0x0284)
+#define CR162 CTL_REG(0x0288)
+#define CR163 CTL_REG(0x028C)
+#define CR164 CTL_REG(0x0290)
+#define CR165 CTL_REG(0x0294)
+#define CR166 CTL_REG(0x0298)
+#define CR167 CTL_REG(0x029C)
+#define CR168 CTL_REG(0x02A0)
+#define CR169 CTL_REG(0x02A4)
+#define CR170 CTL_REG(0x02A8)
+#define CR171 CTL_REG(0x02AC)
+#define CR172 CTL_REG(0x02B0)
+#define CR173 CTL_REG(0x02B4)
+#define CR174 CTL_REG(0x02B8)
+#define CR175 CTL_REG(0x02BC)
+#define CR176 CTL_REG(0x02C0)
+#define CR177 CTL_REG(0x02C4)
+#define CR178 CTL_REG(0x02C8)
+#define CR179 CTL_REG(0x02CC)
+#define CR180 CTL_REG(0x02D0)
+#define CR181 CTL_REG(0x02D4)
+#define CR182 CTL_REG(0x02D8)
+#define CR183 CTL_REG(0x02DC)
+#define CR184 CTL_REG(0x02E0)
+#define CR185 CTL_REG(0x02E4)
+#define CR186 CTL_REG(0x02E8)
+#define CR187 CTL_REG(0x02EC)
+#define CR188 CTL_REG(0x02F0)
+#define CR189 CTL_REG(0x02F4)
+#define CR190 CTL_REG(0x02F8)
+#define CR191 CTL_REG(0x02FC)
+#define CR192 CTL_REG(0x0300)
+#define CR193 CTL_REG(0x0304)
+#define CR194 CTL_REG(0x0308)
+#define CR195 CTL_REG(0x030C)
+#define CR196 CTL_REG(0x0310)
+#define CR197 CTL_REG(0x0314)
+#define CR198 CTL_REG(0x0318)
+#define CR199 CTL_REG(0x031C)
+#define CR200 CTL_REG(0x0320)
+#define CR201 CTL_REG(0x0324)
+#define CR202 CTL_REG(0x0328)
+#define CR203 CTL_REG(0x032C)  /* I2C bus template value & flash control */
+#define CR204 CTL_REG(0x0330)
+#define CR205 CTL_REG(0x0334)
+#define CR206 CTL_REG(0x0338)
+#define CR207 CTL_REG(0x033C)
+#define CR208 CTL_REG(0x0340)
+#define CR209 CTL_REG(0x0344)
+#define CR210 CTL_REG(0x0348)
+#define CR211 CTL_REG(0x034C)
+#define CR212 CTL_REG(0x0350)
+#define CR213 CTL_REG(0x0354)
+#define CR214 CTL_REG(0x0358)
+#define CR215 CTL_REG(0x035C)
+#define CR216 CTL_REG(0x0360)
+#define CR217 CTL_REG(0x0364)
+#define CR218 CTL_REG(0x0368)
+#define CR219 CTL_REG(0x036C)
+#define CR220 CTL_REG(0x0370)
+#define CR221 CTL_REG(0x0374)
+#define CR222 CTL_REG(0x0378)
+#define CR223 CTL_REG(0x037C)
+#define CR224 CTL_REG(0x0380)
+#define CR225 CTL_REG(0x0384)
+#define CR226 CTL_REG(0x0388)
+#define CR227 CTL_REG(0x038C)
+#define CR228 CTL_REG(0x0390)
+#define CR229 CTL_REG(0x0394)
+#define CR230 CTL_REG(0x0398)
+#define CR231 CTL_REG(0x039C)
+#define CR232 CTL_REG(0x03A0)
+#define CR233 CTL_REG(0x03A4)
+#define CR234 CTL_REG(0x03A8)
+#define CR235 CTL_REG(0x03AC)
+#define CR236 CTL_REG(0x03B0)
+
+#define CR240 CTL_REG(0x03C0)
+/*     bit 7:  host-controlled RF register writes
+ * CR241-CR245: for hardware controlled writing of RF bits, not needed for
+ *              USB
+ */
+#define CR241 CTL_REG(0x03C4)
+#define CR242 CTL_REG(0x03C8)
+#define CR243 CTL_REG(0x03CC)
+#define CR244 CTL_REG(0x03D0)
+#define CR245 CTL_REG(0x03D4)
+
+#define CR251 CTL_REG(0x03EC)  /* only used for activation and deactivation of
+                                * Airoha RFs AL2230 and AL7230B
+                                */
+#define CR252 CTL_REG(0x03F0)
+#define CR253 CTL_REG(0x03F4)
+#define CR254 CTL_REG(0x03F8)
+#define CR255 CTL_REG(0x03FC)
+
+#define CR_MAX_PHY_REG 255
+
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+ * driver.
+ */
+
+#define CR_RF_IF_CLK                   CTL_REG(0x0400)
+#define CR_RF_IF_DATA                  CTL_REG(0x0404)
+#define CR_PE1_PE2                     CTL_REG(0x0408)
+#define CR_PE2_DLY                     CTL_REG(0x040C)
+#define CR_LE1                         CTL_REG(0x0410)
+#define CR_LE2                         CTL_REG(0x0414)
+/* Seems to enable/disable GPI (General Purpose IO?) */
+#define CR_GPI_EN                      CTL_REG(0x0418)
+#define CR_RADIO_PD                    CTL_REG(0x042C)
+#define CR_RF2948_PD                   CTL_REG(0x042C)
+#define CR_ENABLE_PS_MANUAL_AGC                CTL_REG(0x043C)
+#define CR_CONFIG_PHILIPS              CTL_REG(0x0440)
+#define CR_SA2400_SER_AP               CTL_REG(0x0444)
+#define CR_I2C_WRITE                   CTL_REG(0x0444)
+#define CR_SA2400_SER_RP               CTL_REG(0x0448)
+#define CR_RADIO_PE                    CTL_REG(0x0458)
+#define CR_RST_BUS_MASTER              CTL_REG(0x045C)
+#define CR_RFCFG                       CTL_REG(0x0464)
+#define CR_HSTSCHG                     CTL_REG(0x046C)
+#define CR_PHY_ON                      CTL_REG(0x0474)
+#define CR_RX_DELAY                    CTL_REG(0x0478)
+#define CR_RX_PE_DELAY                 CTL_REG(0x047C)
+#define CR_GPIO_1                      CTL_REG(0x0490)
+#define CR_GPIO_2                      CTL_REG(0x0494)
+#define CR_EncryBufMux                 CTL_REG(0x04A8)
+#define CR_PS_CTRL                     CTL_REG(0x0500)
+#define CR_ADDA_PWR_DWN                        CTL_REG(0x0504)
+#define CR_ADDA_MBIAS_WARMTIME         CTL_REG(0x0508)
+#define CR_MAC_PS_STATE                        CTL_REG(0x050C)
+
+#define CR_INTERRUPT                   CTL_REG(0x0510)
+#define INT_TX_COMPLETE                        0x00000001
+#define INT_RX_COMPLETE                        0x00000002
+#define INT_RETRY_FAIL                 0x00000004
+#define INT_WAKEUP                     0x00000008
+#define INT_DTIM_NOTIFY                        0x00000020
+#define INT_CFG_NEXT_BCN               0x00000040
+#define INT_BUS_ABORT                  0x00000080
+#define INT_TX_FIFO_READY              0x00000100
+#define INT_UART                       0x00000200
+#define INT_TX_COMPLETE_EN             0x00010000
+#define INT_RX_COMPLETE_EN             0x00020000
+#define INT_RETRY_FAIL_EN              0x00040000
+#define INT_WAKEUP_EN                  0x00080000
+#define INT_DTIM_NOTIFY_EN             0x00200000
+#define INT_CFG_NEXT_BCN_EN            0x00400000
+#define INT_BUS_ABORT_EN               0x00800000
+#define INT_TX_FIFO_READY_EN           0x01000000
+#define INT_UART_EN                    0x02000000
+
+#define CR_TSF_LOW_PART                        CTL_REG(0x0514)
+#define CR_TSF_HIGH_PART               CTL_REG(0x0518)
+
+/* Following three values are in time units (1024us)
+ * Following condition must be met:
+ * atim < tbtt < bcn
+ */
+#define CR_ATIM_WND_PERIOD             CTL_REG(0x051C)
+#define CR_BCN_INTERVAL                        CTL_REG(0x0520)
+#define CR_PRE_TBTT                    CTL_REG(0x0524)
+/* in units of TU(1024us) */
+
+/* for UART support */
+#define CR_UART_RBR_THR_DLL            CTL_REG(0x0540)
+#define CR_UART_DLM_IER                        CTL_REG(0x0544)
+#define CR_UART_IIR_FCR                        CTL_REG(0x0548)
+#define CR_UART_LCR                    CTL_REG(0x054c)
+#define CR_UART_MCR                    CTL_REG(0x0550)
+#define CR_UART_LSR                    CTL_REG(0x0554)
+#define CR_UART_MSR                    CTL_REG(0x0558)
+#define CR_UART_ECR                    CTL_REG(0x055c)
+#define CR_UART_STATUS                 CTL_REG(0x0560)
+
+#define CR_PCI_TX_ADDR_P1              CTL_REG(0x0600)
+#define CR_PCI_TX_AddR_P2              CTL_REG(0x0604)
+#define CR_PCI_RX_AddR_P1              CTL_REG(0x0608)
+#define CR_PCI_RX_AddR_P2              CTL_REG(0x060C)
+
+/* must be overwritten if custom MAC address will be used */
+#define CR_MAC_ADDR_P1                 CTL_REG(0x0610)
+#define CR_MAC_ADDR_P2                 CTL_REG(0x0614)
+#define CR_BSSID_P1                    CTL_REG(0x0618)
+#define CR_BSSID_P2                    CTL_REG(0x061C)
+#define CR_BCN_PLCP_CFG                        CTL_REG(0x0620)
+#define CR_GROUP_HASH_P1               CTL_REG(0x0624)
+#define CR_GROUP_HASH_P2               CTL_REG(0x0628)
+#define CR_RX_TIMEOUT                  CTL_REG(0x062C)
+
+/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
+ * device will use a rate in this table that is less than or equal to the rate
+ * of the incoming frame which prompted the response */
+#define CR_BASIC_RATE_TBL              CTL_REG(0x0630)
+#define CR_RATE_1M     0x0001  /* 802.11b */
+#define CR_RATE_2M     0x0002  /* 802.11b */
+#define CR_RATE_5_5M   0x0004  /* 802.11b */
+#define CR_RATE_11M    0x0008  /* 802.11b */
+#define CR_RATE_6M      0x0100 /* 802.11g */
+#define CR_RATE_9M      0x0200 /* 802.11g */
+#define CR_RATE_12M    0x0400  /* 802.11g */
+#define CR_RATE_18M    0x0800  /* 802.11g */
+#define CR_RATE_24M     0x1000 /* 802.11g */
+#define CR_RATE_36M     0x2000 /* 802.11g */
+#define CR_RATE_48M     0x4000 /* 802.11g */
+#define CR_RATE_54M     0x8000 /* 802.11g */
+#define CR_RATES_80211G        0xff00
+#define CR_RATES_80211B        0x000f
+
+/* Mandatory rates required in the BSS. When producing ACK or CTS messages, if
+ * the device could not find an appropriate rate in CR_BASIC_RATE_TBL, it will
+ * look for a rate in this table that is less than or equal to the rate of
+ * the incoming frame. */
+#define CR_MANDATORY_RATE_TBL          CTL_REG(0x0634)
+#define CR_RTS_CTS_RATE                        CTL_REG(0x0638)
+
+#define CR_WEP_PROTECT                 CTL_REG(0x063C)
+#define CR_RX_THRESHOLD                        CTL_REG(0x0640)
+
+/* register for controlling the LEDS */
+#define CR_LED                         CTL_REG(0x0644)
+/* masks for controlling LEDs */
+#define LED1                           0x0100
+#define LED2                           0x0200
+
+/* Seems to indicate that the configuration is over.
+ */
+#define CR_AFTER_PNP                   CTL_REG(0x0648)
+#define CR_ACK_TIME_80211              CTL_REG(0x0658)
+
+#define CR_RX_OFFSET                   CTL_REG(0x065c)
+
+#define CR_PHY_DELAY                   CTL_REG(0x066C)
+#define CR_BCN_FIFO                    CTL_REG(0x0670)
+#define CR_SNIFFER_ON                  CTL_REG(0x0674)
+
+#define CR_ENCRYPTION_TYPE             CTL_REG(0x0678)
+#define NO_WEP                         0
+#define WEP64                          1
+#define WEP128                         5
+#define WEP256                         6
+#define ENC_SNIFFER                    8
+
+#define CR_ZD1211_RETRY_MAX            CTL_REG(0x067C)
+
+#define CR_REG1                                CTL_REG(0x0680)
+/* Setting the bit UNLOCK_PHY_REGS disallows the write access to physical
+ * registers, so one could argue it is a LOCK bit. But calling it
+ * LOCK_PHY_REGS makes it confusing.
+ */
+#define UNLOCK_PHY_REGS                        0x0080
+
+#define CR_DEVICE_STATE                        CTL_REG(0x0684)
+#define CR_UNDERRUN_CNT                        CTL_REG(0x0688)
+
+#define CR_RX_FILTER                   CTL_REG(0x068c)
+#define RX_FILTER_ASSOC_RESPONSE       0x0002
+#define RX_FILTER_PROBE_RESPONSE       0x0020
+#define RX_FILTER_BEACON               0x0100
+#define RX_FILTER_AUTH                 0x0800
+/* Sniff modus sets filter to 0xfffff */
+
+#define CR_ACK_TIMEOUT_EXT             CTL_REG(0x0690)
+#define CR_BCN_FIFO_SEMAPHORE          CTL_REG(0x0694)
+#define CR_IFS_VALUE                   CTL_REG(0x0698)
+#define CR_RX_TIME_OUT                 CTL_REG(0x069C)
+#define CR_TOTAL_RX_FRM                        CTL_REG(0x06A0)
+#define CR_CRC32_CNT                   CTL_REG(0x06A4)
+#define CR_CRC16_CNT                   CTL_REG(0x06A8)
+#define CR_DECRYPTION_ERR_UNI          CTL_REG(0x06AC)
+#define CR_RX_FIFO_OVERRUN             CTL_REG(0x06B0)
+
+#define CR_DECRYPTION_ERR_MUL          CTL_REG(0x06BC)
+
+#define CR_NAV_CNT                     CTL_REG(0x06C4)
+#define CR_NAV_CCA                     CTL_REG(0x06C8)
+#define CR_RETRY_CNT                   CTL_REG(0x06CC)
+
+#define CR_READ_TCB_ADDR               CTL_REG(0x06E8)
+#define CR_READ_RFD_ADDR               CTL_REG(0x06EC)
+#define CR_CWMIN_CWMAX                 CTL_REG(0x06F0)
+#define CR_TOTAL_TX_FRM                        CTL_REG(0x06F4)
+
+/* CAM: Continuous Access Mode (power management) */
+#define CR_CAM_MODE                    CTL_REG(0x0700)
+#define CR_CAM_ROLL_TB_LOW             CTL_REG(0x0704)
+#define CR_CAM_ROLL_TB_HIGH            CTL_REG(0x0708)
+#define CR_CAM_ADDRESS                 CTL_REG(0x070C)
+#define CR_CAM_DATA                    CTL_REG(0x0710)
+
+#define CR_ROMDIR                      CTL_REG(0x0714)
+
+#define CR_DECRY_ERR_FLG_LOW           CTL_REG(0x0714)
+#define CR_DECRY_ERR_FLG_HIGH          CTL_REG(0x0718)
+
+#define CR_WEPKEY0                     CTL_REG(0x0720)
+#define CR_WEPKEY1                     CTL_REG(0x0724)
+#define CR_WEPKEY2                     CTL_REG(0x0728)
+#define CR_WEPKEY3                     CTL_REG(0x072C)
+#define CR_WEPKEY4                     CTL_REG(0x0730)
+#define CR_WEPKEY5                     CTL_REG(0x0734)
+#define CR_WEPKEY6                     CTL_REG(0x0738)
+#define CR_WEPKEY7                     CTL_REG(0x073C)
+#define CR_WEPKEY8                     CTL_REG(0x0740)
+#define CR_WEPKEY9                     CTL_REG(0x0744)
+#define CR_WEPKEY10                    CTL_REG(0x0748)
+#define CR_WEPKEY11                    CTL_REG(0x074C)
+#define CR_WEPKEY12                    CTL_REG(0x0750)
+#define CR_WEPKEY13                    CTL_REG(0x0754)
+#define CR_WEPKEY14                    CTL_REG(0x0758)
+#define CR_WEPKEY15                    CTL_REG(0x075c)
+#define CR_TKIP_MODE                   CTL_REG(0x0760)
+
+#define CR_EEPROM_PROTECT0             CTL_REG(0x0758)
+#define CR_EEPROM_PROTECT1             CTL_REG(0x075C)
+
+#define CR_DBG_FIFO_RD                 CTL_REG(0x0800)
+#define CR_DBG_SELECT                  CTL_REG(0x0804)
+#define CR_FIFO_Length                 CTL_REG(0x0808)
+
+
+#define CR_RSSI_MGC                    CTL_REG(0x0810)
+
+#define CR_PON                         CTL_REG(0x0818)
+#define CR_RX_ON                       CTL_REG(0x081C)
+#define CR_TX_ON                       CTL_REG(0x0820)
+#define CR_CHIP_EN                     CTL_REG(0x0824)
+#define CR_LO_SW                       CTL_REG(0x0828)
+#define CR_TXRX_SW                     CTL_REG(0x082C)
+#define CR_S_MD                                CTL_REG(0x0830)
+
+#define CR_USB_DEBUG_PORT              CTL_REG(0x0888)
+
+#define CR_ZD1211B_TX_PWR_CTL1         CTL_REG(0x0b00)
+#define CR_ZD1211B_TX_PWR_CTL2         CTL_REG(0x0b04)
+#define CR_ZD1211B_TX_PWR_CTL3         CTL_REG(0x0b08)
+#define CR_ZD1211B_TX_PWR_CTL4         CTL_REG(0x0b0c)
+#define CR_ZD1211B_AIFS_CTL1           CTL_REG(0x0b10)
+#define CR_ZD1211B_AIFS_CTL2           CTL_REG(0x0b14)
+#define CR_ZD1211B_TXOP                        CTL_REG(0x0b20)
+#define CR_ZD1211B_RETRY_MAX           CTL_REG(0x0b28)
+
+#define AP_RX_FILTER                   0x0400feff
+#define STA_RX_FILTER                  0x0000ffff
+
+#define CWIN_SIZE                      0x007f043f
+
+
+#define HWINT_ENABLED                  0x004f0000
+#define HWINT_DISABLED                 0
+
+#define E2P_PWR_INT_GUARD              8
+#define E2P_CHANNEL_COUNT              14
+
+/* If you compare this addresses with the ZYDAS orignal driver, please notify
+ * that we use word mapping for the EEPROM.
+ */
+
+/*
+ * Upper 16 bit contains the regulatory domain.
+ */
+#define E2P_SUBID              E2P_REG(0x00)
+#define E2P_POD                        E2P_REG(0x02)
+#define E2P_MAC_ADDR_P1                E2P_REG(0x04)
+#define E2P_MAC_ADDR_P2                E2P_REG(0x06)
+#define E2P_PWR_CAL_VALUE1     E2P_REG(0x08)
+#define E2P_PWR_CAL_VALUE2     E2P_REG(0x0a)
+#define E2P_PWR_CAL_VALUE3     E2P_REG(0x0c)
+#define E2P_PWR_CAL_VALUE4      E2P_REG(0x0e)
+#define E2P_PWR_INT_VALUE1     E2P_REG(0x10)
+#define E2P_PWR_INT_VALUE2     E2P_REG(0x12)
+#define E2P_PWR_INT_VALUE3     E2P_REG(0x14)
+#define E2P_PWR_INT_VALUE4     E2P_REG(0x16)
+
+/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
+ * also only 11 channels. */
+#define E2P_ALLOWED_CHANNEL    E2P_REG(0x18)
+
+#define E2P_PHY_REG            E2P_REG(0x1a)
+#define E2P_DEVICE_VER         E2P_REG(0x20)
+#define E2P_36M_CAL_VALUE1     E2P_REG(0x28)
+#define E2P_36M_CAL_VALUE2      E2P_REG(0x2a)
+#define E2P_36M_CAL_VALUE3      E2P_REG(0x2c)
+#define E2P_36M_CAL_VALUE4     E2P_REG(0x2e)
+#define E2P_11A_INT_VALUE1     E2P_REG(0x30)
+#define E2P_11A_INT_VALUE2     E2P_REG(0x32)
+#define E2P_11A_INT_VALUE3     E2P_REG(0x34)
+#define E2P_11A_INT_VALUE4     E2P_REG(0x36)
+#define E2P_48M_CAL_VALUE1     E2P_REG(0x38)
+#define E2P_48M_CAL_VALUE2     E2P_REG(0x3a)
+#define E2P_48M_CAL_VALUE3     E2P_REG(0x3c)
+#define E2P_48M_CAL_VALUE4     E2P_REG(0x3e)
+#define E2P_48M_INT_VALUE1     E2P_REG(0x40)
+#define E2P_48M_INT_VALUE2     E2P_REG(0x42)
+#define E2P_48M_INT_VALUE3     E2P_REG(0x44)
+#define E2P_48M_INT_VALUE4     E2P_REG(0x46)
+#define E2P_54M_CAL_VALUE1     E2P_REG(0x48)   /* ??? */
+#define E2P_54M_CAL_VALUE2     E2P_REG(0x4a)
+#define E2P_54M_CAL_VALUE3     E2P_REG(0x4c)
+#define E2P_54M_CAL_VALUE4     E2P_REG(0x4e)
+#define E2P_54M_INT_VALUE1     E2P_REG(0x50)
+#define E2P_54M_INT_VALUE2     E2P_REG(0x52)
+#define E2P_54M_INT_VALUE3     E2P_REG(0x54)
+#define E2P_54M_INT_VALUE4     E2P_REG(0x56)
+
+/* All 16 bit values */
+#define FW_FIRMWARE_VER         FW_REG(0)
+/* non-zero if USB high speed connection */
+#define FW_USB_SPEED            FW_REG(1)
+#define FW_FIX_TX_RATE          FW_REG(2)
+/* Seems to be able to control LEDs over the firmware */
+#define FW_LINK_STATUS          FW_REG(3)
+#define FW_SOFT_RESET           FW_REG(4)
+#define FW_FLASH_CHK            FW_REG(5)
+
+enum {
+       CR_BASE_OFFSET                  = 0x9000,
+       FW_START_OFFSET                 = 0xee00,
+       FW_BASE_ADDR_OFFSET             = FW_START_OFFSET + 0x1d,
+       EEPROM_START_OFFSET             = 0xf800,
+       EEPROM_SIZE                     = 0x800, /* words */
+       LOAD_CODE_SIZE                  = 0xe, /* words */
+       LOAD_VECT_SIZE                  = 0x10000 - 0xfff7, /* words */
+       EEPROM_REGS_OFFSET              = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+       E2P_BASE_OFFSET                 = EEPROM_START_OFFSET +
+                                         EEPROM_REGS_OFFSET,
+};
+
+#define FW_REG_TABLE_ADDR      USB_ADDR(FW_START_OFFSET + 0x1d)
+
+enum {
+       /* indices for ofdm_cal_values */
+       OFDM_36M_INDEX = 0,
+       OFDM_48M_INDEX = 1,
+       OFDM_54M_INDEX = 2,
+};
+
+struct zd_chip {
+       struct zd_usb usb;
+       struct zd_rf rf;
+       struct mutex mutex;
+       u8 e2p_mac[ETH_ALEN];
+       /* EepSetPoint in the vendor driver */
+       u8 pwr_cal_values[E2P_CHANNEL_COUNT];
+       /* integration values in the vendor driver */
+       u8 pwr_int_values[E2P_CHANNEL_COUNT];
+       /* SetPointOFDM in the vendor driver */
+       u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
+       u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+          is_zd1211b:1;
+};
+
+static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
+{
+       return container_of(usb, struct zd_chip, usb);
+}
+
+static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
+{
+       return container_of(rf, struct zd_chip, rf);
+}
+
+#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
+
+void zd_chip_init(struct zd_chip *chip,
+                struct net_device *netdev,
+                struct usb_interface *intf);
+void zd_chip_clear(struct zd_chip *chip);
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
+int zd_chip_reset(struct zd_chip *chip);
+
+static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
+                                     const zd_addr_t *addresses,
+                                     unsigned int count)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_usb_ioread16v(&chip->usb, values, addresses, count);
+}
+
+static inline int zd_ioread16_locked(struct zd_chip *chip, u16 *value,
+                                    const zd_addr_t addr)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_usb_ioread16(&chip->usb, value, addr);
+}
+
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
+                       const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
+                                    const zd_addr_t addr)
+{
+       return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
+}
+
+static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
+                                     zd_addr_t addr)
+{
+       struct zd_ioreq16 ioreq;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       ioreq.addr = addr;
+       ioreq.value = value;
+
+       return zd_usb_iowrite16v(&chip->usb, &ioreq, 1);
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+                         const struct zd_ioreq16 *ioreqs, unsigned int count);
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+                         unsigned int count);
+
+static inline int zd_iowrite32_locked(struct zd_chip *chip, u32 value,
+                                     zd_addr_t addr)
+{
+       struct zd_ioreq32 ioreq;
+
+       ioreq.addr = addr;
+       ioreq.value = value;
+
+       return _zd_iowrite32v_locked(chip, &ioreq, 1);
+}
+
+int zd_iowrite32a_locked(struct zd_chip *chip,
+                        const struct zd_ioreq32 *ioreqs, unsigned int count);
+
+static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
+{
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_usb_rfwrite(&chip->usb, value, bits);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+                      const u32* values, unsigned int count, u8 bits);
+
+/* Locking functions for reading and writing registers.
+ * The different parameters are intentional.
+ */
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value);
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value);
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value);
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value);
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+                 u32 *values, unsigned int count);
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+                  unsigned int count);
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel);
+static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
+{
+       return chip->rf.channel;
+}
+u8  zd_chip_get_channel(struct zd_chip *chip);
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
+int zd_chip_switch_radio_on(struct zd_chip *chip);
+int zd_chip_switch_radio_off(struct zd_chip *chip);
+int zd_chip_enable_int(struct zd_chip *chip);
+void zd_chip_disable_int(struct zd_chip *chip);
+int zd_chip_enable_rx(struct zd_chip *chip);
+void zd_chip_disable_rx(struct zd_chip *chip);
+int zd_chip_enable_hwint(struct zd_chip *chip);
+int zd_chip_disable_hwint(struct zd_chip *chip);
+
+static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
+{
+       return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_set_encryption_type(struct zd_chip *chip, u32 type)
+{
+       return zd_iowrite32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
+{
+       return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
+
+static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
+{
+       return zd_iowrite32(chip, CR_RX_FILTER, filter);
+}
+
+int zd_chip_lock_phy_regs(struct zd_chip *chip);
+int zd_chip_unlock_phy_regs(struct zd_chip *chip);
+
+enum led_status {
+       LED_OFF    = 0,
+       LED_ON     = 1,
+       LED_FLIP   = 2,
+       LED_STATUS = 3,
+};
+
+int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
+int zd_chip_led_flip(struct zd_chip *chip, int led,
+                    const unsigned int *phases_msecs, unsigned int count);
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
+
+static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
+{
+       return zd_ioread32(chip, CR_BCN_INTERVAL, interval);
+}
+
+struct rx_status;
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+                      const struct rx_status *status);
+u8 zd_rx_strength_percent(u8 rssi);
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+
+#endif /* _ZD_CHIP_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
new file mode 100644 (file)
index 0000000..4659068
--- /dev/null
@@ -0,0 +1,48 @@
+/* zd_def.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_DEF_H
+#define _ZD_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#define dev_printk_f(level, dev, fmt, args...) \
+       dev_printk(level, dev, "%s() " fmt, __func__, ##args)
+
+#ifdef DEBUG
+#  define dev_dbg_f(dev, fmt, args...) \
+         dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+#else
+#  define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+#endif /* DEBUG */
+
+#ifdef DEBUG
+#  define ZD_ASSERT(x) \
+do { \
+       if (!(x)) { \
+               pr_debug("%s:%d ASSERT %s VIOLATED!\n", \
+                       __FILE__, __LINE__, __stringify(x)); \
+       } \
+} while (0)
+#else
+#  define ZD_ASSERT(x) do { } while (0)
+#endif
+
+#endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
new file mode 100644 (file)
index 0000000..66905f7
--- /dev/null
@@ -0,0 +1,191 @@
+/* zd_ieee80211.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * A lot of this code is generic and should be moved into the upper layers
+ * at some point.
+ */
+
+#include <linux/errno.h>
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+
+static const struct channel_range channel_ranges[] = {
+       [0]                      = { 0,  0},
+       [ZD_REGDOMAIN_FCC]       = { 1, 12},
+       [ZD_REGDOMAIN_IC]        = { 1, 12},
+       [ZD_REGDOMAIN_ETSI]      = { 1, 14},
+       [ZD_REGDOMAIN_JAPAN]     = { 1, 14},
+       [ZD_REGDOMAIN_SPAIN]     = { 1, 14},
+       [ZD_REGDOMAIN_FRANCE]    = { 1, 14},
+       [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
+};
+
+const struct channel_range *zd_channel_range(u8 regdomain)
+{
+       if (regdomain >= ARRAY_SIZE(channel_ranges))
+               regdomain = 0;
+       return &channel_ranges[regdomain];
+}
+
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
+{
+       const struct channel_range *range = zd_channel_range(regdomain);
+       return range->start <= channel && channel < range->end;
+}
+
+int zd_regdomain_supported(u8 regdomain)
+{
+       const struct channel_range *range = zd_channel_range(regdomain);
+       return range->start != 0;
+}
+
+/* Stores channel frequencies in MHz. */
+static const u16 channel_frequencies[] = {
+       2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+       2452, 2457, 2462, 2467, 2472, 2484,
+};
+
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
+
+static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
+{
+       u32 factor;
+
+       freq->e = 0;
+       if (mhz >= 1000000000U) {
+               pr_debug("zd1211 mhz %u to large\n", mhz);
+               freq->m = 0;
+               return -EINVAL;
+       }
+
+       factor = 1000;
+       while (mhz >= factor) {
+
+               freq->e += 1;
+               factor *= 10;
+       }
+
+       factor /= 1000U;
+       freq->m = mhz * (1000000U/factor) + hz/factor;
+
+       return 0;
+}
+
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
+{
+       if (channel > NUM_CHANNELS) {
+               freq->m = 0;
+               freq->e = 0;
+               return -EINVAL;
+       }
+       if (!channel) {
+               freq->m = 0;
+               freq->e = 0;
+               return -EINVAL;
+       }
+       return compute_freq(freq, channel_frequencies[channel-1], 0);
+}
+
+static int freq_to_mhz(const struct iw_freq *freq)
+{
+       u32 factor;
+       int e;
+
+       /* Such high frequencies are not supported. */
+       if (freq->e > 6)
+               return -EINVAL;
+
+       factor = 1;
+       for (e = freq->e; e > 0; --e) {
+               factor *= 10;
+       }
+       factor = 1000000U / factor;
+
+       if (freq->m % factor) {
+               return -EINVAL;
+       }
+
+       return freq->m / factor;
+}
+
+int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+{
+       int i, r;
+       u32 mhz;
+
+       if (!(freq->flags & IW_FREQ_FIXED))
+               return 0;
+
+       if (freq->m < 1000) {
+               if (freq->m  > NUM_CHANNELS || freq->m == 0)
+                       return -EINVAL;
+               *channel = freq->m;
+               return 1;
+       }
+
+       r = freq_to_mhz(freq);
+       if (r < 0)
+               return r;
+       mhz = r;
+
+       for (i = 0; i < NUM_CHANNELS; i++) {
+               if (mhz == channel_frequencies[i]) {
+                       *channel = i+1;
+                       return 1;
+               }
+       }
+
+       return -EINVAL;
+}
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+{
+       struct ieee80211_geo geo;
+       const struct channel_range *range;
+       int i;
+       u8 channel;
+
+       dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+               "regdomain %#04x\n", regdomain);
+
+       range = zd_channel_range(regdomain);
+       if (range->start == 0) {
+               dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+                       "zd1211 regdomain %#04x not supported\n",
+                       regdomain);
+               return -EINVAL;
+       }
+
+       memset(&geo, 0, sizeof(geo));
+
+       for (i = 0, channel = range->start; channel < range->end; channel++) {
+               struct ieee80211_channel *chan = &geo.bg[i++];
+               chan->freq = channel_frequencies[channel - 1];
+               chan->channel = channel;
+       }
+
+       geo.bg_channels = i;
+       memcpy(geo.name, "XX ", 4);
+       ieee80211_set_geo(ieee, &geo);
+       return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
new file mode 100644 (file)
index 0000000..3632989
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef _ZD_IEEE80211_H
+#define _ZD_IEEE80211_H
+
+#include <net/ieee80211.h>
+#include "zd_types.h"
+
+/* Additional definitions from the standards.
+ */
+
+#define ZD_REGDOMAIN_FCC       0x10
+#define ZD_REGDOMAIN_IC                0x20
+#define ZD_REGDOMAIN_ETSI      0x30
+#define ZD_REGDOMAIN_SPAIN     0x31
+#define ZD_REGDOMAIN_FRANCE    0x32
+#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN     0x41
+
+enum {
+       MIN_CHANNEL24 = 1,
+       MAX_CHANNEL24 = 14,
+};
+
+struct channel_range {
+       u8 start;
+       u8 end; /* exclusive (channel must be less than end) */
+};
+
+struct iw_freq;
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
+
+const struct channel_range *zd_channel_range(u8 regdomain);
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
+int zd_regdomain_supported(u8 regdomain);
+
+/* for 2.4 GHz band */
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
+int zd_find_channel(u8 *channel, const struct iw_freq *freq);
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+       u8 prefix[3];
+       __le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(
+       const struct ofdm_plcp_header *header)
+{
+       return header->prefix[0] & 0xf;
+}
+
+#define ZD_OFDM_RATE_6M                0xb
+#define ZD_OFDM_RATE_9M                0xf
+#define ZD_OFDM_RATE_12M       0xa
+#define ZD_OFDM_RATE_18M       0xe
+#define ZD_OFDM_RATE_24M       0x9
+#define ZD_OFDM_RATE_36M       0xd
+#define ZD_OFDM_RATE_48M       0x8
+#define ZD_OFDM_RATE_54M       0xc
+
+struct cck_plcp_header {
+       u8 signal;
+       u8 service;
+       __le16 length;
+       __le16 crc16;
+} __attribute__((packed));
+
+static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+{
+       return header->signal;
+}
+
+#define ZD_CCK_SIGNAL_1M       0x0a
+#define ZD_CCK_SIGNAL_2M       0x14
+#define ZD_CCK_SIGNAL_5M5      0x37
+#define ZD_CCK_SIGNAL_11M      0x6e
+
+enum ieee80211_std {
+       IEEE80211B = 0x01,
+       IEEE80211A = 0x02,
+       IEEE80211G = 0x04,
+};
+
+#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
new file mode 100644 (file)
index 0000000..3bdc54d
--- /dev/null
@@ -0,0 +1,1057 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/usb.h>
+#include <linux/jiffies.h>
+#include <net/ieee80211_radiotap.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+#include "zd_netdev.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+static void ieee_init(struct ieee80211_device *ieee);
+static void softmac_init(struct ieee80211softmac_device *sm);
+
+int zd_mac_init(struct zd_mac *mac,
+               struct net_device *netdev,
+               struct usb_interface *intf)
+{
+       struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+
+       memset(mac, 0, sizeof(*mac));
+       spin_lock_init(&mac->lock);
+       mac->netdev = netdev;
+
+       ieee_init(ieee);
+       softmac_init(ieee80211_priv(netdev));
+       zd_chip_init(&mac->chip, netdev, intf);
+       return 0;
+}
+
+static int reset_channel(struct zd_mac *mac)
+{
+       int r;
+       unsigned long flags;
+       const struct channel_range *range;
+
+       spin_lock_irqsave(&mac->lock, flags);
+       range = zd_channel_range(mac->regdomain);
+       if (!range->start) {
+               r = -EINVAL;
+               goto out;
+       }
+       mac->requested_channel = range->start;
+       r = 0;
+out:
+       spin_unlock_irqrestore(&mac->lock, flags);
+       return r;
+}
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
+{
+       int r;
+       struct zd_chip *chip = &mac->chip;
+       u8 addr[ETH_ALEN];
+       u8 default_regdomain;
+
+       r = zd_chip_enable_int(chip);
+       if (r)
+               goto out;
+       r = zd_chip_init_hw(chip, device_type);
+       if (r)
+               goto disable_int;
+
+       zd_get_e2p_mac_addr(chip, addr);
+       r = zd_write_mac_addr(chip, addr);
+       if (r)
+               goto disable_int;
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&mac->lock);
+       memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+       spin_unlock_irq(&mac->lock);
+
+       r = zd_read_regdomain(chip, &default_regdomain);
+       if (r)
+               goto disable_int;
+       if (!zd_regdomain_supported(default_regdomain)) {
+               dev_dbg_f(zd_mac_dev(mac),
+                         "Regulatory Domain %#04x is not supported.\n",
+                         default_regdomain);
+               r = -EINVAL;
+               goto disable_int;
+       }
+       spin_lock_irq(&mac->lock);
+       mac->regdomain = mac->default_regdomain = default_regdomain;
+       spin_unlock_irq(&mac->lock);
+       r = reset_channel(mac);
+       if (r)
+               goto disable_int;
+
+       r = zd_set_encryption_type(chip, NO_WEP);
+       if (r)
+               goto disable_int;
+
+       r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
+       if (r)
+               goto disable_int;
+
+       r = 0;
+disable_int:
+       zd_chip_disable_int(chip);
+out:
+       return r;
+}
+
+void zd_mac_clear(struct zd_mac *mac)
+{
+       /* Aquire the lock. */
+       spin_lock(&mac->lock);
+       spin_unlock(&mac->lock);
+       zd_chip_clear(&mac->chip);
+       memset(mac, 0, sizeof(*mac));
+}
+
+static int reset_mode(struct zd_mac *mac)
+{
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+       struct zd_ioreq32 ioreqs[3] = {
+               { CR_RX_FILTER, RX_FILTER_BEACON|RX_FILTER_PROBE_RESPONSE|
+                               RX_FILTER_AUTH|RX_FILTER_ASSOC_RESPONSE },
+               { CR_SNIFFER_ON, 0U },
+               { CR_ENCRYPTION_TYPE, NO_WEP },
+       };
+
+       if (ieee->iw_mode == IW_MODE_MONITOR) {
+               ioreqs[0].value = 0xffffffff;
+               ioreqs[1].value = 0x1;
+               ioreqs[2].value = ENC_SNIFFER;
+       }
+
+       return zd_iowrite32a(&mac->chip, ioreqs, 3);
+}
+
+int zd_mac_open(struct net_device *netdev)
+{
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct zd_chip *chip = &mac->chip;
+       int r;
+
+       r = zd_chip_enable_int(chip);
+       if (r < 0)
+               goto out;
+
+       r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
+       if (r < 0)
+               goto disable_int;
+       r = reset_mode(mac);
+       if (r)
+               goto disable_int;
+       r = zd_chip_switch_radio_on(chip);
+       if (r < 0)
+               goto disable_int;
+       r = zd_chip_set_channel(chip, mac->requested_channel);
+       if (r < 0)
+               goto disable_radio;
+       r = zd_chip_enable_rx(chip);
+       if (r < 0)
+               goto disable_radio;
+       r = zd_chip_enable_hwint(chip);
+       if (r < 0)
+               goto disable_rx;
+
+       ieee80211softmac_start(netdev);
+       return 0;
+disable_rx:
+       zd_chip_disable_rx(chip);
+disable_radio:
+       zd_chip_switch_radio_off(chip);
+disable_int:
+       zd_chip_disable_int(chip);
+out:
+       return r;
+}
+
+int zd_mac_stop(struct net_device *netdev)
+{
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct zd_chip *chip = &mac->chip;
+
+       netif_stop_queue(netdev);
+
+       /*
+        * The order here deliberately is a little different from the open()
+        * method, since we need to make sure there is no opportunity for RX
+        * frames to be processed by softmac after we have stopped it.
+        */
+
+       zd_chip_disable_rx(chip);
+       ieee80211softmac_stop(netdev);
+
+       zd_chip_disable_hwint(chip);
+       zd_chip_switch_radio_off(chip);
+       zd_chip_disable_int(chip);
+
+       return 0;
+}
+
+int zd_mac_set_mac_address(struct net_device *netdev, void *p)
+{
+       int r;
+       unsigned long flags;
+       struct sockaddr *addr = p;
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct zd_chip *chip = &mac->chip;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       dev_dbg_f(zd_mac_dev(mac),
+                 "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+
+       r = zd_write_mac_addr(chip, addr->sa_data);
+       if (r)
+               return r;
+
+       spin_lock_irqsave(&mac->lock, flags);
+       memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
+       spin_unlock_irqrestore(&mac->lock, flags);
+
+       return 0;
+}
+
+int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
+{
+       int r;
+       u8 channel;
+
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&mac->lock);
+       if (regdomain == 0) {
+               regdomain = mac->default_regdomain;
+       }
+       if (!zd_regdomain_supported(regdomain)) {
+               spin_unlock_irq(&mac->lock);
+               return -EINVAL;
+       }
+       mac->regdomain = regdomain;
+       channel = mac->requested_channel;
+       spin_unlock_irq(&mac->lock);
+
+       r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);
+       if (r)
+               return r;
+       if (!zd_regdomain_supports_channel(regdomain, channel)) {
+               r = reset_channel(mac);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
+u8 zd_mac_get_regdomain(struct zd_mac *mac)
+{
+       unsigned long flags;
+       u8 regdomain;
+
+       spin_lock_irqsave(&mac->lock, flags);
+       regdomain = mac->regdomain;
+       spin_unlock_irqrestore(&mac->lock, flags);
+       return regdomain;
+}
+
+static void set_channel(struct net_device *netdev, u8 channel)
+{
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+
+       dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);
+
+       zd_chip_set_channel(&mac->chip, channel);
+}
+
+/* TODO: Should not work in Managed mode. */
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel)
+{
+       unsigned long lock_flags;
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+       if (ieee->iw_mode == IW_MODE_INFRA)
+               return -EPERM;
+
+       spin_lock_irqsave(&mac->lock, lock_flags);
+       if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {
+               spin_unlock_irqrestore(&mac->lock, lock_flags);
+               return -EINVAL;
+       }
+       mac->requested_channel = channel;
+       spin_unlock_irqrestore(&mac->lock, lock_flags);
+       if (netif_running(mac->netdev))
+               return zd_chip_set_channel(&mac->chip, channel);
+       else
+               return 0;
+}
+
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags)
+{
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+       *channel = zd_chip_get_channel(&mac->chip);
+       if (ieee->iw_mode != IW_MODE_INFRA) {
+               spin_lock_irq(&mac->lock);
+               *flags = *channel == mac->requested_channel ?
+                       MAC_FIXED_CHANNEL : 0;
+               spin_unlock(&mac->lock);
+       } else {
+               *flags = 0;
+       }
+       dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags);
+       return 0;
+}
+
+/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
+static u8 cs_typed_rate(u8 cs_rate)
+{
+       static const u8 typed_rates[16] = {
+               [ZD_CS_CCK_RATE_1M]     = ZD_CS_CCK|ZD_CS_CCK_RATE_1M,
+               [ZD_CS_CCK_RATE_2M]     = ZD_CS_CCK|ZD_CS_CCK_RATE_2M,
+               [ZD_CS_CCK_RATE_5_5M]   = ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M,
+               [ZD_CS_CCK_RATE_11M]    = ZD_CS_CCK|ZD_CS_CCK_RATE_11M,
+               [ZD_OFDM_RATE_6M]       = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
+               [ZD_OFDM_RATE_9M]       = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
+               [ZD_OFDM_RATE_12M]      = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
+               [ZD_OFDM_RATE_18M]      = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
+               [ZD_OFDM_RATE_24M]      = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
+               [ZD_OFDM_RATE_36M]      = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
+               [ZD_OFDM_RATE_48M]      = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
+               [ZD_OFDM_RATE_54M]      = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
+       };
+
+       ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
+       return typed_rates[cs_rate & ZD_CS_RATE_MASK];
+}
+
+/* Fallback to lowest rate, if rate is unknown. */
+static u8 rate_to_cs_rate(u8 rate)
+{
+       switch (rate) {
+       case IEEE80211_CCK_RATE_2MB:
+               return ZD_CS_CCK_RATE_2M;
+       case IEEE80211_CCK_RATE_5MB:
+               return ZD_CS_CCK_RATE_5_5M;
+       case IEEE80211_CCK_RATE_11MB:
+               return ZD_CS_CCK_RATE_11M;
+       case IEEE80211_OFDM_RATE_6MB:
+               return ZD_OFDM_RATE_6M;
+       case IEEE80211_OFDM_RATE_9MB:
+               return ZD_OFDM_RATE_9M;
+       case IEEE80211_OFDM_RATE_12MB:
+               return ZD_OFDM_RATE_12M;
+       case IEEE80211_OFDM_RATE_18MB:
+               return ZD_OFDM_RATE_18M;
+       case IEEE80211_OFDM_RATE_24MB:
+               return ZD_OFDM_RATE_24M;
+       case IEEE80211_OFDM_RATE_36MB:
+               return ZD_OFDM_RATE_36M;
+       case IEEE80211_OFDM_RATE_48MB:
+               return ZD_OFDM_RATE_48M;
+       case IEEE80211_OFDM_RATE_54MB:
+               return ZD_OFDM_RATE_54M;
+       }
+       return ZD_CS_CCK_RATE_1M;
+}
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
+{
+       struct ieee80211_device *ieee;
+
+       switch (mode) {
+       case IW_MODE_AUTO:
+       case IW_MODE_ADHOC:
+       case IW_MODE_INFRA:
+               mac->netdev->type = ARPHRD_ETHER;
+               break;
+       case IW_MODE_MONITOR:
+               mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+               break;
+       default:
+               dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);
+               return -EINVAL;
+       }
+
+       ieee = zd_mac_to_ieee80211(mac);
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&ieee->lock);
+       ieee->iw_mode = mode;
+       spin_unlock_irq(&ieee->lock);
+
+       if (netif_running(mac->netdev))
+               return reset_mode(mac);
+
+       return 0;
+}
+
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode)
+{
+       unsigned long flags;
+       struct ieee80211_device *ieee;
+
+       ieee = zd_mac_to_ieee80211(mac);
+       spin_lock_irqsave(&ieee->lock, flags);
+       *mode = ieee->iw_mode;
+       spin_unlock_irqrestore(&ieee->lock, flags);
+       return 0;
+}
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
+{
+       int i;
+       const struct channel_range *channel_range;
+       u8 regdomain;
+
+       memset(range, 0, sizeof(*range));
+
+       /* FIXME: Not so important and depends on the mode. For 802.11g
+        * usually this value is used. It seems to be that Bit/s number is
+        * given here.
+        */
+       range->throughput = 27 * 1000 * 1000;
+
+       range->max_qual.qual = 100;
+       range->max_qual.level = 100;
+
+       /* FIXME: Needs still to be tuned. */
+       range->avg_qual.qual = 71;
+       range->avg_qual.level = 80;
+
+       /* FIXME: depends on standard? */
+       range->min_rts = 256;
+       range->max_rts = 2346;
+
+       range->min_frag = MIN_FRAG_THRESHOLD;
+       range->max_frag = MAX_FRAG_THRESHOLD;
+
+       range->max_encoding_tokens = WEP_KEYS;
+       range->num_encoding_sizes = 2;
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = WEP_KEY_LEN;
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 20;
+
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&mac->lock);
+       regdomain = mac->regdomain;
+       spin_unlock_irq(&mac->lock);
+       channel_range = zd_channel_range(regdomain);
+
+       range->num_channels = channel_range->end - channel_range->start;
+       range->old_num_channels = range->num_channels;
+       range->num_frequency = range->num_channels;
+       range->old_num_frequency = range->num_frequency;
+
+       for (i = 0; i < range->num_frequency; i++) {
+               struct iw_freq *freq = &range->freq[i];
+               freq->i = channel_range->start + i;
+               zd_channel_to_freq(freq, freq->i);
+       }
+
+       return 0;
+}
+
+static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length)
+{
+       static const u8 rate_divisor[] = {
+               [ZD_CS_CCK_RATE_1M]     =  1,
+               [ZD_CS_CCK_RATE_2M]     =  2,
+               [ZD_CS_CCK_RATE_5_5M]   = 11, /* bits must be doubled */
+               [ZD_CS_CCK_RATE_11M]    = 11,
+               [ZD_OFDM_RATE_6M]       =  6,
+               [ZD_OFDM_RATE_9M]       =  9,
+               [ZD_OFDM_RATE_12M]      = 12,
+               [ZD_OFDM_RATE_18M]      = 18,
+               [ZD_OFDM_RATE_24M]      = 24,
+               [ZD_OFDM_RATE_36M]      = 36,
+               [ZD_OFDM_RATE_48M]      = 48,
+               [ZD_OFDM_RATE_54M]      = 54,
+       };
+
+       u32 bits = (u32)tx_length * 8;
+       u32 divisor;
+
+       divisor = rate_divisor[cs_rate];
+       if (divisor == 0)
+               return -EINVAL;
+
+       switch (cs_rate) {
+       case ZD_CS_CCK_RATE_5_5M:
+               bits = (2*bits) + 10; /* round up to the next integer */
+               break;
+       case ZD_CS_CCK_RATE_11M:
+               if (service) {
+                       u32 t = bits % 11;
+                       *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+                       if (0 < t && t <= 3) {
+                               *service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+                       }
+               }
+               bits += 10; /* round up to the next integer */
+               break;
+       }
+
+       return bits/divisor;
+}
+
+enum {
+       R2M_SHORT_PREAMBLE = 0x01,
+       R2M_11A            = 0x02,
+};
+
+static u8 cs_rate_to_modulation(u8 cs_rate, int flags)
+{
+       u8 modulation;
+
+       modulation = cs_typed_rate(cs_rate);
+       if (flags & R2M_SHORT_PREAMBLE) {
+               switch (ZD_CS_RATE(modulation)) {
+               case ZD_CS_CCK_RATE_2M:
+               case ZD_CS_CCK_RATE_5_5M:
+               case ZD_CS_CCK_RATE_11M:
+                       modulation |= ZD_CS_CCK_PREA_SHORT;
+                       return modulation;
+               }
+       }
+       if (flags & R2M_11A) {
+               if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
+                       modulation |= ZD_CS_OFDM_MODE_11A;
+       }
+       return modulation;
+}
+
+static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
+                             struct ieee80211_hdr_4addr *hdr)
+{
+       struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
+       u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
+       u8 rate, cs_rate;
+       int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
+
+       /* FIXME: 802.11a? short preamble? */
+       rate = ieee80211softmac_suggest_txrate(softmac,
+               is_multicast_ether_addr(hdr->addr1), is_mgt);
+
+       cs_rate = rate_to_cs_rate(rate);
+       cs->modulation = cs_rate_to_modulation(cs_rate, 0);
+}
+
+static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
+                          struct ieee80211_hdr_4addr *header)
+{
+       unsigned int tx_length = le16_to_cpu(cs->tx_length);
+       u16 fctl = le16_to_cpu(header->frame_ctl);
+       u16 ftype = WLAN_FC_GET_TYPE(fctl);
+       u16 stype = WLAN_FC_GET_STYPE(fctl);
+
+       /*
+        * CONTROL:
+        * - start at 0x00
+        * - if fragment 0, enable bit 0
+        * - if backoff needed, enable bit 0
+        * - if burst (backoff not needed) disable bit 0
+        * - if multicast, enable bit 1
+        * - if PS-POLL frame, enable bit 2
+        * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable
+        *   bit 4 (FIXME: wtf)
+        * - if frag_len > RTS threshold, set bit 5 as long if it isnt
+        *   multicast or mgt
+        * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit
+        *   7
+        */
+
+       cs->control = 0;
+
+       /* First fragment */
+       if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0)
+               cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
+
+       /* Multicast */
+       if (is_multicast_ether_addr(header->addr1))
+               cs->control |= ZD_CS_MULTICAST;
+
+       /* PS-POLL */
+       if (stype == IEEE80211_STYPE_PSPOLL)
+               cs->control |= ZD_CS_PS_POLL_FRAME;
+
+       if (!is_multicast_ether_addr(header->addr1) &&
+           ftype != IEEE80211_FTYPE_MGMT &&
+           tx_length > zd_netdev_ieee80211(mac->netdev)->rts)
+       {
+               /* FIXME: check the logic */
+               if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) {
+                       /* 802.11g */
+                       cs->control |= ZD_CS_SELF_CTS;
+               } else { /* 802.11b */
+                       cs->control |= ZD_CS_RTS;
+               }
+       }
+
+       /* FIXME: Management frame? */
+}
+
+static int fill_ctrlset(struct zd_mac *mac,
+                       struct ieee80211_txb *txb,
+                       int frag_num)
+{
+       int r;
+       struct sk_buff *skb = txb->fragments[frag_num];
+       struct ieee80211_hdr_4addr *hdr =
+               (struct ieee80211_hdr_4addr *) skb->data;
+       unsigned int frag_len = skb->len + IEEE80211_FCS_LEN;
+       unsigned int next_frag_len;
+       unsigned int packet_length;
+       struct zd_ctrlset *cs = (struct zd_ctrlset *)
+               skb_push(skb, sizeof(struct zd_ctrlset));
+
+       if (frag_num+1  < txb->nr_frags) {
+               next_frag_len = txb->fragments[frag_num+1]->len +
+                               IEEE80211_FCS_LEN;
+       } else {
+               next_frag_len = 0;
+       }
+       ZD_ASSERT(frag_len <= 0xffff);
+       ZD_ASSERT(next_frag_len <= 0xffff);
+
+       cs_set_modulation(mac, cs, hdr);
+
+       cs->tx_length = cpu_to_le16(frag_len);
+
+       cs_set_control(mac, cs, hdr);
+
+       packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
+       ZD_ASSERT(packet_length <= 0xffff);
+       /* ZD1211B: Computing the length difference this way, gives us
+        * flexibility to compute the packet length.
+        */
+       cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ?
+                       packet_length - frag_len : packet_length);
+
+       /*
+        * CURRENT LENGTH:
+        * - transmit frame length in microseconds
+        * - seems to be derived from frame length
+        * - see Cal_Us_Service() in zdinlinef.h
+        * - if macp->bTxBurstEnable is enabled, then multiply by 4
+        *  - bTxBurstEnable is never set in the vendor driver
+        *
+        * SERVICE:
+        * - "for PLCP configuration"
+        * - always 0 except in some situations at 802.11b 11M
+        * - see line 53 of zdinlinef.h
+        */
+       cs->service = 0;
+       r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+                                le16_to_cpu(cs->tx_length));
+       if (r < 0)
+               return r;
+       cs->current_length = cpu_to_le16(r);
+
+       if (next_frag_len == 0) {
+               cs->next_frame_length = 0;
+       } else {
+               r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+                                        next_frag_len);
+               if (r < 0)
+                       return r;
+               cs->next_frame_length = cpu_to_le16(r);
+       }
+
+       return 0;
+}
+
+static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
+{
+       int i, r;
+
+       for (i = 0; i < txb->nr_frags; i++) {
+               struct sk_buff *skb = txb->fragments[i];
+
+               r = fill_ctrlset(mac, txb, i);
+               if (r)
+                       return r;
+               r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
+               if (r)
+                       return r;
+       }
+
+       /* FIXME: shouldn't this be handled by the upper layers? */
+       mac->netdev->trans_start = jiffies;
+
+       ieee80211_txb_free(txb);
+       return 0;
+}
+
+struct zd_rt_hdr {
+       struct ieee80211_radiotap_header rt_hdr;
+       u8  rt_flags;
+       u16 rt_channel;
+       u16 rt_chbitmask;
+       u16 rt_rate;
+};
+
+static void fill_rt_header(void *buffer, struct zd_mac *mac,
+                          const struct ieee80211_rx_stats *stats,
+                          const struct rx_status *status)
+{
+       struct zd_rt_hdr *hdr = buffer;
+
+       hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+       hdr->rt_hdr.it_pad = 0;
+       hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr));
+       hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+                                (1 << IEEE80211_RADIOTAP_CHANNEL) |
+                                (1 << IEEE80211_RADIOTAP_RATE));
+
+       hdr->rt_flags = 0;
+       if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
+               hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+       /* FIXME: 802.11a */
+       hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
+                                            _zd_chip_get_channel(&mac->chip)));
+       hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
+               ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
+               ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
+
+       hdr->rt_rate = stats->rate / 5;
+}
+
+/* Returns 1 if the data packet is for us and 0 otherwise. */
+static int is_data_packet_for_us(struct ieee80211_device *ieee,
+                                struct ieee80211_hdr_4addr *hdr)
+{
+       struct net_device *netdev = ieee->dev;
+       u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+       ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA);
+
+       switch (ieee->iw_mode) {
+       case IW_MODE_ADHOC:
+               if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
+                   memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+                       return 0;
+               break;
+       case IW_MODE_AUTO:
+       case IW_MODE_INFRA:
+               if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
+                   IEEE80211_FCTL_FROMDS ||
+                   memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+                       return 0;
+               break;
+       default:
+               ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR);
+               return 0;
+       }
+
+       return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+              is_multicast_ether_addr(hdr->addr1) ||
+              (netdev->flags & IFF_PROMISC);
+}
+
+/* Filters receiving packets. If it returns 1 send it to ieee80211_rx, if 0
+ * return. If an error is detected -EINVAL is returned. ieee80211_rx_mgt() is
+ * called here.
+ *
+ * It has been based on ieee80211_rx_any.
+ */
+static int filter_rx(struct ieee80211_device *ieee,
+                    const u8 *buffer, unsigned int length,
+                    struct ieee80211_rx_stats *stats)
+{
+       struct ieee80211_hdr_4addr *hdr;
+       u16 fc;
+
+       if (ieee->iw_mode == IW_MODE_MONITOR)
+               return 1;
+
+       hdr = (struct ieee80211_hdr_4addr *)buffer;
+       fc = le16_to_cpu(hdr->frame_ctl);
+       if ((fc & IEEE80211_FCTL_VERS) != 0)
+               return -EINVAL;
+
+       switch (WLAN_FC_GET_TYPE(fc)) {
+       case IEEE80211_FTYPE_MGMT:
+               if (length < sizeof(struct ieee80211_hdr_3addr))
+                       return -EINVAL;
+               ieee80211_rx_mgt(ieee, hdr, stats);
+               return 0;
+       case IEEE80211_FTYPE_CTL:
+               /* Ignore invalid short buffers */
+               return 0;
+       case IEEE80211_FTYPE_DATA:
+               if (length < sizeof(struct ieee80211_hdr_3addr))
+                       return -EINVAL;
+               return is_data_packet_for_us(ieee, hdr);
+       }
+
+       return -EINVAL;
+}
+
+static void update_qual_rssi(struct zd_mac *mac, u8 qual_percent, u8 rssi)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&mac->lock, flags);
+       mac->qual_average = (7 * mac->qual_average + qual_percent) / 8;
+       mac->rssi_average = (7 * mac->rssi_average + rssi) / 8;
+       spin_unlock_irqrestore(&mac->lock, flags);
+}
+
+static int fill_rx_stats(struct ieee80211_rx_stats *stats,
+                        const struct rx_status **pstatus,
+                        struct zd_mac *mac,
+                        const u8 *buffer, unsigned int length)
+{
+       const struct rx_status *status;
+
+       *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+       if (status->frame_status & ZD_RX_ERROR) {
+               /* FIXME: update? */
+               return -EINVAL;
+       }
+       memset(stats, 0, sizeof(struct ieee80211_rx_stats));
+       stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
+                              + sizeof(struct rx_status));
+       /* FIXME: 802.11a */
+       stats->freq = IEEE80211_24GHZ_BAND;
+       stats->received_channel = _zd_chip_get_channel(&mac->chip);
+       stats->rssi = zd_rx_strength_percent(status->signal_strength);
+       stats->signal = zd_rx_qual_percent(buffer,
+                                         length - sizeof(struct rx_status),
+                                         status);
+       stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL;
+       stats->rate = zd_rx_rate(buffer, status);
+       if (stats->rate)
+               stats->mask |= IEEE80211_STATMASK_RATE;
+
+       update_qual_rssi(mac, stats->signal, stats->rssi);
+       return 0;
+}
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+       int r;
+       struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+       struct ieee80211_rx_stats stats;
+       const struct rx_status *status;
+       struct sk_buff *skb;
+
+       if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+                    IEEE80211_FCS_LEN + sizeof(struct rx_status))
+               return -EINVAL;
+
+       r = fill_rx_stats(&stats, &status, mac, buffer, length);
+       if (r)
+               return r;
+
+       length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
+                 sizeof(struct rx_status);
+       buffer += ZD_PLCP_HEADER_SIZE;
+
+       r = filter_rx(ieee, buffer, length, &stats);
+       if (r <= 0)
+               return r;
+
+       skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+       if (!skb)
+               return -ENOMEM;
+       if (ieee->iw_mode == IW_MODE_MONITOR)
+               fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+                              &stats, status);
+       memcpy(skb_put(skb, length), buffer, length);
+
+       r = ieee80211_rx(ieee, skb, &stats);
+       if (!r) {
+               ZD_ASSERT(in_irq());
+               dev_kfree_skb_irq(skb);
+       }
+       return 0;
+}
+
+static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev,
+                    int pri)
+{
+       return zd_mac_tx(zd_netdev_mac(netdev), txb, pri);
+}
+
+static void set_security(struct net_device *netdev,
+                        struct ieee80211_security *sec)
+{
+       struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+       struct ieee80211_security *secinfo = &ieee->sec;
+       int keyidx;
+
+       dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+
+       for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+               if (sec->flags & (1<<keyidx)) {
+                       secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+                       secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+                       memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
+                              SCM_KEY_LEN);
+               }
+
+       if (sec->flags & SEC_ACTIVE_KEY) {
+               secinfo->active_key = sec->active_key;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .active_key = %d\n", sec->active_key);
+       }
+       if (sec->flags & SEC_UNICAST_GROUP) {
+               secinfo->unicast_uses_group = sec->unicast_uses_group;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .unicast_uses_group = %d\n",
+                       sec->unicast_uses_group);
+       }
+       if (sec->flags & SEC_LEVEL) {
+               secinfo->level = sec->level;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .level = %d\n", sec->level);
+       }
+       if (sec->flags & SEC_ENABLED) {
+               secinfo->enabled = sec->enabled;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .enabled = %d\n", sec->enabled);
+       }
+       if (sec->flags & SEC_ENCRYPT) {
+               secinfo->encrypt = sec->encrypt;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .encrypt = %d\n", sec->encrypt);
+       }
+       if (sec->flags & SEC_AUTH_MODE) {
+               secinfo->auth_mode = sec->auth_mode;
+               dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+                       "   .auth_mode = %d\n", sec->auth_mode);
+       }
+}
+
+static void ieee_init(struct ieee80211_device *ieee)
+{
+       ieee->mode = IEEE_B | IEEE_G;
+       ieee->freq_band = IEEE80211_24GHZ_BAND;
+       ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION;
+       ieee->tx_headroom = sizeof(struct zd_ctrlset);
+       ieee->set_security = set_security;
+       ieee->hard_start_xmit = netdev_tx;
+
+       /* Software encryption/decryption for now */
+       ieee->host_build_iv = 0;
+       ieee->host_encrypt = 1;
+       ieee->host_decrypt = 1;
+
+       /* FIXME: default to managed mode, until ieee80211 and zd1211rw can
+        * correctly support AUTO */
+       ieee->iw_mode = IW_MODE_INFRA;
+}
+
+static void softmac_init(struct ieee80211softmac_device *sm)
+{
+       sm->set_channel = set_channel;
+}
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
+{
+       struct zd_mac *mac = zd_netdev_mac(ndev);
+       struct iw_statistics *iw_stats = &mac->iw_stats;
+
+       memset(iw_stats, 0, sizeof(struct iw_statistics));
+       /* We are not setting the status, because ieee->state is not updated
+        * at all and this driver doesn't track authentication state.
+        */
+       spin_lock_irq(&mac->lock);
+       iw_stats->qual.qual = mac->qual_average;
+       iw_stats->qual.level = mac->rssi_average;
+       iw_stats->qual.updated = IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED|
+                                IW_QUAL_NOISE_INVALID;
+       spin_unlock_irq(&mac->lock);
+       /* TODO: update counter */
+       return iw_stats;
+}
+
+#ifdef DEBUG
+static const char* decryption_types[] = {
+       [ZD_RX_NO_WEP] = "none",
+       [ZD_RX_WEP64] = "WEP64",
+       [ZD_RX_TKIP] = "TKIP",
+       [ZD_RX_AES] = "AES",
+       [ZD_RX_WEP128] = "WEP128",
+       [ZD_RX_WEP256] = "WEP256",
+};
+
+static const char *decryption_type_string(u8 type)
+{
+       const char *s;
+
+       if (type < ARRAY_SIZE(decryption_types)) {
+               s = decryption_types[type];
+       } else {
+               s = NULL;
+       }
+       return s ? s : "unknown";
+}
+
+static int is_ofdm(u8 frame_status)
+{
+       return (frame_status & ZD_RX_OFDM);
+}
+
+void zd_dump_rx_status(const struct rx_status *status)
+{
+       const char* modulation;
+       u8 quality;
+
+       if (is_ofdm(status->frame_status)) {
+               modulation = "ofdm";
+               quality = status->signal_quality_ofdm;
+       } else {
+               modulation = "cck";
+               quality = status->signal_quality_cck;
+       }
+       pr_debug("rx status %s strength %#04x qual %#04x decryption %s\n",
+               modulation, status->signal_strength, quality,
+               decryption_type_string(status->decryption_type));
+       if (status->frame_status & ZD_RX_ERROR) {
+               pr_debug("rx error %s%s%s%s%s%s\n",
+                       (status->frame_status & ZD_RX_TIMEOUT_ERROR) ?
+                               "timeout " : "",
+                       (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ?
+                               "fifo " : "",
+                       (status->frame_status & ZD_RX_DECRYPTION_ERROR) ?
+                               "decryption " : "",
+                       (status->frame_status & ZD_RX_CRC32_ERROR) ?
+                               "crc32 " : "",
+                       (status->frame_status & ZD_RX_NO_ADDR1_MATCH_ERROR) ?
+                               "addr1 " : "",
+                       (status->frame_status & ZD_RX_CRC16_ERROR) ?
+                               "crc16" : "");
+       }
+}
+#endif /* DEBUG */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
new file mode 100644 (file)
index 0000000..71e382c
--- /dev/null
@@ -0,0 +1,190 @@
+/* zd_mac.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_MAC_H
+#define _ZD_MAC_H
+
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+
+#include "zd_chip.h"
+#include "zd_netdev.h"
+
+struct zd_ctrlset {
+       u8     modulation;
+       __le16 tx_length;
+       u8     control;
+       /* stores only the difference to tx_length on ZD1211B */
+       __le16 packet_length;
+       __le16 current_length;
+       u8     service;
+       __le16  next_frame_length;
+} __attribute__((packed));
+
+#define ZD_CS_RESERVED_SIZE    25
+
+/* zd_crtlset field modulation */
+#define ZD_CS_RATE_MASK                0x0f
+#define ZD_CS_TYPE_MASK                0x10
+#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
+#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
+
+#define ZD_CS_CCK              0x00
+#define ZD_CS_OFDM             0x10
+
+#define ZD_CS_CCK_RATE_1M      0x00
+#define ZD_CS_CCK_RATE_2M      0x01
+#define ZD_CS_CCK_RATE_5_5M    0x02
+#define ZD_CS_CCK_RATE_11M     0x03
+/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+ */
+
+/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
+#define ZD_CS_CCK_PREA_LONG    0x00
+#define ZD_CS_CCK_PREA_SHORT   0x20
+#define ZD_CS_OFDM_MODE_11G    0x00
+#define ZD_CS_OFDM_MODE_11A    0x20
+
+/* zd_ctrlset control field */
+#define ZD_CS_NEED_RANDOM_BACKOFF      0x01
+#define ZD_CS_MULTICAST                        0x02
+
+#define ZD_CS_FRAME_TYPE_MASK          0x0c
+#define ZD_CS_DATA_FRAME               0x00
+#define ZD_CS_PS_POLL_FRAME            0x04
+#define ZD_CS_MANAGEMENT_FRAME         0x08
+#define ZD_CS_NO_SEQUENCE_CTL_FRAME    0x0c
+
+#define ZD_CS_WAKE_DESTINATION         0x10
+#define ZD_CS_RTS                      0x20
+#define ZD_CS_ENCRYPT                  0x40
+#define ZD_CS_SELF_CTS                 0x80
+
+/* Incoming frames are prepended by a PLCP header */
+#define ZD_PLCP_HEADER_SIZE            5
+
+struct rx_length_info {
+       __le16 length[3];
+       __le16 tag;
+} __attribute__((packed));
+
+#define RX_LENGTH_INFO_TAG             0x697e
+
+struct rx_status {
+       /* rssi */
+       u8 signal_strength;
+       u8 signal_quality_cck;
+       u8 signal_quality_ofdm;
+       u8 decryption_type;
+       u8 frame_status;
+} __attribute__((packed));
+
+/* rx_status field decryption_type */
+#define ZD_RX_NO_WEP   0
+#define ZD_RX_WEP64    1
+#define ZD_RX_TKIP     2
+#define ZD_RX_AES      4
+#define ZD_RX_WEP128   5
+#define ZD_RX_WEP256   6
+
+/* rx_status field frame_status */
+#define ZD_RX_FRAME_MODULATION_MASK    0x01
+#define ZD_RX_CCK                      0x00
+#define ZD_RX_OFDM                     0x01
+
+#define ZD_RX_TIMEOUT_ERROR            0x02
+#define ZD_RX_FIFO_OVERRUN_ERROR       0x04
+#define ZD_RX_DECRYPTION_ERROR         0x08
+#define ZD_RX_CRC32_ERROR              0x10
+#define ZD_RX_NO_ADDR1_MATCH_ERROR     0x20
+#define ZD_RX_CRC16_ERROR              0x40
+#define ZD_RX_ERROR                    0x80
+
+enum mac_flags {
+       MAC_FIXED_CHANNEL = 0x01,
+};
+
+struct zd_mac {
+       struct net_device *netdev;
+       struct zd_chip chip;
+       spinlock_t lock;
+       /* Unlocked reading possible */
+       struct iw_statistics iw_stats;
+       u8 qual_average;
+       u8 rssi_average;
+       u8 regdomain;
+       u8 default_regdomain;
+       u8 requested_channel;
+};
+
+static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
+{
+       return zd_netdev_ieee80211(mac->netdev);
+}
+
+static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
+{
+       return ieee80211softmac_priv(netdev);
+}
+
+static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
+{
+       return container_of(chip, struct zd_mac, chip);
+}
+
+static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
+{
+       return zd_chip_to_mac(zd_usb_to_chip(usb));
+}
+
+#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
+
+int zd_mac_init(struct zd_mac *mac,
+                struct net_device *netdev,
+               struct usb_interface *intf);
+void zd_mac_clear(struct zd_mac *mac);
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
+
+int zd_mac_open(struct net_device *netdev);
+int zd_mac_stop(struct net_device *netdev);
+int zd_mac_set_mac_address(struct net_device *dev, void *p);
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+
+int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
+u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
+
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags);
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
+
+#ifdef DEBUG
+void zd_dump_rx_status(const struct rx_status *status);
+#else
+#define zd_dump_rx_status(status)
+#endif /* DEBUG */
+
+#endif /* _ZD_MAC_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
new file mode 100644 (file)
index 0000000..9df232c
--- /dev/null
@@ -0,0 +1,267 @@
+/* zd_netdev.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <net/ieee80211softmac_wx.h>
+#include <net/iw_handler.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+
+/* Region 0 means reset regdomain to default. */
+static int zd_set_regdomain(struct net_device *netdev,
+                           struct iw_request_info *info,
+                           union iwreq_data *req, char *extra)
+{
+       const u8 *regdomain = (u8 *)req;
+       return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
+}
+
+static int zd_get_regdomain(struct net_device *netdev,
+                           struct iw_request_info *info,
+                           union iwreq_data *req, char *extra)
+{
+       u8 *regdomain = (u8 *)req;
+       if (!regdomain)
+               return -EINVAL;
+       *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
+       return 0;
+}
+
+static const struct iw_priv_args zd_priv_args[] = {
+       {
+               .cmd = ZD_PRIV_SET_REGDOMAIN,
+               .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+               .name = "set_regdomain",
+       },
+       {
+               .cmd = ZD_PRIV_GET_REGDOMAIN,
+               .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+               .name = "get_regdomain",
+       },
+};
+
+#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
+
+static const iw_handler zd_priv_handler[] = {
+       PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
+       PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
+};
+
+static int iw_get_name(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       /* FIXME: check whether 802.11a will also supported, add also
+        *        zd1211B, if we support it.
+        */
+       strlcpy(req->name, "802.11g zd1211", IFNAMSIZ);
+       return 0;
+}
+
+static int iw_set_freq(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       int r;
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct iw_freq *freq = &req->freq;
+       u8 channel;
+
+       r = zd_find_channel(&channel, freq);
+       if (r < 0)
+               return r;
+       r = zd_mac_request_channel(mac, channel);
+       return r;
+}
+
+static int iw_get_freq(struct net_device *netdev,
+                  struct iw_request_info *info,
+                  union iwreq_data *req, char *extra)
+{
+       int r;
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct iw_freq *freq = &req->freq;
+       u8 channel;
+       u8 flags;
+
+       r = zd_mac_get_channel(mac, &channel, &flags);
+       if (r)
+               return r;
+
+       freq->flags = (flags & MAC_FIXED_CHANNEL) ?
+                     IW_FREQ_FIXED : IW_FREQ_AUTO;
+       dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
+                 (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
+       return zd_channel_to_freq(freq, channel);
+}
+
+static int iw_set_mode(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
+}
+
+static int iw_get_mode(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
+}
+
+static int iw_get_range(struct net_device *netdev,
+                      struct iw_request_info *info,
+                      union iwreq_data *req, char *extra)
+{
+       struct iw_range *range = (struct iw_range *)extra;
+
+       dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+       req->data.length = sizeof(*range);
+       return zd_mac_get_range(zd_netdev_mac(netdev), range);
+}
+
+static int iw_set_encode(struct net_device *netdev,
+                        struct iw_request_info *info,
+                        union iwreq_data *data,
+                        char *extra)
+{
+       return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
+               data, extra);
+}
+
+static int iw_get_encode(struct net_device *netdev,
+                        struct iw_request_info *info,
+                        union iwreq_data *data,
+                        char *extra)
+{
+       return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
+               data, extra);
+}
+
+static int iw_set_encodeext(struct net_device *netdev,
+                        struct iw_request_info *info,
+                        union iwreq_data *data,
+                        char *extra)
+{
+       return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
+               data, extra);
+}
+
+static int iw_get_encodeext(struct net_device *netdev,
+                        struct iw_request_info *info,
+                        union iwreq_data *data,
+                        char *extra)
+{
+       return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
+               data, extra);
+}
+
+#define WX(x) [(x)-SIOCIWFIRST]
+
+static const iw_handler zd_standard_iw_handlers[] = {
+       WX(SIOCGIWNAME)         = iw_get_name,
+       WX(SIOCSIWFREQ)         = iw_set_freq,
+       WX(SIOCGIWFREQ)         = iw_get_freq,
+       WX(SIOCSIWMODE)         = iw_set_mode,
+       WX(SIOCGIWMODE)         = iw_get_mode,
+       WX(SIOCGIWRANGE)        = iw_get_range,
+       WX(SIOCSIWENCODE)       = iw_set_encode,
+       WX(SIOCGIWENCODE)       = iw_get_encode,
+       WX(SIOCSIWENCODEEXT)    = iw_set_encodeext,
+       WX(SIOCGIWENCODEEXT)    = iw_get_encodeext,
+       WX(SIOCSIWAUTH)         = ieee80211_wx_set_auth,
+       WX(SIOCGIWAUTH)         = ieee80211_wx_get_auth,
+       WX(SIOCSIWSCAN)         = ieee80211softmac_wx_trigger_scan,
+       WX(SIOCGIWSCAN)         = ieee80211softmac_wx_get_scan_results,
+       WX(SIOCSIWESSID)        = ieee80211softmac_wx_set_essid,
+       WX(SIOCGIWESSID)        = ieee80211softmac_wx_get_essid,
+       WX(SIOCSIWAP)           = ieee80211softmac_wx_set_wap,
+       WX(SIOCGIWAP)           = ieee80211softmac_wx_get_wap,
+       WX(SIOCSIWRATE)         = ieee80211softmac_wx_set_rate,
+       WX(SIOCGIWRATE)         = ieee80211softmac_wx_get_rate,
+       WX(SIOCSIWGENIE)        = ieee80211softmac_wx_set_genie,
+       WX(SIOCGIWGENIE)        = ieee80211softmac_wx_get_genie,
+       WX(SIOCSIWMLME)         = ieee80211softmac_wx_set_mlme,
+};
+
+static const struct iw_handler_def iw_handler_def = {
+       .standard               = zd_standard_iw_handlers,
+       .num_standard           = ARRAY_SIZE(zd_standard_iw_handlers),
+       .private                = zd_priv_handler,
+       .num_private            = ARRAY_SIZE(zd_priv_handler),
+       .private_args           = zd_priv_args,
+       .num_private_args       = ARRAY_SIZE(zd_priv_args),
+       .get_wireless_stats     = zd_mac_get_wireless_stats,
+};
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf)
+{
+       int r;
+       struct net_device *netdev;
+       struct zd_mac *mac;
+
+       netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
+       if (!netdev) {
+               dev_dbg_f(&intf->dev, "out of memory\n");
+               return NULL;
+       }
+
+       mac = zd_netdev_mac(netdev);
+       r = zd_mac_init(mac, netdev, intf);
+       if (r) {
+               usb_set_intfdata(intf, NULL);
+               free_ieee80211(netdev);
+               return NULL;
+       }
+
+       SET_MODULE_OWNER(netdev);
+       SET_NETDEV_DEV(netdev, &intf->dev);
+
+       dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
+       dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
+
+       netdev->open = zd_mac_open;
+       netdev->stop = zd_mac_stop;
+       /* netdev->get_stats = */
+       /* netdev->set_multicast_list = */
+       netdev->set_mac_address = zd_mac_set_mac_address;
+       netdev->wireless_handlers = &iw_handler_def;
+       /* netdev->ethtool_ops = */
+
+       return netdev;
+}
+
+void zd_netdev_free(struct net_device *netdev)
+{
+       if (!netdev)
+               return;
+
+       zd_mac_clear(zd_netdev_mac(netdev));
+       free_ieee80211(netdev);
+}
+
+void zd_netdev_disconnect(struct net_device *netdev)
+{
+       unregister_netdev(netdev);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h
new file mode 100644 (file)
index 0000000..374a957
--- /dev/null
@@ -0,0 +1,45 @@
+/* zd_netdev.h: Header for net device related functions.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_NETDEV_H
+#define _ZD_NETDEV_H
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <net/ieee80211.h>
+
+#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
+#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
+
+static inline struct ieee80211_device *zd_netdev_ieee80211(
+       struct net_device *ndev)
+{
+       return netdev_priv(ndev);
+}
+
+static inline struct net_device *zd_ieee80211_to_netdev(
+       struct ieee80211_device *ieee)
+{
+       return ieee->dev;
+}
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf);
+void zd_netdev_free(struct net_device *netdev);
+
+void zd_netdev_disconnect(struct net_device *netdev);
+
+#endif /* _ZD_NETDEV_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
new file mode 100644 (file)
index 0000000..d3770d2
--- /dev/null
@@ -0,0 +1,151 @@
+/* zd_rf.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include "zd_def.h"
+#include "zd_rf.h"
+#include "zd_ieee80211.h"
+#include "zd_chip.h"
+
+static const char *rfs[] = {
+       [0]             = "unknown RF0",
+       [1]             = "unknown RF1",
+       [UW2451_RF]     = "UW2451_RF",
+       [UCHIP_RF]      = "UCHIP_RF",
+       [AL2230_RF]     = "AL2230_RF",
+       [AL7230B_RF]    = "AL7230B_RF",
+       [THETA_RF]      = "THETA_RF",
+       [AL2210_RF]     = "AL2210_RF",
+       [MAXIM_NEW_RF]  = "MAXIM_NEW_RF",
+       [UW2453_RF]     = "UW2453_RF",
+       [AL2230S_RF]    = "AL2230S_RF",
+       [RALINK_RF]     = "RALINK_RF",
+       [INTERSIL_RF]   = "INTERSIL_RF",
+       [RF2959_RF]     = "RF2959_RF",
+       [MAXIM_NEW2_RF] = "MAXIM_NEW2_RF",
+       [PHILIPS_RF]    = "PHILIPS_RF",
+};
+
+const char *zd_rf_name(u8 type)
+{
+       if (type & 0xf0)
+               type = 0;
+       return rfs[type];
+}
+
+void zd_rf_init(struct zd_rf *rf)
+{
+       memset(rf, 0, sizeof(*rf));
+}
+
+void zd_rf_clear(struct zd_rf *rf)
+{
+       memset(rf, 0, sizeof(*rf));
+}
+
+int zd_rf_init_hw(struct zd_rf *rf, u8 type)
+{
+       int r, t;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       switch (type) {
+       case RF2959_RF:
+               r = zd_rf_init_rf2959(rf);
+               if (r)
+                       return r;
+               break;
+       case AL2230_RF:
+               r = zd_rf_init_al2230(rf);
+               if (r)
+                       return r;
+               break;
+       default:
+               dev_err(zd_chip_dev(chip),
+                       "RF %s %#x is not supported\n", zd_rf_name(type), type);
+               rf->type = 0;
+               return -ENODEV;
+       }
+
+       rf->type = type;
+
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               return r;
+       t = rf->init_hw(rf);
+       r = zd_chip_unlock_phy_regs(chip);
+       if (t)
+               r = t;
+       return r;
+}
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size)
+{
+       return scnprintf(buffer, size, "%s", zd_rf_name(rf->type));
+}
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int r;
+
+       ZD_ASSERT(mutex_is_locked(&zd_rf_to_chip(rf)->mutex));
+       if (channel < MIN_CHANNEL24)
+               return -EINVAL;
+       if (channel > MAX_CHANNEL24)
+               return -EINVAL;
+       dev_dbg_f(zd_chip_dev(zd_rf_to_chip(rf)), "channel: %d\n", channel);
+
+       r = rf->set_channel(rf, channel);
+       if (r >= 0)
+               rf->channel = channel;
+       return r;
+}
+
+int zd_switch_radio_on(struct zd_rf *rf)
+{
+       int r, t;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               return r;
+       t = rf->switch_radio_on(rf);
+       r = zd_chip_unlock_phy_regs(chip);
+       if (t)
+               r = t;
+       return r;
+}
+
+int zd_switch_radio_off(struct zd_rf *rf)
+{
+       int r, t;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       /* TODO: move phy regs handling to zd_chip */
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_chip_lock_phy_regs(chip);
+       if (r)
+               return r;
+       t = rf->switch_radio_off(rf);
+       r = zd_chip_unlock_phy_regs(chip);
+       if (t)
+               r = t;
+       return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
new file mode 100644 (file)
index 0000000..ea30f69
--- /dev/null
@@ -0,0 +1,82 @@
+/* zd_rf.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_RF_H
+#define _ZD_RF_H
+
+#include "zd_types.h"
+
+#define UW2451_RF                      0x2
+#define UCHIP_RF                       0x3
+#define AL2230_RF                      0x4
+#define AL7230B_RF                     0x5     /* a,b,g */
+#define THETA_RF                       0x6
+#define AL2210_RF                      0x7
+#define MAXIM_NEW_RF                   0x8
+#define UW2453_RF                      0x9
+#define AL2230S_RF                     0xa
+#define RALINK_RF                      0xb
+#define INTERSIL_RF                    0xc
+#define RF2959_RF                      0xd
+#define MAXIM_NEW2_RF                  0xe
+#define PHILIPS_RF                     0xf
+
+#define RF_CHANNEL(ch) [(ch)-1]
+
+/* Provides functions of the RF transceiver. */
+
+enum {
+       RF_REG_BITS = 6,
+       RF_VALUE_BITS = 18,
+       RF_RV_BITS = RF_REG_BITS + RF_VALUE_BITS,
+};
+
+struct zd_rf {
+       u8 type;
+
+       u8 channel;
+       /*
+        * Whether this RF should patch the 6M band edge
+        * (assuming E2P_POD agrees)
+        */
+       u8 patch_6m_band_edge:1;
+
+       /* RF-specific functions */
+       int (*init_hw)(struct zd_rf *rf);
+       int (*set_channel)(struct zd_rf *rf, u8 channel);
+       int (*switch_radio_on)(struct zd_rf *rf);
+       int (*switch_radio_off)(struct zd_rf *rf);
+};
+
+const char *zd_rf_name(u8 type);
+void zd_rf_init(struct zd_rf *rf);
+void zd_rf_clear(struct zd_rf *rf);
+int zd_rf_init_hw(struct zd_rf *rf, u8 type);
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size);
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
+
+int zd_switch_radio_on(struct zd_rf *rf);
+int zd_switch_radio_off(struct zd_rf *rf);
+
+/* Functions for individual RF chips */
+
+int zd_rf_init_rf2959(struct zd_rf *rf);
+int zd_rf_init_al2230(struct zd_rf *rf);
+
+#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
new file mode 100644 (file)
index 0000000..0948b25
--- /dev/null
@@ -0,0 +1,308 @@
+/* zd_rf_al2230.c: Functions for the AL2230 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 al2230_table[][3] = {
+       RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
+       RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
+       RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
+       RF_CHANNEL( 4) = { 0x03e790, 0x0b3331, 0x00000d, },
+       RF_CHANNEL( 5) = { 0x03f7a0, 0x033331, 0x00000d, },
+       RF_CHANNEL( 6) = { 0x03f7a0, 0x0b3331, 0x00000d, },
+       RF_CHANNEL( 7) = { 0x03e7a0, 0x033331, 0x00000d, },
+       RF_CHANNEL( 8) = { 0x03e7a0, 0x0b3331, 0x00000d, },
+       RF_CHANNEL( 9) = { 0x03f7b0, 0x033331, 0x00000d, },
+       RF_CHANNEL(10) = { 0x03f7b0, 0x0b3331, 0x00000d, },
+       RF_CHANNEL(11) = { 0x03e7b0, 0x033331, 0x00000d, },
+       RF_CHANNEL(12) = { 0x03e7b0, 0x0b3331, 0x00000d, },
+       RF_CHANNEL(13) = { 0x03f7c0, 0x033331, 0x00000d, },
+       RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
+};
+
+static int zd1211_al2230_init_hw(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR15,   0x20 }, { CR23,   0x40 }, { CR24,  0x20 },
+               { CR26,   0x11 }, { CR28,   0x3e }, { CR29,  0x00 },
+               { CR44,   0x33 }, { CR106,  0x2a }, { CR107, 0x1a },
+               { CR109,  0x09 }, { CR110,  0x27 }, { CR111, 0x2b },
+               { CR112,  0x2b }, { CR119,  0x0a }, { CR10,  0x89 },
+               /* for newest (3rd cut) AL2300 */
+               { CR17,   0x28 },
+               { CR26,   0x93 }, { CR34,   0x30 },
+               /* for newest (3rd cut) AL2300 */
+               { CR35,   0x3e },
+               { CR41,   0x24 }, { CR44,   0x32 },
+               /* for newest (3rd cut) AL2300 */
+               { CR46,   0x96 },
+               { CR47,   0x1e }, { CR79,   0x58 }, { CR80,  0x30 },
+               { CR81,   0x30 }, { CR87,   0x0a }, { CR89,  0x04 },
+               { CR92,   0x0a }, { CR99,   0x28 }, { CR100, 0x00 },
+               { CR101,  0x13 }, { CR102,  0x27 }, { CR106, 0x24 },
+               { CR107,  0x2a }, { CR109,  0x09 }, { CR110, 0x13 },
+               { CR111,  0x1f }, { CR112,  0x1f }, { CR113, 0x27 },
+               { CR114,  0x27 },
+               /* for newest (3rd cut) AL2300 */
+               { CR115,  0x24 },
+               { CR116,  0x24 }, { CR117,  0xf4 }, { CR118, 0xfc },
+               { CR119,  0x10 }, { CR120,  0x4f }, { CR121, 0x77 },
+               { CR122,  0xe0 }, { CR137,  0x88 }, { CR252, 0xff },
+               { CR253,  0xff },
+
+               /* These following happen separately in the vendor driver */
+               { },
+
+               /* shdnb(PLL_ON)=0 */
+               { CR251,  0x2f },
+               /* shdnb(PLL_ON)=1 */
+               { CR251,  0x3f },
+               { CR138,  0x28 }, { CR203,  0x06 },
+       };
+
+       static const u32 rv[] = {
+               /* Channel 1 */
+               0x03f790,
+               0x033331,
+               0x00000d,
+
+               0x0b3331,
+               0x03b812,
+               0x00fff3,
+               0x000da4,
+               0x0f4dc5, /* fix freq shift, 0x04edc5 */
+               0x0805b6,
+               0x011687,
+               0x000688,
+               0x0403b9, /* external control TX power (CR31) */
+               0x00dbba,
+               0x00099b,
+               0x0bdffc,
+               0x00000d,
+               0x00500f,
+
+               /* These writes happen separately in the vendor driver */
+               0x00d00f,
+               0x004c0f,
+               0x00540f,
+               0x00700f,
+               0x00500f,
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+static int zd1211b_al2230_init_hw(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs1[] = {
+               { CR10,  0x89 }, { CR15,  0x20 },
+               { CR17,  0x2B }, /* for newest(3rd cut) AL2230 */
+               { CR23,  0x40 }, { CR24,  0x20 }, { CR26,  0x93 },
+               { CR28,  0x3e }, { CR29,  0x00 },
+               { CR33,  0x28 }, /* 5621 */
+               { CR34,  0x30 },
+               { CR35,  0x3e }, /* for newest(3rd cut) AL2230 */
+               { CR41,  0x24 }, { CR44,  0x32 },
+               { CR46,  0x99 }, /* for newest(3rd cut) AL2230 */
+               { CR47,  0x1e },
+
+               /* ZD1211B 05.06.10 */
+               { CR48,  0x00 }, { CR49,  0x00 }, { CR51,  0x01 },
+               { CR52,  0x80 }, { CR53,  0x7e }, { CR65,  0x00 },
+               { CR66,  0x00 }, { CR67,  0x00 }, { CR68,  0x00 },
+               { CR69,  0x28 },
+
+               { CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
+               { CR87,  0x0a }, { CR89,  0x04 },
+               { CR91,  0x00 }, /* 5621 */
+               { CR92,  0x0a },
+               { CR98,  0x8d }, /* 4804,  for 1212 new algorithm */
+               { CR99,  0x00 }, /* 5621 */
+               { CR101, 0x13 }, { CR102, 0x27 },
+               { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+               { CR107, 0x2a },
+               { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+               { CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+               { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+               { CR114, 0x27 },
+               { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
+               { CR116, 0x24 },
+               { CR117, 0xfa }, /* for 1211b */
+               { CR118, 0xfa }, /* for 1211b */
+               { CR119, 0x10 },
+               { CR120, 0x4f },
+               { CR121, 0x6c }, /* for 1211b */
+               { CR122, 0xfc }, /* E0->FC at 4902 */
+               { CR123, 0x57 }, /* 5623 */
+               { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+               { CR126, 0x6c }, /* 5614 */
+               { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+               { CR137, 0x50 }, /* 5614 */
+               { CR138, 0xa8 },
+               { CR144, 0xac }, /* 5621 */
+               { CR150, 0x0d }, { CR252, 0x00 }, { CR253, 0x00 },
+       };
+
+       static const u32 rv1[] = {
+               /* channel 1 */
+               0x03f790,
+               0x033331,
+               0x00000d,
+
+               0x0b3331,
+               0x03b812,
+               0x00fff3,
+               0x0005a4,
+               0x0f4dc5, /* fix freq shift 0x044dc5 */
+               0x0805b6,
+               0x0146c7,
+               0x000688,
+               0x0403b9, /* External control TX power (CR31) */
+               0x00dbba,
+               0x00099b,
+               0x0bdffc,
+               0x00000d,
+               0x00580f,
+       };
+
+       static const struct zd_ioreq16 ioreqs2[] = {
+               { CR47,  0x1e }, { CR_RFCFG, 0x03 },
+       };
+
+       static const u32 rv2[] = {
+               0x00880f,
+               0x00080f,
+       };
+
+       static const struct zd_ioreq16 ioreqs3[] = {
+               { CR_RFCFG, 0x00 }, { CR47, 0x1e }, { CR251, 0x7f },
+       };
+
+       static const u32 rv3[] = {
+               0x00d80f,
+               0x00780f,
+               0x00580f,
+       };
+
+       static const struct zd_ioreq16 ioreqs4[] = {
+               { CR138, 0x28 }, { CR203, 0x06 },
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
+       if (r)
+               return r;
+       r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+       if (r)
+               return r;
+       r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+       if (r)
+               return r;
+       r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+       if (r)
+               return r;
+       r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+       if (r)
+               return r;
+       r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
+       if (r)
+               return r;
+       return zd_iowrite16a_locked(chip, ioreqs4, ARRAY_SIZE(ioreqs4));
+}
+
+static int al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int r;
+       const u32 *rv = al2230_table[channel-1];
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR138, 0x28 },
+               { CR203, 0x06 },
+       };
+
+       r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
+       if (r)
+               return r;
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x00 },
+               { CR251, 0x3f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x00 },
+               { CR251, 0x7f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al2230_switch_radio_off(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR11,  0x04 },
+               { CR251, 0x2f },
+       };
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al2230(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       rf->set_channel = al2230_set_channel;
+       rf->switch_radio_off = al2230_switch_radio_off;
+       if (chip->is_zd1211b) {
+               rf->init_hw = zd1211b_al2230_init_hw;
+               rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
+       } else {
+               rf->init_hw = zd1211_al2230_init_hw;
+               rf->switch_radio_on = zd1211_al2230_switch_radio_on;
+       }
+       rf->patch_6m_band_edge = 1;
+       return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
new file mode 100644 (file)
index 0000000..5824727
--- /dev/null
@@ -0,0 +1,279 @@
+/* zd_rf_rfmd.c: Functions for the RFMD RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static u32 rf2959_table[][2] = {
+       RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
+       RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
+       RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
+       RF_CHANNEL( 4) = { 0x1819a9, 0x1e6666 },
+       RF_CHANNEL( 5) = { 0x1819b9, 0x1e6666 },
+       RF_CHANNEL( 6) = { 0x1819c9, 0x1e6666 },
+       RF_CHANNEL( 7) = { 0x1819d9, 0x1e6666 },
+       RF_CHANNEL( 8) = { 0x1819e9, 0x1e6666 },
+       RF_CHANNEL( 9) = { 0x1819f9, 0x1e6666 },
+       RF_CHANNEL(10) = { 0x181a09, 0x1e6666 },
+       RF_CHANNEL(11) = { 0x181a19, 0x1e6666 },
+       RF_CHANNEL(12) = { 0x181a29, 0x1e6666 },
+       RF_CHANNEL(13) = { 0x181a39, 0x1e6666 },
+       RF_CHANNEL(14) = { 0x181a60, 0x1c0000 },
+};
+
+#if 0
+static int bits(u32 rw, int from, int to)
+{
+       rw &= ~(0xffffffffU << (to+1));
+       rw >>= from;
+       return rw;
+}
+
+static int bit(u32 rw, int bit)
+{
+       return bits(rw, bit, bit);
+}
+
+static void dump_regwrite(u32 rw)
+{
+       int reg = bits(rw, 18, 22);
+       int rw_flag = bits(rw, 23, 23);
+       PDEBUG("rf2959 %#010x reg %d rw %d", rw, reg, rw_flag);
+
+       switch (reg) {
+       case 0:
+               PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d"
+                      " if_vco_reg_en %d if_vga_en %d",
+                      bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1),
+                      bit(rw, 0));
+               break;
+       case 1:
+               PDEBUG("reg1 IFPLL1 pll_en1 %d kv_en1 %d vtc_en1 %d lpf1 %d"
+                      " cpl1 %d pdp1 %d autocal_en1 %d ld_en1 %d ifloopr %d"
+                      " ifloopc %d dac1 %d",
+                      bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+                      bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+                      bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0, 3));
+               break;
+       case 2:
+               PDEBUG("reg2 IFPLL2 n1 %d num1 %d",
+                      bits(rw, 6, 17), bits(rw, 0, 5));
+               break;
+       case 3:
+               PDEBUG("reg3 IFPLL3 num %d", bits(rw, 0, 17));
+               break;
+       case 4:
+               PDEBUG("reg4 IFPLL4 dn1 %#04x ct_def1 %d kv_def1 %d",
+                      bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+               break;
+       case 5:
+               PDEBUG("reg5 RFPLL1 pll_en %d kv_en %d vtc_en %d lpf %d cpl %d"
+                      " pdp %d autocal_en %d ld_en %d rfloopr %d rfloopc %d"
+                      " dac %d",
+                      bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+                      bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+                      bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0,3));
+               break;
+       case 6:
+               PDEBUG("reg6 RFPLL2 n %d num %d",
+                      bits(rw, 6, 17), bits(rw, 0, 5));
+               break;
+       case 7:
+               PDEBUG("reg7 RFPLL3 num2 %d", bits(rw, 0, 17));
+               break;
+       case 8:
+               PDEBUG("reg8 RFPLL4 dn %#06x ct_def %d kv_def %d",
+                      bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+               break;
+       case 9:
+               PDEBUG("reg9 CAL1 tvco %d tlock %d m_ct_value %d ld_window %d",
+                      bits(rw, 13, 17), bits(rw, 8, 12), bits(rw, 3, 7),
+                      bits(rw, 0, 2));
+               break;
+       case 10:
+               PDEBUG("reg10 TXRX1 rxdcfbbyps %d pcontrol %d txvgc %d"
+                      " rxlpfbw %d txlpfbw %d txdiffmode %d txenmode %d"
+                      " intbiasen %d tybypass %d",
+                      bit(rw, 17), bits(rw, 15, 16), bits(rw, 10, 14),
+                      bits(rw, 7, 9), bits(rw, 4, 6), bit(rw, 3), bit(rw, 2),
+                      bit(rw, 1), bit(rw, 0));
+               break;
+       case 11:
+               PDEBUG("reg11 PCNT1 mid_bias %d p_desired %d pc_offset %d"
+                       " tx_delay %d",
+                       bits(rw, 15, 17), bits(rw, 9, 14), bits(rw, 3, 8),
+                       bits(rw, 0, 2));
+               break;
+       case 12:
+               PDEBUG("reg12 PCNT2 max_power %d mid_power %d min_power %d",
+                      bits(rw, 12, 17), bits(rw, 6, 11), bits(rw, 0, 5));
+               break;
+       case 13:
+               PDEBUG("reg13 VCOT1 rfpll vco comp %d ifpll vco comp %d"
+                      " lobias %d if_biasbuf %d if_biasvco %d rf_biasbuf %d"
+                      " rf_biasvco %d",
+                      bit(rw, 17), bit(rw, 16), bit(rw, 15),
+                      bits(rw, 8, 9), bits(rw, 5, 7), bits(rw, 3, 4),
+                      bits(rw, 0, 2));
+               break;
+       case 14:
+               PDEBUG("reg14 IQCAL rx_acal %d rx_pcal %d"
+                      " tx_acal %d tx_pcal %d",
+                      bits(rw, 13, 17), bits(rw, 9, 12), bits(rw, 4, 8),
+                      bits(rw, 0, 3));
+               break;
+       }
+}
+#endif /* 0 */
+
+static int rf2959_init_hw(struct zd_rf *rf)
+{
+       int r;
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR2,   0x1E }, { CR9,   0x20 }, { CR10,  0x89 },
+               { CR11,  0x00 }, { CR15,  0xD0 }, { CR17,  0x68 },
+               { CR19,  0x4a }, { CR20,  0x0c }, { CR21,  0x0E },
+               { CR23,  0x48 },
+               /* normal size for cca threshold */
+               { CR24,  0x14 },
+               /* { CR24,  0x20 }, */
+               { CR26,  0x90 }, { CR27,  0x30 }, { CR29,  0x20 },
+               { CR31,  0xb2 }, { CR32,  0x43 }, { CR33,  0x28 },
+               { CR38,  0x30 }, { CR34,  0x0f }, { CR35,  0xF0 },
+               { CR41,  0x2a }, { CR46,  0x7F }, { CR47,  0x1E },
+               { CR51,  0xc5 }, { CR52,  0xc5 }, { CR53,  0xc5 },
+               { CR79,  0x58 }, { CR80,  0x30 }, { CR81,  0x30 },
+               { CR82,  0x00 }, { CR83,  0x24 }, { CR84,  0x04 },
+               { CR85,  0x00 }, { CR86,  0x10 }, { CR87,  0x2A },
+               { CR88,  0x10 }, { CR89,  0x24 }, { CR90,  0x18 },
+               /* { CR91,  0x18 }, */
+               /* should solve continous CTS frame problems */
+               { CR91,  0x00 },
+               { CR92,  0x0a }, { CR93,  0x00 }, { CR94,  0x01 },
+               { CR95,  0x00 }, { CR96,  0x40 }, { CR97,  0x37 },
+               { CR98,  0x05 }, { CR99,  0x28 }, { CR100, 0x00 },
+               { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
+               { CR104, 0x18 }, { CR105, 0x12 },
+               /* normal size */
+               { CR106, 0x1a },
+               /* { CR106, 0x22 }, */
+               { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
+               { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
+               { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
+               { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
+               { CR119, 0x16 },
+               /* no TX continuation */
+               { CR122, 0x00 },
+               /* { CR122, 0xff }, */
+               { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
+               { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
+               { CR170, 0xBB },
+       };
+
+       static const u32 rv[] = {
+               0x000007,  /* REG0(CFG1) */
+               0x07dd43,  /* REG1(IFPLL1) */
+               0x080959,  /* REG2(IFPLL2) */
+               0x0e6666,
+               0x116a57,  /* REG4 */
+               0x17dd43,  /* REG5 */
+               0x1819f9,  /* REG6 */
+               0x1e6666,
+               0x214554,
+               0x25e7fa,
+               0x27fffa,
+               /* The Zydas driver somehow forgets to set this value. It's
+                * only set for Japan. We are using internal power control
+                * for now.
+                */
+               0x294128, /* internal power */
+               /* 0x28252c, */ /* External control TX power */
+               /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+               0x2c0000,
+               0x300000,
+               0x340000,  /* REG13(0xD) */
+               0x381e0f,  /* REG14(0xE) */
+               /* Bogus, RF2959's data sheet doesn't know register 27, which is
+                * actually referenced here. The commented 0x11 is 17.
+                */
+               0x6c180f,  /* REG27(0x11) */
+       };
+
+       r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+       if (r)
+               return r;
+
+       return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
+{
+       int i, r;
+       u32 *rv = rf2959_table[channel-1];
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       for (i = 0; i < 2; i++) {
+               r = zd_rfwrite_locked(chip, rv[i], RF_RV_BITS);
+               if (r)
+                       return r;
+       }
+       return 0;
+}
+
+static int rf2959_switch_radio_on(struct zd_rf *rf)
+{
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR10, 0x89 },
+               { CR11, 0x00 },
+       };
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int rf2959_switch_radio_off(struct zd_rf *rf)
+{
+       static const struct zd_ioreq16 ioreqs[] = {
+               { CR10, 0x15 },
+               { CR11, 0x81 },
+       };
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_rf2959(struct zd_rf *rf)
+{
+       struct zd_chip *chip = zd_rf_to_chip(rf);
+
+       if (chip->is_zd1211b) {
+               dev_err(zd_chip_dev(chip),
+                      "RF2959 is currently not supported for ZD1211B"
+                      " devices\n");
+               return -ENODEV;
+       }
+       rf->init_hw = rf2959_init_hw;
+       rf->set_channel = rf2959_set_channel;
+       rf->switch_radio_on = rf2959_switch_radio_on;
+       rf->switch_radio_off = rf2959_switch_radio_off;
+       return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
new file mode 100644 (file)
index 0000000..0155a15
--- /dev/null
@@ -0,0 +1,71 @@
+/* zd_types.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_TYPES_H
+#define _ZD_TYPES_H
+
+#include <linux/types.h>
+
+/* We have three register spaces mapped into the overall USB address space of
+ * 64K words (16-bit values). There is the control register space of
+ * double-word registers, the eeprom register space and the firmware register
+ * space. The control register space is byte mapped, the others are word
+ * mapped.
+ *
+ * For that reason, we are using byte offsets for control registers and word
+ * offsets for everything else.
+ */
+
+typedef u32 __nocast zd_addr_t;
+
+enum {
+       ADDR_BASE_MASK          = 0xff000000,
+       ADDR_OFFSET_MASK        = 0x0000ffff,
+       ADDR_ZERO_MASK          = 0x00ff0000,
+       NULL_BASE               = 0x00000000,
+       USB_BASE                = 0x01000000,
+       CR_BASE                 = 0x02000000,
+       CR_MAX_OFFSET           = 0x0b30,
+       E2P_BASE                = 0x03000000,
+       E2P_MAX_OFFSET          = 0x007e,
+       FW_BASE                 = 0x04000000,
+       FW_MAX_OFFSET           = 0x0005,
+};
+
+#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
+#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
+
+#define ZD_ADDR(base, offset) \
+       ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
+
+#define ZD_NULL_ADDR    ((zd_addr_t)0)
+#define USB_REG(offset)  ZD_ADDR(USB_BASE, offset)     /* word addressing */
+#define CTL_REG(offset)  ZD_ADDR(CR_BASE, offset)      /* byte addressing */
+#define E2P_REG(offset)  ZD_ADDR(E2P_BASE, offset)     /* word addressing */
+#define FW_REG(offset)   ZD_ADDR(FW_BASE, offset)      /* word addressing */
+
+static inline zd_addr_t zd_inc_word(zd_addr_t addr)
+{
+       u32 base = ZD_ADDR_BASE(addr);
+       u32 offset = ZD_OFFSET(addr);
+
+       offset += base == CR_BASE ? 2 : 1;
+
+       return base | offset;
+}
+
+#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
new file mode 100644 (file)
index 0000000..ce1cb2c
--- /dev/null
@@ -0,0 +1,1316 @@
+/* zd_usb.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <asm/unaligned.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_usb.h"
+#include "zd_util.h"
+
+static struct usb_device_id usb_ids[] = {
+       /* ZD1211 */
+       { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+       { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+       /* ZD1211B */
+       { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+       {}
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip.");
+MODULE_AUTHOR("Ulrich Kunitz");
+MODULE_AUTHOR("Daniel Drake");
+MODULE_VERSION("1.0");
+MODULE_DEVICE_TABLE(usb, usb_ids);
+
+#define FW_ZD1211_PREFIX       "zd1211/zd1211_"
+#define FW_ZD1211B_PREFIX      "zd1211/zd1211b_"
+
+/* register address handling */
+
+#ifdef DEBUG
+static int check_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+       u32 base = ZD_ADDR_BASE(addr);
+       u32 offset = ZD_OFFSET(addr);
+
+       if ((u32)addr & ADDR_ZERO_MASK)
+               goto invalid_address;
+       switch (base) {
+       case USB_BASE:
+               break;
+       case CR_BASE:
+               if (offset > CR_MAX_OFFSET) {
+                       dev_dbg(zd_usb_dev(usb),
+                               "CR offset %#010x larger than"
+                               " CR_MAX_OFFSET %#10x\n",
+                               offset, CR_MAX_OFFSET);
+                       goto invalid_address;
+               }
+               if (offset & 1) {
+                       dev_dbg(zd_usb_dev(usb),
+                               "CR offset %#010x is not a multiple of 2\n",
+                               offset);
+                       goto invalid_address;
+               }
+               break;
+       case E2P_BASE:
+               if (offset > E2P_MAX_OFFSET) {
+                       dev_dbg(zd_usb_dev(usb),
+                               "E2P offset %#010x larger than"
+                               " E2P_MAX_OFFSET %#010x\n",
+                               offset, E2P_MAX_OFFSET);
+                       goto invalid_address;
+               }
+               break;
+       case FW_BASE:
+               if (!usb->fw_base_offset) {
+                       dev_dbg(zd_usb_dev(usb),
+                              "ERROR: fw base offset has not been set\n");
+                       return -EAGAIN;
+               }
+               if (offset > FW_MAX_OFFSET) {
+                       dev_dbg(zd_usb_dev(usb),
+                               "FW offset %#10x is larger than"
+                               " FW_MAX_OFFSET %#010x\n",
+                               offset, FW_MAX_OFFSET);
+                       goto invalid_address;
+               }
+               break;
+       default:
+               dev_dbg(zd_usb_dev(usb),
+                       "address has unsupported base %#010x\n", addr);
+               goto invalid_address;
+       }
+
+       return 0;
+invalid_address:
+       dev_dbg(zd_usb_dev(usb),
+               "ERROR: invalid address: %#010x\n", addr);
+       return -EINVAL;
+}
+#endif /* DEBUG */
+
+static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+       u32 base;
+       u16 offset;
+
+       base = ZD_ADDR_BASE(addr);
+       offset = ZD_OFFSET(addr);
+
+       ZD_ASSERT(check_addr(usb, addr) == 0);
+
+       switch (base) {
+       case CR_BASE:
+               offset += CR_BASE_OFFSET;
+               break;
+       case E2P_BASE:
+               offset += E2P_BASE_OFFSET;
+               break;
+       case FW_BASE:
+               offset += usb->fw_base_offset;
+               break;
+       }
+
+       return offset;
+}
+
+/* USB device initialization */
+
+static int request_fw_file(
+       const struct firmware **fw, const char *name, struct device *device)
+{
+       int r;
+
+       dev_dbg_f(device, "fw name %s\n", name);
+
+       r = request_firmware(fw, name, device);
+       if (r)
+               dev_err(device,
+                      "Could not load firmware file %s. Error number %d\n",
+                      name, r);
+       return r;
+}
+
+static inline u16 get_bcdDevice(const struct usb_device *udev)
+{
+       return le16_to_cpu(udev->descriptor.bcdDevice);
+}
+
+enum upload_code_flags {
+       REBOOT = 1,
+};
+
+/* Ensures that MAX_TRANSFER_SIZE is even. */
+#define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1)
+
+static int upload_code(struct usb_device *udev,
+       const u8 *data, size_t size, u16 code_offset, int flags)
+{
+       u8 *p;
+       int r;
+
+       /* USB request blocks need "kmalloced" buffers.
+        */
+       p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
+       if (!p) {
+               dev_err(&udev->dev, "out of memory\n");
+               r = -ENOMEM;
+               goto error;
+       }
+
+       size &= ~1;
+       while (size > 0) {
+               size_t transfer_size = size <= MAX_TRANSFER_SIZE ?
+                       size : MAX_TRANSFER_SIZE;
+
+               dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size);
+
+               memcpy(p, data, transfer_size);
+               r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       USB_REQ_FIRMWARE_DOWNLOAD,
+                       USB_DIR_OUT | USB_TYPE_VENDOR,
+                       code_offset, 0, p, transfer_size, 1000 /* ms */);
+               if (r < 0) {
+                       dev_err(&udev->dev,
+                              "USB control request for firmware upload"
+                              " failed. Error number %d\n", r);
+                       goto error;
+               }
+               transfer_size = r & ~1;
+
+               size -= transfer_size;
+               data += transfer_size;
+               code_offset += transfer_size/sizeof(u16);
+       }
+
+       if (flags & REBOOT) {
+               u8 ret;
+
+               r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+                       USB_REQ_FIRMWARE_CONFIRM,
+                       USB_DIR_IN | USB_TYPE_VENDOR,
+                       0, 0, &ret, sizeof(ret), 5000 /* ms */);
+               if (r != sizeof(ret)) {
+                       dev_err(&udev->dev,
+                               "control request firmeware confirmation failed."
+                               " Return value %d\n", r);
+                       if (r >= 0)
+                               r = -ENODEV;
+                       goto error;
+               }
+               if (ret & 0x80) {
+                       dev_err(&udev->dev,
+                               "Internal error while downloading."
+                               " Firmware confirm return value %#04x\n",
+                               (unsigned int)ret);
+                       r = -ENODEV;
+                       goto error;
+               }
+               dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n",
+                       (unsigned int)ret);
+       }
+
+       r = 0;
+error:
+       kfree(p);
+       return r;
+}
+
+static u16 get_word(const void *data, u16 offset)
+{
+       const __le16 *p = data;
+       return le16_to_cpu(p[offset]);
+}
+
+static char *get_fw_name(char *buffer, size_t size, u8 device_type,
+                      const char* postfix)
+{
+       scnprintf(buffer, size, "%s%s",
+               device_type == DEVICE_ZD1211B ?
+                       FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
+               postfix);
+       return buffer;
+}
+
+static int upload_firmware(struct usb_device *udev, u8 device_type)
+{
+       int r;
+       u16 fw_bcdDevice;
+       u16 bcdDevice;
+       const struct firmware *ub_fw = NULL;
+       const struct firmware *uph_fw = NULL;
+       char fw_name[128];
+
+       bcdDevice = get_bcdDevice(udev);
+
+       r = request_fw_file(&ub_fw,
+               get_fw_name(fw_name, sizeof(fw_name), device_type,  "ub"),
+               &udev->dev);
+       if (r)
+               goto error;
+
+       fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+
+       /* FIXME: do we have any reason to perform the kludge that the vendor
+        * driver does when there is a version mismatch? (their driver uploads
+        * different firmwares and stuff)
+        */
+       if (fw_bcdDevice != bcdDevice) {
+               dev_info(&udev->dev,
+                       "firmware device id %#06x and actual device id "
+                       "%#06x differ, continuing anyway\n",
+                       fw_bcdDevice, bcdDevice);
+       } else {
+               dev_dbg_f(&udev->dev,
+                       "firmware device id %#06x is equal to the "
+                       "actual device id\n", fw_bcdDevice);
+       }
+
+
+       r = request_fw_file(&uph_fw,
+               get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"),
+               &udev->dev);
+       if (r)
+               goto error;
+
+       r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
+                       REBOOT);
+       if (r) {
+               dev_err(&udev->dev,
+                       "Could not upload firmware code uph. Error number %d\n",
+                       r);
+       }
+
+       /* FALL-THROUGH */
+error:
+       release_firmware(ub_fw);
+       release_firmware(uph_fw);
+       return r;
+}
+
+static void disable_read_regs_int(struct zd_usb *usb)
+{
+       struct zd_usb_interrupt *intr = &usb->intr;
+
+       ZD_ASSERT(in_interrupt());
+       spin_lock(&intr->lock);
+       intr->read_regs_enabled = 0;
+       spin_unlock(&intr->lock);
+}
+
+#define urb_dev(urb) (&(urb)->dev->dev)
+
+static inline void handle_regs_int(struct urb *urb)
+{
+       struct zd_usb *usb = urb->context;
+       struct zd_usb_interrupt *intr = &usb->intr;
+       int len;
+
+       ZD_ASSERT(in_interrupt());
+       spin_lock(&intr->lock);
+
+       if (intr->read_regs_enabled) {
+               intr->read_regs.length = len = urb->actual_length;
+
+               if (len > sizeof(intr->read_regs.buffer))
+                       len = sizeof(intr->read_regs.buffer);
+               memcpy(intr->read_regs.buffer, urb->transfer_buffer, len);
+               intr->read_regs_enabled = 0;
+               complete(&intr->read_regs.completion);
+               goto out;
+       }
+
+       dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
+out:
+       spin_unlock(&intr->lock);
+}
+
+static inline void handle_retry_failed_int(struct urb *urb)
+{
+       dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
+}
+
+
+static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+       int r;
+       struct usb_int_header *hdr;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ESHUTDOWN:
+       case -EINVAL:
+       case -ENODEV:
+       case -ENOENT:
+       case -ECONNRESET:
+               goto kfree;
+       case -EPIPE:
+               usb_clear_halt(urb->dev, EP_INT_IN);
+               /* FALL-THROUGH */
+       default:
+               goto resubmit;
+       }
+
+       if (urb->actual_length < sizeof(hdr)) {
+               dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb);
+               goto resubmit;
+       }
+
+       hdr = urb->transfer_buffer;
+       if (hdr->type != USB_INT_TYPE) {
+               dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb);
+               goto resubmit;
+       }
+
+       switch (hdr->id) {
+       case USB_INT_ID_REGS:
+               handle_regs_int(urb);
+               break;
+       case USB_INT_ID_RETRY_FAILED:
+               handle_retry_failed_int(urb);
+               break;
+       default:
+               dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
+                       (unsigned int)hdr->id);
+               goto resubmit;
+       }
+
+resubmit:
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r) {
+               dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb);
+               goto kfree;
+       }
+       return;
+kfree:
+       kfree(urb->transfer_buffer);
+}
+
+static inline int int_urb_interval(struct usb_device *udev)
+{
+       switch (udev->speed) {
+       case USB_SPEED_HIGH:
+               return 4;
+       case USB_SPEED_LOW:
+               return 10;
+       case USB_SPEED_FULL:
+       default:
+               return 1;
+       }
+}
+
+static inline int usb_int_enabled(struct zd_usb *usb)
+{
+       unsigned long flags;
+       struct zd_usb_interrupt *intr = &usb->intr;
+       struct urb *urb;
+
+       spin_lock_irqsave(&intr->lock, flags);
+       urb = intr->urb;
+       spin_unlock_irqrestore(&intr->lock, flags);
+       return urb != NULL;
+}
+
+int zd_usb_enable_int(struct zd_usb *usb)
+{
+       int r;
+       struct usb_device *udev;
+       struct zd_usb_interrupt *intr = &usb->intr;
+       void *transfer_buffer = NULL;
+       struct urb *urb;
+
+       dev_dbg_f(zd_usb_dev(usb), "\n");
+
+       urb = usb_alloc_urb(0, GFP_NOFS);
+       if (!urb) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&intr->lock);
+       if (intr->urb) {
+               spin_unlock_irq(&intr->lock);
+               r = 0;
+               goto error_free_urb;
+       }
+       intr->urb = urb;
+       spin_unlock_irq(&intr->lock);
+
+       /* TODO: make it a DMA buffer */
+       r = -ENOMEM;
+       transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+       if (!transfer_buffer) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "couldn't allocate transfer_buffer\n");
+               goto error_set_urb_null;
+       }
+
+       udev = zd_usb_to_usbdev(usb);
+       usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
+                        transfer_buffer, USB_MAX_EP_INT_BUFFER,
+                        int_urb_complete, usb,
+                        intr->interval);
+
+       dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
+       r = usb_submit_urb(urb, GFP_NOFS);
+       if (r) {
+               dev_dbg_f(zd_usb_dev(usb),
+                        "Couldn't submit urb. Error number %d\n", r);
+               goto error;
+       }
+
+       return 0;
+error:
+       kfree(transfer_buffer);
+error_set_urb_null:
+       spin_lock_irq(&intr->lock);
+       intr->urb = NULL;
+       spin_unlock_irq(&intr->lock);
+error_free_urb:
+       usb_free_urb(urb);
+out:
+       return r;
+}
+
+void zd_usb_disable_int(struct zd_usb *usb)
+{
+       unsigned long flags;
+       struct zd_usb_interrupt *intr = &usb->intr;
+       struct urb *urb;
+
+       spin_lock_irqsave(&intr->lock, flags);
+       urb = intr->urb;
+       if (!urb) {
+               spin_unlock_irqrestore(&intr->lock, flags);
+               return;
+       }
+       intr->urb = NULL;
+       spin_unlock_irqrestore(&intr->lock, flags);
+
+       usb_kill_urb(urb);
+       dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
+       usb_free_urb(urb);
+}
+
+static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
+                            unsigned int length)
+{
+       int i;
+       struct zd_mac *mac = zd_usb_to_mac(usb);
+       const struct rx_length_info *length_info;
+
+       if (length < sizeof(struct rx_length_info)) {
+               /* It's not a complete packet anyhow. */
+               return;
+       }
+       length_info = (struct rx_length_info *)
+               (buffer + length - sizeof(struct rx_length_info));
+
+       /* It might be that three frames are merged into a single URB
+        * transaction. We have to check for the length info tag.
+        *
+        * While testing we discovered that length_info might be unaligned,
+        * because if USB transactions are merged, the last packet will not
+        * be padded. Unaligned access might also happen if the length_info
+        * structure is not present.
+        */
+       if (get_unaligned(&length_info->tag) == RX_LENGTH_INFO_TAG) {
+               unsigned int l, k, n;
+               for (i = 0, l = 0;; i++) {
+                       k = le16_to_cpu(get_unaligned(
+                               &length_info->length[i]));
+                       n = l+k;
+                       if (n > length)
+                               return;
+                       zd_mac_rx(mac, buffer+l, k);
+                       if (i >= 2)
+                               return;
+                       l = (n+3) & ~3;
+               }
+       } else {
+               zd_mac_rx(mac, buffer, length);
+       }
+}
+
+static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+       struct zd_usb *usb;
+       struct zd_usb_rx *rx;
+       const u8 *buffer;
+       unsigned int length;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ESHUTDOWN:
+       case -EINVAL:
+       case -ENODEV:
+       case -ENOENT:
+       case -ECONNRESET:
+               return;
+       case -EPIPE:
+               usb_clear_halt(urb->dev, EP_DATA_IN);
+               /* FALL-THROUGH */
+       default:
+               dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+               goto resubmit;
+       }
+
+       buffer = urb->transfer_buffer;
+       length = urb->actual_length;
+       usb = urb->context;
+       rx = &usb->rx;
+
+       if (length%rx->usb_packet_size > rx->usb_packet_size-4) {
+               /* If there is an old first fragment, we don't care. */
+               dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
+               ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
+               spin_lock(&rx->lock);
+               memcpy(rx->fragment, buffer, length);
+               rx->fragment_length = length;
+               spin_unlock(&rx->lock);
+               goto resubmit;
+       }
+
+       spin_lock(&rx->lock);
+       if (rx->fragment_length > 0) {
+               /* We are on a second fragment, we believe */
+               ZD_ASSERT(length + rx->fragment_length <=
+                         ARRAY_SIZE(rx->fragment));
+               dev_dbg_f(urb_dev(urb), "*** second fragment ***\n");
+               memcpy(rx->fragment+rx->fragment_length, buffer, length);
+               handle_rx_packet(usb, rx->fragment,
+                                rx->fragment_length + length);
+               rx->fragment_length = 0;
+               spin_unlock(&rx->lock);
+       } else {
+               spin_unlock(&rx->lock);
+               handle_rx_packet(usb, buffer, length);
+       }
+
+resubmit:
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+struct urb *alloc_urb(struct zd_usb *usb)
+{
+       struct usb_device *udev = zd_usb_to_usbdev(usb);
+       struct urb *urb;
+       void *buffer;
+
+       urb = usb_alloc_urb(0, GFP_NOFS);
+       if (!urb)
+               return NULL;
+       buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+                                 &urb->transfer_dma);
+       if (!buffer) {
+               usb_free_urb(urb);
+               return NULL;
+       }
+
+       usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
+                         buffer, USB_MAX_RX_SIZE,
+                         rx_urb_complete, usb);
+       urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       return urb;
+}
+
+void free_urb(struct urb *urb)
+{
+       if (!urb)
+               return;
+       usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+                       urb->transfer_buffer, urb->transfer_dma);
+       usb_free_urb(urb);
+}
+
+int zd_usb_enable_rx(struct zd_usb *usb)
+{
+       int i, r;
+       struct zd_usb_rx *rx = &usb->rx;
+       struct urb **urbs;
+
+       dev_dbg_f(zd_usb_dev(usb), "\n");
+
+       r = -ENOMEM;
+       urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+       if (!urbs)
+               goto error;
+       for (i = 0; i < URBS_COUNT; i++) {
+               urbs[i] = alloc_urb(usb);
+               if (!urbs[i])
+                       goto error;
+       }
+
+       ZD_ASSERT(!irqs_disabled());
+       spin_lock_irq(&rx->lock);
+       if (rx->urbs) {
+               spin_unlock_irq(&rx->lock);
+               r = 0;
+               goto error;
+       }
+       rx->urbs = urbs;
+       rx->urbs_count = URBS_COUNT;
+       spin_unlock_irq(&rx->lock);
+
+       for (i = 0; i < URBS_COUNT; i++) {
+               r = usb_submit_urb(urbs[i], GFP_NOFS);
+               if (r)
+                       goto error_submit;
+       }
+
+       return 0;
+error_submit:
+       for (i = 0; i < URBS_COUNT; i++) {
+               usb_kill_urb(urbs[i]);
+       }
+       spin_lock_irq(&rx->lock);
+       rx->urbs = NULL;
+       rx->urbs_count = 0;
+       spin_unlock_irq(&rx->lock);
+error:
+       if (urbs) {
+               for (i = 0; i < URBS_COUNT; i++)
+                       free_urb(urbs[i]);
+       }
+       return r;
+}
+
+void zd_usb_disable_rx(struct zd_usb *usb)
+{
+       int i;
+       unsigned long flags;
+       struct urb **urbs;
+       unsigned int count;
+       struct zd_usb_rx *rx = &usb->rx;
+
+       spin_lock_irqsave(&rx->lock, flags);
+       urbs = rx->urbs;
+       count = rx->urbs_count;
+       spin_unlock_irqrestore(&rx->lock, flags);
+       if (!urbs)
+               return;
+
+       for (i = 0; i < count; i++) {
+               usb_kill_urb(urbs[i]);
+               free_urb(urbs[i]);
+       }
+       kfree(urbs);
+
+       spin_lock_irqsave(&rx->lock, flags);
+       rx->urbs = NULL;
+       rx->urbs_count = 0;
+       spin_unlock_irqrestore(&rx->lock, flags);
+}
+
+static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+       int r;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ESHUTDOWN:
+       case -EINVAL:
+       case -ENODEV:
+       case -ENOENT:
+       case -ECONNRESET:
+               dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+               break;
+       case -EPIPE:
+               usb_clear_halt(urb->dev, EP_DATA_OUT);
+               /* FALL-THROUGH */
+       default:
+               dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+               goto resubmit;
+       }
+free_urb:
+       usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+                       urb->transfer_buffer, urb->transfer_dma);
+       usb_free_urb(urb);
+       return;
+resubmit:
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r) {
+               dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
+               goto free_urb;
+       }
+}
+
+/* Puts the frame on the USB endpoint. It doesn't wait for
+ * completion. The frame must contain the control set.
+ */
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
+{
+       int r;
+       struct usb_device *udev = zd_usb_to_usbdev(usb);
+       struct urb *urb;
+       void *buffer;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
+                                 &urb->transfer_dma);
+       if (!buffer) {
+               r = -ENOMEM;
+               goto error_free_urb;
+       }
+       memcpy(buffer, frame, length);
+
+       usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
+                         buffer, length, tx_urb_complete, NULL);
+       urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       r = usb_submit_urb(urb, GFP_ATOMIC);
+       if (r)
+               goto error;
+       return 0;
+error:
+       usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
+                       urb->transfer_dma);
+error_free_urb:
+       usb_free_urb(urb);
+out:
+       return r;
+}
+
+static inline void init_usb_interrupt(struct zd_usb *usb)
+{
+       struct zd_usb_interrupt *intr = &usb->intr;
+
+       spin_lock_init(&intr->lock);
+       intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
+       init_completion(&intr->read_regs.completion);
+       intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+}
+
+static inline void init_usb_rx(struct zd_usb *usb)
+{
+       struct zd_usb_rx *rx = &usb->rx;
+       spin_lock_init(&rx->lock);
+       if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {
+               rx->usb_packet_size = 512;
+       } else {
+               rx->usb_packet_size = 64;
+       }
+       ZD_ASSERT(rx->fragment_length == 0);
+}
+
+static inline void init_usb_tx(struct zd_usb *usb)
+{
+       /* FIXME: at this point we will allocate a fixed number of urb's for
+        * use in a cyclic scheme */
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+                struct usb_interface *intf)
+{
+       memset(usb, 0, sizeof(*usb));
+       usb->intf = usb_get_intf(intf);
+       usb_set_intfdata(usb->intf, netdev);
+       init_usb_interrupt(usb);
+       init_usb_tx(usb);
+       init_usb_rx(usb);
+}
+
+int zd_usb_init_hw(struct zd_usb *usb)
+{
+       int r;
+       struct zd_chip *chip = zd_usb_to_chip(usb);
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread16_locked(chip, &usb->fw_base_offset,
+                       USB_REG((u16)FW_BASE_ADDR_OFFSET));
+       if (r)
+               return r;
+       dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
+                usb->fw_base_offset);
+
+       return 0;
+}
+
+void zd_usb_clear(struct zd_usb *usb)
+{
+       usb_set_intfdata(usb->intf, NULL);
+       usb_put_intf(usb->intf);
+       memset(usb, 0, sizeof(*usb));
+       /* FIXME: usb_interrupt, usb_tx, usb_rx? */
+}
+
+static const char *speed(enum usb_device_speed speed)
+{
+       switch (speed) {
+       case USB_SPEED_LOW:
+               return "low";
+       case USB_SPEED_FULL:
+               return "full";
+       case USB_SPEED_HIGH:
+               return "high";
+       default:
+               return "unknown speed";
+       }
+}
+
+static int scnprint_id(struct usb_device *udev, char *buffer, size_t size)
+{
+       return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
+               get_bcdDevice(udev),
+               speed(udev->speed));
+}
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size)
+{
+       struct usb_device *udev = interface_to_usbdev(usb->intf);
+       return scnprint_id(udev, buffer, size);
+}
+
+#ifdef DEBUG
+static void print_id(struct usb_device *udev)
+{
+       char buffer[40];
+
+       scnprint_id(udev, buffer, sizeof(buffer));
+       buffer[sizeof(buffer)-1] = 0;
+       dev_dbg_f(&udev->dev, "%s\n", buffer);
+}
+#else
+#define print_id(udev) do { } while (0)
+#endif
+
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       int r;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct net_device *netdev = NULL;
+
+       print_id(udev);
+
+       switch (udev->speed) {
+       case USB_SPEED_LOW:
+       case USB_SPEED_FULL:
+       case USB_SPEED_HIGH:
+               break;
+       default:
+               dev_dbg_f(&intf->dev, "Unknown USB speed\n");
+               r = -ENODEV;
+               goto error;
+       }
+
+       netdev = zd_netdev_alloc(intf);
+       if (netdev == NULL) {
+               r = -ENOMEM;
+               goto error;
+       }
+
+       r = upload_firmware(udev, id->driver_info);
+       if (r) {
+               dev_err(&intf->dev,
+                      "couldn't load firmware. Error number %d\n", r);
+               goto error;
+       }
+
+       r = usb_reset_configuration(udev);
+       if (r) {
+               dev_dbg_f(&intf->dev,
+                       "couldn't reset configuration. Error number %d\n", r);
+               goto error;
+       }
+
+       /* At this point the interrupt endpoint is not generally enabled. We
+        * save the USB bandwidth until the network device is opened. But
+        * notify that the initialization of the MAC will require the
+        * interrupts to be temporary enabled.
+        */
+       r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
+       if (r) {
+               dev_dbg_f(&intf->dev,
+                        "couldn't initialize mac. Error number %d\n", r);
+               goto error;
+       }
+
+       r = register_netdev(netdev);
+       if (r) {
+               dev_dbg_f(&intf->dev,
+                        "couldn't register netdev. Error number %d\n", r);
+               goto error;
+       }
+
+       dev_dbg_f(&intf->dev, "successful\n");
+       dev_info(&intf->dev,"%s\n", netdev->name);
+       return 0;
+error:
+       usb_reset_device(interface_to_usbdev(intf));
+       zd_netdev_free(netdev);
+       return r;
+}
+
+static void disconnect(struct usb_interface *intf)
+{
+       struct net_device *netdev = zd_intf_to_netdev(intf);
+       struct zd_mac *mac = zd_netdev_mac(netdev);
+       struct zd_usb *usb = &mac->chip.usb;
+
+       dev_dbg_f(zd_usb_dev(usb), "\n");
+
+       zd_netdev_disconnect(netdev);
+
+       /* Just in case something has gone wrong! */
+       zd_usb_disable_rx(usb);
+       zd_usb_disable_int(usb);
+
+       /* If the disconnect has been caused by a removal of the
+        * driver module, the reset allows reloading of the driver. If the
+        * reset will not be executed here, the upload of the firmware in the
+        * probe function caused by the reloading of the driver will fail.
+        */
+       usb_reset_device(interface_to_usbdev(intf));
+
+       /* If somebody still waits on this lock now, this is an error. */
+       zd_netdev_free(netdev);
+       dev_dbg(&intf->dev, "disconnected\n");
+}
+
+static struct usb_driver driver = {
+       .name           = "zd1211rw",
+       .id_table       = usb_ids,
+       .probe          = probe,
+       .disconnect     = disconnect,
+};
+
+static int __init usb_init(void)
+{
+       int r;
+
+       pr_debug("usb_init()\n");
+
+       r = usb_register(&driver);
+       if (r) {
+               printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
+               return r;
+       }
+
+       pr_debug("zd1211rw initialized\n");
+       return 0;
+}
+
+static void __exit usb_exit(void)
+{
+       pr_debug("usb_exit()\n");
+       usb_deregister(&driver);
+}
+
+module_init(usb_init);
+module_exit(usb_exit);
+
+static int usb_int_regs_length(unsigned int count)
+{
+       return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
+}
+
+static void prepare_read_regs_int(struct zd_usb *usb)
+{
+       struct zd_usb_interrupt *intr = &usb->intr;
+
+       spin_lock(&intr->lock);
+       intr->read_regs_enabled = 1;
+       INIT_COMPLETION(intr->read_regs.completion);
+       spin_unlock(&intr->lock);
+}
+
+static int get_results(struct zd_usb *usb, u16 *values,
+                      struct usb_req_read_regs *req, unsigned int count)
+{
+       int r;
+       int i;
+       struct zd_usb_interrupt *intr = &usb->intr;
+       struct read_regs_int *rr = &intr->read_regs;
+       struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
+
+       spin_lock(&intr->lock);
+
+       r = -EIO;
+       /* The created block size seems to be larger than expected.
+        * However results appear to be correct.
+        */
+       if (rr->length < usb_int_regs_length(count)) {
+               dev_dbg_f(zd_usb_dev(usb),
+                        "error: actual length %d less than expected %d\n",
+                        rr->length, usb_int_regs_length(count));
+               goto error_unlock;
+       }
+       if (rr->length > sizeof(rr->buffer)) {
+               dev_dbg_f(zd_usb_dev(usb),
+                        "error: actual length %d exceeds buffer size %zu\n",
+                        rr->length, sizeof(rr->buffer));
+               goto error_unlock;
+       }
+
+       for (i = 0; i < count; i++) {
+               struct reg_data *rd = &regs->regs[i];
+               if (rd->addr != req->addr[i]) {
+                       dev_dbg_f(zd_usb_dev(usb),
+                                "rd[%d] addr %#06hx expected %#06hx\n", i,
+                                le16_to_cpu(rd->addr),
+                                le16_to_cpu(req->addr[i]));
+                       goto error_unlock;
+               }
+               values[i] = le16_to_cpu(rd->value);
+       }
+
+       r = 0;
+error_unlock:
+       spin_unlock(&intr->lock);
+       return r;
+}
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+                    const zd_addr_t *addresses, unsigned int count)
+{
+       int r;
+       int i, req_len, actual_req_len;
+       struct usb_device *udev;
+       struct usb_req_read_regs *req = NULL;
+       unsigned long timeout;
+
+       if (count < 1) {
+               dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
+               return -EINVAL;
+       }
+       if (count > USB_MAX_IOREAD16_COUNT) {
+               dev_dbg_f(zd_usb_dev(usb),
+                        "error: count %u exceeds possible max %u\n",
+                        count, USB_MAX_IOREAD16_COUNT);
+               return -EINVAL;
+       }
+       if (in_atomic()) {
+               dev_dbg_f(zd_usb_dev(usb),
+                        "error: io in atomic context not supported\n");
+               return -EWOULDBLOCK;
+       }
+       if (!usb_int_enabled(usb)) {
+                dev_dbg_f(zd_usb_dev(usb),
+                         "error: usb interrupt not enabled\n");
+               return -EWOULDBLOCK;
+       }
+
+       req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
+       req = kmalloc(req_len, GFP_NOFS);
+       if (!req)
+               return -ENOMEM;
+       req->id = cpu_to_le16(USB_REQ_READ_REGS);
+       for (i = 0; i < count; i++)
+               req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+
+       udev = zd_usb_to_usbdev(usb);
+       prepare_read_regs_int(usb);
+       r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+                        req, req_len, &actual_req_len, 1000 /* ms */);
+       if (r) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error in usb_bulk_msg(). Error number %d\n", r);
+               goto error;
+       }
+       if (req_len != actual_req_len) {
+               dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"
+                       " req_len %d != actual_req_len %d\n",
+                       req_len, actual_req_len);
+               r = -EIO;
+               goto error;
+       }
+
+       timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,
+                                             msecs_to_jiffies(1000));
+       if (!timeout) {
+               disable_read_regs_int(usb);
+               dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
+               r = -ETIMEDOUT;
+               goto error;
+       }
+
+       r = get_results(usb, values, req, count);
+error:
+       kfree(req);
+       return r;
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+                     unsigned int count)
+{
+       int r;
+       struct usb_device *udev;
+       struct usb_req_write_regs *req = NULL;
+       int i, req_len, actual_req_len;
+
+       if (count == 0)
+               return 0;
+       if (count > USB_MAX_IOWRITE16_COUNT) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: count %u exceeds possible max %u\n",
+                       count, USB_MAX_IOWRITE16_COUNT);
+               return -EINVAL;
+       }
+       if (in_atomic()) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: io in atomic context not supported\n");
+               return -EWOULDBLOCK;
+       }
+
+       req_len = sizeof(struct usb_req_write_regs) +
+                 count * sizeof(struct reg_data);
+       req = kmalloc(req_len, GFP_NOFS);
+       if (!req)
+               return -ENOMEM;
+
+       req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
+       for (i = 0; i < count; i++) {
+               struct reg_data *rw  = &req->reg_writes[i];
+               rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+               rw->value = cpu_to_le16(ioreqs[i].value);
+       }
+
+       udev = zd_usb_to_usbdev(usb);
+       r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+                        req, req_len, &actual_req_len, 1000 /* ms */);
+       if (r) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error in usb_bulk_msg(). Error number %d\n", r);
+               goto error;
+       }
+       if (req_len != actual_req_len) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error in usb_bulk_msg()"
+                       " req_len %d != actual_req_len %d\n",
+                       req_len, actual_req_len);
+               r = -EIO;
+               goto error;
+       }
+
+       /* FALL-THROUGH with r == 0 */
+error:
+       kfree(req);
+       return r;
+}
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
+{
+       int r;
+       struct usb_device *udev;
+       struct usb_req_rfwrite *req = NULL;
+       int i, req_len, actual_req_len;
+       u16 bit_value_template;
+
+       if (in_atomic()) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: io in atomic context not supported\n");
+               return -EWOULDBLOCK;
+       }
+       if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: bits %d are smaller than"
+                       " USB_MIN_RFWRITE_BIT_COUNT %d\n",
+                       bits, USB_MIN_RFWRITE_BIT_COUNT);
+               return -EINVAL;
+       }
+       if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
+                       bits, USB_MAX_RFWRITE_BIT_COUNT);
+               return -EINVAL;
+       }
+#ifdef DEBUG
+       if (value & (~0UL << bits)) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error: value %#09x has bits >= %d set\n",
+                       value, bits);
+               return -EINVAL;
+       }
+#endif /* DEBUG */
+
+       dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
+
+       r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+       if (r) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error %d: Couldn't read CR203\n", r);
+               goto out;
+       }
+       bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
+
+       req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
+       req = kmalloc(req_len, GFP_NOFS);
+       if (!req)
+               return -ENOMEM;
+
+       req->id = cpu_to_le16(USB_REQ_WRITE_RF);
+       /* 1: 3683a, but not used in ZYDAS driver */
+       req->value = cpu_to_le16(2);
+       req->bits = cpu_to_le16(bits);
+
+       for (i = 0; i < bits; i++) {
+               u16 bv = bit_value_template;
+               if (value & (1 << (bits-1-i)))
+                       bv |= RF_DATA;
+               req->bit_values[i] = cpu_to_le16(bv);
+       }
+
+       udev = zd_usb_to_usbdev(usb);
+       r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+                        req, req_len, &actual_req_len, 1000 /* ms */);
+       if (r) {
+               dev_dbg_f(zd_usb_dev(usb),
+                       "error in usb_bulk_msg(). Error number %d\n", r);
+               goto out;
+       }
+       if (req_len != actual_req_len) {
+               dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"
+                       " req_len %d != actual_req_len %d\n",
+                       req_len, actual_req_len);
+               r = -EIO;
+               goto out;
+       }
+
+       /* FALL-THROUGH with r == 0 */
+out:
+       kfree(req);
+       return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
new file mode 100644 (file)
index 0000000..d642028
--- /dev/null
@@ -0,0 +1,240 @@
+/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_USB_H
+#define _ZD_USB_H
+
+#include <linux/completion.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+
+#include "zd_def.h"
+#include "zd_types.h"
+
+enum devicetype {
+       DEVICE_ZD1211  = 0,
+       DEVICE_ZD1211B = 1,
+};
+
+enum endpoints {
+       EP_CTRL     = 0,
+       EP_DATA_OUT = 1,
+       EP_DATA_IN  = 2,
+       EP_INT_IN   = 3,
+       EP_REGS_OUT = 4,
+};
+
+enum {
+       USB_MAX_TRANSFER_SIZE           = 4096, /* bytes */
+       /* FIXME: The original driver uses this value. We have to check,
+        * whether the MAX_TRANSFER_SIZE is sufficient and this needs only be
+        * used if one combined frame is split over two USB transactions.
+        */
+       USB_MAX_RX_SIZE                 = 4800, /* bytes */
+       USB_MAX_IOWRITE16_COUNT         = 15,
+       USB_MAX_IOWRITE32_COUNT         = USB_MAX_IOWRITE16_COUNT/2,
+       USB_MAX_IOREAD16_COUNT          = 15,
+       USB_MAX_IOREAD32_COUNT          = USB_MAX_IOREAD16_COUNT/2,
+       USB_MIN_RFWRITE_BIT_COUNT       = 16,
+       USB_MAX_RFWRITE_BIT_COUNT       = 28,
+       USB_MAX_EP_INT_BUFFER           = 64,
+       USB_ZD1211B_BCD_DEVICE          = 0x4810,
+};
+
+enum control_requests {
+       USB_REQ_WRITE_REGS              = 0x21,
+       USB_REQ_READ_REGS               = 0x22,
+       USB_REQ_WRITE_RF                = 0x23,
+       USB_REQ_PROG_FLASH              = 0x24,
+       USB_REQ_EEPROM_START            = 0x0128, /* ? request is a byte */
+       USB_REQ_EEPROM_MID              = 0x28,
+       USB_REQ_EEPROM_END              = 0x0228, /* ? request is a byte */
+       USB_REQ_FIRMWARE_DOWNLOAD       = 0x30,
+       USB_REQ_FIRMWARE_CONFIRM        = 0x31,
+       USB_REQ_FIRMWARE_READ_DATA      = 0x32,
+};
+
+struct usb_req_read_regs {
+       __le16 id;
+       __le16 addr[0];
+} __attribute__((packed));
+
+struct reg_data {
+       __le16 addr;
+       __le16 value;
+} __attribute__((packed));
+
+struct usb_req_write_regs {
+       __le16 id;
+       struct reg_data reg_writes[0];
+} __attribute__((packed));
+
+enum {
+       RF_IF_LE = 0x02,
+       RF_CLK   = 0x04,
+       RF_DATA  = 0x08,
+};
+
+struct usb_req_rfwrite {
+       __le16 id;
+       __le16 value;
+       /* 1: 3683a */
+       /* 2: other (default) */
+       __le16 bits;
+       /* RF2595: 24 */
+       __le16 bit_values[0];
+       /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+} __attribute__((packed));
+
+/* USB interrupt */
+
+enum usb_int_id {
+       USB_INT_TYPE                    = 0x01,
+       USB_INT_ID_REGS                 = 0x90,
+       USB_INT_ID_RETRY_FAILED         = 0xa0,
+};
+
+enum usb_int_flags {
+       USB_INT_READ_REGS_EN            = 0x01,
+};
+
+struct usb_int_header {
+       u8 type;        /* must always be 1 */
+       u8 id;
+} __attribute__((packed));
+
+struct usb_int_regs {
+       struct usb_int_header hdr;
+       struct reg_data regs[0];
+} __attribute__((packed));
+
+struct usb_int_retry_fail {
+       struct usb_int_header hdr;
+       u8 new_rate;
+       u8 _dummy;
+       u8 addr[ETH_ALEN];
+       u8 ibss_wakeup_dest;
+} __attribute__((packed));
+
+struct read_regs_int {
+       struct completion completion;
+       /* Stores the USB int structure and contains the USB address of the
+        * first requested register before request.
+        */
+       u8 buffer[USB_MAX_EP_INT_BUFFER];
+       int length;
+       __le16 cr_int_addr;
+};
+
+struct zd_ioreq16 {
+       zd_addr_t addr;
+       u16 value;
+};
+
+struct zd_ioreq32 {
+       zd_addr_t addr;
+       u32 value;
+};
+
+struct zd_usb_interrupt {
+       struct read_regs_int read_regs;
+       spinlock_t lock;
+       struct urb *urb;
+       int interval;
+       u8 read_regs_enabled:1;
+};
+
+static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
+{
+       return (struct usb_int_regs *)intr->read_regs.buffer;
+}
+
+#define URBS_COUNT 5
+
+struct zd_usb_rx {
+       spinlock_t lock;
+       u8 fragment[2*USB_MAX_RX_SIZE];
+       unsigned int fragment_length;
+       unsigned int usb_packet_size;
+       struct urb **urbs;
+       int urbs_count;
+};
+
+struct zd_usb_tx {
+       spinlock_t lock;
+};
+
+/* Contains the usb parts. The structure doesn't require a lock, because intf
+ * and fw_base_offset, will not be changed after initialization.
+ */
+struct zd_usb {
+       struct zd_usb_interrupt intr;
+       struct zd_usb_rx rx;
+       struct zd_usb_tx tx;
+       struct usb_interface *intf;
+       u16 fw_base_offset;
+};
+
+#define zd_usb_dev(usb) (&usb->intf->dev)
+
+static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
+{
+       return interface_to_usbdev(usb->intf);
+}
+
+static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
+{
+       return usb_get_intfdata(intf);
+}
+
+static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
+{
+       return zd_intf_to_netdev(usb->intf);
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+                struct usb_interface *intf);
+int zd_usb_init_hw(struct zd_usb *usb);
+void zd_usb_clear(struct zd_usb *usb);
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size);
+
+int zd_usb_enable_int(struct zd_usb *usb);
+void zd_usb_disable_int(struct zd_usb *usb);
+
+int zd_usb_enable_rx(struct zd_usb *usb);
+void zd_usb_disable_rx(struct zd_usb *usb);
+
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+                const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
+                             const zd_addr_t addr)
+{
+       return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+                     unsigned int count);
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+
+#endif /* _ZD_USB_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
new file mode 100644 (file)
index 0000000..d20036c
--- /dev/null
@@ -0,0 +1,82 @@
+/* zd_util.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Utility program
+ */
+
+#include "zd_def.h"
+#include "zd_util.h"
+
+#ifdef DEBUG
+static char hex(u8 v)
+{
+       v &= 0xf;
+       return (v < 10 ? '0' : 'a' - 10) + v;
+}
+
+static char hex_print(u8 c)
+{
+       return (0x20 <= c && c < 0x7f) ? c : '.';
+}
+
+static void dump_line(const u8 *bytes, size_t size)
+{
+       char c;
+       size_t i;
+
+       size = size <= 8 ? size : 8;
+       printk(KERN_DEBUG "zd1211 %p ", bytes);
+       for (i = 0; i < 8; i++) {
+               switch (i) {
+               case 1:
+               case 5:
+                       c = '.';
+                       break;
+               case 3:
+                       c = ':';
+                       break;
+               default:
+                       c = ' ';
+               }
+               if (i < size) {
+                       printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
+               } else {
+                       printk("  %c", c);
+               }
+       }
+
+       for (i = 0; i < size; i++)
+               printk("%c", hex_print(bytes[i]));
+       printk("\n");
+}
+
+void zd_hexdump(const void *bytes, size_t size)
+{
+       size_t i = 0;
+
+       do {
+               dump_line((u8 *)bytes + i, size-i);
+               i += 8;
+       } while (i < size);
+}
+#endif /* DEBUG */
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
+{
+       if (buffer_size < tail_size)
+               return NULL;
+       return (u8 *)buffer + (buffer_size - tail_size);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h
new file mode 100644 (file)
index 0000000..ce26f7a
--- /dev/null
@@ -0,0 +1,29 @@
+/* zd_util.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ZD_UTIL_H
+#define _ZD_UTIL_H
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
+
+#ifdef DEBUG
+void zd_hexdump(const void *bytes, size_t size);
+#else
+#define zd_hexdump(bytes, size)
+#endif /* DEBUG */
+
+#endif /* _ZD_UTIL_H */
index bbbf7e2..8459a18 100644 (file)
 
        Support and updates available at
        http://www.scyld.com/network/yellowfin.html
+       [link no longer provides useful info -jgarzik]
 
-
-       Linux kernel changelog:
-       -----------------------
-
-       LK1.1.1 (jgarzik): Port to 2.4 kernel
-
-       LK1.1.2 (jgarzik):
-       * Merge in becker version 1.05
-
-       LK1.1.3 (jgarzik):
-       * Various cleanups
-       * Update yellowfin_timer to correctly calculate duplex.
-       (suggested by Manfred Spraul)
-
-       LK1.1.4 (val@nmt.edu):
-       * Fix three endian-ness bugs
-       * Support dual function SYM53C885E ethernet chip
-       
-       LK1.1.5 (val@nmt.edu):
-       * Fix forced full-duplex bug I introduced
-
-       LK1.1.6 (val@nmt.edu):
-       * Only print warning on truly "oversized" packets
-       * Fix theoretical bug on gigabit cards - return to 1.1.3 behavior
-       
 */
 
 #define DRV_NAME       "yellowfin"
-#define DRV_VERSION    "1.05+LK1.1.6"
-#define DRV_RELDATE    "Feb 11, 2002"
+#define DRV_VERSION    "2.0"
+#define DRV_RELDATE    "Jun 27, 2006"
 
 #define PFX DRV_NAME ": "
 
@@ -239,8 +215,11 @@ enum capability_flags {
        HasMACAddrBug=32, /* Only on early revs.  */
        DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
 };
+
 /* The PCI I/O space extent. */
-#define YELLOWFIN_SIZE 0x100
+enum {
+       YELLOWFIN_SIZE  = 0x100,
+};
 
 struct pci_id_info {
         const char *name;
@@ -248,16 +227,14 @@ struct pci_id_info {
                 int     pci, pci_mask, subsystem, subsystem_mask;
                 int revision, revision_mask;                            /* Only 8 bits. */
         } id;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
         int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 
 static const struct pci_id_info pci_id_tbl[] = {
        {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
-        YELLOWFIN_SIZE,
         FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
        {"Symbios SYM83C885", { 0x07011000, 0xffffffff},
-        YELLOWFIN_SIZE, HasMII | DontUseEeprom },
+         HasMII | DontUseEeprom },
        { }
 };
 
index 15f6cd4..77e7202 100644 (file)
@@ -1052,7 +1052,7 @@ static void ahci_thaw(struct ata_port *ap)
 
 static void ahci_error_handler(struct ata_port *ap)
 {
-       if (!(ap->flags & ATA_FLAG_FROZEN)) {
+       if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                /* restart engine */
                ahci_stop_engine(ap);
                ahci_start_engine(ap);
@@ -1323,6 +1323,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
 
+       /* JMicron-specific fixup: make sure we're in AHCI mode */
+       /* This is protected from races with ata_jmicron by the pci probe
+          locking */
+       if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+               /* AHCI enable, AHCI on function 0 */
+               pci_write_config_byte(pdev, 0x41, 0xa1);
+               /* Function 1 is the PATA controller */
+               if (PCI_FUNC(pdev->devfn))
+                       return -ENODEV;
+       }
+
        rc = pci_enable_device(pdev);
        if (rc)
                return rc;
@@ -1378,10 +1389,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (have_msi)
                hpriv->flags |= AHCI_FLAG_MSI;
 
-       /* JMicron-specific fixup: make sure we're in AHCI mode */
-       if (pdev->vendor == 0x197b)
-               pci_write_config_byte(pdev, 0x41, 0xa1);
-
        /* initialize adapter */
        rc = ahci_host_init(probe_ent);
        if (rc)
index 1c960ac..386e5f2 100644 (file)
@@ -61,9 +61,9 @@
 #include "libata.h"
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[]             = {   5,  100, 2000 };
-const unsigned long sata_deb_timing_eh[]               = {  25,  500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[]     = { 100, 2000, 5000 };
+const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
+const unsigned long sata_deb_timing_hotplug[]          = {  25,  500, 2000 };
+const unsigned long sata_deb_timing_long[]             = { 100, 2000, 5000 };
 
 static unsigned int ata_dev_init_params(struct ata_device *dev,
                                        u16 heads, u16 sectors);
@@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
 {
        int rc;
 
-       if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+       if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
                return;
 
        PREPARE_WORK(&ap->port_task, fn, data);
@@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap)
        DPRINTK("ENTER\n");
 
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+       ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
        spin_unlock_irqrestore(ap->lock, flags);
 
        DPRINTK("flush #1\n");
@@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap)
        }
 
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+       ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
        spin_unlock_irqrestore(ap->lock, flags);
 
        if (ata_msg_ctl(ap))
@@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
        spin_lock_irqsave(ap->lock, flags);
 
        /* no internal command while frozen */
-       if (ap->flags & ATA_FLAG_FROZEN) {
+       if (ap->pflags & ATA_PFLAG_FROZEN) {
                spin_unlock_irqrestore(ap->lock, flags);
                return AC_ERR_SYSTEM;
        }
@@ -1325,6 +1325,19 @@ static void ata_dev_config_ncq(struct ata_device *dev,
                snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
 }
 
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+       int i;
+
+       if (ap->host) {
+               ap->host->max_cmd_len = 0;
+               for (i = 0; i < ATA_MAX_DEVICES; i++)
+                       ap->host->max_cmd_len = max_t(unsigned int,
+                                                     ap->host->max_cmd_len,
+                                                     ap->device[i].cdb_len);
+       }
+}
+
 /**
  *     ata_dev_configure - Configure the specified ATA/ATAPI device
  *     @dev: Target device to configure
@@ -1344,7 +1357,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
        struct ata_port *ap = dev->ap;
        const u16 *id = dev->id;
        unsigned int xfer_mask;
-       int i, rc;
+       int rc;
 
        if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
                ata_dev_printk(dev, KERN_INFO,
@@ -1404,7 +1417,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                        ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
                        /* print device info to dmesg */
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
                                        "max %s, %Lu sectors: %s %s\n",
                                        ata_id_major_version(id),
@@ -1427,7 +1440,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                        }
 
                        /* print device info to dmesg */
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
                                        "max %s, %Lu sectors: CHS %u/%u/%u\n",
                                        ata_id_major_version(id),
@@ -1439,7 +1452,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
 
                if (dev->id[59] & 0x100) {
                        dev->multi_count = dev->id[59] & 0xff;
-                       if (ata_msg_info(ap))
+                       if (ata_msg_drv(ap) && print_info)
                                ata_dev_printk(dev, KERN_INFO,
                                        "ata%u: dev %u multi count %u\n",
                                        ap->id, dev->devno, dev->multi_count);
@@ -1468,21 +1481,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
                }
 
                /* print device info to dmesg */
-               if (ata_msg_info(ap))
+               if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
                                       ata_mode_string(xfer_mask),
                                       cdb_intr_string);
        }
 
-       ap->host->max_cmd_len = 0;
-       for (i = 0; i < ATA_MAX_DEVICES; i++)
-               ap->host->max_cmd_len = max_t(unsigned int,
-                                             ap->host->max_cmd_len,
-                                             ap->device[i].cdb_len);
+       ata_set_port_max_cmd_len(ap);
 
        /* limit bridge transfers to udma5, 200 sectors */
        if (ata_dev_knobble(dev)) {
-               if (ata_msg_info(ap))
+               if (ata_msg_drv(ap) && print_info)
                        ata_dev_printk(dev, KERN_INFO,
                                       "applying bridge limits\n");
                dev->udma_mask &= ATA_UDMA5;
@@ -2137,7 +2146,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
                 * return error code and failing device on failure.
                 */
                for (i = 0; i < ATA_MAX_DEVICES; i++) {
-                       if (ata_dev_enabled(&ap->device[i])) {
+                       if (ata_dev_ready(&ap->device[i])) {
                                ap->ops->set_mode(ap);
                                break;
                        }
@@ -2203,7 +2212,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
                dev = &ap->device[i];
 
-               if (!ata_dev_enabled(dev))
+               /* don't udpate suspended devices' xfer mode */
+               if (!ata_dev_ready(dev))
                        continue;
 
                rc = ata_dev_set_mode(dev);
@@ -2579,7 +2589,7 @@ static void ata_wait_spinup(struct ata_port *ap)
 
        /* first, debounce phy if SATA */
        if (ap->cbl == ATA_CBL_SATA) {
-               rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+               rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
 
                /* if debounced successfully and offline, no need to wait */
                if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@@ -2615,16 +2625,17 @@ static void ata_wait_spinup(struct ata_port *ap)
 int ata_std_prereset(struct ata_port *ap)
 {
        struct ata_eh_context *ehc = &ap->eh_context;
-       const unsigned long *timing;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
        int rc;
 
-       /* hotplug? */
-       if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
-               if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
-                       ehc->i.action |= ATA_EH_HARDRESET;
-               if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
-                       ata_wait_spinup(ap);
-       }
+       /* handle link resume & hotplug spinup */
+       if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+           (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+               ehc->i.action |= ATA_EH_HARDRESET;
+
+       if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+           (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+               ata_wait_spinup(ap);
 
        /* if we're about to do hardreset, nothing more to do */
        if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2632,11 +2643,6 @@ int ata_std_prereset(struct ata_port *ap)
 
        /* if SATA, resume phy */
        if (ap->cbl == ATA_CBL_SATA) {
-               if (ap->flags & ATA_FLAG_LOADING)
-                       timing = sata_deb_timing_boot;
-               else
-                       timing = sata_deb_timing_eh;
-
                rc = sata_phy_resume(ap, timing);
                if (rc && rc != -EOPNOTSUPP) {
                        /* phy resume failed */
@@ -2724,6 +2730,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
  */
 int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
 {
+       struct ata_eh_context *ehc = &ap->eh_context;
+       const unsigned long *timing = sata_ehc_deb_timing(ehc);
        u32 scontrol;
        int rc;
 
@@ -2761,7 +2769,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
        msleep(1);
 
        /* bring phy back */
-       sata_phy_resume(ap, sata_deb_timing_eh);
+       sata_phy_resume(ap, timing);
 
        /* TODO: phy layer with polling, timeouts, etc. */
        if (ata_port_offline(ap)) {
@@ -4285,7 +4293,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
        unsigned int i;
 
        /* no command while frozen */
-       if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+       if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
                return NULL;
 
        /* the last tag is reserved for internal command. */
@@ -4407,7 +4415,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
         * taken care of.
         */
        if (ap->ops->error_handler) {
-               WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+               WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
 
                if (unlikely(qc->err_mask))
                        qc->flags |= ATA_QCFLAG_FAILED;
@@ -5001,86 +5009,120 @@ int ata_flush_cache(struct ata_device *dev)
        return 0;
 }
 
-static int ata_standby_drive(struct ata_device *dev)
+static int ata_host_set_request_pm(struct ata_host_set *host_set,
+                                  pm_message_t mesg, unsigned int action,
+                                  unsigned int ehi_flags, int wait)
 {
-       unsigned int err_mask;
+       unsigned long flags;
+       int i, rc;
 
-       err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
-       if (err_mask) {
-               ata_dev_printk(dev, KERN_ERR, "failed to standby drive "
-                              "(err_mask=0x%x)\n", err_mask);
-               return -EIO;
-       }
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
 
-       return 0;
-}
+               /* Previous resume operation might still be in
+                * progress.  Wait for PM_PENDING to clear.
+                */
+               if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+                       ata_port_wait_eh(ap);
+                       WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+               }
 
-static int ata_start_drive(struct ata_device *dev)
-{
-       unsigned int err_mask;
+               /* request PM ops to EH */
+               spin_lock_irqsave(ap->lock, flags);
 
-       err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
-       if (err_mask) {
-               ata_dev_printk(dev, KERN_ERR, "failed to start drive "
-                              "(err_mask=0x%x)\n", err_mask);
-               return -EIO;
+               ap->pm_mesg = mesg;
+               if (wait) {
+                       rc = 0;
+                       ap->pm_result = &rc;
+               }
+
+               ap->pflags |= ATA_PFLAG_PM_PENDING;
+               ap->eh_info.action |= action;
+               ap->eh_info.flags |= ehi_flags;
+
+               ata_port_schedule_eh(ap);
+
+               spin_unlock_irqrestore(ap->lock, flags);
+
+               /* wait and check result */
+               if (wait) {
+                       ata_port_wait_eh(ap);
+                       WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+                       if (rc)
+                               return rc;
+               }
        }
 
        return 0;
 }
 
 /**
- *     ata_device_resume - wakeup a previously suspended devices
- *     @dev: the device to resume
+ *     ata_host_set_suspend - suspend host_set
+ *     @host_set: host_set to suspend
+ *     @mesg: PM message
  *
- *     Kick the drive back into action, by sending it an idle immediate
- *     command and making sure its transfer mode matches between drive
- *     and host.
+ *     Suspend @host_set.  Actual operation is performed by EH.  This
+ *     function requests EH to perform PM operations and waits for EH
+ *     to finish.
  *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
  */
-int ata_device_resume(struct ata_device *dev)
+int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg)
 {
-       struct ata_port *ap = dev->ap;
+       int i, j, rc;
 
-       if (ap->flags & ATA_FLAG_SUSPENDED) {
-               struct ata_device *failed_dev;
+       rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1);
+       if (rc)
+               goto fail;
 
-               ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
-               ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+       /* EH is quiescent now.  Fail if we have any ready device.
+        * This happens if hotplug occurs between completion of device
+        * suspension and here.
+        */
+       for (i = 0; i < host_set->n_ports; i++) {
+               struct ata_port *ap = host_set->ports[i];
 
-               ap->flags &= ~ATA_FLAG_SUSPENDED;
-               while (ata_set_mode(ap, &failed_dev))
-                       ata_dev_disable(failed_dev);
+               for (j = 0; j < ATA_MAX_DEVICES; j++) {
+                       struct ata_device *dev = &ap->device[j];
+
+                       if (ata_dev_ready(dev)) {
+                               ata_port_printk(ap, KERN_WARNING,
+                                               "suspend failed, device %d "
+                                               "still active\n", dev->devno);
+                               rc = -EBUSY;
+                               goto fail;
+                       }
+               }
        }
-       if (!ata_dev_enabled(dev))
-               return 0;
-       if (dev->class == ATA_DEV_ATA)
-               ata_start_drive(dev);
 
+       host_set->dev->power.power_state = mesg;
        return 0;
+
+ fail:
+       ata_host_set_resume(host_set);
+       return rc;
 }
 
 /**
- *     ata_device_suspend - prepare a device for suspend
- *     @dev: the device to suspend
- *     @state: target power management state
+ *     ata_host_set_resume - resume host_set
+ *     @host_set: host_set to resume
+ *
+ *     Resume @host_set.  Actual operation is performed by EH.  This
+ *     function requests EH to perform PM operations and returns.
+ *     Note that all resume operations are performed parallely.
  *
- *     Flush the cache on the drive, if appropriate, then issue a
- *     standbynow command.
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
  */
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+void ata_host_set_resume(struct ata_host_set *host_set)
 {
-       struct ata_port *ap = dev->ap;
-
-       if (!ata_dev_enabled(dev))
-               return 0;
-       if (dev->class == ATA_DEV_ATA)
-               ata_flush_cache(dev);
-
-       if (state.event != PM_EVENT_FREEZE)
-               ata_standby_drive(dev);
-       ap->flags |= ATA_FLAG_SUSPENDED;
-       return 0;
+       ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET,
+                               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+       host_set->dev->power.power_state = PMSG_ON;
 }
 
 /**
@@ -5440,6 +5482,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
                }
 
                if (ap->ops->error_handler) {
+                       struct ata_eh_info *ehi = &ap->eh_info;
                        unsigned long flags;
 
                        ata_port_probe(ap);
@@ -5447,10 +5490,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
                        /* kick EH for boot probing */
                        spin_lock_irqsave(ap->lock, flags);
 
-                       ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
-                       ap->eh_info.action |= ATA_EH_SOFTRESET;
+                       ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+                       ehi->action |= ATA_EH_SOFTRESET;
+                       ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
-                       ap->flags |= ATA_FLAG_LOADING;
+                       ap->pflags |= ATA_PFLAG_LOADING;
                        ata_port_schedule_eh(ap);
 
                        spin_unlock_irqrestore(ap->lock, flags);
@@ -5518,7 +5562,7 @@ void ata_port_detach(struct ata_port *ap)
 
        /* tell EH we're leaving & flush EH */
        spin_lock_irqsave(ap->lock, flags);
-       ap->flags |= ATA_FLAG_UNLOADING;
+       ap->pflags |= ATA_PFLAG_UNLOADING;
        spin_unlock_irqrestore(ap->lock, flags);
 
        ata_port_wait_eh(ap);
@@ -5723,20 +5767,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
        return (tmp == bits->val) ? 1 : 0;
 }
 
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       return 0;
+
+       if (state.event == PM_EVENT_SUSPEND) {
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 }
 
-int ata_pci_device_resume(struct pci_dev *pdev)
+void ata_pci_device_do_resume(struct pci_dev *pdev)
 {
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        pci_enable_device(pdev);
        pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+       int rc = 0;
+
+       rc = ata_host_set_suspend(host_set, state);
+       if (rc)
+               return rc;
+
+       if (host_set->next) {
+               rc = ata_host_set_suspend(host_set->next, state);
+               if (rc) {
+                       ata_host_set_resume(host_set);
+                       return rc;
+               }
+       }
+
+       ata_pci_device_do_suspend(pdev, state);
+
+       return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+       ata_pci_device_do_resume(pdev);
+       ata_host_set_resume(host_set);
+       if (host_set->next)
+               ata_host_set_resume(host_set->next);
+
        return 0;
 }
 #endif /* CONFIG_PCI */
@@ -5842,9 +5921,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
  * Do not depend on ABI/API stability.
  */
 
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
 EXPORT_SYMBOL_GPL(ata_std_bios_param);
 EXPORT_SYMBOL_GPL(ata_std_ports);
 EXPORT_SYMBOL_GPL(ata_device_add);
@@ -5916,6 +5995,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
 EXPORT_SYMBOL_GPL(sata_scr_write_flush);
 EXPORT_SYMBOL_GPL(ata_port_online);
 EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_set_suspend);
+EXPORT_SYMBOL_GPL(ata_host_set_resume);
 EXPORT_SYMBOL_GPL(ata_id_string);
 EXPORT_SYMBOL_GPL(ata_id_c_string);
 EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -5930,14 +6011,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
 EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
 EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
 EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
 EXPORT_SYMBOL_GPL(ata_pci_device_resume);
 EXPORT_SYMBOL_GPL(ata_pci_default_filter);
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
 EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
 EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
 
index bf5a72a..4b6aa30 100644 (file)
@@ -47,6 +47,8 @@
 
 static void __ata_port_freeze(struct ata_port *ap);
 static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_port_suspend(struct ata_port *ap);
+static void ata_eh_handle_port_resume(struct ata_port *ap);
 
 static void ata_ering_record(struct ata_ering *ering, int is_io,
                             unsigned int err_mask)
@@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
 void ata_scsi_error(struct Scsi_Host *host)
 {
        struct ata_port *ap = ata_shost_to_port(host);
-       spinlock_t *ap_lock = ap->lock;
        int i, repeat_cnt = ATA_EH_MAX_REPEAT;
        unsigned long flags;
 
@@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host)
                struct scsi_cmnd *scmd, *tmp;
                int nr_timedout = 0;
 
-               spin_lock_irqsave(ap_lock, flags);
+               spin_lock_irqsave(ap->lock, flags);
 
                list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
                        struct ata_queued_cmd *qc;
@@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host)
                if (nr_timedout)
                        __ata_port_freeze(ap);
 
-               spin_unlock_irqrestore(ap_lock, flags);
+               spin_unlock_irqrestore(ap->lock, flags);
        } else
-               spin_unlock_wait(ap_lock);
+               spin_unlock_wait(ap->lock);
 
  repeat:
        /* invoke error handler */
        if (ap->ops->error_handler) {
+               /* process port resume request */
+               ata_eh_handle_port_resume(ap);
+
                /* fetch & clear EH info */
-               spin_lock_irqsave(ap_lock, flags);
+               spin_lock_irqsave(ap->lock, flags);
 
                memset(&ap->eh_context, 0, sizeof(ap->eh_context));
                ap->eh_context.i = ap->eh_info;
                memset(&ap->eh_info, 0, sizeof(ap->eh_info));
 
-               ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
-               ap->flags &= ~ATA_FLAG_EH_PENDING;
+               ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+               ap->pflags &= ~ATA_PFLAG_EH_PENDING;
 
-               spin_unlock_irqrestore(ap_lock, flags);
+               spin_unlock_irqrestore(ap->lock, flags);
 
-               /* invoke EH.  if unloading, just finish failed qcs */
-               if (!(ap->flags & ATA_FLAG_UNLOADING))
+               /* invoke EH, skip if unloading or suspended */
+               if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
                        ap->ops->error_handler(ap);
                else
                        ata_eh_finish(ap);
 
+               /* process port suspend request */
+               ata_eh_handle_port_suspend(ap);
+
                /* Exception might have happend after ->error_handler
                 * recovered the port but before this point.  Repeat
                 * EH in such case.
                 */
-               spin_lock_irqsave(ap_lock, flags);
+               spin_lock_irqsave(ap->lock, flags);
 
-               if (ap->flags & ATA_FLAG_EH_PENDING) {
+               if (ap->pflags & ATA_PFLAG_EH_PENDING) {
                        if (--repeat_cnt) {
                                ata_port_printk(ap, KERN_INFO,
                                        "EH pending after completion, "
                                        "repeating EH (cnt=%d)\n", repeat_cnt);
-                               spin_unlock_irqrestore(ap_lock, flags);
+                               spin_unlock_irqrestore(ap->lock, flags);
                                goto repeat;
                        }
                        ata_port_printk(ap, KERN_ERR, "EH pending after %d "
@@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host)
                /* this run is complete, make sure EH info is clear */
                memset(&ap->eh_info, 0, sizeof(ap->eh_info));
 
-               /* Clear host_eh_scheduled while holding ap_lock such
+               /* Clear host_eh_scheduled while holding ap->lock such
                 * that if exception occurs after this point but
                 * before EH completion, SCSI midlayer will
                 * re-initiate EH.
                 */
                host->host_eh_scheduled = 0;
 
-               spin_unlock_irqrestore(ap_lock, flags);
+               spin_unlock_irqrestore(ap->lock, flags);
        } else {
                WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
                ap->ops->eng_timeout(ap);
@@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host)
        scsi_eh_flush_done_q(&ap->eh_done_q);
 
        /* clean up */
-       spin_lock_irqsave(ap_lock, flags);
+       spin_lock_irqsave(ap->lock, flags);
 
-       if (ap->flags & ATA_FLAG_LOADING) {
-               ap->flags &= ~ATA_FLAG_LOADING;
-       } else {
-               if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
-                       queue_work(ata_aux_wq, &ap->hotplug_task);
-               if (ap->flags & ATA_FLAG_RECOVERED)
-                       ata_port_printk(ap, KERN_INFO, "EH complete\n");
-       }
+       if (ap->pflags & ATA_PFLAG_LOADING)
+               ap->pflags &= ~ATA_PFLAG_LOADING;
+       else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+               queue_work(ata_aux_wq, &ap->hotplug_task);
+
+       if (ap->pflags & ATA_PFLAG_RECOVERED)
+               ata_port_printk(ap, KERN_INFO, "EH complete\n");
 
-       ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
+       ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
 
        /* tell wait_eh that we're done */
-       ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
+       ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
        wake_up_all(&ap->eh_wait_q);
 
-       spin_unlock_irqrestore(ap_lock, flags);
+       spin_unlock_irqrestore(ap->lock, flags);
 
        DPRINTK("EXIT\n");
 }
@@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap)
  retry:
        spin_lock_irqsave(ap->lock, flags);
 
-       while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
+       while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
                prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
                spin_unlock_irqrestore(ap->lock, flags);
                schedule();
@@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
        WARN_ON(!ap->ops->error_handler);
 
        qc->flags |= ATA_QCFLAG_FAILED;
-       qc->ap->flags |= ATA_FLAG_EH_PENDING;
+       qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
 
        /* The following will fail if timeout has already expired.
         * ata_scsi_error() takes care of such scmds on EH entry.
@@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
 {
        WARN_ON(!ap->ops->error_handler);
 
-       ap->flags |= ATA_FLAG_EH_PENDING;
+       ap->pflags |= ATA_PFLAG_EH_PENDING;
        scsi_schedule_eh(ap->host);
 
        DPRINTK("port EH scheduled\n");
@@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap)
        if (ap->ops->freeze)
                ap->ops->freeze(ap);
 
-       ap->flags |= ATA_FLAG_FROZEN;
+       ap->pflags |= ATA_PFLAG_FROZEN;
 
        DPRINTK("ata%u port frozen\n", ap->id);
 }
@@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
 
        spin_lock_irqsave(ap->lock, flags);
 
-       ap->flags &= ~ATA_FLAG_FROZEN;
+       ap->pflags &= ~ATA_PFLAG_FROZEN;
 
        if (ap->ops->thaw)
                ap->ops->thaw(ap);
@@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev)
 
        if (ata_scsi_offline_dev(dev)) {
                dev->flags |= ATA_DFLAG_DETACHED;
-               ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+               ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
        }
 
        /* clear per-dev EH actions */
@@ -760,8 +766,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
        unsigned long flags;
 
        spin_lock_irqsave(ap->lock, flags);
+
        ata_eh_clear_action(dev, &ap->eh_info, action);
-       ap->flags |= ATA_FLAG_RECOVERED;
+
+       if (!(ap->eh_context.i.flags & ATA_EHI_QUIET))
+               ap->pflags |= ATA_PFLAG_RECOVERED;
+
        spin_unlock_irqrestore(ap->lock, flags);
 }
 
@@ -1027,7 +1037,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
        int tag, rc;
 
        /* if frozen, we can't do much */
-       if (ap->flags & ATA_FLAG_FROZEN)
+       if (ap->pflags & ATA_PFLAG_FROZEN)
                return;
 
        /* is it NCQ device error? */
@@ -1275,6 +1285,9 @@ static void ata_eh_autopsy(struct ata_port *ap)
 
        DPRINTK("ENTER\n");
 
+       if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+               return;
+
        /* obtain and analyze SError */
        rc = sata_scr_read(ap, SCR_ERROR, &serror);
        if (rc == 0) {
@@ -1327,7 +1340,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
        }
 
        /* enforce default EH actions */
-       if (ap->flags & ATA_FLAG_FROZEN ||
+       if (ap->pflags & ATA_PFLAG_FROZEN ||
            all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
                action |= ATA_EH_SOFTRESET;
        else if (all_err_mask)
@@ -1346,7 +1359,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
 
        /* record autopsy result */
        ehc->i.dev = failed_dev;
-       ehc->i.action = action;
+       ehc->i.action |= action;
 
        DPRINTK("EXIT\n");
 }
@@ -1385,7 +1398,7 @@ static void ata_eh_report(struct ata_port *ap)
                return;
 
        frozen = "";
-       if (ap->flags & ATA_FLAG_FROZEN)
+       if (ap->pflags & ATA_PFLAG_FROZEN)
                frozen = " frozen";
 
        if (ehc->i.dev) {
@@ -1465,7 +1478,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        struct ata_eh_context *ehc = &ap->eh_context;
        unsigned int *classes = ehc->classes;
        int tries = ATA_EH_RESET_TRIES;
-       int verbose = !(ap->flags & ATA_FLAG_LOADING);
+       int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
        unsigned int action;
        ata_reset_fn_t reset;
        int i, did_followup_srst, rc;
@@ -1605,7 +1618,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                dev = &ap->device[i];
                action = ata_eh_dev_action(dev);
 
-               if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
+               if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
                        if (ata_port_offline(ap)) {
                                rc = -EIO;
                                break;
@@ -1636,7 +1649,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                        }
 
                        spin_lock_irqsave(ap->lock, flags);
-                       ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+                       ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
                        spin_unlock_irqrestore(ap->lock, flags);
                }
        }
@@ -1648,6 +1661,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
        return rc;
 }
 
+/**
+ *     ata_eh_suspend - handle suspend EH action
+ *     @ap: target host port
+ *     @r_failed_dev: result parameter to indicate failing device
+ *
+ *     Handle suspend EH action.  Disk devices are spinned down and
+ *     other types of devices are just marked suspended.  Once
+ *     suspended, no EH action to the device is allowed until it is
+ *     resumed.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise
+ */
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+       struct ata_device *dev;
+       int i, rc = 0;
+
+       DPRINTK("ENTER\n");
+
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               unsigned long flags;
+               unsigned int action, err_mask;
+
+               dev = &ap->device[i];
+               action = ata_eh_dev_action(dev);
+
+               if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+                       continue;
+
+               WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+
+               ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+
+               if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+                       /* flush cache */
+                       rc = ata_flush_cache(dev);
+                       if (rc)
+                               break;
+
+                       /* spin down */
+                       err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+                       if (err_mask) {
+                               ata_dev_printk(dev, KERN_ERR, "failed to "
+                                              "spin down (err_mask=0x%x)\n",
+                                              err_mask);
+                               rc = -EIO;
+                               break;
+                       }
+               }
+
+               spin_lock_irqsave(ap->lock, flags);
+               dev->flags |= ATA_DFLAG_SUSPENDED;
+               spin_unlock_irqrestore(ap->lock, flags);
+
+               ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+       }
+
+       if (rc)
+               *r_failed_dev = dev;
+
+       DPRINTK("EXIT\n");
+       return 0;
+}
+
+/**
+ *     ata_eh_prep_resume - prep for resume EH action
+ *     @ap: target host port
+ *
+ *     Clear SUSPENDED in preparation for scheduled resume actions.
+ *     This allows other parts of EH to access the devices being
+ *     resumed.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+static void ata_eh_prep_resume(struct ata_port *ap)
+{
+       struct ata_device *dev;
+       unsigned long flags;
+       int i;
+
+       DPRINTK("ENTER\n");
+
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               unsigned int action;
+
+               dev = &ap->device[i];
+               action = ata_eh_dev_action(dev);
+
+               if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+                       continue;
+
+               spin_lock_irqsave(ap->lock, flags);
+               dev->flags &= ~ATA_DFLAG_SUSPENDED;
+               spin_unlock_irqrestore(ap->lock, flags);
+       }
+
+       DPRINTK("EXIT\n");
+}
+
+/**
+ *     ata_eh_resume - handle resume EH action
+ *     @ap: target host port
+ *     @r_failed_dev: result parameter to indicate failing device
+ *
+ *     Handle resume EH action.  Target devices are already reset and
+ *     revalidated.  Spinning up is the only operation left.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise
+ */
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+       struct ata_device *dev;
+       int i, rc = 0;
+
+       DPRINTK("ENTER\n");
+
+       for (i = 0; i < ATA_MAX_DEVICES; i++) {
+               unsigned int action, err_mask;
+
+               dev = &ap->device[i];
+               action = ata_eh_dev_action(dev);
+
+               if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+                       continue;
+
+               ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+
+               if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+                       err_mask = ata_do_simple_cmd(dev,
+                                                    ATA_CMD_IDLEIMMEDIATE);
+                       if (err_mask) {
+                               ata_dev_printk(dev, KERN_ERR, "failed to "
+                                              "spin up (err_mask=0x%x)\n",
+                                              err_mask);
+                               rc = -EIO;
+                               break;
+                       }
+               }
+
+               ata_eh_done(ap, dev, ATA_EH_RESUME);
+       }
+
+       if (rc)
+               *r_failed_dev = dev;
+
+       DPRINTK("EXIT\n");
+       return 0;
+}
+
 static int ata_port_nr_enabled(struct ata_port *ap)
 {
        int i, cnt = 0;
@@ -1673,7 +1844,19 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
        struct ata_eh_context *ehc = &ap->eh_context;
        int i;
 
-       if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+       /* skip if all possible devices are suspended */
+       for (i = 0; i < ata_port_max_devices(ap); i++) {
+               struct ata_device *dev = &ap->device[i];
+
+               if (ata_dev_absent(dev) || ata_dev_ready(dev))
+                       break;
+       }
+
+       if (i == ata_port_max_devices(ap))
+               return 1;
+
+       /* always thaw frozen port and recover failed devices */
+       if (ap->pflags & ATA_PFLAG_FROZEN || ata_port_nr_enabled(ap))
                return 0;
 
        /* skip if class codes for all vacant slots are ATA_DEV_NONE */
@@ -1744,9 +1927,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        rc = 0;
 
        /* if UNLOADING, finish immediately */
-       if (ap->flags & ATA_FLAG_UNLOADING)
+       if (ap->pflags & ATA_PFLAG_UNLOADING)
                goto out;
 
+       /* prep for resume */
+       ata_eh_prep_resume(ap);
+
        /* skip EH if possible. */
        if (ata_eh_skip_recovery(ap))
                ehc->i.action = 0;
@@ -1774,6 +1960,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        if (rc)
                goto dev_fail;
 
+       /* resume devices */
+       rc = ata_eh_resume(ap, &dev);
+       if (rc)
+               goto dev_fail;
+
        /* configure transfer mode if the port has been reset */
        if (ehc->i.flags & ATA_EHI_DID_RESET) {
                rc = ata_set_mode(ap, &dev);
@@ -1783,6 +1974,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                }
        }
 
+       /* suspend devices */
+       rc = ata_eh_suspend(ap, &dev);
+       if (rc)
+               goto dev_fail;
+
        goto out;
 
  dev_fail:
@@ -1908,11 +2104,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
               ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
               ata_postreset_fn_t postreset)
 {
-       if (!(ap->flags & ATA_FLAG_LOADING)) {
-               ata_eh_autopsy(ap);
-               ata_eh_report(ap);
-       }
-
+       ata_eh_autopsy(ap);
+       ata_eh_report(ap);
        ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
        ata_eh_finish(ap);
 }
+
+/**
+ *     ata_eh_handle_port_suspend - perform port suspend operation
+ *     @ap: port to suspend
+ *
+ *     Suspend @ap.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{
+       unsigned long flags;
+       int rc = 0;
+
+       /* are we suspending? */
+       spin_lock_irqsave(ap->lock, flags);
+       if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+           ap->pm_mesg.event == PM_EVENT_ON) {
+               spin_unlock_irqrestore(ap->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+
+       /* suspend */
+       ata_eh_freeze_port(ap);
+
+       if (ap->ops->port_suspend)
+               rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+
+       /* report result */
+       spin_lock_irqsave(ap->lock, flags);
+
+       ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+       if (rc == 0)
+               ap->pflags |= ATA_PFLAG_SUSPENDED;
+       else
+               ata_port_schedule_eh(ap);
+
+       if (ap->pm_result) {
+               *ap->pm_result = rc;
+               ap->pm_result = NULL;
+       }
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       return;
+}
+
+/**
+ *     ata_eh_handle_port_resume - perform port resume operation
+ *     @ap: port to resume
+ *
+ *     Resume @ap.
+ *
+ *     This function also waits upto one second until all devices
+ *     hanging off this port requests resume EH action.  This is to
+ *     prevent invoking EH and thus reset multiple times on resume.
+ *
+ *     On DPM resume, where some of devices might not be resumed
+ *     together, this may delay port resume upto one second, but such
+ *     DPM resumes are rare and 1 sec delay isn't too bad.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{
+       unsigned long timeout;
+       unsigned long flags;
+       int i, rc = 0;
+
+       /* are we resuming? */
+       spin_lock_irqsave(ap->lock, flags);
+       if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+           ap->pm_mesg.event != PM_EVENT_ON) {
+               spin_unlock_irqrestore(ap->lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       /* spurious? */
+       if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+               goto done;
+
+       if (ap->ops->port_resume)
+               rc = ap->ops->port_resume(ap);
+
+       /* give devices time to request EH */
+       timeout = jiffies + HZ; /* 1s max */
+       while (1) {
+               for (i = 0; i < ATA_MAX_DEVICES; i++) {
+                       struct ata_device *dev = &ap->device[i];
+                       unsigned int action = ata_eh_dev_action(dev);
+
+                       if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+                           !(action & ATA_EH_RESUME))
+                               break;
+               }
+
+               if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+                       break;
+               msleep(10);
+       }
+
+ done:
+       spin_lock_irqsave(ap->lock, flags);
+       ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+       if (ap->pm_result) {
+               *ap->pm_result = rc;
+               ap->pm_result = NULL;
+       }
+       spin_unlock_irqrestore(ap->lock, flags);
+}
index 2915bca..7ced41e 100644 (file)
@@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
        }
 }
 
-int ata_scsi_device_resume(struct scsi_device *sdev)
+/**
+ *     ata_scsi_device_suspend - suspend ATA device associated with sdev
+ *     @sdev: the SCSI device to suspend
+ *     @state: target power management state
+ *
+ *     Request suspend EH action on the ATA device associated with
+ *     @sdev and wait for the operation to complete.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0 on success, -errno otherwise.
+ */
+int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
-       struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+       struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+       unsigned long flags;
+       unsigned int action;
+       int rc = 0;
+
+       if (!dev)
+               goto out;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       /* wait for the previous resume to complete */
+       while (dev->flags & ATA_DFLAG_SUSPENDED) {
+               spin_unlock_irqrestore(ap->lock, flags);
+               ata_port_wait_eh(ap);
+               spin_lock_irqsave(ap->lock, flags);
+       }
+
+       /* if @sdev is already detached, nothing to do */
+       if (sdev->sdev_state == SDEV_OFFLINE ||
+           sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+               goto out_unlock;
+
+       /* request suspend */
+       action = ATA_EH_SUSPEND;
+       if (state.event != PM_EVENT_SUSPEND)
+               action |= ATA_EH_PM_FREEZE;
+       ap->eh_info.dev_action[dev->devno] |= action;
+       ap->eh_info.flags |= ATA_EHI_QUIET;
+       ata_port_schedule_eh(ap);
+
+       spin_unlock_irqrestore(ap->lock, flags);
+
+       /* wait for EH to do the job */
+       ata_port_wait_eh(ap);
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       /* If @sdev is still attached but the associated ATA device
+        * isn't suspended, the operation failed.
+        */
+       if (sdev->sdev_state != SDEV_OFFLINE &&
+           sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+           !(dev->flags & ATA_DFLAG_SUSPENDED))
+               rc = -EIO;
 
-       return ata_device_resume(dev);
+ out_unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+ out:
+       if (rc == 0)
+               sdev->sdev_gendev.power.power_state = state;
+       return rc;
 }
 
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+/**
+ *     ata_scsi_device_resume - resume ATA device associated with sdev
+ *     @sdev: the SCSI device to resume
+ *
+ *     Request resume EH action on the ATA device associated with
+ *     @sdev and return immediately.  This enables parallel
+ *     wakeup/spinup of devices.
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ *
+ *     RETURNS:
+ *     0.
+ */
+int ata_scsi_device_resume(struct scsi_device *sdev)
 {
        struct ata_port *ap = ata_shost_to_port(sdev->host);
-       struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+       struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+       struct ata_eh_info *ehi = &ap->eh_info;
+       unsigned long flags;
+       unsigned int action;
+
+       if (!dev)
+               goto out;
+
+       spin_lock_irqsave(ap->lock, flags);
+
+       /* if @sdev is already detached, nothing to do */
+       if (sdev->sdev_state == SDEV_OFFLINE ||
+           sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+               goto out_unlock;
 
-       return ata_device_suspend(dev, state);
+       /* request resume */
+       action = ATA_EH_RESUME;
+       if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+               __ata_ehi_hotplugged(ehi);
+       else
+               action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+       ehi->dev_action[dev->devno] |= action;
+
+       /* We don't want autopsy and verbose EH messages.  Disable
+        * those if we're the only device on this link.
+        */
+       if (ata_port_max_devices(ap) == 1)
+               ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+       ata_port_schedule_eh(ap);
+
+ out_unlock:
+       spin_unlock_irqrestore(ap->lock, flags);
+ out:
+       sdev->sdev_gendev.power.power_state = PMSG_ON;
+       return 0;
 }
 
 /**
@@ -2930,7 +3039,7 @@ void ata_scsi_hotplug(void *data)
        struct ata_port *ap = data;
        int i;
 
-       if (ap->flags & ATA_FLAG_UNLOADING) {
+       if (ap->pflags & ATA_PFLAG_UNLOADING) {
                DPRINTK("ENTER/EXIT - unloading\n");
                return;
        }
@@ -3011,6 +3120,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
                if (dev) {
                        ap->eh_info.probe_mask |= 1 << dev->devno;
                        ap->eh_info.action |= ATA_EH_SOFTRESET;
+                       ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
                } else
                        rc = -EINVAL;
        }
index 7aabb45..d0a8507 100644 (file)
@@ -109,6 +109,7 @@ enum {
 };
 
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil_pci_device_resume(struct pci_dev *pdev);
 static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
 static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = {
        .id_table               = sil_pci_tbl,
        .probe                  = sil_init_one,
        .remove                 = ata_pci_remove_one,
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = sil_pci_device_resume,
 };
 
 static struct scsi_host_template sil_sht = {
@@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
+       .suspend                = ata_scsi_device_suspend,
+       .resume                 = ata_scsi_device_resume,
 };
 
 static const struct ata_port_operations sil_ops = {
@@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
                 * during hardreset makes controllers with broken SIEN
                 * repeat probing needlessly.
                 */
-               if (!(ap->flags & ATA_FLAG_FROZEN)) {
+               if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
                        ata_ehi_hotplugged(&ap->eh_info);
                        ap->eh_info.serror |= serror;
                }
@@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
        }
 }
 
+static void sil_init_controller(struct pci_dev *pdev,
+                               int n_ports, unsigned long host_flags,
+                               void __iomem *mmio_base)
+{
+       u8 cls;
+       u32 tmp;
+       int i;
+
+       /* Initialize FIFO PCI bus arbitration */
+       cls = sil_get_device_cache_line(pdev);
+       if (cls) {
+               cls >>= 3;
+               cls++;  /* cls = (line_size/8)+1 */
+               for (i = 0; i < n_ports; i++)
+                       writew(cls << 8 | cls,
+                              mmio_base + sil_port[i].fifo_cfg);
+       } else
+               dev_printk(KERN_WARNING, &pdev->dev,
+                          "cache line size not set.  Driver may not function\n");
+
+       /* Apply R_ERR on DMA activate FIS errata workaround */
+       if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+               int cnt;
+
+               for (i = 0, cnt = 0; i < n_ports; i++) {
+                       tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+                       if ((tmp & 0x3) != 0x01)
+                               continue;
+                       if (!cnt)
+                               dev_printk(KERN_INFO, &pdev->dev,
+                                          "Applying R_ERR on DMA activate "
+                                          "FIS errata fix\n");
+                       writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+                       cnt++;
+               }
+       }
+
+       if (n_ports == 4) {
+               /* flip the magic "make 4 ports work" bit */
+               tmp = readl(mmio_base + sil_port[2].bmdma);
+               if ((tmp & SIL_INTR_STEERING) == 0)
+                       writel(tmp | SIL_INTR_STEERING,
+                              mmio_base + sil_port[2].bmdma);
+       }
+}
+
 static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version;
@@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        int rc;
        unsigned int i;
        int pci_dev_busy = 0;
-       u32 tmp;
-       u8 cls;
 
        if (!printed_version++)
                dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                ata_std_ports(&probe_ent->port[i]);
        }
 
-       /* Initialize FIFO PCI bus arbitration */
-       cls = sil_get_device_cache_line(pdev);
-       if (cls) {
-               cls >>= 3;
-               cls++;  /* cls = (line_size/8)+1 */
-               for (i = 0; i < probe_ent->n_ports; i++)
-                       writew(cls << 8 | cls,
-                              mmio_base + sil_port[i].fifo_cfg);
-       } else
-               dev_printk(KERN_WARNING, &pdev->dev,
-                          "cache line size not set.  Driver may not function\n");
-
-       /* Apply R_ERR on DMA activate FIS errata workaround */
-       if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
-               int cnt;
-
-               for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
-                       tmp = readl(mmio_base + sil_port[i].sfis_cfg);
-                       if ((tmp & 0x3) != 0x01)
-                               continue;
-                       if (!cnt)
-                               dev_printk(KERN_INFO, &pdev->dev,
-                                          "Applying R_ERR on DMA activate "
-                                          "FIS errata fix\n");
-                       writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
-                       cnt++;
-               }
-       }
-
-       if (ent->driver_data == sil_3114) {
-               /* flip the magic "make 4 ports work" bit */
-               tmp = readl(mmio_base + sil_port[2].bmdma);
-               if ((tmp & SIL_INTR_STEERING) == 0)
-                       writel(tmp | SIL_INTR_STEERING,
-                              mmio_base + sil_port[2].bmdma);
-       }
+       sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+                           mmio_base);
 
        pci_set_master(pdev);
 
@@ -685,6 +700,18 @@ err_out:
        return rc;
 }
 
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+
+       ata_pci_device_do_resume(pdev);
+       sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags,
+                           host_set->mmio_base);
+       ata_host_set_resume(host_set);
+
+       return 0;
+}
+
 static int __init sil_init(void)
 {
        return pci_module_init(&sil_pci_driver);
index 07a1c6a..2e0f4a4 100644 (file)
@@ -92,6 +92,7 @@ enum {
        HOST_CTRL_STOP          = (1 << 18), /* latched PCI STOP */
        HOST_CTRL_DEVSEL        = (1 << 19), /* latched PCI DEVSEL */
        HOST_CTRL_REQ64         = (1 << 20), /* latched PCI REQ64 */
+       HOST_CTRL_GLOBAL_RST    = (1 << 31), /* global reset */
 
        /*
         * Port registers
@@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap);
 static void sil24_port_stop(struct ata_port *ap);
 static void sil24_host_stop(struct ata_host_set *host_set);
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static int sil24_pci_device_resume(struct pci_dev *pdev);
 
 static const struct pci_device_id sil24_pci_tbl[] = {
        { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = {
        .id_table               = sil24_pci_tbl,
        .probe                  = sil24_init_one,
        .remove                 = ata_pci_remove_one, /* safe? */
+       .suspend                = ata_pci_device_suspend,
+       .resume                 = sil24_pci_device_resume,
 };
 
 static struct scsi_host_template sil24_sht = {
@@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = {
        .slave_configure        = ata_scsi_slave_config,
        .slave_destroy          = ata_scsi_slave_destroy,
        .bios_param             = ata_std_bios_param,
+       .suspend                = ata_scsi_device_suspend,
+       .resume                 = ata_scsi_device_resume,
 };
 
 static const struct ata_port_operations sil24_ops = {
@@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
        /* SStatus oscillates between zero and valid status after
         * DEV_RST, debounce it.
         */
-       rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+       rc = sata_phy_debounce(ap, sata_deb_timing_long);
        if (rc) {
                reason = "PHY debouncing failed";
                goto err;
@@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set)
        kfree(hpriv);
 }
 
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+                                 unsigned long host_flags,
+                                 void __iomem *host_base,
+                                 void __iomem *port_base)
+{
+       u32 tmp;
+       int i;
+
+       /* GPIO off */
+       writel(0, host_base + HOST_FLASH_CMD);
+
+       /* clear global reset & mask interrupts during initialization */
+       writel(0, host_base + HOST_CTRL);
+
+       /* init ports */
+       for (i = 0; i < n_ports; i++) {
+               void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+               /* Initial PHY setting */
+               writel(0x20c, port + PORT_PHY_CFG);
+
+               /* Clear port RST */
+               tmp = readl(port + PORT_CTRL_STAT);
+               if (tmp & PORT_CS_PORT_RST) {
+                       writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+                       tmp = ata_wait_register(port + PORT_CTRL_STAT,
+                                               PORT_CS_PORT_RST,
+                                               PORT_CS_PORT_RST, 10, 100);
+                       if (tmp & PORT_CS_PORT_RST)
+                               dev_printk(KERN_ERR, &pdev->dev,
+                                          "failed to clear port RST\n");
+               }
+
+               /* Configure IRQ WoC */
+               if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+               else
+                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+               /* Zero error counters. */
+               writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+               writel(0x8000, port + PORT_CRC_ERR_THRESH);
+               writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+               writel(0x0000, port + PORT_DECODE_ERR_CNT);
+               writel(0x0000, port + PORT_CRC_ERR_CNT);
+               writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+               /* Always use 64bit activation */
+               writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+               /* Clear port multiplier enable and resume bits */
+               writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+       }
+
+       /* Turn on interrupts */
+       writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        static int printed_version = 0;
@@ -1076,9 +1140,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
-       /* GPIO off */
-       writel(0, host_base + HOST_FLASH_CMD);
-
        /* Apply workaround for completion IRQ loss on PCI-X errata */
        if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
                tmp = readl(host_base + HOST_CTRL);
@@ -1090,56 +1151,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                        probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
        }
 
-       /* clear global reset & mask interrupts during initialization */
-       writel(0, host_base + HOST_CTRL);
-
        for (i = 0; i < probe_ent->n_ports; i++) {
-               void __iomem *port = port_base + i * PORT_REGS_SIZE;
-               unsigned long portu = (unsigned long)port;
+               unsigned long portu =
+                       (unsigned long)port_base + i * PORT_REGS_SIZE;
 
                probe_ent->port[i].cmd_addr = portu;
                probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
 
                ata_std_ports(&probe_ent->port[i]);
-
-               /* Initial PHY setting */
-               writel(0x20c, port + PORT_PHY_CFG);
-
-               /* Clear port RST */
-               tmp = readl(port + PORT_CTRL_STAT);
-               if (tmp & PORT_CS_PORT_RST) {
-                       writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
-                       tmp = ata_wait_register(port + PORT_CTRL_STAT,
-                                               PORT_CS_PORT_RST,
-                                               PORT_CS_PORT_RST, 10, 100);
-                       if (tmp & PORT_CS_PORT_RST)
-                               dev_printk(KERN_ERR, &pdev->dev,
-                                          "failed to clear port RST\n");
-               }
-
-               /* Configure IRQ WoC */
-               if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
-                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
-               else
-                       writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
-               /* Zero error counters. */
-               writel(0x8000, port + PORT_DECODE_ERR_THRESH);
-               writel(0x8000, port + PORT_CRC_ERR_THRESH);
-               writel(0x8000, port + PORT_HSHK_ERR_THRESH);
-               writel(0x0000, port + PORT_DECODE_ERR_CNT);
-               writel(0x0000, port + PORT_CRC_ERR_CNT);
-               writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
-               /* Always use 64bit activation */
-               writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
-               /* Clear port multiplier enable and resume bits */
-               writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
        }
 
-       /* Turn on interrupts */
-       writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+       sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags,
+                             host_base, port_base);
 
        pci_set_master(pdev);
 
@@ -1162,6 +1185,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        return rc;
 }
 
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+       struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev);
+       struct sil24_host_priv *hpriv = host_set->private_data;
+
+       ata_pci_device_do_resume(pdev);
+
+       if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+               writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+       sil24_init_controller(pdev, host_set->n_ports,
+                             host_set->ports[0]->flags,
+                             hpriv->host_base, hpriv->port_base);
+
+       ata_host_set_resume(host_set);
+
+       return 0;
+}
+
 static int __init sil24_init(void)
 {
        return pci_module_init(&sil24_pci_driver);
index 916fe6f..ad37871 100644 (file)
@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
        .bmdma_status           = ata_bmdma_status,
        .qc_prep                = ata_qc_prep,
        .qc_issue               = ata_qc_issue_prot,
-       .data_xfer              = ata_pio_data_xfer,
+       .data_xfer              = ata_mmio_data_xfer,
        .freeze                 = ata_bmdma_freeze,
        .thaw                   = ata_bmdma_thaw,
        .error_handler          = ata_bmdma_error_handler,
index a7d6643..54c6b2a 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/mach/serial_at91.h>
 #include <asm/arch/board.h>
 #include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
 
 #if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -140,9 +141,9 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
                 */
                if (port->mapbase == AT91_BASE_US0) {
                        if (mctrl & TIOCM_RTS)
-                               at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
+                               at91_set_gpio_value(AT91_PIN_PA21, 0);
                        else
-                               at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
+                               at91_set_gpio_value(AT91_PIN_PA21, 1);
                }
        }
 
index 5980c45..89ba0df 100644 (file)
@@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
        fl->fl_ops = &nlmclnt_lock_ops;
 }
 
-static void do_vfs_lock(struct file_lock *fl)
+static int do_vfs_lock(struct file_lock *fl)
 {
        int res = 0;
        switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
@@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
                default:
                        BUG();
        }
-       if (res < 0)
-               printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
-                               __FUNCTION__);
+       return res;
 }
 
 /*
@@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
        struct nlm_wait *block = NULL;
+       unsigned char fl_flags = fl->fl_flags;
        int status = -ENOLCK;
 
        if (!host->h_monitored && nsm_monitor(host) < 0) {
@@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
                                        host->h_name);
                goto out;
        }
+       fl->fl_flags |= FL_ACCESS;
+       status = do_vfs_lock(fl);
+       if (status < 0)
+               goto out;
 
        block = nlmclnt_prepare_block(host, fl);
 again:
@@ -539,9 +542,10 @@ again:
                        up_read(&host->h_rwsem);
                        goto again;
                }
-               fl->fl_flags |= FL_SLEEP;
                /* Ensure the resulting lock will get added to granted list */
-               do_vfs_lock(fl);
+               fl->fl_flags = fl_flags | FL_SLEEP;
+               if (do_vfs_lock(fl) < 0)
+                       printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
                up_read(&host->h_rwsem);
        }
        status = nlm_stat_to_errno(resp->status);
@@ -552,6 +556,7 @@ out_unblock:
                nlmclnt_cancel(host, req->a_args.block, fl);
 out:
        nlm_release_call(req);
+       fl->fl_flags = fl_flags;
        return status;
 }
 
@@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
        struct nlm_host *host = req->a_host;
        struct nlm_res  *resp = &req->a_res;
-       int             status;
+       int status = 0;
 
        /*
         * Note: the server is supposed to either grant us the unlock
         * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
         * case, we want to unlock.
         */
+       fl->fl_flags |= FL_EXISTS;
        down_read(&host->h_rwsem);
-       do_vfs_lock(fl);
+       if (do_vfs_lock(fl) == -ENOENT) {
+               up_read(&host->h_rwsem);
+               goto out;
+       }
        up_read(&host->h_rwsem);
 
        if (req->a_flags & RPC_TASK_ASYNC)
@@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
        if (status < 0)
                goto out;
 
-       status = 0;
        if (resp->status == NLM_LCK_GRANTED)
                goto out;
 
index 1ad29c9..b0b41a6 100644 (file)
@@ -725,6 +725,10 @@ next_task:
 /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
  * at the head of the list, but that's secret knowledge known only to
  * flock_lock_file and posix_lock_file.
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * whether or not a lock was successfully freed by testing the return
+ * value for -ENOENT.
  */
 static int flock_lock_file(struct file *filp, struct file_lock *request)
 {
@@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
        int found = 0;
 
        lock_kernel();
+       if (request->fl_flags & FL_ACCESS)
+               goto find_conflict;
        for_each_lock(inode, before) {
                struct file_lock *fl = *before;
                if (IS_POSIX(fl))
@@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                break;
        }
 
-       if (request->fl_type == F_UNLCK)
+       if (request->fl_type == F_UNLCK) {
+               if ((request->fl_flags & FL_EXISTS) && !found)
+                       error = -ENOENT;
                goto out;
+       }
 
        error = -ENOMEM;
        new_fl = locks_alloc_lock();
@@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
        if (found)
                cond_resched();
 
+find_conflict:
        for_each_lock(inode, before) {
                struct file_lock *fl = *before;
                if (IS_POSIX(fl))
@@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                        locks_insert_block(fl, request);
                goto out;
        }
+       if (request->fl_flags & FL_ACCESS)
+               goto out;
        locks_copy_lock(new_fl, request);
        locks_insert_lock(&inode->i_flock, new_fl);
        new_fl = NULL;
@@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
 
        error = 0;
        if (!added) {
-               if (request->fl_type == F_UNLCK)
+               if (request->fl_type == F_UNLCK) {
+                       if (request->fl_flags & FL_EXISTS)
+                               error = -ENOENT;
                        goto out;
+               }
 
                if (!new_fl) {
                        error = -ENOLCK;
@@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
  * Add a POSIX style lock to a file.
  * We merge adjacent & overlapping locks whenever possible.
  * POSIX locks are sorted by owner task, then by starting address
+ *
+ * Note that if called with an FL_EXISTS argument, the caller may determine
+ * whether or not a lock was successfully freed by testing the return
+ * value for -ENOENT.
  */
 int posix_lock_file(struct file *filp, struct file_lock *fl)
 {
index 3ddda6f..e7ffb4d 100644 (file)
@@ -690,7 +690,9 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd)
                        goto out_force;
                /* This is an open(2) */
                if (nfs_lookup_check_intent(nd, LOOKUP_OPEN) != 0 &&
-                               !(server->flags & NFS_MOUNT_NOCTO))
+                               !(server->flags & NFS_MOUNT_NOCTO) &&
+                               (S_ISREG(inode->i_mode) ||
+                                S_ISDIR(inode->i_mode)))
                        goto out_force;
        }
        return nfs_revalidate_inode(server, inode);
index 4cdd1b4..fecd3b0 100644 (file)
@@ -67,25 +67,19 @@ struct nfs_direct_req {
        struct kref             kref;           /* release manager */
 
        /* I/O parameters */
-       struct list_head        list,           /* nfs_read/write_data structs */
-                               rewrite_list;   /* saved nfs_write_data structs */
        struct nfs_open_context *ctx;           /* file open context info */
        struct kiocb *          iocb;           /* controlling i/o request */
        struct inode *          inode;          /* target file of i/o */
-       unsigned long           user_addr;      /* location of user's buffer */
-       size_t                  user_count;     /* total bytes to move */
-       loff_t                  pos;            /* starting offset in file */
-       struct page **          pages;          /* pages in our buffer */
-       unsigned int            npages;         /* count of pages */
 
        /* completion state */
+       atomic_t                io_count;       /* i/os we're waiting for */
        spinlock_t              lock;           /* protect completion state */
-       int                     outstanding;    /* i/os we're waiting for */
        ssize_t                 count,          /* bytes actually processed */
                                error;          /* any reported error */
        struct completion       completion;     /* wait for i/o completion */
 
        /* commit state */
+       struct list_head        rewrite_list;   /* saved nfs_write_data structs */
        struct nfs_write_data * commit_data;    /* special write_data for commits */
        int                     flags;
 #define NFS_ODIRECT_DO_COMMIT          (1)     /* an unstable reply was received */
@@ -93,8 +87,37 @@ struct nfs_direct_req {
        struct nfs_writeverf    verf;           /* unstable write verifier */
 };
 
-static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync);
 static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode);
+static const struct rpc_call_ops nfs_write_direct_ops;
+
+static inline void get_dreq(struct nfs_direct_req *dreq)
+{
+       atomic_inc(&dreq->io_count);
+}
+
+static inline int put_dreq(struct nfs_direct_req *dreq)
+{
+       return atomic_dec_and_test(&dreq->io_count);
+}
+
+/*
+ * "size" is never larger than rsize or wsize.
+ */
+static inline int nfs_direct_count_pages(unsigned long user_addr, size_t size)
+{
+       int page_count;
+
+       page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       page_count -= user_addr >> PAGE_SHIFT;
+       BUG_ON(page_count < 0);
+
+       return page_count;
+}
+
+static inline unsigned int nfs_max_pages(unsigned int size)
+{
+       return (size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+}
 
 /**
  * nfs_direct_IO - NFS address space operation for direct I/O
@@ -118,50 +141,21 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
        return -EINVAL;
 }
 
-static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty)
+static void nfs_direct_dirty_pages(struct page **pages, int npages)
 {
        int i;
        for (i = 0; i < npages; i++) {
                struct page *page = pages[i];
-               if (do_dirty && !PageCompound(page))
+               if (!PageCompound(page))
                        set_page_dirty_lock(page);
-               page_cache_release(page);
        }
-       kfree(pages);
 }
 
-static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages)
+static void nfs_direct_release_pages(struct page **pages, int npages)
 {
-       int result = -ENOMEM;
-       unsigned long page_count;
-       size_t array_size;
-
-       page_count = (user_addr + size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       page_count -= user_addr >> PAGE_SHIFT;
-
-       array_size = (page_count * sizeof(struct page *));
-       *pages = kmalloc(array_size, GFP_KERNEL);
-       if (*pages) {
-               down_read(&current->mm->mmap_sem);
-               result = get_user_pages(current, current->mm, user_addr,
-                                       page_count, (rw == READ), 0,
-                                       *pages, NULL);
-               up_read(&current->mm->mmap_sem);
-               if (result != page_count) {
-                       /*
-                        * If we got fewer pages than expected from
-                        * get_user_pages(), the user buffer runs off the
-                        * end of a mapping; return EFAULT.
-                        */
-                       if (result >= 0) {
-                               nfs_free_user_pages(*pages, result, 0);
-                               result = -EFAULT;
-                       } else
-                               kfree(*pages);
-                       *pages = NULL;
-               }
-       }
-       return result;
+       int i;
+       for (i = 0; i < npages; i++)
+               page_cache_release(pages[i]);
 }
 
 static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
@@ -173,13 +167,13 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
                return NULL;
 
        kref_init(&dreq->kref);
+       kref_get(&dreq->kref);
        init_completion(&dreq->completion);
-       INIT_LIST_HEAD(&dreq->list);
        INIT_LIST_HEAD(&dreq->rewrite_list);
        dreq->iocb = NULL;
        dreq->ctx = NULL;
        spin_lock_init(&dreq->lock);
-       dreq->outstanding = 0;
+       atomic_set(&dreq->io_count, 0);
        dreq->count = 0;
        dreq->error = 0;
        dreq->flags = 0;
@@ -220,18 +214,11 @@ out:
 }
 
 /*
- * We must hold a reference to all the pages in this direct read request
- * until the RPCs complete.  This could be long *after* we are woken up in
- * nfs_direct_wait (for instance, if someone hits ^C on a slow server).
- *
- * In addition, synchronous I/O uses a stack-allocated iocb.  Thus we
- * can't trust the iocb is still valid here if this is a synchronous
- * request.  If the waiter is woken prematurely, the iocb is long gone.
+ * Synchronous I/O uses a stack-allocated iocb.  Thus we can't trust
+ * the iocb is still valid here if this is a synchronous request.
  */
 static void nfs_direct_complete(struct nfs_direct_req *dreq)
 {
-       nfs_free_user_pages(dreq->pages, dreq->npages, 1);
-
        if (dreq->iocb) {
                long res = (long) dreq->error;
                if (!res)
@@ -244,48 +231,10 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
 }
 
 /*
- * Note we also set the number of requests we have in the dreq when we are
- * done.  This prevents races with I/O completion so we will always wait
- * until all requests have been dispatched and completed.
+ * We must hold a reference to all the pages in this direct read request
+ * until the RPCs complete.  This could be long *after* we are woken up in
+ * nfs_direct_wait (for instance, if someone hits ^C on a slow server).
  */
-static struct nfs_direct_req *nfs_direct_read_alloc(size_t nbytes, size_t rsize)
-{
-       struct list_head *list;
-       struct nfs_direct_req *dreq;
-       unsigned int rpages = (rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-       dreq = nfs_direct_req_alloc();
-       if (!dreq)
-               return NULL;
-
-       list = &dreq->list;
-       for(;;) {
-               struct nfs_read_data *data = nfs_readdata_alloc(rpages);
-
-               if (unlikely(!data)) {
-                       while (!list_empty(list)) {
-                               data = list_entry(list->next,
-                                                 struct nfs_read_data, pages);
-                               list_del(&data->pages);
-                               nfs_readdata_free(data);
-                       }
-                       kref_put(&dreq->kref, nfs_direct_req_release);
-                       return NULL;
-               }
-
-               INIT_LIST_HEAD(&data->pages);
-               list_add(&data->pages, list);
-
-               data->req = (struct nfs_page *) dreq;
-               dreq->outstanding++;
-               if (nbytes <= rsize)
-                       break;
-               nbytes -= rsize;
-       }
-       kref_get(&dreq->kref);
-       return dreq;
-}
-
 static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
 {
        struct nfs_read_data *data = calldata;
@@ -294,6 +243,9 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
        if (nfs_readpage_result(task, data) != 0)
                return;
 
+       nfs_direct_dirty_pages(data->pagevec, data->npages);
+       nfs_direct_release_pages(data->pagevec, data->npages);
+
        spin_lock(&dreq->lock);
 
        if (likely(task->tk_status >= 0))
@@ -301,13 +253,10 @@ static void nfs_direct_read_result(struct rpc_task *task, void *calldata)
        else
                dreq->error = task->tk_status;
 
-       if (--dreq->outstanding) {
-               spin_unlock(&dreq->lock);
-               return;
-       }
-
        spin_unlock(&dreq->lock);
-       nfs_direct_complete(dreq);
+
+       if (put_dreq(dreq))
+               nfs_direct_complete(dreq);
 }
 
 static const struct rpc_call_ops nfs_read_direct_ops = {
@@ -316,41 +265,60 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
 };
 
 /*
- * For each nfs_read_data struct that was allocated on the list, dispatch
- * an NFS READ operation
+ * For each rsize'd chunk of the user's buffer, dispatch an NFS READ
+ * operation.  If nfs_readdata_alloc() or get_user_pages() fails,
+ * bail and stop sending more reads.  Read length accounting is
+ * handled automatically by nfs_direct_read_result().  Otherwise, if
+ * no requests have been sent, just return an error.
  */
-static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
+static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
 {
        struct nfs_open_context *ctx = dreq->ctx;
        struct inode *inode = ctx->dentry->d_inode;
-       struct list_head *list = &dreq->list;
-       struct page **pages = dreq->pages;
-       size_t count = dreq->user_count;
-       loff_t pos = dreq->pos;
        size_t rsize = NFS_SERVER(inode)->rsize;
-       unsigned int curpage, pgbase;
+       unsigned int rpages = nfs_max_pages(rsize);
+       unsigned int pgbase;
+       int result;
+       ssize_t started = 0;
+
+       get_dreq(dreq);
 
-       curpage = 0;
-       pgbase = dreq->user_addr & ~PAGE_MASK;
+       pgbase = user_addr & ~PAGE_MASK;
        do {
                struct nfs_read_data *data;
                size_t bytes;
 
+               result = -ENOMEM;
+               data = nfs_readdata_alloc(rpages);
+               if (unlikely(!data))
+                       break;
+
                bytes = rsize;
                if (count < rsize)
                        bytes = count;
 
-               BUG_ON(list_empty(list));
-               data = list_entry(list->next, struct nfs_read_data, pages);
-               list_del_init(&data->pages);
+               data->npages = nfs_direct_count_pages(user_addr, bytes);
+               down_read(&current->mm->mmap_sem);
+               result = get_user_pages(current, current->mm, user_addr,
+                                       data->npages, 1, 0, data->pagevec, NULL);
+               up_read(&current->mm->mmap_sem);
+               if (unlikely(result < data->npages)) {
+                       if (result > 0)
+                               nfs_direct_release_pages(data->pagevec, result);
+                       nfs_readdata_release(data);
+                       break;
+               }
+
+               get_dreq(dreq);
 
+               data->req = (struct nfs_page *) dreq;
                data->inode = inode;
                data->cred = ctx->cred;
                data->args.fh = NFS_FH(inode);
                data->args.context = ctx;
                data->args.offset = pos;
                data->args.pgbase = pgbase;
-               data->args.pages = &pages[curpage];
+               data->args.pages = data->pagevec;
                data->args.count = bytes;
                data->res.fattr = &data->fattr;
                data->res.eof = 0;
@@ -373,33 +341,35 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq)
                                bytes,
                                (unsigned long long)data->args.offset);
 
+               started += bytes;
+               user_addr += bytes;
                pos += bytes;
                pgbase += bytes;
-               curpage += pgbase >> PAGE_SHIFT;
                pgbase &= ~PAGE_MASK;
 
                count -= bytes;
        } while (count != 0);
-       BUG_ON(!list_empty(list));
+
+       if (put_dreq(dreq))
+               nfs_direct_complete(dreq);
+
+       if (started)
+               return 0;
+       return result < 0 ? (ssize_t) result : -EFAULT;
 }
 
-static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, unsigned int nr_pages)
+static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
 {
-       ssize_t result;
+       ssize_t result = 0;
        sigset_t oldset;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct rpc_clnt *clnt = NFS_CLIENT(inode);
        struct nfs_direct_req *dreq;
 
-       dreq = nfs_direct_read_alloc(count, NFS_SERVER(inode)->rsize);
+       dreq = nfs_direct_req_alloc();
        if (!dreq)
                return -ENOMEM;
 
-       dreq->user_addr = user_addr;
-       dreq->user_count = count;
-       dreq->pos = pos;
-       dreq->pages = pages;
-       dreq->npages = nr_pages;
        dreq->inode = inode;
        dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
        if (!is_sync_kiocb(iocb))
@@ -407,8 +377,9 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
 
        nfs_add_stats(inode, NFSIOS_DIRECTREADBYTES, count);
        rpc_clnt_sigmask(clnt, &oldset);
-       nfs_direct_read_schedule(dreq);
-       result = nfs_direct_wait(dreq);
+       result = nfs_direct_read_schedule(dreq, user_addr, count, pos);
+       if (!result)
+               result = nfs_direct_wait(dreq);
        rpc_clnt_sigunmask(clnt, &oldset);
 
        return result;
@@ -416,10 +387,10 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, unsigned long user_addr, size
 
 static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
 {
-       list_splice_init(&dreq->rewrite_list, &dreq->list);
-       while (!list_empty(&dreq->list)) {
-               struct nfs_write_data *data = list_entry(dreq->list.next, struct nfs_write_data, pages);
+       while (!list_empty(&dreq->rewrite_list)) {
+               struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages);
                list_del(&data->pages);
+               nfs_direct_release_pages(data->pagevec, data->npages);
                nfs_writedata_release(data);
        }
 }
@@ -427,14 +398,51 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq)
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
 {
-       struct list_head *pos;
+       struct inode *inode = dreq->inode;
+       struct list_head *p;
+       struct nfs_write_data *data;
 
-       list_splice_init(&dreq->rewrite_list, &dreq->list);
-       list_for_each(pos, &dreq->list)
-               dreq->outstanding++;
        dreq->count = 0;
+       get_dreq(dreq);
+
+       list_for_each(p, &dreq->rewrite_list) {
+               data = list_entry(p, struct nfs_write_data, pages);
+
+               get_dreq(dreq);
+
+               /*
+                * Reset data->res.
+                */
+               nfs_fattr_init(&data->fattr);
+               data->res.count = data->args.count;
+               memset(&data->verf, 0, sizeof(data->verf));
+
+               /*
+                * Reuse data->task; data->args should not have changed
+                * since the original request was sent.
+                */
+               rpc_init_task(&data->task, NFS_CLIENT(inode), RPC_TASK_ASYNC,
+                               &nfs_write_direct_ops, data);
+               NFS_PROTO(inode)->write_setup(data, FLUSH_STABLE);
+
+               data->task.tk_priority = RPC_PRIORITY_NORMAL;
+               data->task.tk_cookie = (unsigned long) inode;
+
+               /*
+                * We're called via an RPC callback, so BKL is already held.
+                */
+               rpc_execute(&data->task);
+
+               dprintk("NFS: %5u rescheduled direct write call (req %s/%Ld, %u bytes @ offset %Lu)\n",
+                               data->task.tk_pid,
+                               inode->i_sb->s_id,
+                               (long long)NFS_FILEID(inode),
+                               data->args.count,
+                               (unsigned long long)data->args.offset);
+       }
 
-       nfs_direct_write_schedule(dreq, FLUSH_STABLE);
+       if (put_dreq(dreq))
+               nfs_direct_write_complete(dreq, inode);
 }
 
 static void nfs_direct_commit_result(struct rpc_task *task, void *calldata)
@@ -471,8 +479,8 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
        data->cred = dreq->ctx->cred;
 
        data->args.fh = NFS_FH(data->inode);
-       data->args.offset = dreq->pos;
-       data->args.count = dreq->user_count;
+       data->args.offset = 0;
+       data->args.count = 0;
        data->res.count = 0;
        data->res.fattr = &data->fattr;
        data->res.verf = &data->verf;
@@ -534,47 +542,6 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
 }
 #endif
 
-static struct nfs_direct_req *nfs_direct_write_alloc(size_t nbytes, size_t wsize)
-{
-       struct list_head *list;
-       struct nfs_direct_req *dreq;
-       unsigned int wpages = (wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
-       dreq = nfs_direct_req_alloc();
-       if (!dreq)
-               return NULL;
-
-       list = &dreq->list;
-       for(;;) {
-               struct nfs_write_data *data = nfs_writedata_alloc(wpages);
-
-               if (unlikely(!data)) {
-                       while (!list_empty(list)) {
-                               data = list_entry(list->next,
-                                                 struct nfs_write_data, pages);
-                               list_del(&data->pages);
-                               nfs_writedata_free(data);
-                       }
-                       kref_put(&dreq->kref, nfs_direct_req_release);
-                       return NULL;
-               }
-
-               INIT_LIST_HEAD(&data->pages);
-               list_add(&data->pages, list);
-
-               data->req = (struct nfs_page *) dreq;
-               dreq->outstanding++;
-               if (nbytes <= wsize)
-                       break;
-               nbytes -= wsize;
-       }
-
-       nfs_alloc_commit_data(dreq);
-
-       kref_get(&dreq->kref);
-       return dreq;
-}
-
 static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
 {
        struct nfs_write_data *data = calldata;
@@ -604,8 +571,6 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
                                }
                }
        }
-       /* In case we have to resend */
-       data->args.stable = NFS_FILE_SYNC;
 
        spin_unlock(&dreq->lock);
 }
@@ -619,14 +584,8 @@ static void nfs_direct_write_release(void *calldata)
        struct nfs_write_data *data = calldata;
        struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req;
 
-       spin_lock(&dreq->lock);
-       if (--dreq->outstanding) {
-               spin_unlock(&dreq->lock);
-               return;
-       }
-       spin_unlock(&dreq->lock);
-
-       nfs_direct_write_complete(dreq, data->inode);
+       if (put_dreq(dreq))
+               nfs_direct_write_complete(dreq, data->inode);
 }
 
 static const struct rpc_call_ops nfs_write_direct_ops = {
@@ -635,41 +594,62 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
 };
 
 /*
- * For each nfs_write_data struct that was allocated on the list, dispatch
- * an NFS WRITE operation
+ * For each wsize'd chunk of the user's buffer, dispatch an NFS WRITE
+ * operation.  If nfs_writedata_alloc() or get_user_pages() fails,
+ * bail and stop sending more writes.  Write length accounting is
+ * handled automatically by nfs_direct_write_result().  Otherwise, if
+ * no requests have been sent, just return an error.
  */
-static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
+static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
 {
        struct nfs_open_context *ctx = dreq->ctx;
        struct inode *inode = ctx->dentry->d_inode;
-       struct list_head *list = &dreq->list;
-       struct page **pages = dreq->pages;
-       size_t count = dreq->user_count;
-       loff_t pos = dreq->pos;
        size_t wsize = NFS_SERVER(inode)->wsize;
-       unsigned int curpage, pgbase;
+       unsigned int wpages = nfs_max_pages(wsize);
+       unsigned int pgbase;
+       int result;
+       ssize_t started = 0;
 
-       curpage = 0;
-       pgbase = dreq->user_addr & ~PAGE_MASK;
+       get_dreq(dreq);
+
+       pgbase = user_addr & ~PAGE_MASK;
        do {
                struct nfs_write_data *data;
                size_t bytes;
 
+               result = -ENOMEM;
+               data = nfs_writedata_alloc(wpages);
+               if (unlikely(!data))
+                       break;
+
                bytes = wsize;
                if (count < wsize)
                        bytes = count;
 
-               BUG_ON(list_empty(list));
-               data = list_entry(list->next, struct nfs_write_data, pages);
+               data->npages = nfs_direct_count_pages(user_addr, bytes);
+               down_read(&current->mm->mmap_sem);
+               result = get_user_pages(current, current->mm, user_addr,
+                                       data->npages, 0, 0, data->pagevec, NULL);
+               up_read(&current->mm->mmap_sem);
+               if (unlikely(result < data->npages)) {
+                       if (result > 0)
+                               nfs_direct_release_pages(data->pagevec, result);
+                       nfs_writedata_release(data);
+                       break;
+               }
+
+               get_dreq(dreq);
+
                list_move_tail(&data->pages, &dreq->rewrite_list);
 
+               data->req = (struct nfs_page *) dreq;
                data->inode = inode;
                data->cred = ctx->cred;
                data->args.fh = NFS_FH(inode);
                data->args.context = ctx;
                data->args.offset = pos;
                data->args.pgbase = pgbase;
-               data->args.pages = &pages[curpage];
+               data->args.pages = data->pagevec;
                data->args.count = bytes;
                data->res.fattr = &data->fattr;
                data->res.count = bytes;
@@ -693,19 +673,26 @@ static void nfs_direct_write_schedule(struct nfs_direct_req *dreq, int sync)
                                bytes,
                                (unsigned long long)data->args.offset);
 
+               started += bytes;
+               user_addr += bytes;
                pos += bytes;
                pgbase += bytes;
-               curpage += pgbase >> PAGE_SHIFT;
                pgbase &= ~PAGE_MASK;
 
                count -= bytes;
        } while (count != 0);
-       BUG_ON(!list_empty(list));
+
+       if (put_dreq(dreq))
+               nfs_direct_write_complete(dreq, inode);
+
+       if (started)
+               return 0;
+       return result < 0 ? (ssize_t) result : -EFAULT;
 }
 
-static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos, struct page **pages, int nr_pages)
+static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, size_t count, loff_t pos)
 {
-       ssize_t result;
+       ssize_t result = 0;
        sigset_t oldset;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct rpc_clnt *clnt = NFS_CLIENT(inode);
@@ -713,17 +700,14 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
        size_t wsize = NFS_SERVER(inode)->wsize;
        int sync = 0;
 
-       dreq = nfs_direct_write_alloc(count, wsize);
+       dreq = nfs_direct_req_alloc();
        if (!dreq)
                return -ENOMEM;
+       nfs_alloc_commit_data(dreq);
+
        if (dreq->commit_data == NULL || count < wsize)
                sync = FLUSH_STABLE;
 
-       dreq->user_addr = user_addr;
-       dreq->user_count = count;
-       dreq->pos = pos;
-       dreq->pages = pages;
-       dreq->npages = nr_pages;
        dreq->inode = inode;
        dreq->ctx = get_nfs_open_context((struct nfs_open_context *)iocb->ki_filp->private_data);
        if (!is_sync_kiocb(iocb))
@@ -734,8 +718,9 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
        nfs_begin_data_update(inode);
 
        rpc_clnt_sigmask(clnt, &oldset);
-       nfs_direct_write_schedule(dreq, sync);
-       result = nfs_direct_wait(dreq);
+       result = nfs_direct_write_schedule(dreq, user_addr, count, pos, sync);
+       if (!result)
+               result = nfs_direct_wait(dreq);
        rpc_clnt_sigunmask(clnt, &oldset);
 
        return result;
@@ -765,8 +750,6 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
 ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
 {
        ssize_t retval = -EINVAL;
-       int page_count;
-       struct page **pages;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
 
@@ -788,14 +771,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count,
        if (retval)
                goto out;
 
-       retval = nfs_get_user_pages(READ, (unsigned long) buf,
-                                               count, &pages);
-       if (retval < 0)
-               goto out;
-       page_count = retval;
-
-       retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos,
-                                               pages, page_count);
+       retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos);
        if (retval > 0)
                iocb->ki_pos = pos + retval;
 
@@ -831,8 +807,6 @@ out:
 ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
 {
        ssize_t retval;
-       int page_count;
-       struct page **pages;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
 
@@ -860,14 +834,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
        if (retval)
                goto out;
 
-       retval = nfs_get_user_pages(WRITE, (unsigned long) buf,
-                                               count, &pages);
-       if (retval < 0)
-               goto out;
-       page_count = retval;
-
-       retval = nfs_direct_write(iocb, (unsigned long) buf, count,
-                                       pos, pages, page_count);
+       retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
 
        /*
         * XXX: nfs_end_data_update() already ensures this file's
index b4916b0..e6ee97f 100644 (file)
@@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
                default:
                        BUG();
        }
-       if (res < 0)
-               printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
-                               __FUNCTION__);
        return res;
 }
 
@@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
-       /* Unlock _before_ we do the RPC call */
-       do_vfs_lock(fl->fl_file, fl);
        return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
 }
 
@@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        struct rpc_task *task;
        int status = 0;
 
-       /* Is this a delegated lock? */
-       if (test_bit(NFS_DELEGATED_STATE, &state->flags))
-               goto out_unlock;
-       /* Is this open_owner holding any locks on the server? */
-       if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
-               goto out_unlock;
-
        status = nfs4_set_lock_state(state, request);
+       /* Unlock _before_ we do the RPC call */
+       request->fl_flags |= FL_EXISTS;
+       if (do_vfs_lock(request->fl_file, request) == -ENOENT)
+               goto out;
        if (status != 0)
-               goto out_unlock;
+               goto out;
+       /* Is this a delegated lock? */
+       if (test_bit(NFS_DELEGATED_STATE, &state->flags))
+               goto out;
        lsp = request->fl_u.nfs4_fl.owner;
-       status = -ENOMEM;
        seqid = nfs_alloc_seqid(&lsp->ls_seqid);
+       status = -ENOMEM;
        if (seqid == NULL)
-               goto out_unlock;
+               goto out;
        task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
        status = PTR_ERR(task);
        if (IS_ERR(task))
-               goto out_unlock;
+               goto out;
        status = nfs4_wait_for_completion_rpc_task(task);
        rpc_release_task(task);
-       return status;
-out_unlock:
-       do_vfs_lock(request->fl_file, request);
+out:
        return status;
 }
 
@@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
        struct nfs4_exception exception = { };
        int err;
 
-       /* Cache the lock if possible... */
-       if (test_bit(NFS_DELEGATED_STATE, &state->flags))
-               return 0;
        do {
+               /* Cache the lock if possible... */
+               if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+                       return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, 1);
                if (err != -NFS4ERR_DELAY)
                        break;
@@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
        if (err != 0)
                return err;
        do {
+               if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+                       return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, 0);
                if (err != -NFS4ERR_DELAY)
                        break;
@@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
        struct nfs4_client *clp = state->owner->so_client;
+       unsigned char fl_flags = request->fl_flags;
        int status;
 
        /* Is this a delegated open? */
-       if (NFS_I(state->inode)->delegation_state != 0) {
-               /* Yes: cache locks! */
-               status = do_vfs_lock(request->fl_file, request);
-               /* ...but avoid races with delegation recall... */
-               if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
-                       return status;
-       }
-       down_read(&clp->cl_sem);
        status = nfs4_set_lock_state(state, request);
        if (status != 0)
                goto out;
+       request->fl_flags |= FL_ACCESS;
+       status = do_vfs_lock(request->fl_file, request);
+       if (status < 0)
+               goto out;
+       down_read(&clp->cl_sem);
+       if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+               struct nfs_inode *nfsi = NFS_I(state->inode);
+               /* Yes: cache locks! */
+               down_read(&nfsi->rwsem);
+               /* ...but avoid races with delegation recall... */
+               if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+                       request->fl_flags = fl_flags & ~FL_SLEEP;
+                       status = do_vfs_lock(request->fl_file, request);
+                       up_read(&nfsi->rwsem);
+                       goto out_unlock;
+               }
+               up_read(&nfsi->rwsem);
+       }
        status = _nfs4_do_setlk(state, cmd, request, 0);
        if (status != 0)
-               goto out;
+               goto out_unlock;
        /* Note: we always want to sleep here! */
-       request->fl_flags |= FL_SLEEP;
+       request->fl_flags = fl_flags | FL_SLEEP;
        if (do_vfs_lock(request->fl_file, request) < 0)
                printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
-out:
+out_unlock:
        up_read(&clp->cl_sem);
+out:
+       request->fl_flags = fl_flags;
        return status;
 }
 
index bca5734..86bac6a 100644 (file)
@@ -578,7 +578,7 @@ static int nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, un
        return ret;
 }
 
-static void nfs_cancel_requests(struct list_head *head)
+static void nfs_cancel_dirty_list(struct list_head *head)
 {
        struct nfs_page *req;
        while(!list_empty(head)) {
@@ -589,6 +589,19 @@ static void nfs_cancel_requests(struct list_head *head)
        }
 }
 
+static void nfs_cancel_commit_list(struct list_head *head)
+{
+       struct nfs_page *req;
+
+       while(!list_empty(head)) {
+               req = nfs_list_entry(head->next);
+               nfs_list_remove_request(req);
+               nfs_inode_remove_request(req);
+               nfs_clear_page_writeback(req);
+               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
+       }
+}
+
 /*
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
@@ -1381,6 +1394,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
                nfs_list_remove_request(req);
                nfs_mark_request_commit(req);
                nfs_clear_page_writeback(req);
+               dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
        }
        return -ENOMEM;
 }
@@ -1499,7 +1513,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
                if (pages != 0) {
                        spin_unlock(&nfsi->req_lock);
                        if (how & FLUSH_INVALIDATE)
-                               nfs_cancel_requests(&head);
+                               nfs_cancel_dirty_list(&head);
                        else
                                ret = nfs_flush_list(inode, &head, pages, how);
                        spin_lock(&nfsi->req_lock);
@@ -1512,7 +1526,7 @@ int nfs_sync_inode_wait(struct inode *inode, unsigned long idx_start,
                        break;
                if (how & FLUSH_INVALIDATE) {
                        spin_unlock(&nfsi->req_lock);
-                       nfs_cancel_requests(&head);
+                       nfs_cancel_commit_list(&head);
                        spin_lock(&nfsi->req_lock);
                        continue;
                }
index 2dc93b1..f63842c 100644 (file)
  */
 #define        NR_IRQS         (NR_AIC_IRQS + (4 * 32))
 
-
-#ifndef __ASSEMBLY__
-/*
- * Initialize the IRQ controller.
- */
-extern void at91rm9200_init_irq(unsigned int priority[]);
-#endif
-
 #endif
index 134b320..43aef9b 100644 (file)
@@ -716,6 +716,7 @@ extern spinlock_t files_lock;
 #define FL_POSIX       1
 #define FL_FLOCK       2
 #define FL_ACCESS      8       /* not trying to lock, just looking */
+#define FL_EXISTS      16      /* when unlocking, test for existence */
 #define FL_LEASE       32      /* lease held on this file */
 #define FL_CLOSE       64      /* unlock on close */
 #define FL_SLEEP       128     /* A blocking lock */
index f4284bf..6cc497a 100644 (file)
@@ -131,6 +131,7 @@ enum {
        ATA_DFLAG_CFG_MASK      = (1 << 8) - 1,
 
        ATA_DFLAG_PIO           = (1 << 8), /* device currently in PIO mode */
+       ATA_DFLAG_SUSPENDED     = (1 << 9), /* device suspended */
        ATA_DFLAG_INIT_MASK     = (1 << 16) - 1,
 
        ATA_DFLAG_DETACH        = (1 << 16),
@@ -160,22 +161,28 @@ enum {
        ATA_FLAG_HRST_TO_RESUME = (1 << 11), /* hardreset to resume phy */
        ATA_FLAG_SKIP_D2H_BSY   = (1 << 12), /* can't wait for the first D2H
                                              * Register FIS clearing BSY */
-
        ATA_FLAG_DEBUGMSG       = (1 << 13),
-       ATA_FLAG_FLUSH_PORT_TASK = (1 << 14), /* flush port task */
 
-       ATA_FLAG_EH_PENDING     = (1 << 15), /* EH pending */
-       ATA_FLAG_EH_IN_PROGRESS = (1 << 16), /* EH in progress */
-       ATA_FLAG_FROZEN         = (1 << 17), /* port is frozen */
-       ATA_FLAG_RECOVERED      = (1 << 18), /* recovery action performed */
-       ATA_FLAG_LOADING        = (1 << 19), /* boot/loading probe */
-       ATA_FLAG_UNLOADING      = (1 << 20), /* module is unloading */
-       ATA_FLAG_SCSI_HOTPLUG   = (1 << 21), /* SCSI hotplug scheduled */
+       /* The following flag belongs to ap->pflags but is kept in
+        * ap->flags because it's referenced in many LLDs and will be
+        * removed in not-too-distant future.
+        */
+       ATA_FLAG_DISABLED       = (1 << 23), /* port is disabled, ignore it */
+
+       /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
-       ATA_FLAG_DISABLED       = (1 << 22), /* port is disabled, ignore it */
-       ATA_FLAG_SUSPENDED      = (1 << 23), /* port is suspended (power) */
+       /* struct ata_port pflags */
+       ATA_PFLAG_EH_PENDING    = (1 << 0), /* EH pending */
+       ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), /* EH in progress */
+       ATA_PFLAG_FROZEN        = (1 << 2), /* port is frozen */
+       ATA_PFLAG_RECOVERED     = (1 << 3), /* recovery action performed */
+       ATA_PFLAG_LOADING       = (1 << 4), /* boot/loading probe */
+       ATA_PFLAG_UNLOADING     = (1 << 5), /* module is unloading */
+       ATA_PFLAG_SCSI_HOTPLUG  = (1 << 6), /* SCSI hotplug scheduled */
 
-       /* bits 24:31 of ap->flags are reserved for LLDD specific flags */
+       ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
+       ATA_PFLAG_SUSPENDED     = (1 << 17), /* port is suspended (power) */
+       ATA_PFLAG_PM_PENDING    = (1 << 18), /* PM operation pending */
 
        /* struct ata_queued_cmd flags */
        ATA_QCFLAG_ACTIVE       = (1 << 0), /* cmd not yet ack'd to scsi lyer */
@@ -248,12 +255,19 @@ enum {
        ATA_EH_REVALIDATE       = (1 << 0),
        ATA_EH_SOFTRESET        = (1 << 1),
        ATA_EH_HARDRESET        = (1 << 2),
+       ATA_EH_SUSPEND          = (1 << 3),
+       ATA_EH_RESUME           = (1 << 4),
+       ATA_EH_PM_FREEZE        = (1 << 5),
 
        ATA_EH_RESET_MASK       = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
-       ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE,
+       ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE | ATA_EH_SUSPEND |
+                                 ATA_EH_RESUME | ATA_EH_PM_FREEZE,
 
        /* ata_eh_info->flags */
        ATA_EHI_HOTPLUGGED      = (1 << 0),  /* could have been hotplugged */
+       ATA_EHI_RESUME_LINK     = (1 << 1),  /* need to resume link */
+       ATA_EHI_NO_AUTOPSY      = (1 << 2),  /* no autopsy */
+       ATA_EHI_QUIET           = (1 << 3),  /* be quiet */
 
        ATA_EHI_DID_RESET       = (1 << 16), /* already reset this port */
 
@@ -486,6 +500,7 @@ struct ata_port {
        const struct ata_port_operations *ops;
        spinlock_t              *lock;
        unsigned long           flags;  /* ATA_FLAG_xxx */
+       unsigned int            pflags; /* ATA_PFLAG_xxx */
        unsigned int            id;     /* unique id req'd by scsi midlyr */
        unsigned int            port_no; /* unique port #; from zero */
        unsigned int            hard_port_no;   /* hardware port #; from zero */
@@ -535,6 +550,9 @@ struct ata_port {
        struct list_head        eh_done_q;
        wait_queue_head_t       eh_wait_q;
 
+       pm_message_t            pm_mesg;
+       int                     *pm_result;
+
        void                    *private_data;
 
        u8                      sector_buf[ATA_SECT_SIZE]; /* owned by EH */
@@ -589,6 +607,9 @@ struct ata_port_operations {
        void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
                           u32 val);
 
+       int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
+       int (*port_resume) (struct ata_port *ap);
+
        int (*port_start) (struct ata_port *ap);
        void (*port_stop) (struct ata_port *ap);
 
@@ -622,9 +643,18 @@ struct ata_timing {
 
 #define FIT(v,vmin,vmax)       max_t(short,min_t(short,v,vmax),vmin)
 
-extern const unsigned long sata_deb_timing_boot[];
-extern const unsigned long sata_deb_timing_eh[];
-extern const unsigned long sata_deb_timing_before_fsrst[];
+extern const unsigned long sata_deb_timing_normal[];
+extern const unsigned long sata_deb_timing_hotplug[];
+extern const unsigned long sata_deb_timing_long[];
+
+static inline const unsigned long *
+sata_ehc_deb_timing(struct ata_eh_context *ehc)
+{
+       if (ehc->i.flags & ATA_EHI_HOTPLUGGED)
+               return sata_deb_timing_hotplug;
+       else
+               return sata_deb_timing_normal;
+}
 
 extern void ata_port_probe(struct ata_port *);
 extern void __sata_phy_reset(struct ata_port *ap);
@@ -644,6 +674,8 @@ extern void ata_std_ports(struct ata_ioports *ioaddr);
 extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
                             unsigned int n_ports);
 extern void ata_pci_remove_one (struct pci_dev *pdev);
+extern void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state);
+extern void ata_pci_device_do_resume(struct pci_dev *pdev);
 extern int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state);
 extern int ata_pci_device_resume(struct pci_dev *pdev);
 extern int ata_pci_clear_simplex(struct pci_dev *pdev);
@@ -664,8 +696,9 @@ extern int ata_port_online(struct ata_port *ap);
 extern int ata_port_offline(struct ata_port *ap);
 extern int ata_scsi_device_resume(struct scsi_device *);
 extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
-extern int ata_device_resume(struct ata_device *);
-extern int ata_device_suspend(struct ata_device *, pm_message_t state);
+extern int ata_host_set_suspend(struct ata_host_set *host_set,
+                               pm_message_t mesg);
+extern void ata_host_set_resume(struct ata_host_set *host_set);
 extern int ata_ratelimit(void);
 extern unsigned int ata_busy_sleep(struct ata_port *ap,
                                   unsigned long timeout_pat,
@@ -825,19 +858,24 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        (ehi)->desc_len = 0; \
 } while (0)
 
-static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
 {
        if (ehi->flags & ATA_EHI_HOTPLUGGED)
                return;
 
-       ehi->flags |= ATA_EHI_HOTPLUGGED;
+       ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
        ehi->hotplug_timestamp = jiffies;
 
-       ehi->err_mask |= AC_ERR_ATA_BUS;
        ehi->action |= ATA_EH_SOFTRESET;
        ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
 }
 
+static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
+{
+       __ata_ehi_hotplugged(ehi);
+       ehi->err_mask |= AC_ERR_ATA_BUS;
+}
+
 /*
  * qc helpers
  */
@@ -921,6 +959,11 @@ static inline unsigned int ata_dev_absent(const struct ata_device *dev)
        return ata_class_absent(dev->class);
 }
 
+static inline unsigned int ata_dev_ready(const struct ata_device *dev)
+{
+       return ata_dev_enabled(dev) && !(dev->flags & ATA_DFLAG_SUSPENDED);
+}
+
 /*
  * port helpers
  */
index 7c7320f..2d3fb64 100644 (file)
@@ -729,6 +729,7 @@ struct nfs_read_data {
        struct list_head        pages;  /* Coalesced read requests */
        struct nfs_page         *req;   /* multi ops per nfs_page */
        struct page             **pagevec;
+       unsigned int            npages; /* active pages in pagevec */
        struct nfs_readargs args;
        struct nfs_readres  res;
 #ifdef CONFIG_NFS_V4
@@ -747,6 +748,7 @@ struct nfs_write_data {
        struct list_head        pages;          /* Coalesced requests we wish to flush */
        struct nfs_page         *req;           /* multi ops per nfs_page */
        struct page             **pagevec;
+       unsigned int            npages;         /* active pages in pagevec */
        struct nfs_writeargs    args;           /* argument struct */
        struct nfs_writeres     res;            /* result struct */
 #ifdef CONFIG_NFS_V4
index 685081c..c09396d 100644 (file)
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
+#define PCI_VENDOR_ID_JMICRON          0x197B
+#define PCI_DEVICE_ID_JMICRON_JMB360   0x2360
+#define PCI_DEVICE_ID_JMICRON_JMB361   0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB363   0x2363
+#define PCI_DEVICE_ID_JMICRON_JMB365   0x2365
+#define PCI_DEVICE_ID_JMICRON_JMB366   0x2366
+#define PCI_DEVICE_ID_JMICRON_JMB368   0x2368
 
 #define PCI_VENDOR_ID_TEKRAM           0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290     0xdc29
index 7a483ab..00ad810 100644 (file)
@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
         */
        u8 static_essid:1,
           associating:1,
+          assoc_wait:1,
           bssvalid:1,
           bssfixed:1;
 
index 47ccf15..72d4d4e 100644 (file)
@@ -368,6 +368,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 
        /* Put this code here so that we avoid duplicating it in all
         * Rx paths. - Jean II */
+#ifdef CONFIG_WIRELESS_EXT
 #ifdef IW_WIRELESS_SPY         /* defined in iw_handler.h */
        /* If spy monitoring on */
        if (ieee->spy_data.spy_number > 0) {
@@ -396,15 +397,16 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
        }
 #endif                         /* IW_WIRELESS_SPY */
+#endif                         /* CONFIG_WIRELESS_EXT */
 
 #ifdef NOT_YET
        hostap_update_rx_stats(local->ap, hdr, rx_stats);
 #endif
 
        if (ieee->iw_mode == IW_MODE_MONITOR) {
-               ieee80211_monitor_rx(ieee, skb, rx_stats);
                stats->rx_packets++;
                stats->rx_bytes += skb->len;
+               ieee80211_monitor_rx(ieee, skb, rx_stats);
                return 1;
        }
 
index de148ae..bf04213 100644 (file)
@@ -562,10 +562,13 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
        struct net_device_stats *stats = &ieee->stats;
        struct sk_buff *skb_frag;
        int priority = -1;
+       int fraglen = total_len;
+       int headroom = ieee->tx_headroom;
+       struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx];
 
        spin_lock_irqsave(&ieee->lock, flags);
 
-       if (encrypt_mpdu && !ieee->sec.encrypt)
+       if (encrypt_mpdu && (!ieee->sec.encrypt || !crypt))
                encrypt_mpdu = 0;
 
        /* If there is no driver handler to take the TXB, dont' bother
@@ -581,20 +584,24 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee,
                goto success;
        }
 
-       if (encrypt_mpdu)
+       if (encrypt_mpdu) {
                frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+               fraglen += crypt->ops->extra_mpdu_prefix_len +
+                          crypt->ops->extra_mpdu_postfix_len;
+               headroom += crypt->ops->extra_mpdu_prefix_len;
+       }
 
        /* When we allocate the TXB we allocate enough space for the reserve
         * and full fragment bytes (bytes_per_frag doesn't include prefix,
         * postfix, header, FCS, etc.) */
-       txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC);
+       txb = ieee80211_alloc_txb(1, fraglen, headroom, GFP_ATOMIC);
        if (unlikely(!txb)) {
                printk(KERN_WARNING "%s: Could not allocate TXB\n",
                       ieee->dev->name);
                goto failed;
        }
        txb->encrypted = 0;
-       txb->payload_size = total_len;
+       txb->payload_size = fraglen;
 
        skb_frag = txb->fragments[0];
 
index 5e9a906..44215ce 100644 (file)
@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
        
        dprintk(KERN_INFO PFX "sent association request!\n");
 
-       /* Change the state to associating */
        spin_lock_irqsave(&mac->lock, flags);
-       mac->associnfo.associating = 1;
        mac->associated = 0; /* just to make sure */
 
        /* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
 ieee80211softmac_assoc_timeout(void *d)
 {
        struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+       struct ieee80211softmac_network *n;
        unsigned long flags;
 
        spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
        mac->associnfo.associating = 0;
        mac->associnfo.bssvalid = 0;
        mac->associated = 0;
+
+       n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
        spin_unlock_irqrestore(&mac->lock, flags);
 
        dprintk(KERN_INFO PFX "assoc request timed out!\n");
-       /* FIXME: we need to know the network here. that requires a bit of restructuring */
-       ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
+       ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
 }
 
 void
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
        if (mac->associated)
                ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
 
+       spin_lock_irqsave(&mac->lock, flags);
+       mac->associnfo.associating = 1;
+       spin_unlock_irqrestore(&mac->lock, flags);
+
        /* try to find the requested network in our list, if we found one already */
        if (bssvalid || mac->associnfo.bssfixed)
                found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);       
@@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
        memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
        
        /* we found a network! authenticate (if necessary) and associate to it. */
-       if (!found->authenticated) {
+       if (found->authenticating) {
+               dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+               if(!mac->associnfo.assoc_wait) {
+                       mac->associnfo.assoc_wait = 1;
+                       ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+               }
+               return;
+       }
+       if (!found->authenticated && !found->authenticating) {
                /* This relies on the fact that _auth_req only queues the work,
                 * otherwise adding the notification would be racy. */
                if (!ieee80211softmac_auth_req(mac, found)) {
-                       dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
-                       ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+                       if(!mac->associnfo.assoc_wait) {
+                               dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
+                               mac->associnfo.assoc_wait = 1;
+                               ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+                       }
                } else {
                        printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
+                       mac->associnfo.assoc_wait = 0;
                        ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
                }
                return;
        }
        /* finally! now we can start associating */
+       mac->associnfo.assoc_wait = 0;
        ieee80211softmac_assoc(mac, found);
 }
 
index 90b8484..ebc33ca 100644 (file)
@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
        struct ieee80211softmac_auth_queue_item *auth;
        unsigned long flags;
        
-       if (net->authenticating)
+       if (net->authenticating || net->authenticated)
                return 0;
+       net->authenticating = 1;
 
        /* Add the network if it's not already added */
        ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
                        return;
                }
                net->authenticated = 0;
-               net->authenticating = 1;
                /* add a timeout call so we eventually give up waiting for an auth reply */
                schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
                auth->retry--;
index 0954161..8cc8b20 100644 (file)
@@ -229,6 +229,9 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
                return 0;
        ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
 
+       /* Fill in the capabilities */
+       (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
+
        /* Fill in Listen Interval (?) */
        (*pkt)->listen_interval = cpu_to_le16(10);
        
index 0e65ff4..75320b6 100644 (file)
@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
                              char *extra)
 {
        struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+       struct ieee80211softmac_network *n;
+       struct ieee80211softmac_auth_queue_item *authptr;
        int length = 0;
        unsigned long flags;
-       
+
+       /* Check if we're already associating to this or another network
+        * If it's another network, cancel and start over with our new network
+        * If it's our network, ignore the change, we're already doing it!
+        */
+       if((sm->associnfo.associating || sm->associated) &&
+          (data->essid.flags && data->essid.length && extra)) {
+               /* Get the associating network */
+               n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+               if(n && n->essid.len == (data->essid.length - 1) &&
+                  !memcmp(n->essid.data, extra, n->essid.len)) {
+                       dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+                               MAC_ARG(sm->associnfo.bssid));
+                       return 0;
+               } else {
+                       dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+                       spin_lock_irqsave(&sm->lock,flags);
+                       /* Cancel assoc work */
+                       cancel_delayed_work(&sm->associnfo.work);
+                       /* We don't have to do this, but it's a little cleaner */
+                       list_for_each_entry(authptr, &sm->auth_queue, list)
+                               cancel_delayed_work(&authptr->work);
+                       sm->associnfo.bssvalid = 0;
+                       sm->associnfo.bssfixed = 0;
+                       spin_unlock_irqrestore(&sm->lock,flags);
+                       flush_scheduled_work();
+               }
+       }
+
+
        spin_lock_irqsave(&sm->lock, flags);
-       
+
        sm->associnfo.static_essid = 0;
+       sm->associnfo.assoc_wait = 0;
 
        if (data->essid.flags && data->essid.length && extra /*required?*/) {
                length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
index 49174f0..6ac4510 100644 (file)
@@ -191,7 +191,6 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
        do {
                /* Are any pointers crossing a page boundary? */
                if (pgto_base == 0) {
-                       flush_dcache_page(*pgto);
                        pgto_base = PAGE_CACHE_SIZE;
                        pgto--;
                }
@@ -211,11 +210,11 @@ _shift_data_right_pages(struct page **pages, size_t pgto_base,
                vto = kmap_atomic(*pgto, KM_USER0);
                vfrom = kmap_atomic(*pgfrom, KM_USER1);
                memmove(vto + pgto_base, vfrom + pgfrom_base, copy);
+               flush_dcache_page(*pgto);
                kunmap_atomic(vfrom, KM_USER1);
                kunmap_atomic(vto, KM_USER0);
 
        } while ((len -= copy) != 0);
-       flush_dcache_page(*pgto);
 }
 
 /*