Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / net / wireless / spectrum_cs.c
index bcc7038..54fe4e4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
- * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
+ * Symbol Wireless Networker LA4100, CompactFlash cards by Socket
  * Communications and Intel PRO/Wireless 2011B.
  *
  * The driver implements Symbol firmware download.  The rest is handled
@@ -21,6 +21,7 @@
 #define DRIVER_NAME "spectrum_cs"
 #define PFX DRIVER_NAME ": "
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -34,6 +35,8 @@
 
 #include "orinoco.h"
 
+static unsigned char *primsym;
+static unsigned char *secsym;
 static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
 static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
 
@@ -117,8 +120,8 @@ static void spectrum_cs_release(struct pcmcia_device *link);
  * Each block has the following structure.
  */
 struct dblock {
-       __le32 addr;            /* adapter address where to write the block */
-       __le16 len;             /* length of the data only, in bytes */
+       __le32 _addr;           /* adapter address where to write the block */
+       __le16 _len;            /* length of the data only, in bytes */
        char data[0];           /* data to be written */
 } __attribute__ ((packed));
 
@@ -128,9 +131,9 @@ struct dblock {
  * items with matching ID should be written.
  */
 struct pdr {
-       __le32 id;              /* record ID */
-       __le32 addr;            /* adapter address where to write the data */
-       __le32 len;             /* expected length of the data, in bytes */
+       __le32 _id;             /* record ID */
+       __le32 _addr;           /* adapter address where to write the data */
+       __le32 _len;            /* expected length of the data, in bytes */
        char next[0];           /* next PDR starts here */
 } __attribute__ ((packed));
 
@@ -141,8 +144,8 @@ struct pdr {
  * be plugged into the secondary firmware.
  */
 struct pdi {
-       __le16 len;             /* length of ID and data, in words */
-       __le16 id;              /* record ID */
+       __le16 _len;            /* length of ID and data, in words */
+       __le16 _id;             /* record ID */
        char data[0];           /* plug data */
 } __attribute__ ((packed));
 
@@ -151,44 +154,44 @@ struct pdi {
 static inline u32
 dblock_addr(const struct dblock *blk)
 {
-       return le32_to_cpu(blk->addr);
+       return le32_to_cpu(blk->_addr);
 }
 
 static inline u32
 dblock_len(const struct dblock *blk)
 {
-       return le16_to_cpu(blk->len);
+       return le16_to_cpu(blk->_len);
 }
 
 static inline u32
 pdr_id(const struct pdr *pdr)
 {
-       return le32_to_cpu(pdr->id);
+       return le32_to_cpu(pdr->_id);
 }
 
 static inline u32
 pdr_addr(const struct pdr *pdr)
 {
-       return le32_to_cpu(pdr->addr);
+       return le32_to_cpu(pdr->_addr);
 }
 
 static inline u32
 pdr_len(const struct pdr *pdr)
 {
-       return le32_to_cpu(pdr->len);
+       return le32_to_cpu(pdr->_len);
 }
 
 static inline u32
 pdi_id(const struct pdi *pdi)
 {
-       return le16_to_cpu(pdi->id);
+       return le16_to_cpu(pdi->_id);
 }
 
 /* Return length of the data only, in bytes */
 static inline u32
 pdi_len(const struct pdi *pdi)
 {
-       return 2 * (le16_to_cpu(pdi->len) - 1);
+       return 2 * (le16_to_cpu(pdi->_len) - 1);
 }
 
 
@@ -340,7 +343,8 @@ spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
 
        /* do the actual plugging */
        spectrum_aux_setaddr(hw, pdr_addr(pdr));
-       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
+       hermes_write_words(hw, HERMES_AUXDATA, pdi->data,
+                          pdi_len(pdi) / 2);
 
        return 0;
 }
@@ -420,8 +424,8 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
 
        while (dblock_addr(blk) != BLOCK_END) {
                spectrum_aux_setaddr(hw, blkaddr);
-               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-                                  blklen);
+               hermes_write_words(hw, HERMES_AUXDATA, blk->data,
+                                  blklen / 2);
 
                blk = (struct dblock *) &blk->data[blklen];
                blkaddr = dblock_addr(blk);
@@ -438,7 +442,7 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
  */
 static int
 spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
-                 const unsigned char *image, int secondary)
+                 const unsigned char *image)
 {
        int ret;
        const unsigned char *ptr;
@@ -453,7 +457,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
        first_block = (const struct dblock *) ptr;
 
        /* Read the PDA */
-       if (secondary) {
+       if (image != primsym) {
                ret = spectrum_read_pda(hw, pda, sizeof(pda));
                if (ret)
                        return ret;
@@ -470,7 +474,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
                return ret;
 
        /* Write the PDA to the adapter */
-       if (secondary) {
+       if (image != primsym) {
                ret = spectrum_apply_pda(hw, first_block, pda);
                if (ret)
                        return ret;
@@ -485,7 +489,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
        ret = hermes_init(hw);
 
        /* hermes_reset() should return 0 with the secondary firmware */
-       if (secondary && ret != 0)
+       if (image != primsym && ret != 0)
                return -ENODEV;
 
        /* And this should work with any firmware */
@@ -507,30 +511,33 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
        const struct firmware *fw_entry;
 
        if (request_firmware(&fw_entry, primary_fw_name,
-                            &handle_to_dev(link)) != 0) {
+                            &handle_to_dev(link)) == 0) {
+               primsym = fw_entry->data;
+       } else {
                printk(KERN_ERR PFX "Cannot find firmware: %s\n",
                       primary_fw_name);
                return -ENOENT;
        }
 
-       /* Load primary firmware */
-       ret = spectrum_dl_image(hw, link, fw_entry->data, 0);
-       release_firmware(fw_entry);
-       if (ret) {
-               printk(KERN_ERR PFX "Primary firmware download failed\n");
-               return ret;
-       }
-
        if (request_firmware(&fw_entry, secondary_fw_name,
-                            &handle_to_dev(link)) != 0) {
+                            &handle_to_dev(link)) == 0) {
+               secsym = fw_entry->data;
+       } else {
                printk(KERN_ERR PFX "Cannot find firmware: %s\n",
                       secondary_fw_name);
                return -ENOENT;
        }
 
+       /* Load primary firmware */
+       ret = spectrum_dl_image(hw, link, primsym);
+       if (ret) {
+               printk(KERN_ERR PFX "Primary firmware download failed\n");
+               return ret;
+       }
+
        /* Load secondary firmware */
-       ret = spectrum_dl_image(hw, link, fw_entry->data, 1);
-       release_firmware(fw_entry);
+       ret = spectrum_dl_image(hw, link, secsym);
+
        if (ret) {
                printk(KERN_ERR PFX "Secondary firmware download failed\n");
        }
@@ -619,11 +626,14 @@ static void spectrum_cs_detach(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
 
-       if (link->dev_node)
-               unregister_netdev(dev);
-
        spectrum_cs_release(link);
 
+       DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node);
+       if (link->dev_node) {
+               DEBUG(0, PFX "About to unregister net device %p\n",
+                     dev);
+               unregister_netdev(dev);
+       }
        free_orinocodev(dev);
 }                              /* spectrum_cs_detach */
 
@@ -643,10 +653,13 @@ spectrum_cs_config(struct pcmcia_device *link)
        int last_fn, last_ret;
        u_char buf[64];
        config_info_t conf;
+       cisinfo_t info;
        tuple_t tuple;
        cisparse_t parse;
        void __iomem *mem;
 
+       CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info));
+
        /*
         * This reads the card's CONFIG tuple to find its
         * configuration registers.
@@ -696,6 +709,12 @@ spectrum_cs_config(struct pcmcia_device *link)
                        goto next_entry;
                link->conf.ConfigIndex = cfg->index;
 
+               /* Does this card need audio output? */
+               if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+                       link->conf.Attributes |= CONF_ENABLE_SPKR;
+                       link->conf.Status = CCSR_AUDIO_ENA;
+               }
+
                /* Use power settings for Vcc and Vpp if present */
                /* Note that the CIS values need to be rescaled */
                if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
