orinoco_usb: avoid in_atomic
[linux-2.6-block.git] / drivers / net / wireless / orinoco / hermes_dld.c
CommitLineData
f482eb79 1/*
f90d8d47 2 * Hermes download helper.
f482eb79 3 *
f90d8d47 4 * This helper:
f482eb79
DK
5 * - is capable of writing to the volatile area of the hermes device
6 * - is currently not capable of writing to non-volatile areas
7 * - provide helpers to identify and update plugin data
8 * - is not capable of interpreting a fw image directly. That is up to
9 * the main card driver.
10 * - deals with Hermes I devices. It can probably be modified to deal
11 * with Hermes II devices
12 *
13 * Copyright (C) 2007, David Kilroy
14 *
15 * Plug data code slightly modified from spectrum_cs driver
16 * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
17 * Portions based on information in wl_lkm_718 Agere driver
18 * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
19 *
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License
23 * at http://www.mozilla.org/MPL/
24 *
25 * Software distributed under the License is distributed on an "AS IS"
26 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
27 * the License for the specific language governing rights and
28 * limitations under the License.
29 *
30 * Alternatively, the contents of this file may be used under the
31 * terms of the GNU General Public License version 2 (the "GPL"), in
32 * which case the provisions of the GPL are applicable instead of the
33 * above. If you wish to allow the use of your version of this file
34 * only under the terms of the GPL and not to allow others to use your
35 * version of this file under the MPL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and
37 * other provisions required by the GPL. If you do not delete the
38 * provisions above, a recipient may use your version of this file
39 * under either the MPL or the GPL.
40 */
41
42#include <linux/module.h>
43#include <linux/delay.h>
44#include "hermes.h"
45#include "hermes_dld.h"
46
f482eb79
DK
47#define PFX "hermes_dld: "
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 */
e2334180 57#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
f482eb79
DK
58
59#define HERMES_AUX_PW0 0xFE01
60#define HERMES_AUX_PW1 0xDC23
61#define HERMES_AUX_PW2 0xBA45
62
8f5ae73c
DK
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
e2334180 69/* End markers used in dblocks */
f482eb79
DK
70#define PDI_END 0x00000000 /* End of PDA */
71#define BLOCK_END 0xFFFFFFFF /* Last image block */
e2334180
DK
72#define TEXT_END 0x1A /* End of text header */
73
e2334180
DK
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
f482eb79
DK
79
80/*
81 * The following structures have little-endian fields denoted by
82 * the leading underscore. Don't access them directly - use inline
83 * functions defined below.
84 */
85
86/*
87 * The binary image to be downloaded consists of series of data blocks.
88 * Each block has the following structure.
89 */
90struct dblock {
91 __le32 addr; /* adapter address where to write the block */
92 __le16 len; /* length of the data only, in bytes */
93 char data[0]; /* data to be written */
94} __attribute__ ((packed));
95
96/*
97 * Plug Data References are located in in the image after the last data
98 * block. They refer to areas in the adapter memory where the plug data
99 * items with matching ID should be written.
100 */
101struct pdr {
102 __le32 id; /* record ID */
103 __le32 addr; /* adapter address where to write the data */
104 __le32 len; /* expected length of the data, in bytes */
105 char next[0]; /* next PDR starts here */
106} __attribute__ ((packed));
107
108/*
109 * Plug Data Items are located in the EEPROM read from the adapter by
110 * primary firmware. They refer to the device-specific data that should
111 * be plugged into the secondary firmware.
112 */
113struct pdi {
114 __le16 len; /* length of ID and data, in words */
115 __le16 id; /* record ID */
116 char data[0]; /* plug data */
117} __attribute__ ((packed));
118
e2334180
DK
119/*** FW data block access functions ***/
120
f482eb79
DK
121static inline u32
122dblock_addr(const struct dblock *blk)
123{
124 return le32_to_cpu(blk->addr);
125}
126
127static inline u32
128dblock_len(const struct dblock *blk)
129{
130 return le16_to_cpu(blk->len);
131}
132
e2334180
DK
133/*** PDR Access functions ***/
134
f482eb79
DK
135static inline u32
136pdr_id(const struct pdr *pdr)
137{
138 return le32_to_cpu(pdr->id);
139}
140
141static inline u32
142pdr_addr(const struct pdr *pdr)
143{
144 return le32_to_cpu(pdr->addr);
145}
146
147static inline u32
148pdr_len(const struct pdr *pdr)
149{
150 return le32_to_cpu(pdr->len);
151}
152
e2334180
DK
153/*** PDI Access functions ***/
154
f482eb79
DK
155static inline u32
156pdi_id(const struct pdi *pdi)
157{
158 return le16_to_cpu(pdi->id);
159}
160
161/* Return length of the data only, in bytes */
162static inline u32
163pdi_len(const struct pdi *pdi)
164{
165 return 2 * (le16_to_cpu(pdi->len) - 1);
166}
167
e2334180
DK
168/*** Hermes AUX control ***/
169
f482eb79 170static inline void
e2334180 171hermes_aux_setaddr(hermes_t *hw, u32 addr)
f482eb79
DK
172{
173 hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
174 hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
175}
176
e2334180
DK
177static inline int
178hermes_aux_control(hermes_t *hw, int enabled)
f482eb79 179{
e2334180
DK
180 int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
181 int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
f482eb79
DK
182 int i;
183
184 /* Already open? */
e2334180 185 if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
f482eb79
DK
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);
e2334180 191 hermes_write_reg(hw, HERMES_CONTROL, action);
f482eb79
DK
192
193 for (i = 0; i < 20; i++) {
194 udelay(10);
195 if (hermes_read_reg(hw, HERMES_CONTROL) ==
e2334180 196 desired_state)
f482eb79
DK
197 return 0;
198 }
199
200 return -EBUSY;
201}
202
e2334180
DK
203/*** Plug Data Functions ***/
204
f482eb79
DK
205/*
206 * Scan PDR for the record with the specified RECORD_ID.
207 * If it's not found, return NULL.
208 */
3faa19cd
DK
209static const struct pdr *
210hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
f482eb79 211{
3faa19cd 212 const struct pdr *pdr = first_pdr;
f482eb79 213
3faa19cd
DK
214 end -= sizeof(struct pdr);
215
216 while (((void *) pdr <= end) &&
e2334180 217 (pdr_id(pdr) != PDI_END)) {
f482eb79
DK
218 /*
219 * PDR area is currently not terminated by PDI_END.
220 * It's followed by CRC records, which have the type
221 * field where PDR has length. The type can be 0 or 1.
222 */
223 if (pdr_len(pdr) < 2)
224 return NULL;
225
226 /* If the record ID matches, we are done */
227 if (pdr_id(pdr) == record_id)
228 return pdr;
229
230 pdr = (struct pdr *) pdr->next;
231 }
232 return NULL;
233}
234
8f5ae73c 235/* Scan production data items for a particular entry */
3faa19cd
DK
236static const struct pdi *
237hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
8f5ae73c 238{
3faa19cd
DK
239 const struct pdi *pdi = first_pdi;
240
241 end -= sizeof(struct pdi);
8f5ae73c 242
3faa19cd
DK
243 while (((void *) pdi <= end) &&
244 (pdi_id(pdi) != PDI_END)) {
8f5ae73c
DK
245
246 /* If the record ID matches, we are done */
247 if (pdi_id(pdi) == record_id)
248 return pdi;
249
250 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
251 }
252 return NULL;
253}
254
f482eb79
DK
255/* Process one Plug Data Item - find corresponding PDR and plug it */
256static int
3faa19cd
DK
257hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
258 const struct pdi *pdi, const void *pdr_end)
f482eb79 259{
3faa19cd 260 const struct pdr *pdr;
f482eb79 261
e2334180 262 /* Find the PDR corresponding to this PDI */
3faa19cd 263 pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
f482eb79
DK
264
265 /* No match is found, safe to ignore */
266 if (!pdr)
267 return 0;
268
269 /* Lengths of the data in PDI and PDR must match */
270 if (pdi_len(pdi) != pdr_len(pdr))
271 return -EINVAL;
272
273 /* do the actual plugging */
e2334180 274 hermes_aux_setaddr(hw, pdr_addr(pdr));
f482eb79
DK
275 hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
276
277 return 0;
278}
279
280/* Read PDA from the adapter */
e2334180
DK
281int 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? */
f482eb79
DK
286{
287 int ret;
e2334180
DK
288 u16 pda_size;
289 u16 data_len = pda_len;
290 __le16 *data = pda;
f482eb79 291
e2334180
DK
292 if (use_eeprom) {
293 /* PDA of spectrum symbol is in eeprom */
294
295 /* Issue command to read EEPROM */
b42f2074 296 ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
e2334180
DK
297 if (ret)
298 return ret;
8f5ae73c
DK
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;
e2334180 308 }
f482eb79
DK
309
310 /* Open auxiliary port */
e2334180 311 ret = hermes_aux_control(hw, 1);
35832c50 312 pr_debug(PFX "AUX enable returned %d\n", ret);
f482eb79
DK
313 if (ret)
314 return ret;
315
316 /* read PDA from EEPROM */
e2334180
DK
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);
35832c50 322 pr_debug(PFX "AUX disable returned %d\n", ret);
f482eb79
DK
323
324 /* Check PDA length */
325 pda_size = le16_to_cpu(pda[0]);
35832c50
DK
326 pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
327 pda_size, pda_len);
f482eb79
DK
328 if (pda_size > pda_len)
329 return -EINVAL;
330
331 return 0;
332}
f482eb79 333
e2334180
DK
334/* Parse PDA and write the records into the adapter
335 *
336 * Attempt to write every records that is in the specified pda
337 * which also has a valid production data record for the firmware.
338 */
339int hermes_apply_pda(hermes_t *hw,
340 const char *first_pdr,
3faa19cd
DK
341 const void *pdr_end,
342 const __le16 *pda,
343 const void *pda_end)
f482eb79
DK
344{
345 int ret;
e2334180 346 const struct pdi *pdi;
3faa19cd 347 const struct pdr *pdr;
f482eb79 348
3faa19cd
DK
349 pdr = (const struct pdr *) first_pdr;
350 pda_end -= sizeof(struct pdi);
f482eb79
DK
351
352 /* Go through every PDI and plug them into the adapter */
e2334180 353 pdi = (const struct pdi *) (pda + 2);
3faa19cd
DK
354 while (((void *) pdi <= pda_end) &&
355 (pdi_id(pdi) != PDI_END)) {
356 ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
f482eb79
DK
357 if (ret)
358 return ret;
359
360 /* Increment to the next PDI */
e2334180 361 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
f482eb79
DK
362 }
363 return 0;
364}
e2334180
DK
365
366/* Identify the total number of bytes in all blocks
367 * including the header data.
368 */
369size_t
3faa19cd 370hermes_blocks_length(const char *first_block, const void *end)
e2334180
DK
371{
372 const struct dblock *blk = (const struct dblock *) first_block;
373 int total_len = 0;
374 int len;
375
3faa19cd
DK
376 end -= sizeof(*blk);
377
e2334180
DK
378 /* Skip all blocks to locate Plug Data References
379 * (Spectrum CS) */
3faa19cd
DK
380 while (((void *) blk <= end) &&
381 (dblock_addr(blk) != BLOCK_END)) {
e2334180
DK
382 len = dblock_len(blk);
383 total_len += sizeof(*blk) + len;
384 blk = (struct dblock *) &blk->data[len];
385 }
386
387 return total_len;
388}
e2334180
DK
389
390/*** Hermes programming ***/
f482eb79 391
8f5ae73c
DK
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 */
399int 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
b42f2074
DK
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);
8f5ae73c
DK
415 if (err)
416 return err;
417
b42f2074
DK
418 err = hw->ops->init_cmd_wait(hw,
419 0x0000 | HERMES_CMD_INIT,
420 0, 0, 0, NULL);
8f5ae73c
DK
421 if (err)
422 return err;
423
424 err = hermes_aux_control(hw, 1);
35832c50 425 pr_debug(PFX "AUX enable returned %d\n", err);
8f5ae73c
DK
426
427 if (err)
428 return err;
429
a589296a 430 pr_debug(PFX "Enabling volatile, EP 0x%08x\n", offset);
b42f2074
DK
431 err = hw->ops->init_cmd_wait(hw,
432 HERMES_PROGRAM_ENABLE_VOLATILE,
433 offset & 0xFFFFu,
434 offset >> 16,
435 0,
436 NULL);
35832c50 437 pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
8f5ae73c
DK
438
439 return err;
440}
8f5ae73c
DK
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 */
448int hermesi_program_end(hermes_t *hw)
449{
450 struct hermes_response resp;
451 int rc = 0;
452 int err;
453
b42f2074 454 rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
8f5ae73c 455
35832c50
DK
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);
8f5ae73c
DK
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);
35832c50 465 pr_debug(PFX "AUX disable returned %d\n", err);
8f5ae73c
DK
466
467 /* Acknowledge any outstanding command */
468 hermes_write_regn(hw, EVACK, 0xFFFF);
469
470 /* Reinitialise, ignoring return */
b42f2074
DK
471 (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
472 0, 0, 0, NULL);
8f5ae73c
DK
473
474 return rc ? rc : err;
475}
8f5ae73c 476
e2334180 477/* Program the data blocks */
3faa19cd 478int hermes_program(hermes_t *hw, const char *first_block, const void *end)
f482eb79
DK
479{
480 const struct dblock *blk;
481 u32 blkaddr;
482 u32 blklen;
e2334180
DK
483#if LIMIT_PROGRAM_SIZE
484 u32 addr;
485 u32 len;
486#endif
487
488 blk = (const struct dblock *) first_block;
489
3faa19cd 490 if ((void *) blk > (end - sizeof(*blk)))
e2334180 491 return -EIO;
f482eb79 492
f482eb79
DK
493 blkaddr = dblock_addr(blk);
494 blklen = dblock_len(blk);
495
e2334180 496 while ((blkaddr != BLOCK_END) &&
3faa19cd 497 (((void *) blk + blklen) <= end)) {
35832c50
DK
498 pr_debug(PFX "Programming block of length %d "
499 "to address 0x%08x\n", blklen, blkaddr);
e2334180
DK
500
501#if !LIMIT_PROGRAM_SIZE
502 /* wl_lkm driver splits this into writes of 2000 bytes */
503 hermes_aux_setaddr(hw, blkaddr);
f482eb79
DK
504 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
505 blklen);
e2334180
DK
506#else
507 len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
508 addr = blkaddr;
509
510 while (addr < (blkaddr + blklen)) {
35832c50
DK
511 pr_debug(PFX "Programming subblock of length %d "
512 "to address 0x%08x. Data @ %p\n",
513 len, addr, &blk->data[addr - blkaddr]);
e2334180
DK
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];
526
3faa19cd 527 if ((void *) blk > (end - sizeof(*blk)))
e2334180 528 return -EIO;
f482eb79 529
f482eb79
DK
530 blkaddr = dblock_addr(blk);
531 blklen = dblock_len(blk);
532 }
533 return 0;
534}
8f5ae73c
DK
535
536/*** Default plugging data for Hermes I ***/
537/* Values from wl_lkm_718/hcf/dhf.c */
538
539#define DEFINE_DEFAULT_PDR(pid, length, data) \
540static const struct { \
541 __le16 len; \
542 __le16 id; \
543 u8 val[length]; \
544} __attribute__ ((packed)) default_pdr_data_##pid = { \
3faa19cd 545 cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
8f5ae73c 546 sizeof(__le16)) - 1), \
3faa19cd 547 cpu_to_le16(pid), \
8f5ae73c
DK
548 data \
549}
550
551#define DEFAULT_PDR(pid) default_pdr_data_##pid
552
06fe9fb4 553/* HWIF Compatibility */
8f5ae73c
DK
554DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
555
556/* PPPPSign */
557DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
558
559/* PPPPProf */
560DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
561
562/* Antenna diversity */
563DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
564
565/* Modem VCO band Set-up */
566DEFINE_DEFAULT_PDR(0x0160, 28,
567 "\x00\x00\x00\x00\x00\x00\x00\x00"
568 "\x00\x00\x00\x00\x00\x00\x00\x00"
569 "\x00\x00\x00\x00\x00\x00\x00\x00"
570 "\x00\x00\x00\x00");
571
572/* Modem Rx Gain Table Values */
573DEFINE_DEFAULT_PDR(0x0161, 256,
574 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
575 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
576 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
577 "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
578 "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
579 "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
580 "\x3B\x01\x3A\01\x3A\x01\x39\x01"
581 "\x39\x01\x38\01\x38\x01\x37\x01"
582 "\x37\x01\x36\01\x36\x01\x35\x01"
583 "\x35\x01\x34\01\x34\x01\x33\x01"
584 "\x33\x01\x32\x01\x32\x01\x31\x01"
585 "\x31\x01\x30\x01\x30\x01\x7B\x01"
586 "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
587 "\x79\x01\x78\x01\x78\x01\x77\x01"
588 "\x77\x01\x76\x01\x76\x01\x75\x01"
589 "\x75\x01\x74\x01\x74\x01\x73\x01"
590 "\x73\x01\x72\x01\x72\x01\x71\x01"
591 "\x71\x01\x70\x01\x70\x01\x68\x01"
592 "\x68\x01\x67\x01\x67\x01\x66\x01"
593 "\x66\x01\x65\x01\x65\x01\x57\x01"
594 "\x57\x01\x56\x01\x56\x01\x55\x01"
595 "\x55\x01\x54\x01\x54\x01\x53\x01"
596 "\x53\x01\x52\x01\x52\x01\x51\x01"
597 "\x51\x01\x50\x01\x50\x01\x48\x01"
598 "\x48\x01\x47\x01\x47\x01\x46\x01"
599 "\x46\x01\x45\x01\x45\x01\x44\x01"
600 "\x44\x01\x43\x01\x43\x01\x42\x01"
601 "\x42\x01\x41\x01\x41\x01\x40\x01"
602 "\x40\x01\x40\x01\x40\x01\x40\x01"
603 "\x40\x01\x40\x01\x40\x01\x40\x01"
604 "\x40\x01\x40\x01\x40\x01\x40\x01"
605 "\x40\x01\x40\x01\x40\x01\x40\x01");
606
607/* Write PDA according to certain rules.
608 *
609 * For every production data record, look for a previous setting in
610 * the pda, and use that.
611 *
612 * For certain records, use defaults if they are not found in pda.
613 */
614int hermes_apply_pda_with_defaults(hermes_t *hw,
615 const char *first_pdr,
3faa19cd
DK
616 const void *pdr_end,
617 const __le16 *pda,
618 const void *pda_end)
8f5ae73c
DK
619{
620 const struct pdr *pdr = (const struct pdr *) first_pdr;
3faa19cd
DK
621 const struct pdi *first_pdi = (const struct pdi *) &pda[2];
622 const struct pdi *pdi;
623 const struct pdi *default_pdi = NULL;
624 const struct pdi *outdoor_pdi;
8f5ae73c
DK
625 int record_id;
626
3faa19cd
DK
627 pdr_end -= sizeof(struct pdr);
628
629 while (((void *) pdr <= pdr_end) &&
8f5ae73c
DK
630 (pdr_id(pdr) != PDI_END)) {
631 /*
632 * For spectrum_cs firmwares,
633 * PDR area is currently not terminated by PDI_END.
634 * It's followed by CRC records, which have the type
635 * field where PDR has length. The type can be 0 or 1.
636 */
637 if (pdr_len(pdr) < 2)
638 break;
639 record_id = pdr_id(pdr);
640
3faa19cd 641 pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
8f5ae73c 642 if (pdi)
35832c50
DK
643 pr_debug(PFX "Found record 0x%04x at %p\n",
644 record_id, pdi);
8f5ae73c
DK
645
646 switch (record_id) {
647 case 0x110: /* Modem REFDAC values */
648 case 0x120: /* Modem VGDAC values */
3faa19cd
DK
649 outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
650 pda_end);
8f5ae73c
DK
651 default_pdi = NULL;
652 if (outdoor_pdi) {
653 pdi = outdoor_pdi;
35832c50
DK
654 pr_debug(PFX
655 "Using outdoor record 0x%04x at %p\n",
656 record_id + 1, pdi);
8f5ae73c
DK
657 }
658 break;
06fe9fb4 659 case 0x5: /* HWIF Compatibility */
8f5ae73c
DK
660 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
661 break;
662 case 0x108: /* PPPPSign */
663 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
664 break;
665 case 0x109: /* PPPPProf */
666 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
667 break;
668 case 0x150: /* Antenna diversity */
669 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
670 break;
671 case 0x160: /* Modem VCO band Set-up */
672 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
673 break;
674 case 0x161: /* Modem Rx Gain Table Values */
675 default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
676 break;
677 default:
678 default_pdi = NULL;
679 break;
680 }
681 if (!pdi && default_pdi) {
682 /* Use default */
683 pdi = default_pdi;
35832c50
DK
684 pr_debug(PFX "Using default record 0x%04x at %p\n",
685 record_id, pdi);
8f5ae73c
DK
686 }
687
688 if (pdi) {
689 /* Lengths of the data in PDI and PDR must match */
3faa19cd
DK
690 if ((pdi_len(pdi) == pdr_len(pdr)) &&
691 ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
8f5ae73c
DK
692 /* do the actual plugging */
693 hermes_aux_setaddr(hw, pdr_addr(pdr));
694 hermes_write_bytes(hw, HERMES_AUXDATA,
695 pdi->data, pdi_len(pdi));
696 }
697 }
698
699 pdr++;
700 }
701 return 0;
702}