Staging: rt2870: remove dead LEAP_SUPPORT code
[safe/jmp/linux-2.6] / drivers / staging / wlan-ng / prism2fw.c
1 /* from src/prism2/download/prism2dl.c
2 *
3 * utility for downloading prism2 images moved into kernelspace
4 *
5 * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
6 * --------------------------------------------------------------------
7 *
8 * linux-wlan
9 *
10 *   The contents of this file are subject to the Mozilla Public
11 *   License Version 1.1 (the "License"); you may not use this file
12 *   except in compliance with the License. You may obtain a copy of
13 *   the License at http://www.mozilla.org/MPL/
14 *
15 *   Software distributed under the License is distributed on an "AS
16 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 *   implied. See the License for the specific language governing
18 *   rights and limitations under the License.
19 *
20 *   Alternatively, the contents of this file may be used under the
21 *   terms of the GNU Public License version 2 (the "GPL"), in which
22 *   case the provisions of the GPL are applicable instead of the
23 *   above.  If you wish to allow the use of your version of this file
24 *   only under the terms of the GPL and not to allow others to use
25 *   your version of this file under the MPL, indicate your decision
26 *   by deleting the provisions above and replace them with the notice
27 *   and other provisions required by the GPL.  If you do not delete
28 *   the provisions above, a recipient may use your version of this
29 *   file under either the MPL or the GPL.
30 *
31 * --------------------------------------------------------------------
32 *
33 * Inquiries regarding the linux-wlan Open Source project can be
34 * made directly to:
35 *
36 * AbsoluteValue Systems Inc.
37 * info@linux-wlan.com
38 * http://www.linux-wlan.com
39 *
40 * --------------------------------------------------------------------
41 *
42 * Portions of the development of this software were funded by
43 * Intersil Corporation as part of PRISM(R) chipset product development.
44 *
45 * --------------------------------------------------------------------
46 */
47
48 /*================================================================*/
49 /* System Includes */
50 #include <linux/sort.h>
51 #include <linux/firmware.h>
52
53 /*================================================================*/
54 /* Local Constants */
55
56 #define PRISM2_USB_FWFILE       "prism2_ru.hex"
57
58 #define S3DATA_MAX              5000
59 #define S3PLUG_MAX              200
60 #define S3CRC_MAX               200
61 #define S3INFO_MAX              50
62 #define SREC_LINE_MAX           264
63 #define S3LEN_TXTOFFSET         2
64 #define S3LEN_TXTLEN            2
65 #define S3ADDR_TXTOFFSET        4
66 #define S3ADDR_TXTLEN           8
67 #define S3DATA_TXTOFFSET        12
68 /*S3DATA_TXTLEN                 variable, depends on len field */
69 /*S3CKSUM_TXTOFFSET             variable, depends on len field */
70 #define S3CKSUM_TXTLEN          2
71 #define SERNUM_LEN_MAX          12
72
73 #define S3PLUG_ITEMCODE_TXTOFFSET       (S3DATA_TXTOFFSET)
74 #define S3PLUG_ITEMCODE_TXTLEN          8
75 #define S3PLUG_ADDR_TXTOFFSET           (S3DATA_TXTOFFSET+8)
76 #define S3PLUG_ADDR_TXTLEN              8
77 #define S3PLUG_LEN_TXTOFFSET            (S3DATA_TXTOFFSET+16)
78 #define S3PLUG_LEN_TXTLEN               8
79
80 #define S3CRC_ADDR_TXTOFFSET            (S3DATA_TXTOFFSET)
81 #define S3CRC_ADDR_TXTLEN               8
82 #define S3CRC_LEN_TXTOFFSET             (S3DATA_TXTOFFSET+8)
83 #define S3CRC_LEN_TXTLEN                8
84 #define S3CRC_DOWRITE_TXTOFFSET         (S3DATA_TXTOFFSET+16)
85 #define S3CRC_DOWRITE_TXTLEN            8
86
87 #define S3INFO_LEN_TXTOFFSET            (S3DATA_TXTOFFSET)
88 #define S3INFO_LEN_TXTLEN               4
89 #define S3INFO_TYPE_TXTOFFSET           (S3DATA_TXTOFFSET+4)
90 #define S3INFO_TYPE_TXTLEN              4
91 #define S3INFO_DATA_TXTOFFSET           (S3DATA_TXTOFFSET+8)
92 /* S3INFO_DATA_TXTLEN                   variable, depends on INFO_LEN field */
93
94 #define S3ADDR_PLUG             (0xff000000UL)
95 #define S3ADDR_CRC              (0xff100000UL)
96 #define S3ADDR_INFO             (0xff200000UL)
97
98 #define PDAFILE_LINE_MAX        1024
99
100 #define CHUNKS_MAX              100
101
102 #define WRITESIZE_MAX           4096
103
104 /*================================================================*/
105 /* Local Macros */
106
107 #define bswap_16(x) \
108      (__extension__                                                           \
109       ({ register unsigned short int __v, __x = (x);                          \
110            __asm__ ("rorw $8, %w0"                                            \
111                     : "=r" (__v)                                              \
112                     : "0" (__x)                                               \
113                     : "cc");                                                  \
114          __v; }))
115
116 #define bswap_32(x) \
117      (__extension__                                                           \
118       ({ register unsigned int __v, __x = (x);                                \
119            __asm__ ("rorw $8, %w0;"                                           \
120                     "rorl $16, %0;"                                           \
121                     "rorw $8, %w0"                                            \
122                     : "=r" (__v)                                              \
123                     : "0" (__x)                                               \
124                     : "cc");                                                  \
125          __v; }))
126
127 /*================================================================*/
128 /* Local Types */
129
130 typedef struct s3datarec {
131         u32 len;
132         u32 addr;
133         u8 checksum;
134         u8 *data;
135 } s3datarec_t;
136
137 typedef struct s3plugrec {
138         u32 itemcode;
139         u32 addr;
140         u32 len;
141 } s3plugrec_t;
142
143 typedef struct s3crcrec {
144         u32 addr;
145         u32 len;
146         unsigned int dowrite;
147 } s3crcrec_t;
148
149 typedef struct s3inforec {
150         u16 len;
151         u16 type;
152         union {
153                 hfa384x_compident_t version;
154                 hfa384x_caplevel_t compat;
155                 u16 buildseq;
156                 hfa384x_compident_t platform;
157         } info;
158 } s3inforec_t;
159
160 typedef struct pda {
161         u8 buf[HFA384x_PDA_LEN_MAX];
162         hfa384x_pdrec_t *rec[HFA384x_PDA_RECS_MAX];
163         unsigned int nrec;
164 } pda_t;
165
166 typedef struct imgchunk {
167         u32 addr;               /* start address */
168         u32 len;                /* in bytes */
169         u16 crc;                /* CRC value (if it falls at a chunk boundary) */
170         u8 *data;
171 } imgchunk_t;
172
173 /*================================================================*/
174 /* Local Static Definitions */
175
176 /*----------------------------------------------------------------*/
177 /* s-record image processing */
178
179 /* Data records */
180 unsigned int ns3data = 0;
181 s3datarec_t s3data[S3DATA_MAX];
182
183 /* Plug records */
184 unsigned int ns3plug = 0;
185 s3plugrec_t s3plug[S3PLUG_MAX];
186
187 /* CRC records */
188 unsigned int ns3crc = 0;
189 s3crcrec_t s3crc[S3CRC_MAX];
190
191 /* Info records */
192 unsigned int ns3info = 0;
193 s3inforec_t s3info[S3INFO_MAX];
194
195 /* S7 record (there _better_ be only one) */
196 u32 startaddr;
197
198 /* Load image chunks */
199 unsigned int nfchunks;
200 imgchunk_t fchunk[CHUNKS_MAX];
201
202 /* Note that for the following pdrec_t arrays, the len and code */
203 /*   fields are stored in HOST byte order. The mkpdrlist() function */
204 /*   does the conversion.  */
205 /*----------------------------------------------------------------*/
206 /* PDA, built from [card|newfile]+[addfile1+addfile2...] */
207
208 pda_t pda;
209 hfa384x_compident_t nicid;
210 hfa384x_caplevel_t rfid;
211 hfa384x_caplevel_t macid;
212 hfa384x_caplevel_t priid;
213
214 /*================================================================*/
215 /* Local Function Declarations */
216
217 int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t * wlandev);
218 int read_srecfile(char *rfptr, int rfsize);
219 int mkimage(imgchunk_t * clist, unsigned int *ccnt);
220 int read_cardpda(pda_t * pda, wlandevice_t * wlandev);
221 int mkpdrlist(pda_t * pda);
222 int s3datarec_compare(const void *p1, const void *p2);
223 int plugimage(imgchunk_t * fchunk, unsigned int nfchunks,
224               s3plugrec_t * s3plug, unsigned int ns3plug, pda_t * pda);
225 int crcimage(imgchunk_t * fchunk, unsigned int nfchunks,
226              s3crcrec_t * s3crc, unsigned int ns3crc);
227 int writeimage(wlandevice_t * wlandev, imgchunk_t * fchunk,
228                unsigned int nfchunks);
229 void free_chunks(imgchunk_t * fchunk, unsigned int *nfchunks);
230 void free_srecs(void);
231
232 int validate_identity(void);
233
234 /*================================================================*/
235 /* Function Definitions */
236
237 /*----------------------------------------------------------------
238 * prism2_fwtry
239 *
240 * Try and get firmware into memory
241 *
242 * Arguments:
243 *       udev    usb device structure
244 *       wlandev wlan device structure
245 *
246 * Returns:
247 *       0       - success
248 *       ~0      - failure
249 ----------------------------------------------------------------*/
250 int prism2_fwtry(struct usb_device *udev, wlandevice_t * wlandev)
251 {
252         const struct firmware *fw_entry = NULL;
253
254         printk(KERN_INFO "prism2_usb: Checking for firmware %s\n",
255                PRISM2_USB_FWFILE);
256         if (request_firmware(&fw_entry, PRISM2_USB_FWFILE, &udev->dev) != 0) {
257                 printk(KERN_INFO
258                        "prism2_usb: Firmware not available, but not essential\n");
259                 printk(KERN_INFO
260                        "prism2_usb: can continue to use card anyway.\n");
261                 return 1;
262         }
263
264         printk(KERN_INFO "prism2_usb: %s will be processed, size %d\n",
265                PRISM2_USB_FWFILE, fw_entry->size);
266         prism2_fwapply((char *)fw_entry->data, fw_entry->size, wlandev);
267
268         release_firmware(fw_entry);
269         return 0;
270 }
271
272 /*----------------------------------------------------------------
273 * prism2_fwapply
274 *
275 * Apply the firmware loaded into memory
276 *
277 * Arguments:
278 *       rfptr   firmware image in kernel memory
279 *       rfsize  firmware size in kernel memory
280 *       wlandev device
281 *
282 * Returns:
283 *       0       - success
284 *       ~0      - failure
285 ----------------------------------------------------------------*/
286 int prism2_fwapply(char *rfptr, int rfsize, wlandevice_t * wlandev)
287 {
288         signed int result = 0;
289         p80211msg_dot11req_mibget_t getmsg;
290         p80211itemd_t *item;
291         u32 *data;
292
293         /* Initialize the data structures */
294         ns3data = 0;
295         memset(s3data, 0, sizeof(s3data));
296         ns3plug = 0;
297         memset(s3plug, 0, sizeof(s3plug));
298         ns3crc = 0;
299         memset(s3crc, 0, sizeof(s3crc));
300         ns3info = 0;
301         memset(s3info, 0, sizeof(s3info));
302         startaddr = 0;
303
304         nfchunks = 0;
305         memset(fchunk, 0, sizeof(fchunk));
306         memset(&nicid, 0, sizeof(nicid));
307         memset(&rfid, 0, sizeof(rfid));
308         memset(&macid, 0, sizeof(macid));
309         memset(&priid, 0, sizeof(priid));
310
311         /* clear the pda and add an initial END record */
312         memset(&pda, 0, sizeof(pda));
313         pda.rec[0] = (hfa384x_pdrec_t *) pda.buf;
314         pda.rec[0]->len = cpu_to_le16(2);       /* len in words *//* len in words */
315         pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
316         pda.nrec = 1;
317
318         /*-----------------------------------------------------*/
319         /* Put card into fwload state */
320         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
321
322         /* Build the PDA we're going to use. */
323         if (read_cardpda(&pda, wlandev)) {
324                 printk(KERN_ERR "load_cardpda failed, exiting.\n");
325                 return (1);
326         }
327
328         /* read the card's PRI-SUP */
329         memset(&getmsg, 0, sizeof(getmsg));
330         getmsg.msgcode = DIDmsg_dot11req_mibget;
331         getmsg.msglen = sizeof(getmsg);
332         strcpy(getmsg.devname, wlandev->name);
333
334         getmsg.mibattribute.did = DIDmsg_dot11req_mibget_mibattribute;
335         getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
336         getmsg.resultcode.did = DIDmsg_dot11req_mibget_resultcode;
337         getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
338
339         item = (p80211itemd_t *) getmsg.mibattribute.data;
340         item->did = DIDmib_p2_p2NIC_p2PRISupRange;
341         item->status = P80211ENUM_msgitem_status_no_value;
342
343         data = (u32 *) item->data;
344
345         /* DIDmsg_dot11req_mibget */
346         prism2mgmt_mibset_mibget(wlandev, &getmsg);
347         if (getmsg.resultcode.data != P80211ENUM_resultcode_success) {
348                 printk(KERN_ERR "Couldn't fetch PRI-SUP info\n");
349         }
350
351         /* Already in host order */
352         priid.role = *data++;
353         priid.id = *data++;
354         priid.variant = *data++;
355         priid.bottom = *data++;
356         priid.top = *data++;
357
358         /* Read the S3 file */
359         result = read_srecfile(rfptr, rfsize);
360         if (result) {
361                 printk(KERN_ERR "Failed to read the data exiting.\n");
362                 return (1);
363         }
364         /* Sort the S3 data records */
365         sort(s3data, ns3data, sizeof(s3datarec_t), s3datarec_compare, NULL);
366
367         result = validate_identity();
368
369         if (result) {
370                 printk(KERN_ERR "Incompatible firmware image.\n");
371                 return (1);
372         }
373
374         if (startaddr == 0x00000000) {
375                 printk(KERN_ERR "Can't RAM download a Flash image!\n");
376                 return (1);
377         }
378
379         /* Make the image chunks */
380         result = mkimage(fchunk, &nfchunks);
381
382         /* Do any plugging */
383         result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
384         if (result) {
385                 printk(KERN_ERR "Failed to plug data.\n");
386                 return (1);
387         }
388
389         /* Insert any CRCs */
390         if (crcimage(fchunk, nfchunks, s3crc, ns3crc)) {
391                 printk(KERN_ERR "Failed to insert all CRCs\n");
392                 return (1);
393         }
394
395         /* Write the image */
396         result = writeimage(wlandev, fchunk, nfchunks);
397         if (result) {
398                 printk(KERN_ERR "Failed to ramwrite image data.\n");
399                 return (1);
400         }
401
402         /* clear any allocated memory */
403         free_chunks(fchunk, &nfchunks);
404         free_srecs();
405
406         printk(KERN_INFO "prism2_usb: firmware loading finished.\n");
407
408         return result;
409 }
410
411 /*----------------------------------------------------------------
412 * crcimage
413 *
414 * Adds a CRC16 in the two bytes prior to each block identified by
415 * an S3 CRC record.  Currently, we don't actually do a CRC we just
416 * insert the value 0xC0DE in hfa384x order.
417 *
418 * Arguments:
419 *       fchunk          Array of image chunks
420 *       nfchunks        Number of image chunks
421 *       s3crc           Array of crc records
422 *       ns3crc          Number of crc records
423 *
424 * Returns:
425 *       0       success
426 *       ~0      failure
427 ----------------------------------------------------------------*/
428 int crcimage(imgchunk_t * fchunk, unsigned int nfchunks, s3crcrec_t * s3crc,
429              unsigned int ns3crc)
430 {
431         int result = 0;
432         int i;
433         int c;
434         u32 crcstart;
435         u32 crcend;
436         u32 cstart = 0;
437         u32 cend;
438         u8 *dest;
439         u32 chunkoff;
440
441         for (i = 0; i < ns3crc; i++) {
442                 if (!s3crc[i].dowrite)
443                         continue;
444                 crcstart = s3crc[i].addr;
445                 crcend = s3crc[i].addr + s3crc[i].len;
446                 /* Find chunk */
447                 for (c = 0; c < nfchunks; c++) {
448                         cstart = fchunk[c].addr;
449                         cend = fchunk[c].addr + fchunk[c].len;
450                         /*  the line below does an address & len match search */
451                         /*  unfortunately, I've found that the len fields of */
452                         /*  some crc records don't match with the length of */
453                         /*  the actual data, so we're not checking right */
454                         /*  now */
455                         /* if ( crcstart-2 >= cstart && crcend <= cend ) break; */
456
457                         /* note the -2 below, it's to make sure the chunk has */
458                         /*   space for the CRC value */
459                         if (crcstart - 2 >= cstart && crcstart < cend)
460                                 break;
461                 }
462                 if (c >= nfchunks) {
463                         printk(KERN_ERR
464                                "Failed to find chunk for "
465                                "crcrec[%d], addr=0x%06x len=%d , "
466                                "aborting crc.\n",
467                                i, s3crc[i].addr, s3crc[i].len);
468                         return 1;
469                 }
470
471                 /* Insert crc */
472                 pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
473                 chunkoff = crcstart - cstart - 2;
474                 dest = fchunk[c].data + chunkoff;
475                 *dest = 0xde;
476                 *(dest + 1) = 0xc0;
477
478         }
479         return result;
480 }
481
482 /*----------------------------------------------------------------
483 * free_chunks
484 *
485 * Clears the chunklist data structures in preparation for a new file.
486 *
487 * Arguments:
488 *       none
489 *
490 * Returns:
491 *       nothing
492 ----------------------------------------------------------------*/
493 void free_chunks(imgchunk_t * fchunk, unsigned int *nfchunks)
494 {
495         int i;
496         for (i = 0; i < *nfchunks; i++) {
497                 if (fchunk[i].data != NULL) {
498                         kfree(fchunk[i].data);
499                 }
500         }
501         *nfchunks = 0;
502         memset(fchunk, 0, sizeof(fchunk));
503
504 }
505
506 /*----------------------------------------------------------------
507 * free_srecs
508 *
509 * Clears the srec data structures in preparation for a new file.
510 *
511 * Arguments:
512 *       none
513 *
514 * Returns:
515 *       nothing
516 ----------------------------------------------------------------*/
517 void free_srecs(void)
518 {
519         int i;
520         for (i = 0; i < ns3data; i++) {
521                 kfree(s3data[i].data);
522         }
523         ns3data = 0;
524         memset(s3data, 0, sizeof(s3data));
525         ns3plug = 0;
526         memset(s3plug, 0, sizeof(s3plug));
527         ns3crc = 0;
528         memset(s3crc, 0, sizeof(s3crc));
529         ns3info = 0;
530         memset(s3info, 0, sizeof(s3info));
531         startaddr = 0;
532 }
533
534 /*----------------------------------------------------------------
535 * mkimage
536 *
537 * Scans the currently loaded set of S records for data residing
538 * in contiguous memory regions.  Each contiguous region is then
539 * made into a 'chunk'.  This function assumes that we're building
540 * a new chunk list.  Assumes the s3data items are in sorted order.
541 *
542 * Arguments:    none
543 *
544 * Returns:
545 *       0       - success
546 *       ~0      - failure (probably an errno)
547 ----------------------------------------------------------------*/
548 int mkimage(imgchunk_t * clist, unsigned int *ccnt)
549 {
550         int result = 0;
551         int i;
552         int j;
553         int currchunk = 0;
554         u32 nextaddr = 0;
555         u32 s3start;
556         u32 s3end;
557         u32 cstart = 0;
558         u32 cend;
559         u32 coffset;
560
561         /* There may already be data in the chunklist */
562         *ccnt = 0;
563
564         /* Establish the location and size of each chunk */
565         for (i = 0; i < ns3data; i++) {
566                 if (s3data[i].addr == nextaddr) {
567                         /* existing chunk, grow it */
568                         clist[currchunk].len += s3data[i].len;
569                         nextaddr += s3data[i].len;
570                 } else {
571                         /* New chunk */
572                         (*ccnt)++;
573                         currchunk = *ccnt - 1;
574                         clist[currchunk].addr = s3data[i].addr;
575                         clist[currchunk].len = s3data[i].len;
576                         nextaddr = s3data[i].addr + s3data[i].len;
577                         /* Expand the chunk if there is a CRC record at */
578                         /* their beginning bound */
579                         for (j = 0; j < ns3crc; j++) {
580                                 if (s3crc[j].dowrite &&
581                                     s3crc[j].addr == clist[currchunk].addr) {
582                                         clist[currchunk].addr -= 2;
583                                         clist[currchunk].len += 2;
584                                 }
585                         }
586                 }
587         }
588
589         /* We're currently assuming there aren't any overlapping chunks */
590         /*  if this proves false, we'll need to add code to coalesce. */
591
592         /* Allocate buffer space for chunks */
593         for (i = 0; i < *ccnt; i++) {
594                 clist[i].data = kmalloc(clist[i].len, GFP_KERNEL);
595                 if (clist[i].data == NULL) {
596                         printk(KERN_ERR
597                                "failed to allocate image space, exitting.\n");
598                         return (1);
599                 }
600                 memset(clist[i].data, 0, clist[i].len);
601         }
602
603         /* Display chunks */
604         for (i = 0; i < *ccnt; i++) {
605                 pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
606                          i, clist[i].addr, clist[i].len);
607         }
608
609         /* Copy srec data to chunks */
610         for (i = 0; i < ns3data; i++) {
611                 s3start = s3data[i].addr;
612                 s3end = s3start + s3data[i].len - 1;
613                 for (j = 0; j < *ccnt; j++) {
614                         cstart = clist[j].addr;
615                         cend = cstart + clist[j].len - 1;
616                         if (s3start >= cstart && s3end <= cend) {
617                                 break;
618                         }
619                 }
620                 if (((unsigned int)j) >= (*ccnt)) {
621                         printk(KERN_ERR
622                                "s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
623                                s3start, s3data[i].len);
624                         return (1);
625                 }
626                 coffset = s3start - cstart;
627                 memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
628         }
629
630         return result;
631 }
632
633 /*----------------------------------------------------------------
634 * mkpdrlist
635 *
636 * Reads a raw PDA and builds an array of pdrec_t structures.
637 *
638 * Arguments:
639 *       pda     buffer containing raw PDA bytes
640 *       pdrec   ptr to an array of pdrec_t's.  Will be filled on exit.
641 *       nrec    ptr to a variable that will contain the count of PDRs
642 *
643 * Returns:
644 *       0       - success
645 *       ~0      - failure (probably an errno)
646 ----------------------------------------------------------------*/
647 int mkpdrlist(pda_t * pda)
648 {
649         int result = 0;
650         u16 *pda16 = (u16 *) pda->buf;
651         int curroff;            /* in 'words' */
652
653         pda->nrec = 0;
654         curroff = 0;
655         while (curroff < (HFA384x_PDA_LEN_MAX / 2) &&
656                le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
657                 pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]);
658
659                 if (le16_to_cpu(pda->rec[pda->nrec]->code) == HFA384x_PDR_NICID) {
660                         memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
661                                sizeof(nicid));
662                         nicid.id = le16_to_cpu(nicid.id);
663                         nicid.variant = le16_to_cpu(nicid.variant);
664                         nicid.major = le16_to_cpu(nicid.major);
665                         nicid.minor = le16_to_cpu(nicid.minor);
666                 }
667                 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
668                     HFA384x_PDR_MFISUPRANGE) {
669                         memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
670                                sizeof(rfid));
671                         rfid.id = le16_to_cpu(rfid.id);
672                         rfid.variant = le16_to_cpu(rfid.variant);
673                         rfid.bottom = le16_to_cpu(rfid.bottom);
674                         rfid.top = le16_to_cpu(rfid.top);
675                 }
676                 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
677                     HFA384x_PDR_CFISUPRANGE) {
678                         memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
679                                sizeof(macid));
680                         macid.id = le16_to_cpu(macid.id);
681                         macid.variant = le16_to_cpu(macid.variant);
682                         macid.bottom = le16_to_cpu(macid.bottom);
683                         macid.top = le16_to_cpu(macid.top);
684                 }
685
686                 (pda->nrec)++;
687                 curroff += le16_to_cpu(pda16[curroff]) + 1;
688
689         }
690         if (curroff >= (HFA384x_PDA_LEN_MAX / 2)) {
691                 printk(KERN_ERR
692                        "no end record found or invalid lengths in "
693                        "PDR data, exiting. %x %d\n", curroff, pda->nrec);
694                 return (1);
695         }
696         if (le16_to_cpu(pda16[curroff + 1]) == HFA384x_PDR_END_OF_PDA) {
697                 pda->rec[pda->nrec] = (hfa384x_pdrec_t *) & (pda16[curroff]);
698                 (pda->nrec)++;
699         }
700         return result;
701 }
702
703 /*----------------------------------------------------------------
704 * plugimage
705 *
706 * Plugs the given image using the given plug records from the given
707 * PDA and filename.
708 *
709 * Arguments:
710 *       fchunk          Array of image chunks
711 *       nfchunks        Number of image chunks
712 *       s3plug          Array of plug records
713 *       ns3plug         Number of plug records
714 *       pda             Current pda data
715 *
716 * Returns:
717 *       0       success
718 *       ~0      failure
719 ----------------------------------------------------------------*/
720 int plugimage(imgchunk_t * fchunk, unsigned int nfchunks,
721               s3plugrec_t * s3plug, unsigned int ns3plug, pda_t * pda)
722 {
723         int result = 0;
724         int i;                  /* plug index */
725         int j;                  /* index of PDR or -1 if fname plug */
726         int c;                  /* chunk index */
727         u32 pstart;
728         u32 pend;
729         u32 cstart = 0;
730         u32 cend;
731         u32 chunkoff;
732         u8 *dest;
733
734         /* for each plug record */
735         for (i = 0; i < ns3plug; i++) {
736                 pstart = s3plug[i].addr;
737                 pend = s3plug[i].addr + s3plug[i].len;
738                 /* find the matching PDR (or filename) */
739                 if (s3plug[i].itemcode != 0xffffffffUL) {       /* not filename */
740                         for (j = 0; j < pda->nrec; j++) {
741                                 if (s3plug[i].itemcode ==
742                                     le16_to_cpu(pda->rec[j]->code))
743                                         break;
744                         }
745                 } else {
746                         j = -1;
747                 }
748                 if (j >= pda->nrec && j != -1) {        /*  if no matching PDR, fail */
749                         printk(KERN_WARNING
750                                "warning: Failed to find PDR for "
751                                "plugrec 0x%04x.\n", s3plug[i].itemcode);
752                         continue;       /* and move on to the next PDR */
753 #if 0
754                         /* MSM: They swear that unless it's the MAC address,
755                          * the serial number, or the TX calibration records,
756                          * then there's reasonable defaults in the f/w
757                          * image.  Therefore, missing PDRs in the card
758                          * should only be a warning, not fatal.
759                          * TODO: add fatals for the PDRs mentioned above.
760                          */
761                         result = 1;
762                         continue;
763 #endif
764                 }
765
766                 /* Validate plug len against PDR len */
767                 if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
768                         printk(KERN_ERR
769                                "error: Plug vs. PDR len mismatch for "
770                                "plugrec 0x%04x, abort plugging.\n",
771                                s3plug[i].itemcode);
772                         result = 1;
773                         continue;
774                 }
775
776                 /* Validate plug address against chunk data and identify chunk */
777                 for (c = 0; c < nfchunks; c++) {
778                         cstart = fchunk[c].addr;
779                         cend = fchunk[c].addr + fchunk[c].len;
780                         if (pstart >= cstart && pend <= cend)
781                                 break;
782                 }
783                 if (c >= nfchunks) {
784                         printk(KERN_ERR
785                                "error: Failed to find image chunk for "
786                                "plugrec 0x%04x.\n", s3plug[i].itemcode);
787                         result = 1;
788                         continue;
789                 }
790
791                 /* Plug data */
792                 chunkoff = pstart - cstart;
793                 dest = fchunk[c].data + chunkoff;
794                 pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, "
795                          "cnum=%d coff=0x%06x\n",
796                          s3plug[i].itemcode, pstart, s3plug[i].len,
797                          c, chunkoff);
798
799                 if (j == -1) {  /* plug the filename */
800                         memset(dest, 0, s3plug[i].len);
801                         strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
802                 } else {        /* plug a PDR */
803                         memcpy(dest, &(pda->rec[j]->data), s3plug[i].len);
804                 }
805         }
806         return result;
807
808 }
809
810 /*----------------------------------------------------------------
811 * read_cardpda
812 *
813 * Sends the command for the driver to read the pda from the card
814 * named in the device variable.  Upon success, the card pda is
815 * stored in the "cardpda" variables.  Note that the pda structure
816 * is considered 'well formed' after this function.  That means
817 * that the nrecs is valid, the rec array has been set up, and there's
818 * a valid PDAEND record in the raw PDA data.
819 *
820 * Arguments:
821 *       pda             pda structure
822 *       wlandev         device
823 *
824 * Returns:
825 *       0       - success
826 *       ~0      - failure (probably an errno)
827 ----------------------------------------------------------------*/
828 int read_cardpda(pda_t * pda, wlandevice_t * wlandev)
829 {
830         int result = 0;
831         p80211msg_p2req_readpda_t msg;
832
833         /* set up the msg */
834         msg.msgcode = DIDmsg_p2req_readpda;
835         msg.msglen = sizeof(msg);
836         strcpy(msg.devname, wlandev->name);
837         msg.pda.did = DIDmsg_p2req_readpda_pda;
838         msg.pda.len = HFA384x_PDA_LEN_MAX;
839         msg.pda.status = P80211ENUM_msgitem_status_no_value;
840         msg.resultcode.did = DIDmsg_p2req_readpda_resultcode;
841         msg.resultcode.len = sizeof(u32);
842         msg.resultcode.status = P80211ENUM_msgitem_status_no_value;
843
844         if (prism2mgmt_readpda(wlandev, &msg) != 0) {
845                 /* prism2mgmt_readpda prints an errno if appropriate */
846                 result = -1;
847         } else if (msg.resultcode.data == P80211ENUM_resultcode_success) {
848                 memcpy(pda->buf, msg.pda.data, HFA384x_PDA_LEN_MAX);
849                 result = mkpdrlist(pda);
850         } else {
851                 /* resultcode must've been something other than success */
852                 result = -1;
853         }
854
855         return result;
856 }
857
858 /*----------------------------------------------------------------
859 * copy_line
860 *
861 * Copies a line of text, up to \n, \0, or SREC_LINE_MAX, or limit of
862 * From array
863 *
864 * Arguments:
865 *       from    From addr
866 *       to      To addr
867 *       limit   Addr of last character in From array that can be copied
868 *
869 * Returns:
870 *       Num characters copied
871 ----------------------------------------------------------------*/
872 int copyline(char *from, char *to, char *limit)
873 {
874         int c = 0;
875
876         while ((c < SREC_LINE_MAX - 1) && (from + c <= limit) &&
877                (from[c] != '\n') && (from[c] != '\0')) {
878                 to[c] = from[c];
879                 c++;
880         }
881
882         to[c] = '\0';
883         return (c < SREC_LINE_MAX - 1) ? c + 1 : c;
884 }
885
886 /*----------------------------------------------------------------
887 * read_srecfile
888 *
889 * Reads the given srecord file and loads the records into the
890 * s3xxx arrays.  This function can be called repeatedly (once for
891 * each of a set of files), if necessary.  This function performs
892 * no validation of the data except for the grossest of S-record
893 * line format checks.  Don't forget that these will be DOS files...
894 * CR/LF at the end of each line.
895 *
896 * Here's the SREC format we're dealing with:
897 * S[37]nnaaaaaaaaddd...dddcc
898 *
899 *       nn - number of bytes starting with the address field
900 * aaaaaaaa - address in readable (or big endian) format
901 * dd....dd - 0-245 data bytes (two chars per byte)
902 *       cc - checksum
903 *
904 * The S7 record's (there should be only one) address value gets
905 * saved in startaddr.  It's the start execution address used
906 * for RAM downloads.
907 *
908 * The S3 records have a collection of subformats indicated by the
909 * value of aaaaaaaa:
910 *   0xff000000 - Plug record, data field format:
911 *                xxxxxxxxaaaaaaaassssssss
912 *                x - PDR code number (little endian)
913 *                a - Address in load image to plug (little endian)
914 *                s - Length of plug data area (little endian)
915 *
916 *   0xff100000 - CRC16 generation record, data field format:
917 *                aaaaaaaassssssssbbbbbbbb
918 *                a - Start address for CRC calculation (little endian)
919 *                s - Length of data to  calculate over (little endian)
920 *                b - Boolean, true=write crc, false=don't write
921 *
922 *   0xff200000 - Info record, data field format:
923 *                ssssttttdd..dd
924 *                s - Size in words (little endian)
925 *                t - Info type (little endian), see #defines and
926 *                    s3inforec_t for details about types.
927 *                d - (s - 1) little endian words giving the contents of
928 *                    the given info type.
929 *
930 * Arguments:
931 *       rfptr   firmware image (s-record structure) in kernel memory
932 *       rfsize  firmware size in kernel memory
933 *
934 * Returns:
935 *       0       - success
936 *       ~0      - failure (probably an errno)
937 ----------------------------------------------------------------*/
938 int read_srecfile(char *rfptr, int rfsize)
939 {
940         int result = 0;
941         char buf[SREC_LINE_MAX];
942         char tmpbuf[30];
943         s3datarec_t tmprec;
944         int i, c;
945         int line = 0;
946         u16 *tmpinfo;
947         char *endptr = rfptr + rfsize;
948
949         pr_debug("Reading S-record file ...\n");
950
951         while ((c = copyline(rfptr, buf, endptr)) >= 12) {
952                 rfptr = rfptr + c;
953                 line++;
954                 if (buf[0] != 'S') {
955                         printk(KERN_ERR "%d warning: No initial \'S\'\n", line);
956                         return 1;
957                 }
958                 if (buf[1] == '7') {    /* S7 record, start address */
959                         buf[12] = '\0';
960                         startaddr = simple_strtoul(buf + 4, NULL, 16);
961                         pr_debug("  S7 start addr, line=%d "
962                                  " addr=0x%08x\n", line, startaddr);
963                         continue;
964                 } else if (buf[1] == '3') {
965                         /* Ok, it's an S3, parse and put it in the right array */
966                         /* Record Length field (we only want datalen) */
967                         memcpy(tmpbuf, buf + S3LEN_TXTOFFSET, S3LEN_TXTLEN);
968                         tmpbuf[S3LEN_TXTLEN] = '\0';
969                         tmprec.len = simple_strtoul(tmpbuf, NULL, 16) - 4 - 1;  /* 4=addr, 1=cksum */
970                         /* Address field */
971                         memcpy(tmpbuf, buf + S3ADDR_TXTOFFSET, S3ADDR_TXTLEN);
972                         tmpbuf[S3ADDR_TXTLEN] = '\0';
973                         tmprec.addr = simple_strtoul(tmpbuf, NULL, 16);
974                         /* Checksum field */
975                         tmprec.checksum =
976                             simple_strtoul(buf + strlen(buf) - 2, NULL, 16);
977
978                         switch (tmprec.addr) {
979                         case S3ADDR_PLUG:
980                                 memcpy(tmpbuf, buf + S3PLUG_ITEMCODE_TXTOFFSET,
981                                        S3PLUG_ITEMCODE_TXTLEN);
982                                 tmpbuf[S3PLUG_ITEMCODE_TXTLEN] = '\0';
983                                 s3plug[ns3plug].itemcode =
984                                     simple_strtoul(tmpbuf, NULL, 16);
985                                 s3plug[ns3plug].itemcode =
986                                     bswap_32(s3plug[ns3plug].itemcode);
987
988                                 memcpy(tmpbuf, buf + S3PLUG_ADDR_TXTOFFSET,
989                                        S3PLUG_ADDR_TXTLEN);
990                                 tmpbuf[S3PLUG_ADDR_TXTLEN] = '\0';
991                                 s3plug[ns3plug].addr =
992                                     simple_strtoul(tmpbuf, NULL, 16);
993                                 s3plug[ns3plug].addr =
994                                     bswap_32(s3plug[ns3plug].addr);
995
996                                 memcpy(tmpbuf, buf + S3PLUG_LEN_TXTOFFSET,
997                                        S3PLUG_LEN_TXTLEN);
998                                 tmpbuf[S3PLUG_LEN_TXTLEN] = '\0';
999                                 s3plug[ns3plug].len =
1000                                     simple_strtoul(tmpbuf, NULL, 16);
1001                                 s3plug[ns3plug].len =
1002                                     bswap_32(s3plug[ns3plug].len);
1003
1004                                 pr_debug("  S3 plugrec, line=%d "
1005                                          "itemcode=0x%04x addr=0x%08x len=%d\n",
1006                                          line,
1007                                          s3plug[ns3plug].itemcode,
1008                                          s3plug[ns3plug].addr,
1009                                          s3plug[ns3plug].len);
1010
1011                                 ns3plug++;
1012                                 if (ns3plug == S3PLUG_MAX) {
1013                                         printk(KERN_ERR
1014                                                "S3 plugrec limit reached - aborting\n");
1015                                         return 1;
1016                                 }
1017                                 break;
1018                         case S3ADDR_CRC:
1019                                 memcpy(tmpbuf, buf + S3CRC_ADDR_TXTOFFSET,
1020                                        S3CRC_ADDR_TXTLEN);
1021                                 tmpbuf[S3CRC_ADDR_TXTLEN] = '\0';
1022                                 s3crc[ns3crc].addr =
1023                                     simple_strtoul(tmpbuf, NULL, 16);
1024                                 s3crc[ns3crc].addr =
1025                                     bswap_32(s3crc[ns3crc].addr);
1026
1027                                 memcpy(tmpbuf, buf + S3CRC_LEN_TXTOFFSET,
1028                                        S3CRC_LEN_TXTLEN);
1029                                 tmpbuf[S3CRC_LEN_TXTLEN] = '\0';
1030                                 s3crc[ns3crc].len =
1031                                     simple_strtoul(tmpbuf, NULL, 16);
1032                                 s3crc[ns3crc].len = bswap_32(s3crc[ns3crc].len);
1033
1034                                 memcpy(tmpbuf, buf + S3CRC_DOWRITE_TXTOFFSET,
1035                                        S3CRC_DOWRITE_TXTLEN);
1036                                 tmpbuf[S3CRC_DOWRITE_TXTLEN] = '\0';
1037                                 s3crc[ns3crc].dowrite =
1038                                     simple_strtoul(tmpbuf, NULL, 16);
1039                                 s3crc[ns3crc].dowrite =
1040                                     bswap_32(s3crc[ns3crc].dowrite);
1041
1042                                 pr_debug("  S3 crcrec, line=%d "
1043                                          "addr=0x%08x len=%d write=0x%08x\n",
1044                                          line,
1045                                          s3crc[ns3crc].addr,
1046                                          s3crc[ns3crc].len,
1047                                          s3crc[ns3crc].dowrite);
1048                                 ns3crc++;
1049                                 if (ns3crc == S3CRC_MAX) {
1050                                         printk(KERN_ERR
1051                                                "S3 crcrec limit reached - aborting\n");
1052                                         return 1;
1053                                 }
1054                                 break;
1055                         case S3ADDR_INFO:
1056                                 memcpy(tmpbuf, buf + S3INFO_LEN_TXTOFFSET,
1057                                        S3INFO_LEN_TXTLEN);
1058                                 tmpbuf[S3INFO_LEN_TXTLEN] = '\0';
1059                                 s3info[ns3info].len =
1060                                     simple_strtoul(tmpbuf, NULL, 16);
1061                                 s3info[ns3info].len =
1062                                     bswap_16(s3info[ns3info].len);
1063
1064                                 memcpy(tmpbuf, buf + S3INFO_TYPE_TXTOFFSET,
1065                                        S3INFO_TYPE_TXTLEN);
1066                                 tmpbuf[S3INFO_TYPE_TXTLEN] = '\0';
1067                                 s3info[ns3info].type =
1068                                     simple_strtoul(tmpbuf, NULL, 16);
1069                                 s3info[ns3info].type =
1070                                     bswap_16(s3info[ns3info].type);
1071
1072                                 pr_debug("  S3 inforec, line=%d "
1073                                          "len=0x%04x type=0x%04x\n",
1074                                          line,
1075                                          s3info[ns3info].len,
1076                                          s3info[ns3info].type);
1077                                 if (((s3info[ns3info].len - 1) * sizeof(u16)) >
1078                                     sizeof(s3info[ns3info].info)) {
1079                                         printk(KERN_ERR
1080                                                " S3 inforec length too long - aborting\n");
1081                                         return 1;
1082                                 }
1083
1084                                 tmpinfo =
1085                                     (u16 *) & (s3info[ns3info].info.version);
1086                                 for (i = 0; i < s3info[ns3info].len - 1; i++) {
1087                                         memcpy(tmpbuf,
1088                                                buf + S3INFO_DATA_TXTOFFSET +
1089                                                (i * 4), 4);
1090                                         tmpbuf[4] = '\0';
1091                                         tmpinfo[i] =
1092                                             simple_strtoul(tmpbuf, NULL, 16);
1093                                         tmpinfo[i] = bswap_16(tmpinfo[i]);
1094                                 }
1095                                 pr_debug("            info=");
1096                                 for (i = 0; i < s3info[ns3info].len - 1; i++) {
1097                                         pr_debug("%04x ", tmpinfo[i]);
1098                                 }
1099                                 pr_debug("\n");
1100
1101                                 ns3info++;
1102                                 if (ns3info == S3INFO_MAX) {
1103                                         printk(KERN_ERR
1104                                                "S3 inforec limit reached - aborting\n");
1105                                         return 1;
1106                                 }
1107                                 break;
1108                         default:        /* Data record */
1109                                 s3data[ns3data].addr = tmprec.addr;
1110                                 s3data[ns3data].len = tmprec.len;
1111                                 s3data[ns3data].checksum = tmprec.checksum;
1112                                 s3data[ns3data].data =
1113                                     kmalloc(tmprec.len, GFP_KERNEL);
1114                                 for (i = 0; i < tmprec.len; i++) {
1115                                         memcpy(tmpbuf,
1116                                                buf + S3DATA_TXTOFFSET + (i * 2),
1117                                                2);
1118                                         tmpbuf[2] = '\0';
1119                                         s3data[ns3data].data[i] =
1120                                             simple_strtoul(tmpbuf, NULL, 16);
1121                                 }
1122                                 ns3data++;
1123                                 if (ns3data == S3DATA_MAX) {
1124                                         printk(KERN_ERR
1125                                                "S3 datarec limit reached - aborting\n");
1126                                         return 1;
1127                                 }
1128                                 break;
1129                         }
1130                 } else {
1131                         printk(KERN_WARNING
1132                                "%d warning: Unknown S-record detected.\n",
1133                                line);
1134                 }
1135         }
1136         return result;
1137 }
1138
1139 /*----------------------------------------------------------------
1140 * s3datarec_compare
1141 *
1142 * Comparison function for sort().
1143 *
1144 * Arguments:
1145 *       p1      ptr to the first item
1146 *       p2      ptr to the second item
1147 * Returns:
1148 *       0       items are equal
1149 *       <0      p1 < p2
1150 *       >0      p1 > p2
1151 ----------------------------------------------------------------*/
1152 int s3datarec_compare(const void *p1, const void *p2)
1153 {
1154         const s3datarec_t *s1 = p1;
1155         const s3datarec_t *s2 = p2;
1156         if (s1->addr == s2->addr)
1157                 return 0;
1158         if (s1->addr < s2->addr)
1159                 return -1;
1160         return 1;
1161 }
1162
1163 /*----------------------------------------------------------------
1164 * writeimage
1165 *
1166 * Takes the chunks, builds p80211 messages and sends them down
1167 * to the driver for writing to the card.
1168 *
1169 * Arguments:
1170 *       wlandev         device
1171 *       fchunk          Array of image chunks
1172 *       nfchunks        Number of image chunks
1173 *
1174 * Returns:
1175 *       0       success
1176 *       ~0      failure
1177 ----------------------------------------------------------------*/
1178 int writeimage(wlandevice_t * wlandev, imgchunk_t * fchunk,
1179                unsigned int nfchunks)
1180 {
1181         int result = 0;
1182         p80211msg_p2req_ramdl_state_t rstatemsg;
1183         p80211msg_p2req_ramdl_write_t rwritemsg;
1184         p80211msg_t *msgp;
1185         u32 resultcode;
1186         int i;
1187         int j;
1188         unsigned int nwrites;
1189         u32 curroff;
1190         u32 currlen;
1191         u32 currdaddr;
1192
1193         /* Initialize the messages */
1194         memset(&rstatemsg, 0, sizeof(rstatemsg));
1195         strcpy(rstatemsg.devname, wlandev->name);
1196         rstatemsg.msgcode = DIDmsg_p2req_ramdl_state;
1197         rstatemsg.msglen = sizeof(rstatemsg);
1198         rstatemsg.enable.did = DIDmsg_p2req_ramdl_state_enable;
1199         rstatemsg.exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
1200         rstatemsg.resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
1201         rstatemsg.enable.status = P80211ENUM_msgitem_status_data_ok;
1202         rstatemsg.exeaddr.status = P80211ENUM_msgitem_status_data_ok;
1203         rstatemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
1204         rstatemsg.enable.len = sizeof(u32);
1205         rstatemsg.exeaddr.len = sizeof(u32);
1206         rstatemsg.resultcode.len = sizeof(u32);
1207
1208         memset(&rwritemsg, 0, sizeof(rwritemsg));
1209         strcpy(rwritemsg.devname, wlandev->name);
1210         rwritemsg.msgcode = DIDmsg_p2req_ramdl_write;
1211         rwritemsg.msglen = sizeof(rwritemsg);
1212         rwritemsg.addr.did = DIDmsg_p2req_ramdl_write_addr;
1213         rwritemsg.len.did = DIDmsg_p2req_ramdl_write_len;
1214         rwritemsg.data.did = DIDmsg_p2req_ramdl_write_data;
1215         rwritemsg.resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
1216         rwritemsg.addr.status = P80211ENUM_msgitem_status_data_ok;
1217         rwritemsg.len.status = P80211ENUM_msgitem_status_data_ok;
1218         rwritemsg.data.status = P80211ENUM_msgitem_status_data_ok;
1219         rwritemsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
1220         rwritemsg.addr.len = sizeof(u32);
1221         rwritemsg.len.len = sizeof(u32);
1222         rwritemsg.data.len = WRITESIZE_MAX;
1223         rwritemsg.resultcode.len = sizeof(u32);
1224
1225         /* Send xxx_state(enable) */
1226         pr_debug("Sending dl_state(enable) message.\n");
1227         rstatemsg.enable.data = P80211ENUM_truth_true;
1228         rstatemsg.exeaddr.data = startaddr;
1229
1230         msgp = (p80211msg_t *) & rstatemsg;
1231         result = prism2mgmt_ramdl_state(wlandev, msgp);
1232         if (result) {
1233                 printk(KERN_ERR
1234                        "writeimage state enable failed w/ result=%d, "
1235                        "aborting download\n", result);
1236                 return result;
1237         }
1238         resultcode = rstatemsg.resultcode.data;
1239         if (resultcode != P80211ENUM_resultcode_success) {
1240                 printk(KERN_ERR
1241                        "writeimage()->xxxdl_state msg indicates failure, "
1242                        "w/ resultcode=%d, aborting download.\n", resultcode);
1243                 return 1;
1244         }
1245
1246         /* Now, loop through the data chunks and send WRITESIZE_MAX data */
1247         for (i = 0; i < nfchunks; i++) {
1248                 nwrites = fchunk[i].len / WRITESIZE_MAX;
1249                 nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1250                 curroff = 0;
1251                 for (j = 0; j < nwrites; j++) {
1252                         currlen =
1253                             (fchunk[i].len - (WRITESIZE_MAX * j)) >
1254                             WRITESIZE_MAX ? WRITESIZE_MAX : (fchunk[i].len -
1255                                                              (WRITESIZE_MAX *
1256                                                               j));
1257                         curroff = j * WRITESIZE_MAX;
1258                         currdaddr = fchunk[i].addr + curroff;
1259                         /* Setup the message */
1260                         rwritemsg.addr.data = currdaddr;
1261                         rwritemsg.len.data = currlen;
1262                         memcpy(rwritemsg.data.data,
1263                                fchunk[i].data + curroff, currlen);
1264
1265                         /* Send flashdl_write(pda) */
1266                         pr_debug
1267                             ("Sending xxxdl_write message addr=%06x len=%d.\n",
1268                              currdaddr, currlen);
1269
1270                         msgp = (p80211msg_t *) & rwritemsg;
1271                         result = prism2mgmt_ramdl_write(wlandev, msgp);
1272
1273                         /* Check the results */
1274                         if (result) {
1275                                 printk(KERN_ERR
1276                                        "writeimage chunk write failed w/ result=%d, "
1277                                        "aborting download\n", result);
1278                                 return result;
1279                         }
1280                         resultcode = rstatemsg.resultcode.data;
1281                         if (resultcode != P80211ENUM_resultcode_success) {
1282                                 printk(KERN_ERR
1283                                        "writeimage()->xxxdl_write msg indicates failure, "
1284                                        "w/ resultcode=%d, aborting download.\n",
1285                                        resultcode);
1286                                 return 1;
1287                         }
1288
1289                 }
1290         }
1291
1292         /* Send xxx_state(disable) */
1293         pr_debug("Sending dl_state(disable) message.\n");
1294         rstatemsg.enable.data = P80211ENUM_truth_false;
1295         rstatemsg.exeaddr.data = 0;
1296
1297         msgp = (p80211msg_t *) & rstatemsg;
1298         result = prism2mgmt_ramdl_state(wlandev, msgp);
1299         if (result) {
1300                 printk(KERN_ERR
1301                        "writeimage state disable failed w/ result=%d, "
1302                        "aborting download\n", result);
1303                 return result;
1304         }
1305         resultcode = rstatemsg.resultcode.data;
1306         if (resultcode != P80211ENUM_resultcode_success) {
1307                 printk(KERN_ERR
1308                        "writeimage()->xxxdl_state msg indicates failure, "
1309                        "w/ resultcode=%d, aborting download.\n", resultcode);
1310                 return 1;
1311         }
1312         return result;
1313 }
1314
1315 int validate_identity(void)
1316 {
1317         int i;
1318         int result = 1;
1319
1320         pr_debug("NIC ID: %#x v%d.%d.%d\n",
1321                  nicid.id, nicid.major, nicid.minor, nicid.variant);
1322         pr_debug("MFI ID: %#x v%d %d->%d\n",
1323                  rfid.id, rfid.variant, rfid.bottom, rfid.top);
1324         pr_debug("CFI ID: %#x v%d %d->%d\n",
1325                  macid.id, macid.variant, macid.bottom, macid.top);
1326         pr_debug("PRI ID: %#x v%d %d->%d\n",
1327                  priid.id, priid.variant, priid.bottom, priid.top);
1328
1329         for (i = 0; i < ns3info; i++) {
1330                 switch (s3info[i].type) {
1331                 case 1:
1332                         pr_debug("Version:  ID %#x %d.%d.%d\n",
1333                                  s3info[i].info.version.id,
1334                                  s3info[i].info.version.major,
1335                                  s3info[i].info.version.minor,
1336                                  s3info[i].info.version.variant);
1337                         break;
1338                 case 2:
1339                         pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1340                                  s3info[i].info.compat.role,
1341                                  s3info[i].info.compat.id,
1342                                  s3info[i].info.compat.variant,
1343                                  s3info[i].info.compat.bottom,
1344                                  s3info[i].info.compat.top);
1345
1346                         /* MAC compat range */
1347                         if ((s3info[i].info.compat.role == 1) &&
1348                             (s3info[i].info.compat.id == 2)) {
1349                                 if (s3info[i].info.compat.variant !=
1350                                     macid.variant) {
1351                                         result = 2;
1352                                 }
1353                         }
1354
1355                         /* PRI compat range */
1356                         if ((s3info[i].info.compat.role == 1) &&
1357                             (s3info[i].info.compat.id == 3)) {
1358                                 if ((s3info[i].info.compat.bottom > priid.top)
1359                                     || (s3info[i].info.compat.top <
1360                                         priid.bottom)) {
1361                                         result = 3;
1362                                 }
1363                         }
1364                         /* SEC compat range */
1365                         if ((s3info[i].info.compat.role == 1) &&
1366                             (s3info[i].info.compat.id == 4)) {
1367
1368                         }
1369
1370                         break;
1371                 case 3:
1372                         pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1373
1374                         break;
1375                 case 4:
1376                         pr_debug("Platform:  ID %#x %d.%d.%d\n",
1377                                  s3info[i].info.version.id,
1378                                  s3info[i].info.version.major,
1379                                  s3info[i].info.version.minor,
1380                                  s3info[i].info.version.variant);
1381
1382                         if (nicid.id != s3info[i].info.version.id)
1383                                 continue;
1384                         if (nicid.major != s3info[i].info.version.major)
1385                                 continue;
1386                         if (nicid.minor != s3info[i].info.version.minor)
1387                                 continue;
1388                         if ((nicid.variant != s3info[i].info.version.variant) &&
1389                             (nicid.id != 0x8008))
1390                                 continue;
1391
1392                         if (result != 2)
1393                                 result = 0;
1394                         break;
1395                 case 0x8001:
1396                         pr_debug("name inforec len %d\n", s3info[i].len);
1397
1398                         break;
1399                 default:
1400                         pr_debug("Unknown inforec type %d\n", s3info[i].type);
1401                 }
1402         }
1403         // walk through
1404
1405         return result;
1406 }