diff options
author | David Kilroy <kilroyd@googlemail.com> | 2010-05-01 09:05:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-05-03 14:53:09 -0400 |
commit | 07cefe7ac983374ee4c369f1d4aee3093bf3b44f (patch) | |
tree | c4db80ac5a3f28bda1a5c93fb9b88b7db728898e /drivers | |
parent | fc97431a50962e66c052ec6909d4b2582efd3554 (diff) |
orinoco_usb: implement fw download
This involves some refactorring of the common fw download code to
substitute ezusb versions of various functions.
Note that WPA-enabled firmwares (9.xx series) will not work fully with
orinoco_usb yet.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/orinoco/fw.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes.c | 208 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/hermes_dld.c | 243 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/orinoco_usb.c | 120 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/spectrum_cs.c | 1 |
6 files changed, 349 insertions, 238 deletions
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 07c79e5de32d..94c0853f6814 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c | |||
@@ -121,7 +121,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
121 | dev_dbg(dev, "Attempting to download firmware %s\n", firmware); | 121 | dev_dbg(dev, "Attempting to download firmware %s\n", firmware); |
122 | 122 | ||
123 | /* Read current plug data */ | 123 | /* Read current plug data */ |
124 | err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); | 124 | err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); |
125 | dev_dbg(dev, "Read PDA returned %d\n", err); | 125 | dev_dbg(dev, "Read PDA returned %d\n", err); |
126 | if (err) | 126 | if (err) |
127 | goto free; | 127 | goto free; |
@@ -148,7 +148,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
148 | } | 148 | } |
149 | 149 | ||
150 | /* Enable aux port to allow programming */ | 150 | /* Enable aux port to allow programming */ |
151 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); | 151 | err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); |
152 | dev_dbg(dev, "Program init returned %d\n", err); | 152 | dev_dbg(dev, "Program init returned %d\n", err); |
153 | if (err != 0) | 153 | if (err != 0) |
154 | goto abort; | 154 | goto abort; |
@@ -176,7 +176,7 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
176 | goto abort; | 176 | goto abort; |
177 | 177 | ||
178 | /* Tell card we've finished */ | 178 | /* Tell card we've finished */ |
179 | err = hermesi_program_end(hw); | 179 | err = hw->ops->program_end(hw); |
180 | dev_dbg(dev, "Program end returned %d\n", err); | 180 | dev_dbg(dev, "Program end returned %d\n", err); |
181 | if (err != 0) | 181 | if (err != 0) |
182 | goto abort; | 182 | goto abort; |
@@ -223,7 +223,7 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
223 | if (!pda) | 223 | if (!pda) |
224 | return -ENOMEM; | 224 | return -ENOMEM; |
225 | 225 | ||
226 | ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); | 226 | ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); |
227 | if (ret) | 227 | if (ret) |
228 | goto free; | 228 | goto free; |
229 | } | 229 | } |
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c index 845693fb25f3..6c6a23e08df6 100644 --- a/drivers/net/wireless/orinoco/hermes.c +++ b/drivers/net/wireless/orinoco/hermes.c | |||
@@ -52,6 +52,26 @@ | |||
52 | #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ | 52 | #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */ |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * AUX port access. To unlock the AUX port write the access keys to the | ||
56 | * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL | ||
57 | * register. Then read it and make sure it's HERMES_AUX_ENABLED. | ||
58 | */ | ||
59 | #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ | ||
60 | #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ | ||
61 | #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ | ||
62 | #define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ | ||
63 | |||
64 | #define HERMES_AUX_PW0 0xFE01 | ||
65 | #define HERMES_AUX_PW1 0xDC23 | ||
66 | #define HERMES_AUX_PW2 0xBA45 | ||
67 | |||
68 | /* HERMES_CMD_DOWNLD */ | ||
69 | #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) | ||
70 | #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) | ||
71 | #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) | ||
72 | #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) | ||
73 | |||
74 | /* | ||
55 | * Debugging helpers | 75 | * Debugging helpers |
56 | */ | 76 | */ |
57 | 77 | ||
@@ -170,6 +190,7 @@ void hermes_struct_init(hermes_t *hw, void __iomem *address, int reg_spacing) | |||
170 | hw->iobase = address; | 190 | hw->iobase = address; |
171 | hw->reg_spacing = reg_spacing; | 191 | hw->reg_spacing = reg_spacing; |
172 | hw->inten = 0x0; | 192 | hw->inten = 0x0; |
193 | hw->eeprom_pda = false; | ||
173 | hw->ops = &hermes_ops_local; | 194 | hw->ops = &hermes_ops_local; |
174 | } | 195 | } |
175 | EXPORT_SYMBOL(hermes_struct_init); | 196 | EXPORT_SYMBOL(hermes_struct_init); |
@@ -529,6 +550,189 @@ static int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, | |||
529 | return err; | 550 | return err; |
530 | } | 551 | } |
531 | 552 | ||
553 | /*** Hermes AUX control ***/ | ||
554 | |||
555 | static inline void | ||
556 | hermes_aux_setaddr(hermes_t *hw, u32 addr) | ||
557 | { | ||
558 | hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); | ||
559 | hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); | ||
560 | } | ||
561 | |||
562 | static inline int | ||
563 | hermes_aux_control(hermes_t *hw, int enabled) | ||
564 | { | ||
565 | int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; | ||
566 | int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; | ||
567 | int i; | ||
568 | |||
569 | /* Already open? */ | ||
570 | if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) | ||
571 | return 0; | ||
572 | |||
573 | hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); | ||
574 | hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); | ||
575 | hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); | ||
576 | hermes_write_reg(hw, HERMES_CONTROL, action); | ||
577 | |||
578 | for (i = 0; i < 20; i++) { | ||
579 | udelay(10); | ||
580 | if (hermes_read_reg(hw, HERMES_CONTROL) == | ||
581 | desired_state) | ||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | return -EBUSY; | ||
586 | } | ||
587 | |||
588 | /*** Hermes programming ***/ | ||
589 | |||
590 | /* About to start programming data (Hermes I) | ||
591 | * offset is the entry point | ||
592 | * | ||
593 | * Spectrum_cs' Symbol fw does not require this | ||
594 | * wl_lkm Agere fw does | ||
595 | * Don't know about intersil | ||
596 | */ | ||
597 | static int hermesi_program_init(hermes_t *hw, u32 offset) | ||
598 | { | ||
599 | int err; | ||
600 | |||
601 | /* Disable interrupts?*/ | ||
602 | /*hw->inten = 0x0;*/ | ||
603 | /*hermes_write_regn(hw, INTEN, 0);*/ | ||
604 | /*hermes_set_irqmask(hw, 0);*/ | ||
605 | |||
606 | /* Acknowledge any outstanding command */ | ||
607 | hermes_write_regn(hw, EVACK, 0xFFFF); | ||
608 | |||
609 | /* Using init_cmd_wait rather than cmd_wait */ | ||
610 | err = hw->ops->init_cmd_wait(hw, | ||
611 | 0x0100 | HERMES_CMD_INIT, | ||
612 | 0, 0, 0, NULL); | ||
613 | if (err) | ||
614 | return err; | ||
615 | |||
616 | err = hw->ops->init_cmd_wait(hw, | ||
617 | 0x0000 | HERMES_CMD_INIT, | ||
618 | 0, 0, 0, NULL); | ||
619 | if (err) | ||
620 | return err; | ||
621 | |||
622 | err = hermes_aux_control(hw, 1); | ||
623 | pr_debug("AUX enable returned %d\n", err); | ||
624 | |||
625 | if (err) | ||
626 | return err; | ||
627 | |||
628 | pr_debug("Enabling volatile, EP 0x%08x\n", offset); | ||
629 | err = hw->ops->init_cmd_wait(hw, | ||
630 | HERMES_PROGRAM_ENABLE_VOLATILE, | ||
631 | offset & 0xFFFFu, | ||
632 | offset >> 16, | ||
633 | 0, | ||
634 | NULL); | ||
635 | pr_debug("PROGRAM_ENABLE returned %d\n", err); | ||
636 | |||
637 | return err; | ||
638 | } | ||
639 | |||
640 | /* Done programming data (Hermes I) | ||
641 | * | ||
642 | * Spectrum_cs' Symbol fw does not require this | ||
643 | * wl_lkm Agere fw does | ||
644 | * Don't know about intersil | ||
645 | */ | ||
646 | static int hermesi_program_end(hermes_t *hw) | ||
647 | { | ||
648 | struct hermes_response resp; | ||
649 | int rc = 0; | ||
650 | int err; | ||
651 | |||
652 | rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); | ||
653 | |||
654 | pr_debug("PROGRAM_DISABLE returned %d, " | ||
655 | "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", | ||
656 | rc, resp.resp0, resp.resp1, resp.resp2); | ||
657 | |||
658 | if ((rc == 0) && | ||
659 | ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) | ||
660 | rc = -EIO; | ||
661 | |||
662 | err = hermes_aux_control(hw, 0); | ||
663 | pr_debug("AUX disable returned %d\n", err); | ||
664 | |||
665 | /* Acknowledge any outstanding command */ | ||
666 | hermes_write_regn(hw, EVACK, 0xFFFF); | ||
667 | |||
668 | /* Reinitialise, ignoring return */ | ||
669 | (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT, | ||
670 | 0, 0, 0, NULL); | ||
671 | |||
672 | return rc ? rc : err; | ||
673 | } | ||
674 | |||
675 | static int hermes_program_bytes(struct hermes *hw, const char *data, | ||
676 | u32 addr, u32 len) | ||
677 | { | ||
678 | /* wl lkm splits the programming into chunks of 2000 bytes. | ||
679 | * This restriction appears to come from USB. The PCMCIA | ||
680 | * adapters can program the whole lot in one go */ | ||
681 | hermes_aux_setaddr(hw, addr); | ||
682 | hermes_write_bytes(hw, HERMES_AUXDATA, data, len); | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | /* Read PDA from the adapter */ | ||
687 | static int hermes_read_pda(hermes_t *hw, __le16 *pda, u32 pda_addr, u16 pda_len) | ||
688 | { | ||
689 | int ret; | ||
690 | u16 pda_size; | ||
691 | u16 data_len = pda_len; | ||
692 | __le16 *data = pda; | ||
693 | |||
694 | if (hw->eeprom_pda) { | ||
695 | /* PDA of spectrum symbol is in eeprom */ | ||
696 | |||
697 | /* Issue command to read EEPROM */ | ||
698 | ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); | ||
699 | if (ret) | ||
700 | return ret; | ||
701 | } else { | ||
702 | /* wl_lkm does not include PDA size in the PDA area. | ||
703 | * We will pad the information into pda, so other routines | ||
704 | * don't have to be modified */ | ||
705 | pda[0] = cpu_to_le16(pda_len - 2); | ||
706 | /* Includes CFG_PROD_DATA but not itself */ | ||
707 | pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ | ||
708 | data_len = pda_len - 4; | ||
709 | data = pda + 2; | ||
710 | } | ||
711 | |||
712 | /* Open auxiliary port */ | ||
713 | ret = hermes_aux_control(hw, 1); | ||
714 | pr_debug("AUX enable returned %d\n", ret); | ||
715 | if (ret) | ||
716 | return ret; | ||
717 | |||
718 | /* Read PDA */ | ||
719 | hermes_aux_setaddr(hw, pda_addr); | ||
720 | hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); | ||
721 | |||
722 | /* Close aux port */ | ||
723 | ret = hermes_aux_control(hw, 0); | ||
724 | pr_debug("AUX disable returned %d\n", ret); | ||
725 | |||
726 | /* Check PDA length */ | ||
727 | pda_size = le16_to_cpu(pda[0]); | ||
728 | pr_debug("Actual PDA length %d, Max allowed %d\n", | ||
729 | pda_size, pda_len); | ||
730 | if (pda_size > pda_len) | ||
731 | return -EINVAL; | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
532 | static void hermes_lock_irqsave(spinlock_t *lock, | 736 | static void hermes_lock_irqsave(spinlock_t *lock, |
533 | unsigned long *flags) __acquires(lock) | 737 | unsigned long *flags) __acquires(lock) |
534 | { | 738 | { |
@@ -561,6 +765,10 @@ static const struct hermes_ops hermes_ops_local = { | |||
561 | .write_ltv = hermes_write_ltv, | 765 | .write_ltv = hermes_write_ltv, |
562 | .bap_pread = hermes_bap_pread, | 766 | .bap_pread = hermes_bap_pread, |
563 | .bap_pwrite = hermes_bap_pwrite, | 767 | .bap_pwrite = hermes_bap_pwrite, |
768 | .read_pda = hermes_read_pda, | ||
769 | .program_init = hermesi_program_init, | ||
770 | .program_end = hermesi_program_end, | ||
771 | .program = hermes_program_bytes, | ||
564 | .lock_irqsave = hermes_lock_irqsave, | 772 | .lock_irqsave = hermes_lock_irqsave, |
565 | .unlock_irqrestore = hermes_unlock_irqrestore, | 773 | .unlock_irqrestore = hermes_unlock_irqrestore, |
566 | .lock_irq = hermes_lock_irq, | 774 | .lock_irq = hermes_lock_irq, |
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h index aed14ff2d235..9ca34e722b45 100644 --- a/drivers/net/wireless/orinoco/hermes.h +++ b/drivers/net/wireless/orinoco/hermes.h | |||
@@ -393,6 +393,12 @@ struct hermes_ops { | |||
393 | u16 id, u16 offset); | 393 | u16 id, u16 offset); |
394 | int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf, | 394 | int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf, |
395 | int len, u16 id, u16 offset); | 395 | int len, u16 id, u16 offset); |
396 | int (*read_pda)(struct hermes *hw, __le16 *pda, | ||
397 | u32 pda_addr, u16 pda_len); | ||
398 | int (*program_init)(struct hermes *hw, u32 entry_point); | ||
399 | int (*program_end)(struct hermes *hw); | ||
400 | int (*program)(struct hermes *hw, const char *buf, | ||
401 | u32 addr, u32 len); | ||
396 | void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags); | 402 | void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags); |
397 | void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags); | 403 | void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags); |
398 | void (*lock_irq)(spinlock_t *lock); | 404 | void (*lock_irq)(spinlock_t *lock); |
@@ -406,6 +412,7 @@ typedef struct hermes { | |||
406 | #define HERMES_16BIT_REGSPACING 0 | 412 | #define HERMES_16BIT_REGSPACING 0 |
407 | #define HERMES_32BIT_REGSPACING 1 | 413 | #define HERMES_32BIT_REGSPACING 1 |
408 | u16 inten; /* Which interrupts should be enabled? */ | 414 | u16 inten; /* Which interrupts should be enabled? */ |
415 | bool eeprom_pda; | ||
409 | const struct hermes_ops *ops; | 416 | const struct hermes_ops *ops; |
410 | void *priv; | 417 | void *priv; |
411 | } hermes_t; | 418 | } hermes_t; |
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index 8f22e2026a82..6da85e75fce0 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c | |||
@@ -46,37 +46,11 @@ | |||
46 | 46 | ||
47 | #define PFX "hermes_dld: " | 47 | #define PFX "hermes_dld: " |
48 | 48 | ||
49 | /* | ||
50 | * AUX port access. To unlock the AUX port write the access keys to the | ||
51 | * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL | ||
52 | * register. Then read it and make sure it's HERMES_AUX_ENABLED. | ||
53 | */ | ||
54 | #define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ | ||
55 | #define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ | ||
56 | #define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ | ||
57 | #define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */ | ||
58 | |||
59 | #define HERMES_AUX_PW0 0xFE01 | ||
60 | #define HERMES_AUX_PW1 0xDC23 | ||
61 | #define HERMES_AUX_PW2 0xBA45 | ||
62 | |||
63 | /* HERMES_CMD_DOWNLD */ | ||
64 | #define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD) | ||
65 | #define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD) | ||
66 | #define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD) | ||
67 | #define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD) | ||
68 | |||
69 | /* End markers used in dblocks */ | 49 | /* End markers used in dblocks */ |
70 | #define PDI_END 0x00000000 /* End of PDA */ | 50 | #define PDI_END 0x00000000 /* End of PDA */ |
71 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ | 51 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ |
72 | #define TEXT_END 0x1A /* End of text header */ | 52 | #define TEXT_END 0x1A /* End of text header */ |
73 | 53 | ||
74 | /* Limit the amout we try to download in a single shot. | ||
75 | * Size is in bytes. | ||
76 | */ | ||
77 | #define MAX_DL_SIZE 1024 | ||
78 | #define LIMIT_PROGRAM_SIZE 0 | ||
79 | |||
80 | /* | 54 | /* |
81 | * The following structures have little-endian fields denoted by | 55 | * The following structures have little-endian fields denoted by |
82 | * the leading underscore. Don't access them directly - use inline | 56 | * the leading underscore. Don't access them directly - use inline |
@@ -165,41 +139,6 @@ pdi_len(const struct pdi *pdi) | |||
165 | return 2 * (le16_to_cpu(pdi->len) - 1); | 139 | return 2 * (le16_to_cpu(pdi->len) - 1); |
166 | } | 140 | } |
167 | 141 | ||
168 | /*** Hermes AUX control ***/ | ||
169 | |||
170 | static inline void | ||
171 | hermes_aux_setaddr(hermes_t *hw, u32 addr) | ||
172 | { | ||
173 | hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7)); | ||
174 | hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F)); | ||
175 | } | ||
176 | |||
177 | static inline int | ||
178 | hermes_aux_control(hermes_t *hw, int enabled) | ||
179 | { | ||
180 | int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED; | ||
181 | int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE; | ||
182 | int i; | ||
183 | |||
184 | /* Already open? */ | ||
185 | if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state) | ||
186 | return 0; | ||
187 | |||
188 | hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0); | ||
189 | hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1); | ||
190 | hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2); | ||
191 | hermes_write_reg(hw, HERMES_CONTROL, action); | ||
192 | |||
193 | for (i = 0; i < 20; i++) { | ||
194 | udelay(10); | ||
195 | if (hermes_read_reg(hw, HERMES_CONTROL) == | ||
196 | desired_state) | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | return -EBUSY; | ||
201 | } | ||
202 | |||
203 | /*** Plug Data Functions ***/ | 142 | /*** Plug Data Functions ***/ |
204 | 143 | ||
205 | /* | 144 | /* |
@@ -271,62 +210,7 @@ hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr, | |||
271 | return -EINVAL; | 210 | return -EINVAL; |
272 | 211 | ||
273 | /* do the actual plugging */ | 212 | /* do the actual plugging */ |
274 | hermes_aux_setaddr(hw, pdr_addr(pdr)); | 213 | hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi)); |
275 | hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi)); | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | /* Read PDA from the adapter */ | ||
281 | int hermes_read_pda(hermes_t *hw, | ||
282 | __le16 *pda, | ||
283 | u32 pda_addr, | ||
284 | u16 pda_len, | ||
285 | int use_eeprom) /* can we get this into hw? */ | ||
286 | { | ||
287 | int ret; | ||
288 | u16 pda_size; | ||
289 | u16 data_len = pda_len; | ||
290 | __le16 *data = pda; | ||
291 | |||
292 | if (use_eeprom) { | ||
293 | /* PDA of spectrum symbol is in eeprom */ | ||
294 | |||
295 | /* Issue command to read EEPROM */ | ||
296 | ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL); | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | } else { | ||
300 | /* wl_lkm does not include PDA size in the PDA area. | ||
301 | * We will pad the information into pda, so other routines | ||
302 | * don't have to be modified */ | ||
303 | pda[0] = cpu_to_le16(pda_len - 2); | ||
304 | /* Includes CFG_PROD_DATA but not itself */ | ||
305 | pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ | ||
306 | data_len = pda_len - 4; | ||
307 | data = pda + 2; | ||
308 | } | ||
309 | |||
310 | /* Open auxiliary port */ | ||
311 | ret = hermes_aux_control(hw, 1); | ||
312 | pr_debug(PFX "AUX enable returned %d\n", ret); | ||
313 | if (ret) | ||
314 | return ret; | ||
315 | |||
316 | /* read PDA from EEPROM */ | ||
317 | hermes_aux_setaddr(hw, pda_addr); | ||
318 | hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2); | ||
319 | |||
320 | /* Close aux port */ | ||
321 | ret = hermes_aux_control(hw, 0); | ||
322 | pr_debug(PFX "AUX disable returned %d\n", ret); | ||
323 | |||
324 | /* Check PDA length */ | ||
325 | pda_size = le16_to_cpu(pda[0]); | ||
326 | pr_debug(PFX "Actual PDA length %d, Max allowed %d\n", | ||
327 | pda_size, pda_len); | ||
328 | if (pda_size > pda_len) | ||
329 | return -EINVAL; | ||
330 | 214 | ||
331 | return 0; | 215 | return 0; |
332 | } | 216 | } |
@@ -389,101 +273,13 @@ hermes_blocks_length(const char *first_block, const void *end) | |||
389 | 273 | ||
390 | /*** Hermes programming ***/ | 274 | /*** Hermes programming ***/ |
391 | 275 | ||
392 | /* About to start programming data (Hermes I) | ||
393 | * offset is the entry point | ||
394 | * | ||
395 | * Spectrum_cs' Symbol fw does not require this | ||
396 | * wl_lkm Agere fw does | ||
397 | * Don't know about intersil | ||
398 | */ | ||
399 | int hermesi_program_init(hermes_t *hw, u32 offset) | ||
400 | { | ||
401 | int err; | ||
402 | |||
403 | /* Disable interrupts?*/ | ||
404 | /*hw->inten = 0x0;*/ | ||
405 | /*hermes_write_regn(hw, INTEN, 0);*/ | ||
406 | /*hermes_set_irqmask(hw, 0);*/ | ||
407 | |||
408 | /* Acknowledge any outstanding command */ | ||
409 | hermes_write_regn(hw, EVACK, 0xFFFF); | ||
410 | |||
411 | /* Using init_cmd_wait rather than cmd_wait */ | ||
412 | err = hw->ops->init_cmd_wait(hw, | ||
413 | 0x0100 | HERMES_CMD_INIT, | ||
414 | 0, 0, 0, NULL); | ||
415 | if (err) | ||
416 | return err; | ||
417 | |||
418 | err = hw->ops->init_cmd_wait(hw, | ||
419 | 0x0000 | HERMES_CMD_INIT, | ||
420 | 0, 0, 0, NULL); | ||
421 | if (err) | ||
422 | return err; | ||
423 | |||
424 | err = hermes_aux_control(hw, 1); | ||
425 | pr_debug(PFX "AUX enable returned %d\n", err); | ||
426 | |||
427 | if (err) | ||
428 | return err; | ||
429 | |||
430 | pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset); | ||
431 | err = hw->ops->init_cmd_wait(hw, | ||
432 | HERMES_PROGRAM_ENABLE_VOLATILE, | ||
433 | offset & 0xFFFFu, | ||
434 | offset >> 16, | ||
435 | 0, | ||
436 | NULL); | ||
437 | pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err); | ||
438 | |||
439 | return err; | ||
440 | } | ||
441 | |||
442 | /* Done programming data (Hermes I) | ||
443 | * | ||
444 | * Spectrum_cs' Symbol fw does not require this | ||
445 | * wl_lkm Agere fw does | ||
446 | * Don't know about intersil | ||
447 | */ | ||
448 | int hermesi_program_end(hermes_t *hw) | ||
449 | { | ||
450 | struct hermes_response resp; | ||
451 | int rc = 0; | ||
452 | int err; | ||
453 | |||
454 | rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp); | ||
455 | |||
456 | pr_debug(PFX "PROGRAM_DISABLE returned %d, " | ||
457 | "r0 0x%04x, r1 0x%04x, r2 0x%04x\n", | ||
458 | rc, resp.resp0, resp.resp1, resp.resp2); | ||
459 | |||
460 | if ((rc == 0) && | ||
461 | ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD)) | ||
462 | rc = -EIO; | ||
463 | |||
464 | err = hermes_aux_control(hw, 0); | ||
465 | pr_debug(PFX "AUX disable returned %d\n", err); | ||
466 | |||
467 | /* Acknowledge any outstanding command */ | ||
468 | hermes_write_regn(hw, EVACK, 0xFFFF); | ||
469 | |||
470 | /* Reinitialise, ignoring return */ | ||
471 | (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT, | ||
472 | 0, 0, 0, NULL); | ||
473 | |||
474 | return rc ? rc : err; | ||
475 | } | ||
476 | |||
477 | /* Program the data blocks */ | 276 | /* Program the data blocks */ |
478 | int hermes_program(hermes_t *hw, const char *first_block, const void *end) | 277 | int hermes_program(hermes_t *hw, const char *first_block, const void *end) |
479 | { | 278 | { |
480 | const struct dblock *blk; | 279 | const struct dblock *blk; |
481 | u32 blkaddr; | 280 | u32 blkaddr; |
482 | u32 blklen; | 281 | u32 blklen; |
483 | #if LIMIT_PROGRAM_SIZE | 282 | int err = 0; |
484 | u32 addr; | ||
485 | u32 len; | ||
486 | #endif | ||
487 | 283 | ||
488 | blk = (const struct dblock *) first_block; | 284 | blk = (const struct dblock *) first_block; |
489 | 285 | ||
@@ -498,30 +294,10 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) | |||
498 | pr_debug(PFX "Programming block of length %d " | 294 | pr_debug(PFX "Programming block of length %d " |
499 | "to address 0x%08x\n", blklen, blkaddr); | 295 | "to address 0x%08x\n", blklen, blkaddr); |
500 | 296 | ||
501 | #if !LIMIT_PROGRAM_SIZE | 297 | err = hw->ops->program(hw, blk->data, blkaddr, blklen); |
502 | /* wl_lkm driver splits this into writes of 2000 bytes */ | 298 | if (err) |
503 | hermes_aux_setaddr(hw, blkaddr); | 299 | break; |
504 | hermes_write_bytes(hw, HERMES_AUXDATA, blk->data, | 300 | |
505 | blklen); | ||
506 | #else | ||
507 | len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE; | ||
508 | addr = blkaddr; | ||
509 | |||
510 | while (addr < (blkaddr + blklen)) { | ||
511 | pr_debug(PFX "Programming subblock of length %d " | ||
512 | "to address 0x%08x. Data @ %p\n", | ||
513 | len, addr, &blk->data[addr - blkaddr]); | ||
514 | |||
515 | hermes_aux_setaddr(hw, addr); | ||
516 | hermes_write_bytes(hw, HERMES_AUXDATA, | ||
517 | &blk->data[addr - blkaddr], | ||
518 | len); | ||
519 | |||
520 | addr += len; | ||
521 | len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ? | ||
522 | (blkaddr + blklen - addr) : MAX_DL_SIZE; | ||
523 | } | ||
524 | #endif | ||
525 | blk = (const struct dblock *) &blk->data[blklen]; | 301 | blk = (const struct dblock *) &blk->data[blklen]; |
526 | 302 | ||
527 | if ((void *) blk > (end - sizeof(*blk))) | 303 | if ((void *) blk > (end - sizeof(*blk))) |
@@ -530,7 +306,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end) | |||
530 | blkaddr = dblock_addr(blk); | 306 | blkaddr = dblock_addr(blk); |
531 | blklen = dblock_len(blk); | 307 | blklen = dblock_len(blk); |
532 | } | 308 | } |
533 | return 0; | 309 | return err; |
534 | } | 310 | } |
535 | 311 | ||
536 | /*** Default plugging data for Hermes I ***/ | 312 | /*** Default plugging data for Hermes I ***/ |
@@ -690,9 +466,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
690 | if ((pdi_len(pdi) == pdr_len(pdr)) && | 466 | if ((pdi_len(pdi) == pdr_len(pdr)) && |
691 | ((void *) pdi->data + pdi_len(pdi) < pda_end)) { | 467 | ((void *) pdi->data + pdi_len(pdi) < pda_end)) { |
692 | /* do the actual plugging */ | 468 | /* do the actual plugging */ |
693 | hermes_aux_setaddr(hw, pdr_addr(pdr)); | 469 | hw->ops->program(hw, pdi->data, pdr_addr(pdr), |
694 | hermes_write_bytes(hw, HERMES_AUXDATA, | 470 | pdi_len(pdi)); |
695 | pdi->data, pdi_len(pdi)); | ||
696 | } | 471 | } |
697 | } | 472 | } |
698 | 473 | ||
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 8e1b31cbd375..e22093359f3e 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c | |||
@@ -184,6 +184,11 @@ MODULE_FIRMWARE("orinoco_ezusb_fw"); | |||
184 | #define EZUSB_RID_RX 0x0701 | 184 | #define EZUSB_RID_RX 0x0701 |
185 | #define EZUSB_RID_INIT1 0x0702 | 185 | #define EZUSB_RID_INIT1 0x0702 |
186 | #define EZUSB_RID_ACK 0x0710 | 186 | #define EZUSB_RID_ACK 0x0710 |
187 | #define EZUSB_RID_READ_PDA 0x0800 | ||
188 | #define EZUSB_RID_PROG_INIT 0x0852 | ||
189 | #define EZUSB_RID_PROG_SET_ADDR 0x0853 | ||
190 | #define EZUSB_RID_PROG_BYTES 0x0854 | ||
191 | #define EZUSB_RID_PROG_END 0x0855 | ||
187 | #define EZUSB_RID_DOCMD 0x0860 | 192 | #define EZUSB_RID_DOCMD 0x0860 |
188 | 193 | ||
189 | /* Recognize info frames */ | 194 | /* Recognize info frames */ |
@@ -198,6 +203,8 @@ MODULE_FIRMWARE("orinoco_ezusb_fw"); | |||
198 | 203 | ||
199 | #define BULK_BUF_SIZE 2048 | 204 | #define BULK_BUF_SIZE 2048 |
200 | 205 | ||
206 | #define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet)) | ||
207 | |||
201 | #define FW_BUF_SIZE 64 | 208 | #define FW_BUF_SIZE 64 |
202 | #define FW_VAR_OFFSET_PTR 0x359 | 209 | #define FW_VAR_OFFSET_PTR 0x359 |
203 | #define FW_VAR_VALUE 0 | 210 | #define FW_VAR_VALUE 0 |
@@ -1077,6 +1084,115 @@ static int ezusb_bap_pread(struct hermes *hw, int bap, | |||
1077 | return 0; | 1084 | return 0; |
1078 | } | 1085 | } |
1079 | 1086 | ||
1087 | static int ezusb_read_pda(struct hermes *hw, __le16 *pda, | ||
1088 | u32 pda_addr, u16 pda_len) | ||
1089 | { | ||
1090 | struct ezusb_priv *upriv = hw->priv; | ||
1091 | struct request_context *ctx; | ||
1092 | __le16 data[] = { | ||
1093 | cpu_to_le16(pda_addr & 0xffff), | ||
1094 | cpu_to_le16(pda_len - 4) | ||
1095 | }; | ||
1096 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA); | ||
1097 | if (!ctx) | ||
1098 | return -ENOMEM; | ||
1099 | |||
1100 | /* wl_lkm does not include PDA size in the PDA area. | ||
1101 | * We will pad the information into pda, so other routines | ||
1102 | * don't have to be modified */ | ||
1103 | pda[0] = cpu_to_le16(pda_len - 2); | ||
1104 | /* Includes CFG_PROD_DATA but not itself */ | ||
1105 | pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */ | ||
1106 | |||
1107 | return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, | ||
1108 | EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4, | ||
1109 | NULL); | ||
1110 | } | ||
1111 | |||
1112 | static int ezusb_program_init(struct hermes *hw, u32 entry_point) | ||
1113 | { | ||
1114 | struct ezusb_priv *upriv = hw->priv; | ||
1115 | struct request_context *ctx; | ||
1116 | __le32 data = cpu_to_le32(entry_point); | ||
1117 | |||
1118 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK); | ||
1119 | if (!ctx) | ||
1120 | return -ENOMEM; | ||
1121 | |||
1122 | return ezusb_access_ltv(upriv, ctx, sizeof(data), &data, | ||
1123 | EZUSB_FRAME_CONTROL, NULL, 0, NULL); | ||
1124 | } | ||
1125 | |||
1126 | static int ezusb_program_end(struct hermes *hw) | ||
1127 | { | ||
1128 | struct ezusb_priv *upriv = hw->priv; | ||
1129 | struct request_context *ctx; | ||
1130 | |||
1131 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK); | ||
1132 | if (!ctx) | ||
1133 | return -ENOMEM; | ||
1134 | |||
1135 | return ezusb_access_ltv(upriv, ctx, 0, NULL, | ||
1136 | EZUSB_FRAME_CONTROL, NULL, 0, NULL); | ||
1137 | } | ||
1138 | |||
1139 | static int ezusb_program_bytes(struct hermes *hw, const char *buf, | ||
1140 | u32 addr, u32 len) | ||
1141 | { | ||
1142 | struct ezusb_priv *upriv = hw->priv; | ||
1143 | struct request_context *ctx; | ||
1144 | __le32 data = cpu_to_le32(addr); | ||
1145 | int err; | ||
1146 | |||
1147 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK); | ||
1148 | if (!ctx) | ||
1149 | return -ENOMEM; | ||
1150 | |||
1151 | err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data, | ||
1152 | EZUSB_FRAME_CONTROL, NULL, 0, NULL); | ||
1153 | if (err) | ||
1154 | return err; | ||
1155 | |||
1156 | ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK); | ||
1157 | if (!ctx) | ||
1158 | return -ENOMEM; | ||
1159 | |||
1160 | return ezusb_access_ltv(upriv, ctx, len, buf, | ||
1161 | EZUSB_FRAME_CONTROL, NULL, 0, NULL); | ||
1162 | } | ||
1163 | |||
1164 | static int ezusb_program(struct hermes *hw, const char *buf, | ||
1165 | u32 addr, u32 len) | ||
1166 | { | ||
1167 | u32 ch_addr; | ||
1168 | u32 ch_len; | ||
1169 | int err = 0; | ||
1170 | |||
1171 | /* We can only send 2048 bytes out of the bulk xmit at a time, | ||
1172 | * so we have to split any programming into chunks of <2048 | ||
1173 | * bytes. */ | ||
1174 | |||
1175 | ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE; | ||
1176 | ch_addr = addr; | ||
1177 | |||
1178 | while (ch_addr < (addr + len)) { | ||
1179 | pr_debug("Programming subblock of length %d " | ||
1180 | "to address 0x%08x. Data @ %p\n", | ||
1181 | ch_len, ch_addr, &buf[ch_addr - addr]); | ||
1182 | |||
1183 | err = ezusb_program_bytes(hw, &buf[ch_addr - addr], | ||
1184 | ch_addr, ch_len); | ||
1185 | if (err) | ||
1186 | break; | ||
1187 | |||
1188 | ch_addr += ch_len; | ||
1189 | ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ? | ||
1190 | (addr + len - ch_addr) : MAX_DL_SIZE; | ||
1191 | } | ||
1192 | |||
1193 | return err; | ||
1194 | } | ||
1195 | |||
1080 | static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) | 1196 | static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev) |
1081 | { | 1197 | { |
1082 | struct orinoco_private *priv = ndev_priv(dev); | 1198 | struct orinoco_private *priv = ndev_priv(dev); |
@@ -1440,6 +1556,10 @@ static const struct hermes_ops ezusb_ops = { | |||
1440 | .read_ltv = ezusb_read_ltv, | 1556 | .read_ltv = ezusb_read_ltv, |
1441 | .write_ltv = ezusb_write_ltv, | 1557 | .write_ltv = ezusb_write_ltv, |
1442 | .bap_pread = ezusb_bap_pread, | 1558 | .bap_pread = ezusb_bap_pread, |
1559 | .read_pda = ezusb_read_pda, | ||
1560 | .program_init = ezusb_program_init, | ||
1561 | .program_end = ezusb_program_end, | ||
1562 | .program = ezusb_program, | ||
1443 | .lock_irqsave = ezusb_lock_irqsave, | 1563 | .lock_irqsave = ezusb_lock_irqsave, |
1444 | .unlock_irqrestore = ezusb_unlock_irqrestore, | 1564 | .unlock_irqrestore = ezusb_unlock_irqrestore, |
1445 | .lock_irq = ezusb_lock_irq, | 1565 | .lock_irq = ezusb_lock_irq, |
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index b4f68ef771e4..9b1af4976bf5 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c | |||
@@ -349,6 +349,7 @@ spectrum_cs_config(struct pcmcia_device *link) | |||
349 | goto failed; | 349 | goto failed; |
350 | 350 | ||
351 | hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); | 351 | hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING); |
352 | hw->eeprom_pda = true; | ||
352 | 353 | ||
353 | /* | 354 | /* |
354 | * This actually configures the PCMCIA socket -- setting up | 355 | * This actually configures the PCMCIA socket -- setting up |