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----------------------------------------------------------------*/
 204static int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev)
 205{
 206        const struct firmware *fw_entry = NULL;
 207
 208        netdev_info(wlandev->netdev, "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                netdev_info(wlandev->netdev,
 213                       "prism2_usb: Firmware not available, but not essential\n");
 214                netdev_info(wlandev->netdev,
 215                       "prism2_usb: can continue to use card anyway.\n");
 216                return 1;
 217        }
 218
 219        netdev_info(wlandev->netdev,
 220                    "prism2_usb: %s will be processed, size %zu\n",
 221                    PRISM2_USB_FWFILE, fw_entry->size);
 222        prism2_fwapply((const struct ihex_binrec *)fw_entry->data, wlandev);
 223
 224        release_firmware(fw_entry);
 225        return 0;
 226}
 227
 228/*----------------------------------------------------------------
 229* prism2_fwapply
 230*
 231* Apply the firmware loaded into memory
 232*
 233* Arguments:
 234*       rfptr   firmware image in kernel memory
 235*       wlandev device
 236*
 237* Returns:
 238*       0       - success
 239*       ~0      - failure
 240----------------------------------------------------------------*/
 241static int prism2_fwapply(const struct ihex_binrec *rfptr,
 242                          wlandevice_t *wlandev)
 243{
 244        signed int result = 0;
 245        struct p80211msg_dot11req_mibget getmsg;
 246        p80211itemd_t *item;
 247        u32 *data;
 248
 249        /* Initialize the data structures */
 250        ns3data = 0;
 251        memset(s3data, 0, sizeof(s3data));
 252        ns3plug = 0;
 253        memset(s3plug, 0, sizeof(s3plug));
 254        ns3crc = 0;
 255        memset(s3crc, 0, sizeof(s3crc));
 256        ns3info = 0;
 257        memset(s3info, 0, sizeof(s3info));
 258        startaddr = 0;
 259
 260        nfchunks = 0;
 261        memset(fchunk, 0, sizeof(fchunk));
 262        memset(&nicid, 0, sizeof(nicid));
 263        memset(&rfid, 0, sizeof(rfid));
 264        memset(&macid, 0, sizeof(macid));
 265        memset(&priid, 0, sizeof(priid));
 266
 267        /* clear the pda and add an initial END record */
 268        memset(&pda, 0, sizeof(pda));
 269        pda.rec[0] = (hfa384x_pdrec_t *) pda.buf;
 270        pda.rec[0]->len = cpu_to_le16(2);       /* len in words */
 271        pda.rec[0]->code = cpu_to_le16(HFA384x_PDR_END_OF_PDA);
 272        pda.nrec = 1;
 273
 274        /*-----------------------------------------------------*/
 275        /* Put card into fwload state */
 276        prism2sta_ifstate(wlandev, P80211ENUM_ifstate_fwload);
 277
 278        /* Build the PDA we're going to use. */
 279        if (read_cardpda(&pda, wlandev)) {
 280                netdev_err(wlandev->netdev, "load_cardpda failed, exiting.\n");
 281                return 1;
 282        }
 283
 284        /* read the card's PRI-SUP */
 285        memset(&getmsg, 0, sizeof(getmsg));
 286        getmsg.msgcode = DIDmsg_dot11req_mibget;
 287        getmsg.msglen = sizeof(getmsg);
 288        strcpy(getmsg.devname, wlandev->name);
 289
 290        getmsg.mibattribute.did = DIDmsg_dot11req_mibget_mibattribute;
 291        getmsg.mibattribute.status = P80211ENUM_msgitem_status_data_ok;
 292        getmsg.resultcode.did = DIDmsg_dot11req_mibget_resultcode;
 293        getmsg.resultcode.status = P80211ENUM_msgitem_status_no_value;
 294
 295        item = (p80211itemd_t *) getmsg.mibattribute.data;
 296        item->did = DIDmib_p2_p2NIC_p2PRISupRange;
 297        item->status = P80211ENUM_msgitem_status_no_value;
 298
 299        data = (u32 *) item->data;
 300
 301        /* DIDmsg_dot11req_mibget */
 302        prism2mgmt_mibset_mibget(wlandev, &getmsg);
 303        if (getmsg.resultcode.data != P80211ENUM_resultcode_success)
 304                netdev_err(wlandev->netdev, "Couldn't fetch PRI-SUP info\n");
 305
 306        /* Already in host order */
 307        priid.role = *data++;
 308        priid.id = *data++;
 309        priid.variant = *data++;
 310        priid.bottom = *data++;
 311        priid.top = *data++;
 312
 313        /* Read the S3 file */
 314        result = read_fwfile(rfptr);
 315        if (result) {
 316                netdev_err(wlandev->netdev,
 317                           "Failed to read the data exiting.\n");
 318                return 1;
 319        }
 320
 321        result = validate_identity();
 322
 323        if (result) {
 324                netdev_err(wlandev->netdev, "Incompatible firmware image.\n");
 325                return 1;
 326        }
 327
 328        if (startaddr == 0x00000000) {
 329                netdev_err(wlandev->netdev,
 330                           "Can't RAM download a Flash image!\n");
 331                return 1;
 332        }
 333
 334        /* Make the image chunks */
 335        result = mkimage(fchunk, &nfchunks);
 336        if (result) {
 337                netdev_err(wlandev->netdev, "Failed to make image chunk.\n");
 338                return 1;
 339        }
 340
 341        /* Do any plugging */
 342        result = plugimage(fchunk, nfchunks, s3plug, ns3plug, &pda);
 343        if (result) {
 344                netdev_err(wlandev->netdev, "Failed to plug data.\n");
 345                return 1;
 346        }
 347
 348        /* Insert any CRCs */
 349        if (crcimage(fchunk, nfchunks, s3crc, ns3crc)) {
 350                netdev_err(wlandev->netdev, "Failed to insert all CRCs\n");
 351                return 1;
 352        }
 353
 354        /* Write the image */
 355        result = writeimage(wlandev, fchunk, nfchunks);
 356        if (result) {
 357                netdev_err(wlandev->netdev, "Failed to ramwrite image data.\n");
 358                return 1;
 359        }
 360
 361        /* clear any allocated memory */
 362        free_chunks(fchunk, &nfchunks);
 363        free_srecs();
 364
 365        netdev_info(wlandev->netdev, "prism2_usb: firmware loading finished.\n");
 366
 367        return result;
 368}
 369
 370/*----------------------------------------------------------------
 371* crcimage
 372*
 373* Adds a CRC16 in the two bytes prior to each block identified by
 374* an S3 CRC record.  Currently, we don't actually do a CRC we just
 375* insert the value 0xC0DE in hfa384x order.
 376*
 377* Arguments:
 378*       fchunk          Array of image chunks
 379*       nfchunks        Number of image chunks
 380*       s3crc           Array of crc records
 381*       ns3crc          Number of crc records
 382*
 383* Returns:
 384*       0       success
 385*       ~0      failure
 386----------------------------------------------------------------*/
 387static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks,
 388             struct s3crcrec *s3crc, unsigned int ns3crc)
 389{
 390        int result = 0;
 391        int i;
 392        int c;
 393        u32 crcstart;
 394        u32 crcend;
 395        u32 cstart = 0;
 396        u32 cend;
 397        u8 *dest;
 398        u32 chunkoff;
 399
 400        for (i = 0; i < ns3crc; i++) {
 401                if (!s3crc[i].dowrite)
 402                        continue;
 403                crcstart = s3crc[i].addr;
 404                crcend = s3crc[i].addr + s3crc[i].len;
 405                /* Find chunk */
 406                for (c = 0; c < nfchunks; c++) {
 407                        cstart = fchunk[c].addr;
 408                        cend = fchunk[c].addr + fchunk[c].len;
 409                        /* the line below does an address & len match search */
 410                        /* unfortunately, I've found that the len fields of */
 411                        /* some crc records don't match with the length of */
 412                        /* the actual data, so we're not checking right now */
 413                        /* if (crcstart-2 >= cstart && crcend <= cend) break; */
 414
 415                        /* note the -2 below, it's to make sure the chunk has */
 416                        /* space for the CRC value */
 417                        if (crcstart - 2 >= cstart && crcstart < cend)
 418                                break;
 419                }
 420                if (c >= nfchunks) {
 421                        pr_err("Failed to find chunk for crcrec[%d], addr=0x%06x len=%d , aborting crc.\n",
 422                               i, s3crc[i].addr, s3crc[i].len);
 423                        return 1;
 424                }
 425
 426                /* Insert crc */
 427                pr_debug("Adding crc @ 0x%06x\n", s3crc[i].addr - 2);
 428                chunkoff = crcstart - cstart - 2;
 429                dest = fchunk[c].data + chunkoff;
 430                *dest = 0xde;
 431                *(dest + 1) = 0xc0;
 432
 433        }
 434        return result;
 435}
 436
 437/*----------------------------------------------------------------
 438* free_chunks
 439*
 440* Clears the chunklist data structures in preparation for a new file.
 441*
 442* Arguments:
 443*       none
 444*
 445* Returns:
 446*       nothing
 447----------------------------------------------------------------*/
 448static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks)
 449{
 450        int i;
 451
 452        for (i = 0; i < *nfchunks; i++)
 453                kfree(fchunk[i].data);
 454
 455        *nfchunks = 0;
 456        memset(fchunk, 0, sizeof(*fchunk));
 457
 458}
 459
 460/*----------------------------------------------------------------
 461* free_srecs
 462*
 463* Clears the srec data structures in preparation for a new file.
 464*
 465* Arguments:
 466*       none
 467*
 468* Returns:
 469*       nothing
 470----------------------------------------------------------------*/
 471static void free_srecs(void)
 472{
 473        ns3data = 0;
 474        memset(s3data, 0, sizeof(s3data));
 475        ns3plug = 0;
 476        memset(s3plug, 0, sizeof(s3plug));
 477        ns3crc = 0;
 478        memset(s3crc, 0, sizeof(s3crc));
 479        ns3info = 0;
 480        memset(s3info, 0, sizeof(s3info));
 481        startaddr = 0;
 482}
 483
 484/*----------------------------------------------------------------
 485* mkimage
 486*
 487* Scans the currently loaded set of S records for data residing
 488* in contiguous memory regions.  Each contiguous region is then
 489* made into a 'chunk'.  This function assumes that we're building
 490* a new chunk list.  Assumes the s3data items are in sorted order.
 491*
 492* Arguments:    none
 493*
 494* Returns:
 495*       0       - success
 496*       ~0      - failure (probably an errno)
 497----------------------------------------------------------------*/
 498static int mkimage(struct imgchunk *clist, unsigned int *ccnt)
 499{
 500        int result = 0;
 501        int i;
 502        int j;
 503        int currchunk = 0;
 504        u32 nextaddr = 0;
 505        u32 s3start;
 506        u32 s3end;
 507        u32 cstart = 0;
 508        u32 cend;
 509        u32 coffset;
 510
 511        /* There may already be data in the chunklist */
 512        *ccnt = 0;
 513
 514        /* Establish the location and size of each chunk */
 515        for (i = 0; i < ns3data; i++) {
 516                if (s3data[i].addr == nextaddr) {
 517                        /* existing chunk, grow it */
 518                        clist[currchunk].len += s3data[i].len;
 519                        nextaddr += s3data[i].len;
 520                } else {
 521                        /* New chunk */
 522                        (*ccnt)++;
 523                        currchunk = *ccnt - 1;
 524                        clist[currchunk].addr = s3data[i].addr;
 525                        clist[currchunk].len = s3data[i].len;
 526                        nextaddr = s3data[i].addr + s3data[i].len;
 527                        /* Expand the chunk if there is a CRC record at */
 528                        /* their beginning bound */
 529                        for (j = 0; j < ns3crc; j++) {
 530                                if (s3crc[j].dowrite &&
 531                                    s3crc[j].addr == clist[currchunk].addr) {
 532                                        clist[currchunk].addr -= 2;
 533                                        clist[currchunk].len += 2;
 534                                }
 535                        }
 536                }
 537        }
 538
 539        /* We're currently assuming there aren't any overlapping chunks */
 540        /*  if this proves false, we'll need to add code to coalesce. */
 541
 542        /* Allocate buffer space for chunks */
 543        for (i = 0; i < *ccnt; i++) {
 544                clist[i].data = kzalloc(clist[i].len, GFP_KERNEL);
 545                if (!clist[i].data) {
 546                        pr_err("failed to allocate image space, exitting.\n");
 547                        return 1;
 548                }
 549                pr_debug("chunk[%d]: addr=0x%06x len=%d\n",
 550                         i, clist[i].addr, clist[i].len);
 551        }
 552
 553        /* Copy srec data to chunks */
 554        for (i = 0; i < ns3data; i++) {
 555                s3start = s3data[i].addr;
 556                s3end = s3start + s3data[i].len - 1;
 557                for (j = 0; j < *ccnt; j++) {
 558                        cstart = clist[j].addr;
 559                        cend = cstart + clist[j].len - 1;
 560                        if (s3start >= cstart && s3end <= cend)
 561                                break;
 562                }
 563                if (((unsigned int)j) >= (*ccnt)) {
 564                        pr_err("s3rec(a=0x%06x,l=%d), no chunk match, exiting.\n",
 565                               s3start, s3data[i].len);
 566                        return 1;
 567                }
 568                coffset = s3start - cstart;
 569                memcpy(clist[j].data + coffset, s3data[i].data, s3data[i].len);
 570        }
 571
 572        return result;
 573}
 574
 575/*----------------------------------------------------------------
 576* mkpdrlist
 577*
 578* Reads a raw PDA and builds an array of pdrec_t structures.
 579*
 580* Arguments:
 581*       pda     buffer containing raw PDA bytes
 582*       pdrec   ptr to an array of pdrec_t's.  Will be filled on exit.
 583*       nrec    ptr to a variable that will contain the count of PDRs
 584*
 585* Returns:
 586*       0       - success
 587*       ~0      - failure (probably an errno)
 588----------------------------------------------------------------*/
 589static int mkpdrlist(struct pda *pda)
 590{
 591        u16 *pda16 = (u16 *) pda->buf;
 592        int curroff;            /* in 'words' */
 593
 594        pda->nrec = 0;
 595        curroff = 0;
 596        while (curroff < (HFA384x_PDA_LEN_MAX / 2 - 1) &&
 597               le16_to_cpu(pda16[curroff + 1]) != HFA384x_PDR_END_OF_PDA) {
 598                pda->rec[pda->nrec] = (hfa384x_pdrec_t *) &(pda16[curroff]);
 599
 600                if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
 601                    HFA384x_PDR_NICID) {
 602                        memcpy(&nicid, &pda->rec[pda->nrec]->data.nicid,
 603                               sizeof(nicid));
 604                        nicid.id = le16_to_cpu(nicid.id);
 605                        nicid.variant = le16_to_cpu(nicid.variant);
 606                        nicid.major = le16_to_cpu(nicid.major);
 607                        nicid.minor = le16_to_cpu(nicid.minor);
 608                }
 609                if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
 610                    HFA384x_PDR_MFISUPRANGE) {
 611                        memcpy(&rfid, &pda->rec[pda->nrec]->data.mfisuprange,
 612                               sizeof(rfid));
 613                        rfid.id = le16_to_cpu(rfid.id);
 614                        rfid.variant = le16_to_cpu(rfid.variant);
 615                        rfid.bottom = le16_to_cpu(rfid.bottom);
 616                        rfid.top = le16_to_cpu(rfid.top);
 617                }
 618                if (le16_to_cpu(pda->rec[pda->nrec]->code) ==
 619                    HFA384x_PDR_CFISUPRANGE) {
 620                        memcpy(&macid, &pda->rec[pda->nrec]->data.cfisuprange,
 621                               sizeof(macid));
 622                        macid.id = le16_to_cpu(macid.id);
 623                        macid.variant = le16_to_cpu(macid.variant);
 624                        macid.bottom = le16_to_cpu(macid.bottom);
 625                        macid.top = le16_to_cpu(macid.top);
 626                }
 627
 628                (pda->nrec)++;
 629                curroff += le16_to_cpu(pda16[curroff]) + 1;
 630
 631        }
 632        if (curroff >= (HFA384x_PDA_LEN_MAX / 2 - 1)) {
 633                pr_err("no end record found or invalid lengths in PDR data, exiting. %x %d\n",
 634                       curroff, pda->nrec);
 635                return 1;
 636        }
 637        pda->rec[pda->nrec] = (hfa384x_pdrec_t *) &(pda16[curroff]);
 638        (pda->nrec)++;
 639        return 0;
 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                        pr_warn("warning: Failed to find PDR for plugrec 0x%04x.\n",
 689                                s3plug[i].itemcode);
 690                        continue;       /* and move on to the next PDR */
 691#if 0
 692                        /* MSM: They swear that unless it's the MAC address,
 693                         * the serial number, or the TX calibration records,
 694                         * then there's reasonable defaults in the f/w
 695                         * image.  Therefore, missing PDRs in the card
 696                         * should only be a warning, not fatal.
 697                         * TODO: add fatals for the PDRs mentioned above.
 698                         */
 699                        result = 1;
 700                        continue;
 701#endif
 702                }
 703
 704                /* Validate plug len against PDR len */
 705                if (j != -1 && s3plug[i].len < le16_to_cpu(pda->rec[j]->len)) {
 706                        pr_err("error: Plug vs. PDR len mismatch for plugrec 0x%04x, abort plugging.\n",
 707                               s3plug[i].itemcode);
 708                        result = 1;
 709                        continue;
 710                }
 711
 712                /*
 713                 * Validate plug address against
 714                 * chunk data and identify chunk
 715                 */
 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                        pr_err("error: Failed to find image chunk for plugrec 0x%04x.\n",
 724                               s3plug[i].itemcode);
 725                        result = 1;
 726                        continue;
 727                }
 728
 729                /* Plug data */
 730                chunkoff = pstart - cstart;
 731                dest = fchunk[c].data + chunkoff;
 732                pr_debug("Plugging item 0x%04x @ 0x%06x, len=%d, cnum=%d coff=0x%06x\n",
 733                         s3plug[i].itemcode, pstart, s3plug[i].len,
 734                         c, chunkoff);
 735
 736                if (j == -1) {  /* plug the filename */
 737                        memset(dest, 0, s3plug[i].len);
 738                        strncpy(dest, PRISM2_USB_FWFILE, s3plug[i].len - 1);
 739                } else {        /* plug a PDR */
 740                        memcpy(dest, &(pda->rec[j]->data), s3plug[i].len);
 741                }
 742        }
 743        return result;
 744
 745}
 746
 747/*----------------------------------------------------------------
 748* read_cardpda
 749*
 750* Sends the command for the driver to read the pda from the card
 751* named in the device variable.  Upon success, the card pda is
 752* stored in the "cardpda" variables.  Note that the pda structure
 753* is considered 'well formed' after this function.  That means
 754* that the nrecs is valid, the rec array has been set up, and there's
 755* a valid PDAEND record in the raw PDA data.
 756*
 757* Arguments:
 758*       pda             pda structure
 759*       wlandev         device
 760*
 761* Returns:
 762*       0       - success
 763*       ~0      - failure (probably an errno)
 764----------------------------------------------------------------*/
 765static int read_cardpda(struct pda *pda, wlandevice_t *wlandev)
 766{
 767        int result = 0;
 768        struct p80211msg_p2req_readpda *msg;
 769
 770        msg = kzalloc(sizeof(*msg), GFP_KERNEL);
 771        if (!msg)
 772                return -ENOMEM;
 773
 774        /* set up the msg */
 775        msg->msgcode = DIDmsg_p2req_readpda;
 776        msg->msglen = sizeof(msg);
 777        strcpy(msg->devname, wlandev->name);
 778        msg->pda.did = DIDmsg_p2req_readpda_pda;
 779        msg->pda.len = HFA384x_PDA_LEN_MAX;
 780        msg->pda.status = P80211ENUM_msgitem_status_no_value;
 781        msg->resultcode.did = DIDmsg_p2req_readpda_resultcode;
 782        msg->resultcode.len = sizeof(u32);
 783        msg->resultcode.status = P80211ENUM_msgitem_status_no_value;
 784
 785        if (prism2mgmt_readpda(wlandev, msg) != 0) {
 786                /* prism2mgmt_readpda prints an errno if appropriate */
 787                result = -1;
 788        } else if (msg->resultcode.data == P80211ENUM_resultcode_success) {
 789                memcpy(pda->buf, msg->pda.data, HFA384x_PDA_LEN_MAX);
 790                result = mkpdrlist(pda);
 791        } else {
 792                /* resultcode must've been something other than success */
 793                result = -1;
 794        }
 795
 796        kfree(msg);
 797        return result;
 798}
 799
 800/*----------------------------------------------------------------
 801* read_fwfile
 802*
 803* Reads the given fw file which should have been compiled from an srec
 804* file. Each record in the fw file will either be a plain data record,
 805* a start address record, or other records used for plugging.
 806*
 807* Note that data records are expected to be sorted into
 808* ascending address order in the fw file.
 809*
 810* Note also that the start address record, originally an S7 record in
 811* the srec file, is expected in the fw file to be like a data record but
 812* with a certain address to make it identifiable.
 813*
 814* Here's the SREC format that the fw should have come from:
 815* S[37]nnaaaaaaaaddd...dddcc
 816*
 817*       nn - number of bytes starting with the address field
 818* aaaaaaaa - address in readable (or big endian) format
 819* dd....dd - 0-245 data bytes (two chars per byte)
 820*       cc - checksum
 821*
 822* The S7 record's (there should be only one) address value gets
 823* converted to an S3 record with address of 0xff400000, with the
 824* start address being stored as a 4 byte data word. That address is
 825* the start execution address used for RAM downloads.
 826*
 827* The S3 records have a collection of subformats indicated by the
 828* value of aaaaaaaa:
 829*   0xff000000 - Plug record, data field format:
 830*                xxxxxxxxaaaaaaaassssssss
 831*                x - PDR code number (little endian)
 832*                a - Address in load image to plug (little endian)
 833*                s - Length of plug data area (little endian)
 834*
 835*   0xff100000 - CRC16 generation record, data field format:
 836*                aaaaaaaassssssssbbbbbbbb
 837*                a - Start address for CRC calculation (little endian)
 838*                s - Length of data to  calculate over (little endian)
 839*                b - Boolean, true=write crc, false=don't write
 840*
 841*   0xff200000 - Info record, data field format:
 842*                ssssttttdd..dd
 843*                s - Size in words (little endian)
 844*                t - Info type (little endian), see #defines and
 845*                    struct s3inforec for details about types.
 846*                d - (s - 1) little endian words giving the contents of
 847*                    the given info type.
 848*
 849*   0xff400000 - Start address record, data field format:
 850*                aaaaaaaa
 851*                a - Address in load image to plug (little endian)
 852*
 853* Arguments:
 854*       record  firmware image (ihex record structure) in kernel memory
 855*
 856* Returns:
 857*       0       - success
 858*       ~0      - failure (probably an errno)
 859----------------------------------------------------------------*/
 860static int read_fwfile(const struct ihex_binrec *record)
 861{
 862        int             i;
 863        int             rcnt = 0;
 864        u16             *tmpinfo;
 865        u16             *ptr16;
 866        u32             *ptr32, len, addr;
 867
 868        pr_debug("Reading fw file ...\n");
 869
 870        while (record) {
 871
 872                rcnt++;
 873
 874                len = be16_to_cpu(record->len);
 875                addr = be32_to_cpu(record->addr);
 876
 877                /* Point into data for different word lengths */
 878                ptr32 = (u32 *) record->data;
 879                ptr16 = (u16 *) record->data;
 880
 881                /* parse what was an S3 srec and put it in the right array */
 882                switch (addr) {
 883                case S3ADDR_START:
 884                        startaddr = *ptr32;
 885                        pr_debug("  S7 start addr, record=%d addr=0x%08x\n",
 886                                      rcnt,
 887                                      startaddr);
 888                        break;
 889                case S3ADDR_PLUG:
 890                        s3plug[ns3plug].itemcode = *ptr32;
 891                        s3plug[ns3plug].addr = *(ptr32 + 1);
 892                        s3plug[ns3plug].len = *(ptr32 + 2);
 893
 894                        pr_debug("  S3 plugrec, record=%d itemcode=0x%08x addr=0x%08x len=%d\n",
 895                                      rcnt,
 896                                      s3plug[ns3plug].itemcode,
 897                                      s3plug[ns3plug].addr,
 898                                      s3plug[ns3plug].len);
 899
 900                        ns3plug++;
 901                        if (ns3plug == S3PLUG_MAX) {
 902                                pr_err("S3 plugrec limit reached - aborting\n");
 903                                return 1;
 904                        }
 905                        break;
 906                case S3ADDR_CRC:
 907                        s3crc[ns3crc].addr = *ptr32;
 908                        s3crc[ns3crc].len = *(ptr32 + 1);
 909                        s3crc[ns3crc].dowrite = *(ptr32 + 2);
 910
 911                        pr_debug("  S3 crcrec, record=%d 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                                pr_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 len=0x%04x type=0x%04x\n",
 927                                      rcnt,
 928                                      s3info[ns3info].len,
 929                                      s3info[ns3info].type);
 930                        if (((s3info[ns3info].len - 1) * sizeof(u16)) >
 931                           sizeof(s3info[ns3info].info)) {
 932                                pr_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                                pr_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                                pr_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 = kzalloc(sizeof(*rstmsg), GFP_KERNEL);
 996        rwrmsg = kzalloc(sizeof(*rwrmsg), GFP_KERNEL);
 997        if (!rstmsg || !rwrmsg) {
 998                kfree(rstmsg);
 999                kfree(rwrmsg);
1000                netdev_err(wlandev->netdev,
1001                           "writeimage: no memory for firmware download, aborting download\n");
1002                return -ENOMEM;
1003        }
1004
1005        /* Initialize the messages */
1006        strcpy(rstmsg->devname, wlandev->name);
1007        rstmsg->msgcode = DIDmsg_p2req_ramdl_state;
1008        rstmsg->msglen = sizeof(*rstmsg);
1009        rstmsg->enable.did = DIDmsg_p2req_ramdl_state_enable;
1010        rstmsg->exeaddr.did = DIDmsg_p2req_ramdl_state_exeaddr;
1011        rstmsg->resultcode.did = DIDmsg_p2req_ramdl_state_resultcode;
1012        rstmsg->enable.status = P80211ENUM_msgitem_status_data_ok;
1013        rstmsg->exeaddr.status = P80211ENUM_msgitem_status_data_ok;
1014        rstmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1015        rstmsg->enable.len = sizeof(u32);
1016        rstmsg->exeaddr.len = sizeof(u32);
1017        rstmsg->resultcode.len = sizeof(u32);
1018
1019        strcpy(rwrmsg->devname, wlandev->name);
1020        rwrmsg->msgcode = DIDmsg_p2req_ramdl_write;
1021        rwrmsg->msglen = sizeof(*rwrmsg);
1022        rwrmsg->addr.did = DIDmsg_p2req_ramdl_write_addr;
1023        rwrmsg->len.did = DIDmsg_p2req_ramdl_write_len;
1024        rwrmsg->data.did = DIDmsg_p2req_ramdl_write_data;
1025        rwrmsg->resultcode.did = DIDmsg_p2req_ramdl_write_resultcode;
1026        rwrmsg->addr.status = P80211ENUM_msgitem_status_data_ok;
1027        rwrmsg->len.status = P80211ENUM_msgitem_status_data_ok;
1028        rwrmsg->data.status = P80211ENUM_msgitem_status_data_ok;
1029        rwrmsg->resultcode.status = P80211ENUM_msgitem_status_no_value;
1030        rwrmsg->addr.len = sizeof(u32);
1031        rwrmsg->len.len = sizeof(u32);
1032        rwrmsg->data.len = WRITESIZE_MAX;
1033        rwrmsg->resultcode.len = sizeof(u32);
1034
1035        /* Send xxx_state(enable) */
1036        pr_debug("Sending dl_state(enable) message.\n");
1037        rstmsg->enable.data = P80211ENUM_truth_true;
1038        rstmsg->exeaddr.data = startaddr;
1039
1040        result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1041        if (result) {
1042                netdev_err(wlandev->netdev,
1043                           "writeimage state enable failed w/ result=%d, aborting download\n",
1044                           result);
1045                goto free_result;
1046        }
1047        resultcode = rstmsg->resultcode.data;
1048        if (resultcode != P80211ENUM_resultcode_success) {
1049                netdev_err(wlandev->netdev,
1050                           "writeimage()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1051                           resultcode);
1052                result = 1;
1053                goto free_result;
1054        }
1055
1056        /* Now, loop through the data chunks and send WRITESIZE_MAX data */
1057        for (i = 0; i < nfchunks; i++) {
1058                nwrites = fchunk[i].len / WRITESIZE_MAX;
1059                nwrites += (fchunk[i].len % WRITESIZE_MAX) ? 1 : 0;
1060                curroff = 0;
1061                for (j = 0; j < nwrites; j++) {
1062                        /* TODO Move this to a separate function */
1063                        int lenleft = fchunk[i].len - (WRITESIZE_MAX * j);
1064
1065                        if (fchunk[i].len > WRITESIZE_MAX)
1066                                currlen = WRITESIZE_MAX;
1067                        else
1068                                currlen = lenleft;
1069                        curroff = j * WRITESIZE_MAX;
1070                        currdaddr = fchunk[i].addr + curroff;
1071                        /* Setup the message */
1072                        rwrmsg->addr.data = currdaddr;
1073                        rwrmsg->len.data = currlen;
1074                        memcpy(rwrmsg->data.data,
1075                               fchunk[i].data + curroff, currlen);
1076
1077                        /* Send flashdl_write(pda) */
1078                        pr_debug
1079                            ("Sending xxxdl_write message addr=%06x len=%d.\n",
1080                             currdaddr, currlen);
1081
1082                        result = prism2mgmt_ramdl_write(wlandev, rwrmsg);
1083
1084                        /* Check the results */
1085                        if (result) {
1086                                netdev_err(wlandev->netdev,
1087                                           "writeimage chunk write failed w/ result=%d, aborting download\n",
1088                                           result);
1089                                goto free_result;
1090                        }
1091                        resultcode = rstmsg->resultcode.data;
1092                        if (resultcode != P80211ENUM_resultcode_success) {
1093                                pr_err("writeimage()->xxxdl_write msg indicates failure, w/ resultcode=%d, aborting download.\n",
1094                                       resultcode);
1095                                result = 1;
1096                                goto free_result;
1097                        }
1098
1099                }
1100        }
1101
1102        /* Send xxx_state(disable) */
1103        pr_debug("Sending dl_state(disable) message.\n");
1104        rstmsg->enable.data = P80211ENUM_truth_false;
1105        rstmsg->exeaddr.data = 0;
1106
1107        result = prism2mgmt_ramdl_state(wlandev, rstmsg);
1108        if (result) {
1109                netdev_err(wlandev->netdev,
1110                           "writeimage state disable failed w/ result=%d, aborting download\n",
1111                           result);
1112                goto free_result;
1113        }
1114        resultcode = rstmsg->resultcode.data;
1115        if (resultcode != P80211ENUM_resultcode_success) {
1116                netdev_err(wlandev->netdev,
1117                           "writeimage()->xxxdl_state msg indicates failure, w/ resultcode=%d, aborting download.\n",
1118                           resultcode);
1119                result = 1;
1120                goto free_result;
1121        }
1122
1123free_result:
1124        kfree(rstmsg);
1125        kfree(rwrmsg);
1126        return result;
1127}
1128
1129static int validate_identity(void)
1130{
1131        int i;
1132        int result = 1;
1133        int trump = 0;
1134
1135        pr_debug("NIC ID: %#x v%d.%d.%d\n",
1136                 nicid.id, nicid.major, nicid.minor, nicid.variant);
1137        pr_debug("MFI ID: %#x v%d %d->%d\n",
1138                 rfid.id, rfid.variant, rfid.bottom, rfid.top);
1139        pr_debug("CFI ID: %#x v%d %d->%d\n",
1140                 macid.id, macid.variant, macid.bottom, macid.top);
1141        pr_debug("PRI ID: %#x v%d %d->%d\n",
1142                 priid.id, priid.variant, priid.bottom, priid.top);
1143
1144        for (i = 0; i < ns3info; i++) {
1145                switch (s3info[i].type) {
1146                case 1:
1147                        pr_debug("Version:  ID %#x %d.%d.%d\n",
1148                                 s3info[i].info.version.id,
1149                                 s3info[i].info.version.major,
1150                                 s3info[i].info.version.minor,
1151                                 s3info[i].info.version.variant);
1152                        break;
1153                case 2:
1154                        pr_debug("Compat: Role %#x Id %#x v%d %d->%d\n",
1155                                 s3info[i].info.compat.role,
1156                                 s3info[i].info.compat.id,
1157                                 s3info[i].info.compat.variant,
1158                                 s3info[i].info.compat.bottom,
1159                                 s3info[i].info.compat.top);
1160
1161                        /* MAC compat range */
1162                        if ((s3info[i].info.compat.role == 1) &&
1163                            (s3info[i].info.compat.id == 2)) {
1164                                if (s3info[i].info.compat.variant !=
1165                                    macid.variant) {
1166                                        result = 2;
1167                                }
1168                        }
1169
1170                        /* PRI compat range */
1171                        if ((s3info[i].info.compat.role == 1) &&
1172                            (s3info[i].info.compat.id == 3)) {
1173                                if ((s3info[i].info.compat.bottom > priid.top)
1174                                    || (s3info[i].info.compat.top <
1175                                        priid.bottom)) {
1176                                        result = 3;
1177                                }
1178                        }
1179                        /* SEC compat range */
1180                        if ((s3info[i].info.compat.role == 1) &&
1181                            (s3info[i].info.compat.id == 4)) {
1182                                /* FIXME: isn't something missing here? */
1183                        }
1184
1185                        break;
1186                case 3:
1187                        pr_debug("Seq: %#x\n", s3info[i].info.buildseq);
1188
1189                        break;
1190                case 4:
1191                        pr_debug("Platform:  ID %#x %d.%d.%d\n",
1192                                 s3info[i].info.version.id,
1193                                 s3info[i].info.version.major,
1194                                 s3info[i].info.version.minor,
1195                                 s3info[i].info.version.variant);
1196
1197                        if (nicid.id != s3info[i].info.version.id)
1198                                continue;
1199                        if (nicid.major != s3info[i].info.version.major)
1200                                continue;
1201                        if (nicid.minor != s3info[i].info.version.minor)
1202                                continue;
1203                        if ((nicid.variant != s3info[i].info.version.variant) &&
1204                            (nicid.id != 0x8008))
1205                                continue;
1206
1207                        trump = 1;
1208                        break;
1209                case 0x8001:
1210                        pr_debug("name inforec len %d\n", s3info[i].len);
1211
1212                        break;
1213                default:
1214                        pr_debug("Unknown inforec type %d\n", s3info[i].type);
1215                }
1216        }
1217        /* walk through */
1218
1219        if (trump && (result != 2))
1220                result = 0;
1221        return result;
1222}
1223