Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
[pandora-kernel.git] / drivers / net / wireless / spectrum_cs.c
index d7e9d9c..b0c71c3 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <linux/firmware.h>
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
@@ -34,9 +33,6 @@
 
 #include "orinoco.h"
 
-static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
-static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
-
 /********************************************************************/
 /* Module stuff                                                            */
 /********************************************************************/
@@ -71,161 +67,11 @@ struct orinoco_pccard {
 static int spectrum_cs_config(struct pcmcia_device *link);
 static void spectrum_cs_release(struct pcmcia_device *link);
 
-/********************************************************************/
-/* Firmware downloader                                             */
-/********************************************************************/
-
-/* Position of PDA in the adapter memory */
-#define EEPROM_ADDR    0x3000
-#define EEPROM_LEN     0x200
-#define PDA_OFFSET     0x100
-
-#define PDA_ADDR       (EEPROM_ADDR + PDA_OFFSET)
-#define PDA_WORDS      ((EEPROM_LEN - PDA_OFFSET) / 2)
-
 /* Constants for the CISREG_CCSR register */
 #define HCR_RUN                0x07    /* run firmware after reset */
 #define HCR_IDLE       0x0E    /* don't run firmware after reset */
 #define HCR_MEM16      0x10    /* memory width bit, should be preserved */
 
-/*
- * AUX port access.  To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register.  Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE      0x8000  /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE     0x4000  /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED     0xC000  /* Auxiliary port is open */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* End markers */
-#define PDI_END                0x00000000      /* End of PDA */
-#define BLOCK_END      0xFFFFFFFF      /* Last image block */
-#define TEXT_END       0x1A            /* End of text header */
-
-/*
- * The following structures have little-endian fields denoted by
- * the leading underscore.  Don't access them directly - use inline
- * functions defined below.
- */
-
-/*
- * The binary image to be downloaded consists of series of data blocks.
- * 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 */
-       char data[0];           /* data to be written */
-} __attribute__ ((packed));
-
-/*
- * Plug Data References are located in in the image after the last data
- * block.  They refer to areas in the adapter memory where the plug data
- * 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 */
-       char next[0];           /* next PDR starts here */
-} __attribute__ ((packed));
-
-
-/*
- * Plug Data Items are located in the EEPROM read from the adapter by
- * primary firmware.  They refer to the device-specific data that should
- * be plugged into the secondary firmware.
- */
-struct pdi {
-       __le16 len;             /* length of ID and data, in words */
-       __le16 id;              /* record ID */
-       char data[0];           /* plug data */
-} __attribute__ ((packed));
-
-
-/* Functions for access to little-endian data */
-static inline u32
-dblock_addr(const struct dblock *blk)
-{
-       return le32_to_cpu(blk->addr);
-}
-
-static inline u32
-dblock_len(const struct dblock *blk)
-{
-       return le16_to_cpu(blk->len);
-}
-
-static inline u32
-pdr_id(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->id);
-}
-
-static inline u32
-pdr_addr(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->addr);
-}
-
-static inline u32
-pdr_len(const struct pdr *pdr)
-{
-       return le32_to_cpu(pdr->len);
-}
-
-static inline u32
-pdi_id(const struct pdi *pdi)
-{
-       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);
-}
-
-
-/* Set address of the auxiliary port */
-static inline void
-spectrum_aux_setaddr(hermes_t *hw, u32 addr)
-{
-       hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
-       hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-
-/* Open access to the auxiliary port */
-static int
-spectrum_aux_open(hermes_t *hw)
-{
-       int i;
-
-       /* Already open? */
-       if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
-               return 0;
-
-       hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
-       hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
-       hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
-       hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
-
-       for (i = 0; i < 20; i++) {
-               udelay(10);
-               if (hermes_read_reg(hw, HERMES_CONTROL) ==
-                   HERMES_AUX_ENABLED)
-                       return 0;
-       }
-
-       return -EBUSY;
-}
-
 
 #define CS_CHECK(fn, ret) \
   do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
@@ -292,275 +138,29 @@ spectrum_reset(struct pcmcia_device *link, int idle)
        return -ENODEV;
 }
 
