Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
[pandora-kernel.git] / 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 /*
75  * PDA == Production Data Area
76  *
77  * In principle, the max. size of the PDA is is 4096 words. Currently,
78  * however, only about 500 bytes of this area are used.
79  *
80  * Some USB implementations can't handle sizes in excess of 1016. Note
81  * that PDA is not actually used in those USB environments, but may be
82  * retrieved by common code.
83  */
84 #define MAX_PDA_SIZE    1000
85
86 /* Limit the amout we try to download in a single shot.
87  * Size is in bytes.
88  */
89 #define MAX_DL_SIZE 1024
90 #define LIMIT_PROGRAM_SIZE 0
91
92 /*
93  * The following structures have little-endian fields denoted by
94  * the leading underscore.  Don't access them directly - use inline
95  * functions defined below.
96  */
97
98 /*
99  * The binary image to be downloaded consists of series of data blocks.
100  * Each block has the following structure.
101  */
102 struct dblock {
103         __le32 addr;            /* adapter address where to write the block */
104         __le16 len;             /* length of the data only, in bytes */
105         char data[0];           /* data to be written */
106 } __attribute__ ((packed));
107
108 /*
109  * Plug Data References are located in in the image after the last data
110  * block.  They refer to areas in the adapter memory where the plug data
111  * items with matching ID should be written.
112  */
113 struct pdr {
114         __le32 id;              /* record ID */
115         __le32 addr;            /* adapter address where to write the data */
116         __le32 len;             /* expected length of the data, in bytes */
117         char next[0];           /* next PDR starts here */
118 } __attribute__ ((packed));
119
120 /*
121  * Plug Data Items are located in the EEPROM read from the adapter by
122  * primary firmware.  They refer to the device-specific data that should
123  * be plugged into the secondary firmware.
124  */
125 struct pdi {
126         __le16 len;             /* length of ID and data, in words */
127         __le16 id;              /* record ID */
128         char data[0];           /* plug data */
129 } __attribute__ ((packed));
130
131 /*** FW data block access functions ***/
132
133 static inline u32
134 dblock_addr(const struct dblock *blk)
135 {
136         return le32_to_cpu(blk->addr);
137 }
138
139 static inline u32
140 dblock_len(const struct dblock *blk)
141 {
142         return le16_to_cpu(blk->len);
143 }
144
145 /*** PDR Access functions ***/
146
147 static inline u32
148 pdr_id(const struct pdr *pdr)
149 {
150         return le32_to_cpu(pdr->id);
151 }
152
153 static inline u32
154 pdr_addr(const struct pdr *pdr)
155 {
156         return le32_to_cpu(pdr->addr);
157 }
158
159 static inline u32
160 pdr_len(const struct pdr *pdr)
161 {
162         return le32_to_cpu(pdr->len);
163 }
164
165 /*** PDI Access functions ***/
166
167 static inline u32
168 pdi_id(const struct pdi *pdi)
169 {
170         return le16_to_cpu(pdi->id);
171 }
172
173 /* Return length of the data only, in bytes */
174 static inline u32
175 pdi_len(const struct pdi *pdi)
176 {
177         return 2 * (le16_to_cpu(pdi->len) - 1);
178 }
179
180 /*** Hermes AUX control ***/
181
182 static inline void
183 hermes_aux_setaddr(hermes_t *hw, u32 addr)
184 {
185         hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
186         hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
187 }
188
189 static inline int
190 hermes_aux_control(hermes_t *hw, int enabled)
191 {
192         int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
193         int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
194         int i;
195
196         /* Already open? */
197         if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
198                 return 0;
199
200         hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
201         hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
202         hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
203         hermes_write_reg(hw, HERMES_CONTROL, action);
204
205         for (i = 0; i < 20; i++) {
206                 udelay(10);
207                 if (hermes_read_reg(hw, HERMES_CONTROL) ==
208                     desired_state)
209                         return 0;
210         }
211
212         return -EBUSY;
213 }
214
215 /*** Plug Data Functions ***/
216
217 /*
218  * Scan PDR for the record with the specified RECORD_ID.
219  * If it's not found, return NULL.
220  */
221 static struct pdr *
222 hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
223 {
224         struct pdr *pdr = first_pdr;
225         void *end = (void *)first_pdr + MAX_PDA_SIZE;
226
227         while (((void *)pdr < end) &&
228                (pdr_id(pdr) != PDI_END)) {
229                 /*
230                  * PDR area is currently not terminated by PDI_END.
231                  * It's followed by CRC records, which have the type
232                  * field where PDR has length.  The type can be 0 or 1.
233                  */
234                 if (pdr_len(pdr) < 2)
235                         return NULL;
236
237                 /* If the record ID matches, we are done */
238                 if (pdr_id(pdr) == record_id)
239                         return pdr;
240
241                 pdr = (struct pdr *) pdr->next;
242         }
243         return NULL;
244 }
245
246 /* Scan production data items for a particular entry */
247 static struct pdi *
248 hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
249 {
250         struct pdi *pdi = first_pdi;
251
252         while (pdi_id(pdi) != PDI_END) {
253
254                 /* If the record ID matches, we are done */
255                 if (pdi_id(pdi) == record_id)
256                         return pdi;
257
258                 pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
259         }
260         return NULL;
261 }
262
263 /* Process one Plug Data Item - find corresponding PDR and plug it */
264 static int
265 hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
266 {
267         struct pdr *pdr;
268
269         /* Find the PDR corresponding to this PDI */
270         pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
271
272         /* No match is found, safe to ignore */
273         if (!pdr)
274                 return 0;
275
276         /* Lengths of the data in PDI and PDR must match */
277         if (pdi_len(pdi) != pdr_len(pdr))
278                 return -EINVAL;
279
280         /* do the actual plugging */
281         hermes_aux_setaddr(hw, pdr_addr(pdr));
282         hermes_write_bytes(hw, HERMES_AUXDATA, pdi->data, pdi_len(pdi));
283
284         return 0;
285 }
286
287 /* Read PDA from the adapter */
288 int hermes_read_pda(hermes_t *hw,
289                     __le16 *pda,
290                     u32 pda_addr,
291                     u16 pda_len,
292                     int use_eeprom) /* can we get this into hw? */
293 {
294         int ret;
295         u16 pda_size;
296         u16 data_len = pda_len;
297         __le16 *data = pda;
298
299         if (use_eeprom) {
300                 /* PDA of spectrum symbol is in eeprom */
301
302                 /* Issue command to read EEPROM */
303                 ret = hermes_docmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
304                 if (ret)
305                         return ret;
306         } else {
307                 /* wl_lkm does not include PDA size in the PDA area.
308                  * We will pad the information into pda, so other routines
309                  * don't have to be modified */
310                 pda[0] = cpu_to_le16(pda_len - 2);
311                         /* Includes CFG_PROD_DATA but not itself */
312                 pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
313                 data_len = pda_len - 4;
314                 data = pda + 2;
315         }
316
317         /* Open auxiliary port */
318         ret = hermes_aux_control(hw, 1);
319         printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
320         if (ret)
321                 return ret;
322
323         /* read PDA from EEPROM */
324         hermes_aux_setaddr(hw, pda_addr);
325         hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
326
327         /* Close aux port */
328         ret = hermes_aux_control(hw, 0);
329         printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
330
331         /* Check PDA length */
332         pda_size = le16_to_cpu(pda[0]);
333         printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
334                pda_size, pda_len);
335         if (pda_size > pda_len)
336                 return -EINVAL;
337
338         return 0;
339 }
340
341 /* Parse PDA and write the records into the adapter
342  *
343  * Attempt to write every records that is in the specified pda
344  * which also has a valid production data record for the firmware.
345  */
346 int hermes_apply_pda(hermes_t *hw,
347                      const char *first_pdr,
348                      const __le16 *pda)
349 {
350         int ret;
351         const struct pdi *pdi;
352         struct pdr *pdr;
353
354         pdr = (struct pdr *) first_pdr;
355
356         /* Go through every PDI and plug them into the adapter */
357         pdi = (const struct pdi *) (pda + 2);
358         while (pdi_id(pdi) != PDI_END) {
359                 ret = hermes_plug_pdi(hw, pdr, pdi);
360                 if (ret)
361                         return ret;
362
363                 /* Increment to the next PDI */
364                 pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
365         }
366         return 0;
367 }
368
369 /* Identify the total number of bytes in all blocks
370  * including the header data.
371  */
372 size_t
373 hermes_blocks_length(const char *first_block)
374 {
375         const struct dblock *blk = (const struct dblock *) first_block;
376         int total_len = 0;
377         int len;
378
379         /* Skip all blocks to locate Plug Data References
380          * (Spectrum CS) */
381         while (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 char *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 ((const char *) 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                (((const char *) 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 ((const char *) 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 __le16 *pda)
620 {
621         const struct pdr *pdr = (const struct pdr *) first_pdr;
622         struct pdi *first_pdi = (struct pdi *) &pda[2];
623         struct pdi *pdi;
624         struct pdi *default_pdi = NULL;
625         struct pdi *outdoor_pdi;
626         void *end = (void *)first_pdr + MAX_PDA_SIZE;
627         int record_id;
628
629         while (((void *)pdr < end) &&
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
641                 pdi = hermes_find_pdi(first_pdi, record_id);
642                 if (pdi)
643                         printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
644                                record_id, pdi);
645
646                 switch (record_id) {
647                 case 0x110: /* Modem REFDAC values */
648                 case 0x120: /* Modem VGDAC values */
649                         outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
650                         default_pdi = NULL;
651                         if (outdoor_pdi) {
652                                 pdi = outdoor_pdi;
653                                 printk(KERN_DEBUG PFX
654                                        "Using outdoor record 0x%04x at %p\n",
655                                        record_id + 1, pdi);
656                         }
657                         break;
658                 case 0x5: /*  HWIF Compatiblity */
659                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
660                         break;
661                 case 0x108: /* PPPPSign */
662                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
663                         break;
664                 case 0x109: /* PPPPProf */
665                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
666                         break;
667                 case 0x150: /* Antenna diversity */
668                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
669                         break;
670                 case 0x160: /* Modem VCO band Set-up */
671                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
672                         break;
673                 case 0x161: /* Modem Rx Gain Table Values */
674                         default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
675                         break;
676                 default:
677                         default_pdi = NULL;
678                         break;
679                 }
680                 if (!pdi && default_pdi) {
681                         /* Use default */
682                         pdi = default_pdi;
683                         printk(KERN_DEBUG PFX
684                                "Using default record 0x%04x at %p\n",
685                                record_id, pdi);
686                 }
687
688                 if (pdi) {
689                         /* Lengths of the data in PDI and PDR must match */
690                         if (pdi_len(pdi) == pdr_len(pdr)) {
691                                 /* do the actual plugging */
692                                 hermes_aux_setaddr(hw, pdr_addr(pdr));
693                                 hermes_write_bytes(hw, HERMES_AUXDATA,
694                                                    pdi->data, pdi_len(pdi));
695                         }
696                 }
697
698                 pdr++;
699         }
700         return 0;
701 }