Merge tag 'fsnotify_for_v6.5-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / staging / wlan-ng / prism2fw.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1)
2 /* from src/prism2/download/prism2dl.c
3  *
4  * utility for downloading prism2 images moved into kernelspace
5  *
6  * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
7  * --------------------------------------------------------------------
8  *
9  * linux-wlan
10  *
11  * --------------------------------------------------------------------
12  *
13  * Inquiries regarding the linux-wlan Open Source project can be
14  * made directly to:
15  *
16  * AbsoluteValue Systems Inc.
17  * info@linux-wlan.com
18  * http://www.linux-wlan.com
19  *
20  * --------------------------------------------------------------------
21  *
22  * Portions of the development of this software were funded by
23  * Intersil Corporation as part of PRISM(R) chipset product development.
24  *
25  * --------------------------------------------------------------------
26  */
27
28 /*================================================================*/
29 /* System Includes */
30 #include <linux/ihex.h>
31 #include <linux/slab.h>
32
33 /*================================================================*/
34 /* Local Constants */
35
36 #define PRISM2_USB_FWFILE       "prism2_ru.fw"
37 MODULE_FIRMWARE(PRISM2_USB_FWFILE);
38
39 #define S3DATA_MAX              5000
40 #define S3PLUG_MAX              200
41 #define S3CRC_MAX               200
42 #define S3INFO_MAX              50
43
44 #define S3ADDR_PLUG             (0xff000000UL)
45 #define S3ADDR_CRC              (0xff100000UL)
46 #define S3ADDR_INFO             (0xff200000UL)
47 #define S3ADDR_START            (0xff400000UL)
48
49 #define CHUNKS_MAX              100
50
51 #define WRITESIZE_MAX           4096
52
53 /*================================================================*/
54 /* Local Types */
55
56 struct s3datarec {
57         u32 len;
58         u32 addr;
59         u8 checksum;
60         u8 *data;
61 };
62
63 struct s3plugrec {
64         u32 itemcode;
65         u32 addr;
66         u32 len;
67 };
68
69 struct s3crcrec {
70         u32 addr;
71         u32 len;
72         unsigned int dowrite;
73 };
74
75 struct s3inforec {
76         u16 len;
77         u16 type;
78         union {
79                 struct hfa384x_compident version;
80                 struct hfa384x_caplevel compat;
81                 u16 buildseq;
82                 struct hfa384x_compident platform;
83         } info;
84 };
85
86 struct pda {
87         u8 buf[HFA384x_PDA_LEN_MAX];
88         struct hfa384x_pdrec *rec[HFA384x_PDA_RECS_MAX];
89         unsigned int nrec;
90 };
91
92 struct imgchunk {
93         u32 addr;       /* start address */
94         u32 len;        /* in bytes */
95         u16 crc;        /* CRC value (if it falls at a chunk boundary) */
96         u8 *data;
97 };
98
99 /*================================================================*/
100 /* Local Static Definitions */
101
102 /*----------------------------------------------------------------*/
103 /* s-record image processing */
104
105 /* Data records */
106 static unsigned int ns3data;
107 static struct s3datarec *s3data;
108
109 /* Plug records */
110 static unsigned int ns3plug;
111 static struct s3plugrec s3plug[S3PLUG_MAX];
112
113 /* CRC records */
114 static unsigned int ns3crc;
115 static struct s3crcrec s3crc[S3CRC_MAX];
116
117 /* Info records */
118 static unsigned int ns3info;
119 static struct s3inforec s3info[S3INFO_MAX];
120
121 /* S7 record (there _better_ be only one) */
122 static u32 startaddr;
123
124 /* Load image chunks */
125 static unsigned int nfchunks;
126 static struct imgchunk fchunk[CHUNKS_MAX];
127
128 /* Note that for the following pdrec_t arrays, the len and code */
129 /*   fields are stored in HOST byte order. The mkpdrlist() function */
130 /*   does the conversion.  */
131 /*----------------------------------------------------------------*/
132 /* PDA, built from [card|newfile]+[addfile1+addfile2...] */
133
134 static struct pda pda;
135 static struct hfa384x_compident nicid;
136 static struct hfa384x_caplevel rfid;
137 static struct hfa384x_caplevel macid;
138 static struct hfa384x_caplevel priid;
139
140 /*================================================================*/
141 /* Local Function Declarations */
142
143 static int prism2_fwapply(const struct ihex_binrec *rfptr,
144                           struct wlandevice *wlandev);
145
146 static int read_fwfile(const struct ihex_binrec *rfptr);
147
148 static int mkimage(struct imgchunk *clist, unsigned int *ccnt);
149
150 static int read_cardpda(struct pda *pda, struct wlandevice *wlandev);
151
152 static int mkpdrlist(struct pda *pda);
153
154 static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
155                      struct s3plugrec *s3plug, unsigned int ns3plug,
156                      struct pda *pda);
157
158 static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
159                     struct s3crcrec *s3crc, unsigned int ns3crc);
160
161 static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
162                       unsigned int nfchunks);
163
164 static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks);
165
166 static void free_srecs(void);
167
168 static int validate_identity(void);
169
170 /*================================================================*/
171 /* Function Definitions */
172
173 /*----------------------------------------------------------------
174  * prism2_fwtry
175  *
176  * Try and get firmware into memory
177  *
178  * Arguments:
179  *      udev    usb device structure
180  *      wlandev wlan device structure
181  *
182  * Returns:
183  *      0       - success
184  *      ~0      - failure
185  *----------------------------------------------------------------
186  */
187 static int prism2_fwtry(struct usb_device *udev, struct wlandevice *wlandev)
188 {
189         const struct firmware *fw_entry = NULL;
190
191         netdev_info(wlandev->netdev, "prism2_usb: Checking for firmware %s\n",
192                     PRISM2_USB_FWFILE);
193         if (request_ihex_firmware(&fw_entry,
194                                   PRISM2_USB_FWFILE, &udev->dev) != 0) {
195                 netdev_info(wlandev->netdev,
196                             "prism2_usb: Firmware not available, but not essential\n");
197                 netdev_info(wlandev->netdev,
198                             "prism2_usb: can continue to use card anyway.\n");
199                 return 1;
200         }
201
202         netdev_info(wlandev->netdev,
203                     "prism2_usb: %s will be processed, size %zu\n",
204                     PRISM2_USB_FWFILE, fw_entry->size);
205         prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
206
207         release_firmware(fw_entry);
208         return 0;
209 }
210
211 /*----------------------------------------------------------------
212  * prism2_fwapply
213  *
214  * Apply the firmware loaded into memory
215  *
216  * Arguments:
217  *      rfptr   firmware image in kernel memory
218  *      wlandev device
219  *
220  * Returns:
221  *      0       - success
222  *      ~0      - failure
223  *----------------------------------------------------------------
224  */
225 static int prism2_fwapply(const struct ihex_binrec *rfptr,
226                           struct wlandevice *wlandev)
227 {
228         signed int result = 0;
229         struct p80211msg_dot11req_mibget getmsg;
230         struct p80211itemd *item;
231         u32 *data;
232
233         /* Initialize the data structures */
234         ns3data = 0;
235         s3data = kcalloc(S3DATA_MAX, sizeof(*s3data), GFP_KERNEL);
236         if (!s3data) {
237                 result = -ENOMEM;
238                 goto out;
239         }
240
241         ns3plug = 0;
242         memset(s3plug, 0, sizeof(s3plug));
243         ns3crc = 0;
244         memset(s3crc, 0, sizeof(s3crc));
245         ns3info = 0;
246         memset(s3info, 0, sizeof(s3info));
247         startaddr = 0;
248
249         nfchunks = 0;
250         memset(fchunk, 0, sizeof(fchunk));
251         memset(&nicid, 0, sizeof(nicid));
252         memset(&rfid, 0, sizeof(rfid));
253         memset(&macid, 0, sizeof(macid));
254         memset(&priid, 0, sizeof(priid));
255
256         /* clear the pda and add an initial END record */
257         memset(&pda, 0, sizeof(pda));
258         pda.rec[0] = (struct hfa384x_pdrec *)pda.buf;
259         pda.rec[0]->len = cpu_to_le16(2);       /* len in words */
260         pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
261         pda.nrec = 1;
262
263         /*-----------------------------------------------------*/
264         /* Put card into fwload state */
265         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
266
267         /* Build the PDA we're going to use. */
268         if (read_cardpda(&pda, wlandev)) {
269                 netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n");
270                 result = 1;
271                 goto out;
272         }
273
274         /* read the card's PRI-SUP */
275         memset(&getmsg, 0, sizeof(getmsg));
276         getmsg.msgcode = DIDMSG_DOT11REQ_MIBGET;
277         getmsg.msglen = sizeof(getmsg);
278         strscpy(getmsg.devname, wlandev->name, sizeof(getmsg.devname));
279
280         getmsg.mibattribute.did = DIDMSG_DOT11REQ_MIBGET_MIBATTRIBUTE;
281         getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
282         getmsg.resultcode.did = DIDMSG_DOT11REQ_MIBGET_RESULTCODE;
283         getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
284
285         item = (struct p80211itemd *)getmsg.mibattribute.data;
286         item->did = DIDMIB_P2_NIC_PRISUPRANGE;
287         item->status = P80211ENUM_msgitem_status_no_value;
288
289         data = (u32 *)item->data;
290
291         /* DIDmsg_dot11req_mibget */
292         prism2mgmt_mibset_mibget(wlandev, &getmsg);
293         if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
294                 netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n");
295
296         /* Already in host order */
297         priid.role = *data++;
298         priid.id = *data++;
299         priid.variant = *data++;
300         priid.bottom = *data++;
301         priid.top = *data++;
302
303         /* Read the S3 file */
304         result = read_fwfile(rfptr);
305         if (result) {
306                 netdev_err(wlandev->netdev,
307                            "Failed to read the data exiting.\n");
308                 goto out;
309         }
310
311         result = validate_identity();
312         if (result) {
313                 netdev_err(wlandev->netdev, "Incompatible firmware image.\n");
314                 goto out;
315         }
316
317         if (startaddr == 0x00000000) {
318                 netdev_err(wlandev->netdev,
319                            "Can't RAM download a Flash image!\n");
320                 result = 1;
321                 goto out;
322         }
323
324         /* Make the image chunks */
325         result = mkimage(fchunk, &nfchunks);
326         if (result) {
327                 netdev_err(wlandev->netdev, "Failed to make image chunk.\n");
328                 goto free_chunks;
329         }
330
331         /* Do any plugging */
332         result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
333         if (result) {
334                 netdev_err(wlandev->netdev, "Failed to plug data.\n");
335                 goto free_chunks;
336         }
337
338         /* Insert any CRCs */
339         result = crcimage(fchunk, nfchunks, s3crc, ns3crc);
340         if (result) {
341                 netdev_err(wlandev->netdev, "Failed to insert all CRCs\n");
342                 goto free_chunks;
343         }
344
345         /* Write the image */
346         result = writeimage(wlandev, fchunk, nfchunks);
347         if (result) {
348                 netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n");
349                 goto free_chunks;
350         }
351
352         netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n");
353
354 free_chunks:
355         /* clear any allocated memory */
356         free_chunks(fchunk, &nfchunks);
357         free_srecs();
358
359 out:
360         return result;
361 }
362
363 /*----------------------------------------------------------------
364  * crcimage
365  *
366  * Adds a CRC16 in the two bytes prior to each block identified by
367  * an S3 CRC record.  Currently, we don't actually do a CRC we just
368  * insert the value 0xC0DE in hfa384x order.
369  *
370  * Arguments:
371  *      fchunk          Array of image chunks
372  *      nfchunks        Number of image chunks
373  *      s3crc           Array of crc records
374  *      ns3crc          Number of crc records
375  *
376  * Returns:
377  *      0       success
378  *      ~0      failure
379  *----------------------------------------------------------------
380  */
381 static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
382                     struct s3crcrec *s3crc, unsigned int ns3crc)
383 {
384         int result = 0;
385         int i;
386         int c;
387         u32 crcstart;
388         u32 cstart = 0;
389         u32 cend;
390         u8 *dest;
391         u32 chunkoff;
392
393         for (i = 0; i < ns3crc; i++) {
394                 if (!s3crc[i].dowrite)
395                         continue;
396                 crcstart = s3crc[i].addr;
397                 /* Find chunk */
398                 for (c = 0; c < nfchunks; c++) {
399                         cstart = fchunk[c].addr;
400                         cend = fchunk[c].addr + fchunk[c].len;
401                         /* the line below does an address & len match search */
402                         /* unfortunately, I've found that the len fields of */
403                         /* some crc records don't match with the length of */
404                         /* the actual data, so we're not checking right now */
405                         /* if (crcstart-2 >= cstart && crcend <= cend) break; */
406
407                         /* note the -2 below, it's to make sure the chunk has */
408                         /* space for the CRC value */
409                         if (crcstart - 2 >= cstart && crcstart < cend)
410                                 break;
411                 }
412                 if (c >= nfchunks) {
413                         pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n",
414                                i, s3crc[i].addr, s3crc[i].len);
415                         return 1;
416                 }
417
418                 /* Insert crc */
419                 pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
420                 chunkoff = crcstart - cstart - 2;
421                 dest = fchunk[c].data + chunkoff;
422                 *dest = 0xde;
423                 *(dest + 1) = 0xc0;
424         }
425         return result;
426 }
427
428 /*----------------------------------------------------------------
429  * free_chunks
430  *
431  * Clears the chunklist data structures in preparation for a new file.
432  *
433  * Arguments:
434  *      none
435  *
436  * Returns:
437  *      nothing
438  *----------------------------------------------------------------
439  */
440 static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
441 {
442         int i;
443
444         for (i = 0; i < *nfchunks; i++)
445                 kfree(fchunk[i].data);
446
447         *nfchunks = 0;
448         memset(fchunk, 0, sizeof(*fchunk));
449 }
450
451 /*----------------------------------------------------------------
452  * free_srecs
453  *
454  * Clears the srec data structures in preparation for a new file.
455  *
456  * Arguments:
457  *      none
458  *
459  * Returns:
460  *      nothing
461  *----------------------------------------------------------------
462  */
463 static void free_srecs(void)
464 {
465         ns3data = 0;
466         kfree(s3data);
467         ns3plug = 0;
468         memset(s3plug, 0, sizeof(s3plug));
469         ns3crc = 0;
470         memset(s3crc, 0, sizeof(s3crc));
471         ns3info = 0;
472         memset(s3info, 0, sizeof(s3info));
473         startaddr = 0;
474 }
475
476 /*----------------------------------------------------------------
477  * mkimage
478  *
479  * Scans the currently loaded set of S records for data residing
480  * in contiguous memory regions.  Each contiguous region is then
481  * made into a 'chunk'.  This function assumes that we're building
482  * a new chunk list.  Assumes the s3data items are in sorted order.
483  *
484  * Arguments:   none
485  *
486  * Returns:
487  *      0       - success
488  *      ~0      - failure (probably an errno)
489  *----------------------------------------------------------------
490  */
491 static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
492 {
493         int result = 0;
494         int i;
495         int j;
496         int currchunk = 0;
497         u32 nextaddr = 0;
498         u32 s3start;
499         u32 s3end;
500         u32 cstart = 0;
501         u32 cend;
502         u32 coffset;
503
504         /* There may already be data in the chunklist */
505         *ccnt = 0;
506
507         /* Establish the location and size of each chunk */
508         for (i = 0; i < ns3data; i++) {
509                 if (s3data[i].addr == nextaddr) {
510                         /* existing chunk, grow it */
511                         clist[currchunk].len += s3data[i].len;
512                         nextaddr += s3data[i].len;
513                 } else {
514                         /* New chunk */
515                         (*ccnt)++;
516                         currchunk = *ccnt - 1;
517                         clist[currchunk].addr = s3data[i].addr;
518                         clist[currchunk].len = s3data[i].len;
519                         nextaddr = s3data[i].addr + s3data[i].len;
520                         /* Expand the chunk if there is a CRC record at */
521                         /* their beginning bound */
522                         for (j = 0; j < ns3crc; j++) {
523                                 if (s3crc[j].dowrite &&
524                                     s3crc[j].addr == clist[currchunk].addr) {
525                                         clist[currchunk].addr -= 2;
526                                         clist[currchunk].len += 2;
527                                 }
528                         }
529                 }
530         }
531
532         /* We're currently assuming there aren't any overlapping chunks */
533         /*  if this proves false, we'll need to add code to coalesce. */
534
535         /* Allocate buffer space for chunks */
536         for (i = 0; i < *ccnt; i++) {
537                 clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
538                 if (!clist[i].data)
539                         return 1;
540
541                 pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
542                          i, clist[i].addr, clist[i].len);
543         }
544
545         /* Copy srec data to chunks */
546         for (i = 0; i < ns3data; i++) {
547                 s3start = s3data[i].addr;
548                 s3end = s3start + s3data[i].len - 1;
549                 for (j = 0; j < *ccnt; j++) {
550                         cstart = clist[j].addr;
551                         cend = cstart + clist[j].len - 1;
552                         if (s3start >= cstart && s3end <= cend)
553                                 break;
554                 }
555                 if (((unsigned int)j) >= (*ccnt)) {
556                         pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
557                                s3start, s3data[i].len);
558                         return 1;
559                 }
560                 coffset = s3start - cstart;
561                 memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
562         }
563
564         return result;
565 }
566
567 /*----------------------------------------------------------------
568  * mkpdrlist
569  *
570  * Reads a raw PDA and builds an array of pdrec_t structures.
571  *
572  * Arguments:
573  *      pda     buffer containing raw PDA bytes
574  *      pdrec   ptr to an array of pdrec_t's.  Will be filled on exit.
575  *      nrec    ptr to a variable that will contain the count of PDRs
576  *
577  * Returns:
578  *      0       - success
579  *      ~0      - failure (probably an errno)
580  *----------------------------------------------------------------
581  */
582 static int mkpdrlist(struct pda *pda)
583 {
584         __le16 *pda16 = (__le16 *)pda->buf;
585         int curroff;            /* in 'words' */
586
587         pda->nrec = 0;
588         curroff = 0;
589         while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) &&
590                le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
591                 pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
592
593                 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
594                     HFA384x_PDR_NICID) {
595                         memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
596                                sizeof(nicid));
597                         le16_to_cpus(&nicid.id);
598                         le16_to_cpus(&nicid.variant);
599                         le16_to_cpus(&nicid.major);
600                         le16_to_cpus(&nicid.minor);
601                 }
602                 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
603                     HFA384x_PDR_MFISUPRANGE) {
604                         memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
605                                sizeof(rfid));
606                         le16_to_cpus(&rfid.id);
607                         le16_to_cpus(&rfid.variant);
608                         le16_to_cpus(&rfid.bottom);
609                         le16_to_cpus(&rfid.top);
610                 }
611                 if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
612                     HFA384x_PDR_CFISUPRANGE) {
613                         memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
614                                sizeof(macid));
615                         le16_to_cpus(&macid.id);
616                         le16_to_cpus(&macid.variant);
617                         le16_to_cpus(&macid.bottom);
618                         le16_to_cpus(&macid.top);
619                 }
620
621                 (pda->nrec)++;
622                 curroff += le16_to_cpu(pda16[curroff]) + 1;
623         }
624         if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) {
625                 pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n",
626                        curroff, pda->nrec);
627                 return 1;
628         }
629         pda->rec[pda->nrec] = (struct hfa384x_pdrec *)&pda16[curroff];
630         (pda->nrec)++;
631         return 0;
632 }
633
634 /*----------------------------------------------------------------
635  * plugimage
636  *
637  * Plugs the given image using the given plug records from the given
638  * PDA and filename.
639  *
640  * Arguments:
641  *      fchunk          Array of image chunks
642  *      nfchunks        Number of image chunks
643  *      s3plug          Array of plug records
644  *      ns3plug         Number of plug records
645  *      pda             Current pda data
646  *
647  * Returns:
648  *      0       success
649  *      ~0      failure
650  *----------------------------------------------------------------
651  */
652 static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks,
653                      struct s3plugrec *s3plug, unsigned int ns3plug,
654                      struct pda *pda)
655 {
656         int result = 0;
657         int i;                  /* plug index */
658         int j;                  /* index of PDR or -1 if fname plug */
659         int c;                  /* chunk index */
660         u32 pstart;
661         u32 pend;
662         u32 cstart = 0;
663         u32 cend;
664         u32 chunkoff;
665         u8 *dest;
666
667         /* for each plug record */
668         for (i = 0; i < ns3plug; i++) {
669                 pstart = s3plug[i].addr;
670                 pend = s3plug[i].addr + s3plug[i].len;
671                 j = -1;
672                 /* find the matching PDR (or filename) */
673                 if (s3plug[i].itemcode != 0xffffffffUL) { /* not filename */
674                         for (j = 0; j < pda->nrec; j++) {
675                                 if (s3plug[i].itemcode ==
676                                     le16_to_cpu(pda->rec[j]->code))
677                                         break;
678                         }
679                 }
680                 if (j >= pda->nrec && j != -1) { /*  if no matching PDR, fail */
681                         pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
682                                 s3plug[i].itemcode);
683                         continue;       /* and move on to the next PDR */
684
685                         /* MSM: They swear that unless it's the MAC address,
686                          * the serial number, or the TX calibration records,
687                          * then there's reasonable defaults in the f/w
688                          * image.  Therefore, missing PDRs in the card
689                          * should only be a warning, not fatal.
690                          * TODO: add fatals for the PDRs mentioned above.
691                          */
692                 }
693
694                 /* Validate plug len against PDR len */
695                 if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
696                         pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n",
697                                s3plug[i].itemcode);
698                         result = 1;
699                         continue;
700                 }
701
702                 /*
703                  * Validate plug address against
704                  * chunk data and identify chunk
705                  */
706                 for (c = 0; c < nfchunks; c++) {
707                         cstart = fchunk[c].addr;
708                         cend = fchunk[c].addr + fchunk[c].len;
709                         if (pstart >= cstart && pend <= cend)
710                                 break;
711                 }
712                 if (c >= nfchunks) {
713                         pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n",
714                                s3plug[i].itemcode);
715                         result = 1;
716                         continue;
717                 }
718
719                 /* Plug data */
720                 chunkoff = pstart - cstart;
721                 dest = fchunk[c].data + chunkoff;
722                 pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n",
723                          s3plug[i].itemcode, pstart, s3plug[i].len,
724                          c, chunkoff);
725
726                 if (j == -1) {  /* plug the filename */
727                         memset(dest, 0, s3plug[i].len);
728                         strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
729                 } else {        /* plug a PDR */
730                         memcpy(dest, &pda->rec[j]->data, s3plug[i].len);
731                 }
732         }
733         return result;
734 }
735
736 /*----------------------------------------------------------------
737  * read_cardpda
738  *
739  * Sends the command for the driver to read the pda from the card
740  * named in the device variable.  Upon success, the card pda is
741  * stored in the "cardpda" variables.  Note that the pda structure
742  * is considered 'well formed' after this function.  That means
743  * that the nrecs is valid, the rec array has been set up, and there's
744  * a valid PDAEND record in the raw PDA data.
745  *
746  * Arguments:
747  *      pda             pda structure
748  *      wlandev         device
749  *
750  * Returns:
751  *      0       - success
752  *      ~0      - failure (probably an errno)
753  *----------------------------------------------------------------
754  */
755 static int read_cardpda(struct pda *pda, struct wlandevice *wlandev)
756 {
757         int result = 0;
758         struct p80211msg_p2req_readpda *msg;
759
760         msg = kzalloc(sizeof(*msg), GFP_KERNEL);
761         if (!msg)
762                 return -ENOMEM;
763
764         /* set up the msg */
765         msg->msgcode = DIDMSG_P2REQ_READPDA;
766         msg->msglen = sizeof(msg);
767         strscpy(msg->devname, wlandev->name, sizeof(msg->devname));
768         msg->pda.did = DIDMSG_P2REQ_READPDA_PDA;
769         msg->pda.len = HFA384x_PDA_LEN_MAX;
770         msg->pda.status = P80211ENUM_msgitem_status_no_value;
771         msg->resultcode.did = DIDMSG_P2REQ_READPDA_RESULTCODE;
772         msg->resultcode.len = sizeof(u32);
773         msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
774
775         if (prism2mgmt_readpda(wlandev, msg) != 0) {
776                 /* prism2mgmt_readpda prints an errno if appropriate */
777                 result = -1;
778         } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
779                 memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
780                 result = mkpdrlist(pda);
781         } else {
782                 /* resultcode must've been something other than success */
783                 result = -1;
784         }
785
786         kfree(msg);
787         return result;
788 }
789
790 /*----------------------------------------------------------------
791  * read_fwfile
792  *
793  * Reads the given fw file which should have been compiled from an srec
794  * file. Each record in the fw file will either be a plain data record,
795  * a start address record, or other records used for plugging.
796  *
797  * Note that data records are expected to be sorted into
798  * ascending address order in the fw file.
799  *
800  * Note also that the start address record, originally an S7 record in
801  * the srec file, is expected in the fw file to be like a data record but
802  * with a certain address to make it identifiable.
803  *
804  * Here's the SREC format that the fw should have come from:
805  * S[37]nnaaaaaaaaddd...dddcc
806  *
807  *       nn - number of bytes starting with the address field
808  * aaaaaaaa - address in readable (or big endian) format
809  * dd....dd - 0-245 data bytes (two chars per byte)
810  *       cc - checksum
811  *
812  * The S7 record's (there should be only one) address value gets
813  * converted to an S3 record with address of 0xff400000, with the
814  * start address being stored as a 4 byte data word. That address is
815  * the start execution address used for RAM downloads.
816  *
817  * The S3 records have a collection of subformats indicated by the
818  * value of aaaaaaaa:
819  *   0xff000000 - Plug record, data field format:
820  *                xxxxxxxxaaaaaaaassssssss
821  *                x - PDR code number (little endian)
822  *                a - Address in load image to plug (little endian)
823  *                s - Length of plug data area (little endian)
824  *
825  *   0xff100000 - CRC16 generation record, data field format:
826  *                aaaaaaaassssssssbbbbbbbb
827  *                a - Start address for CRC calculation (little endian)
828  *                s - Length of data to  calculate over (little endian)
829  *                b - Boolean, true=write crc, false=don't write
830  *
831  *   0xff200000 - Info record, data field format:
832  *                ssssttttdd..dd
833  *                s - Size in words (little endian)
834  *                t - Info type (little endian), see #defines and
835  *                    struct s3inforec for details about types.
836  *                d - (s - 1) little endian words giving the contents of
837  *                    the given info type.
838  *
839  *   0xff400000 - Start address record, data field format:
840  *                aaaaaaaa
841  *                a - Address in load image to plug (little endian)
842  *
843  * Arguments:
844  *      record  firmware image (ihex record structure) in kernel memory
845  *
846  * Returns:
847  *      0       - success
848  *      ~0      - failure (probably an errno)
849  *----------------------------------------------------------------
850  */
851 static int read_fwfile(const struct ihex_binrec *record)
852 {
853         int             i;
854         int             rcnt = 0;
855         u16             *tmpinfo;
856         u16             *ptr16;
857         u32             *ptr32, len, addr;
858
859         pr_debug("Reading fw file ...\n");
860
861         while (record) {
862                 rcnt++;
863
864                 len = be16_to_cpu(record->len);
865                 addr = be32_to_cpu(record->addr);
866
867                 /* Point into data for different word lengths */
868                 ptr32 = (u32 *)record->data;
869                 ptr16 = (u16 *)record->data;
870
871                 /* parse what was an S3 srec and put it in the right array */
872                 switch (addr) {
873                 case S3ADDR_START:
874                         startaddr = *ptr32;
875                         pr_debug("  S7 start addr, record=%d addr=0x%08x\n",
876                                  rcnt,
877                                  startaddr);
878                         break;
879                 case S3ADDR_PLUG:
880                         s3plug[ns3plug].itemcode = *ptr32;
881                         s3plug[ns3plug].addr = *(ptr32 + 1);
882                         s3plug[ns3plug].len = *(ptr32 + 2);
883
884                         pr_debug("  S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n",
885                                  rcnt,
886                                  s3plug[ns3plug].itemcode,
887                                  s3plug[ns3plug].addr,
888                                  s3plug[ns3plug].len);
889
890                         ns3plug++;
891                         if (ns3plug == S3PLUG_MAX) {
892                                 pr_err("S3 plugrec limit reached - aborting\n");
893                                 return 1;
894                         }
895                         break;
896                 case S3ADDR_CRC:
897                         s3crc[ns3crc].addr = *ptr32;
898                         s3crc[ns3crc].len = *(ptr32 + 1);
899                         s3crc[ns3crc].dowrite = *(ptr32 + 2);
900
901                         pr_debug("  S3 crcrec, record=%d addr=0x%08x len=%d write=0x%08x\n",
902                                  rcnt,
903                                  s3crc[ns3crc].addr,
904                                  s3crc[ns3crc].len,
905                                  s3crc[ns3crc].dowrite);
906                         ns3crc++;
907                         if (ns3crc == S3CRC_MAX) {
908                                 pr_err("S3 crcrec limit reached - aborting\n");
909                                 return 1;
910                         }
911                         break;
912                 case S3ADDR_INFO:
913                         s3info[ns3info].len = *ptr16;
914                         s3info[ns3info].type = *(ptr16 + 1);
915
916                         pr_debug("  S3 inforec, record=%d len=0x%04x type=0x%04x\n",
917                                  rcnt,
918                                  s3info[ns3info].len,
919                                  s3info[ns3info].type);
920                         if (((s3info[ns3info].len - 1) * sizeof(u16)) >
921                            sizeof(s3info[ns3info].info)) {
922                                 pr_err("S3 inforec length too long - aborting\n");
923                                 return 1;
924                         }
925
926                         tmpinfo = (u16 *)&s3info[ns3info].info.version;
927                         pr_debug("            info=");
928                         for (i = 0; i < s3info[ns3info].len - 1; i++) {
929                                 tmpinfo[i] = *(ptr16 + 2 + i);
930                                 pr_debug("%04x ", tmpinfo[i]);
931                         }
932                         pr_debug("\n");
933
934                         ns3info++;
935                         if (ns3info == S3INFO_MAX) {
936                                 pr_err("S3 inforec limit reached - aborting\n");
937                                 return 1;
938                         }
939                         break;
940                 default:        /* Data record */
941                         s3data[ns3data].addr = addr;
942                         s3data[ns3data].len = len;
943                         s3data[ns3data].data = (uint8_t *)record->data;
944                         ns3data++;
945                         if (ns3data == S3DATA_MAX) {
946                                 pr_err("S3 datarec limit reached - aborting\n");
947                                 return 1;
948                         }
949                         break;
950                 }
951                 record = ihex_next_binrec(record);
952         }
953         return 0;
954 }
955
956 /*----------------------------------------------------------------
957  * writeimage
958  *
959  * Takes the chunks, builds p80211 messages and sends them down
960  * to the driver for writing to the card.
961  *
962  * Arguments:
963  *      wlandev         device
964  *      fchunk          Array of image chunks
965  *      nfchunks        Number of image chunks
966  *
967  * Returns:
968  *      0       success
969  *      ~0      failure
970  *----------------------------------------------------------------
971  */
972 static int writeimage(struct wlandevice *wlandev, struct imgchunk *fchunk,
973                       unsigned int nfchunks)
974 {
975         int result = 0;
976         struct p80211msg_p2req_ramdl_state *rstmsg;
977         struct p80211msg_p2req_ramdl_write *rwrmsg;
978         u32 resultcode;
979         int i;
980         int j;
981         unsigned int nwrites;
982         u32 curroff;
983         u32 currlen;
984         u32 currdaddr;
985
986         rstmsg = kzalloc(sizeof(*rstmsg), GFP_KERNEL);
987         rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL);
988         if (!rstmsg || !rwrmsg) {
989                 netdev_err(wlandev->netdev,
990                            "%s: no memory for firmware download, aborting download\n",
991                            __func__);
992                 result = -ENOMEM;
993                 goto free_result;
994         }
995
996         /* Initialize the messages */
997         strscpy(rstmsg->devname, wlandev->name, sizeof(rstmsg->devname));
998         rstmsg->msgcode = DIDMSG_P2REQ_RAMDL_STATE;
999         rstmsg->msglen = sizeof(*rstmsg);
1000         rstmsg->enable.did = DIDMSG_P2REQ_RAMDL_STATE_ENABLE;
1001         rstmsg->exeaddr.did = DIDMSG_P2REQ_RAMDL_STATE_EXEADDR;
1002         rstmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_STATE_RESULTCODE;
1003         rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
1004         rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
1005         rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1006         rstmsg->enable.len = sizeof(u32);
1007         rstmsg->exeaddr.len = sizeof(u32);
1008         rstmsg->resultcode.len = sizeof(u32);
1009
1010         strscpy(rwrmsg->devname, wlandev->name, sizeof(rwrmsg->devname));
1011         rwrmsg->msgcode = DIDMSG_P2REQ_RAMDL_WRITE;
1012         rwrmsg->msglen = sizeof(*rwrmsg);
1013         rwrmsg->addr.did = DIDMSG_P2REQ_RAMDL_WRITE_ADDR;
1014         rwrmsg->len.did = DIDMSG_P2REQ_RAMDL_WRITE_LEN;
1015         rwrmsg->data.did = DIDMSG_P2REQ_RAMDL_WRITE_DATA;
1016         rwrmsg->resultcode.did = DIDMSG_P2REQ_RAMDL_WRITE_RESULTCODE;
1017         rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
1018         rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
1019         rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
1020         rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1021         rwrmsg->addr.len = sizeof(u32);
1022         rwrmsg->len.len = sizeof(u32);
1023         rwrmsg->data.len = WRITESIZE_MAX;
1024         rwrmsg->resultcode.len = sizeof(u32);
1025
1026         /* Send xxx_state(enable) */
1027         pr_debug("Sending dl_state(enable) message.\n");
1028         rstmsg->enable.data = P80211ENUM_truth_true;
1029         rstmsg->exeaddr.data = startaddr;
1030
1031         result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1032         if (result) {
1033                 netdev_err(wlandev->netdev,
1034                            "%s state enable failed w/ result=%d, aborting download\n",
1035                            __func__, result);
1036                 goto free_result;
1037         }
1038         resultcode = rstmsg->resultcode.data;
1039         if (resultcode != P80211ENUM_resultcode_success) {
1040                 netdev_err(wlandev->netdev,
1041                            "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1042                            __func__, resultcode);
1043                 result = 1;
1044                 goto free_result;
1045         }
1046
1047         /* Now, loop through the data chunks and send WRITESIZE_MAX data */
1048         for (i = 0; i < nfchunks; i++) {
1049                 nwrites = fchunk[i].len / WRITESIZE_MAX;
1050                 nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1051                 curroff = 0;
1052                 for (j = 0; j < nwrites; j++) {
1053                         /* TODO Move this to a separate function */
1054                         int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
1055
1056                         if (fchunk[i].len > WRITESIZE_MAX)
1057                                 currlen = WRITESIZE_MAX;
1058                         else
1059                                 currlen = lenleft;
1060                         curroff = j * WRITESIZE_MAX;
1061                         currdaddr = fchunk[i].addr + curroff;
1062                         /* Setup the message */
1063                         rwrmsg->addr.data = currdaddr;
1064                         rwrmsg->len.data = currlen;
1065                         memcpy(rwrmsg->data.data,
1066                                fchunk[i].data + curroff, currlen);
1067
1068                         /* Send flashdl_write(pda) */
1069                         pr_debug
1070                             ("Sending xxxdl_write message addr=%06x len=%d.\n",
1071                              currdaddr, currlen);
1072
1073                         result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
1074
1075                         /* Check the results */
1076                         if (result) {
1077                                 netdev_err(wlandev->netdev,
1078                                            "%s chunk write failed w/ result=%d, aborting download\n",
1079                                            __func__, result);
1080                                 goto free_result;
1081                         }
1082                         resultcode = rstmsg->resultcode.data;
1083                         if (resultcode != P80211ENUM_resultcode_success) {
1084                                 pr_err("%s()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n",
1085                                        __func__, resultcode);
1086                                 result = 1;
1087                                 goto free_result;
1088                         }
1089                 }
1090         }
1091
1092         /* Send xxx_state(disable) */
1093         pr_debug("Sending dl_state(disable) message.\n");
1094         rstmsg->enable.data = P80211ENUM_truth_false;
1095         rstmsg->exeaddr.data = 0;
1096
1097         result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1098         if (result) {
1099                 netdev_err(wlandev->netdev,
1100                            "%s state disable failed w/ result=%d, aborting download\n",
1101                            __func__, result);
1102                 goto free_result;
1103         }
1104         resultcode = rstmsg->resultcode.data;
1105         if (resultcode != P80211ENUM_resultcode_success) {
1106                 netdev_err(wlandev->netdev,
1107                            "%s()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1108                            __func__, resultcode);
1109                 result = 1;
1110                 goto free_result;
1111         }
1112
1113 free_result:
1114         kfree(rstmsg);
1115         kfree(rwrmsg);
1116         return result;
1117 }
1118
1119 static int validate_identity(void)
1120 {
1121         int i;
1122         int result = 1;
1123         int trump = 0;
1124
1125         pr_debug("NIC ID: %#x v%d.%d.%d\n",
1126                  nicid.id, nicid.major, nicid.minor, nicid.variant);
1127         pr_debug("MFI ID: %#x v%d %d->%d\n",
1128                  rfid.id, rfid.variant, rfid.bottom, rfid.top);
1129         pr_debug("CFI ID: %#x v%d %d->%d\n",
1130                  macid.id, macid.variant, macid.bottom, macid.top);
1131         pr_debug("PRI ID: %#x v%d %d->%d\n",
1132                  priid.id, priid.variant, priid.bottom, priid.top);
1133
1134         for (i = 0; i < ns3info; i++) {
1135                 switch (s3info[i].type) {
1136                 case 1:
1137                         pr_debug("Version:  ID %#x %d.%d.%d\n",
1138                                  s3info[i].info.version.id,
1139                                  s3info[i].info.version.major,
1140                                  s3info[i].info.version.minor,
1141                                  s3info[i].info.version.variant);
1142                         break;
1143                 case 2:
1144                         pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1145                                  s3info[i].info.compat.role,
1146                                  s3info[i].info.compat.id,
1147                                  s3info[i].info.compat.variant,
1148                                  s3info[i].info.compat.bottom,
1149                                  s3info[i].info.compat.top);
1150
1151                         /* MAC compat range */
1152                         if ((s3info[i].info.compat.role == 1) &&
1153                             (s3info[i].info.compat.id == 2)) {
1154                                 if (s3info[i].info.compat.variant !=
1155                                     macid.variant) {
1156                                         result = 2;
1157                                 }
1158                         }
1159
1160                         /* PRI compat range */
1161                         if ((s3info[i].info.compat.role == 1) &&
1162                             (s3info[i].info.compat.id == 3)) {
1163                                 if ((s3info[i].info.compat.bottom >
1164                                      priid.top) ||
1165                                     (s3info[i].info.compat.top <
1166                                      priid.bottom)) {
1167                                         result = 3;
1168                                 }
1169                         }
1170                         /* SEC compat range */
1171                         if ((s3info[i].info.compat.role == 1) &&
1172                             (s3info[i].info.compat.id == 4)) {
1173                                 /* FIXME: isn't something missing here? */
1174                         }
1175
1176                         break;
1177                 case 3:
1178                         pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1179
1180                         break;
1181                 case 4:
1182                         pr_debug("Platform:  ID %#x %d.%d.%d\n",
1183                                  s3info[i].info.version.id,
1184                                  s3info[i].info.version.major,
1185                                  s3info[i].info.version.minor,
1186                                  s3info[i].info.version.variant);
1187
1188                         if (nicid.id != s3info[i].info.version.id)
1189                                 continue;
1190                         if (nicid.major != s3info[i].info.version.major)
1191                                 continue;
1192                         if (nicid.minor != s3info[i].info.version.minor)
1193                                 continue;
1194                         if ((nicid.variant != s3info[i].info.version.variant) &&
1195                             (nicid.id != 0x8008))
1196                                 continue;
1197
1198                         trump = 1;
1199                         break;
1200                 case 0x8001:
1201                         pr_debug("name inforec len %d\n", s3info[i].len);
1202
1203                         break;
1204                 default:
1205                         pr_debug("Unknown inforec type %d\n", s3info[i].type);
1206                 }
1207         }
1208         /* walk through */
1209
1210         if (trump && (result != 2))
1211                 result = 0;
1212         return result;
1213 }