+/********************************************************************/
+/* Device methods                                                  */
+/********************************************************************/
 
-/*
- * Scan PDR for the record with the specified RECORD_ID.
- * If it's not found, return NULL.
- */
-static struct pdr *
-spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
-{
-       struct pdr *pdr = first_pdr;
-
-       while (pdr_id(pdr) != PDI_END) {
-               /*
-                * PDR area is currently not terminated by PDI_END.
-                * It's followed by CRC records, which have the type
-                * field where PDR has length.  The type can be 0 or 1.
-                */
-               if (pdr_len(pdr) < 2)
-                       return NULL;
-
-               /* If the record ID matches, we are done */
-               if (pdr_id(pdr) == record_id)
-                       return pdr;
-
-               pdr = (struct pdr *) pdr->next;
-       }
-       return NULL;
-}
-
-
-/* Process one Plug Data Item - find corresponding PDR and plug it */
-static int
-spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
-{
-       struct pdr *pdr;
-
-       /* Find the PDI corresponding to this PDR */
-       pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
-
-       /* No match is found, safe to ignore */
-       if (!pdr)
-               return 0;
-
-       /* Lengths of the data in PDI and PDR must match */
-       if (pdi_len(pdi) != pdr_len(pdr))
-               return -EINVAL;
-
-       /* do the actual plugging */
-       spectrum_aux_setaddr(hw, pdr_addr(pdr));
-       hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
-
-       return 0;
-}
-
-
-/* Read PDA from the adapter */
-static int
-spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len)
-{
-       int ret;
-       int pda_size;
-
-       /* Issue command to read EEPROM */
-       ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
-       if (ret)
-               return ret;
-
-       /* Open auxiliary port */
-       ret = spectrum_aux_open(hw);
-       if (ret)
-               return ret;
-
-       /* read PDA from EEPROM */
-       spectrum_aux_setaddr(hw, PDA_ADDR);
-       hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
-
-       /* Check PDA length */
-       pda_size = le16_to_cpu(pda[0]);
-       if (pda_size > pda_len)
-               return -EINVAL;
-
-       return 0;
-}
-
-
-/* Parse PDA and write the records into the adapter */
-static int
-spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
-                  __le16 *pda)
-{
-       int ret;
-       struct pdi *pdi;
-       struct pdr *first_pdr;
-       const struct dblock *blk = first_block;
-
-       /* Skip all blocks to locate Plug Data References */
-       while (dblock_addr(blk) != BLOCK_END)
-               blk = (struct dblock *) &blk->data[dblock_len(blk)];
-
-       first_pdr = (struct pdr *) blk;
-
-       /* Go through every PDI and plug them into the adapter */
-       pdi = (struct pdi *) (pda + 2);
-       while (pdi_id(pdi) != PDI_END) {
-               ret = spectrum_plug_pdi(hw, first_pdr, pdi);
-               if (ret)
-                       return ret;
-
-               /* Increment to the next PDI */
-               pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
-       }
-       return 0;
-}
-
-
-/* Load firmware blocks into the adapter */
-static int
-spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
-{
-       const struct dblock *blk;
-       u32 blkaddr;
-       u32 blklen;
-
-       blk = first_block;
-       blkaddr = dblock_addr(blk);
-       blklen = dblock_len(blk);
-
-       while (dblock_addr(blk) != BLOCK_END) {
-               spectrum_aux_setaddr(hw, blkaddr);
-               hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
-                                  blklen);
-
-               blk = (struct dblock *) &blk->data[blklen];
-               blkaddr = dblock_addr(blk);
-               blklen = dblock_len(blk);
-       }
-       return 0;
-}
-
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds.  For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
 static int
-spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
-                 const unsigned char *image, int secondary)
+spectrum_cs_hard_reset(struct orinoco_private *priv)
 {
-       int ret;
-       const unsigned char *ptr;
-       const struct dblock *first_block;
-
-       /* Plug Data Area (PDA) */
-       __le16 pda[PDA_WORDS];
-
-       /* Binary block begins after the 0x1A marker */
-       ptr = image;
-       while (*ptr++ != TEXT_END);
-       first_block = (const struct dblock *) ptr;
-
-       /* Read the PDA */
-       if (secondary) {
-               ret = spectrum_read_pda(hw, pda, sizeof(pda));
-               if (ret)
-                       return ret;
-       }
-
-       /* Stop the firmware, so that it can be safely rewritten */
-       ret = spectrum_reset(link, 1);
-       if (ret)
-               return ret;
-
-       /* Program the adapter with new firmware */
-       ret = spectrum_load_blocks(hw, first_block);
-       if (ret)
-               return ret;
-
-       /* Write the PDA to the adapter */
-       if (secondary) {
-               ret = spectrum_apply_pda(hw, first_block, pda);
-               if (ret)
-                       return ret;
-       }
-
-       /* Run the firmware */
-       ret = spectrum_reset(link, 0);
-       if (ret)
-               return ret;
-
-       /* Reset hermes chip and make sure it responds */
-       ret = hermes_init(hw);
-
-       /* hermes_reset() should return 0 with the secondary firmware */
-       if (secondary && ret != 0)
-               return -ENODEV;
+       struct orinoco_pccard *card = priv->card;
+       struct pcmcia_device *link = card->p_dev;
 
-       /* And this should work with any firmware */
-       if (!hermes_present(hw))
-               return -ENODEV;
+       /* Soft reset using COR and HCR */
+       spectrum_reset(link, 0);
 
        return 0;
 }
 
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
 static int
-spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
-{
-       int ret;
-       const struct firmware *fw_entry;
-
-       if (request_firmware(&fw_entry, primary_fw_name,
-                            &handle_to_dev(link)) != 0) {
-               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) {
-               printk(KERN_ERR PFX "Cannot find firmware: %s\n",
-                      secondary_fw_name);
-               return -ENOENT;
-       }
-
-       /* Load secondary firmware */
-       ret = spectrum_dl_image(hw, link, fw_entry->data, 1);
-       release_firmware(fw_entry);
-       if (ret) {
-               printk(KERN_ERR PFX "Secondary firmware download failed\n");
-       }
-
-       return ret;
-}
-
-/********************************************************************/
-/* Device methods                                                  */
-/********************************************************************/
-
-static int
-spectrum_cs_hard_reset(struct orinoco_private *priv)
+spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
 {
        struct orinoco_pccard *card = priv->card;
        struct pcmcia_device *link = card->p_dev;
-       int err;
 
-       if (!hermes_present(&priv->hw)) {
-               /* The firmware needs to be reloaded */
-               if (spectrum_dl_firmware(&priv->hw, link) != 0) {
-                       printk(KERN_ERR PFX "Firmware download failed\n");
-                       err = -ENODEV;
-               }
-       } else {
-               /* Soft reset using COR and HCR */
-               spectrum_reset(link, 0);
-       }
-
-       return 0;
+       return spectrum_reset(link, idle);
 }
 
 /********************************************************************/
@@ -582,7 +182,9 @@ spectrum_cs_probe(struct pcmcia_device *link)
        struct orinoco_private *priv;
        struct orinoco_pccard *card;
 
-       dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset);
+       dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+                              spectrum_cs_hard_reset,
+                              spectrum_cs_stop_firmware);
        if (! dev)
                return -ENOMEM;
        priv = netdev_priv(dev);
@@ -593,7 +195,7 @@ spectrum_cs_probe(struct pcmcia_device *link)
        link->priv = dev;
 
        /* Interrupt setup */
-       link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+       link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
        link->irq.Handler = orinoco_interrupt;
        link->irq.Instance = dev; 
@@ -760,7 +362,7 @@ spectrum_cs_config(struct pcmcia_device *link)
        dev->irq = link->irq.AssignedIRQ;
        card->node.major = card->node.minor = 0;
 
-       /* Reset card and download firmware */
+       /* Reset card */
        if (spectrum_cs_hard_reset(priv) != 0) {
                goto failed;
        }