diff options
author | David Kilroy <kilroyd@googlemail.com> | 2009-02-04 18:05:52 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:44:26 -0500 |
commit | 37a2e566f82de9a88fe119479162f9984af2180d (patch) | |
tree | 4d2e99a9b9bfdc4dfa57262a0965afc0c540653d /drivers/net/wireless | |
parent | 4adb474b6b7e26e1318acab5e98864aa78f9b233 (diff) |
orinoco: Move firmware handling into a separate file
No functional change.
Signed-off-by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/orinoco/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/fw.c | 340 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/fw.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco/main.c | 335 |
4 files changed, 358 insertions, 335 deletions
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile index 9d3ef2941229..fecdbcec51a1 100644 --- a/drivers/net/wireless/orinoco/Makefile +++ b/drivers/net/wireless/orinoco/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the orinoco wireless device drivers. | 2 | # Makefile for the orinoco wireless device drivers. |
3 | # | 3 | # |
4 | orinoco-objs := main.o mic.o scan.o | 4 | orinoco-objs := main.o fw.o mic.o scan.o |
5 | 5 | ||
6 | obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o | 6 | obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o |
7 | obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o | 7 | obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o |
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c new file mode 100644 index 000000000000..81c3d76648ba --- /dev/null +++ b/drivers/net/wireless/orinoco/fw.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* Firmware file reading and download helpers | ||
2 | * | ||
3 | * See copyright notice in main.c | ||
4 | */ | ||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/firmware.h> | ||
7 | |||
8 | #include "hermes.h" | ||
9 | #include "hermes_dld.h" | ||
10 | #include "orinoco.h" | ||
11 | |||
12 | #include "fw.h" | ||
13 | |||
14 | /* End markers (for Symbol firmware only) */ | ||
15 | #define TEXT_END 0x1A /* End of text header */ | ||
16 | |||
17 | struct fw_info { | ||
18 | char *pri_fw; | ||
19 | char *sta_fw; | ||
20 | char *ap_fw; | ||
21 | u32 pda_addr; | ||
22 | u16 pda_size; | ||
23 | }; | ||
24 | |||
25 | const static struct fw_info orinoco_fw[] = { | ||
26 | { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, | ||
27 | { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, | ||
28 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } | ||
29 | }; | ||
30 | |||
31 | /* Structure used to access fields in FW | ||
32 | * Make sure LE decoding macros are used | ||
33 | */ | ||
34 | struct orinoco_fw_header { | ||
35 | char hdr_vers[6]; /* ASCII string for header version */ | ||
36 | __le16 headersize; /* Total length of header */ | ||
37 | __le32 entry_point; /* NIC entry point */ | ||
38 | __le32 blocks; /* Number of blocks to program */ | ||
39 | __le32 block_offset; /* Offset of block data from eof header */ | ||
40 | __le32 pdr_offset; /* Offset to PDR data from eof header */ | ||
41 | __le32 pri_offset; /* Offset to primary plug data */ | ||
42 | __le32 compat_offset; /* Offset to compatibility data*/ | ||
43 | char signature[0]; /* FW signature length headersize-20 */ | ||
44 | } __attribute__ ((packed)); | ||
45 | |||
46 | /* Download either STA or AP firmware into the card. */ | ||
47 | static int | ||
48 | orinoco_dl_firmware(struct orinoco_private *priv, | ||
49 | const struct fw_info *fw, | ||
50 | int ap) | ||
51 | { | ||
52 | /* Plug Data Area (PDA) */ | ||
53 | __le16 *pda; | ||
54 | |||
55 | hermes_t *hw = &priv->hw; | ||
56 | const struct firmware *fw_entry; | ||
57 | const struct orinoco_fw_header *hdr; | ||
58 | const unsigned char *first_block; | ||
59 | const unsigned char *end; | ||
60 | const char *firmware; | ||
61 | struct net_device *dev = priv->ndev; | ||
62 | int err = 0; | ||
63 | |||
64 | pda = kzalloc(fw->pda_size, GFP_KERNEL); | ||
65 | if (!pda) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | if (ap) | ||
69 | firmware = fw->ap_fw; | ||
70 | else | ||
71 | firmware = fw->sta_fw; | ||
72 | |||
73 | printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", | ||
74 | dev->name, firmware); | ||
75 | |||
76 | /* Read current plug data */ | ||
77 | err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); | ||
78 | printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); | ||
79 | if (err) | ||
80 | goto free; | ||
81 | |||
82 | if (!priv->cached_fw) { | ||
83 | err = request_firmware(&fw_entry, firmware, priv->dev); | ||
84 | |||
85 | if (err) { | ||
86 | printk(KERN_ERR "%s: Cannot find firmware %s\n", | ||
87 | dev->name, firmware); | ||
88 | err = -ENOENT; | ||
89 | goto free; | ||
90 | } | ||
91 | } else | ||
92 | fw_entry = priv->cached_fw; | ||
93 | |||
94 | hdr = (const struct orinoco_fw_header *) fw_entry->data; | ||
95 | |||
96 | /* Enable aux port to allow programming */ | ||
97 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); | ||
98 | printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); | ||
99 | if (err != 0) | ||
100 | goto abort; | ||
101 | |||
102 | /* Program data */ | ||
103 | first_block = (fw_entry->data + | ||
104 | le16_to_cpu(hdr->headersize) + | ||
105 | le32_to_cpu(hdr->block_offset)); | ||
106 | end = fw_entry->data + fw_entry->size; | ||
107 | |||
108 | err = hermes_program(hw, first_block, end); | ||
109 | printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); | ||
110 | if (err != 0) | ||
111 | goto abort; | ||
112 | |||
113 | /* Update production data */ | ||
114 | first_block = (fw_entry->data + | ||
115 | le16_to_cpu(hdr->headersize) + | ||
116 | le32_to_cpu(hdr->pdr_offset)); | ||
117 | |||
118 | err = hermes_apply_pda_with_defaults(hw, first_block, pda); | ||
119 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); | ||
120 | if (err) | ||
121 | goto abort; | ||
122 | |||
123 | /* Tell card we've finished */ | ||
124 | err = hermesi_program_end(hw); | ||
125 | printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); | ||
126 | if (err != 0) | ||
127 | goto abort; | ||
128 | |||
129 | /* Check if we're running */ | ||
130 | printk(KERN_DEBUG "%s: hermes_present returned %d\n", | ||
131 | dev->name, hermes_present(hw)); | ||
132 | |||
133 | abort: | ||
134 | /* If we requested the firmware, release it. */ | ||
135 | if (!priv->cached_fw) | ||
136 | release_firmware(fw_entry); | ||
137 | |||
138 | free: | ||
139 | kfree(pda); | ||
140 | return err; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * Process a firmware image - stop the card, load the firmware, reset | ||
145 | * the card and make sure it responds. For the secondary firmware take | ||
146 | * care of the PDA - read it and then write it on top of the firmware. | ||
147 | */ | ||
148 | static int | ||
149 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | ||
150 | const unsigned char *image, const unsigned char *end, | ||
151 | int secondary) | ||
152 | { | ||
153 | hermes_t *hw = &priv->hw; | ||
154 | int ret = 0; | ||
155 | const unsigned char *ptr; | ||
156 | const unsigned char *first_block; | ||
157 | |||
158 | /* Plug Data Area (PDA) */ | ||
159 | __le16 *pda = NULL; | ||
160 | |||
161 | /* Binary block begins after the 0x1A marker */ | ||
162 | ptr = image; | ||
163 | while (*ptr++ != TEXT_END); | ||
164 | first_block = ptr; | ||
165 | |||
166 | /* Read the PDA from EEPROM */ | ||
167 | if (secondary) { | ||
168 | pda = kzalloc(fw->pda_size, GFP_KERNEL); | ||
169 | if (!pda) | ||
170 | return -ENOMEM; | ||
171 | |||
172 | ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); | ||
173 | if (ret) | ||
174 | goto free; | ||
175 | } | ||
176 | |||
177 | /* Stop the firmware, so that it can be safely rewritten */ | ||
178 | if (priv->stop_fw) { | ||
179 | ret = priv->stop_fw(priv, 1); | ||
180 | if (ret) | ||
181 | goto free; | ||
182 | } | ||
183 | |||
184 | /* Program the adapter with new firmware */ | ||
185 | ret = hermes_program(hw, first_block, end); | ||
186 | if (ret) | ||
187 | goto free; | ||
188 | |||
189 | /* Write the PDA to the adapter */ | ||
190 | if (secondary) { | ||
191 | size_t len = hermes_blocks_length(first_block); | ||
192 | ptr = first_block + len; | ||
193 | ret = hermes_apply_pda(hw, ptr, pda); | ||
194 | kfree(pda); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* Run the firmware */ | ||
200 | if (priv->stop_fw) { | ||
201 | ret = priv->stop_fw(priv, 0); | ||
202 | if (ret) | ||
203 | return ret; | ||
204 | } | ||
205 | |||
206 | /* Reset hermes chip and make sure it responds */ | ||
207 | ret = hermes_init(hw); | ||
208 | |||
209 | /* hermes_reset() should return 0 with the secondary firmware */ | ||
210 | if (secondary && ret != 0) | ||
211 | return -ENODEV; | ||
212 | |||
213 | /* And this should work with any firmware */ | ||
214 | if (!hermes_present(hw)) | ||
215 | return -ENODEV; | ||
216 | |||
217 | return 0; | ||
218 | |||
219 | free: | ||
220 | kfree(pda); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | |||
225 | /* | ||
226 | * Download the firmware into the card, this also does a PCMCIA soft | ||
227 | * reset on the card, to make sure it's in a sane state. | ||
228 | */ | ||
229 | static int | ||
230 | symbol_dl_firmware(struct orinoco_private *priv, | ||
231 | const struct fw_info *fw) | ||
232 | { | ||
233 | struct net_device *dev = priv->ndev; | ||
234 | int ret; | ||
235 | const struct firmware *fw_entry; | ||
236 | |||
237 | if (!priv->cached_pri_fw) { | ||
238 | if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { | ||
239 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
240 | dev->name, fw->pri_fw); | ||
241 | return -ENOENT; | ||
242 | } | ||
243 | } else | ||
244 | fw_entry = priv->cached_pri_fw; | ||
245 | |||
246 | /* Load primary firmware */ | ||
247 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
248 | fw_entry->data + fw_entry->size, 0); | ||
249 | |||
250 | if (!priv->cached_pri_fw) | ||
251 | release_firmware(fw_entry); | ||
252 | if (ret) { | ||
253 | printk(KERN_ERR "%s: Primary firmware download failed\n", | ||
254 | dev->name); | ||
255 | return ret; | ||
256 | } | ||
257 | |||
258 | if (!priv->cached_fw) { | ||
259 | if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { | ||
260 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
261 | dev->name, fw->sta_fw); | ||
262 | return -ENOENT; | ||
263 | } | ||
264 | } else | ||
265 | fw_entry = priv->cached_fw; | ||
266 | |||
267 | /* Load secondary firmware */ | ||
268 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
269 | fw_entry->data + fw_entry->size, 1); | ||
270 | if (!priv->cached_fw) | ||
271 | release_firmware(fw_entry); | ||
272 | if (ret) { | ||
273 | printk(KERN_ERR "%s: Secondary firmware download failed\n", | ||
274 | dev->name); | ||
275 | } | ||
276 | |||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | int orinoco_download(struct orinoco_private *priv) | ||
281 | { | ||
282 | int err = 0; | ||
283 | /* Reload firmware */ | ||
284 | switch (priv->firmware_type) { | ||
285 | case FIRMWARE_TYPE_AGERE: | ||
286 | /* case FIRMWARE_TYPE_INTERSIL: */ | ||
287 | err = orinoco_dl_firmware(priv, | ||
288 | &orinoco_fw[priv->firmware_type], 0); | ||
289 | break; | ||
290 | |||
291 | case FIRMWARE_TYPE_SYMBOL: | ||
292 | err = symbol_dl_firmware(priv, | ||
293 | &orinoco_fw[priv->firmware_type]); | ||
294 | break; | ||
295 | case FIRMWARE_TYPE_INTERSIL: | ||
296 | break; | ||
297 | } | ||
298 | /* TODO: if we fail we probably need to reinitialise | ||
299 | * the driver */ | ||
300 | |||
301 | return err; | ||
302 | } | ||
303 | |||
304 | void orinoco_cache_fw(struct orinoco_private *priv, int ap) | ||
305 | { | ||
306 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) | ||
307 | const struct firmware *fw_entry = NULL; | ||
308 | const char *pri_fw; | ||
309 | const char *fw; | ||
310 | |||
311 | pri_fw = orinoco_fw[priv->firmware_type].pri_fw; | ||
312 | if (ap) | ||
313 | fw = orinoco_fw[priv->firmware_type].ap_fw; | ||
314 | else | ||
315 | fw = orinoco_fw[priv->firmware_type].sta_fw; | ||
316 | |||
317 | if (pri_fw) { | ||
318 | if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) | ||
319 | priv->cached_pri_fw = fw_entry; | ||
320 | } | ||
321 | |||
322 | if (fw) { | ||
323 | if (request_firmware(&fw_entry, fw, priv->dev) == 0) | ||
324 | priv->cached_fw = fw_entry; | ||
325 | } | ||
326 | #endif | ||
327 | } | ||
328 | |||
329 | void orinoco_uncache_fw(struct orinoco_private *priv) | ||
330 | { | ||
331 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) | ||
332 | if (priv->cached_pri_fw) | ||
333 | release_firmware(priv->cached_pri_fw); | ||
334 | if (priv->cached_fw) | ||
335 | release_firmware(priv->cached_fw); | ||
336 | |||
337 | priv->cached_pri_fw = NULL; | ||
338 | priv->cached_fw = NULL; | ||
339 | #endif | ||
340 | } | ||
diff --git a/drivers/net/wireless/orinoco/fw.h b/drivers/net/wireless/orinoco/fw.h new file mode 100644 index 000000000000..2290f0845d59 --- /dev/null +++ b/drivers/net/wireless/orinoco/fw.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* Firmware file reading and download helpers | ||
2 | * | ||
3 | * See copyright notice in main.c | ||
4 | */ | ||
5 | #ifndef _ORINOCO_FW_H_ | ||
6 | #define _ORINOCO_FW_H_ | ||
7 | |||
8 | /* Forward declations */ | ||
9 | struct orinoco_private; | ||
10 | |||
11 | int orinoco_download(struct orinoco_private *priv); | ||
12 | |||
13 | void orinoco_cache_fw(struct orinoco_private *priv, int ap); | ||
14 | void orinoco_uncache_fw(struct orinoco_private *priv); | ||
15 | |||
16 | #endif /* _ORINOCO_FW_H_ */ | ||
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index f0454440dd7b..f49cabd70877 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c | |||
@@ -83,7 +83,6 @@ | |||
83 | #include <linux/netdevice.h> | 83 | #include <linux/netdevice.h> |
84 | #include <linux/etherdevice.h> | 84 | #include <linux/etherdevice.h> |
85 | #include <linux/ethtool.h> | 85 | #include <linux/ethtool.h> |
86 | #include <linux/firmware.h> | ||
87 | #include <linux/suspend.h> | 86 | #include <linux/suspend.h> |
88 | #include <linux/if_arp.h> | 87 | #include <linux/if_arp.h> |
89 | #include <linux/wireless.h> | 88 | #include <linux/wireless.h> |
@@ -94,6 +93,7 @@ | |||
94 | #include "hermes_dld.h" | 93 | #include "hermes_dld.h" |
95 | #include "scan.h" | 94 | #include "scan.h" |
96 | #include "mic.h" | 95 | #include "mic.h" |
96 | #include "fw.h" | ||
97 | 97 | ||
98 | #include "orinoco.h" | 98 | #include "orinoco.h" |
99 | 99 | ||
@@ -310,339 +310,6 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) | |||
310 | 310 | ||
311 | 311 | ||
312 | /********************************************************************/ | 312 | /********************************************************************/ |
313 | /* Download functionality */ | ||
314 | /********************************************************************/ | ||
315 | |||
316 | struct fw_info { | ||
317 | char *pri_fw; | ||
318 | char *sta_fw; | ||
319 | char *ap_fw; | ||
320 | u32 pda_addr; | ||
321 | u16 pda_size; | ||
322 | }; | ||
323 | |||
324 | const static struct fw_info orinoco_fw[] = { | ||
325 | { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, | ||
326 | { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, | ||
327 | { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } | ||
328 | }; | ||
329 | |||
330 | /* Structure used to access fields in FW | ||
331 | * Make sure LE decoding macros are used | ||
332 | */ | ||
333 | struct orinoco_fw_header { | ||
334 | char hdr_vers[6]; /* ASCII string for header version */ | ||
335 | __le16 headersize; /* Total length of header */ | ||
336 | __le32 entry_point; /* NIC entry point */ | ||
337 | __le32 blocks; /* Number of blocks to program */ | ||
338 | __le32 block_offset; /* Offset of block data from eof header */ | ||
339 | __le32 pdr_offset; /* Offset to PDR data from eof header */ | ||
340 | __le32 pri_offset; /* Offset to primary plug data */ | ||
341 | __le32 compat_offset; /* Offset to compatibility data*/ | ||
342 | char signature[0]; /* FW signature length headersize-20 */ | ||
343 | } __attribute__ ((packed)); | ||
344 | |||
345 | /* Download either STA or AP firmware into the card. */ | ||
346 | static int | ||
347 | orinoco_dl_firmware(struct orinoco_private *priv, | ||
348 | const struct fw_info *fw, | ||
349 | int ap) | ||
350 | { | ||
351 | /* Plug Data Area (PDA) */ | ||
352 | __le16 *pda; | ||
353 | |||
354 | hermes_t *hw = &priv->hw; | ||
355 | const struct firmware *fw_entry; | ||
356 | const struct orinoco_fw_header *hdr; | ||
357 | const unsigned char *first_block; | ||
358 | const unsigned char *end; | ||
359 | const char *firmware; | ||
360 | struct net_device *dev = priv->ndev; | ||
361 | int err = 0; | ||
362 | |||
363 | pda = kzalloc(fw->pda_size, GFP_KERNEL); | ||
364 | if (!pda) | ||
365 | return -ENOMEM; | ||
366 | |||
367 | if (ap) | ||
368 | firmware = fw->ap_fw; | ||
369 | else | ||
370 | firmware = fw->sta_fw; | ||
371 | |||
372 | printk(KERN_DEBUG "%s: Attempting to download firmware %s\n", | ||
373 | dev->name, firmware); | ||
374 | |||
375 | /* Read current plug data */ | ||
376 | err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0); | ||
377 | printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err); | ||
378 | if (err) | ||
379 | goto free; | ||
380 | |||
381 | if (!priv->cached_fw) { | ||
382 | err = request_firmware(&fw_entry, firmware, priv->dev); | ||
383 | |||
384 | if (err) { | ||
385 | printk(KERN_ERR "%s: Cannot find firmware %s\n", | ||
386 | dev->name, firmware); | ||
387 | err = -ENOENT; | ||
388 | goto free; | ||
389 | } | ||
390 | } else | ||
391 | fw_entry = priv->cached_fw; | ||
392 | |||
393 | hdr = (const struct orinoco_fw_header *) fw_entry->data; | ||
394 | |||
395 | /* Enable aux port to allow programming */ | ||
396 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); | ||
397 | printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); | ||
398 | if (err != 0) | ||
399 | goto abort; | ||
400 | |||
401 | /* Program data */ | ||
402 | first_block = (fw_entry->data + | ||
403 | le16_to_cpu(hdr->headersize) + | ||
404 | le32_to_cpu(hdr->block_offset)); | ||
405 | end = fw_entry->data + fw_entry->size; | ||
406 | |||
407 | err = hermes_program(hw, first_block, end); | ||
408 | printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err); | ||
409 | if (err != 0) | ||
410 | goto abort; | ||
411 | |||
412 | /* Update production data */ | ||
413 | first_block = (fw_entry->data + | ||
414 | le16_to_cpu(hdr->headersize) + | ||
415 | le32_to_cpu(hdr->pdr_offset)); | ||
416 | |||
417 | err = hermes_apply_pda_with_defaults(hw, first_block, pda); | ||
418 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); | ||
419 | if (err) | ||
420 | goto abort; | ||
421 | |||
422 | /* Tell card we've finished */ | ||
423 | err = hermesi_program_end(hw); | ||
424 | printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err); | ||
425 | if (err != 0) | ||
426 | goto abort; | ||
427 | |||
428 | /* Check if we're running */ | ||
429 | printk(KERN_DEBUG "%s: hermes_present returned %d\n", | ||
430 | dev->name, hermes_present(hw)); | ||
431 | |||
432 | abort: | ||
433 | /* If we requested the firmware, release it. */ | ||
434 | if (!priv->cached_fw) | ||
435 | release_firmware(fw_entry); | ||
436 | |||
437 | free: | ||
438 | kfree(pda); | ||
439 | return err; | ||
440 | } | ||
441 | |||
442 | /* End markers */ | ||
443 | #define TEXT_END 0x1A /* End of text header */ | ||
444 | |||
445 | /* | ||
446 | * Process a firmware image - stop the card, load the firmware, reset | ||
447 | * the card and make sure it responds. For the secondary firmware take | ||
448 | * care of the PDA - read it and then write it on top of the firmware. | ||
449 | */ | ||
450 | static int | ||
451 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | ||
452 | const unsigned char *image, const unsigned char *end, | ||
453 | int secondary) | ||
454 | { | ||
455 | hermes_t *hw = &priv->hw; | ||
456 | int ret = 0; | ||
457 | const unsigned char *ptr; | ||
458 | const unsigned char *first_block; | ||
459 | |||
460 | /* Plug Data Area (PDA) */ | ||
461 | __le16 *pda = NULL; | ||
462 | |||
463 | /* Binary block begins after the 0x1A marker */ | ||
464 | ptr = image; | ||
465 | while (*ptr++ != TEXT_END); | ||
466 | first_block = ptr; | ||
467 | |||
468 | /* Read the PDA from EEPROM */ | ||
469 | if (secondary) { | ||
470 | pda = kzalloc(fw->pda_size, GFP_KERNEL); | ||
471 | if (!pda) | ||
472 | return -ENOMEM; | ||
473 | |||
474 | ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1); | ||
475 | if (ret) | ||
476 | goto free; | ||
477 | } | ||
478 | |||
479 | /* Stop the firmware, so that it can be safely rewritten */ | ||
480 | if (priv->stop_fw) { | ||
481 | ret = priv->stop_fw(priv, 1); | ||
482 | if (ret) | ||
483 | goto free; | ||
484 | } | ||
485 | |||
486 | /* Program the adapter with new firmware */ | ||
487 | ret = hermes_program(hw, first_block, end); | ||
488 | if (ret) | ||
489 | goto free; | ||
490 | |||
491 | /* Write the PDA to the adapter */ | ||
492 | if (secondary) { | ||
493 | size_t len = hermes_blocks_length(first_block); | ||
494 | ptr = first_block + len; | ||
495 | ret = hermes_apply_pda(hw, ptr, pda); | ||
496 | kfree(pda); | ||
497 | if (ret) | ||
498 | return ret; | ||
499 | } | ||
500 | |||
501 | /* Run the firmware */ | ||
502 | if (priv->stop_fw) { | ||
503 | ret = priv->stop_fw(priv, 0); | ||
504 | if (ret) | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | /* Reset hermes chip and make sure it responds */ | ||
509 | ret = hermes_init(hw); | ||
510 | |||
511 | /* hermes_reset() should return 0 with the secondary firmware */ | ||
512 | if (secondary && ret != 0) | ||
513 | return -ENODEV; | ||
514 | |||
515 | /* And this should work with any firmware */ | ||
516 | if (!hermes_present(hw)) | ||
517 | return -ENODEV; | ||
518 | |||
519 | return 0; | ||
520 | |||
521 | free: | ||
522 | kfree(pda); | ||
523 | return ret; | ||
524 | } | ||
525 | |||
526 | |||
527 | /* | ||
528 | * Download the firmware into the card, this also does a PCMCIA soft | ||
529 | * reset on the card, to make sure it's in a sane state. | ||
530 | */ | ||
531 | static int | ||
532 | symbol_dl_firmware(struct orinoco_private *priv, | ||
533 | const struct fw_info *fw) | ||
534 | { | ||
535 | struct net_device *dev = priv->ndev; | ||
536 | int ret; | ||
537 | const struct firmware *fw_entry; | ||
538 | |||
539 | if (!priv->cached_pri_fw) { | ||
540 | if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { | ||
541 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
542 | dev->name, fw->pri_fw); | ||
543 | return -ENOENT; | ||
544 | } | ||
545 | } else | ||
546 | fw_entry = priv->cached_pri_fw; | ||
547 | |||
548 | /* Load primary firmware */ | ||
549 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
550 | fw_entry->data + fw_entry->size, 0); | ||
551 | |||
552 | if (!priv->cached_pri_fw) | ||
553 | release_firmware(fw_entry); | ||
554 | if (ret) { | ||
555 | printk(KERN_ERR "%s: Primary firmware download failed\n", | ||
556 | dev->name); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | if (!priv->cached_fw) { | ||
561 | if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { | ||
562 | printk(KERN_ERR "%s: Cannot find firmware: %s\n", | ||
563 | dev->name, fw->sta_fw); | ||
564 | return -ENOENT; | ||
565 | } | ||
566 | } else | ||
567 | fw_entry = priv->cached_fw; | ||
568 | |||
569 | /* Load secondary firmware */ | ||
570 | ret = symbol_dl_image(priv, fw, fw_entry->data, | ||
571 | fw_entry->data + fw_entry->size, 1); | ||
572 | if (!priv->cached_fw) | ||
573 | release_firmware(fw_entry); | ||
574 | if (ret) { | ||
575 | printk(KERN_ERR "%s: Secondary firmware download failed\n", | ||
576 | dev->name); | ||
577 | } | ||
578 | |||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | static int orinoco_download(struct orinoco_private *priv) | ||
583 | { | ||
584 | int err = 0; | ||
585 | /* Reload firmware */ | ||
586 | switch (priv->firmware_type) { | ||
587 | case FIRMWARE_TYPE_AGERE: | ||
588 | /* case FIRMWARE_TYPE_INTERSIL: */ | ||
589 | err = orinoco_dl_firmware(priv, | ||
590 | &orinoco_fw[priv->firmware_type], 0); | ||
591 | break; | ||
592 | |||
593 | case FIRMWARE_TYPE_SYMBOL: | ||
594 | err = symbol_dl_firmware(priv, | ||
595 | &orinoco_fw[priv->firmware_type]); | ||
596 | break; | ||
597 | case FIRMWARE_TYPE_INTERSIL: | ||
598 | break; | ||
599 | } | ||
600 | /* TODO: if we fail we probably need to reinitialise | ||
601 | * the driver */ | ||
602 | |||
603 | return err; | ||
604 | } | ||
605 | |||
606 | #if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) | ||
607 | static void orinoco_cache_fw(struct orinoco_private *priv, int ap) | ||
608 | { | ||
609 | const struct firmware *fw_entry = NULL; | ||
610 | const char *pri_fw; | ||
611 | const char *fw; | ||
612 | |||
613 | pri_fw = orinoco_fw[priv->firmware_type].pri_fw; | ||
614 | if (ap) | ||
615 | fw = orinoco_fw[priv->firmware_type].ap_fw; | ||
616 | else | ||
617 | fw = orinoco_fw[priv->firmware_type].sta_fw; | ||
618 | |||
619 | if (pri_fw) { | ||
620 | if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) | ||
621 | priv->cached_pri_fw = fw_entry; | ||
622 | } | ||
623 | |||
624 | if (fw) { | ||
625 | if (request_firmware(&fw_entry, fw, priv->dev) == 0) | ||
626 | priv->cached_fw = fw_entry; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static void orinoco_uncache_fw(struct orinoco_private *priv) | ||
631 | { | ||
632 | if (priv->cached_pri_fw) | ||
633 | release_firmware(priv->cached_pri_fw); | ||
634 | if (priv->cached_fw) | ||
635 | release_firmware(priv->cached_fw); | ||
636 | |||
637 | priv->cached_pri_fw = NULL; | ||
638 | priv->cached_fw = NULL; | ||
639 | } | ||
640 | #else | ||
641 | #define orinoco_cache_fw(priv, ap) | ||
642 | #define orinoco_uncache_fw(priv) | ||
643 | #endif | ||
644 | |||
645 | /********************************************************************/ | ||
646 | /* Device methods */ | 313 | /* Device methods */ |
647 | /********************************************************************/ | 314 | /********************************************************************/ |
648 | 315 | ||