aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Kilroy <kilroyd@gmail.com>2008-08-21 18:27:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-08-22 19:28:04 -0400
commitf482eb797a391a098046a934f55af8bd785a4494 (patch)
treee5238e31f384e32dcbb16b1e8376da0679130786 /drivers
parentfc5a62d8b7052ea588e4f7750cd78b0c4c47015a (diff)
orinoco: Move firmware download functionality into new module
Move the functionality from spectrum_cs to hermes_dld in preparation for making it more generic and usable by other orinoco drivers. Signed-off-by: David Kilroy <kilroyd@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/hermes_dld.c338
-rw-r--r--drivers/net/wireless/hermes_dld.h45
-rw-r--r--drivers/net/wireless/spectrum_cs.c274
4 files changed, 385 insertions, 274 deletions
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c05fd7627f3f..59d2d805f60b 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o
16obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o 16obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o
17obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o 17obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o
18 18
19obj-$(CONFIG_HERMES) += orinoco.o hermes.o 19obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o
20obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o 20obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
21obj-$(CONFIG_APPLE_AIRPORT) += airport.o 21obj-$(CONFIG_APPLE_AIRPORT) += airport.o
22obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o 22obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/hermes_dld.c
new file mode 100644
index 000000000000..9a8ef3040d59
--- /dev/null
+++ b/drivers/net/wireless/hermes_dld.c
@@ -0,0 +1,338 @@
1/*
2 * Hermes download helper driver.
3 *
4 * This could be entirely merged into hermes.c.
5 *
6 * I'm keeping it separate to minimise the amount of merging between
7 * kernel upgrades. It also means the memory overhead for drivers that
8 * don't need firmware download low.
9 *
10 * This driver:
11 * - is capable of writing to the volatile area of the hermes device
12 * - is currently not capable of writing to non-volatile areas
13 * - provide helpers to identify and update plugin data
14 * - is not capable of interpreting a fw image directly. That is up to
15 * the main card driver.
16 * - deals with Hermes I devices. It can probably be modified to deal
17 * with Hermes II devices
18 *
19 * Copyright (C) 2007, David Kilroy
20 *
21 * Plug data code slightly modified from spectrum_cs driver
22 * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
23 * Portions based on information in wl_lkm_718 Agere driver
24 * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
25 *
26 * The contents of this file are subject to the Mozilla Public License
27 * Version 1.1 (the "License"); you may not use this file except in
28 * compliance with the License. You may obtain a copy of the License
29 * at http://www.mozilla.org/MPL/
30 *
31 * Software distributed under the License is distributed on an "AS IS"
32 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
33 * the License for the specific language governing rights and
34 * limitations under the License.
35 *
36 * Alternatively, the contents of this file may be used under the
37 * terms of the GNU General Public License version 2 (the "GPL"), in
38 * which case the provisions of the GPL are applicable instead of the
39 * above. If you wish to allow the use of your version of this file
40 * only under the terms of the GPL and not to allow others to use your
41 * version of this file under the MPL, indicate your decision by
42 * deleting the provisions above and replace them with the notice and
43 * other provisions required by the GPL. If you do not delete the
44 * provisions above, a recipient may use your version of this file
45 * under either the MPL or the GPL.
46 */
47
48#include <linux/module.h>
49#include <linux/delay.h>
50#include "hermes.h"
51#include "hermes_dld.h"
52
53MODULE_DESCRIPTION("Download helper for Lucent Hermes chipset");
54MODULE_AUTHOR("David Kilroy <kilroyd@gmail.com>");
55MODULE_LICENSE("Dual MPL/GPL");
56
57#define PFX "hermes_dld: "
58
59/*
60 * AUX port access. To unlock the AUX port write the access keys to the
61 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
62 * register. Then read it and make sure it's HERMES_AUX_ENABLED.
63 */
64#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
65#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
66#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
67
68#define HERMES_AUX_PW0 0xFE01
69#define HERMES_AUX_PW1 0xDC23
70#define HERMES_AUX_PW2 0xBA45
71
72/* End markers */
73#define PDI_END 0x00000000 /* End of PDA */
74#define BLOCK_END 0xFFFFFFFF /* Last image block */
75
76/*
77 * The following structures have little-endian fields denoted by
78 * the leading underscore. Don't access them directly - use inline
79 * functions defined below.
80 */
81
82/*
83 * The binary image to be downloaded consists of series of data blocks.
84 * Each block has the following structure.
85 */
86struct dblock {
87 __le32 addr; /* adapter address where to write the block */
88 __le16 len; /* length of the data only, in bytes */
89 char data[0]; /* data to be written */
90} __attribute__ ((packed));
91
92/*
93 * Plug Data References are located in in the image after the last data
94 * block. They refer to areas in the adapter memory where the plug data
95 * items with matching ID should be written.
96 */
97struct pdr {
98 __le32 id; /* record ID */
99 __le32 addr; /* adapter address where to write the data */
100 __le32 len; /* expected length of the data, in bytes */
101 char next[0]; /* next PDR starts here */
102} __attribute__ ((packed));
103
104/*
105 * Plug Data Items are located in the EEPROM read from the adapter by
106 * primary firmware. They refer to the device-specific data that should
107 * be plugged into the secondary firmware.
108 */
109struct pdi {
110 __le16 len; /* length of ID and data, in words */
111 __le16 id; /* record ID */
112 char data[0]; /* plug data */
113} __attribute__ ((packed));
114
115/* Functions for access to little-endian data */
116static inline u32
117dblock_addr(const struct dblock *blk)
118{
119 return le32_to_cpu(blk->addr);
120}
121
122static inline u32
123dblock_len(const struct dblock *blk)
124{
125 return le16_to_cpu(blk->len);
126}
127
128static inline u32
129pdr_id(const struct pdr *pdr)
130{
131 return le32_to_cpu(pdr->id);
132}
133
134static inline u32
135pdr_addr(const struct pdr *pdr)
136{
137 return le32_to_cpu(pdr->addr);
138}
139
140static inline u32
141pdr_len(const struct pdr *pdr)
142{
143 return le32_to_cpu(pdr->len);
144}
145
146static inline u32
147pdi_id(const struct pdi *pdi)
148{
149 return le16_to_cpu(pdi->id);
150}
151
152/* Return length of the data only, in bytes */
153static inline u32
154pdi_len(const struct pdi *pdi)
155{
156 return 2 * (le16_to_cpu(pdi->len) - 1);
157}
158
159/* Set address of the auxiliary port */
160static inline void
161spectrum_aux_setaddr(hermes_t *hw, u32 addr)
162{
163 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
164 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
165}
166
167/* Open access to the auxiliary port */
168static int
169spectrum_aux_open(hermes_t *hw)
170{
171 int i;
172
173 /* Already open? */
174 if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
175 return 0;
176
177 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
178 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
179 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
180 hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
181
182 for (i = 0; i < 20; i++) {
183 udelay(10);
184 if (hermes_read_reg(hw, HERMES_CONTROL) ==
185 HERMES_AUX_ENABLED)
186 return 0;
187 }
188
189 return -EBUSY;
190}
191
192/*
193 * Scan PDR for the record with the specified RECORD_ID.
194 * If it's not found, return NULL.
195 */
196static struct pdr *
197spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
198{
199 struct pdr *pdr = first_pdr;
200
201 while (pdr_id(pdr) != PDI_END) {
202 /*
203 * PDR area is currently not terminated by PDI_END.
204 * It's followed by CRC records, which have the type
205 * field where PDR has length. The type can be 0 or 1.
206 */
207 if (pdr_len(pdr) < 2)
208 return NULL;
209
210 /* If the record ID matches, we are done */
211 if (pdr_id(pdr) == record_id)
212 return pdr;
213
214 pdr = (struct pdr *) pdr->next;
215 }
216 return NULL;
217}
218
219/* Process one Plug Data Item - find corresponding PDR and plug it */
220static int
221spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
222{
223 struct pdr *pdr;
224
225 /* Find the PDI corresponding to this PDR */
226 pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
227
228 /* No match is found, safe to ignore */
229 if (!pdr)
230 return 0;
231
232 /* Lengths of the data in PDI and PDR must match */
233 if (pdi_len(pdi) != pdr_len(pdr))
234 return -EINVAL;
235
236 /* do the actual plugging */
237 spectrum_aux_setaddr(hw, pdr_addr(pdr));
238 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
239
240 return 0;
241}
242
243/* Read PDA from the adapter */
244int
245spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len)
246{
247 int ret;
248 int pda_size;
249
250 /* Issue command to read EEPROM */
251 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
252 if (ret)
253 return ret;
254
255 /* Open auxiliary port */
256 ret = spectrum_aux_open(hw);
257 if (ret)
258 return ret;
259
260 /* read PDA from EEPROM */
261 spectrum_aux_setaddr(hw, PDA_ADDR);
262 hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
263
264 /* Check PDA length */
265 pda_size = le16_to_cpu(pda[0]);
266 if (pda_size > pda_len)
267 return -EINVAL;
268
269 return 0;
270}
271EXPORT_SYMBOL(spectrum_read_pda);
272
273/* Parse PDA and write the records into the adapter */
274int
275spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
276 __le16 *pda)
277{
278 int ret;
279 struct pdi *pdi;
280 struct pdr *first_pdr;
281 const struct dblock *blk = first_block;
282
283 /* Skip all blocks to locate Plug Data References */
284 while (dblock_addr(blk) != BLOCK_END)
285 blk = (struct dblock *) &blk->data[dblock_len(blk)];
286
287 first_pdr = (struct pdr *) blk;
288
289 /* Go through every PDI and plug them into the adapter */
290 pdi = (struct pdi *) (pda + 2);
291 while (pdi_id(pdi) != PDI_END) {
292 ret = spectrum_plug_pdi(hw, first_pdr, pdi);
293 if (ret)
294 return ret;
295
296 /* Increment to the next PDI */
297 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
298 }
299 return 0;
300}
301EXPORT_SYMBOL(spectrum_apply_pda);
302
303/* Load firmware blocks into the adapter */
304int
305spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
306{
307 const struct dblock *blk;
308 u32 blkaddr;
309 u32 blklen;
310
311 blk = first_block;
312 blkaddr = dblock_addr(blk);
313 blklen = dblock_len(blk);
314
315 while (dblock_addr(blk) != BLOCK_END) {
316 spectrum_aux_setaddr(hw, blkaddr);
317 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
318 blklen);
319
320 blk = (struct dblock *) &blk->data[blklen];
321 blkaddr = dblock_addr(blk);
322 blklen = dblock_len(blk);
323 }
324 return 0;
325}
326EXPORT_SYMBOL(spectrum_load_blocks);
327
328static int __init init_hermes_dld(void)
329{
330 return 0;
331}
332
333static void __exit exit_hermes_dld(void)
334{
335}
336
337module_init(init_hermes_dld);
338module_exit(exit_hermes_dld);
diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/hermes_dld.h
new file mode 100644
index 000000000000..2c8892ac635b
--- /dev/null
+++ b/drivers/net/wireless/hermes_dld.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2007, David Kilroy
3 *
4 * The contents of this file are subject to the Mozilla Public License
5 * Version 1.1 (the "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy of the License
7 * at http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11 * the License for the specific language governing rights and
12 * limitations under the License.
13 *
14 * Alternatively, the contents of this file may be used under the
15 * terms of the GNU General Public License version 2 (the "GPL"), in
16 * which case the provisions of the GPL are applicable instead of the
17 * above. If you wish to allow the use of your version of this file
18 * only under the terms of the GPL and not to allow others to use your
19 * version of this file under the MPL, indicate your decision by
20 * deleting the provisions above and replace them with the notice and
21 * other provisions required by the GPL. If you do not delete the
22 * provisions above, a recipient may use your version of this file
23 * under either the MPL or the GPL.
24 */
25#ifndef _HERMES_DLD_H
26#define _HERMES_DLD_H
27
28#include "hermes.h"
29
30/* Position of PDA in the adapter memory */
31#define EEPROM_ADDR 0x3000
32#define EEPROM_LEN 0x200
33#define PDA_OFFSET 0x100
34
35#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET)
36#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2)
37
38struct dblock;
39
40int spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len);
41int spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
42 __le16 *pda);
43int spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block);
44
45#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index 98df9bc7836a..579873d0e8c9 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -33,6 +33,7 @@
33#include <pcmcia/ds.h> 33#include <pcmcia/ds.h>
34 34
35#include "orinoco.h" 35#include "orinoco.h"
36#include "hermes_dld.h"
36 37
37static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; 38static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
38static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; 39static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
@@ -88,144 +89,9 @@ static void spectrum_cs_release(struct pcmcia_device *link);
88#define HCR_IDLE 0x0E /* don't run firmware after reset */ 89#define HCR_IDLE 0x0E /* don't run firmware after reset */
89#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ 90#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
90 91
91/*
92 * AUX port access. To unlock the AUX port write the access keys to the
93 * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
94 * register. Then read it and make sure it's HERMES_AUX_ENABLED.
95 */
96#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
97#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
98#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
99
100#define HERMES_AUX_PW0 0xFE01
101#define HERMES_AUX_PW1 0xDC23
102#define HERMES_AUX_PW2 0xBA45
103
104/* End markers */ 92/* End markers */
105#define PDI_END 0x00000000 /* End of PDA */
106#define BLOCK_END 0xFFFFFFFF /* Last image block */
107#define TEXT_END 0x1A /* End of text header */ 93#define TEXT_END 0x1A /* End of text header */
108 94
109/*
110 * The following structures have little-endian fields denoted by
111 * the leading underscore. Don't access them directly - use inline
112 * functions defined below.
113 */
114
115/*
116 * The binary image to be downloaded consists of series of data blocks.
117 * Each block has the following structure.
118 */
119struct dblock {
120 __le32 addr; /* adapter address where to write the block */
121 __le16 len; /* length of the data only, in bytes */
122 char data[0]; /* data to be written */
123} __attribute__ ((packed));
124
125/*
126 * Plug Data References are located in in the image after the last data
127 * block. They refer to areas in the adapter memory where the plug data
128 * items with matching ID should be written.
129 */
130struct pdr {
131 __le32 id; /* record ID */
132 __le32 addr; /* adapter address where to write the data */
133 __le32 len; /* expected length of the data, in bytes */
134 char next[0]; /* next PDR starts here */
135} __attribute__ ((packed));
136
137
138/*
139 * Plug Data Items are located in the EEPROM read from the adapter by
140 * primary firmware. They refer to the device-specific data that should
141 * be plugged into the secondary firmware.
142 */
143struct pdi {
144 __le16 len; /* length of ID and data, in words */
145 __le16 id; /* record ID */
146 char data[0]; /* plug data */
147} __attribute__ ((packed));
148
149
150/* Functions for access to little-endian data */
151static inline u32
152dblock_addr(const struct dblock *blk)
153{
154 return le32_to_cpu(blk->addr);
155}
156
157static inline u32
158dblock_len(const struct dblock *blk)
159{
160 return le16_to_cpu(blk->len);
161}
162
163static inline u32
164pdr_id(const struct pdr *pdr)
165{
166 return le32_to_cpu(pdr->id);
167}
168
169static inline u32
170pdr_addr(const struct pdr *pdr)
171{
172 return le32_to_cpu(pdr->addr);
173}
174
175static inline u32
176pdr_len(const struct pdr *pdr)
177{
178 return le32_to_cpu(pdr->len);
179}
180
181static inline u32
182pdi_id(const struct pdi *pdi)
183{
184 return le16_to_cpu(pdi->id);
185}
186
187/* Return length of the data only, in bytes */
188static inline u32
189pdi_len(const struct pdi *pdi)
190{
191 return 2 * (le16_to_cpu(pdi->len) - 1);
192}
193
194
195/* Set address of the auxiliary port */
196static inline void
197spectrum_aux_setaddr(hermes_t *hw, u32 addr)
198{
199 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
200 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
201}
202
203
204/* Open access to the auxiliary port */
205static int
206spectrum_aux_open(hermes_t *hw)
207{
208 int i;
209
210 /* Already open? */
211 if (hermes_read_reg(hw, HERMES_CONTROL) == HERMES_AUX_ENABLED)
212 return 0;
213
214 hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
215 hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
216 hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
217 hermes_write_reg(hw, HERMES_CONTROL, HERMES_AUX_ENABLE);
218
219 for (i = 0; i < 20; i++) {
220 udelay(10);
221 if (hermes_read_reg(hw, HERMES_CONTROL) ==
222 HERMES_AUX_ENABLED)
223 return 0;
224 }
225
226 return -EBUSY;
227}
228
229 95
230#define CS_CHECK(fn, ret) \ 96#define CS_CHECK(fn, ret) \
231 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) 97 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
@@ -294,144 +160,6 @@ spectrum_reset(struct pcmcia_device *link, int idle)
294 160
295 161
296/* 162/*
297 * Scan PDR for the record with the specified RECORD_ID.
298 * If it's not found, return NULL.
299 */
300static struct pdr *
301spectrum_find_pdr(struct pdr *first_pdr, u32 record_id)
302{
303 struct pdr *pdr = first_pdr;
304
305 while (pdr_id(pdr) != PDI_END) {
306 /*
307 * PDR area is currently not terminated by PDI_END.
308 * It's followed by CRC records, which have the type
309 * field where PDR has length. The type can be 0 or 1.
310 */
311 if (pdr_len(pdr) < 2)
312 return NULL;
313
314 /* If the record ID matches, we are done */
315 if (pdr_id(pdr) == record_id)
316 return pdr;
317
318 pdr = (struct pdr *) pdr->next;
319 }
320 return NULL;
321}
322
323
324/* Process one Plug Data Item - find corresponding PDR and plug it */
325static int
326spectrum_plug_pdi(hermes_t *hw, struct pdr *first_pdr, struct pdi *pdi)
327{
328 struct pdr *pdr;
329
330 /* Find the PDI corresponding to this PDR */
331 pdr = spectrum_find_pdr(first_pdr, pdi_id(pdi));
332
333 /* No match is found, safe to ignore */
334 if (!pdr)
335 return 0;
336
337 /* Lengths of the data in PDI and PDR must match */
338 if (pdi_len(pdi) != pdr_len(pdr))
339 return -EINVAL;
340
341 /* do the actual plugging */
342 spectrum_aux_setaddr(hw, pdr_addr(pdr));
343 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
344
345 return 0;
346}
347
348
349/* Read PDA from the adapter */
350static int
351spectrum_read_pda(hermes_t *hw, __le16 *pda, int pda_len)
352{
353 int ret;
354 int pda_size;
355
356 /* Issue command to read EEPROM */
357 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
358 if (ret)
359 return ret;
360
361 /* Open auxiliary port */
362 ret = spectrum_aux_open(hw);
363 if (ret)
364 return ret;
365
366 /* read PDA from EEPROM */
367 spectrum_aux_setaddr(hw, PDA_ADDR);
368 hermes_read_words(hw, HERMES_AUXDATA, pda, pda_len / 2);
369
370 /* Check PDA length */
371 pda_size = le16_to_cpu(pda[0]);
372 if (pda_size > pda_len)
373 return -EINVAL;
374
375 return 0;
376}
377
378
379/* Parse PDA and write the records into the adapter */
380static int
381spectrum_apply_pda(hermes_t *hw, const struct dblock *first_block,
382 __le16 *pda)
383{
384 int ret;
385 struct pdi *pdi;
386 struct pdr *first_pdr;
387 const struct dblock *blk = first_block;
388
389 /* Skip all blocks to locate Plug Data References */
390 while (dblock_addr(blk) != BLOCK_END)
391 blk = (struct dblock *) &blk->data[dblock_len(blk)];
392
393 first_pdr = (struct pdr *) blk;
394
395 /* Go through every PDI and plug them into the adapter */
396 pdi = (struct pdi *) (pda + 2);
397 while (pdi_id(pdi) != PDI_END) {
398 ret = spectrum_plug_pdi(hw, first_pdr, pdi);
399 if (ret)
400 return ret;
401
402 /* Increment to the next PDI */
403 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
404 }
405 return 0;
406}
407
408
409/* Load firmware blocks into the adapter */
410static int
411spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
412{
413 const struct dblock *blk;
414 u32 blkaddr;
415 u32 blklen;
416
417 blk = first_block;
418 blkaddr = dblock_addr(blk);
419 blklen = dblock_len(blk);
420
421 while (dblock_addr(blk) != BLOCK_END) {
422 spectrum_aux_setaddr(hw, blkaddr);
423 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
424 blklen);
425
426 blk = (struct dblock *) &blk->data[blklen];
427 blkaddr = dblock_addr(blk);
428 blklen = dblock_len(blk);
429 }
430 return 0;
431}
432
433
434/*
435 * Process a firmware image - stop the card, load the firmware, reset 163 * Process a firmware image - stop the card, load the firmware, reset
436 * the card and make sure it responds. For the secondary firmware take 164 * the card and make sure it responds. For the secondary firmware take
437 * care of the PDA - read it and then write it on top of the firmware. 165 * care of the PDA - read it and then write it on top of the firmware.