123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- // SPDX-License-Identifier: GPL-2.0
- static int prism2_enable_aux_port(struct net_device *dev, int enable)
- {
- u16 val, reg;
- int i, tries;
- unsigned long flags;
- struct hostap_interface *iface;
- local_info_t *local;
- iface = netdev_priv(dev);
- local = iface->local;
- if (local->no_pri) {
- if (enable) {
- PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
- "port is already enabled\n", dev->name);
- }
- return 0;
- }
- spin_lock_irqsave(&local->cmdlock, flags);
- /* wait until busy bit is clear */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- spin_unlock_irqrestore(&local->cmdlock, flags);
- printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
- dev->name, reg);
- return -ETIMEDOUT;
- }
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
- if (enable) {
- HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
- printk("prism2_enable_aux_port: was not disabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_ENABLE;
- } else {
- HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
- printk("prism2_enable_aux_port: was not enabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_DISABLE;
- }
- HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
- udelay(5);
- i = 10000;
- while (i > 0) {
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
- val &= HFA384X_AUX_PORT_MASK;
- if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
- (!enable && val == HFA384X_AUX_PORT_DISABLED))
- break;
- udelay(10);
- i--;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
- if (i == 0) {
- printk("prism2_enable_aux_port(%d) timed out\n",
- enable);
- return -ETIMEDOUT;
- }
- return 0;
- }
- static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
- {
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
- page = addr >> 7;
- offset = addr & 0x7f;
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
- udelay(5);
- #ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
- #else /* PRISM2_PCI */
- HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
- #endif /* PRISM2_PCI */
- return 0;
- }
- static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
- {
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
- page = addr >> 7;
- offset = addr & 0x7f;
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
- udelay(5);
- #ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
- #else /* PRISM2_PCI */
- HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
- #endif /* PRISM2_PCI */
- return 0;
- }
- static int prism2_pda_ok(u8 *buf)
- {
- __le16 *pda = (__le16 *) buf;
- int pos;
- u16 len, pdr;
- if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
- buf[3] == 0x00)
- return 0;
- pos = 0;
- while (pos + 1 < PRISM2_PDA_SIZE / 2) {
- len = le16_to_cpu(pda[pos]);
- pdr = le16_to_cpu(pda[pos + 1]);
- if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
- return 0;
- if (pdr == 0x0000 && len == 2) {
- /* PDA end found */
- return 1;
- }
- pos += len + 1;
- }
- return 0;
- }
- #define prism2_download_aux_dump_npages 65536
- struct prism2_download_aux_dump {
- local_info_t *local;
- u16 page[0x80];
- };
- static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
- {
- struct prism2_download_aux_dump *ctx = m->private;
- hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
- seq_write(m, ctx->page, 0x80);
- return 0;
- }
- static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
- {
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 1);
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
- }
- static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
- {
- ++*_pos;
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
- }
- static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
- {
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 0);
- }
- static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
- .start = prism2_download_aux_dump_proc_start,
- .next = prism2_download_aux_dump_proc_next,
- .stop = prism2_download_aux_dump_proc_stop,
- .show = prism2_download_aux_dump_proc_show,
- };
- static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
- {
- int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
- sizeof(struct prism2_download_aux_dump));
- if (ret == 0) {
- struct seq_file *m = file->private_data;
- m->private = PDE_DATA(inode);
- }
- return ret;
- }
- static const struct file_operations prism2_download_aux_dump_proc_fops = {
- .open = prism2_download_aux_dump_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_private,
- };
- static u8 * prism2_read_pda(struct net_device *dev)
- {
- u8 *buf;
- int res, i, found = 0;
- #define NUM_PDA_ADDRS 4
- unsigned int pda_addr[NUM_PDA_ADDRS] = {
- 0x7f0000 /* others than HFA3841 */,
- 0x3f0000 /* HFA3841 */,
- 0x390000 /* apparently used in older cards */,
- 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
- };
- buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return NULL;
- /* Note: wlan card should be in initial state (just after init cmd)
- * and no other operations should be performed concurrently. */
- prism2_enable_aux_port(dev, 1);
- for (i = 0; i < NUM_PDA_ADDRS; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
- dev->name, pda_addr[i]);
- res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
- if (res)
- continue;
- if (res == 0 && prism2_pda_ok(buf)) {
- PDEBUG2(DEBUG_EXTRA2, ": OK\n");
- found = 1;
- break;
- } else {
- PDEBUG2(DEBUG_EXTRA2, ": failed\n");
- }
- }
- prism2_enable_aux_port(dev, 0);
- if (!found) {
- printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
- kfree(buf);
- buf = NULL;
- }
- return buf;
- }
- static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param)
- {
- struct net_device *dev = local->dev;
- int ret = 0, i;
- u16 param0, param1;
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
- local->hw_downloading = 1;
- if (local->pri_only) {
- hfa384x_disable_interrupts(dev);
- } else {
- prism2_hw_shutdown(dev, 0);
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
- param0 = param->start_addr & 0xffff;
- param1 = param->start_addr >> 16;
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -1;
- goto out;
- }
- }
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
- /* ProgMode disable causes the hardware to restart itself from the
- * given starting address. Give hw some time and ACK command just in
- * case restart did not happen. */
- mdelay(5);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
- mdelay(5);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after RAM "
- "download failed\n", dev->name);
- ret = -1;
- goto out;
- }
- out:
- local->hw_downloading = 0;
- return ret;
- }
- static int prism2_enable_genesis(local_info_t *local, int hcr)
- {
- struct net_device *dev = local->dev;
- u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
- u8 readbuf[4];
- printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
- dev->name, hcr);
- local->func->cor_sreset(local);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- local->func->genesis_reset(local, hcr);
- /* Readback test */
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
- if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
- printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
- hcr);
- return 0;
- } else {
- printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
- "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
- hcr, initseq[0], initseq[1], initseq[2], initseq[3],
- readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
- return 1;
- }
- }
- static int prism2_get_ram_size(local_info_t *local)
- {
- int ret;
- /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0)
- ret = 8;
- else if (prism2_enable_genesis(local, 0x0f) == 0)
- ret = 16;
- else
- ret = -1;
- /* Disable genesis mode */
- local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
- return ret;
- }
- static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param)
- {
- struct net_device *dev = local->dev;
- int ram16 = 0, i;
- int ret = 0;
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -EBUSY;
- }
- if (!local->func->genesis_reset || !local->func->cor_sreset) {
- printk(KERN_INFO "%s: Genesis mode downloading not supported "
- "with this hwmodel\n", dev->name);
- return -EOPNOTSUPP;
- }
- local->hw_downloading = 1;
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_DEBUG "%s: failed to enable AUX port\n",
- dev->name);
- ret = -EIO;
- goto out;
- }
- if (local->sram_type == -1) {
- /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0) {
- ram16 = 0;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
- "SRAM\n", dev->name);
- } else if (prism2_enable_genesis(local, 0x0f) == 0) {
- ram16 = 1;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
- "SRAM\n", dev->name);
- } else {
- printk(KERN_DEBUG "%s: Could not initiate genesis "
- "mode\n", dev->name);
- ret = -EIO;
- goto out;
- }
- } else {
- if (prism2_enable_genesis(local, local->sram_type == 8 ?
- 0x1f : 0x0f)) {
- printk(KERN_DEBUG "%s: Failed to set Genesis "
- "mode (sram_type=%d)\n", dev->name,
- local->sram_type);
- ret = -EIO;
- goto out;
- }
- ram16 = local->sram_type != 8;
- }
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -EIO;
- goto out;
- }
- }
- PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
- local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
- dev->name);
- }
- mdelay(5);
- local->hw_downloading = 0;
- PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
- /*
- * Make sure the INIT command does not generate a command completion
- * event by disabling interrupts.
- */
- hfa384x_disable_interrupts(dev);
- if (prism2_hw_init(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
- PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
- if (prism2_hw_init2(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
- out:
- local->hw_downloading = 0;
- return ret;
- }
- #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
- /* Note! Non-volatile downloading functionality has not yet been tested
- * thoroughly and it may corrupt flash image and effectively kill the card that
- * is being updated. You have been warned. */
- static inline int prism2_download_block(struct net_device *dev,
- u32 addr, u8 *data,
- u32 bufaddr, int rest_len)
- {
- u16 param0, param1;
- int block_len;
- block_len = rest_len < 4096 ? rest_len : 4096;
- param0 = addr & 0xffff;
- param1 = addr >> 16;
- HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Flash download command execution "
- "failed\n", dev->name);
- return -1;
- }
- if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
- printk(KERN_WARNING "%s: flash download at 0x%08x "
- "(len=%d) failed\n", dev->name, addr, block_len);
- return -1;
- }
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
- 0)) {
- printk(KERN_WARNING "%s: Flash write command execution "
- "failed\n", dev->name);
- return -1;
- }
- return block_len;
- }
- static int prism2_download_nonvolatile(local_info_t *local,
- struct prism2_download_data *dl)
- {
- struct net_device *dev = local->dev;
- int ret = 0, i;
- struct {
- __le16 page;
- __le16 offset;
- __le16 len;
- } dlbuffer;
- u32 bufaddr;
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
- ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
- &dlbuffer, 6, 0);
- if (ret < 0) {
- printk(KERN_WARNING "%s: Could not read download buffer "
- "parameters\n", dev->name);
- goto out;
- }
- printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
- le16_to_cpu(dlbuffer.len),
- le16_to_cpu(dlbuffer.page),
- le16_to_cpu(dlbuffer.offset));
- bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
- local->hw_downloading = 1;
- if (!local->pri_only) {
- prism2_hw_shutdown(dev, 0);
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
- hfa384x_disable_interrupts(dev);
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
- printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
- for (i = 0; i < dl->num_areas; i++) {
- int rest_len = dl->data[i].len;
- int data_off = 0;
- while (rest_len > 0) {
- int block_len;
- block_len = prism2_download_block(
- dev, dl->data[i].addr + data_off,
- dl->data[i].data + data_off, bufaddr,
- rest_len);
- if (block_len < 0) {
- ret = -1;
- goto out;
- }
- rest_len -= block_len;
- data_off += block_len;
- }
- }
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), 0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
- mdelay(5);
- local->func->hw_reset(dev);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after flash "
- "download failed\n", dev->name);
- ret = -1;
- } else {
- printk(KERN_INFO "%s: Card initialized successfully after "
- "flash download\n", dev->name);
- }
- out:
- local->hw_downloading = 0;
- return ret;
- }
- #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
- static void prism2_download_free_data(struct prism2_download_data *dl)
- {
- int i;
- if (dl == NULL)
- return;
- for (i = 0; i < dl->num_areas; i++)
- kfree(dl->data[i].data);
- kfree(dl);
- }
- static int prism2_download(local_info_t *local,
- struct prism2_download_param *param)
- {
- int ret = 0;
- int i;
- u32 total_len = 0;
- struct prism2_download_data *dl = NULL;
- printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
- "num_areas=%d\n",
- param->dl_cmd, param->start_addr, param->num_areas);
- if (param->num_areas > 100) {
- ret = -EINVAL;
- goto out;
- }
- dl = kzalloc(sizeof(*dl) + param->num_areas *
- sizeof(struct prism2_download_data_area), GFP_KERNEL);
- if (dl == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- dl->dl_cmd = param->dl_cmd;
- dl->start_addr = param->start_addr;
- dl->num_areas = param->num_areas;
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2,
- " area %d: addr=0x%08x len=%d ptr=0x%p\n",
- i, param->data[i].addr, param->data[i].len,
- param->data[i].ptr);
- dl->data[i].addr = param->data[i].addr;
- dl->data[i].len = param->data[i].len;
- total_len += param->data[i].len;
- if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
- total_len > PRISM2_MAX_DOWNLOAD_LEN) {
- ret = -E2BIG;
- goto out;
- }
- dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
- if (dl->data[i].data == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- if (copy_from_user(dl->data[i].data, param->data[i].ptr,
- param->data[i].len)) {
- ret = -EFAULT;
- goto out;
- }
- }
- switch (param->dl_cmd) {
- case PRISM2_DOWNLOAD_VOLATILE:
- case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
- ret = prism2_download_volatile(local, dl);
- break;
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
- ret = prism2_download_genesis(local, dl);
- break;
- case PRISM2_DOWNLOAD_NON_VOLATILE:
- #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
- ret = prism2_download_nonvolatile(local, dl);
- #else /* PRISM2_NON_VOLATILE_DOWNLOAD */
- printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
- local->dev->name);
- ret = -EOPNOTSUPP;
- #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
- break;
- default:
- printk(KERN_DEBUG "%s: unsupported download command %d\n",
- local->dev->name, param->dl_cmd);
- ret = -EINVAL;
- break;
- }
- out:
- if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
- prism2_download_free_data(local->dl_pri);
- local->dl_pri = dl;
- } else if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
- prism2_download_free_data(local->dl_sec);
- local->dl_sec = dl;
- } else
- prism2_download_free_data(dl);
- return ret;
- }
|