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