Main Page | Data Structures | Directories | File List | Data Fields | Globals

hostap_download.c

Go to the documentation of this file.
00001 static int prism2_enable_aux_port(struct net_device *dev, int enable)
00002 {
00003         u16 val, reg;
00004         int i, tries;
00005         unsigned long flags;
00006         struct hostap_interface *iface = dev->priv;
00007         local_info_t *local = iface->local;
00008 
00009         spin_lock_irqsave(&local->cmdlock, flags);
00010 
00011         /* wait until busy bit is clear */
00012         tries = HFA384X_CMD_BUSY_TIMEOUT;
00013         while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
00014                 tries--;
00015                 udelay(1);
00016         }
00017         if (tries == 0) {
00018                 reg = HFA384X_INW(HFA384X_CMD_OFF);
00019                 spin_unlock_irqrestore(&local->cmdlock, flags);
00020                 printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
00021                        dev->name, reg);
00022                 return -ETIMEDOUT;
00023         }
00024 
00025         val = HFA384X_INW(HFA384X_CONTROL_OFF);
00026 
00027         if (enable) {
00028                 HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
00029                 HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
00030                 HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
00031 
00032                 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
00033                         printk("prism2_enable_aux_port: was not disabled!?\n");
00034                 val &= ~HFA384X_AUX_PORT_MASK;
00035                 val |= HFA384X_AUX_PORT_ENABLE;
00036         } else {
00037                 HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
00038                 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
00039                 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
00040 
00041                 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
00042                         printk("prism2_enable_aux_port: was not enabled!?\n");
00043                 val &= ~HFA384X_AUX_PORT_MASK;
00044                 val |= HFA384X_AUX_PORT_DISABLE;
00045         }
00046         HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
00047 
00048         udelay(5);
00049 
00050         i = 10000;
00051         while (i > 0) {
00052                 val = HFA384X_INW(HFA384X_CONTROL_OFF);
00053                 val &= HFA384X_AUX_PORT_MASK;
00054 
00055                 if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
00056                     (!enable && val == HFA384X_AUX_PORT_DISABLED))
00057                         break;
00058 
00059                 udelay(10);
00060                 i--;
00061         }
00062 
00063         spin_unlock_irqrestore(&local->cmdlock, flags);
00064 
00065         if (i == 0) {
00066                 printk("prism2_enable_aux_port(%d) timed out\n",
00067                        enable);
00068                 return -ETIMEDOUT;
00069         }
00070 
00071         return 0;
00072 }
00073 
00074 
00075 static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
00076                             void *buf)
00077 {
00078         u16 page, offset;
00079         if (addr & 1 || len & 1)
00080                 return -1;
00081 
00082         page = addr >> 7;
00083         offset = addr & 0x7f;
00084 
00085         HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
00086         HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
00087 
00088         udelay(5);
00089 
00090 #ifdef PRISM2_PCI
00091         {
00092                 u16 *pos = (u16 *) buf;
00093                 while (len > 0) {
00094                         *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
00095                         len -= 2;
00096                 }
00097         }
00098 #else /* PRISM2_PCI */
00099         HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
00100 #endif /* PRISM2_PCI */
00101 
00102         return 0;
00103 }
00104 
00105 
00106 static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
00107                           void *buf)
00108 {
00109         u16 page, offset;
00110         if (addr & 1 || len & 1)
00111                 return -1;
00112 
00113         page = addr >> 7;
00114         offset = addr & 0x7f;
00115 
00116         HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
00117         HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
00118 
00119         udelay(5);
00120 
00121 #ifdef PRISM2_PCI
00122         {
00123                 u16 *pos = (u16 *) buf;
00124                 while (len > 0) {
00125                         HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
00126                         len -= 2;
00127                 }
00128         }
00129 #else /* PRISM2_PCI */
00130         HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
00131 #endif /* PRISM2_PCI */
00132 
00133         return 0;
00134 }
00135 
00136 
00137 static int prism2_pda_ok(u8 *buf)
00138 {
00139         u16 *pda = (u16 *) buf;
00140         int pos;
00141         u16 len, pdr;
00142 
00143         if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
00144             buf[3] == 0x00)
00145                 return 0;
00146 
00147         pos = 0;
00148         while (pos + 1 < PRISM2_PDA_SIZE / 2) {
00149                 len = le16_to_cpu(pda[pos]);
00150                 pdr = le16_to_cpu(pda[pos + 1]);
00151                 if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
00152                         return 0;
00153 
00154                 if (pdr == 0x0000 && len == 2) {
00155                         /* PDA end found */
00156                         return 1;
00157                 }
00158 
00159                 pos += len + 1;
00160         }
00161 
00162         return 0;
00163 }
00164 
00165 
00166 static u8 * prism2_read_pda(struct net_device *dev)
00167 {
00168         u8 *buf;
00169         int res, i, found = 0;
00170 #define NUM_PDA_ADDRS 3
00171         unsigned int pda_addr[NUM_PDA_ADDRS] = {
00172                 0x7f0000 /* others than HFA3841 */,
00173                 0x3f0000 /* HFA3841 */,
00174                 0x390000 /* apparently used in older cards */
00175         };
00176 
00177         buf = (u8 *) kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
00178         if (buf == NULL)
00179                 return NULL;
00180 
00181         /* Note: wlan card should be in initial state (just after init cmd)
00182          * and no other operations should be performed concurrently. */
00183 
00184         prism2_enable_aux_port(dev, 1);
00185 
00186         for (i = 0; i < NUM_PDA_ADDRS; i++) {
00187                 printk(KERN_DEBUG "%s: trying to read PDA from 0x%08x",
00188                        dev->name, pda_addr[i]);
00189                 res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
00190                 if (res)
00191                         continue;
00192                 if (res == 0 && prism2_pda_ok(buf)) {
00193                         printk(": OK\n");
00194                         found = 1;
00195                         break;
00196                 } else {
00197                         printk(": failed\n");
00198                 }
00199         }
00200 
00201         prism2_enable_aux_port(dev, 0);
00202 
00203         if (!found) {
00204                 kfree(buf);
00205                 buf = NULL;
00206         }
00207 
00208         return buf;
00209 }
00210 
00211 
00212 static int prism2_download_volatile(local_info_t *local,
00213                                     struct prism2_download_data *param)
00214 {
00215         struct net_device *dev = local->dev;
00216         int ret = 0, i;
00217         u16 param0, param1;
00218 
00219         if (local->hw_downloading) {
00220                 printk(KERN_WARNING "%s: Already downloading - aborting new "
00221                        "request\n", dev->name);
00222                 return -1;
00223         }
00224 
00225         local->hw_downloading = 1;
00226         if (local->pri_only) {
00227                 hfa384x_disable_interrupts(dev);
00228         } else {
00229                 prism2_hw_shutdown(dev, 0);
00230 
00231                 if (prism2_hw_init(dev, 0)) {
00232                         printk(KERN_WARNING "%s: Could not initialize card for"
00233                                " download\n", dev->name);
00234                         ret = -1;
00235                         goto out;
00236                 }
00237         }
00238 
00239         if (prism2_enable_aux_port(dev, 1)) {
00240                 printk(KERN_WARNING "%s: Could not enable AUX port\n",
00241                        dev->name);
00242                 ret = -1;
00243                 goto out;
00244         }
00245 
00246         param0 = param->start_addr & 0xffff;
00247         param1 = param->start_addr >> 16;
00248 
00249         HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
00250         HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
00251         if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
00252                              (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
00253                              param0)) {
00254                 printk(KERN_WARNING "%s: Download command execution failed\n",
00255                        dev->name);
00256                 ret = -1;
00257                 goto out;
00258         }
00259 
00260         for (i = 0; i < param->num_areas; i++) {
00261                 printk(KERN_DEBUG "%s: Writing %d bytes at 0x%08x\n",
00262                        dev->name, param->data[i].len, param->data[i].addr);
00263                 if (hfa384x_to_aux(dev, param->data[i].addr,
00264                                    param->data[i].len, param->data[i].data)) {
00265                         printk(KERN_WARNING "%s: RAM download at 0x%08x "
00266                                "(len=%d) failed\n", dev->name,
00267                                param->data[i].addr, param->data[i].len);
00268                         ret = -1;
00269                         goto out;
00270                 }
00271         }
00272 
00273         HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
00274         HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
00275         if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
00276                                 (HFA384X_PROGMODE_DISABLE << 8), param0)) {
00277                 printk(KERN_WARNING "%s: Download command execution failed\n",
00278                        dev->name);
00279                 ret = -1;
00280                 goto out;
00281         }
00282         /* ProgMode disable causes the hardware to restart itself from the
00283          * given starting address. Give hw some time and ACK command just in
00284          * case restart did not happen. */
00285         mdelay(5);
00286         HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
00287 
00288         if (prism2_enable_aux_port(dev, 0)) {
00289                 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
00290                        dev->name);
00291                 /* continue anyway.. restart should have taken care of this */
00292         }
00293 
00294         mdelay(5);
00295         local->hw_downloading = 0;
00296         if (prism2_hw_config(dev, 2)) {
00297                 printk(KERN_WARNING "%s: Card configuration after RAM "
00298                        "download failed\n", dev->name);
00299                 ret = -1;
00300                 goto out2;
00301         }
00302 
00303         goto out2;
00304  out:
00305         local->hw_downloading = 0;
00306  out2:
00307         return ret;
00308 }
00309 
00310 
00311 static int prism2_enable_genesis(local_info_t *local, int hcr)
00312 {
00313         struct net_device *dev = local->dev;
00314         u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
00315         u8 readbuf[4];
00316 
00317         printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
00318                dev->name, hcr);
00319         local->func->cor_sreset(local);
00320         hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
00321         local->func->genesis_reset(local, hcr);
00322 
00323         /* Readback test */
00324         hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
00325         hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
00326         hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
00327 
00328         if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
00329                 printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
00330                        hcr);
00331                 return 0;
00332         } else {
00333                 printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
00334                        "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
00335                        hcr, initseq[0], initseq[1], initseq[2], initseq[3],
00336                        readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
00337                 return 1;
00338         }
00339 }
00340 
00341 
00342 static int prism2_download_genesis(local_info_t *local,
00343                                    struct prism2_download_data *param)
00344 {
00345         struct net_device *dev = local->dev;
00346         int ram16 = 0, i;
00347 
00348         if (local->hw_downloading) {
00349                 printk(KERN_WARNING "%s: Already downloading - aborting new "
00350                        "request\n", dev->name);
00351                 return -EBUSY;
00352         }
00353 
00354         if (!local->func->genesis_reset || !local->func->cor_sreset) {
00355                 printk(KERN_INFO "%s: Genesis mode downloading not supported "
00356                        "with this hwmodel\n", dev->name);
00357                 return -EOPNOTSUPP;
00358         }
00359 
00360         local->hw_downloading = 1;
00361 
00362         if (prism2_enable_aux_port(dev, 1)) {
00363                 printk(KERN_DEBUG "%s: failed to enable AUX port\n",
00364                        dev->name);
00365                 return -EIO;
00366         }
00367 
00368         /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
00369         if (prism2_enable_genesis(local, 0x1f) == 0) {
00370                 ram16 = 0;
00371                 printk(KERN_DEBUG "%s: Genesis mode OK using x8 SRAM\n",
00372                        dev->name);
00373         } else if (prism2_enable_genesis(local, 0x0f) == 0) {
00374                 ram16 = 1;
00375                 printk(KERN_DEBUG "%s: Genesis mode OK using x16 SRAM\n",
00376                        dev->name);
00377         } else {
00378                 printk(KERN_DEBUG "%s: Could not initiate genesis mode\n",
00379                        dev->name);
00380                 return -EIO;
00381         }
00382 
00383         for (i = 0; i < param->num_areas; i++) {
00384                 printk(KERN_DEBUG "%s: Writing %d bytes at 0x%08x\n",
00385                        dev->name, param->data[i].len, param->data[i].addr);
00386                 if (hfa384x_to_aux(dev, param->data[i].addr,
00387                                    param->data[i].len, param->data[i].data)) {
00388                         printk(KERN_WARNING "%s: RAM download at 0x%08x "
00389                                "(len=%d) failed\n", dev->name,
00390                                param->data[i].addr, param->data[i].len);
00391                         return -EIO;
00392                 }
00393         }
00394 
00395         printk(KERN_DEBUG "Disable genesis mode\n");
00396         local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
00397         if (prism2_enable_aux_port(dev, 0)) {
00398                 printk(KERN_DEBUG "Failed to disable AUX port\n");
00399         }
00400 
00401         mdelay(5);
00402         local->hw_downloading = 0;
00403 
00404         printk(KERN_DEBUG "Trying to initialize card\n");
00405         if (prism2_hw_init(dev, 1)) {
00406                 printk(KERN_DEBUG "Initialization failed\n");
00407                 return -EIO;
00408         }
00409 
00410         printk(KERN_DEBUG "Card initialized - running PRI only\n");
00411         if (prism2_hw_init(dev, 1) || prism2_hw_init2(dev, 1)) {
00412                 printk(KERN_DEBUG "Initialization failed\n");
00413                 return -EIO;
00414         }
00415 
00416         return 0;
00417 }
00418 
00419 
00420 #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
00421 /* Note! Non-volatile downloading functionality has not yet been tested
00422  * thoroughly and it may corrupt flash image and effectively kill the card that
00423  * is being updated. You have been warned. */
00424 
00425 static inline int prism2_download_block(struct net_device *dev,
00426                                         u32 addr, u8 *data,
00427                                         u32 bufaddr, int rest_len)
00428 {
00429         u16 param0, param1;
00430         int block_len;
00431 
00432         block_len = rest_len < 4096 ? rest_len : 4096;
00433 
00434         param0 = addr & 0xffff;
00435         param1 = addr >> 16;
00436 
00437         HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
00438         HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
00439 
00440         if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
00441                              (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
00442                              param0)) {
00443                 printk(KERN_WARNING "%s: Flash download command execution "
00444                        "failed\n", dev->name);
00445                 return -1;
00446         }
00447 
00448         if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
00449                 printk(KERN_WARNING "%s: flash download at 0x%08x "
00450                        "(len=%d) failed\n", dev->name, addr, block_len);
00451                 return -1;
00452         }
00453 
00454         HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
00455         HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
00456         if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
00457                              (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
00458                              0)) {
00459                 printk(KERN_WARNING "%s: Flash write command execution "
00460                        "failed\n", dev->name);
00461                 return -1;
00462         }
00463 
00464         return block_len;
00465 }
00466 
00467 
00468 static int prism2_download_nonvolatile(local_info_t *local,
00469                                        struct prism2_download_data *dl)
00470 {
00471         struct net_device *dev = local->dev;
00472         int ret = 0, i;
00473         struct {
00474                 u16 page;
00475                 u16 offset;
00476                 u16 len;
00477         } dlbuffer;
00478         u32 bufaddr;
00479 
00480         if (local->hw_downloading) {
00481                 printk(KERN_WARNING "%s: Already downloading - aborting new "
00482                        "request\n", dev->name);
00483                 return -1;
00484         }
00485 
00486         local->hw_downloading = 1;
00487 
00488         ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
00489                                    &dlbuffer, 6, 0);
00490 
00491         if (ret < 0) {
00492                 printk(KERN_WARNING "%s: Could not read download buffer "
00493                        "parameters\n", dev->name);
00494                 goto out;
00495         }
00496 
00497         dlbuffer.page = le16_to_cpu(dlbuffer.page);
00498         dlbuffer.offset = le16_to_cpu(dlbuffer.offset);
00499         dlbuffer.len = le16_to_cpu(dlbuffer.len);
00500 
00501         printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
00502                dlbuffer.len, dlbuffer.page, dlbuffer.offset);
00503 
00504         bufaddr = (dlbuffer.page << 7) + dlbuffer.offset;
00505 
00506         if (!local->pri_only) {
00507                 prism2_hw_shutdown(dev, 0);
00508 
00509                 if (prism2_hw_init(dev, 0)) {
00510                         printk(KERN_WARNING "%s: Could not initialize card for"
00511                                " download\n", dev->name);
00512                         ret = -1;
00513                         goto out;
00514                 }
00515         }
00516 
00517         hfa384x_disable_interrupts(dev);
00518 
00519         if (prism2_enable_aux_port(dev, 1)) {
00520                 printk(KERN_WARNING "%s: Could not enable AUX port\n",
00521                        dev->name);
00522                 ret = -1;
00523                 goto out;
00524         }
00525 
00526         printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
00527         for (i = 0; i < dl->num_areas; i++) {
00528                 int rest_len = dl->data[i].len;
00529                 int data_off = 0;
00530 
00531                 while (rest_len > 0) {
00532                         int block_len;
00533 
00534                         block_len = prism2_download_block(
00535                                 dev, dl->data[i].addr + data_off,
00536                                 dl->data[i].data + data_off, bufaddr,
00537                                 rest_len);
00538 
00539                         if (block_len < 0) {
00540                                 ret = -1;
00541                                 goto out;
00542                         }
00543 
00544                         rest_len -= block_len;
00545                         data_off += block_len;
00546                 }
00547         }
00548 
00549         HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
00550         HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
00551         if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
00552                                 (HFA384X_PROGMODE_DISABLE << 8), 0)) {
00553                 printk(KERN_WARNING "%s: Download command execution failed\n",
00554                        dev->name);
00555                 ret = -1;
00556                 goto out;
00557         }
00558 
00559         if (prism2_enable_aux_port(dev, 0)) {
00560                 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
00561                        dev->name);
00562                 /* continue anyway.. restart should have taken care of this */
00563         }
00564 
00565         mdelay(5);
00566 
00567         local->func->hw_reset(dev);
00568         local->hw_downloading = 0;
00569         if (prism2_hw_config(dev, 2)) {
00570                 printk(KERN_WARNING "%s: Card configuration after flash "
00571                        "download failed\n", dev->name);
00572                 ret = -1;
00573         } else {
00574                 printk(KERN_INFO "%s: Card initialized successfully after "
00575                        "flash download\n", dev->name);
00576         }
00577 
00578  out:
00579         local->hw_downloading = 0;
00580         return ret;
00581 }
00582 #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
00583 
00584 
00585 static void prism2_download_free_data(struct prism2_download_data *dl)
00586 {
00587         int i;
00588 
00589         if (dl == NULL)
00590                 return;
00591 
00592         for (i = 0; i < dl->num_areas; i++)
00593                 kfree(dl->data[i].data);
00594         kfree(dl);
00595 }
00596 
00597 
00598 static int prism2_download(local_info_t *local,
00599                            struct prism2_download_param *param)
00600 {
00601         int ret = 0;
00602         int i;
00603         u32 total_len = 0;
00604         struct prism2_download_data *dl = NULL;
00605 
00606         printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
00607                "num_areas=%d\n",
00608                param->dl_cmd, param->start_addr, param->num_areas);
00609 
00610         if (param->num_areas > 100) {
00611                 ret = -EINVAL;
00612                 goto out;
00613         }
00614 
00615         dl = kmalloc(sizeof(*dl) + param->num_areas *
00616                      sizeof(struct prism2_download_data_area), GFP_KERNEL);
00617         if (dl == NULL) {
00618                 ret = -ENOMEM;
00619                 goto out;
00620         }
00621         memset(dl, 0, sizeof(*dl) + param->num_areas *
00622                sizeof(struct prism2_download_data_area));
00623         dl->dl_cmd = param->dl_cmd;
00624         dl->start_addr = param->start_addr;
00625         dl->num_areas = param->num_areas;
00626         for (i = 0; i < param->num_areas; i++) {
00627                 printk(KERN_DEBUG "  area %d: addr=0x%08x len=%d ptr=0x%p\n",
00628                        i, param->data[i].addr, param->data[i].len,
00629                        param->data[i].ptr);
00630 
00631                 dl->data[i].addr = param->data[i].addr;
00632                 dl->data[i].len = param->data[i].len;
00633 
00634                 total_len += param->data[i].len;
00635                 if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
00636                     total_len > PRISM2_MAX_DOWNLOAD_LEN) {
00637                         ret = -E2BIG;
00638                         goto out;
00639                 }
00640 
00641                 dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
00642                 if (dl->data[i].data == NULL) {
00643                         ret = -ENOMEM;
00644                         goto out;
00645                 }
00646 
00647                 if (copy_from_user(dl->data[i].data, param->data[i].ptr,
00648                                    param->data[i].len)) {
00649                         ret = -EFAULT;
00650                         goto out;
00651                 }
00652         }
00653 
00654         switch (param->dl_cmd) {
00655         case PRISM2_DOWNLOAD_VOLATILE:
00656         case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
00657                 ret = prism2_download_volatile(local, dl);
00658                 break;
00659         case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
00660         case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
00661                 ret = prism2_download_genesis(local, dl);
00662                 break;
00663         case PRISM2_DOWNLOAD_NON_VOLATILE:
00664 #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
00665                 ret = prism2_download_nonvolatile(local, dl);
00666 #else /* PRISM2_NON_VOLATILE_DOWNLOAD */
00667                 printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
00668                        local->dev->name);
00669                 ret = -EOPNOTSUPP;
00670 #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
00671                 break;
00672         default:
00673                 printk(KERN_DEBUG "%s: unsupported download command %d\n",
00674                        local->dev->name, param->dl_cmd);
00675                 ret = -EINVAL;
00676                 break;
00677         };
00678 
00679  out:
00680         if (ret == 0 && dl &&
00681             param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
00682                 prism2_download_free_data(local->dl_pri);
00683                 local->dl_pri = dl;
00684         } else if (ret == 0 && dl &&
00685                    param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
00686                 prism2_download_free_data(local->dl_sec);
00687                 local->dl_sec = dl;
00688         } else
00689                 prism2_download_free_data(dl);
00690 
00691         return ret;
00692 }

Generated on Mon Nov 21 15:58:09 2005 for openwifi by  doxygen 1.4.1