blob: 89d3849abfe002f67a53ea2ea4111625f7e6358e [file] [log] [blame]
Jouni Malinenff1d2762005-05-12 22:54:16 -04001static int prism2_enable_aux_port(struct net_device *dev, int enable)
2{
3 u16 val, reg;
4 int i, tries;
5 unsigned long flags;
6 struct hostap_interface *iface;
7 local_info_t *local;
8
9 iface = netdev_priv(dev);
10 local = iface->local;
11
12 if (local->no_pri) {
13 if (enable) {
14 PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
15 "port is already enabled\n", dev->name);
16 }
17 return 0;
18 }
19
20 spin_lock_irqsave(&local->cmdlock, flags);
21
22 /* wait until busy bit is clear */
23 tries = HFA384X_CMD_BUSY_TIMEOUT;
24 while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
25 tries--;
26 udelay(1);
27 }
28 if (tries == 0) {
29 reg = HFA384X_INW(HFA384X_CMD_OFF);
30 spin_unlock_irqrestore(&local->cmdlock, flags);
31 printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
32 dev->name, reg);
33 return -ETIMEDOUT;
34 }
35
36 val = HFA384X_INW(HFA384X_CONTROL_OFF);
37
38 if (enable) {
39 HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
40 HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
41 HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
42
43 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
44 printk("prism2_enable_aux_port: was not disabled!?\n");
45 val &= ~HFA384X_AUX_PORT_MASK;
46 val |= HFA384X_AUX_PORT_ENABLE;
47 } else {
48 HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
49 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
50 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
51
52 if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
53 printk("prism2_enable_aux_port: was not enabled!?\n");
54 val &= ~HFA384X_AUX_PORT_MASK;
55 val |= HFA384X_AUX_PORT_DISABLE;
56 }
57 HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
58
59 udelay(5);
60
61 i = 10000;
62 while (i > 0) {
63 val = HFA384X_INW(HFA384X_CONTROL_OFF);
64 val &= HFA384X_AUX_PORT_MASK;
65
66 if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
67 (!enable && val == HFA384X_AUX_PORT_DISABLED))
68 break;
69
70 udelay(10);
71 i--;
72 }
73
74 spin_unlock_irqrestore(&local->cmdlock, flags);
75
76 if (i == 0) {
77 printk("prism2_enable_aux_port(%d) timed out\n",
78 enable);
79 return -ETIMEDOUT;
80 }
81
82 return 0;
83}
84
85
86static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
87 void *buf)
88{
89 u16 page, offset;
90 if (addr & 1 || len & 1)
91 return -1;
92
93 page = addr >> 7;
94 offset = addr & 0x7f;
95
96 HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
97 HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
98
99 udelay(5);
100
101#ifdef PRISM2_PCI
102 {
Al Viro8a9faf32007-12-21 03:30:16 -0500103 __le16 *pos = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400104 while (len > 0) {
105 *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
106 len -= 2;
107 }
108 }
109#else /* PRISM2_PCI */
110 HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
111#endif /* PRISM2_PCI */
112
113 return 0;
114}
115
116
117static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
118 void *buf)
119{
120 u16 page, offset;
121 if (addr & 1 || len & 1)
122 return -1;
123
124 page = addr >> 7;
125 offset = addr & 0x7f;
126
127 HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
128 HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
129
130 udelay(5);
131
132#ifdef PRISM2_PCI
133 {
Al Viro8a9faf32007-12-21 03:30:16 -0500134 __le16 *pos = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400135 while (len > 0) {
136 HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
137 len -= 2;
138 }
139 }
140#else /* PRISM2_PCI */
141 HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
142#endif /* PRISM2_PCI */
143
144 return 0;
145}
146
147
148static int prism2_pda_ok(u8 *buf)
149{
Al Viro8a9faf32007-12-21 03:30:16 -0500150 __le16 *pda = (__le16 *) buf;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400151 int pos;
152 u16 len, pdr;
153
154 if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
155 buf[3] == 0x00)
156 return 0;
157
158 pos = 0;
159 while (pos + 1 < PRISM2_PDA_SIZE / 2) {
160 len = le16_to_cpu(pda[pos]);
161 pdr = le16_to_cpu(pda[pos + 1]);
162 if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
163 return 0;
164
165 if (pdr == 0x0000 && len == 2) {
166 /* PDA end found */
167 return 1;
168 }
169
170 pos += len + 1;
171 }
172
173 return 0;
174}
175
176
177static int prism2_download_aux_dump(struct net_device *dev,
178 unsigned int addr, int len, u8 *buf)
179{
180 int res;
181
182 prism2_enable_aux_port(dev, 1);
183 res = hfa384x_from_aux(dev, addr, len, buf);
184 prism2_enable_aux_port(dev, 0);
185 if (res)
186 return -1;
187
188 return 0;
189}
190
191
192static u8 * prism2_read_pda(struct net_device *dev)
193{
194 u8 *buf;
195 int res, i, found = 0;
196#define NUM_PDA_ADDRS 4
197 unsigned int pda_addr[NUM_PDA_ADDRS] = {
198 0x7f0000 /* others than HFA3841 */,
199 0x3f0000 /* HFA3841 */,
200 0x390000 /* apparently used in older cards */,
201 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
202 };
203
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800204 buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
Jouni Malinenff1d2762005-05-12 22:54:16 -0400205 if (buf == NULL)
206 return NULL;
207
208 /* Note: wlan card should be in initial state (just after init cmd)
209 * and no other operations should be performed concurrently. */
210
211 prism2_enable_aux_port(dev, 1);
212
213 for (i = 0; i < NUM_PDA_ADDRS; i++) {
214 PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
215 dev->name, pda_addr[i]);
216 res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
217 if (res)
218 continue;
219 if (res == 0 && prism2_pda_ok(buf)) {
220 PDEBUG2(DEBUG_EXTRA2, ": OK\n");
221 found = 1;
222 break;
223 } else {
224 PDEBUG2(DEBUG_EXTRA2, ": failed\n");
225 }
226 }
227
228 prism2_enable_aux_port(dev, 0);
229
230 if (!found) {
231 printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
232 kfree(buf);
233 buf = NULL;
234 }
235
236 return buf;
237}
238
239
240static int prism2_download_volatile(local_info_t *local,
241 struct prism2_download_data *param)
242{
243 struct net_device *dev = local->dev;
244 int ret = 0, i;
245 u16 param0, param1;
246
247 if (local->hw_downloading) {
248 printk(KERN_WARNING "%s: Already downloading - aborting new "
249 "request\n", dev->name);
250 return -1;
251 }
252
253 local->hw_downloading = 1;
254 if (local->pri_only) {
255 hfa384x_disable_interrupts(dev);
256 } else {
257 prism2_hw_shutdown(dev, 0);
258
259 if (prism2_hw_init(dev, 0)) {
260 printk(KERN_WARNING "%s: Could not initialize card for"
261 " download\n", dev->name);
262 ret = -1;
263 goto out;
264 }
265 }
266
267 if (prism2_enable_aux_port(dev, 1)) {
268 printk(KERN_WARNING "%s: Could not enable AUX port\n",
269 dev->name);
270 ret = -1;
271 goto out;
272 }
273
274 param0 = param->start_addr & 0xffff;
275 param1 = param->start_addr >> 16;
276
277 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
278 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
279 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
280 (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
281 param0)) {
282 printk(KERN_WARNING "%s: Download command execution failed\n",
283 dev->name);
284 ret = -1;
285 goto out;
286 }
287
288 for (i = 0; i < param->num_areas; i++) {
289 PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
290 dev->name, param->data[i].len, param->data[i].addr);
291 if (hfa384x_to_aux(dev, param->data[i].addr,
292 param->data[i].len, param->data[i].data)) {
293 printk(KERN_WARNING "%s: RAM download at 0x%08x "
294 "(len=%d) failed\n", dev->name,
295 param->data[i].addr, param->data[i].len);
296 ret = -1;
297 goto out;
298 }
299 }
300
301 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
302 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
303 if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
304 (HFA384X_PROGMODE_DISABLE << 8), param0)) {
305 printk(KERN_WARNING "%s: Download command execution failed\n",
306 dev->name);
307 ret = -1;
308 goto out;
309 }
310 /* ProgMode disable causes the hardware to restart itself from the
311 * given starting address. Give hw some time and ACK command just in
312 * case restart did not happen. */
313 mdelay(5);
314 HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
315
316 if (prism2_enable_aux_port(dev, 0)) {
317 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
318 dev->name);
319 /* continue anyway.. restart should have taken care of this */
320 }
321
322 mdelay(5);
323 local->hw_downloading = 0;
324 if (prism2_hw_config(dev, 2)) {
325 printk(KERN_WARNING "%s: Card configuration after RAM "
326 "download failed\n", dev->name);
327 ret = -1;
328 goto out;
329 }
330
331 out:
332 local->hw_downloading = 0;
333 return ret;
334}
335
336
337static int prism2_enable_genesis(local_info_t *local, int hcr)
338{
339 struct net_device *dev = local->dev;
340 u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
341 u8 readbuf[4];
342
343 printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
344 dev->name, hcr);
345 local->func->cor_sreset(local);
346 hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
347 local->func->genesis_reset(local, hcr);
348
349 /* Readback test */
350 hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
351 hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
352 hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
353
354 if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
355 printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
356 hcr);
357 return 0;
358 } else {
359 printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
360 "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
361 hcr, initseq[0], initseq[1], initseq[2], initseq[3],
362 readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
363 return 1;
364 }
365}
366
367
368static int prism2_get_ram_size(local_info_t *local)
369{
370 int ret;
371
372 /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
373 if (prism2_enable_genesis(local, 0x1f) == 0)
374 ret = 8;
375 else if (prism2_enable_genesis(local, 0x0f) == 0)
376 ret = 16;
377 else
378 ret = -1;
379
380 /* Disable genesis mode */
381 local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
382
383 return ret;
384}
385
386
387static int prism2_download_genesis(local_info_t *local,
388 struct prism2_download_data *param)
389{
390 struct net_device *dev = local->dev;
391 int ram16 = 0, i;
392 int ret = 0;
393
394 if (local->hw_downloading) {
395 printk(KERN_WARNING "%s: Already downloading - aborting new "
396 "request\n", dev->name);
397 return -EBUSY;
398 }
399
400 if (!local->func->genesis_reset || !local->func->cor_sreset) {
401 printk(KERN_INFO "%s: Genesis mode downloading not supported "
402 "with this hwmodel\n", dev->name);
403 return -EOPNOTSUPP;
404 }
405
406 local->hw_downloading = 1;
407
408 if (prism2_enable_aux_port(dev, 1)) {
409 printk(KERN_DEBUG "%s: failed to enable AUX port\n",
410 dev->name);
411 ret = -EIO;
412 goto out;
413 }
414
415 if (local->sram_type == -1) {
416 /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
417 if (prism2_enable_genesis(local, 0x1f) == 0) {
418 ram16 = 0;
419 PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
420 "SRAM\n", dev->name);
421 } else if (prism2_enable_genesis(local, 0x0f) == 0) {
422 ram16 = 1;
423 PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
424 "SRAM\n", dev->name);
425 } else {
426 printk(KERN_DEBUG "%s: Could not initiate genesis "
427 "mode\n", dev->name);
428 ret = -EIO;
429 goto out;
430 }
431 } else {
432 if (prism2_enable_genesis(local, local->sram_type == 8 ?
433 0x1f : 0x0f)) {
434 printk(KERN_DEBUG "%s: Failed to set Genesis "
435 "mode (sram_type=%d)\n", dev->name,
436 local->sram_type);
437 ret = -EIO;
438 goto out;
439 }
440 ram16 = local->sram_type != 8;
441 }
442
443 for (i = 0; i < param->num_areas; i++) {
444 PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
445 dev->name, param->data[i].len, param->data[i].addr);
446 if (hfa384x_to_aux(dev, param->data[i].addr,
447 param->data[i].len, param->data[i].data)) {
448 printk(KERN_WARNING "%s: RAM download at 0x%08x "
449 "(len=%d) failed\n", dev->name,
450 param->data[i].addr, param->data[i].len);
451 ret = -EIO;
452 goto out;
453 }
454 }
455
456 PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
457 local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
458 if (prism2_enable_aux_port(dev, 0)) {
459 printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
460 dev->name);
461 }
462
463 mdelay(5);
464 local->hw_downloading = 0;
465
466 PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
467 /*
468 * Make sure the INIT command does not generate a command completion
469 * event by disabling interrupts.
470 */
471 hfa384x_disable_interrupts(dev);
472 if (prism2_hw_init(dev, 1)) {
473 printk(KERN_DEBUG "%s: Initialization after genesis mode "
474 "download failed\n", dev->name);
475 ret = -EIO;
476 goto out;
477 }
478
479 PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
480 if (prism2_hw_init2(dev, 1)) {
481 printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
482 "download failed\n", dev->name);
483 ret = -EIO;
484 goto out;
485 }
486
487 out:
488 local->hw_downloading = 0;
489 return ret;
490}
491
492
493#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
494/* Note! Non-volatile downloading functionality has not yet been tested
495 * thoroughly and it may corrupt flash image and effectively kill the card that
496 * is being updated. You have been warned. */
497
498static inline int prism2_download_block(struct net_device *dev,
499 u32 addr, u8 *data,
500 u32 bufaddr, int rest_len)
501{
502 u16 param0, param1;
503 int block_len;
504
505 block_len = rest_len < 4096 ? rest_len : 4096;
506
507 param0 = addr & 0xffff;
508 param1 = addr >> 16;
509
510 HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
511 HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
512
513 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
514 (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
515 param0)) {
516 printk(KERN_WARNING "%s: Flash download command execution "
517 "failed\n", dev->name);
518 return -1;
519 }
520
521 if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
522 printk(KERN_WARNING "%s: flash download at 0x%08x "
523 "(len=%d) failed\n", dev->name, addr, block_len);
524 return -1;
525 }
526
527 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
528 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
529 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
530 (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
531 0)) {
532 printk(KERN_WARNING "%s: Flash write command execution "
533 "failed\n", dev->name);
534 return -1;
535 }
536
537 return block_len;
538}
539
540
541static int prism2_download_nonvolatile(local_info_t *local,
542 struct prism2_download_data *dl)
543{
544 struct net_device *dev = local->dev;
545 int ret = 0, i;
546 struct {
Al Viro8a9faf32007-12-21 03:30:16 -0500547 __le16 page;
548 __le16 offset;
549 __le16 len;
Jouni Malinenff1d2762005-05-12 22:54:16 -0400550 } dlbuffer;
551 u32 bufaddr;
552
553 if (local->hw_downloading) {
554 printk(KERN_WARNING "%s: Already downloading - aborting new "
555 "request\n", dev->name);
556 return -1;
557 }
558
559 ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
560 &dlbuffer, 6, 0);
561
562 if (ret < 0) {
563 printk(KERN_WARNING "%s: Could not read download buffer "
564 "parameters\n", dev->name);
565 goto out;
566 }
567
Jouni Malinenff1d2762005-05-12 22:54:16 -0400568 printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
Al Viro8a9faf32007-12-21 03:30:16 -0500569 le16_to_cpu(dlbuffer.len),
570 le16_to_cpu(dlbuffer.page),
571 le16_to_cpu(dlbuffer.offset));
Jouni Malinenff1d2762005-05-12 22:54:16 -0400572
Al Viro8a9faf32007-12-21 03:30:16 -0500573 bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
Jouni Malinenff1d2762005-05-12 22:54:16 -0400574
575 local->hw_downloading = 1;
576
577 if (!local->pri_only) {
578 prism2_hw_shutdown(dev, 0);
579
580 if (prism2_hw_init(dev, 0)) {
581 printk(KERN_WARNING "%s: Could not initialize card for"
582 " download\n", dev->name);
583 ret = -1;
584 goto out;
585 }
586 }
587
588 hfa384x_disable_interrupts(dev);
589
590 if (prism2_enable_aux_port(dev, 1)) {
591 printk(KERN_WARNING "%s: Could not enable AUX port\n",
592 dev->name);
593 ret = -1;
594 goto out;
595 }
596
597 printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
598 for (i = 0; i < dl->num_areas; i++) {
599 int rest_len = dl->data[i].len;
600 int data_off = 0;
601
602 while (rest_len > 0) {
603 int block_len;
604
605 block_len = prism2_download_block(
606 dev, dl->data[i].addr + data_off,
607 dl->data[i].data + data_off, bufaddr,
608 rest_len);
609
610 if (block_len < 0) {
611 ret = -1;
612 goto out;
613 }
614
615 rest_len -= block_len;
616 data_off += block_len;
617 }
618 }
619
620 HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
621 HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
622 if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
623 (HFA384X_PROGMODE_DISABLE << 8), 0)) {
624 printk(KERN_WARNING "%s: Download command execution failed\n",
625 dev->name);
626 ret = -1;
627 goto out;
628 }
629
630 if (prism2_enable_aux_port(dev, 0)) {
631 printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
632 dev->name);
633 /* continue anyway.. restart should have taken care of this */
634 }
635
636 mdelay(5);
637
638 local->func->hw_reset(dev);
639 local->hw_downloading = 0;
640 if (prism2_hw_config(dev, 2)) {
641 printk(KERN_WARNING "%s: Card configuration after flash "
642 "download failed\n", dev->name);
643 ret = -1;
644 } else {
645 printk(KERN_INFO "%s: Card initialized successfully after "
646 "flash download\n", dev->name);
647 }
648
649 out:
650 local->hw_downloading = 0;
651 return ret;
652}
653#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
654
655
656static void prism2_download_free_data(struct prism2_download_data *dl)
657{
658 int i;
659
660 if (dl == NULL)
661 return;
662
663 for (i = 0; i < dl->num_areas; i++)
664 kfree(dl->data[i].data);
665 kfree(dl);
666}
667
668
669static int prism2_download(local_info_t *local,
670 struct prism2_download_param *param)
671{
672 int ret = 0;
673 int i;
674 u32 total_len = 0;
675 struct prism2_download_data *dl = NULL;
676
677 printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
678 "num_areas=%d\n",
679 param->dl_cmd, param->start_addr, param->num_areas);
680
681 if (param->num_areas > 100) {
682 ret = -EINVAL;
683 goto out;
684 }
685
Yan Burmanb0471bb72006-12-02 13:33:40 +0200686 dl = kzalloc(sizeof(*dl) + param->num_areas *
Jouni Malinenff1d2762005-05-12 22:54:16 -0400687 sizeof(struct prism2_download_data_area), GFP_KERNEL);
688 if (dl == NULL) {
689 ret = -ENOMEM;
690 goto out;
691 }
Jouni Malinenff1d2762005-05-12 22:54:16 -0400692 dl->dl_cmd = param->dl_cmd;
693 dl->start_addr = param->start_addr;
694 dl->num_areas = param->num_areas;
695 for (i = 0; i < param->num_areas; i++) {
696 PDEBUG(DEBUG_EXTRA2,
697 " area %d: addr=0x%08x len=%d ptr=0x%p\n",
698 i, param->data[i].addr, param->data[i].len,
699 param->data[i].ptr);
700
701 dl->data[i].addr = param->data[i].addr;
702 dl->data[i].len = param->data[i].len;
703
704 total_len += param->data[i].len;
705 if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
706 total_len > PRISM2_MAX_DOWNLOAD_LEN) {
707 ret = -E2BIG;
708 goto out;
709 }
710
711 dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
712 if (dl->data[i].data == NULL) {
713 ret = -ENOMEM;
714 goto out;
715 }
716
717 if (copy_from_user(dl->data[i].data, param->data[i].ptr,
718 param->data[i].len)) {
719 ret = -EFAULT;
720 goto out;
721 }
722 }
723
724 switch (param->dl_cmd) {
725 case PRISM2_DOWNLOAD_VOLATILE:
726 case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
727 ret = prism2_download_volatile(local, dl);
728 break;
729 case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
730 case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
731 ret = prism2_download_genesis(local, dl);
732 break;
733 case PRISM2_DOWNLOAD_NON_VOLATILE:
734#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
735 ret = prism2_download_nonvolatile(local, dl);
736#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
737 printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
738 local->dev->name);
739 ret = -EOPNOTSUPP;
740#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
741 break;
742 default:
743 printk(KERN_DEBUG "%s: unsupported download command %d\n",
744 local->dev->name, param->dl_cmd);
745 ret = -EINVAL;
746 break;
747 };
748
749 out:
750 if (ret == 0 && dl &&
751 param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
752 prism2_download_free_data(local->dl_pri);
753 local->dl_pri = dl;
754 } else if (ret == 0 && dl &&
755 param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
756 prism2_download_free_data(local->dl_sec);
757 local->dl_sec = dl;
758 } else
759 prism2_download_free_data(dl);
760
761 return ret;
762}