Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[linux-2.6] / drivers / net / wireless / orinoco / hermes_dld.c
1 /*
2  * Hermes download helper.
3  *
4  * This helper:
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
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 */
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 */
70 #define PDI_END         0x00000000      /* End of PDA */
71 #define BLOCK_END       0xFFFFFFFF      /* Last image block */
72 #define TEXT_END        0x1A            /* End of text header */
73
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 /*
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  */
90 struct 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  */
101 struct 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  */
113 struct 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
119 /*** FW data block access functions ***/
120
121 static inline u32
122 dblock_addr(const struct dblock *blk)
123 {
124         return le32_to_cpu(blk->addr);
125 }
126
127 static inline u32
128 dblock_len(const struct dblock *blk)
129 {
130         return le16_to_cpu(blk->len);
131 }
132
133 /*** PDR Access functions ***/
134
135 static inline u32
136 pdr_id(const struct pdr *pdr)
137 {
138         return le32_to_cpu(pdr->id);
139 }
140
141 static inline u32
142 pdr_addr(const struct pdr *pdr)
143 {
144         return le32_to_cpu(pdr->addr);
145 }
146
147 static inline u32
148 pdr_len(const struct pdr *pdr)
149 {
150         return le32_to_cpu(pdr->len);
151 }
152
153 /*** PDI Access functions ***/
154
155 static inline u32
156 pdi_id(const struct pdi *pdi)
157 {
158         return le16_to_cpu(pdi->id);
159 }
160
161 /* Return length of the data only, in bytes */
162 static inline u32
163 pdi_len(const struct pdi *pdi)
164 {
165         return 2 * (le16_to_cpu(pdi->len) - 1);
166 }
167
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 ***/
204
205 /*
206  * Scan PDR for the record with the specified RECORD_ID.
207  * If it's not found, return NULL.
208  */
209 static const struct pdr *
210 hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
211 {
212         const struct pdr *pdr = first_pdr;
213
214         end -= sizeof(struct pdr);
215
216         while (((void *) pdr <= end) &&
217                (pdr_id(pdr) != PDI_END)) {
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
235 /* Scan production data items for a particular entry */
236 static const struct pdi *
237 hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
238 {
239         const struct pdi *pdi = first_pdi;
240
241         end -= sizeof(struct pdi);
242
243         while (((void *) pdi <= end) &&
244                (pdi_id(pdi) != PDI_END)) {
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
255 /* Process one Plug Data Item - find corresponding PDR and plug it */
256 static int
257 hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
258                 const struct pdi *pdi, const void *pdr_end)
259 {
260         const struct pdr *pdr;
261
262         /* Find the PDR corresponding to this PDI */
263         pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
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 */
274         hermes_aux_setaddr(hw, pdr_addr(pdr));
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 = hermes_docmd_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         printk(KERN_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         printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
323
324         /* Check PDA length */
325         pda_size = le16_to_cpu(pda[0]);
326         printk(KERN_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
331         return 0;
332 }
333
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  */
339 int hermes_apply_pda(hermes_t *hw,
340                      const char *first_pdr,
341                      const void *pdr_end,
342                      const __le16 *pda,
343                      const void *pda_end)
344 {
345         int ret;
346         const struct pdi *pdi;
347         const struct pdr *pdr;
348
349         pdr = (const struct pdr *) first_pdr;
350         pda_end -= sizeof(struct pdi);
351
352         /* Go through every PDI and plug them into the adapter */
353         pdi = (const struct pdi *) (pda + 2);
354         while (((void *) pdi <= pda_end) &&
355                (pdi_id(pdi) != PDI_END)) {
356                 ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
357                 if (ret)
358                         return ret;
359
360                 /* Increment to the next PDI */
361                 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
362         }
363         return 0;
364 }
365
366 /* Identify the total number of bytes in all blocks
367  * including the header data.
368  */
369 size_t
370 hermes_blocks_length(const char *first_block, const void *end)
371 {
372         const struct dblock *blk = (const struct dblock *) first_block;
373         int total_len = 0;
374         int len;
375
376         end -= sizeof(*blk);
377
378         /* Skip all blocks to locate Plug Data References
379          * (Spectrum CS) */
380         while (((void *) blk <= end) &&
381                (dblock_addr(blk) != BLOCK_END)) {
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 }
389
390 /*** Hermes programming ***/
391
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 doicmd_wait rather than docmd_wait */
412         err = hermes_doicmd_wait(hw,
413                                  0x0100 | HERMES_CMD_INIT,
414                                  0, 0, 0, NULL);
415         if (err)
416                 return err;
417
418         err = hermes_doicmd_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         printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
426
427         if (err)
428                 return err;
429
430         printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
431         err = hermes_doicmd_wait(hw,
432                                  HERMES_PROGRAM_ENABLE_VOLATILE,
433                                  offset & 0xFFFFu,
434                                  offset >> 16,
435                                  0,
436                                  NULL);
437         printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
438                err);
439
440         return err;
441 }
442
443 /* Done programming data (Hermes I)
444  *
445  * Spectrum_cs' Symbol fw does not require this
446  * wl_lkm Agere fw does
447  * Don't know about intersil
448  */
449 int hermesi_program_end(hermes_t *hw)
450 {
451         struct hermes_response resp;
452         int rc = 0;
453         int err;
454
455         rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
456
457         printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
458                "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
459                rc, resp.resp0, resp.resp1, resp.resp2);
460
461         if ((rc == 0) &&
462             ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
463                 rc = -EIO;
464
465         err = hermes_aux_control(hw, 0);
466         printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
467
468         /* Acknowledge any outstanding command */
469         hermes_write_regn(hw, EVACK, 0xFFFF);
470
471         /* Reinitialise, ignoring return */
472         (void) hermes_doicmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
473                                   0, 0, 0, NULL);
474
475         return rc ? rc : err;
476 }
477
478 /* Program the data blocks */
479 int hermes_program(hermes_t *hw, const char *first_block, const void *end)
480 {
481         const struct dblock *blk;
482         u32 blkaddr;
483         u32 blklen;
484 #if LIMIT_PROGRAM_SIZE
485         u32 addr;
486         u32 len;
487 #endif
488
489         blk = (const struct dblock *) first_block;
490
491         if ((void *) blk > (end - sizeof(*blk)))
492                 return -EIO;
493
494         blkaddr = dblock_addr(blk);
495         blklen = dblock_len(blk);
496
497         while ((blkaddr != BLOCK_END) &&
498                (((void *) blk + blklen) <= end)) {
499                 printk(KERN_DEBUG PFX
500                        "Programming block of length %d to address 0x%08x\n",
501                        blklen, blkaddr);
502
503 #if !LIMIT_PROGRAM_SIZE
504                 /* wl_lkm driver splits this into writes of 2000 bytes */
505                 hermes_aux_setaddr(hw, blkaddr);
506                 hermes_write_bytes(hw, HERMES_AUXDATA, blk->data,
507                                    blklen);
508 #else
509                 len = (blklen < MAX_DL_SIZE) ? blklen : MAX_DL_SIZE;
510                 addr = blkaddr;
511
512                 while (addr < (blkaddr + blklen)) {
513                         printk(KERN_DEBUG PFX
514                                "Programming subblock of length %d "
515                                "to address 0x%08x. Data @ %p\n",
516                                len, addr, &blk->data[addr - blkaddr]);
517
518                         hermes_aux_setaddr(hw, addr);
519                         hermes_write_bytes(hw, HERMES_AUXDATA,
520                                            &blk->data[addr - blkaddr],
521                                            len);
522
523                         addr += len;
524                         len = ((blkaddr + blklen - addr) < MAX_DL_SIZE) ?
525                                 (blkaddr + blklen - addr) : MAX_DL_SIZE;
526                 }
527 #endif
528                 blk = (const struct dblock *) &blk->data[blklen];
529
530                 if ((void *) blk > (end - sizeof(*blk)))
531                         return -EIO;
532
533                 blkaddr = dblock_addr(blk);
534                 blklen = dblock_len(blk);
535         }
536         return 0;
537 }
538
539 /*** Default plugging data for Hermes I ***/
540 /* Values from wl_lkm_718/hcf/dhf.c */
541
542 #define DEFINE_DEFAULT_PDR(pid, length, data)                           \
543 static const struct {                                                   \
544         __le16 len;                                                     \
545         __le16 id;                                                      \
546         u8 val[length];                                                 \
547 } __attribute__ ((packed)) default_pdr_data_##pid = {                   \
548         cpu_to_le16((sizeof(default_pdr_data_##pid)/                    \
549                                 sizeof(__le16)) - 1),                   \
550         cpu_to_le16(pid),                                               \
551         data                                                            \
552 }
553
554 #define DEFAULT_PDR(pid) default_pdr_data_##pid
555
556 /*  HWIF Compatiblity */
557 DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
558
559 /* PPPPSign */
560 DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
561
562 /* PPPPProf */
563 DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
564
565 /* Antenna diversity */
566 DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
567
568 /* Modem VCO band Set-up */
569 DEFINE_DEFAULT_PDR(0x0160, 28,
570                    "\x00\x00\x00\x00\x00\x00\x00\x00"
571                    "\x00\x00\x00\x00\x00\x00\x00\x00"
572                    "\x00\x00\x00\x00\x00\x00\x00\x00"
573                    "\x00\x00\x00\x00");
574
575 /* Modem Rx Gain Table Values */
576 DEFINE_DEFAULT_PDR(0x0161, 256,
577                    "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
578                    "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
579                    "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
580                    "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
581                    "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
582                    "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
583                    "\x3B\x01\x3A\01\x3A\x01\x39\x01"
584                    "\x39\x01\x38\01\x38\x01\x37\x01"
585                    "\x37\x01\x36\01\x36\x01\x35\x01"
586                    "\x35\x01\x34\01\x34\x01\x33\x01"
587                    "\x33\x01\x32\x01\x32\x01\x31\x01"
588                    "\x31\x01\x30\x01\x30\x01\x7B\x01"
589                    "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
590                    "\x79\x01\x78\x01\x78\x01\x77\x01"
591                    "\x77\x01\x76\x01\x76\x01\x75\x01"
592                    "\x75\x01\x74\x01\x74\x01\x73\x01"
593                    "\x73\x01\x72\x01\x72\x01\x71\x01"
594                    "\x71\x01\x70\x01\x70\x01\x68\x01"
595                    "\x68\x01\x67\x01\x67\x01\x66\x01"
596                    "\x66\x01\x65\x01\x65\x01\x57\x01"
597                    "\x57\x01\x56\x01\x56\x01\x55\x01"
598                    "\x55\x01\x54\x01\x54\x01\x53\x01"
599                    "\x53\x01\x52\x01\x52\x01\x51\x01"
600                    "\x51\x01\x50\x01\x50\x01\x48\x01"
601                    "\x48\x01\x47\x01\x47\x01\x46\x01"
602                    "\x46\x01\x45\x01\x45\x01\x44\x01"
603                    "\x44\x01\x43\x01\x43\x01\x42\x01"
604                    "\x42\x01\x41\x01\x41\x01\x40\x01"
605                    "\x40\x01\x40\x01\x40\x01\x40\x01"
606                    "\x40\x01\x40\x01\x40\x01\x40\x01"
607                    "\x40\x01\x40\x01\x40\x01\x40\x01"
608                    "\x40\x01\x40\x01\x40\x01\x40\x01");
609
610 /* Write PDA according to certain rules.
611  *
612  * For every production data record, look for a previous setting in
613  * the pda, and use that.
614  *
615  * For certain records, use defaults if they are not found in pda.
616  */
617 int hermes_apply_pda_with_defaults(hermes_t *hw,
618                                    const char *first_pdr,
619                                    const void *pdr_end,
620                                    const __le16 *pda,
621                                    const void *pda_end)
622 {
623         const struct pdr *pdr = (const struct pdr *) first_pdr;
624         const struct pdi *first_pdi = (const struct pdi *) &pda[2];
625         const struct pdi *pdi;
626         const struct pdi *default_pdi = NULL;
627         const struct pdi *outdoor_pdi;
628         int record_id;
629
630         pdr_end -= sizeof(struct pdr);
631
632         while (((void *) pdr <= pdr_end) &&
633                (pdr_id(pdr) != PDI_END)) {
634                 /*
635                  * For spectrum_cs firmwares,
636                  * PDR area is currently not terminated by PDI_END.
637                  * It's followed by CRC records, which have the type
638                  * field where PDR has length.  The type can be 0 or 1.
639                  */
640                 if (pdr_len(pdr) < 2)
641                         break;
642                 record_id = pdr_id(pdr);
643
644                 pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
645                 if (pdi)
646                         printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
647                                record_id, pdi);
648
649                 switch (record_id) {
650                 case 0x110: /* Modem REFDAC values */
651                 case 0x120: /* Modem VGDAC values */
652                         outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
653                                                       pda_end);
654                         default_pdi = NULL;
655                         if (outdoor_pdi) {
656                                 pdi = outdoor_pdi;
657                                 printk(KERN_DEBUG PFX
658                                        "Using outdoor record 0x%04x at %p\n",
659                                        record_id + 1, pdi);
660                         }
661                         break;
662                 case 0x5: /*  HWIF Compatiblity */
663                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
664                         break;
665                 case 0x108: /* PPPPSign */
666                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
667                         break;
668                 case 0x109: /* PPPPProf */
669                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
670                         break;
671                 case 0x150: /* Antenna diversity */
672                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
673                         break;
674                 case 0x160: /* Modem VCO band Set-up */
675                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
676                         break;
677                 case 0x161: /* Modem Rx Gain Table Values */
678                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
679                         break;
680                 default:
681                         default_pdi = NULL;
682                         break;
683                 }
684                 if (!pdi && default_pdi) {
685                         /* Use default */
686                         pdi = default_pdi;
687                         printk(KERN_DEBUG PFX
688                                "Using default record 0x%04x at %p\n",
689                                record_id, pdi);
690                 }
691
692                 if (pdi) {
693                         /* Lengths of the data in PDI and PDR must match */
694                         if ((pdi_len(pdi) == pdr_len(pdr)) &&
695                             ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
696                                 /* do the actual plugging */
697                                 hermes_aux_setaddr(hw, pdr_addr(pdr));
698                                 hermes_write_bytes(hw, HERMES_AUXDATA,
699                                                    pdi->data, pdi_len(pdi));
700                         }
701                 }
702
703                 pdr++;
704         }
705         return 0;
706 }