@@ -816,10 +835,19 @@ spectrum_cs_config(struct pcmcia_device *link)
                                     net_device has been registered */
 
        /* Finally, report what we've done */
-       printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
-              link->irq.AssignedIRQ, link->io.BasePort1,
-              link->io.BasePort1 + link->io.NumPorts1 - 1);
+       printk(KERN_DEBUG "%s: index 0x%02x: ",
+              dev->name, link->conf.ConfigIndex);
+       if (link->conf.Vpp)
+               printk(", Vpp %d.%d", link->conf.Vpp / 10,
+                      link->conf.Vpp % 10);
+       printk(", irq %d", link->irq.AssignedIRQ);
+       if (link->io.NumPorts1)
+               printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+                      link->io.BasePort1 + link->io.NumPorts1 - 1);
+       if (link->io.NumPorts2)
+               printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+                      link->io.BasePort2 + link->io.NumPorts2 - 1);
+       printk("\n");
 
        return 0;
 
@@ -860,10 +888,11 @@ spectrum_cs_suspend(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
        struct orinoco_private *priv = netdev_priv(dev);
+       unsigned long flags;
        int err = 0;
 
        /* Mark the device as stopped, to block IO until later */
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        err = __orinoco_down(dev);
        if (err)
@@ -873,9 +902,9 @@ spectrum_cs_suspend(struct pcmcia_device *link)
        netif_device_detach(dev);
        priv->hw_unavailable++;
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       return err;
+       return 0;
 }
 
 static int
@@ -903,7 +932,7 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
        " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
 
 static struct pcmcia_device_id spectrum_cs_ids[] = {
-       PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
+       PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4100 */
        PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
        PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
        PCMCIA_DEVICE_NULL,