📄 spectrum_cs.c
字号:
*/ 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 intspectrum_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_words(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi) / 2); return 0;}/* Read PDA from the adapter */static intspectrum_read_pda(hermes_t *hw, u16 *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 intspectrum_apply_pda(hermes_t *hw, const struct dblock *first_block, u16 *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 intspectrum_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_words(hw, HERMES_AUXDATA, blk->data, blklen / 2); 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 intspectrum_dl_image(hermes_t *hw, dev_link_t *link, const unsigned char *image){ int ret; const unsigned char *ptr; const struct dblock *first_block; /* Plug Data Area (PDA) */ u16 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 (image != primsym) { 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 (image != primsym) { 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 (image != primsym && ret != 0) return -ENODEV; /* And this should work with any firmware */ if (!hermes_present(hw)) return -ENODEV; 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 intspectrum_dl_firmware(hermes_t *hw, dev_link_t *link){ int ret; client_handle_t handle = link->handle;#ifndef SPECTRUM_FW_INCLUDED const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, &handle_to_dev(handle)) == 0) { primsym = fw_entry->data; } else { printk(KERN_ERR PFX "Cannot find firmware: %s\n", primary_fw_name); return -ENOENT; } if (request_firmware(&fw_entry, secondary_fw_name, &handle_to_dev(handle)) == 0) { secsym = fw_entry->data; } else { printk(KERN_ERR PFX "Cannot find firmware: %s\n", secondary_fw_name); return -ENOENT; }#endif /* 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, secsym); if (ret) { printk(KERN_ERR PFX "Secondary firmware download failed\n"); } return ret;}/********************************************************************//* Device methods *//********************************************************************/static intspectrum_cs_hard_reset(struct orinoco_private *priv){ struct orinoco_pccard *card = priv->card; dev_link_t *link = &card->link; int err; if (!hermes_present(&priv->hw)) { /* The firmware needs to be reloaded */ if (spectrum_dl_firmware(&priv->hw, &card->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;}/********************************************************************//* PCMCIA stuff *//********************************************************************//* * This creates an "instance" of the driver, allocating local data * structures for one device. The device is registered with Card * Services. * * The dev_link structure is initialized, but we don't actually * configure the card at this point -- we wait until we receive a card * insertion event. */static dev_link_t *spectrum_cs_attach(void){ struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; dev_link_t *link; client_reg_t client_reg; int ret; dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); if (! dev) return NULL; priv = netdev_priv(dev); card = priv->card; /* Link both structures together */ link = &card->link; link->priv = dev; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = orinoco_interrupt; link->irq.Instance = dev; /* General socket configuration defaults can go here. In this * client, we assume very little, and rely on the CIS for * almost everything. In most clients, many details (i.e., * number, sizes, and attributes of IO windows) are fixed by * the nature of the device, and can be hard-wired here. */ link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY_AND_IO; /* Register with Card Services */ /* FIXME: need a lock? */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Version = 0x0210; /* FIXME: what does this mean? */ client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); spectrum_cs_detach(link); return NULL; } return link;} /* spectrum_cs_attach *//* * This deletes a driver "instance". The device is de-registered with * Card Services. If it has been released, all local data structures * are freed. Otherwise, the structures will be freed when the device * is released. */static void spectrum_cs_detach(dev_link_t *link){ dev_link_t **linkp; struct net_device *dev = link->priv; /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; BUG_ON(*linkp == NULL); if (link->state & DEV_CONFIG) spectrum_cs_release(link); /* Break the link with Card Services */ if (link->handle) pcmcia_deregister_client(link->handle); /* Unlink device structure, and free it */ *linkp = link->next; DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); if (link->dev) { DEBUG(0, PFX "About to unregister net device %p\n", dev); unregister_netdev(dev); } free_orinocodev(dev);} /* spectrum_cs_detach *//* * spectrum_cs_config() is scheduled to run after a CARD_INSERTION * event is received, to configure the PCMCIA socket, and to make the * device available to the system. */static voidspectrum_cs_config(dev_link_t *link){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -