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