diff options
author | David Kilroy <kilroyd@gmail.com> | 2008-08-21 18:27:54 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-22 19:28:05 -0400 |
commit | 3994d502017a2239e30152d1231843ad05d04a7b (patch) | |
tree | c4f15d1b95783d035d954173167ff08e65665461 /drivers/net | |
parent | 8f5ae73c5366128d3800cf9765507422bcf1ef96 (diff) |
orinoco: Invoke firmware download in main driver
Firmware download is enabled for Agere in orinoco_cs. Symbol firmware
download has been moved out of spectrum_cs into orinoco_cs. Firmware
download is not enabled for Intersil.
Symbol based firmware is restricted to only download on spectrum_cs
based cards.
The firmware names are hardcoded for each firmware type.
Signed-off-by: David Kilroy <kilroyd@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/wireless/airport.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.c | 314 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.h | 9 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_cs.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_nortel.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_pci.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_plx.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_tmd.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/spectrum_cs.c | 159 |
10 files changed, 346 insertions, 156 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 1ac46ad48c3e..ea7da7117f4d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -335,6 +335,7 @@ config HERMES | |||
335 | tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" | 335 | tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" |
336 | depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 | 336 | depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211 |
337 | select WIRELESS_EXT | 337 | select WIRELESS_EXT |
338 | select FW_LOADER | ||
338 | ---help--- | 339 | ---help--- |
339 | A driver for 802.11b wireless cards based on the "Hermes" or | 340 | A driver for 802.11b wireless cards based on the "Hermes" or |
340 | Intersil HFA384x (Prism 2) MAC controller. This includes the vast | 341 | Intersil HFA384x (Prism 2) MAC controller. This includes the vast |
@@ -424,7 +425,6 @@ config PCMCIA_HERMES | |||
424 | config PCMCIA_SPECTRUM | 425 | config PCMCIA_SPECTRUM |
425 | tristate "Symbol Spectrum24 Trilogy PCMCIA card support" | 426 | tristate "Symbol Spectrum24 Trilogy PCMCIA card support" |
426 | depends on PCMCIA && HERMES | 427 | depends on PCMCIA && HERMES |
427 | select FW_LOADER | ||
428 | ---help--- | 428 | ---help--- |
429 | 429 | ||
430 | This is a driver for 802.11b cards using RAM-loadable Symbol | 430 | This is a driver for 802.11b cards using RAM-loadable Symbol |
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c index 6f7eb9f59223..ce03a2e865fa 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/airport.c | |||
@@ -180,7 +180,8 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match) | |||
180 | } | 180 | } |
181 | 181 | ||
182 | /* Allocate space for private device-specific data */ | 182 | /* Allocate space for private device-specific data */ |
183 | dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); | 183 | dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev, |
184 | airport_hard_reset, NULL); | ||
184 | if (! dev) { | 185 | if (! dev) { |
185 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | 186 | printk(KERN_ERR PFX "Cannot allocate network device\n"); |
186 | return -ENODEV; | 187 | return -ENODEV; |
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 00b1d595fa3c..306697aa3330 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -82,12 +82,14 @@ | |||
82 | #include <linux/netdevice.h> | 82 | #include <linux/netdevice.h> |
83 | #include <linux/etherdevice.h> | 83 | #include <linux/etherdevice.h> |
84 | #include <linux/ethtool.h> | 84 | #include <linux/ethtool.h> |
85 | #include <linux/firmware.h> | ||
85 | #include <linux/if_arp.h> | 86 | #include <linux/if_arp.h> |
86 | #include <linux/wireless.h> | 87 | #include <linux/wireless.h> |
87 | #include <net/iw_handler.h> | 88 | #include <net/iw_handler.h> |
88 | #include <net/ieee80211.h> | 89 | #include <net/ieee80211.h> |
89 | 90 | ||
90 | #include "hermes_rid.h" | 91 | #include "hermes_rid.h" |
92 | #include "hermes_dld.h" | ||
91 | #include "orinoco.h" | 93 | #include "orinoco.h" |
92 | 94 | ||
93 | /********************************************************************/ | 95 | /********************************************************************/ |
@@ -301,6 +303,272 @@ static void orinoco_bss_data_init(struct orinoco_private *priv) | |||
301 | list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); | 303 | list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); |
302 | } | 304 | } |
303 | 305 | ||
306 | |||
307 | /********************************************************************/ | ||
308 | /* Download functionality */ | ||
309 | /********************************************************************/ | ||
310 | |||
311 | struct fw_info { | ||
312 | char *pri_fw; | ||
313 | char *sta_fw; | ||
314 | char *ap_fw; | ||
315 | u32 pda_addr; | ||
316 | u16 pda_size; | ||
317 | }; | ||
318 | |||
319 | const static struct fw_info orinoco_fw[] = { | ||
320 | { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, | ||
321 | { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, | ||
322 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 } | ||
323 | }; | ||
324 | |||
325 | /* Structure used to access fields in FW | ||
326 | * Make sure LE decoding macros are used | ||
327 | */ | ||
328 | struct orinoco_fw_header { | ||
329 | char hdr_vers[6]; /* ASCII string for header version */ | ||
330 | __le16 headersize; /* Total length of header */ | ||
331 | __le32 entry_point; /* NIC entry point */ | ||
332 | __le32 blocks; /* Number of blocks to program */ | ||
333 | __le32 block_offset; /* Offset of block data from eof header */ | ||
334 | __le32 pdr_offset; /* Offset to PDR data from eof header */ | ||
335 | __le32 pri_offset; /* Offset to primary plug data */ | ||
336 | __le32 compat_offset; /* Offset to compatibility data*/ | ||
337 | char signature[0]; /* FW signature length headersize-20 */ | ||
338 | } __attribute__ ((packed)); | ||
339 | |||
340 | /* Download either STA or AP firmware into the card. */ | ||
341 | static int | ||
342 | orinoco_dl_firmware(struct orinoco_private *priv, | ||
343 | const struct fw_info *fw, | ||
344 | int ap) | ||
345 | { | ||
346 | /* Plug Data Area (PDA) */ | ||
347 | __le16 pda[512] = { 0 }; | ||
348 | |||
349 | hermes_t *hw = &priv->hw; | ||
350 | const struct firmware *fw_entry; | ||
351 | const struct orinoco_fw_header *hdr; | ||
352 | const unsigned char *first_block; | ||
353 | const unsigned char *end; | ||
354 | const char *firmware; | ||
355 | struct net_device *dev = priv->ndev; | ||
356 | int err; | ||
357 | |||
358 | if (ap) | ||
359 | firmware = fw->ap_fw; | ||
360 | else | ||
361 | firmware = fw->sta_fw; | ||
362 | |||
363 | printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", | ||
364 | dev->name, firmware); | ||
365 | |||
366 | /* Read current plug data */ | ||
367 | err = hermes_read_pda(hw, pda, fw->pda_addr, | ||
368 | min_t(u16, fw->pda_size, sizeof(pda)), 0); | ||
369 | printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); | ||
370 | if (err) | ||
371 | return err; | ||
372 | |||
373 | err = request_firmware(&fw_entry, firmware, priv->dev); | ||
374 | if (err) { | ||
375 | printk(KERN_ERR "%s: Cannot find firmware %s\n", | ||
376 | dev->name, firmware); | ||
377 | return -ENOENT; | ||
378 | } | ||
379 | |||
380 | hdr = (const struct orinoco_fw_header *) fw_entry->data; | ||
381 | |||
382 | /* Enable aux port to allow programming */ | ||
383 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); | ||
384 | printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); | ||
385 | if (err != 0) | ||
386 | goto abort; | ||
387 | |||
388 | /* Program data */ | ||
389 | first_block = (fw_entry->data + | ||
390 | le16_to_cpu(hdr->headersize) + | ||
391 | le32_to_cpu(hdr->block_offset)); | ||
392 | end = fw_entry->data + fw_entry->size; | ||
393 | |||
394 | err = hermes_program(hw, first_block, end); | ||
395 | printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); | ||
396 | if (err != 0) | ||
397 | goto abort; | ||
398 | |||
399 | /* Update production data */ | ||
400 | first_block = (fw_entry->data + | ||
401 | le16_to_cpu(hdr->headersize) + | ||
402 | le32_to_cpu(hdr->pdr_offset)); | ||
403 | |||
404 | err = hermes_apply_pda_with_defaults(hw, first_block, pda); | ||
405 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); | ||
406 | if (err) | ||
407 | goto abort; | ||
408 | |||
409 | /* Tell card we've finished */ | ||
410 | err = hermesi_program_end(hw); | ||
411 | printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); | ||
412 | if (err != 0) | ||
413 | goto abort; | ||
414 | |||
415 | /* Check if we're running */ | ||
416 | printk(KERN_DEBUG "%s: hermes_present returned %d\n", | ||
417 | dev->name, hermes_present(hw)); | ||
418 | |||
419 | abort: | ||
420 | release_firmware(fw_entry); | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | /* End markers */ | ||
425 | #define TEXT_END 0x1A /* End of text header */ | ||
426 | |||
427 | /* | ||
428 | * Process a firmware image - stop the card, load the firmware, reset | ||
429 | * the card and make sure it responds. For the secondary firmware take | ||
430 | * care of the PDA - read it and then write it on top of the firmware. | ||
431 | */ | ||
432 | static int | ||
433 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | ||
434 | const unsigned char *image, const unsigned char *end, | ||
435 | int secondary) | ||
436 | { | ||
437 | hermes_t *hw = &priv->hw; | ||
438 | int ret; | ||
439 | const unsigned char *ptr; | ||
440 | const unsigned char *first_block; | ||
441 | |||
442 | /* Plug Data Area (PDA) */ | ||
443 | __le16 pda[256]; | ||
444 | |||
445 | /* Binary block begins after the 0x1A marker */ | ||
446 | ptr = image; | ||
447 | while (*ptr++ != TEXT_END); | ||
448 | first_block = ptr; | ||
449 | |||
450 | /* Read the PDA from EEPROM */ | ||
451 | if (secondary) { | ||
452 | ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | /* Stop the firmware, so that it can be safely rewritten */ | ||
458 | if (priv->stop_fw) { | ||
459 | ret = priv->stop_fw(priv, 1); | ||
460 | if (ret) | ||
461 | return ret; | ||
462 | } | ||
463 | |||
464 | /* Program the adapter with new firmware */ | ||
465 | ret = hermes_program(hw, first_block, end); | ||
466 | if (ret) | ||
467 | return ret; | ||
468 | |||
469 | /* Write the PDA to the adapter */ | ||
470 | if (secondary) { | ||
471 | size_t len = hermes_blocks_length(first_block); | ||
472 | ptr = first_block + len; | ||
473 | ret = hermes_apply_pda(hw, ptr, pda); | ||
474 | if (ret) | ||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | /* Run the firmware */ | ||
479 | if (priv->stop_fw) { | ||
480 | ret = priv->stop_fw(priv, 0); | ||
481 | if (ret) | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | /* Reset hermes chip and make sure it responds */ | ||
486 | ret = hermes_init(hw); | ||
487 | |||
488 | /* hermes_reset() should return 0 with the secondary firmware */ | ||
489 | if (secondary && ret != 0) | ||
490 | return -ENODEV; | ||
491 | |||
492 | /* And this should work with any firmware */ | ||
493 | if (!hermes_present(hw)) | ||
494 | return -ENODEV; | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | |||
500 | /* | ||
501 | * Download the firmware into the card, this also does a PCMCIA soft | ||
502 | * reset on the card, to make sure it's in a sane state. | ||
503 | */ | ||
504 | static int | ||
505 | symbol_dl_firmware(struct orinoco_private *priv, | ||
506 | const struct fw_info *fw) | ||
507 | { | ||
508 | struct net_device *dev = priv->ndev; | ||
509 | int ret; | ||
510 | const struct firmware *fw_entry; | ||
511 | |||
512 | if (request_firmware(&fw_entry, fw->pri_fw, | ||
513 | priv->dev) != 0) { | ||
514 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
515 | dev->name, fw->pri_fw); | ||
516 | return -ENOENT; | ||
517 | } | ||
518 | |||
519 | /* Load primary firmware */ | ||
520 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
521 | fw_entry->data + fw_entry->size, 0); | ||
522 | release_firmware(fw_entry); | ||
523 | if (ret) { | ||
524 | printk(KERN_ERR "%s: Primary firmware download failed\n", | ||
525 | dev->name); | ||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | if (request_firmware(&fw_entry, fw->sta_fw, | ||
530 | priv->dev) != 0) { | ||
531 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
532 | dev->name, fw->sta_fw); | ||
533 | return -ENOENT; | ||
534 | } | ||
535 | |||
536 | /* Load secondary firmware */ | ||
537 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
538 | fw_entry->data + fw_entry->size, 1); | ||
539 | release_firmware(fw_entry); | ||
540 | if (ret) { | ||
541 | printk(KERN_ERR "%s: Secondary firmware download failed\n", | ||
542 | dev->name); | ||
543 | } | ||
544 | |||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | static int orinoco_download(struct orinoco_private *priv) | ||
549 | { | ||
550 | int err = 0; | ||
551 | /* Reload firmware */ | ||
552 | switch (priv->firmware_type) { | ||
553 | case FIRMWARE_TYPE_AGERE: | ||
554 | /* case FIRMWARE_TYPE_INTERSIL: */ | ||
555 | err = orinoco_dl_firmware(priv, | ||
556 | &orinoco_fw[priv->firmware_type], 0); | ||
557 | break; | ||
558 | |||
559 | case FIRMWARE_TYPE_SYMBOL: | ||
560 | err = symbol_dl_firmware(priv, | ||
561 | &orinoco_fw[priv->firmware_type]); | ||
562 | break; | ||
563 | case FIRMWARE_TYPE_INTERSIL: | ||
564 | break; | ||
565 | } | ||
566 | /* TODO: if we fail we probably need to reinitialise | ||
567 | * the driver */ | ||
568 | |||
569 | return err; | ||
570 | } | ||
571 | |||
304 | /********************************************************************/ | 572 | /********************************************************************/ |
305 | /* Device methods */ | 573 | /* Device methods */ |
306 | /********************************************************************/ | 574 | /********************************************************************/ |
@@ -2043,6 +2311,12 @@ static void orinoco_reset(struct work_struct *work) | |||
2043 | } | 2311 | } |
2044 | } | 2312 | } |
2045 | 2313 | ||
2314 | if (priv->do_fw_download) { | ||
2315 | err = orinoco_download(priv); | ||
2316 | if (err) | ||
2317 | priv->do_fw_download = 0; | ||
2318 | } | ||
2319 | |||
2046 | err = orinoco_reinit_firmware(dev); | 2320 | err = orinoco_reinit_firmware(dev); |
2047 | if (err) { | 2321 | if (err) { |
2048 | printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", | 2322 | printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", |
@@ -2254,6 +2528,7 @@ static int determine_firmware(struct net_device *dev) | |||
2254 | priv->has_ibss = 1; | 2528 | priv->has_ibss = 1; |
2255 | priv->has_wep = 0; | 2529 | priv->has_wep = 0; |
2256 | priv->has_big_wep = 0; | 2530 | priv->has_big_wep = 0; |
2531 | priv->do_fw_download = 0; | ||
2257 | 2532 | ||
2258 | /* Determine capabilities from the firmware version */ | 2533 | /* Determine capabilities from the firmware version */ |
2259 | switch (priv->firmware_type) { | 2534 | switch (priv->firmware_type) { |
@@ -2273,6 +2548,7 @@ static int determine_firmware(struct net_device *dev) | |||
2273 | priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ | 2548 | priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */ |
2274 | priv->ibss_port = 1; | 2549 | priv->ibss_port = 1; |
2275 | priv->has_hostscan = (firmver >= 0x8000a); | 2550 | priv->has_hostscan = (firmver >= 0x8000a); |
2551 | priv->do_fw_download = 1; | ||
2276 | priv->broken_monitor = (firmver >= 0x80000); | 2552 | priv->broken_monitor = (firmver >= 0x80000); |
2277 | 2553 | ||
2278 | /* Tested with Agere firmware : | 2554 | /* Tested with Agere firmware : |
@@ -2317,6 +2593,21 @@ static int determine_firmware(struct net_device *dev) | |||
2317 | firmver >= 0x31000; | 2593 | firmver >= 0x31000; |
2318 | priv->has_preamble = (firmver >= 0x20000); | 2594 | priv->has_preamble = (firmver >= 0x20000); |
2319 | priv->ibss_port = 4; | 2595 | priv->ibss_port = 4; |
2596 | |||
2597 | /* Symbol firmware is found on various cards, but | ||
2598 | * there has been no attempt to check firmware | ||
2599 | * download on non-spectrum_cs based cards. | ||
2600 | * | ||
2601 | * Given that the Agere firmware download works | ||
2602 | * differently, we should avoid doing a firmware | ||
2603 | * download with the Symbol algorithm on non-spectrum | ||
2604 | * cards. | ||
2605 | * | ||
2606 | * For now we can identify a spectrum_cs based card | ||
2607 | * because it has a firmware reset function. | ||
2608 | */ | ||
2609 | priv->do_fw_download = (priv->stop_fw != NULL); | ||
2610 | |||
2320 | priv->broken_disableport = (firmver == 0x25013) || | 2611 | priv->broken_disableport = (firmver == 0x25013) || |
2321 | (firmver >= 0x30000 && firmver <= 0x31000); | 2612 | (firmver >= 0x30000 && firmver <= 0x31000); |
2322 | priv->has_hostscan = (firmver >= 0x31001) || | 2613 | priv->has_hostscan = (firmver >= 0x31001) || |
@@ -2387,6 +2678,20 @@ static int orinoco_init(struct net_device *dev) | |||
2387 | goto out; | 2678 | goto out; |
2388 | } | 2679 | } |
2389 | 2680 | ||
2681 | if (priv->do_fw_download) { | ||
2682 | err = orinoco_download(priv); | ||
2683 | if (err) | ||
2684 | priv->do_fw_download = 0; | ||
2685 | |||
2686 | /* Check firmware version again */ | ||
2687 | err = determine_firmware(dev); | ||
2688 | if (err != 0) { | ||
2689 | printk(KERN_ERR "%s: Incompatible firmware, aborting\n", | ||
2690 | dev->name); | ||
2691 | goto out; | ||
2692 | } | ||
2693 | } | ||
2694 | |||
2390 | if (priv->has_port3) | 2695 | if (priv->has_port3) |
2391 | printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); | 2696 | printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n", dev->name); |
2392 | if (priv->has_ibss) | 2697 | if (priv->has_ibss) |
@@ -2529,8 +2834,11 @@ static int orinoco_init(struct net_device *dev) | |||
2529 | return err; | 2834 | return err; |
2530 | } | 2835 | } |
2531 | 2836 | ||
2532 | struct net_device *alloc_orinocodev(int sizeof_card, | 2837 | struct net_device |
2533 | int (*hard_reset)(struct orinoco_private *)) | 2838 | *alloc_orinocodev(int sizeof_card, |
2839 | struct device *device, | ||
2840 | int (*hard_reset)(struct orinoco_private *), | ||
2841 | int (*stop_fw)(struct orinoco_private *, int)) | ||
2534 | { | 2842 | { |
2535 | struct net_device *dev; | 2843 | struct net_device *dev; |
2536 | struct orinoco_private *priv; | 2844 | struct orinoco_private *priv; |
@@ -2545,6 +2853,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, | |||
2545 | + sizeof(struct orinoco_private)); | 2853 | + sizeof(struct orinoco_private)); |
2546 | else | 2854 | else |
2547 | priv->card = NULL; | 2855 | priv->card = NULL; |
2856 | priv->dev = device; | ||
2548 | 2857 | ||
2549 | if (orinoco_bss_data_allocate(priv)) | 2858 | if (orinoco_bss_data_allocate(priv)) |
2550 | goto err_out_free; | 2859 | goto err_out_free; |
@@ -2570,6 +2879,7 @@ struct net_device *alloc_orinocodev(int sizeof_card, | |||
2570 | dev->open = orinoco_open; | 2879 | dev->open = orinoco_open; |
2571 | dev->stop = orinoco_stop; | 2880 | dev->stop = orinoco_stop; |
2572 | priv->hard_reset = hard_reset; | 2881 | priv->hard_reset = hard_reset; |
2882 | priv->stop_fw = stop_fw; | ||
2573 | 2883 | ||
2574 | spin_lock_init(&priv->lock); | 2884 | spin_lock_init(&priv->lock); |
2575 | priv->open = 0; | 2885 | priv->open = 0; |
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index c6b1858abde8..e0acb633e9d5 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h | |||
@@ -44,7 +44,9 @@ typedef struct { | |||
44 | 44 | ||
45 | struct orinoco_private { | 45 | struct orinoco_private { |
46 | void *card; /* Pointer to card dependent structure */ | 46 | void *card; /* Pointer to card dependent structure */ |
47 | struct device *dev; | ||
47 | int (*hard_reset)(struct orinoco_private *); | 48 | int (*hard_reset)(struct orinoco_private *); |
49 | int (*stop_fw)(struct orinoco_private *, int); | ||
48 | 50 | ||
49 | /* Synchronisation stuff */ | 51 | /* Synchronisation stuff */ |
50 | spinlock_t lock; | 52 | spinlock_t lock; |
@@ -83,6 +85,7 @@ struct orinoco_private { | |||
83 | unsigned int has_preamble:1; | 85 | unsigned int has_preamble:1; |
84 | unsigned int has_sensitivity:1; | 86 | unsigned int has_sensitivity:1; |
85 | unsigned int has_hostscan:1; | 87 | unsigned int has_hostscan:1; |
88 | unsigned int do_fw_download:1; | ||
86 | unsigned int broken_disableport:1; | 89 | unsigned int broken_disableport:1; |
87 | unsigned int broken_monitor:1; | 90 | unsigned int broken_monitor:1; |
88 | 91 | ||
@@ -130,8 +133,10 @@ extern int orinoco_debug; | |||
130 | /* Exported prototypes */ | 133 | /* Exported prototypes */ |
131 | /********************************************************************/ | 134 | /********************************************************************/ |
132 | 135 | ||
133 | extern struct net_device *alloc_orinocodev(int sizeof_card, | 136 | extern struct net_device *alloc_orinocodev( |
134 | int (*hard_reset)(struct orinoco_private *)); | 137 | int sizeof_card, struct device *device, |
138 | int (*hard_reset)(struct orinoco_private *), | ||
139 | int (*stop_fw)(struct orinoco_private *, int)); | ||
135 | extern void free_orinocodev(struct net_device *dev); | 140 | extern void free_orinocodev(struct net_device *dev); |
136 | extern int __orinoco_up(struct net_device *dev); | 141 | extern int __orinoco_up(struct net_device *dev); |
137 | extern int __orinoco_down(struct net_device *dev); | 142 | extern int __orinoco_down(struct net_device *dev); |
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1c216e015f64..1ccf5a40cf06 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c | |||
@@ -109,7 +109,8 @@ orinoco_cs_probe(struct pcmcia_device *link) | |||
109 | struct orinoco_private *priv; | 109 | struct orinoco_private *priv; |
110 | struct orinoco_pccard *card; | 110 | struct orinoco_pccard *card; |
111 | 111 | ||
112 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); | 112 | dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), |
113 | orinoco_cs_hard_reset, NULL); | ||
113 | if (! dev) | 114 | if (! dev) |
114 | return -ENOMEM; | 115 | return -ENOMEM; |
115 | priv = netdev_priv(dev); | 116 | priv = netdev_priv(dev); |
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c index 35ec5fcf81a6..2fc86596302e 100644 --- a/drivers/net/wireless/orinoco_nortel.c +++ b/drivers/net/wireless/orinoco_nortel.c | |||
@@ -182,7 +182,8 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev, | |||
182 | } | 182 | } |
183 | 183 | ||
184 | /* Allocate network device */ | 184 | /* Allocate network device */ |
185 | dev = alloc_orinocodev(sizeof(*card), orinoco_nortel_cor_reset); | 185 | dev = alloc_orinocodev(sizeof(*card), &pdev->dev, |
186 | orinoco_nortel_cor_reset, NULL); | ||
186 | if (!dev) { | 187 | if (!dev) { |
187 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | 188 | printk(KERN_ERR PFX "Cannot allocate network device\n"); |
188 | err = -ENOMEM; | 189 | err = -ENOMEM; |
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c index 2547d5dac0d3..4ebd638a073e 100644 --- a/drivers/net/wireless/orinoco_pci.c +++ b/drivers/net/wireless/orinoco_pci.c | |||
@@ -139,7 +139,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, | |||
139 | } | 139 | } |
140 | 140 | ||
141 | /* Allocate network device */ | 141 | /* Allocate network device */ |
142 | dev = alloc_orinocodev(sizeof(*card), orinoco_pci_cor_reset); | 142 | dev = alloc_orinocodev(sizeof(*card), &pdev->dev, |
143 | orinoco_pci_cor_reset, NULL); | ||
143 | if (!dev) { | 144 | if (!dev) { |
144 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | 145 | printk(KERN_ERR PFX "Cannot allocate network device\n"); |
145 | err = -ENOMEM; | 146 | err = -ENOMEM; |
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c index 98fe165337d1..ef761857bb38 100644 --- a/drivers/net/wireless/orinoco_plx.c +++ b/drivers/net/wireless/orinoco_plx.c | |||
@@ -221,7 +221,8 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, | |||
221 | } | 221 | } |
222 | 222 | ||
223 | /* Allocate network device */ | 223 | /* Allocate network device */ |
224 | dev = alloc_orinocodev(sizeof(*card), orinoco_plx_cor_reset); | 224 | dev = alloc_orinocodev(sizeof(*card), &pdev->dev, |
225 | orinoco_plx_cor_reset, NULL); | ||
225 | if (!dev) { | 226 | if (!dev) { |
226 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | 227 | printk(KERN_ERR PFX "Cannot allocate network device\n"); |
227 | err = -ENOMEM; | 228 | err = -ENOMEM; |
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c index df493185a4af..ede24ec309c0 100644 --- a/drivers/net/wireless/orinoco_tmd.c +++ b/drivers/net/wireless/orinoco_tmd.c | |||
@@ -124,7 +124,8 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev, | |||
124 | } | 124 | } |
125 | 125 | ||
126 | /* Allocate network device */ | 126 | /* Allocate network device */ |
127 | dev = alloc_orinocodev(sizeof(*card), orinoco_tmd_cor_reset); | 127 | dev = alloc_orinocodev(sizeof(*card), &pdev->dev, |
128 | orinoco_tmd_cor_reset, NULL); | ||
128 | if (!dev) { | 129 | if (!dev) { |
129 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | 130 | printk(KERN_ERR PFX "Cannot allocate network device\n"); |
130 | err = -ENOMEM; | 131 | err = -ENOMEM; |
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 2fb00183cd71..e368759d1d89 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/firmware.h> | ||
29 | #include <pcmcia/cs_types.h> | 28 | #include <pcmcia/cs_types.h> |
30 | #include <pcmcia/cs.h> | 29 | #include <pcmcia/cs.h> |
31 | #include <pcmcia/cistpl.h> | 30 | #include <pcmcia/cistpl.h> |
@@ -33,10 +32,6 @@ | |||
33 | #include <pcmcia/ds.h> | 32 | #include <pcmcia/ds.h> |
34 | 33 | ||
35 | #include "orinoco.h" | 34 | #include "orinoco.h" |
36 | #include "hermes_dld.h" | ||
37 | |||
38 | static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; | ||
39 | static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; | ||
40 | 35 | ||
41 | /********************************************************************/ | 36 | /********************************************************************/ |
42 | /* Module stuff */ | 37 | /* Module stuff */ |
@@ -72,26 +67,11 @@ struct orinoco_pccard { | |||
72 | static int spectrum_cs_config(struct pcmcia_device *link); | 67 | static int spectrum_cs_config(struct pcmcia_device *link); |
73 | static void spectrum_cs_release(struct pcmcia_device *link); | 68 | static void spectrum_cs_release(struct pcmcia_device *link); |
74 | 69 | ||
75 | /********************************************************************/ | ||
76 | /* Firmware downloader */ | ||
77 | /********************************************************************/ | ||
78 | |||
79 | /* Position of PDA in the adapter memory */ | ||
80 | #define EEPROM_ADDR 0x3000 | ||
81 | #define EEPROM_LEN 0x200 | ||
82 | #define PDA_OFFSET 0x100 | ||
83 | |||
84 | #define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) | ||
85 | #define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) | ||
86 | |||
87 | /* Constants for the CISREG_CCSR register */ | 70 | /* Constants for the CISREG_CCSR register */ |
88 | #define HCR_RUN 0x07 /* run firmware after reset */ | 71 | #define HCR_RUN 0x07 /* run firmware after reset */ |
89 | #define HCR_IDLE 0x0E /* don't run firmware after reset */ | 72 | #define HCR_IDLE 0x0E /* don't run firmware after reset */ |
90 | #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ | 73 | #define HCR_MEM16 0x10 /* memory width bit, should be preserved */ |
91 | 74 | ||
92 | /* End markers */ | ||
93 | #define TEXT_END 0x1A /* End of text header */ | ||
94 | |||
95 | 75 | ||
96 | #define CS_CHECK(fn, ret) \ | 76 | #define CS_CHECK(fn, ret) \ |
97 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) | 77 | do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) |
@@ -158,142 +138,29 @@ spectrum_reset(struct pcmcia_device *link, int idle) | |||
158 | return -ENODEV; | 138 | return -ENODEV; |
159 | } | 139 | } |
160 | 140 | ||
141 | /********************************************************************/ | ||
142 | /* Device methods */ | ||
143 | /********************************************************************/ | ||
161 | 144 | ||
162 | /* | ||
163 | * Process a firmware image - stop the card, load the firmware, reset | ||
164 | * the card and make sure it responds. For the secondary firmware take | ||
165 | * care of the PDA - read it and then write it on top of the firmware. | ||
166 | */ | ||
167 | static int | 145 | static int |
168 | spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, | 146 | spectrum_cs_hard_reset(struct orinoco_private *priv) |
169 | const unsigned char *image, const unsigned char *end, | ||
170 | int secondary) | ||
171 | { | 147 | { |
172 | int ret; | 148 | struct orinoco_pccard *card = priv->card; |
173 | const unsigned char *ptr; | 149 | struct pcmcia_device *link = card->p_dev; |
174 | const unsigned char *first_block; | ||
175 | |||
176 | /* Plug Data Area (PDA) */ | ||
177 | __le16 pda[PDA_WORDS]; | ||
178 | |||
179 | /* Binary block begins after the 0x1A marker */ | ||
180 | ptr = image; | ||
181 | while (*ptr++ != TEXT_END); | ||
182 | first_block = ptr; | ||
183 | |||
184 | /* Read the PDA from EEPROM */ | ||
185 | if (secondary) { | ||
186 | ret = hermes_read_pda(hw, pda, PDA_ADDR, sizeof(pda), 1); | ||
187 | if (ret) | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | /* Stop the firmware, so that it can be safely rewritten */ | ||
192 | ret = spectrum_reset(link, 1); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | /* Program the adapter with new firmware */ | ||
197 | ret = hermes_program(hw, first_block, end); | ||
198 | if (ret) | ||
199 | return ret; | ||
200 | |||
201 | /* Write the PDA to the adapter */ | ||
202 | if (secondary) { | ||
203 | size_t len = hermes_blocks_length(first_block); | ||
204 | ptr = first_block + len; | ||
205 | ret = hermes_apply_pda(hw, ptr, pda); | ||
206 | if (ret) | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* Run the firmware */ | ||
211 | ret = spectrum_reset(link, 0); | ||
212 | if (ret) | ||
213 | return ret; | ||
214 | |||
215 | /* Reset hermes chip and make sure it responds */ | ||
216 | ret = hermes_init(hw); | ||
217 | |||
218 | /* hermes_reset() should return 0 with the secondary firmware */ | ||
219 | if (secondary && ret != 0) | ||
220 | return -ENODEV; | ||
221 | 150 | ||
222 | /* And this should work with any firmware */ | 151 | /* Soft reset using COR and HCR */ |
223 | if (!hermes_present(hw)) | 152 | spectrum_reset(link, 0); |
224 | return -ENODEV; | ||
225 | 153 | ||
226 | return 0; | 154 | return 0; |
227 | } | 155 | } |
228 | 156 | ||
229 | |||
230 | /* | ||
231 | * Download the firmware into the card, this also does a PCMCIA soft | ||
232 | * reset on the card, to make sure it's in a sane state. | ||
233 | */ | ||
234 | static int | 157 | static int |
235 | spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) | 158 | spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle) |
236 | { | ||
237 | int ret; | ||
238 | const struct firmware *fw_entry; | ||
239 | |||
240 | if (request_firmware(&fw_entry, primary_fw_name, | ||
241 | &handle_to_dev(link)) != 0) { | ||
242 | printk(KERN_ERR PFX "Cannot find firmware: %s\n", | ||
243 | primary_fw_name); | ||
244 | return -ENOENT; | ||
245 | } | ||
246 | |||
247 | /* Load primary firmware */ | ||
248 | ret = spectrum_dl_image(hw, link, fw_entry->data, | ||
249 | fw_entry->data + fw_entry->size, 0); | ||
250 | release_firmware(fw_entry); | ||
251 | if (ret) { | ||
252 | printk(KERN_ERR PFX "Primary firmware download failed\n"); | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | if (request_firmware(&fw_entry, secondary_fw_name, | ||
257 | &handle_to_dev(link)) != 0) { | ||
258 | printk(KERN_ERR PFX "Cannot find firmware: %s\n", | ||
259 | secondary_fw_name); | ||
260 | return -ENOENT; | ||
261 | } | ||
262 | |||
263 | /* Load secondary firmware */ | ||
264 | ret = spectrum_dl_image(hw, link, fw_entry->data, | ||
265 | fw_entry->data + fw_entry->size, 1); | ||
266 | release_firmware(fw_entry); | ||
267 | if (ret) { | ||
268 | printk(KERN_ERR PFX "Secondary firmware download failed\n"); | ||
269 | } | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | /********************************************************************/ | ||
275 | /* Device methods */ | ||
276 | /********************************************************************/ | ||
277 | |||
278 | static int | ||
279 | spectrum_cs_hard_reset(struct orinoco_private *priv) | ||
280 | { | 159 | { |
281 | struct orinoco_pccard *card = priv->card; | 160 | struct orinoco_pccard *card = priv->card; |
282 | struct pcmcia_device *link = card->p_dev; | 161 | struct pcmcia_device *link = card->p_dev; |
283 | int err; | ||
284 | 162 | ||
285 | if (!hermes_present(&priv->hw)) { | 163 | return spectrum_reset(link, idle); |
286 | /* The firmware needs to be reloaded */ | ||
287 | if (spectrum_dl_firmware(&priv->hw, link) != 0) { | ||
288 | printk(KERN_ERR PFX "Firmware download failed\n"); | ||
289 | err = -ENODEV; | ||
290 | } | ||
291 | } else { | ||
292 | /* Soft reset using COR and HCR */ | ||
293 | spectrum_reset(link, 0); | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | 164 | } |
298 | 165 | ||
299 | /********************************************************************/ | 166 | /********************************************************************/ |
@@ -315,7 +182,9 @@ spectrum_cs_probe(struct pcmcia_device *link) | |||
315 | struct orinoco_private *priv; | 182 | struct orinoco_private *priv; |
316 | struct orinoco_pccard *card; | 183 | struct orinoco_pccard *card; |
317 | 184 | ||
318 | dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); | 185 | dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link), |
186 | spectrum_cs_hard_reset, | ||
187 | spectrum_cs_stop_firmware); | ||
319 | if (! dev) | 188 | if (! dev) |
320 | return -ENOMEM; | 189 | return -ENOMEM; |
321 | priv = netdev_priv(dev); | 190 | priv = netdev_priv(dev); |
@@ -517,7 +386,7 @@ spectrum_cs_config(struct pcmcia_device *link) | |||
517 | dev->irq = link->irq.AssignedIRQ; | 386 | dev->irq = link->irq.AssignedIRQ; |
518 | card->node.major = card->node.minor = 0; | 387 | card->node.major = card->node.minor = 0; |
519 | 388 | ||
520 | /* Reset card and download firmware */ | 389 | /* Reset card */ |
521 | if (spectrum_cs_hard_reset(priv) != 0) { | 390 | if (spectrum_cs_hard_reset(priv) != 0) { |
522 | goto failed; | 391 | goto failed; |
523 | } | 392 | } |